Front Haul Interface Library first seed code contribution
[o-du/phy.git] / fhi_lib / lib / ethernet / ethdi.c
1 /******************************************************************************
2 *
3 *   Copyright (c) 2019 Intel.
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 *
17 *******************************************************************************/
18
19
20 /**
21  * @brief This file has all definitions for the Ethernet Data Interface Layer
22  * @file ethdi.c
23  * @ingroup group_lte_source_auxlib
24  * @author Intel Corporation
25  **/
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdint.h>
30 #include <errno.h>
31 #include <sys/queue.h>
32 #include <err.h>
33 #include <assert.h>
34 #include <linux/limits.h>
35 #include <sys/types.h>
36 #include <stdlib.h>
37 #include <sys/time.h>
38 #include <time.h>
39 #include <unistd.h>
40
41 #include <rte_config.h>
42 #include <rte_common.h>
43 #include <rte_log.h>
44 #include <rte_memory.h>
45 #include <rte_memcpy.h>
46 #include <rte_memzone.h>
47 #include <rte_eal.h>
48 #include <rte_per_lcore.h>
49 #include <rte_launch.h>
50 #include <rte_atomic.h>
51 #include <rte_cycles.h>
52 #include <rte_prefetch.h>
53 #include <rte_lcore.h>
54 #include <rte_per_lcore.h>
55 #include <rte_branch_prediction.h>
56 #include <rte_interrupts.h>
57 #include <rte_pci.h>
58 #include <rte_debug.h>
59 #include <rte_ethdev.h>
60 #include <rte_ring.h>
61 #include <rte_mbuf.h>
62 #include <rte_timer.h>
63
64 #include "ethernet.h"
65 #include "ethdi.h"
66 #ifndef MLOG_ENABLED
67 #include "../src/mlog_lnx_xRAN.h"
68 #else
69 #include "mlog_lnx.h"
70 #endif
71
72 #include "../src/xran_lib_mlog_tasks_id.h"
73
74 struct xran_ethdi_ctx g_ethdi_ctx = { 0 };
75 enum xran_if_state xran_if_current_state = XRAN_STOPPED;
76
77 struct rte_mbuf *xran_ethdi_mbuf_alloc(void)
78 {
79     return rte_pktmbuf_alloc(_eth_mbuf_pool);
80 }
81
82 int xran_ethdi_mbuf_send(struct rte_mbuf *mb, uint16_t ethertype)
83 {
84     struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
85     int res = 0;
86
87     mb->port = ctx->io_cfg.port[ETHDI_UP_VF];
88     xran_add_eth_hdr_vlan(&ctx->entities[ID_RU], ethertype, mb, ctx->up_vtag);
89
90     res = xran_enqueue_mbuf(mb, ctx->tx_ring[ETHDI_UP_VF]);
91     return res;
92 }
93
94 int xran_ethdi_mbuf_send_cp(struct rte_mbuf *mb, uint16_t ethertype)
95 {
96     struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
97     int res = 0;
98
99     mb->port = ctx->io_cfg.port[ETHDI_CP_VF];
100     xran_add_eth_hdr_vlan(&ctx->entities[ID_RU], ethertype, mb, ctx->cp_vtag);
101
102     res = xran_enqueue_mbuf(mb, ctx->tx_ring[ETHDI_CP_VF]);
103     return res;
104 }
105
106 void xran_ethdi_stop_tx()
107 {
108     struct xran_ethdi_ctx *const ctx = xran_ethdi_get_ctx();
109     rte_timer_stop_sync(&ctx->timer_tx);
110 }
111
112
113 struct {
114     uint16_t ethertype;
115     ethertype_handler fn;
116 } xran_ethertype_handlers[] = {
117     { ETHER_TYPE_ETHDI, NULL },
118     { ETHER_TYPE_ECPRI, NULL },
119     { ETHER_TYPE_START_TX, NULL }
120 };
121
122
123
124 int xran_register_ethertype_handler(uint16_t ethertype, ethertype_handler callback)
125 {
126     int i;
127
128     for (i = 0; i < RTE_DIM(xran_ethertype_handlers); ++i)
129         if (xran_ethertype_handlers[i].ethertype == ethertype) {
130             xran_ethertype_handlers[i].fn = callback;
131
132             return 1;
133         }
134
135     elog("support for ethertype %u not found", ethertype);
136
137     return 0;
138 }
139
140 int xran_handle_ether(uint16_t ethertype, struct rte_mbuf *pkt, uint64_t rx_time)
141 {
142     int i;
143
144     for (i = 0; i < RTE_DIM(xran_ethertype_handlers); ++i)
145         if (xran_ethertype_handlers[i].ethertype == ethertype)
146             if (xran_ethertype_handlers[i].fn)
147                 return xran_ethertype_handlers[i].fn(pkt, rx_time);
148
149     wlog("Packet with unrecognized ethertype '%.4X' dropped", ethertype);
150
151     return 0;
152 };
153
154
155 /* Process vlan tag. Cut the ethernet header. Call the etherype handlers. */
156 int xran_ethdi_filter_packet(struct rte_mbuf *pkt, uint64_t rx_time)
157 {
158     struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
159
160 #ifdef VLAN_SUPPORT
161     if (rte_vlan_strip(pkt) == 0) {
162         if (pkt->vlan_tci == ctx->cp_vtag) {
163             dlog("VLAN tci matches %d", pkt->vlan_tci);
164         } else {
165             wlog("packet with wrong VLAN tag %d, dropping",
166                     pkt->vlan_tci);
167             return 0;
168         }
169     } else
170         dlog("Packet not vlan tagged");
171 #endif
172
173     const struct ether_hdr *eth_hdr = rte_pktmbuf_mtod(pkt, void *);
174
175 #if defined(DPDKIO_DEBUG) && DPDKIO_DEBUG > 1
176     nlog("*** processing RX'ed packet of size %d ***",
177             rte_pktmbuf_data_len(pkt));
178     /* TODO: just dump ethernet header in readable format? */
179 #endif
180
181 #if defined(DPDKIO_DEBUG) && DPDKIO_DEBUG > 1
182     {
183         char dst[ETHER_ADDR_FMT_SIZE] = "(empty)";
184         char src[ETHER_ADDR_FMT_SIZE] = "(empty)";
185
186         ether_format_addr(dst, sizeof(dst), &eth_hdr->d_addr);
187         ether_format_addr(src, sizeof(src), &eth_hdr->s_addr);
188         nlog("src: %s dst: %s ethertype: %.4X", dst, src,
189                 rte_be_to_cpu_16(eth_hdr->ether_type));
190     }
191 #endif
192
193     /* Cut out the ethernet header. It's not needed anymore. */
194     if (rte_pktmbuf_adj(pkt, sizeof(*eth_hdr)) == NULL) {
195         wlog("Packet too short, dropping");
196         return 0;
197     }
198
199
200     return xran_handle_ether(rte_be_to_cpu_16(eth_hdr->ether_type), pkt, rx_time);
201 }
202
203
204
205
206 int xran_ethdi_init_dpdk_io(char *name, const struct xran_io_loop_cfg *io_cfg,
207     int *lcore_id, struct ether_addr *p_lls_cu_addr, struct ether_addr *p_ru_addr,
208     uint16_t cp_vlan, uint16_t up_vlan)
209 {
210     uint16_t port[2] = {0, 0};
211     struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
212     int i;
213     char core_mask[20];
214     char *argv[] = { name, core_mask, "-m3072", "--proc-type=auto",
215         "--file-prefix", name, "-w", "0000:00:00.0" };
216
217     if (io_cfg == NULL)
218         return 0;
219
220     snprintf(core_mask, sizeof(core_mask), "-c%x",
221             (1 << io_cfg->core) |
222             (1 << io_cfg->system_core) |
223             (1 << io_cfg->pkt_proc_core) |
224             (1 << io_cfg->pkt_aux_core) |
225             (1 << io_cfg->timing_core));
226
227     ctx->io_cfg = *io_cfg;
228     ctx->ping_state           = PING_IDLE;
229     ctx->known_peers          = 1;
230     ctx->busy_poll_till = rte_rdtsc();
231     ctx->cp_vtag = cp_vlan;
232     ctx->up_vtag = up_vlan;
233
234     for (i = 0; i <= ID_BROADCAST; i++)     /* Initialize all as broadcast */
235         memset(&ctx->entities[i], 0xFF, sizeof(ctx->entities[0]));
236
237     /* This will return on system_core, which is not necessarily the
238      * one we're on right now. */
239     if (rte_eal_init(RTE_DIM(argv), argv) < 0)
240         rte_panic("Cannot init EAL: %s\n", rte_strerror(rte_errno));
241
242     xran_init_mbuf_pool();
243
244     /* Timers. */
245     rte_timer_subsystem_init();
246     rte_timer_init(&ctx->timer_ping);
247     rte_timer_init(&ctx->timer_sync);
248     rte_timer_init(&ctx->timer_tx);
249
250     *lcore_id = rte_get_next_lcore(rte_lcore_id(), 0, 0);
251
252     PANIC_ON(*lcore_id == RTE_MAX_LCORE, "out of lcores for io_loop()");
253
254     if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
255         for (i = 0; i < ETHDI_VF_MAX; i ++){
256             if (rte_eth_dev_attach(io_cfg->dpdk_dev[i], &port[i]) != 0 ||
257                 rte_eth_dev_count_avail() == 0)
258                 errx(1, "Network port doesn't exist.");
259             xran_init_port(port[i], p_lls_cu_addr);   /* we only have 1 port at this stage */
260             if(i==0){
261                 ctx->tx_ring[i] = rte_ring_create("tx_ring_up", NUM_MBUFS,
262                     rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);
263                 ctx->rx_ring[i] = rte_ring_create("rx_ring_up", NUM_MBUFS,
264                     rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);
265                 ctx->pkt_dump_ring[i] = rte_ring_create("pkt_dump_ring_up", NUM_MBUFS,
266                     rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);
267             }else {
268                 ctx->tx_ring[i] = rte_ring_create("tx_ring_cp", NUM_MBUFS,
269                     rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);
270                 ctx->rx_ring[i] = rte_ring_create("rx_ring_cp", NUM_MBUFS,
271                     rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);
272                 ctx->pkt_dump_ring[i] = rte_ring_create("pkt_dump_ring_cp", NUM_MBUFS,
273                     rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ);
274             }
275         }
276     } else {
277         rte_panic("ethdi_dpdk_io_loop() failed to start  with RTE_PROC_SECONDARY\n");
278     }
279     PANIC_ON(ctx->tx_ring == NULL, "failed to allocate tx ring");
280     PANIC_ON(ctx->rx_ring == NULL, "failed to allocate rx ring");
281     PANIC_ON(ctx->pkt_dump_ring == NULL, "failed to allocate pkt dumping ring");
282     for (i = 0; i < ETHDI_VF_MAX; i++)
283         ctx->io_cfg.port[i] = port[i];
284
285     rte_eth_macaddr_get(port[ETHDI_UP_VF], &ctx->entities[io_cfg->id]);
286     ether_addr_copy(p_ru_addr,  &ctx->entities[ID_RU]);
287
288     /* Start the actual IO thread */
289     if (rte_eal_remote_launch(xran_ethdi_dpdk_io_loop, &ctx->io_cfg, *lcore_id))
290         rte_panic("ethdi_dpdk_io_loop() failed to start\n");
291
292     return 1;
293 }
294
295 static inline uint16_t xran_tx_from_ring(int port, struct rte_ring *r)
296 {
297     struct rte_mbuf *mbufs[BURST_SIZE];
298     uint16_t dequeued, sent = 0;
299     uint32_t remaining;
300     int i;
301     long t1 = MLogTick();
302
303     dequeued = rte_ring_dequeue_burst(r, (void **)mbufs, BURST_SIZE,
304             &remaining);
305     if (!dequeued)
306         return 0;   /* Nothing to send. */
307
308     while (1) {     /* When tx queue is full it is trying again till succeed */
309         t1 = MLogTick();
310         sent += rte_eth_tx_burst(port, 0, &mbufs[sent], dequeued - sent);
311         MLogTask(PID_RADIO_ETH_TX_BURST, t1, MLogTick());
312
313         if (sent == dequeued)
314             return remaining;
315     }
316 }
317
318
319
320 /*
321  * This is the main DPDK-IO loop.
322  * This will sleep if there's no packets incoming and there's
323  * no work enqueued, sleep lenth is defined in IDLE_SLEEP_MICROSECS
324  */
325 int xran_ethdi_dpdk_io_loop(void *io_loop_cfg)
326 {
327     struct xran_ethdi_ctx *ctx = xran_ethdi_get_ctx();
328     const struct xran_io_loop_cfg *const cfg = io_loop_cfg;
329     const int port[ETHDI_VF_MAX] = {cfg->port[ETHDI_UP_VF], cfg->port[ETHDI_CP_VF]};
330     int port_id = 0;
331     struct sched_param sched_param;
332     int res = 0;
333
334     printf("%s [PORT: %d %d] [CPU %2d] [PID: %6d]\n", __FUNCTION__, port[ETHDI_UP_VF], port[ETHDI_CP_VF] , rte_lcore_id(), getpid());
335
336     printf("%s [CPU %2d] [PID: %6d]\n", __FUNCTION__,  rte_lcore_id(), getpid());
337     sched_param.sched_priority = XRAN_THREAD_DEFAULT_PRIO;
338     if ((res = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sched_param)))
339     {
340         printf("priority is not changed: coreId = %d, result1 = %d\n",rte_lcore_id(), res);
341     }
342
343     for (;;) {
344         for (port_id = 0; port_id < ETHDI_VF_MAX; port_id++){
345             struct rte_mbuf *mbufs[BURST_SIZE];
346             /* RX */
347             const uint16_t rxed = rte_eth_rx_burst(port[port_id], 0, mbufs, BURST_SIZE);
348             if (rxed != 0){
349                 long t1 = MLogTick();
350                 rte_ring_enqueue_burst(ctx->rx_ring[port_id], (void*)mbufs, rxed, NULL);
351                 MLogTask(PID_RADIO_RX_VALIDATE, t1, MLogTick());
352             }
353
354             /* TX */
355             const uint16_t sent = xran_tx_from_ring(port[port_id], ctx->tx_ring[port_id]);
356             if (rxed | sent)
357                 continue;   /* more packets might be waiting in queues */
358
359             rte_pause();    /* short pause, optimize memory access */
360             if (XRAN_STOPPED == xran_if_current_state)
361                 break;
362         }
363
364         if (XRAN_STOPPED == xran_if_current_state)
365                 break;
366     }
367
368     fflush(stderr);
369     fflush(stdout);
370     puts("IO loop finished");
371
372     //for (port_id = 0; port_id < ETHDI_VF_MAX; port_id++)
373       //  xran_ethdi_port_stats(port[port_id]);
374
375     return 0;
376 }