Integrate irq mode into PROX (support display and command line)
[samplevnf.git] / VNFs / DPPD-PROX / prox_port_cfg.c
1 /*
2 // Copyright (c) 2010-2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <string.h>
18 #include <stdio.h>
19 #include <rte_version.h>
20 #include <rte_eth_ring.h>
21 #include <rte_mbuf.h>
22 #if (RTE_VERSION >= RTE_VERSION_NUM(17,11,0,0))
23 #include <rte_bus_vdev.h>
24 #else
25 #if (RTE_VERSION > RTE_VERSION_NUM(17,5,0,2))
26 #include <rte_dev.h>
27 #else
28 #if (RTE_VERSION >= RTE_VERSION_NUM(2,1,0,0))
29 #include <rte_eth_null.h>
30 #endif
31 #endif
32 #endif
33
34 #include "prox_port_cfg.h"
35 #include "prox_globals.h"
36 #include "log.h"
37 #include "quit.h"
38 #include "defaults.h"
39 #include "toeplitz.h"
40 #include "defines.h"
41 #include "prox_cksum.h"
42 #include "stats_irq.h"
43
44 struct prox_port_cfg prox_port_cfg[PROX_MAX_PORTS];
45 rte_atomic32_t lsc;
46
47 int prox_nb_active_ports(void)
48 {
49         int ret = 0;
50         for (uint32_t i = 0; i < PROX_MAX_PORTS; ++i) {
51                 ret += prox_port_cfg[i].active;
52         }
53         return ret;
54 }
55
56 int prox_last_port_active(void)
57 {
58         int ret = -1;
59         for (uint32_t i = 0; i < PROX_MAX_PORTS; ++i) {
60                 if (prox_port_cfg[i].active) {
61                         ret = i;
62                 }
63         }
64         return ret;
65 }
66
67 #if RTE_VERSION >= RTE_VERSION_NUM(17,11,0,0)
68 static int lsc_cb(__attribute__((unused)) uint16_t port_id, enum rte_eth_event_type type, __attribute__((unused)) void *param,
69         __attribute__((unused)) void *ret_param)
70 #else
71 #if RTE_VERSION >= RTE_VERSION_NUM(17,8,0,1)
72 static int lsc_cb(__attribute__((unused)) uint8_t port_id, enum rte_eth_event_type type, __attribute__((unused)) void *param,
73         __attribute__((unused)) void *ret_param)
74 #else
75 static void lsc_cb(__attribute__((unused)) uint8_t port_id, enum rte_eth_event_type type, __attribute__((unused)) void *param)
76 #endif
77 #endif
78 {
79         if (RTE_ETH_EVENT_INTR_LSC != type) {
80 #if RTE_VERSION >= RTE_VERSION_NUM(17,8,0,1)
81                 return -1;
82 #else
83                 return;
84 #endif
85         }
86
87         rte_atomic32_inc(&lsc);
88
89 #if RTE_VERSION >= RTE_VERSION_NUM(17,8,0,1)
90         return 0;
91 #endif
92 }
93
94 struct prox_pktmbuf_reinit_args {
95         struct rte_mempool *mp;
96         struct lcore_cfg   *lconf;
97 };
98
99 /* standard mbuf initialization procedure */
100 void prox_pktmbuf_init(struct rte_mempool *mp, void *opaque_arg, void *_m, unsigned i)
101 {
102         struct rte_mbuf *mbuf = _m;
103
104 #if RTE_VERSION >= RTE_VERSION_NUM(1,8,0,0)
105         mbuf->tx_offload = CALC_TX_OL(sizeof(struct ether_hdr), sizeof(struct ipv4_hdr));
106 #else
107         mbuf->pkt.vlan_macip.f.l2_len = sizeof(struct ether_hdr);
108         mbuf->pkt.vlan_macip.f.l3_len = sizeof(struct ipv4_hdr);
109 #endif
110
111         rte_pktmbuf_init(mp, opaque_arg, mbuf, i);
112 }
113
114 void prox_pktmbuf_reinit(void *arg, void *start, __attribute__((unused)) void *end, uint32_t idx)
115 {
116         struct prox_pktmbuf_reinit_args *init_args = arg;
117         struct rte_mbuf *m;
118         char* obj = start;
119
120         obj += init_args->mp->header_size;
121         m = (struct rte_mbuf*)obj;
122
123         prox_pktmbuf_init(init_args->mp, init_args->lconf, obj, idx);
124 }
125
126 /* initialize rte devices and check the number of available ports */
127 void init_rte_dev(int use_dummy_devices)
128 {
129         uint8_t nb_ports, port_id_max;
130         int port_id_last;
131         struct rte_eth_dev_info dev_info;
132
133         nb_ports = rte_eth_dev_count();
134         /* get available ports configuration */
135         PROX_PANIC(use_dummy_devices && nb_ports, "Can't use dummy devices while there are also real ports\n");
136
137         if (use_dummy_devices) {
138 #if (RTE_VERSION >= RTE_VERSION_NUM(2,1,0,0))
139                 nb_ports = prox_last_port_active() + 1;
140                 plog_info("Creating %u dummy devices\n", nb_ports);
141
142                 char port_name[32] = "0dummy_dev";
143                 for (uint32_t i = 0; i < nb_ports; ++i) {
144 #if (RTE_VERSION > RTE_VERSION_NUM(17,5,0,1))
145                         rte_vdev_init(port_name, "size=ETHER_MIN_LEN,copy=0");
146 #else
147                         eth_dev_null_create(port_name, 0, ETHER_MIN_LEN, 0);
148 #endif
149                         port_name[0]++;
150                 }
151 #else
152         PROX_PANIC(use_dummy_devices, "Can't use dummy devices\n");
153 #endif
154         }
155         else if (prox_last_port_active() != -1) {
156                 PROX_PANIC(nb_ports == 0, "\tError: DPDK could not find any port\n");
157                 plog_info("\tDPDK has found %u ports\n", nb_ports);
158         }
159
160         if (nb_ports > PROX_MAX_PORTS) {
161                 plog_warn("\tWarning: I can deal with at most %u ports."
162                         " Please update PROX_MAX_PORTS and recompile.\n", PROX_MAX_PORTS);
163
164                 nb_ports = PROX_MAX_PORTS;
165         }
166         port_id_max = nb_ports - 1;
167         port_id_last = prox_last_port_active();
168         PROX_PANIC(port_id_last > port_id_max,
169                    "\tError: invalid port(s) specified, last port index active: %d (max index is %d)\n",
170                    port_id_last, port_id_max);
171
172         /* Assign ports to PROX interfaces & Read max RX/TX queues per port */
173         for (uint8_t port_id = 0; port_id < nb_ports; ++port_id) {
174                 /* skip ports that are not enabled */
175                 if (!prox_port_cfg[port_id].active) {
176                         continue;
177                 }
178                 plog_info("\tGetting info for rte dev %u\n", port_id);
179                 rte_eth_dev_info_get(port_id, &dev_info);
180                 struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
181                 port_cfg->socket = -1;
182
183                 port_cfg->max_txq = dev_info.max_tx_queues;
184                 port_cfg->max_rxq = dev_info.max_rx_queues;
185
186                 if (!dev_info.pci_dev)
187                         continue;
188
189                 snprintf(port_cfg->pci_addr, sizeof(port_cfg->pci_addr),
190                          "%04x:%02x:%02x.%1x", dev_info.pci_dev->addr.domain, dev_info.pci_dev->addr.bus, dev_info.pci_dev->addr.devid, dev_info.pci_dev->addr.function);
191                 strncpy(port_cfg->driver_name, dev_info.driver_name, sizeof(port_cfg->driver_name));
192                 plog_info("\tPort %u : driver='%s' tx_queues=%d rx_queues=%d\n", port_id, !strcmp(port_cfg->driver_name, "")? "null" : port_cfg->driver_name, port_cfg->max_txq, port_cfg->max_rxq);
193
194                 if (strncmp(port_cfg->driver_name, "rte_", 4) == 0) {
195                         strncpy(port_cfg->short_name, prox_port_cfg[port_id].driver_name + 4, sizeof(port_cfg->short_name));
196                 } else if (strncmp(port_cfg->driver_name, "net_", 4) == 0) {
197                         strncpy(port_cfg->short_name, prox_port_cfg[port_id].driver_name + 4, sizeof(port_cfg->short_name));
198                 } else {
199                         strncpy(port_cfg->short_name, prox_port_cfg[port_id].driver_name, sizeof(port_cfg->short_name));
200                 }
201                 char *ptr;
202                 if ((ptr = strstr(port_cfg->short_name, "_pmd")) != NULL) {
203                         *ptr = '\x0';
204                 }
205
206                 /* Try to find the device's numa node */
207                 char buf[1024];
208                 snprintf(buf, sizeof(buf), "/sys/bus/pci/devices/%s/numa_node", port_cfg->pci_addr);
209                 FILE* numa_node_fd = fopen(buf, "r");
210                 if (numa_node_fd) {
211                         if (fgets(buf, sizeof(buf), numa_node_fd) == NULL) {
212                                 plog_warn("Failed to read numa_node for device %s\n", port_cfg->pci_addr);
213                         }
214                         port_cfg->socket = strtol(buf, 0, 0);
215                         if (port_cfg->socket == -1) {
216                                 plog_warn("System did not report numa_node for device %s\n", port_cfg->pci_addr);
217                         }
218                         fclose(numa_node_fd);
219                 }
220
221                 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_IPV4_CKSUM) {
222                         port_cfg->capabilities.tx_offload_cksum |= IPV4_CKSUM;
223                 }
224                 if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_UDP_CKSUM) {
225                         port_cfg->capabilities.tx_offload_cksum |= UDP_CKSUM;
226                 }
227         }
228 }
229
230 /* Create rte ring-backed devices */
231 uint8_t init_rte_ring_dev(void)
232 {
233         uint8_t nb_ring_dev = 0;
234
235         for (uint8_t port_id = 0; port_id < PROX_MAX_PORTS; ++port_id) {
236                 /* skip ports that are not enabled */
237                 if (!prox_port_cfg[port_id].active) {
238                         continue;
239                 }
240                 struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
241                 if (port_cfg->rx_ring[0] != '\0') {
242                         plog_info("\tRing-backed port %u: rx='%s' tx='%s'\n", port_id, port_cfg->rx_ring, port_cfg->tx_ring);
243
244                         struct rte_ring* rx_ring = rte_ring_lookup(port_cfg->rx_ring);
245                         PROX_PANIC(rx_ring == NULL, "Ring %s not found for port %d!\n", port_cfg->rx_ring, port_id);
246                         struct rte_ring* tx_ring = rte_ring_lookup(port_cfg->tx_ring);
247                         PROX_PANIC(tx_ring == NULL, "Ring %s not found for port %d!\n", port_cfg->tx_ring, port_id);
248
249                         int ret = rte_eth_from_rings(port_cfg->name, &rx_ring, 1, &tx_ring, 1, rte_socket_id());
250                         PROX_PANIC(ret != 0, "Failed to create eth_dev from rings for port %d\n", port_id);
251
252                         port_cfg->port_conf.intr_conf.lsc = 0; /* Link state interrupt not supported for ring-backed ports */
253
254                         nb_ring_dev++;
255                 }
256         }
257
258         return nb_ring_dev;
259 }
260
261 static void init_port(struct prox_port_cfg *port_cfg)
262 {
263         static char dummy_pool_name[] = "0_dummy";
264         struct rte_eth_link link;
265         uint8_t port_id;
266         int ret;
267
268         port_id = port_cfg - prox_port_cfg;
269         plog_info("\t*** Initializing port %u ***\n", port_id);
270         plog_info("\t\tPort name is set to %s\n", port_cfg->name);
271         plog_info("\t\tPort max RX/TX queue is %u/%u\n", port_cfg->max_rxq, port_cfg->max_txq);
272         plog_info("\t\tPort driver is %s\n", port_cfg->driver_name);
273
274         PROX_PANIC(port_cfg->n_rxq == 0 && port_cfg->n_txq == 0,
275                    "\t\t port %u is enabled but no RX or TX queues have been configured", port_id);
276
277         if (port_cfg->n_rxq == 0) {
278                 /* not receiving on this port */
279                 plog_info("\t\tPort %u had no RX queues, setting to 1\n", port_id);
280                 port_cfg->n_rxq = 1;
281                 uint32_t mbuf_size = MBUF_SIZE;
282                 if (strcmp(port_cfg->short_name, "vmxnet3") == 0) {
283                         mbuf_size = MBUF_SIZE + RTE_PKTMBUF_HEADROOM;
284                 }
285                 plog_info("\t\tAllocating dummy memory pool on socket %u with %u elements of size %u\n",
286                           port_cfg->socket, port_cfg->n_rxd, mbuf_size);
287                 port_cfg->pool[0] = rte_mempool_create(dummy_pool_name, port_cfg->n_rxd, mbuf_size,
288                                                        0,
289                                                        sizeof(struct rte_pktmbuf_pool_private),
290                                                        rte_pktmbuf_pool_init, NULL,
291                                                        prox_pktmbuf_init, 0,
292                                                        port_cfg->socket, 0);
293                 PROX_PANIC(port_cfg->pool[0] == NULL, "Failed to allocate dummy memory pool on socket %u with %u elements\n",
294                            port_cfg->socket, port_cfg->n_rxd);
295                 dummy_pool_name[0]++;
296         } else {
297                 // Most pmd do not support setting mtu yet...
298                 if (!strcmp(port_cfg->short_name, "ixgbe")) {
299                         plog_info("\t\tSetting MTU size to %u for port %u ...\n", port_cfg->mtu, port_id);
300                         ret = rte_eth_dev_set_mtu(port_id, port_cfg->mtu);
301                         PROX_PANIC(ret < 0, "\n\t\t\trte_eth_dev_set_mtu() failed on port %u: error %d\n", port_id, ret);
302                 }
303
304                 if (port_cfg->n_txq == 0) {
305                         /* not sending on this port */
306                         plog_info("\t\tPort %u had no TX queues, setting to 1\n", port_id);
307                         port_cfg->n_txq = 1;
308                 }
309         }
310
311         if (port_cfg->n_rxq > 1)  {
312                 // Enable RSS if multiple receive queues
313                 port_cfg->port_conf.rxmode.mq_mode                      |= ETH_MQ_RX_RSS;
314                 port_cfg->port_conf.rx_adv_conf.rss_conf.rss_key        = toeplitz_init_key;
315                 port_cfg->port_conf.rx_adv_conf.rss_conf.rss_key_len    = TOEPLITZ_KEY_LEN;
316 #if RTE_VERSION >= RTE_VERSION_NUM(2,0,0,0)
317                 port_cfg->port_conf.rx_adv_conf.rss_conf.rss_hf         = ETH_RSS_IPV4|ETH_RSS_NONFRAG_IPV4_UDP;
318 #else
319                 port_cfg->port_conf.rx_adv_conf.rss_conf.rss_hf         = ETH_RSS_IPV4|ETH_RSS_NONF_IPV4_UDP;
320 #endif
321         }
322
323         plog_info("\t\tConfiguring port %u... with %u RX queues and %u TX queues\n",
324                   port_id, port_cfg->n_rxq, port_cfg->n_txq);
325
326         PROX_PANIC(port_cfg->n_rxq > port_cfg->max_rxq, "\t\t\tToo many RX queues (configuring %u, max is %u)\n", port_cfg->n_rxq, port_cfg->max_rxq);
327         PROX_PANIC(port_cfg->n_txq > port_cfg->max_txq, "\t\t\tToo many TX queues (configuring %u, max is %u)\n", port_cfg->n_txq, port_cfg->max_txq);
328
329         if (!strcmp(port_cfg->short_name, "ixgbe_vf") ||
330             !strcmp(port_cfg->short_name, "virtio") ||
331 #if RTE_VERSION < RTE_VERSION_NUM(1,8,0,0)
332             !strcmp(port_cfg->short_name, "i40e") ||
333 #endif
334             !strcmp(port_cfg->short_name, "i40e_vf") ||
335             !strcmp(port_cfg->short_name, "avp") || /* Wind River */
336             !strcmp(port_cfg->driver_name, "") || /* NULL device */
337             !strcmp(port_cfg->short_name, "vmxnet3")) {
338                 port_cfg->port_conf.intr_conf.lsc = 0;
339                 plog_info("\t\tDisabling link state interrupt for vmxnet3/VF/virtio (unsupported)\n");
340         }
341
342         if (port_cfg->lsc_set_explicitely) {
343                 port_cfg->port_conf.intr_conf.lsc = port_cfg->lsc_val;
344                 plog_info("\t\tOverriding link state interrupt configuration to '%s'\n", port_cfg->lsc_val? "enabled" : "disabled");
345         }
346         if (!strcmp(port_cfg->short_name, "vmxnet3")) {
347                 if (port_cfg->n_txd < 512) {
348                         // Vmxnet3 driver requires minimum 512 tx descriptors
349                         plog_info("\t\tNumber of TX descriptors is set to 512 (minimum required for vmxnet3\n");
350                         port_cfg->n_txd = 512;
351                 }
352         }
353
354         ret = rte_eth_dev_configure(port_id, port_cfg->n_rxq,
355                                     port_cfg->n_txq, &port_cfg->port_conf);
356         PROX_PANIC(ret < 0, "\t\t\trte_eth_dev_configure() failed on port %u: %s (%d)\n", port_id, strerror(-ret), ret);
357
358         if (port_cfg->port_conf.intr_conf.lsc) {
359                 rte_eth_dev_callback_register(port_id, RTE_ETH_EVENT_INTR_LSC, lsc_cb, NULL);
360         }
361
362         plog_info("\t\tMAC address set to "MAC_BYTES_FMT"\n", MAC_BYTES(port_cfg->eth_addr.addr_bytes));
363
364         /* initialize RX queues */
365         for (uint16_t queue_id = 0; queue_id < port_cfg->n_rxq; ++queue_id) {
366                 plog_info("\t\tSetting up RX queue %u on port %u on socket %u with %u desc (pool 0x%p)\n",
367                           queue_id, port_id, port_cfg->socket,
368                           port_cfg->n_rxd, port_cfg->pool[queue_id]);
369
370                 ret = rte_eth_rx_queue_setup(port_id, queue_id,
371                                              port_cfg->n_rxd,
372                                              port_cfg->socket, &port_cfg->rx_conf,
373                                              port_cfg->pool[queue_id]);
374
375                 PROX_PANIC(ret < 0, "\t\t\trte_eth_rx_queue_setup() failed on port %u: error %s (%d)\n", port_id, strerror(-ret), ret);
376         }
377         if (!strcmp(port_cfg->short_name, "virtio")) {
378                 port_cfg->tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOOFFLOADS;
379                 plog_info("\t\tDisabling TX offloads (virtio does not support TX offloads)\n");
380         }
381
382         if (!strcmp(port_cfg->short_name, "vmxnet3")) {
383                 port_cfg->tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOOFFLOADS | ETH_TXQ_FLAGS_NOMULTSEGS;
384                 plog_info("\t\tDisabling TX offloads and multsegs on port %d as vmxnet3 does not support them\n", port_id);
385         }
386         /* initialize one TX queue per logical core on each port */
387         for (uint16_t queue_id = 0; queue_id < port_cfg->n_txq; ++queue_id) {
388                 plog_info("\t\tSetting up TX queue %u on socket %u with %u desc\n",
389                           queue_id, port_cfg->socket, port_cfg->n_txd);
390                 ret = rte_eth_tx_queue_setup(port_id, queue_id, port_cfg->n_txd,
391                                              port_cfg->socket, &port_cfg->tx_conf);
392                 PROX_PANIC(ret < 0, "\t\t\trte_eth_tx_queue_setup() failed on port %u: error %d\n", port_id, ret);
393         }
394
395         plog_info("\t\tStarting up port %u ...", port_id);
396         ret = rte_eth_dev_start(port_id);
397
398         PROX_PANIC(ret < 0, "\n\t\t\trte_eth_dev_start() failed on port %u: error %d\n", port_id, ret);
399         plog_info(" done: ");
400
401         /* Getting link status can be done without waiting if Link
402            State Interrupt is enabled since in that case, if the link
403            is recognized as being down, an interrupt will notify that
404            it has gone up. */
405         if (port_cfg->port_conf.intr_conf.lsc)
406                 rte_eth_link_get_nowait(port_id, &link);
407         else
408                 rte_eth_link_get(port_id, &link);
409
410         port_cfg->link_up = link.link_status;
411         port_cfg->link_speed = link.link_speed;
412         if (link.link_status) {
413                 plog_info("Link Up - speed %'u Mbps - %s\n",
414                           link.link_speed,
415                           (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
416                           "full-duplex" : "half-duplex");
417         }
418         else {
419                 plog_info("Link Down\n");
420         }
421
422         if (port_cfg->promiscuous) {
423                 rte_eth_promiscuous_enable(port_id);
424                 plog_info("\t\tport %u in promiscuous mode\n", port_id);
425         }
426
427         if (strcmp(port_cfg->short_name, "ixgbe_vf") &&
428             strcmp(port_cfg->short_name, "i40e") &&
429             strcmp(port_cfg->short_name, "i40e_vf") &&
430             strcmp(port_cfg->short_name, "vmxnet3")) {
431                 for (uint8_t i = 0; i < 16; ++i) {
432                         ret = rte_eth_dev_set_rx_queue_stats_mapping(port_id, i, i);
433                         if (ret) {
434                                 plog_info("\t\trte_eth_dev_set_rx_queue_stats_mapping() failed: error %d\n", ret);
435                         }
436                         ret = rte_eth_dev_set_tx_queue_stats_mapping(port_id, i, i);
437                         if (ret) {
438                                 plog_info("\t\trte_eth_dev_set_tx_queue_stats_mapping() failed: error %d\n", ret);
439                         }
440                 }
441         }
442 }
443
444 void init_port_all(void)
445 {
446         uint8_t max_port_idx = prox_last_port_active() + 1;
447
448         for (uint8_t portid = 0; portid < max_port_idx; ++portid) {
449                 if (!prox_port_cfg[portid].active) {
450                         continue;
451                 }
452                 init_port(&prox_port_cfg[portid]);
453         }
454 }
455
456 void close_ports_atexit(void)
457 {
458         uint8_t max_port_idx = prox_last_port_active() + 1;
459
460         for (uint8_t portid = 0; portid < max_port_idx; ++portid) {
461                 if (!prox_port_cfg[portid].active) {
462                         continue;
463                 }
464                 rte_eth_dev_close(portid);
465         }
466 }
467
468 void init_port_addr(void)
469 {
470         struct prox_port_cfg *port_cfg;
471
472         for (uint8_t port_id = 0; port_id < PROX_MAX_PORTS; ++port_id) {
473                 if (!prox_port_cfg[port_id].active) {
474                         continue;
475                 }
476                 port_cfg = &prox_port_cfg[port_id];
477
478                 switch (port_cfg->type) {
479                 case PROX_PORT_MAC_HW:
480                         rte_eth_macaddr_get(port_id, &port_cfg->eth_addr);
481                         break;
482                 case PROX_PORT_MAC_RAND:
483                         eth_random_addr(port_cfg->eth_addr.addr_bytes);
484                         break;
485                 case PROX_PORT_MAC_SET:
486                         break;
487                 }
488         }
489 }
490
491 int port_is_active(uint8_t port_id)
492 {
493         if (port_id > PROX_MAX_PORTS) {
494                 plog_info("requested port is higher than highest supported port ID (%u)\n", PROX_MAX_PORTS);
495                 return 0;
496         }
497
498         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
499         if (!port_cfg->active) {
500                 plog_info("Port %u is not active\n", port_id);
501                 return 0;
502         }
503         return 1;
504 }