On Fri, May 23, 2014 at 11:04 AM, Daniele Di Proietto <ddiproie...@vmware.com> wrote: > Signed-off-by: Daniele Di Proietto <ddiproie...@vmware.com> > --- > lib/netdev-dpdk.c | 139 > +++++++++++++++++++++++++++++++----------------------- > 1 file changed, 80 insertions(+), 59 deletions(-) > > diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c > index ee811eb..0798a18 100644 > --- a/lib/netdev-dpdk.c > +++ b/lib/netdev-dpdk.c > @@ -605,107 +605,128 @@ netdev_dpdk_rxq_recv(struct netdev_rxq *rxq_, struct > ofpbuf **packets, int *c) > } > > inline static void > -dpdk_queue_pkt(struct netdev_dpdk *dev, int qid, > - struct rte_mbuf *pkt) > +dpdk_queue_pkts(struct netdev_dpdk *dev, int qid, > + struct rte_mbuf **pkts, int c) > { > struct dpdk_tx_queue *txq = &dev->tx_q[qid]; > uint64_t diff_tsc; > uint64_t cur_tsc; > uint32_t nb_tx; > > + int i = 0; > + > rte_spinlock_lock(&txq->tx_lock); > - txq->burst_pkts[txq->count++] = pkt; > - if (txq->count == MAX_TX_QUEUE_LEN) { > - goto flush; > - } > - cur_tsc = rte_get_timer_cycles(); > - if (txq->count == 1) { > - txq->tsc = cur_tsc; > - } > - diff_tsc = cur_tsc - txq->tsc; > - if (diff_tsc >= DRAIN_TSC) { > - goto flush; > - } > - rte_spinlock_unlock(&txq->tx_lock); > - return; > + while (i < c) { > + int freeslots = MAX_TX_QUEUE_LEN - txq->count; > + int tocopy = MIN(freeslots, c-i); > > -flush: > - nb_tx = rte_eth_tx_burst(dev->port_id, qid, txq->burst_pkts, txq->count); > - if (nb_tx != txq->count) { > - /* free buffers if we couldn't transmit packets */ > - rte_mempool_put_bulk(dev->dpdk_mp->mp, > - (void **) &txq->burst_pkts[nb_tx], > - (txq->count - nb_tx)); > + memcpy(&txq->burst_pkts[txq->count], &pkts[i], tocopy * sizeof > (struct rte_mbuf *)); > + > + txq->count += tocopy; > + i += tocopy; > + > + if (txq->count == MAX_TX_QUEUE_LEN) { > + goto flush; > + } > + cur_tsc = rte_get_timer_cycles(); > + if (txq->count == 1) { > + txq->tsc = cur_tsc; > + } > + diff_tsc = cur_tsc - txq->tsc; > + if (diff_tsc >= DRAIN_TSC) { > + goto flush; > + } > + continue; > + > + flush: > + nb_tx = rte_eth_tx_burst(dev->port_id, qid, txq->burst_pkts, > txq->count); > + if (nb_tx != txq->count) { > + /* free buffers if we couldn't transmit packets */ > + rte_mempool_put_bulk(dev->dpdk_mp->mp, > + (void **) &txq->burst_pkts[nb_tx], > + (txq->count - nb_tx)); > + } > + txq->count = 0; > } > - txq->count = 0; > rte_spinlock_unlock(&txq->tx_lock); > } > > /* Tx function. Transmit packets indefinitely */ > static void > -dpdk_do_tx_copy(struct netdev *netdev, char *buf, int size) > +dpdk_do_tx_copy(struct netdev *netdev, struct ofpbuf ** ofpbufs, int c) > { > struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); > - struct rte_mbuf *pkt; > + struct rte_mbuf *pkts[c]; > + int i; > > - pkt = rte_pktmbuf_alloc(dev->dpdk_mp->mp); > - if (!pkt) { > - ovs_mutex_lock(&dev->mutex); > - dev->stats.tx_dropped++; > - ovs_mutex_unlock(&dev->mutex); > - return; > - } > + for (i = 0; i < c; i++) { > + int size = ofpbuf_size(ofpbufs[i]); > + if (size > dev->max_packet_len) { > + VLOG_WARN_RL(&rl, "Too big size %d max_packet_len %d", > + (int)size , dev->max_packet_len); > + > + ovs_mutex_lock(&dev->mutex); > + dev->stats.tx_dropped++; > + ovs_mutex_unlock(&dev->mutex); > + } > + need to skip this packet. > + pkts[i] = rte_pktmbuf_alloc(dev->dpdk_mp->mp); > + > + if (!pkts[i]) { > + ovs_mutex_lock(&dev->mutex); > + dev->stats.tx_dropped++; > + ovs_mutex_unlock(&dev->mutex); > + return; > + } > > - /* We have to do a copy for now */ > - memcpy(pkt->pkt.data, buf, size); > + /* We have to do a copy for now */ > + memcpy(pkts[i]->pkt.data, ofpbuf_data(ofpbufs[i]), size); > > - rte_pktmbuf_data_len(pkt) = size; > - rte_pktmbuf_pkt_len(pkt) = size; > + rte_pktmbuf_data_len(pkts[i]) = size; > + rte_pktmbuf_pkt_len(pkts[i]) = size; > + } > > - dpdk_queue_pkt(dev, NON_PMD_THREAD_TX_QUEUE, pkt); > + dpdk_queue_pkts(dev, NON_PMD_THREAD_TX_QUEUE, pkts, c); > dpdk_queue_flush(dev, NON_PMD_THREAD_TX_QUEUE); > } > > static int > -netdev_dpdk_send(struct netdev *netdev, > - struct ofpbuf *ofpbuf, bool may_steal) > +netdev_dpdk_send_batch(struct netdev *netdev, > + struct ofpbuf **ofpbufs, int c, bool may_steal) > { > struct netdev_dpdk *dev = netdev_dpdk_cast(netdev); > int ret; > + int i; > > - if (ofpbuf_size(ofpbuf) > dev->max_packet_len) { > - VLOG_WARN_RL(&rl, "Too big size %d max_packet_len %d", > - (int)ofpbuf_size(ofpbuf) , dev->max_packet_len); > - > - ovs_mutex_lock(&dev->mutex); > - dev->stats.tx_dropped++; > - ovs_mutex_unlock(&dev->mutex); > - > - ret = E2BIG; > - goto out; > - } > - > - if (!may_steal || ofpbuf->source != OFPBUF_DPDK) { > - dpdk_do_tx_copy(netdev, (char *) ofpbuf_data(ofpbuf), > ofpbuf_size(ofpbuf)); > + if (!may_steal || ofpbufs[0]->source != OFPBUF_DPDK) { > + dpdk_do_tx_copy(netdev, ofpbufs, c); > > if (may_steal) { > - ofpbuf_delete(ofpbuf); > + for (i = 0; i < c; i++) { > + ofpbuf_delete(ofpbufs[i]); > + } > } > } else { > int qid; > > qid = rte_lcore_id() % NR_QUEUE; > > - dpdk_queue_pkt(dev, qid, (struct rte_mbuf *)ofpbuf); > - > + /* TODO: warn if any packet bigger than dev->max_packet_len */
I think we have to check this. Better to add it now, and optimize it later. > + dpdk_queue_pkts(dev, qid, (struct rte_mbuf **)ofpbufs, c); > } > ret = 0; > > -out: > return ret; > } > > static int > +netdev_dpdk_send(struct netdev *netdev, > + struct ofpbuf *ofpbuf, bool may_steal) > +{ > + return netdev_dpdk_send_batch(netdev, &ofpbuf, 1, may_steal); > +} > + > +static int > netdev_dpdk_set_etheraddr(struct netdev *netdev, > const uint8_t mac[ETH_ADDR_LEN]) > { > @@ -1122,7 +1143,7 @@ static struct netdev_class netdev_dpdk_class = { > NULL, /* get_tunnel_config */ > > netdev_dpdk_send, /* send */ > - NULL, /* send_batch */ > + netdev_dpdk_send_batch, /* send_batch */ > NULL, /* send_wait */ > > netdev_dpdk_set_etheraddr, > -- > 2.0.0.rc0 > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev