Add support for reception of jumbo frames 87/55787/1
authorXavier Simonart <xavier.simonart@intel.com>
Sat, 14 Apr 2018 15:19:41 +0000 (17:19 +0200)
committerXavier Simonart <xavier.simonart@intel.com>
Sun, 15 Apr 2018 13:41:16 +0000 (15:41 +0200)
Jumbo frames are now supported through the addition of a "mtu"
parameter of the port in the config file.
Setting the mtu to a value higher than 1500 bytes will enable
the reception of jumbo frames.
In addition, the rte_eth_dev_set_mtu is now set for all pmds.
Finally, setting mbuf_size does not set MEMPOOL_F_NO_SPREAD
anymore. This option was only used for pure debugging.

Big packets can be received using two ways
- Using multiple "small" mbufs, i.e. around 2K. This is the default.
- Using one big mbuf holding the whole packet. This can be enabled
  by setting a parameter mbuf_size in the receiving core configuration

Change-Id: Idd60ad31f41c89f9522dff4d894af2696b7a2ea1
Signed-off-by: Xavier Simonart <xavier.simonart@intel.com>
VNFs/DPPD-PROX/main.c
VNFs/DPPD-PROX/prox_args.c
VNFs/DPPD-PROX/prox_port_cfg.c

index 2c8517f..931b30c 100644 (file)
@@ -285,6 +285,7 @@ static void configure_if_tx_queues(struct task_args *targ, uint8_t socket)
 
 static void configure_if_rx_queues(struct task_args *targ, uint8_t socket)
 {
+       struct prox_port_cfg *port;
        for (int i = 0; i < targ->nb_rxports; i++) {
                uint8_t if_port = targ->rx_port_queue[i].port;
 
@@ -293,15 +294,23 @@ static void configure_if_rx_queues(struct task_args *targ, uint8_t socket)
                }
 
                PROX_PANIC(!prox_port_cfg[if_port].active, "Port %u not used, aborting...\n", if_port);
+               port = &prox_port_cfg[if_port];
 
-               if(prox_port_cfg[if_port].rx_ring[0] != '\0') {
-                       prox_port_cfg[if_port].n_rxq = 0;
+               if(port->rx_ring[0] != '\0') {
+                       port->n_rxq = 0;
                }
 
+               // Force multi segment support if mbuf size is not big enough.
+               // This is usually the case when setting a big mtu size i.e. enabling jumbo frames.
+               uint16_t max_frame_size = port->mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + 2 * PROX_VLAN_TAG_SIZE;
+               if (max_frame_size + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM > targ->mbuf_size) {
+                       targ->task_init->flag_features &= ~TASK_FEATURE_TXQ_FLAGS_NOMULTSEGS;
+                       plog_info("\t\tDisabling No MultSegs on port %u as %lu > %u\n", if_port, max_frame_size + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM, targ->mbuf_size);
+               }
                targ->rx_port_queue[i].queue = prox_port_cfg[if_port].n_rxq;
-               prox_port_cfg[if_port].pool[targ->rx_port_queue[i].queue] = targ->pool;
-               prox_port_cfg[if_port].pool_size[targ->rx_port_queue[i].queue] = targ->nb_mbuf - 1;
-               prox_port_cfg[if_port].n_rxq++;
+               port->pool[targ->rx_port_queue[i].queue] = targ->pool;
+               port->pool_size[targ->rx_port_queue[i].queue] = targ->nb_mbuf - 1;
+               port->n_rxq++;
 
                int dsocket = prox_port_cfg[if_port].socket;
                if (dsocket != -1 && dsocket != socket) {
@@ -319,8 +328,8 @@ static void configure_if_queues(void)
        while (core_targ_next(&lconf, &targ, 0) == 0) {
                socket = rte_lcore_to_socket_id(lconf->id);
 
-               configure_if_tx_queues(targ, socket);
                configure_if_rx_queues(targ, socket);
+               configure_if_tx_queues(targ, socket);
        }
 }
 
@@ -578,6 +587,52 @@ static void shuffle_mempool(struct rte_mempool* mempool, uint32_t nb_mbuf)
        prox_free(pkts);
 }
 
+static void set_mbuf_size(struct task_args *targ)
+{
+       /* mbuf size can be set
+        *  - from config file (highest priority, overwriting any other config) - should only be used as workaround
+        *  - through each 'mode', overwriting the default mbuf_size
+        *  - defaulted to MBUF_SIZE i.e. 1518 Bytes
+        * Except if set explicitely, ensure that size is big enough for vmxnet3 driver
+        */
+       if (targ->mbuf_size_set_explicitely)
+               return;
+
+       if (targ->task_init->mbuf_size != 0) {
+               /* mbuf_size not set through config file but set through mode */
+               targ->mbuf_size = targ->task_init->mbuf_size;
+       }
+
+       struct prox_port_cfg *port;
+       uint16_t max_frame_size = 0;
+       for (int i = 0; i < targ->nb_rxports; i++) {
+               uint8_t if_port = targ->rx_port_queue[i].port;
+
+               if (if_port == OUT_DISCARD) {
+                       continue;
+               }
+               port = &prox_port_cfg[if_port];
+               if (max_frame_size < port->mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + 2 * PROX_VLAN_TAG_SIZE)
+                       max_frame_size = port->mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + 2 * PROX_VLAN_TAG_SIZE;
+
+               if (strcmp(port->short_name, "vmxnet3") == 0) {
+                       if (targ->mbuf_size < MBUF_SIZE + RTE_PKTMBUF_HEADROOM)
+                               targ->mbuf_size = MBUF_SIZE + RTE_PKTMBUF_HEADROOM;
+                       if (targ->mbuf_size < max_frame_size)
+                               targ->mbuf_size = max_frame_size + RTE_PKTMBUF_HEADROOM;
+               }
+       }
+       if (max_frame_size) {
+               // i40e supports a maximum of 5 descriptors chained
+               uint16_t required_mbuf_size = RTE_ALIGN(max_frame_size / 5, 128) + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM;
+               if (required_mbuf_size > targ->mbuf_size) {
+                       targ->mbuf_size = required_mbuf_size;
+                       plog_info("\t\tSetting mbuf_size to %u to support frame_size %u (mtu %u)\n", targ->mbuf_size, max_frame_size, port->mtu);
+               }
+       }
+
+}
+
 static void setup_mempools_unique_per_socket(void)
 {
        uint32_t flags = 0;
@@ -595,11 +650,7 @@ static void setup_mempools_unique_per_socket(void)
                uint8_t socket = rte_lcore_to_socket_id(lconf->id);
                PROX_ASSERT(socket < MAX_SOCKETS);
 
-               if (targ->mbuf_size_set_explicitely)
-                       flags = MEMPOOL_F_NO_SPREAD;
-               if ((!targ->mbuf_size_set_explicitely) && (targ->task_init->mbuf_size != 0)) {
-                       targ->mbuf_size = targ->task_init->mbuf_size;
-               }
+               set_mbuf_size(targ);
                if (targ->rx_port_queue[0].port != OUT_DISCARD) {
                        struct prox_port_cfg* port_cfg = &prox_port_cfg[targ->rx_port_queue[0].port];
                        PROX_ASSERT(targ->nb_mbuf != 0);
@@ -616,10 +667,6 @@ static void setup_mempools_unique_per_socket(void)
                                PROX_PANIC(mbuf_size[socket] != targ->mbuf_size,
                                           "all mbuf_size must have the same size if using a unique mempool per socket\n");
                        }
-                       if ((!targ->mbuf_size_set_explicitely) && (strcmp(port_cfg->short_name, "vmxnet3") == 0)) {
-                               if (mbuf_size[socket] < MBUF_SIZE + RTE_PKTMBUF_HEADROOM)
-                                       mbuf_size[socket] = MBUF_SIZE + RTE_PKTMBUF_HEADROOM;
-                       }
                }
        }
        for (int i = 0 ; i < MAX_SOCKETS; i++) {
@@ -668,24 +715,7 @@ static void setup_mempool_for_rx_task(struct lcore_cfg *lconf, struct task_args
        char memzone_name[64];
        char name[64];
 
-       /* mbuf size can be set
-        *  - from config file (highest priority, overwriting any other config) - should only be used as workaround
-        *  - through each 'mode', overwriting the default mbuf_size
-        *  - defaulted to MBUF_SIZE i.e. 1518 Bytes
-        * Except is set expliciteky, ensure that size is big enough for vmxnet3 driver
-        */
-       if (targ->mbuf_size_set_explicitely) {
-               flags = MEMPOOL_F_NO_SPREAD;
-               /* targ->mbuf_size already set */
-       }
-       else if (targ->task_init->mbuf_size != 0) {
-               /* mbuf_size not set through config file but set through mode */
-               targ->mbuf_size = targ->task_init->mbuf_size;
-       }
-       else if (strcmp(port_cfg->short_name, "vmxnet3") == 0) {
-               if (targ->mbuf_size < MBUF_SIZE + RTE_PKTMBUF_HEADROOM)
-                       targ->mbuf_size = MBUF_SIZE + RTE_PKTMBUF_HEADROOM;
-       }
+       set_mbuf_size(targ);
 
        /* allocate memory pool for packets */
        PROX_ASSERT(targ->nb_mbuf != 0);
index 08f27e9..53223ca 100644 (file)
@@ -546,6 +546,20 @@ static int get_port_cfg(unsigned sindex, char *str, void *data)
                }
                cfg->port_conf.rxmode.hw_strip_crc = val;
        }
+       else if (STR_EQ(str, "mtu size")) {
+               uint32_t val;
+               if (parse_int(&val, pkey)) {
+                       return -1;
+               }
+               if (val) {
+                       cfg->mtu = val;
+                       if (cfg->mtu + ETHER_HDR_LEN + ETHER_CRC_LEN > ETHER_MAX_LEN) {
+                               cfg->port_conf.rxmode.max_rx_pkt_len = cfg->mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + 2 * PROX_VLAN_TAG_SIZE;
+                               cfg->port_conf.rxmode.jumbo_frame = 1;
+                       }
+               }
+       }
+
        else if (STR_EQ(str, "rss")) {
                uint32_t val;
                if (parse_bool(&val, pkey)) {
index c4787b1..c00948a 100644 (file)
@@ -294,12 +294,10 @@ static void init_port(struct prox_port_cfg *port_cfg)
                           port_cfg->socket, port_cfg->n_rxd);
                dummy_pool_name[0]++;
        } else {
-               // Most pmd do not support setting mtu yet...
-               if (!strcmp(port_cfg->short_name, "ixgbe")) {
-                       plog_info("\t\tSetting MTU size to %u for port %u ...\n", port_cfg->mtu, port_id);
-                       ret = rte_eth_dev_set_mtu(port_id, port_cfg->mtu);
-                       PROX_PANIC(ret < 0, "\n\t\t\trte_eth_dev_set_mtu() failed on port %u: error %d\n", port_id, ret);
-               }
+               // Most pmd should now support setting mtu
+               plog_info("\t\tSetting MTU size to %u for port %u ...\n", port_cfg->mtu, port_id);
+               ret = rte_eth_dev_set_mtu(port_id, port_cfg->mtu);
+               PROX_PANIC(ret < 0, "\n\t\t\trte_eth_dev_set_mtu() failed on port %u: error %d\n", port_id, ret);
 
                if (port_cfg->n_txq == 0) {
                        /* not sending on this port */