> >"Kavanagh, Mark B" <mark.b.kavan...@intel.com> writes: > >>> >>>"Kavanagh, Mark B" <mark.b.kavan...@intel.com> writes: >>> >>>>> >>>>>"Kavanagh, Mark B" <mark.b.kavan...@intel.com> writes: >>>>>> Further clarifications below Aaron - please let me know if you have >>>>>> any additional comments. >>>>>> >>>>>> Thanks, >>>>>> Mark >>>>> >>>>>Thanks again for this work, Mark! >>>>> >>>>>>> >>>>>>>One addendum below, Aaron. >>>>>>> >>>>>>>> >>>>>>>>>Hi Mark, >>>>>>>>> >>>>>>>>>Thanks for the patch! I've not done a very thorough review of this, but >>>>>>>>>my first-blush comments are inline. >>>>>>>> >>>>>>>>Thanks for the review Aaron! >>>>>>>> >>>>>>>>Any additional comments are welcome - my initial responses are >>>> inline, below. >>>>>>>> >>>>>>>>Thanks, >>>>>>>>Mark >>>>>>>> >>>>>>>>> >>>>>>>>>Mark Kavanagh <mark.b.kavan...@intel.com> writes: >>>>>>>>>> Add support for Jumbo Frames to DPDK-enabled port types, >>>>>>>>>> using single-segment-mbufs. >>>>>>>>>> >>>>>>>>>> Using this approach, the amount of memory allocated for each mbuf >>>>>>>>>> to store frame data is increased to a value greater than 1518B >>>>>>>>>> (typical Ethernet maximum frame length). The increased space >>>>>>>>>> available in the mbuf means that an entire Jumbo Frame can be carried >>>>>>>>>> in a single mbuf, as opposed to partitioning it across multiple mbuf >>>>>>>>>> segments. >>>>>>>>>> >>>>>>>>>> The amount of space allocated to each mbuf to hold frame data is >>>>>>>>>> defined dynamically by the user when adding a DPDK port to a bridge. >>>>>>>>>> If an MTU value is not supplied, or the user-supplied value is >>>>>>>>>> invalid, >>>>>>>>>> the MTU for the port defaults to standard Ethernet MTU (i.e. 1500B). >>>>>>>>>> >>>>>>>>>> Signed-off-by: Mark Kavanagh <mark.b.kavan...@intel.com> >>>>>>>>>> --- >>>>>>>>> >>>>>>>>>This is a new feature which has user-visible impact, so should be >>>>>>>>>announced in NEWS (plus, it's great news). >>>>>>>> >>>>>>>>No problem - I'll add an entry. >>>>>>>> >>>>>>>>> >>>>>>>>>> INSTALL.DPDK.md | 59 ++++++++- >>>>>>>>>> lib/netdev-dpdk.c | 356 >>>>>> +++++++++++++++++++++++++++++++++++++++++------------- >>>>>>>>>> 2 files changed, 328 insertions(+), 87 deletions(-) >>>>>>>>>> >>>>>>>>>> diff --git a/INSTALL.DPDK.md b/INSTALL.DPDK.md >>>>>>>>>> index 96b686c..2f23e27 100644 >>>>>>>>>> --- a/INSTALL.DPDK.md >>>>>>>>>> +++ b/INSTALL.DPDK.md >>>>>>>>>> @@ -859,10 +859,61 @@ by adding the following string: >>>>>>>>>> to <interface> sections of all network devices used by >>>> DPDK. Parameter 'N' >>>>>>>>>> determines how many queues can be used by the guest. >>>>>>>>>> >>>>>>>>>> + >>>>>>>>>> +Jumbo Frames >>>>>>>>>> +------------ >>>>>>>>>> + >>>>>>>>>> +Support for Jumbo Frames may be enabled at run-time for >> DPDK-type ports. >>>>>>>>>> + >>>>>>>>>> +To avail of Jumbo Frame support, add the '--dpdk-mtu' option to >>>>>> the ovs-vsctl >>>>>>>>>> +'add-port' command-line, along with the required MTU for the port. >>>>>>>>>> +e.g. >>>>>>>>> >>>>>>>>>This text and the example do not match. I think '--dpdk-mtu' is >> not valid. >>>>>>>> >>>>>>>>Good catch, thanks. >>>>>>>> >>>>>>>>> >>>>>>>>>> + >>>>>>>>>> + ``` >>>>>>>>>> + ovs-vsctl add-port br0 dpdk0 -- set Interface dpdk0 type=dpdk >>>>>> options:dpdk-mtu=9000 >>>>>>>>>> + ``` >>>>>>>>>> + >>>>>>>>>> +When Jumbo Frames are enabled, the size of a DPDK port's mbuf >>>> segments are >>>>>>>>>> +increased, such that a full Jumbo Frame may be accommodated >>>>>> inside a single >>>>>>>>>> +mbuf segment. Once set, the MTU for a DPDK port is immutable. >>>>>>>>> >>>>>>>>>Why no support? DPDK supports changing the mtu. >>>>>>>> >>>>>>>>I guess my rationale here is that an MTU change can't be triggered >>>>>> via OVS command-line, nor >>>>>>>>can it be triggered programmatically via DPDK (apart from an >>>> explicit call to >>>>>>>>rte_eth_dev_set_mtu). >>>>>>>>So, while technically it's possibly, from a user's point of view, >>>>>> there's no way to >>>>>>>configure >>>>>>>>it, outside of modifying the code directly. If I've missed something >>>>>> here, please let me >>>>>>>>know. >>>>>>>> >>>>>>>>> >>>>>>>>>> +Jumbo frame support has been validated against 13312B >> frames, using the >>>>>>>>>> +DPDK `igb_uio` driver, but larger frames and other DPDK NIC >> drivers may >>>>>>>>>> +theoretically be supported. Supported port types excludes >>>>>> vHost-Cuse ports, as >>>>>>>>>> +this feature is pending deprecation. >>>>>>>>>> + >>>>>>>>>> + >>>>>>>>>> +vHost Ports and Jumbo Frames >>>>>>>>>> +---------------------------- >>>>>>>>>> +Jumbo frame support is available for DPDK vHost-User ports >>>>>> only. Some additional >>>>>>>>>> +configuration is needed to take advantage of this feature: >>>>>>>>>> + >>>>>>>>>> + 1. `mergeable buffers` must be enabled for vHost ports, as >>>>>> demonstrated in >>>>>>>>>> + the QEMU command line snippet below: >>>>>>>>>> + >>>>>>>>>> + ``` >>>>>>>>>> + '-netdev type=vhost-user,id=mynet1,chardev=char0,vhostforce \' >>>>>>>>>> + '-device >>>>>> virtio-net-pci,mac=00:00:00:00:00:01,netdev=mynet1,mrg_rxbuf=on' >>>>>>>>>> + ``` >>>>>>>>>> + >>>>>>>>>> + 2. Where virtio devices are bound to the Linux kernel driver >>>> in a guest >>>>>>>>>> + environment (i.e. interfaces are not bound to an in-guest DPDK >>>>>> driver), the >>>>>>>>>> + MTU of those logical network interfaces must also be >>>> increased. This >>>>>>>>>> + avoids segmentation of Jumbo Frames in the guest. Note that >>>>>> 'MTU' refers >>>>>>>>>> + to the length of the IP packet only, and not that of the entire >>>>>> frame. >>>>>>>>>> + >>>>>>>>>> + e.g. To calculate the exact MTU of a standard IPv4 frame, >>>>>> subtract the L2 >>>>>>>>>> + header and CRC lengths (i.e. 18B) from the max supported >>>> frame size. >>>>>>>>>> + So, to set the MTU for a 13312B Jumbo Frame: >>>>>>>>>> + >>>>>>>>>> + ``` >>>>>>>>>> + ifconfig eth1 mtu 13294 >>>>>>>>>> + ``` >>>>>>>>>> + >>>>>>>>>> + >>>>>>>>>> Restrictions: >>>>>>>>>> ------------- >>>>>>>>>> >>>>>>>>>> - - Work with 1500 MTU, needs few changes in DPDK lib to fix >> this issue. >>>>>>>>>> - Currently DPDK port does not make use any offload functionality. >>>>>>>>>> - DPDK-vHost support works with 1G huge pages. >>>>>>>>>> >>>>>>>>>> @@ -903,6 +954,12 @@ Restrictions: >>>>>>>>>> the next release of DPDK (which includes the above patch) is >>>>>> available and >>>>>>>>>> integrated into OVS. >>>>>>>>>> >>>>>>>>>> + Jumbo Frames: >>>>>>>>>> + - `virtio-pmd`: DPDK apps in the guest do not exit >>>>>> gracefully. The source of >>>>>>>>>> + this issue is currently being investigated. >>>>>>>>>> + - vHost-Cuse: Jumbo Frame support is not available for vHost >>>> Cuse ports. >>>>>>>>>> + >>>>>>>>>> + >>>>>>>>>> Bug Reporting: >>>>>>>>>> -------------- >>>>>>>>>> >>>>>>>>>> diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c >>>>>>>>>> index de7e488..5f23e28 100644 >>>>>>>>>> --- a/lib/netdev-dpdk.c >>>>>>>>>> +++ b/lib/netdev-dpdk.c >>>>>>>>>> @@ -62,20 +62,25 @@ static struct vlog_rate_limit rl = >>>>>> VLOG_RATE_LIMIT_INIT(5, 20); >>>>>>>>>> #define OVS_CACHE_LINE_SIZE CACHE_LINE_SIZE >>>>>>>>>> #define OVS_VPORT_DPDK "ovs_dpdk" >>>>>>>>>> >>>>>>>>>> +#define NETDEV_DPDK_JUMBO_FRAME_ENABLED 1 >>>>>>>>>> +#define NETDEV_DPDK_DEFAULT_RX_BUFSIZE 1024 >>>>>>>>>> + >>>>>>>>>> /* >>>>>>>>>> * need to reserve tons of extra space in the mbufs so we can >> align the >>>>>>>>>> * DMA addresses to 4KB. >>>>>>>>>> * The minimum mbuf size is limited to avoid scatter behaviour >>>> and drop in >>>>>>>>>> * performance for standard Ethernet MTU. >>>>>>>>>> */ >>>>>>>>>> -#define MTU_TO_MAX_LEN(mtu) ((mtu) + ETHER_HDR_LEN + ETHER_CRC_LEN) >>>>>>>>>> -#define MBUF_SIZE_MTU(mtu) (MTU_TO_MAX_LEN(mtu) \ >>>>>>>>>> - + sizeof(struct dp_packet) \ >>>>>>>>>> - + RTE_PKTMBUF_HEADROOM) >>>>>>>>>> -#define MBUF_SIZE_DRIVER (2048 \ >>>>>>>>>> - + sizeof (struct rte_mbuf) \ >>>>>>>>>> - + RTE_PKTMBUF_HEADROOM) >>>>>>>>>> -#define MBUF_SIZE(mtu) MAX(MBUF_SIZE_MTU(mtu), >>>>>>>>>> MBUF_SIZE_DRIVER) >>>>>>>>>> +#define MTU_TO_FRAME_LEN(mtu) ((mtu) + ETHER_HDR_LEN + >>>>>> ETHER_CRC_LEN) >>>>>>>>>> +#define FRAME_LEN_TO_MTU(frame_len) ((frame_len)- ETHER_HDR_LEN >>>>>> - ETHER_CRC_LEN) >>>>>>>>>> +#define MBUF_SEGMENT_SIZE(mtu) ( MTU_TO_FRAME_LEN(mtu) \ >>>>>>>>>> + + sizeof(struct dp_packet) \ >>>>>>>>>> + + RTE_PKTMBUF_HEADROOM) >>>>>>>>>> + >>>>>>>>>> +/* This value should be specified as a multiple of the DPDK >> NIC driver's >>>>>>>>>> + * 'min_rx_bufsize' attribute (currently 1024B for 'igb_uio'). >>>>>>>>>> + */ >>>>>>>>>> +#define NETDEV_DPDK_MAX_FRAME_LEN 13312 >>>>>>>>>> >>>>>>>>>> /* Max and min number of packets in the mempool. OVS tries to >>>> allocate a >>>>>>>>>> * mempool with MAX_NB_MBUF: if this fails (because the system >>>>>> doesn't have >>>>>>>>>> @@ -86,6 +91,8 @@ static struct vlog_rate_limit rl = >>>>>> VLOG_RATE_LIMIT_INIT(5, 20); >>>>>>>>>> #define MIN_NB_MBUF (4096 * 4) >>>>>>>>>> #define MP_CACHE_SZ RTE_MEMPOOL_CACHE_MAX_SIZE >>>>>>>>>> >>>>>>>>>> +#define DPDK_VLAN_TAG_LEN 4 >>>>>>>>>> + >>>>>>>>>> /* MAX_NB_MBUF can be divided by 2 many times, until MIN_NB_MBUF */ >>>>>>>>>> BUILD_ASSERT_DECL(MAX_NB_MBUF % >>>>>> ROUND_DOWN_POW2(MAX_NB_MBUF/MIN_NB_MBUF) == 0); >>>>>>>>>> >>>>>>>>>> @@ -114,7 +121,6 @@ static const struct rte_eth_conf port_conf = { >>>>>>>>>> .header_split = 0, /* Header Split disabled */ >>>>>>>>>> .hw_ip_checksum = 0, /* IP checksum offload disabled */ >>>>>>>>>> .hw_vlan_filter = 0, /* VLAN filtering disabled */ >>>>>>>>>> - .jumbo_frame = 0, /* Jumbo Frame Support disabled */ >>>>>>>>>> .hw_strip_crc = 0, >>>>>>>>>> }, >>>>>>>>>> .rx_adv_conf = { >>>>>>>>>> @@ -254,6 +260,39 @@ is_dpdk_class(const struct netdev_class *class) >>>>>>>>>> return class->construct == netdev_dpdk_construct; >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> +/* DPDK NIC drivers allocate RX buffers at a particular granularity >>>>>>>>>> + * (specified by rte_eth_dev_info.min_rx_bufsize - currently 1K >>>>>> for igb_uio). >>>>>>>>>> + * If 'frame_len' is not a multiple of this value, insufficient >>>>>> buffers are >>>>>>>>>> + * allocated to accomodate the packet in its >>>>>> entirety. Furthermore, the igb_uio >>>>>>>>>> + * driver needs to ensure that there is also sufficient space in >>>>>> the Rx buffer >>>>>>>>>> + * to accommodate two VLAN tags (for QinQ frames). If the RX >>>> buffer is too >>>>>>>>>> + * small, then the driver enables scatter RX behaviour, which >>>>>>>>>> reduces >>>>>>>>>> + * performance. To prevent this, use a buffer size that is closest >>>>>>>>>> to >>>>>>>>>> + * 'frame_len', but which satisfies the aforementioned criteria. >>>>>>>>>> + */ >>>>>>>>>> +static uint32_t >>>>>>>>>> +dpdk_buf_size(struct netdev_dpdk *netdev, int frame_len) >>>>>>>>>> +{ >>>>>>>>>> + struct rte_eth_dev_info info; >>>>>>>>>> + uint32_t buf_size; >>>>>>>>>> + uint32_t len = frame_len + (2 * DPDK_VLAN_TAG_LEN); >>>>>>>>>> + >>>>>>>>>> + if(netdev->type == DPDK_DEV_ETH) { >>>>>>>>>> + rte_eth_dev_info_get(netdev->port_id, &info); >>>>>>>>>> + buf_size = (info.min_rx_bufsize == 0) ? >>>>>>>>>> + NETDEV_DPDK_DEFAULT_RX_BUFSIZE : >>>>>>>>>> + info.min_rx_bufsize; >>>>>>>>> >>>>>>>>>Why not use the rte_eth_dev_get_mtu call to get the port configured >>>>>>>>>mtu? >>>>>>>> >>>>>>>>I'm not sure if I follow - the MTU isn't the issue here, but rather >>>>>> the buffer size used >>>>>>>>when creating the rte_mempool, which must be a multiple of the >>>>>> driver's min_rx_bufsize. >>>>>>>> >>>>>>>>> >>>>>>>>>> + } else { >>>>>>>>>> + buf_size = NETDEV_DPDK_DEFAULT_RX_BUFSIZE; >>>>>>>>>> + } >>>>>>>>>> + >>>>>>>>>> + if(len % buf_size) { >>>>>>>>>> + len = buf_size * ((len/buf_size) + 1); >>>>>>>>>> + } >>>>>>>>>> + >>>>>>>>>> + return len; >>>>>>>>>> +} >>>>>>>>>> + >>>>>>>>>> /* XXX: use dpdk malloc for entire OVS. in fact huge page >> should be used >>>>>>>>>> * for all other segments data, bss and text. */ >>>>>>>>>> >>>>>>>>>> @@ -280,31 +319,70 @@ free_dpdk_buf(struct dp_packet *p) >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> static void >>>>>>>>>> -__rte_pktmbuf_init(struct rte_mempool *mp, >>>>>>>>>> - void *opaque_arg OVS_UNUSED, >>>>>>>>>> - void *_m, >>>>>>>>>> - unsigned i OVS_UNUSED) >>>>>>>>>> +ovs_rte_pktmbuf_pool_init(struct rte_mempool *mp, void *opaque_arg) >>>>>>>>>> { >>>>>>>>>> - struct rte_mbuf *m = _m; >>>>>>>>>> - uint32_t buf_len = mp->elt_size - sizeof(struct dp_packet); >>>>>>>>>> + struct rte_pktmbuf_pool_private *user_mbp_priv, *mbp_priv; >>>>>>>>>> + struct rte_pktmbuf_pool_private default_mbp_priv; >>>>>>>>>> + uint16_t roomsz; >>>>>>>>>> >>>>>>>>>> RTE_MBUF_ASSERT(mp->elt_size >= sizeof(struct dp_packet)); >>>>>>>>>> >>>>>>>>>> - memset(m, 0, mp->elt_size); >>>>>>>>>> + /* if no structure is provided, assume no mbuf private area */ >>>>>>>>>> + >>>>>>>>>> + user_mbp_priv = opaque_arg; >>>>>>>>>> + if (user_mbp_priv == NULL) { >>>>>>>>>> + default_mbp_priv.mbuf_priv_size = 0; >>>>>>>>>> + if (mp->elt_size > sizeof(struct dp_packet)) { >>>>>>>>>> + roomsz = mp->elt_size - sizeof(struct dp_packet); >>>>>>>>>> + } else { >>>>>>>>>> + roomsz = 0; >>>>>>>>>> + } >>>>>>>>>> + default_mbp_priv.mbuf_data_room_size = roomsz; >>>>>>>>>> + user_mbp_priv = &default_mbp_priv; >>>>>>>>>> + } >>>>>>>>>> + >>>>>>>>>> + RTE_MBUF_ASSERT(mp->elt_size >= sizeof(struct dp_packet) + >>>>>>>>>> + user_mbp_priv->mbuf_data_room_size + >>>>>>>>>> + user_mbp_priv->mbuf_priv_size); >>>>>>>>>> + >>>>>>>>>> + mbp_priv = rte_mempool_get_priv(mp); >>>>>>>>>> + memcpy(mbp_priv, user_mbp_priv, sizeof(*mbp_priv)); >>>>>>>>>> +} >>>>>>>>>> + >>>>>>>>>> +/* Initialise some fields in the mbuf structure that are not >>>>>> modified by the >>>>>>>>>> + * user once created (origin pool, buffer start address, etc.*/ >>>>>>>>>> +static void >>>>>>>>>> +__ovs_rte_pktmbuf_init(struct rte_mempool *mp, >>>>>>>>>> + void *opaque_arg OVS_UNUSED, >>>>>>>>>> + void *_m, >>>>>>>>>> + unsigned i OVS_UNUSED) >>>>>>>>>> +{ >>>>>>>>>> + struct rte_mbuf *m = _m; >>>>>>>>>> + uint32_t buf_size, buf_len, priv_size; >>>>>>>>>> + >>>>>>>>>> + priv_size = rte_pktmbuf_priv_size(mp); >>>>>>>>>> + buf_size = sizeof(struct dp_packet) + priv_size; >>>>>>>>>> + buf_len = rte_pktmbuf_data_room_size(mp); >>>>>>>>>> >>>>>>>>>> - /* start of buffer is just after mbuf structure */ >>>>>>>>>> - m->buf_addr = (char *)m + sizeof(struct dp_packet); >>>>>>>>>> - m->buf_physaddr = rte_mempool_virt2phy(mp, m) + >>>>>>>>>> - sizeof(struct dp_packet); >>>>>>>>>> - m->buf_len = (uint16_t)buf_len; >>>>>>>>>> + RTE_MBUF_ASSERT(RTE_ALIGN(priv_size, RTE_MBUF_PRIV_ALIGN) == >>>> priv_size); >>>>>>>>>> + RTE_MBUF_ASSERT(mp->elt_size >= buf_size); >>>>>>>>>> + RTE_MBUF_ASSERT(buf_len <= UINT16_MAX); >>>>>>>>>> >>>>>>>>>> - /* keep some headroom between start of buffer and data */ >>>>>>>>>> - m->data_off = RTE_MIN(RTE_PKTMBUF_HEADROOM, m->buf_len); >>>>>>>>>> + memset(m, 0, mp->elt_size); >>>>>>>>>> >>>>>>>>>> - /* init some constant fields */ >>>>>>>>>> - m->pool = mp; >>>>>>>>>> - m->nb_segs = 1; >>>>>>>>>> - m->port = 0xff; >>>>>>>>>> + /* start of buffer is after dp_packet structure and priv data */ >>>>>>>>>> + m->priv_size = priv_size; >>>>>>>>>> + m->buf_addr = (char *)m + buf_size; >>>>>>>>>> + m->buf_physaddr = rte_mempool_virt2phy(mp, m) + buf_size; >>>>>>>>>> + m->buf_len = (uint16_t)buf_len; >>>>>>>>>> + >>>>>>>>>> + /* keep some headroom between start of buffer and data */ >>>>>>>>>> + m->data_off = RTE_MIN(RTE_PKTMBUF_HEADROOM, >>>> (uint16_t)m->buf_len); >>>>>>>>>> + >>>>>>>>>> + /* init some constant fields */ >>>>>>>>>> + m->pool = mp; >>>>>>>>>> + m->nb_segs = 1; >>>>>>>>>> + m->port = 0xff; >>>>>>>>> >>>>>>>>>Please don't mix tabs and spaces in the file. >>>>>>>> >>>>>>>>Apologies - this was a copy/paste from a DPDK file, which uses tabs. >>>>>>>> >>>>>>>>> >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> static void >>>>>>>>>> @@ -315,7 +393,7 @@ ovs_rte_pktmbuf_init(struct rte_mempool *mp, >>>>>>>>>> { >>>>>>>>>> struct rte_mbuf *m = _m; >>>>>>>>>> >>>>>>>>>> - __rte_pktmbuf_init(mp, opaque_arg, _m, i); >>>>>>>>>> + __ovs_rte_pktmbuf_init(mp, opaque_arg, m, i); >>>>>>>>>> >>>>>>>>>> dp_packet_init_dpdk((struct dp_packet *) m, m->buf_len); >>>>>>>>>> } >>>>>>>>>> @@ -326,6 +404,7 @@ dpdk_mp_get(int socket_id, int mtu) >>>>>> OVS_REQUIRES(dpdk_mutex) >>>>>>>>>> struct dpdk_mp *dmp = NULL; >>>>>>>>>> char mp_name[RTE_MEMPOOL_NAMESIZE]; >>>>>>>>>> unsigned mp_size; >>>>>>>>>> + struct rte_pktmbuf_pool_private mbp_priv; >>>>>>>>>> >>>>>>>>>> LIST_FOR_EACH (dmp, list_node, &dpdk_mp_list) { >>>>>>>>>> if (dmp->socket_id == socket_id && dmp->mtu == mtu) { >>>>>>>>>> @@ -338,6 +417,8 @@ dpdk_mp_get(int socket_id, int mtu) >>>>>> OVS_REQUIRES(dpdk_mutex) >>>>>>>>>> dmp->socket_id = socket_id; >>>>>>>>>> dmp->mtu = mtu; >>>>>>>>>> dmp->refcount = 1; >>>>>>>>>> + mbp_priv.mbuf_data_room_size = MTU_TO_FRAME_LEN(mtu) + >>>>>> RTE_PKTMBUF_HEADROOM; >>>>>>>>>> + mbp_priv.mbuf_priv_size = 0; >>>>>>>>>> >>>>>>>>>> mp_size = MAX_NB_MBUF; >>>>>>>>>> do { >>>>>>>>>> @@ -346,10 +427,10 @@ dpdk_mp_get(int socket_id, int mtu) >>>>>> OVS_REQUIRES(dpdk_mutex) >>>>>>>>>> return NULL; >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> - dmp->mp = rte_mempool_create(mp_name, mp_size, >>>>>>>>>> MBUF_SIZE(mtu), >>>>>>>>>> + dmp->mp = rte_mempool_create(mp_name, mp_size, >>>>>> MBUF_SEGMENT_SIZE(mtu), >>>>>>>>>> MP_CACHE_SZ, >>>>>>>>>> sizeof(struct rte_pktmbuf_pool_private), >>>>>>>>>> - rte_pktmbuf_pool_init, NULL, >>>>>>>>>> + ovs_rte_pktmbuf_pool_init, &mbp_priv, >>>>>>>>>> ovs_rte_pktmbuf_init, NULL, >>>>>>>>>> socket_id, 0); >>>>>>>>>> } while (!dmp->mp && rte_errno == ENOMEM && (mp_size /= 2) >= >>>>>> MIN_NB_MBUF); >>>>>>>>>> @@ -433,6 +514,7 @@ dpdk_eth_dev_queue_setup(struct netdev_dpdk >>>>>> *dev, int n_rxq, int >>>>>>>>n_txq) >>>>>>>>>> { >>>>>>>>>> int diag = 0; >>>>>>>>>> int i; >>>>>>>>>> + struct rte_eth_conf conf = port_conf; >>>>>>>>>> >>>>>>>>>> /* A device may report more queues than it makes available >> (this has >>>>>>>>>> * been observed for Intel xl710, which reserves some of them >>>>>>>>>> for >>>>>>>>>> @@ -444,7 +526,12 @@ dpdk_eth_dev_queue_setup(struct netdev_dpdk >>>>>> *dev, int n_rxq, int >>>>>>>>>n_txq) >>>>>>>>>> VLOG_INFO("Retrying setup with (rxq:%d txq:%d)", n_rxq, n_txq); >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> - diag = rte_eth_dev_configure(dev->port_id, n_rxq, n_txq, >>>>>> &port_conf); >>>>>>>>>> + if(OVS_UNLIKELY(dev->mtu > ETHER_MTU)) { >>>>>>>>>> + conf.rxmode.jumbo_frame = >>>>>>>>>> NETDEV_DPDK_JUMBO_FRAME_ENABLED; >>>>>>>>>> + conf.rxmode.max_rx_pkt_len = MTU_TO_FRAME_LEN(dev->mtu); >>>>>>>>>> + } >>>>>>>>>> + >>>>>>>>>> + diag = rte_eth_dev_configure(dev->port_id, n_rxq, n_txq, >> &conf); >>>>>>>>>> if (diag) { >>>>>>>>>> break; >>>>>>>>>> } >>>>>>>>>> @@ -586,6 +673,7 @@ netdev_dpdk_init(struct netdev *netdev_, >>>>>> unsigned int port_no, >>>>>>>>>> struct netdev_dpdk *netdev = netdev_dpdk_cast(netdev_); >>>>>>>>>> int sid; >>>>>>>>>> int err = 0; >>>>>>>>>> + uint32_t buf_size; >>>>>>>>>> >>>>>>>>>> ovs_mutex_init(&netdev->mutex); >>>>>>>>>> ovs_mutex_lock(&netdev->mutex); >>>>>>>>>> @@ -605,10 +693,16 @@ netdev_dpdk_init(struct netdev *netdev_, >>>>>> unsigned int port_no, >>>>>>>>>> netdev->port_id = port_no; >>>>>>>>>> netdev->type = type; >>>>>>>>>> netdev->flags = 0; >>>>>>>>>> + >>>>>>>>>> + /* Initialize port's MTU and frame len to the default >>>> Ethernet values. >>>>>>>>>> + * Larger, user-specified (jumbo) frame buffers are >> accommodated in >>>>>>>>>> + * netdev_dpdk_set_config. >>>>>>>>>> + */ >>>>>>>>>> + netdev->max_packet_len = ETHER_MAX_LEN; >>>>>>>>>> netdev->mtu = ETHER_MTU; >>>>>>>>>> - netdev->max_packet_len = MTU_TO_MAX_LEN(netdev->mtu); >>>>>>>>>> >>>>>>>>>> - netdev->dpdk_mp = dpdk_mp_get(netdev->socket_id, netdev->mtu); >>>>>>>>>> + buf_size = dpdk_buf_size(netdev, ETHER_MAX_LEN); >>>>>>>>>> + netdev->dpdk_mp = dpdk_mp_get(netdev->socket_id, >>>>>> FRAME_LEN_TO_MTU(buf_size)); >>>>>>>>>> if (!netdev->dpdk_mp) { >>>>>>>>>> err = ENOMEM; >>>>>>>>>> goto unlock; >>>>>>>>>> @@ -651,6 +745,24 @@ dpdk_dev_parse_name(const char dev_name[], >>>>>> const char prefix[], >>>>>>>>>> return 0; >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> +static void >>>>>>>>>> +dpdk_dev_parse_mtu(const struct smap *args, int *mtu) >>>>>>>>>> +{ >>>>>>>>>> + const char *mtu_str = smap_get(args, "dpdk-mtu"); >>>>>>>>>> + int local_mtu; >>>>>>>>>> + >>>>>>>>>> + if(mtu_str) { >>>>>>>>>> + local_mtu = atoi(mtu_str); >>>>>>>>> >>>>>>>>>Please use strtol or strtoul here, and detect errors in the string by >>>>>>>>>checking endptr. That way, we can be sure that random garbage on the >>>>>>>>>stack won't accidentally become the mtu. >>>>>>>> >>>>>>>>Will do, thanks. >>>>>>>> >>>>>>>>> >>>>>>>>>> + } >>>>>>>>>> + if(!mtu_str || local_mtu < ETHER_MTU || >>>>>>>>>> + local_mtu > FRAME_LEN_TO_MTU(NETDEV_DPDK_MAX_FRAME_LEN)) { >>>>>>>>>> + local_mtu = ETHER_MTU; >>>>>>>>>> + VLOG_WARN("Invalid or missing dpdk-mtu parameter - defaulting >>>>>> to %d.\n", >>>>>>>>>> + local_mtu); >>>>>>>>>> + } >>>>>>>>>> + *mtu = local_mtu; >>>>>>>>>> +} >>>>>>>>>> + >>>>>>>>>> static int >>>>>>>>>> vhost_construct_helper(struct netdev *netdev_) >> OVS_REQUIRES(dpdk_mutex) >>>>>>>>>> { >>>>>>>>>> @@ -777,11 +889,77 @@ netdev_dpdk_get_config(const struct netdev >>>>>> *netdev_, struct smap >>>>>>>>>*args) >>>>>>>>>> smap_add_format(args, "configured_rx_queues", "%d", >> netdev_->n_rxq); >>>>>>>>>> smap_add_format(args, "requested_tx_queues", "%d", >> netdev_->n_txq); >>>>>>>>>> smap_add_format(args, "configured_tx_queues", "%d", >>>> dev->real_n_txq); >>>>>>>>>> + smap_add_format(args, "mtu", "%d", dev->mtu); >>>>>>>>>> ovs_mutex_unlock(&dev->mutex); >>>>>>>>>> >>>>>>>>>> return 0; >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> +/* Set the mtu of DPDK_DEV_ETH ports */ >>>>>>>>>> +static int >>>>>>>>>> +netdev_dpdk_set_mtu(const struct netdev *netdev, int mtu) >>>>>>>>>> +{ >>>>>>>>>> + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); >>>>>>>>>> + int old_mtu, err; >>>>>>>>>> + uint32_t buf_size; >>>>>>>>>> + int dpdk_mtu; >>>>>>>>>> + struct dpdk_mp *old_mp; >>>>>>>>>> + struct dpdk_mp *mp; >>>>>>>>>> + >>>>>>>>>> + ovs_mutex_lock(&dpdk_mutex); >>>>>>>>>> + ovs_mutex_lock(&dev->mutex); >>>>>>>>>> + if (dev->mtu == mtu) { >>>>>>>>>> + err = 0; >>>>>>>>>> + goto out; >>>>>>>>>> + } >>>>>>>>>> + >>>>>>>>>> + buf_size = dpdk_buf_size(dev, MTU_TO_FRAME_LEN(mtu)); >>>>>>>>>> + dpdk_mtu = FRAME_LEN_TO_MTU(buf_size); >>>>>>>>>> + >>>>>>>>>> + mp = dpdk_mp_get(dev->socket_id, dpdk_mtu); >>>>>>>>>> + if (!mp) { >>>>>>>>>> + err = ENOMEM; >>>>>>>>>> + goto out; >>>>>>>>>> + } >>>>>>>>>> + >>>>>>>>>> + rte_eth_dev_stop(dev->port_id); >>>>>>>>>> + >>>>>>>>>> + old_mtu = dev->mtu; >>>>>>>>>> + old_mp = dev->dpdk_mp; >>>>>>>>>> + dev->dpdk_mp = mp; >>>>>>>>>> + dev->mtu = mtu; >>>>>>>>>> + dev->max_packet_len = MTU_TO_FRAME_LEN(dev->mtu); >>>>>>>>>> + >>>>>>>>>> + err = dpdk_eth_dev_init(dev); >>>>>>>>> >>>>>>>>>Why call the dpdk_eth_dev_init here? Since you are directly calling >>>>>>>>>rte_eth_dev_X functions here - wouldn't it make sense to use the >>>>>>>>>rte_eth_dev_start() instead? >>>>>> >>>>>> The rx queues for the device need to be assigned the mempool that was >>>>>> allocated for the jumbo frames; since dpdk_eth_dev_init handles the >>>>>> queue setup, rte_eth_dev configuration, etc. it makes sense to call it >>>>>> here. >>>>>> >>>>>>>> >>>>>>>>This is legacy code, but I can refactor if needs be. >>>>>>>> >>>>>>>>> >>>>>>>>>> + if (err) { >>>>>>>>>> + VLOG_WARN("Unable to set MTU '%d' for '%s'; reverting to last >>>>>> known " >>>>>>>>>> + "good value '%d'\n", mtu, dev->up.name, old_mtu); >>>>>>>>>> + dpdk_mp_put(mp); >>>>>>>>>> + dev->mtu = old_mtu; >>>>>>>>>> + dev->dpdk_mp = old_mp; >>>>>>>>>> + dev->max_packet_len = MTU_TO_FRAME_LEN(dev->mtu); >>>>>>>>>> + err = dpdk_eth_dev_init(dev); >>>>>>>>> >>>>>>>>>What happens if this returns a failure? By using dpdk_eth_dev_init, you >>>>>>>>>will cause a queue reconfiguration action, which is not needed, and can >>>>>>>>>error. >>>>>> >>>>>> This call is needed, in case the eth_dev's queue configuration was >>>>>> changed by the previous call. >>>>>> The error handling for this call is arguably outside the scope of this >>>>>> patch, and could be submitted as a separate patch - what do you think? >>>>> >>>>>That's probably a good idea. >>>>> >>>>>>>>> >>>>>>>> >>>>>>>>As above. >>>>>>>> >>>>>>>>>If you are intending to set MTU, I would have expected calls to >>>>>>>>>rte_eth_dev_set_mtu. However, I don't see any. Is there a reason? I >>>>>>>>>recognize that much of this is legacy, but since you are touching it :) >>>>>>>> >>>>>>>>I actually had a number of issues with rte_eth_dev_set_mtu early on >>>>>> in the patch; I can take >>>>>>>>a second look now that the code is more stable though. >>>>>>> >>>>>>>I remembered why I didn't use this. >>>>>>> >>>>>>>If you look at the IXGBE driver's mtu_set function, it refuses frame >>>>>> lengths which are larger >>>>>>>than the eth_dev's min_rx_buf_size (- RTE_PKTMBUF_HEADROOM). >>>>>>>This might be avoided by configuring the device for scatter RX >>>>>> behavior, but this incurs a >>>>>>>performance impact. >>>>> >>>>>It seems strange to me that we need to ignore the library API for this >>>>>one case, right? What if the user is only doing vhostuser PMDs mixed >>>>>with a bnx2x card? >>>>> >>>> >>>> I can't say that I've familiar enough with this setup to form an >>>> answer on that one Aaron. >>>> >>>>>It would be better to get it fixed in the library, I think. After all, >>>>>they gave a generic setting to change MTU - why don't they make it >>>>>behave well? >>>>> >>>> >>>> Let me follow up on that with some local DPDK folks here. >>>> >> >> Just a quick follow up on this Aaron: I did implement a version of >> this patch that used rte_eth_dev_set_mtu; however, not all DPDK >> drivers yet implement that function (e.g. i40e), so I reverted to the >> previous version. >> DPDK team did mention that the _set_mtu function for i40e should be >> implemented 'soon', but no dates were specified. See this thread on >> the DPDK ML for more details: >> http://dpdk.org/ml/archives/dev/2016-February/032910.html > >Thanks so much for that, it's good to know. I guess we need to wait for >them to fully implement their api before calling it, so I'm okay with >this change.
Perfect - thanks again for your review and feedback on this patch! > >>>> Would you consider this a showstopper for upstreaming of this feature? >>>> If we need to wait for a change to DPDK, Jumbo Frames will miss the >>>> 2.5 window. >>> >>>I don't think it would be a show stopper as long as other devices wouldn't >>>be negatively impacted, but it's a place where a /*XXX: This is a >>>workaround for dpdk*/ comment should be included so that we can fix it >>>when/if it is updated in the library. What do you think? >>> >>>>>>><snippet> >>>>>>>ixgbe_dev_mtu_set(...) { >>>>>>> >>>>>>>... >>>>>>> >>>>>>> /* refuse mtu that requires the support of scattered packets when >>>>>>> this >>>>>>> * feature has not been enabled before. */ >>>>>>> if (!dev->data->scattered_rx && >>>>>>> (frame_size + 2 * IXGBE_VLAN_TAG_SIZE > >>>>>>> dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM)) >>>>>>> return -EINVAL; >>>>>>> >>>>>>>... >>>>>>>} >>>>>>></snippet> >>>>>>> >>>>>>> >>>>>>>> >>>>>>>>> >>>>>>>>>> + goto out; >>>>>>>>>> + } >>>>>>>>>> + >>>>>>>>>> + dpdk_mp_put(old_mp); >>>>>>>>>> + netdev_change_seq_changed(netdev); >>>>>>>>>> +out: >>>>>>>>>> + ovs_mutex_unlock(&dev->mutex); >>>>>>>>>> + ovs_mutex_unlock(&dpdk_mutex); >>>>>>>>>> + return err; >>>>>>>>>> +} >>>>>>>>>> + >>>>>>>>>> +static int >>>>>>>>>> +netdev_dpdk_set_config(struct netdev *netdev_, const struct >> smap *args) >>>>>>>>>> +{ >>>>>>>>>> + int mtu; >>>>>>>>>> + >>>>>>>>>> + dpdk_dev_parse_mtu(args, &mtu); >>>>>>>>>> + >>>>>>>>>> + return netdev_dpdk_set_mtu(netdev_, mtu); >>>>>>>>>> +} >>>>>>>>>> + >>>>>>>>>> static int >>>>>>>>>> netdev_dpdk_get_numa_id(const struct netdev *netdev_) >>>>>>>>>> { >>>>>>>>>> @@ -1358,54 +1536,6 @@ netdev_dpdk_get_mtu(const struct netdev >>>>>> *netdev, int *mtup) >>>>>>>>>> >>>>>>>>>> return 0; >>>>>>>>>> } >>>>>>>>>> - >>>>>>>>>> -static int >>>>>>>>>> -netdev_dpdk_set_mtu(const struct netdev *netdev, int mtu) >>>>>>>>>> -{ >>>>>>>>>> - struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); >>>>>>>>>> - int old_mtu, err; >>>>>>>>>> - struct dpdk_mp *old_mp; >>>>>>>>>> - struct dpdk_mp *mp; >>>>>>>>>> - >>>>>>>>>> - ovs_mutex_lock(&dpdk_mutex); >>>>>>>>>> - ovs_mutex_lock(&dev->mutex); >>>>>>>>>> - if (dev->mtu == mtu) { >>>>>>>>>> - err = 0; >>>>>>>>>> - goto out; >>>>>>>>>> - } >>>>>>>>>> - >>>>>>>>>> - mp = dpdk_mp_get(dev->socket_id, dev->mtu); >>>>>>>>>> - if (!mp) { >>>>>>>>>> - err = ENOMEM; >>>>>>>>>> - goto out; >>>>>>>>>> - } >>>>>>>>>> - >>>>>>>>>> - rte_eth_dev_stop(dev->port_id); >>>>>>>>>> - >>>>>>>>>> - old_mtu = dev->mtu; >>>>>>>>>> - old_mp = dev->dpdk_mp; >>>>>>>>>> - dev->dpdk_mp = mp; >>>>>>>>>> - dev->mtu = mtu; >>>>>>>>>> - dev->max_packet_len = MTU_TO_MAX_LEN(dev->mtu); >>>>>>>>>> - >>>>>>>>>> - err = dpdk_eth_dev_init(dev); >>>>>>>>>> - if (err) { >>>>>>>>>> - dpdk_mp_put(mp); >>>>>>>>>> - dev->mtu = old_mtu; >>>>>>>>>> - dev->dpdk_mp = old_mp; >>>>>>>>>> - dev->max_packet_len = MTU_TO_MAX_LEN(dev->mtu); >>>>>>>>>> - dpdk_eth_dev_init(dev); >>>>>>>>>> - goto out; >>>>>>>>>> - } >>>>>>>>>> - >>>>>>>>>> - dpdk_mp_put(old_mp); >>>>>>>>>> - netdev_change_seq_changed(netdev); >>>>>>>>>> -out: >>>>>>>>>> - ovs_mutex_unlock(&dev->mutex); >>>>>>>>>> - ovs_mutex_unlock(&dpdk_mutex); >>>>>>>>>> - return err; >>>>>>>>>> -} >>>>>>>>>> - >>>>>>>>>> static int >>>>>>>>>> netdev_dpdk_get_carrier(const struct netdev *netdev_, bool >>>>>>>>>> *carrier); >>>>>>>>>> >>>>>>>>>> @@ -1682,7 +1812,7 @@ netdev_dpdk_get_status(const struct netdev >>>>>> *netdev_, struct smap >>>>>>>>>*args) >>>>>>>>>> smap_add_format(args, "numa_id", "%d", >>>>>> rte_eth_dev_socket_id(dev->port_id)); >>>>>>>>>> smap_add_format(args, "driver_name", "%s", >>>>>>>>>> dev_info.driver_name); >>>>>>>>>> smap_add_format(args, "min_rx_bufsize", "%u", >>>>>> dev_info.min_rx_bufsize); >>>>>>>>>> - smap_add_format(args, "max_rx_pktlen", "%u", >>>> dev_info.max_rx_pktlen); >>>>>>>>>> + smap_add_format(args, "max_rx_pktlen", "%u", >>>>>>>>>> dev->max_packet_len); >>>>>>>>>> smap_add_format(args, "max_rx_queues", "%u", >>>> dev_info.max_rx_queues); >>>>>>>>>> smap_add_format(args, "max_tx_queues", "%u", >>>> dev_info.max_tx_queues); >>>>>>>>>> smap_add_format(args, "max_mac_addrs", "%u", >>>> dev_info.max_mac_addrs); >>>>>>>>>> @@ -1904,6 +2034,51 @@ dpdk_vhost_user_class_init(void) >>>>>>>>>> return 0; >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> +/* Set the mtu of DPDK_DEV_VHOST ports */ >>>>>>>>>> +static int >>>>>>>>>> +netdev_dpdk_vhost_set_mtu(const struct netdev *netdev, int mtu) >>>>>>>>>> +{ >>>>>>>>>> + struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); >>>>>>>>>> + int err = 0; >>>>>>>>>> + struct dpdk_mp *old_mp; >>>>>>>>>> + struct dpdk_mp *mp; >>>>>>>>>> + >>>>>>>>>> + ovs_mutex_lock(&dpdk_mutex); >>>>>>>>>> + ovs_mutex_lock(&dev->mutex); >>>>>>>>>> + if (dev->mtu == mtu) { >>>>>>>>>> + err = 0; >>>>>>>>>> + goto out; >>>>>>>>>> + } >>>>>>>>>> + >>>>>>>>>> + mp = dpdk_mp_get(dev->socket_id, mtu); >>>>>>>>>> + if (!mp) { >>>>>>>>>> + err = ENOMEM; >>>>>>>>>> + goto out; >>>>>>>>>> + } >>>>>>>>>> + >>>>>>>>>> + old_mp = dev->dpdk_mp; >>>>>>>>>> + dev->dpdk_mp = mp; >>>>>>>>>> + dev->mtu = mtu; >>>>>>>>>> + dev->max_packet_len = MTU_TO_FRAME_LEN(dev->mtu); >>>>>>>>>> + >>>>>>>>>> + dpdk_mp_put(old_mp); >>>>>>>>>> + netdev_change_seq_changed(netdev); >>>>>>>>>> +out: >>>>>>>>>> + ovs_mutex_unlock(&dev->mutex); >>>>>>>>>> + ovs_mutex_unlock(&dpdk_mutex); >>>>>>>>>> + return err; >>>>>>>>>> +} >>>>>>>>>> + >>>>>>>>>> +static int >>>>>>>>>> +netdev_dpdk_vhost_set_config(struct netdev *netdev_, const >>>>>> struct smap *args) >>>>>>>>>> +{ >>>>>>>>>> + int mtu; >>>>>>>>>> + >>>>>>>>>> + dpdk_dev_parse_mtu(args, &mtu); >>>>>>>>>> + >>>>>>>>>> + return netdev_dpdk_vhost_set_mtu(netdev_, mtu); >>>>>>>>>> +} >>>>>>>>>> + >>>>>>>>>> static void >>>>>>>>>> dpdk_common_init(void) >>>>>>>>>> { >>>>>>>>>> @@ -2040,8 +2215,9 @@ unlock_dpdk: >>>>>>>>>> return err; >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> -#define NETDEV_DPDK_CLASS(NAME, INIT, CONSTRUCT, DESTRUCT, >>>> MULTIQ, SEND, \ >>>>>>>>>> - GET_CARRIER, GET_STATS, GET_FEATURES, GET_STATUS, RXQ_RECV) \ >>>>>>>>>> +#define NETDEV_DPDK_CLASS(NAME, INIT, CONSTRUCT, DESTRUCT, >> SET_CONFIG, \ >>>>>>>>>> + MULTIQ, SEND, SET_MTU, GET_CARRIER, GET_STATS, >> GET_FEATURES, \ >>>>>>>>>> + GET_STATUS, RXQ_RECV) \ >>>>>>>>>> { \ >>>>>>>>>> NAME, \ >>>>>>>>>> INIT, /* init */ \ >>>>>>>>>> @@ -2053,7 +2229,7 @@ unlock_dpdk: >>>>>>>>>> DESTRUCT, \ >>>>>>>>>> netdev_dpdk_dealloc, \ >>>>>>>>>> netdev_dpdk_get_config, \ >>>>>>>>>> - NULL, /* netdev_dpdk_set_config */ \ >>>>>>>>>> + SET_CONFIG, \ >>>>>>>>>> NULL, /* get_tunnel_config */ \ >>>>>>>>>> NULL, /* build header */ \ >>>>>>>>>> NULL, /* push header */ \ >>>>>>>>>> @@ -2067,7 +2243,7 @@ unlock_dpdk: >>>>>>>>>> netdev_dpdk_set_etheraddr, \ >>>>>>>>>> netdev_dpdk_get_etheraddr, \ >>>>>>>>>> netdev_dpdk_get_mtu, \ >>>>>>>>>> - netdev_dpdk_set_mtu, \ >>>>>>>>>> + SET_MTU, \ >>>>>>>>>> netdev_dpdk_get_ifindex, \ >>>>>>>>>> GET_CARRIER, \ >>>>>>>>>> netdev_dpdk_get_carrier_resets, \ >>>>>>>>>> @@ -2213,8 +2389,10 @@ static const struct netdev_class dpdk_class = >>>>>>>>>> NULL, >>>>>>>>>> netdev_dpdk_construct, >>>>>>>>>> netdev_dpdk_destruct, >>>>>>>>>> + netdev_dpdk_set_config, >>>>>>>>>> netdev_dpdk_set_multiq, >>>>>>>>>> netdev_dpdk_eth_send, >>>>>>>>>> + netdev_dpdk_set_mtu, >>>>>>>>>> netdev_dpdk_get_carrier, >>>>>>>>>> netdev_dpdk_get_stats, >>>>>>>>>> netdev_dpdk_get_features, >>>>>>>>>> @@ -2227,8 +2405,10 @@ static const struct netdev_class >> dpdk_ring_class = >>>>>>>>>> NULL, >>>>>>>>>> netdev_dpdk_ring_construct, >>>>>>>>>> netdev_dpdk_destruct, >>>>>>>>>> + netdev_dpdk_set_config, >>>>>>>>>> netdev_dpdk_set_multiq, >>>>>>>>>> netdev_dpdk_ring_send, >>>>>>>>>> + netdev_dpdk_set_mtu, >>>>>>>>>> netdev_dpdk_get_carrier, >>>>>>>>>> netdev_dpdk_get_stats, >>>>>>>>>> netdev_dpdk_get_features, >>>>>>>>>> @@ -2241,8 +2421,10 @@ static const struct netdev_class >>>>>> OVS_UNUSED dpdk_vhost_cuse_class >>>>>>>= >>>>>>>>>> dpdk_vhost_cuse_class_init, >>>>>>>>>> netdev_dpdk_vhost_cuse_construct, >>>>>>>>>> netdev_dpdk_vhost_destruct, >>>>>>>>>> + NULL, >>>>>>>>>> netdev_dpdk_vhost_set_multiq, >>>>>>>>>> netdev_dpdk_vhost_send, >>>>>>>>>> + NULL, >>>>>>>>>> netdev_dpdk_vhost_get_carrier, >>>>>>>>>> netdev_dpdk_vhost_get_stats, >>>>>>>>>> NULL, >>>>>>>>>> @@ -2255,8 +2437,10 @@ static const struct netdev_class >>>>>> OVS_UNUSED dpdk_vhost_user_class >>>>>>>= >>>>>>>>>> dpdk_vhost_user_class_init, >>>>>>>>>> netdev_dpdk_vhost_user_construct, >>>>>>>>>> netdev_dpdk_vhost_destruct, >>>>>>>>>> + netdev_dpdk_vhost_set_config, >>>>>>>>>> netdev_dpdk_vhost_set_multiq, >>>>>>>>>> netdev_dpdk_vhost_send, >>>>>>>>>> + netdev_dpdk_vhost_set_mtu, >>>>>>>>>> netdev_dpdk_vhost_get_carrier, >>>>>>>>>> netdev_dpdk_vhost_get_stats, >>>>>>>>>> NULL, >>>>>>>>_______________________________________________ >>>>>>>>dev mailing list >>>>>>>>dev@openvswitch.org >>>>>>>>http://openvswitch.org/mailman/listinfo/dev >>>>>>>_______________________________________________ >>>>>>>dev mailing list >>>>>>>dev@openvswitch.org >>>>>>>http://openvswitch.org/mailman/listinfo/dev >>>>><#secure method=pgpmime mode=encrypt> _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev