Merge "Add support for counting non dataplane related packets"
[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 #include "prox_compat.h"
44
45 struct prox_port_cfg prox_port_cfg[PROX_MAX_PORTS];
46 rte_atomic32_t lsc;
47
48 int prox_nb_active_ports(void)
49 {
50         int ret = 0;
51         for (uint32_t i = 0; i < PROX_MAX_PORTS; ++i) {
52                 ret += prox_port_cfg[i].active;
53         }
54         return ret;
55 }
56
57 int prox_last_port_active(void)
58 {
59         int ret = -1;
60         for (uint32_t i = 0; i < PROX_MAX_PORTS; ++i) {
61                 if (prox_port_cfg[i].active) {
62                         ret = i;
63                 }
64         }
65         return ret;
66 }
67
68 #if RTE_VERSION >= RTE_VERSION_NUM(17,11,0,0)
69 static int lsc_cb(__attribute__((unused)) uint16_t port_id, enum rte_eth_event_type type, __attribute__((unused)) void *param,
70         __attribute__((unused)) void *ret_param)
71 #else
72 #if RTE_VERSION >= RTE_VERSION_NUM(17,8,0,1)
73 static int lsc_cb(__attribute__((unused)) uint8_t port_id, enum rte_eth_event_type type, __attribute__((unused)) void *param,
74         __attribute__((unused)) void *ret_param)
75 #else
76 static void lsc_cb(__attribute__((unused)) uint8_t port_id, enum rte_eth_event_type type, __attribute__((unused)) void *param)
77 #endif
78 #endif
79 {
80         if (RTE_ETH_EVENT_INTR_LSC != type) {
81 #if RTE_VERSION >= RTE_VERSION_NUM(17,8,0,1)
82                 return -1;
83 #else
84                 return;
85 #endif
86         }
87
88         rte_atomic32_inc(&lsc);
89
90 #if RTE_VERSION >= RTE_VERSION_NUM(17,8,0,1)
91         return 0;
92 #endif
93 }
94
95 struct prox_pktmbuf_reinit_args {
96         struct rte_mempool *mp;
97         struct lcore_cfg   *lconf;
98 };
99
100 /* standard mbuf initialization procedure */
101 void prox_pktmbuf_init(struct rte_mempool *mp, void *opaque_arg, void *_m, unsigned i)
102 {
103         struct rte_mbuf *mbuf = _m;
104
105 #if RTE_VERSION >= RTE_VERSION_NUM(1,8,0,0)
106         mbuf->tx_offload = CALC_TX_OL(sizeof(struct ether_hdr), sizeof(struct ipv4_hdr));
107 #else
108         mbuf->pkt.vlan_macip.f.l2_len = sizeof(struct ether_hdr);
109         mbuf->pkt.vlan_macip.f.l3_len = sizeof(struct ipv4_hdr);
110 #endif
111
112         rte_pktmbuf_init(mp, opaque_arg, mbuf, i);
113 }
114
115 void prox_pktmbuf_reinit(void *arg, void *start, __attribute__((unused)) void *end, uint32_t idx)
116 {
117         struct prox_pktmbuf_reinit_args *init_args = arg;
118         struct rte_mbuf *m;
119         char* obj = start;
120
121         obj += init_args->mp->header_size;
122         m = (struct rte_mbuf*)obj;
123
124         prox_pktmbuf_init(init_args->mp, init_args->lconf, obj, idx);
125 }
126
127 #define CONFIGURE_TX_OFFLOAD(flag)                                           \
128         if (port_cfg->requested_tx_offload & flag)                              {\
129                 if (port_cfg->disabled_tx_offload & flag)                       {\
130                         plog_info("\t\t%s disabled by configuration\n", #flag);\
131                         port_cfg->requested_tx_offload &= ~flag;\
132                 } else if (port_cfg->dev_info.tx_offload_capa & flag) {\
133                         port_cfg->port_conf.txmode.offloads |= flag;\
134                         plog_info("\t\t%s enabled on port\n", #flag);\
135                 } else if (port_cfg->dev_info.tx_queue_offload_capa & flag) {\
136                         port_cfg->tx_conf.offloads |= flag;\
137                         plog_info("\t\t%s enabled on queue\n", #flag);\
138                 } else {\
139                         port_cfg->requested_tx_offload &= ~flag;\
140                         plog_info("\t\t%s disabled as neither port or queue supports it\n", #flag);\
141                 }\
142         } else {\
143                 plog_info("\t\t%s disabled\n", #flag);\
144         }\
145
146 #define CONFIGURE_RX_OFFLOAD(flag)                                           \
147         if (port_cfg->requested_rx_offload & flag)                              {\
148                 if (port_cfg->dev_info.rx_offload_capa & flag) {\
149                         port_cfg->port_conf.rxmode.offloads |= flag;\
150                         plog_info("\t\t%s enabled on port\n", #flag);\
151                 } else if (port_cfg->dev_info.rx_queue_offload_capa & flag) {\
152                         port_cfg->rx_conf.offloads |= flag;\
153                         plog_info("\t\t%s enabled on queue\n", #flag);\
154                 } else {\
155                         port_cfg->requested_rx_offload &= ~flag;\
156                         plog_info("\t\t%s disabled as neither port or queue supports it\n", #flag);\
157                 }\
158         } else {\
159                 plog_info("\t\t%s disabled\n", #flag);\
160         }\
161
162
163 /* initialize rte devices and check the number of available ports */
164 void init_rte_dev(int use_dummy_devices)
165 {
166         uint8_t nb_ports, port_id_max;
167         int port_id_last;
168         struct rte_eth_dev_info dev_info;
169         const struct rte_pci_device *pci_dev;
170
171         nb_ports = rte_eth_dev_count();
172         /* get available ports configuration */
173         PROX_PANIC(use_dummy_devices && nb_ports, "Can't use dummy devices while there are also real ports\n");
174
175         if (use_dummy_devices) {
176 #if (RTE_VERSION >= RTE_VERSION_NUM(2,1,0,0))
177                 nb_ports = prox_last_port_active() + 1;
178                 plog_info("Creating %u dummy devices\n", nb_ports);
179
180                 char port_name[32] = "0dummy_dev";
181                 for (uint32_t i = 0; i < nb_ports; ++i) {
182 #if (RTE_VERSION > RTE_VERSION_NUM(17,5,0,1))
183                         rte_vdev_init(port_name, "size=ETHER_MIN_LEN,copy=0");
184 #else
185                         eth_dev_null_create(port_name, 0, ETHER_MIN_LEN, 0);
186 #endif
187                         port_name[0]++;
188                 }
189 #else
190         PROX_PANIC(use_dummy_devices, "Can't use dummy devices\n");
191 #endif
192         }
193         else if (prox_last_port_active() != -1) {
194                 PROX_PANIC(nb_ports == 0, "\tError: DPDK could not find any port\n");
195                 plog_info("\tDPDK has found %u ports\n", nb_ports);
196         }
197
198         if (nb_ports > PROX_MAX_PORTS) {
199                 plog_warn("\tWarning: I can deal with at most %u ports."
200                         " Please update PROX_MAX_PORTS and recompile.\n", PROX_MAX_PORTS);
201
202                 nb_ports = PROX_MAX_PORTS;
203         }
204         port_id_max = nb_ports - 1;
205         port_id_last = prox_last_port_active();
206         PROX_PANIC(port_id_last > port_id_max,
207                    "\tError: invalid port(s) specified, last port index active: %d (max index is %d)\n",
208                    port_id_last, port_id_max);
209
210         /* Assign ports to PROX interfaces & Read max RX/TX queues per port */
211         for (uint8_t port_id = 0; port_id < nb_ports; ++port_id) {
212                 /* skip ports that are not enabled */
213                 if (!prox_port_cfg[port_id].active) {
214                         continue;
215                 }
216                 plog_info("\tGetting info for rte dev %u\n", port_id);
217                 rte_eth_dev_info_get(port_id, &dev_info);
218                 struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
219                 port_cfg->socket = -1;
220
221                 memcpy(&port_cfg->dev_info, &dev_info, sizeof(struct rte_eth_dev_info));
222                 port_cfg->max_txq = dev_info.max_tx_queues;
223                 port_cfg->max_rxq = dev_info.max_rx_queues;
224                 port_cfg->max_rx_pkt_len = dev_info.max_rx_pktlen;
225                 port_cfg->min_rx_bufsize = dev_info.min_rx_bufsize;
226
227 #if RTE_VERSION < RTE_VERSION_NUM(18,5,0,0)
228                 pci_dev = dev_info.pci_dev;
229 #else
230                 pci_dev = RTE_DEV_TO_PCI(dev_info.device);
231 #endif
232                 if (!pci_dev)
233                         continue;
234
235                 snprintf(port_cfg->pci_addr, sizeof(port_cfg->pci_addr),
236                          "%04x:%02x:%02x.%1x", pci_dev->addr.domain, pci_dev->addr.bus, pci_dev->addr.devid, pci_dev->addr.function);
237                 strncpy(port_cfg->driver_name, dev_info.driver_name, sizeof(port_cfg->driver_name));
238                 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);
239
240                 if (strncmp(port_cfg->driver_name, "rte_", 4) == 0) {
241                         strncpy(port_cfg->short_name, prox_port_cfg[port_id].driver_name + 4, sizeof(port_cfg->short_name));
242                 } else if (strncmp(port_cfg->driver_name, "net_", 4) == 0) {
243                         strncpy(port_cfg->short_name, prox_port_cfg[port_id].driver_name + 4, sizeof(port_cfg->short_name));
244                 } else {
245                         strncpy(port_cfg->short_name, prox_port_cfg[port_id].driver_name, sizeof(port_cfg->short_name));
246                 }
247                 char *ptr;
248                 if ((ptr = strstr(port_cfg->short_name, "_pmd")) != NULL) {
249                         *ptr = '\x0';
250                 }
251
252                 /* Try to find the device's numa node */
253                 char buf[1024];
254                 snprintf(buf, sizeof(buf), "/sys/bus/pci/devices/%s/numa_node", port_cfg->pci_addr);
255                 FILE* numa_node_fd = fopen(buf, "r");
256                 if (numa_node_fd) {
257                         if (fgets(buf, sizeof(buf), numa_node_fd) == NULL) {
258                                 plog_warn("Failed to read numa_node for device %s\n", port_cfg->pci_addr);
259                         }
260                         port_cfg->socket = strtol(buf, 0, 0);
261                         if (port_cfg->socket == -1) {
262                                 plog_warn("System did not report numa_node for device %s\n", port_cfg->pci_addr);
263                         }
264                         fclose(numa_node_fd);
265                 }
266
267                 // In DPDK 18.08 vmxnet3 reports it supports IPV4 checksum, but packets does not go through when IPv4 cksum is enabled
268                 if ((!strcmp(port_cfg->short_name, "vmxnet3")) && (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_IPV4_CKSUM)) {
269                         plog_info("\t\tDisabling IPV4 cksum on vmxnet3\n");
270                         port_cfg->disabled_tx_offload |= DEV_TX_OFFLOAD_IPV4_CKSUM;
271                 }
272                 if ((!strcmp(port_cfg->short_name, "vmxnet3")) && (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_UDP_CKSUM)) {
273                         plog_info("\t\tDisabling UDP cksum on vmxnet3\n");
274                         port_cfg->disabled_tx_offload |= DEV_TX_OFFLOAD_UDP_CKSUM;
275                 }
276         }
277 }
278
279 /* Create rte ring-backed devices */
280 uint8_t init_rte_ring_dev(void)
281 {
282         uint8_t nb_ring_dev = 0;
283
284         for (uint8_t port_id = 0; port_id < PROX_MAX_PORTS; ++port_id) {
285                 /* skip ports that are not enabled */
286                 if (!prox_port_cfg[port_id].active) {
287                         continue;
288                 }
289                 struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
290                 if (port_cfg->rx_ring[0] != '\0') {
291                         plog_info("\tRing-backed port %u: rx='%s' tx='%s'\n", port_id, port_cfg->rx_ring, port_cfg->tx_ring);
292
293                         struct rte_ring* rx_ring = rte_ring_lookup(port_cfg->rx_ring);
294                         PROX_PANIC(rx_ring == NULL, "Ring %s not found for port %d!\n", port_cfg->rx_ring, port_id);
295                         struct rte_ring* tx_ring = rte_ring_lookup(port_cfg->tx_ring);
296                         PROX_PANIC(tx_ring == NULL, "Ring %s not found for port %d!\n", port_cfg->tx_ring, port_id);
297
298                         int ret = rte_eth_from_rings(port_cfg->name, &rx_ring, 1, &tx_ring, 1, rte_socket_id());
299                         PROX_PANIC(ret != 0, "Failed to create eth_dev from rings for port %d\n", port_id);
300
301                         port_cfg->port_conf.intr_conf.lsc = 0; /* Link state interrupt not supported for ring-backed ports */
302
303                         nb_ring_dev++;
304                 }
305         }
306
307         return nb_ring_dev;
308 }
309
310 static void init_port(struct prox_port_cfg *port_cfg)
311 {
312         static char dummy_pool_name[] = "0_dummy";
313         struct rte_eth_link link;
314         uint8_t port_id;
315         int ret;
316
317         port_id = port_cfg - prox_port_cfg;
318         plog_info("\t*** Initializing port %u ***\n", port_id);
319         plog_info("\t\tPort name is set to %s\n", port_cfg->name);
320         plog_info("\t\tPort max RX/TX queue is %u/%u\n", port_cfg->max_rxq, port_cfg->max_txq);
321         plog_info("\t\tPort driver is %s\n", port_cfg->driver_name);
322 #if RTE_VERSION >= RTE_VERSION_NUM(16,4,0,0)
323         plog_info("\t\tSupported speed mask = 0x%x\n", port_cfg->dev_info.speed_capa);
324 #endif
325
326         PROX_PANIC(port_cfg->n_rxq == 0 && port_cfg->n_txq == 0,
327                    "\t\t port %u is enabled but no RX or TX queues have been configured", port_id);
328
329         if (port_cfg->n_rxq == 0) {
330                 /* not receiving on this port */
331                 plog_info("\t\tPort %u had no RX queues, setting to 1\n", port_id);
332                 port_cfg->n_rxq = 1;
333                 uint32_t mbuf_size = TX_MBUF_SIZE;
334                 plog_info("\t\tAllocating dummy memory pool on socket %u with %u elements of size %u\n",
335                           port_cfg->socket, port_cfg->n_rxd, mbuf_size);
336                 port_cfg->pool[0] = rte_mempool_create(dummy_pool_name, port_cfg->n_rxd, mbuf_size,
337                                                        0,
338                                                        sizeof(struct rte_pktmbuf_pool_private),
339                                                        rte_pktmbuf_pool_init, NULL,
340                                                        prox_pktmbuf_init, 0,
341                                                        port_cfg->socket, 0);
342                 PROX_PANIC(port_cfg->pool[0] == NULL, "Failed to allocate dummy memory pool on socket %u with %u elements\n",
343                            port_cfg->socket, port_cfg->n_rxd);
344                 dummy_pool_name[0]++;
345         } else {
346                 // Most pmd should now support setting mtu
347                 if (port_cfg->mtu + ETHER_HDR_LEN + ETHER_CRC_LEN > port_cfg->max_rx_pkt_len) {
348                         plog_info("\t\tMTU is too big for the port, reducing MTU from %d to %d\n", port_cfg->mtu, port_cfg->max_rx_pkt_len);
349                         port_cfg->mtu = port_cfg->max_rx_pkt_len;
350                 }
351                 plog_info("\t\tSetting MTU size to %u for port %u ...\n", port_cfg->mtu, port_id);
352                 ret = rte_eth_dev_set_mtu(port_id, port_cfg->mtu);
353                 if (ret)
354                         plog_err("\t\t\trte_eth_dev_set_mtu() failed on port %u: error %d\n", port_id, ret);
355
356                 if (port_cfg->n_txq == 0) {
357                         /* not sending on this port */
358                         plog_info("\t\tPort %u had no TX queues, setting to 1\n", port_id);
359                         port_cfg->n_txq = 1;
360                 }
361         }
362
363         if (port_cfg->n_rxq > 1)  {
364                 // Enable RSS if multiple receive queues
365                 port_cfg->port_conf.rxmode.mq_mode                      |= ETH_MQ_RX_RSS;
366                 port_cfg->port_conf.rx_adv_conf.rss_conf.rss_key        = toeplitz_init_key;
367                 port_cfg->port_conf.rx_adv_conf.rss_conf.rss_key_len    = TOEPLITZ_KEY_LEN;
368 #if RTE_VERSION >= RTE_VERSION_NUM(2,0,0,0)
369                 port_cfg->port_conf.rx_adv_conf.rss_conf.rss_hf         = ETH_RSS_IPV4|ETH_RSS_NONFRAG_IPV4_UDP;
370 #else
371                 port_cfg->port_conf.rx_adv_conf.rss_conf.rss_hf         = ETH_RSS_IPV4|ETH_RSS_NONF_IPV4_UDP;
372 #endif
373         }
374
375 #if RTE_VERSION >= RTE_VERSION_NUM(18,8,0,1)
376         plog_info("\t\tRX offload capa = 0x%lx = ", port_cfg->dev_info.rx_offload_capa);
377         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_VLAN_STRIP)
378                 plog_info("VLAN STRIP | ");
379         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_IPV4_CKSUM)
380                 plog_info("IPV4 CKSUM | ");
381         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_UDP_CKSUM)
382                 plog_info("UDP CKSUM | ");
383         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_TCP_CKSUM)
384                 plog_info("TCP CKSUM | ");
385         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_TCP_LRO)
386                 plog_info("TCP LRO | ");
387         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_QINQ_STRIP)
388                 plog_info("QINQ STRIP | ");
389         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM)
390                 plog_info("OUTER_IPV4_CKSUM | ");
391         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_MACSEC_STRIP)
392                 plog_info("MACSEC STRIP | ");
393         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_HEADER_SPLIT)
394                 plog_info("HEADER SPLIT | ");
395         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_VLAN_FILTER)
396                 plog_info("VLAN FILTER | ");
397         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_VLAN_EXTEND)
398                 plog_info("VLAN EXTEND | ");
399         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_JUMBO_FRAME)
400                 plog_info("JUMBO FRAME | ");
401         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_CRC_STRIP)
402                 plog_info("CRC STRIP | ");
403         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_SCATTER)
404                 plog_info("SCATTER | ");
405         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_TIMESTAMP)
406                 plog_info("TIMESTAMP | ");
407         if (port_cfg->dev_info.rx_offload_capa & DEV_RX_OFFLOAD_SECURITY)
408                 plog_info("SECURITY ");
409         plog_info("\n");
410
411         plog_info("\t\tTX offload capa = 0x%lx = ", port_cfg->dev_info.tx_offload_capa);
412         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_VLAN_INSERT)
413                 plog_info("VLAN INSERT | ");
414         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_IPV4_CKSUM)
415                 plog_info("IPV4 CKSUM | ");
416         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_UDP_CKSUM)
417                 plog_info("UDP CKSUM | ");
418         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_TCP_CKSUM)
419                 plog_info("TCP CKSUM | ");
420         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_SCTP_CKSUM)
421                 plog_info("SCTP CKSUM | ");
422         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_TCP_TSO)
423                 plog_info("TCP TS0 | ");
424         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_UDP_TSO)
425                 plog_info("UDP TSO | ");
426         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM)
427                 plog_info("OUTER IPV4 CKSUM | ");
428         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_QINQ_INSERT)
429                 plog_info("QINQ INSERT | ");
430         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_VXLAN_TNL_TSO)
431                 plog_info("VLAN TNL TSO | ");
432         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_GRE_TNL_TSO)
433                 plog_info("GRE TNL TSO | ");
434         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_IPIP_TNL_TSO)
435                 plog_info("IPIP TNL TSO | ");
436         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_GENEVE_TNL_TSO)
437                 plog_info("GENEVE TNL TSO | ");
438         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MACSEC_INSERT)
439                 plog_info("MACSEC INSERT | ");
440         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MT_LOCKFREE)
441                 plog_info("MT LOCKFREE | ");
442         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MULTI_SEGS)
443                 plog_info("MULTI SEG | ");
444         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_SECURITY)
445                 plog_info("SECURITY | ");
446         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_UDP_TNL_TSO)
447                 plog_info("UDP TNL TSO | ");
448         if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_IP_TNL_TSO)
449                 plog_info("IP TNL TSO | ");
450         plog_info("\n");
451
452         plog_info("\t\trx_queue_offload_capa = 0x%lx\n", port_cfg->dev_info.rx_queue_offload_capa);
453         plog_info("\t\ttx_queue_offload_capa = 0x%lx\n", port_cfg->dev_info.tx_queue_offload_capa);
454         plog_info("\t\tflow_type_rss_offloads = 0x%lx\n", port_cfg->dev_info.flow_type_rss_offloads);
455         plog_info("\t\tdefault RX port conf: burst_size = %d, ring_size = %d, nb_queues = %d\n", port_cfg->dev_info.default_rxportconf.burst_size, port_cfg->dev_info.default_rxportconf.ring_size, port_cfg->dev_info.default_rxportconf.nb_queues);
456         plog_info("\t\tdefault TX port conf: burst_size = %d, ring_size = %d, nb_queues = %d\n", port_cfg->dev_info.default_txportconf.burst_size, port_cfg->dev_info.default_txportconf.ring_size, port_cfg->dev_info.default_txportconf.nb_queues);
457 #endif
458
459         // rxmode such as hw src strip
460 #if RTE_VERSION >= RTE_VERSION_NUM(18,8,0,1)
461         CONFIGURE_RX_OFFLOAD(DEV_RX_OFFLOAD_CRC_STRIP);
462         CONFIGURE_RX_OFFLOAD(DEV_RX_OFFLOAD_JUMBO_FRAME);
463 #else
464         if (port_cfg->requested_rx_offload & DEV_RX_OFFLOAD_CRC_STRIP) {
465                 port_cfg->port_conf.rxmode.hw_strip_crc = 1;
466         }
467         if (port_cfg->requested_rx_offload & DEV_RX_OFFLOAD_JUMBO_FRAME) {
468                 port_cfg->port_conf.rxmode.jumbo_frame = 1;
469         }
470 #endif
471
472         // IPV4, UDP, SCTP Checksums
473 #if RTE_VERSION >= RTE_VERSION_NUM(18,8,0,1)
474         CONFIGURE_TX_OFFLOAD(DEV_TX_OFFLOAD_IPV4_CKSUM);
475         CONFIGURE_TX_OFFLOAD(DEV_TX_OFFLOAD_UDP_CKSUM);
476 #else
477         if ((port_cfg->dev_info.tx_offload_capa & (DEV_TX_OFFLOAD_IPV4_CKSUM | DEV_TX_OFFLOAD_UDP_CKSUM)) == 0) {
478                 port_cfg->tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOOFFLOADS;
479                 plog_info("\t\tDisabling TX offloads as pmd reports that it does not support them)\n");
480         }
481         if (!strcmp(port_cfg->short_name, "vmxnet3")) {
482                 port_cfg->tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOXSUMSCTP;
483                 plog_info("\t\tDisabling SCTP offload on port %d as vmxnet3 does not support them\n", port_id);
484         }
485 #endif
486         // Multi Segments
487 #if RTE_VERSION >= RTE_VERSION_NUM(18,8,0,1)
488         CONFIGURE_TX_OFFLOAD(DEV_TX_OFFLOAD_MULTI_SEGS);
489         //if (port_cfg->requested_tx_offload & DEV_TX_OFFLOAD_MULTI_SEGS) {
490                 //if (port_cfg->dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MULTI_SEGS) {
491                         //port_cfg->port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MULTI_SEGS;
492                         //plog_info("\t\tMULTI SEGS TX offloads enabled on port)\n");
493                 //} else if (port_cfg->dev_info.tx_queue_offload_capa & DEV_TX_OFFLOAD_MULTI_SEGS) {
494                         //port_cfg->tx_conf.offloads |= DEV_TX_OFFLOAD_MULTI_SEGS;
495                         //plog_info("\t\tMULTI SEGS TX offloads enabled on queue)\n");
496                 //} else {
497                         //port_cfg->requested_tx_offload &= ~DEV_TX_OFFLOAD_MULTI_SEGS;
498                         //plog_info("\t\tMULTI SEGS TX offloads disabled) as neither port or queue supports it\n");
499                 //}
500         //} else
501                 //plog_info("\t\tMULTI SEGS TX offloads disabled)\n");
502 #else
503         if (!strcmp(port_cfg->short_name, "vmxnet3")) {
504                 port_cfg->tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOMULTSEGS;
505                 plog_info("\t\tDisabling TX multsegs on port %d as vmxnet3 does not support them\n", port_id);
506         } else if (port_cfg->tx_conf.txq_flags & ETH_TXQ_FLAGS_NOMULTSEGS)
507                 plog_info("\t\tDisabling TX multsegs on port %d\n", port_id);
508         else
509                 plog_info("\t\tEnabling TX multsegs on port %d\n", port_id);
510
511         if (port_cfg->tx_conf.txq_flags & ETH_TXQ_FLAGS_NOOFFLOADS)
512                 plog_info("\t\tEnabling No TX offloads on port %d\n", port_id);
513         else
514                 plog_info("\t\tTX offloads enabled on port %d\n", port_id);
515 #endif
516
517         // Refcount
518 #if RTE_VERSION >= RTE_VERSION_NUM(18,8,0,1)
519         CONFIGURE_TX_OFFLOAD(DEV_TX_OFFLOAD_MBUF_FAST_FREE);
520 #else
521         if (port_cfg->tx_conf.txq_flags & ETH_TXQ_FLAGS_NOREFCOUNT)
522                 plog_info("\t\tEnabling No refcnt on port %d\n", port_id);
523         else
524                 plog_info("\t\tRefcnt enabled on port %d\n", port_id);
525 #endif
526
527         plog_info("\t\tConfiguring port %u... with %u RX queues and %u TX queues\n",
528                   port_id, port_cfg->n_rxq, port_cfg->n_txq);
529
530         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);
531         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);
532
533         if (!strcmp(port_cfg->short_name, "ixgbe_vf") ||
534             !strcmp(port_cfg->short_name, "virtio") ||
535 #if RTE_VERSION < RTE_VERSION_NUM(1,8,0,0)
536             !strcmp(port_cfg->short_name, "i40e") ||
537 #endif
538             !strcmp(port_cfg->short_name, "i40e_vf") ||
539             !strcmp(port_cfg->short_name, "avp") || /* Wind River */
540             !strcmp(port_cfg->driver_name, "") || /* NULL device */
541             !strcmp(port_cfg->short_name, "vmxnet3")) {
542                 port_cfg->port_conf.intr_conf.lsc = 0;
543                 plog_info("\t\tDisabling link state interrupt for vmxnet3/VF/virtio (unsupported)\n");
544         }
545
546         if (port_cfg->lsc_set_explicitely) {
547                 port_cfg->port_conf.intr_conf.lsc = port_cfg->lsc_val;
548                 plog_info("\t\tOverriding link state interrupt configuration to '%s'\n", port_cfg->lsc_val? "enabled" : "disabled");
549         }
550         if (!strcmp(port_cfg->short_name, "vmxnet3")) {
551                 if (port_cfg->n_txd < 512) {
552                         // Vmxnet3 driver requires minimum 512 tx descriptors
553                         plog_info("\t\tNumber of TX descriptors is set to 512 (minimum required for vmxnet3\n");
554                         port_cfg->n_txd = 512;
555                 }
556         }
557
558         ret = rte_eth_dev_configure(port_id, port_cfg->n_rxq,
559                                     port_cfg->n_txq, &port_cfg->port_conf);
560         PROX_PANIC(ret < 0, "\t\t\trte_eth_dev_configure() failed on port %u: %s (%d)\n", port_id, strerror(-ret), ret);
561
562         if (port_cfg->port_conf.intr_conf.lsc) {
563                 rte_eth_dev_callback_register(port_id, RTE_ETH_EVENT_INTR_LSC, lsc_cb, NULL);
564         }
565
566         plog_info("\t\tMAC address set to "MAC_BYTES_FMT"\n", MAC_BYTES(port_cfg->eth_addr.addr_bytes));
567
568         /* initialize TX queues first */
569         for (uint16_t queue_id = 0; queue_id < port_cfg->n_txq; ++queue_id) {
570                 plog_info("\t\tSetting up TX queue %u on socket %u with %u desc\n",
571                           queue_id, port_cfg->socket, port_cfg->n_txd);
572                 ret = rte_eth_tx_queue_setup(port_id, queue_id, port_cfg->n_txd,
573                                              port_cfg->socket, &port_cfg->tx_conf);
574                 PROX_PANIC(ret < 0, "\t\t\trte_eth_tx_queue_setup() failed on port %u: error %d\n", port_id, ret);
575         }
576
577         /* initialize RX queues */
578         for (uint16_t queue_id = 0; queue_id < port_cfg->n_rxq; ++queue_id) {
579                 plog_info("\t\tSetting up RX queue %u on port %u on socket %u with %u desc (pool 0x%p)\n",
580                           queue_id, port_id, port_cfg->socket,
581                           port_cfg->n_rxd, port_cfg->pool[queue_id]);
582                 ret = rte_eth_rx_queue_setup(port_id, queue_id,
583                                              port_cfg->n_rxd,
584                                              port_cfg->socket, &port_cfg->rx_conf,
585                                              port_cfg->pool[queue_id]);
586                 PROX_PANIC(ret < 0, "\t\t\trte_eth_rx_queue_setup() failed on port %u: error %s (%d)\n", port_id, strerror(-ret), ret);
587         }
588
589         plog_info("\t\tStarting up port %u ...", port_id);
590         ret = rte_eth_dev_start(port_id);
591
592         PROX_PANIC(ret < 0, "\n\t\t\trte_eth_dev_start() failed on port %u: error %d\n", port_id, ret);
593         plog_info(" done: ");
594
595         /* Getting link status can be done without waiting if Link
596            State Interrupt is enabled since in that case, if the link
597            is recognized as being down, an interrupt will notify that
598            it has gone up. */
599         if (port_cfg->port_conf.intr_conf.lsc)
600                 rte_eth_link_get_nowait(port_id, &link);
601         else
602                 rte_eth_link_get(port_id, &link);
603
604         port_cfg->link_up = link.link_status;
605         port_cfg->link_speed = link.link_speed;
606         if (link.link_status) {
607                 plog_info("Link Up - speed %'u Mbps - %s\n",
608                           link.link_speed,
609                           (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
610                           "full-duplex" : "half-duplex");
611         }
612         else {
613                 plog_info("Link Down\n");
614         }
615
616         if (port_cfg->promiscuous) {
617                 rte_eth_promiscuous_enable(port_id);
618                 plog_info("\t\tport %u in promiscuous mode\n", port_id);
619         }
620
621         if (strcmp(port_cfg->short_name, "ixgbe_vf") &&
622             strcmp(port_cfg->short_name, "i40e") &&
623             strcmp(port_cfg->short_name, "i40e_vf") &&
624             strcmp(port_cfg->short_name, "vmxnet3")) {
625                 for (uint8_t i = 0; i < 16; ++i) {
626                         ret = rte_eth_dev_set_rx_queue_stats_mapping(port_id, i, i);
627                         if (ret) {
628                                 plog_info("\t\trte_eth_dev_set_rx_queue_stats_mapping() failed: error %d\n", ret);
629                         }
630                         ret = rte_eth_dev_set_tx_queue_stats_mapping(port_id, i, i);
631                         if (ret) {
632                                 plog_info("\t\trte_eth_dev_set_tx_queue_stats_mapping() failed: error %d\n", ret);
633                         }
634                 }
635         }
636 }
637
638 void init_port_all(void)
639 {
640         uint8_t max_port_idx = prox_last_port_active() + 1;
641
642         for (uint8_t portid = 0; portid < max_port_idx; ++portid) {
643                 if (!prox_port_cfg[portid].active) {
644                         continue;
645                 }
646                 init_port(&prox_port_cfg[portid]);
647         }
648 }
649
650 void close_ports_atexit(void)
651 {
652         uint8_t max_port_idx = prox_last_port_active() + 1;
653
654         for (uint8_t portid = 0; portid < max_port_idx; ++portid) {
655                 if (!prox_port_cfg[portid].active) {
656                         continue;
657                 }
658                 rte_eth_dev_close(portid);
659         }
660 }
661
662 void init_port_addr(void)
663 {
664         struct prox_port_cfg *port_cfg;
665
666         for (uint8_t port_id = 0; port_id < PROX_MAX_PORTS; ++port_id) {
667                 if (!prox_port_cfg[port_id].active) {
668                         continue;
669                 }
670                 port_cfg = &prox_port_cfg[port_id];
671
672                 switch (port_cfg->type) {
673                 case PROX_PORT_MAC_HW:
674                         rte_eth_macaddr_get(port_id, &port_cfg->eth_addr);
675                         break;
676                 case PROX_PORT_MAC_RAND:
677                         eth_random_addr(port_cfg->eth_addr.addr_bytes);
678                         break;
679                 case PROX_PORT_MAC_SET:
680                         break;
681                 }
682         }
683 }
684
685 int port_is_active(uint8_t port_id)
686 {
687         if (port_id > PROX_MAX_PORTS) {
688                 plog_info("requested port is higher than highest supported port ID (%u)\n", PROX_MAX_PORTS);
689                 return 0;
690         }
691
692         struct prox_port_cfg* port_cfg = &prox_port_cfg[port_id];
693         if (!port_cfg->active) {
694                 plog_info("Port %u is not active\n", port_id);
695                 return 0;
696         }
697         return 1;
698 }