Signed-off-by: Daniele Di Proietto <ddiproie...@vmware.com> --- lib/dpif-netdev.c | 238 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 157 insertions(+), 81 deletions(-)
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 43bfc20..f1f8b54 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -331,14 +331,14 @@ static void dp_netdev_destroy_all_queues(struct dp_netdev *dp) OVS_REQ_WRLOCK(dp->queue_rwlock); static int dpif_netdev_open(const struct dpif_class *, const char *name, bool create, struct dpif **); -static int dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *, - int queue_no, int type, +static int dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf **, + int c, int queue_no, int type, const struct miniflow *, const struct nlattr *userdata); static void dp_netdev_execute_actions(struct dp_netdev *dp, const struct miniflow *, - struct ofpbuf *, bool may_steal, - struct pkt_metadata *, + struct ofpbuf **, int c, bool may_steal, + struct pkt_metadata **, const struct nlattr *actions, size_t actions_len); static void dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf **packets, @@ -1533,7 +1533,7 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute) miniflow_initialize(&key.flow, key.buf); miniflow_extract(execute->packet, md, &key.flow); - dp_netdev_execute_actions(dp, &key.flow, execute->packet, false, md, + dp_netdev_execute_actions(dp, &key.flow, &execute->packet, 1, false, &md, execute->actions, execute->actions_len); return 0; @@ -1986,46 +1986,108 @@ dp_netdev_count_packet(struct dp_netdev *dp, enum dp_stat_type type, int packets ovs_mutex_unlock(&bucket->mutex); } +#define MAX_BATCH 256 + +struct batch_pkt_execute { + unsigned int packet_count; + unsigned int byte_count; + + struct dp_netdev_flow *flow; + struct ofpbuf *packets[MAX_BATCH]; + struct pkt_metadata *md[MAX_BATCH]; + const struct miniflow *mf; +}; + +static inline void +packet_batch_init(struct batch_pkt_execute *batch, struct dp_netdev_flow *flow, + struct ofpbuf *packet, + struct pkt_metadata *md, const struct miniflow *mf) +{ + batch->flow = flow; + batch->mf = mf; + batch->md[0] = md; + batch->packets[0] = packet; + + /* no need to update time and tcp_flags, its same in given input batch. */ + batch->packet_count = 1; + batch->byte_count = ofpbuf_size(packet); +} + +static inline void +packet_batch_update(struct batch_pkt_execute *batch, struct ofpbuf *packet, struct pkt_metadata *md) +{ + + batch->md[batch->packet_count] = md; + batch->packets[batch->packet_count++] = packet; + batch->byte_count += ofpbuf_size(packet); +} + +static inline void +packet_batch_execute(struct batch_pkt_execute *batch, struct dp_netdev *dp) +{ + struct dp_netdev_actions *actions; + struct dp_netdev_flow *flow = batch->flow; + + dp_netdev_flow_used(batch->flow, batch->packet_count, batch->byte_count, batch->mf); + + actions = ovsrcu_get(struct dp_netdev_actions *, &flow->actions); + + dp_netdev_execute_actions(dp, batch->mf, batch->packets, + batch->packet_count, true, + batch->md, actions->actions, actions->size); + + dp_netdev_count_packet(dp, DP_STAT_HIT, batch->packet_count); +} + static void dp_netdev_input(struct dp_netdev *dp, struct ofpbuf **packets, int c, - struct pkt_metadata *md) + struct pkt_metadata **md) { + struct batch_pkt_execute batch; + + struct { + struct miniflow flow; + uint32_t buf[FLOW_U32S]; + } keys[c]; + int i; + memset(&batch, 0, sizeof batch); + for (i = 0; i < c; i++) { struct dp_netdev_flow *netdev_flow; - struct { - struct miniflow flow; - uint32_t buf[FLOW_U32S]; - } key; if (ofpbuf_size(packets[i]) < ETH_HEADER_LEN) { ofpbuf_delete(packets[i]); continue; } - miniflow_initialize(&key.flow, key.buf); - miniflow_extract(packets[i], &md[i], &key.flow); + miniflow_initialize(&keys[i].flow, keys[i].buf); + miniflow_extract(packets[i], md[i], &keys[i].flow); - netdev_flow = dp_netdev_lookup_flow(dp, &key.flow); + netdev_flow = dp_netdev_lookup_flow(dp, &keys[i].flow); if (netdev_flow) { - struct dp_netdev_actions *actions; - - dp_netdev_flow_used(netdev_flow, 1, ofpbuf_size(packets[i]), &key.flow); - - actions = dp_netdev_flow_get_actions(netdev_flow); - dp_netdev_execute_actions(dp, &key.flow, packets[i], true, &md[i], - actions->actions, actions->size); - dp_netdev_count_packet(dp, DP_STAT_HIT, 1); + if (!batch.flow) { + packet_batch_init(&batch, netdev_flow, packets[i], md[i], &keys[i].flow); + } else if (batch.flow == netdev_flow) { + packet_batch_update(&batch, packets[i], md[i]); + } else { + packet_batch_execute(&batch, dp); + packet_batch_init(&batch, netdev_flow, packets[i], md[i], &keys[i].flow); + } } else if (dp->handler_queues) { dp_netdev_count_packet(dp, DP_STAT_MISS, 1); - dp_netdev_output_userspace(dp, packets[i], - miniflow_hash_5tuple(&key.flow, 0) + dp_netdev_output_userspace(dp, &packets[i], 1, + miniflow_hash_5tuple(&keys[i].flow, 0) % dp->n_handlers, - DPIF_UC_MISS, &key.flow, NULL); + DPIF_UC_MISS, &keys[i].flow, NULL); ofpbuf_delete(packets[i]); } } + + if (batch.flow) { + packet_batch_execute(&batch, dp); + } } static void @@ -2034,67 +2096,74 @@ dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf **packets, { uint32_t *recirc_depth = recirc_depth_get(); struct pkt_metadata md[c]; + struct pkt_metadata *pmd[c]; int i; for (i = 0; i < c; i++) { md[i] = PKT_METADATA_INITIALIZER(port_no); + pmd[i] = &md[i]; } *recirc_depth = 0; - dp_netdev_input(dp, packets, c, md); + dp_netdev_input(dp, packets, c, pmd); } static int -dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet, +dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf **packets, int c, int queue_no, int type, const struct miniflow *key, const struct nlattr *userdata) { struct dp_netdev_queue *q; int error; + int i; fat_rwlock_rdlock(&dp->queue_rwlock); q = &dp->handler_queues[queue_no]; ovs_mutex_lock(&q->mutex); - if (q->head - q->tail < MAX_QUEUE_LEN) { - struct dp_netdev_upcall *u = &q->upcalls[q->head++ & QUEUE_MASK]; - struct dpif_upcall *upcall = &u->upcall; - struct ofpbuf *buf = &u->buf; - size_t buf_size; - struct flow flow; - - upcall->type = type; - - /* Allocate buffer big enough for everything. */ - buf_size = ODPUTIL_FLOW_KEY_BYTES; - if (userdata) { - buf_size += NLA_ALIGN(userdata->nla_len); - } - buf_size += ofpbuf_size(packet); - ofpbuf_init(buf, buf_size); - - /* Put ODP flow. */ - miniflow_expand(key, &flow); - odp_flow_key_from_flow(buf, &flow, NULL, flow.in_port.odp_port, true); - upcall->key = ofpbuf_data(buf); - upcall->key_len = ofpbuf_size(buf); - - /* Put userdata. */ - if (userdata) { - upcall->userdata = ofpbuf_put(buf, userdata, - NLA_ALIGN(userdata->nla_len)); - } + for (i = 0; i < c; i++) { + struct ofpbuf * packet = packets[i]; + if (q->head - q->tail < MAX_QUEUE_LEN) { + struct dp_netdev_upcall *u = &q->upcalls[q->head++ & QUEUE_MASK]; + struct dpif_upcall *upcall = &u->upcall; + struct ofpbuf *buf = &u->buf; + size_t buf_size; + struct flow flow; + + upcall->type = type; + + /* Allocate buffer big enough for everything. */ + buf_size = ODPUTIL_FLOW_KEY_BYTES; + if (userdata) { + buf_size += NLA_ALIGN(userdata->nla_len); + } + buf_size += ofpbuf_size(packet); + ofpbuf_init(buf, buf_size); + + /* Put ODP flow. */ + miniflow_expand(key, &flow); + odp_flow_key_from_flow(buf, &flow, NULL, flow.in_port.odp_port, true); + upcall->key = ofpbuf_data(buf); + upcall->key_len = ofpbuf_size(buf); + + /* Put userdata. */ + if (userdata) { + upcall->userdata = ofpbuf_put(buf, userdata, + NLA_ALIGN(userdata->nla_len)); + } - ofpbuf_set_data(&upcall->packet, - ofpbuf_put(buf, ofpbuf_data(packet), ofpbuf_size(packet))); - ofpbuf_set_size(&upcall->packet, ofpbuf_size(packet)); + ofpbuf_set_data(&upcall->packet, + ofpbuf_put(buf, ofpbuf_data(packet), + ofpbuf_size(packet))); + ofpbuf_set_size(&upcall->packet, ofpbuf_size(packet)); - seq_change(q->seq); + seq_change(q->seq); - error = 0; - } else { - dp_netdev_count_packet(dp, DP_STAT_LOST, 1); - error = ENOBUFS; + error = 0; + } else { + dp_netdev_count_packet(dp, DP_STAT_LOST, 1); + error = ENOBUFS; + } } ovs_mutex_unlock(&q->mutex); fat_rwlock_unlock(&dp->queue_rwlock); @@ -2117,19 +2186,13 @@ dp_execute_cb(void *aux_, struct ofpbuf **packets, int c, int type = nl_attr_type(a); struct dp_netdev_port *p; uint32_t *depth = recirc_depth_get(); - struct ofpbuf * packet; - struct pkt_metadata * md; - - ovs_assert(c==1); - - packet = packets[0]; - md = pmd[0]; + int i; switch ((enum ovs_action_attr)type) { case OVS_ACTION_ATTR_OUTPUT: p = dp_netdev_lookup_port(aux->dp, u32_to_odp(nl_attr_get_u32(a))); if (p) { - netdev_send(p->netdev, packet, may_steal); + netdev_send_batch(p->netdev, packets, c, may_steal); } break; @@ -2138,14 +2201,16 @@ dp_execute_cb(void *aux_, struct ofpbuf **packets, int c, userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA); - dp_netdev_output_userspace(aux->dp, packet, + dp_netdev_output_userspace(aux->dp, packets, c, miniflow_hash_5tuple(aux->key, 0) % aux->dp->n_handlers, DPIF_UC_ACTION, aux->key, userdata); if (may_steal) { - ofpbuf_delete(packet); + for (i = 0; i < c; i++) { + ofpbuf_delete(packets[i]); + } } break; } @@ -2168,20 +2233,31 @@ dp_execute_cb(void *aux_, struct ofpbuf **packets, int c, hash = 2; } - md->dp_hash = hash; + for (i = 0; i < c; i++) { + pmd[i]->dp_hash = hash; + } break; } case OVS_ACTION_ATTR_RECIRC: if (*depth < MAX_RECIRC_DEPTH) { - struct pkt_metadata recirc_md = *md; - struct ofpbuf *recirc_packet; + struct pkt_metadata recirc_md[c]; + struct pkt_metadata *recirc_pmd[c]; + struct ofpbuf *recirc_packets[c]; - recirc_packet = may_steal ? packet : ofpbuf_clone(packet); - recirc_md.recirc_id = nl_attr_get_u32(a); + if (!may_steal) { + for (i = 0; i < c; i++) + recirc_packets[i] = ofpbuf_clone(packets[i]); + } + + for (i = 0; i < c; i++) { + recirc_md[i] = *pmd[i]; + recirc_md[i].recirc_id = nl_attr_get_u32(a); + recirc_pmd[i] = &recirc_md[i]; + } (*depth)++; - dp_netdev_input(aux->dp, &recirc_packet, 1, &recirc_md); + dp_netdev_input(aux->dp, may_steal ? packets : recirc_packets, c, recirc_pmd); (*depth)--; break; @@ -2204,13 +2280,13 @@ dp_execute_cb(void *aux_, struct ofpbuf **packets, int c, static void dp_netdev_execute_actions(struct dp_netdev *dp, const struct miniflow *key, - struct ofpbuf *packet, bool may_steal, - struct pkt_metadata *md, + struct ofpbuf **packets, int c, bool may_steal, + struct pkt_metadata **md, const struct nlattr *actions, size_t actions_len) { struct dp_netdev_execute_aux aux = {dp, key}; - odp_execute_actions(&aux, &packet, 1, may_steal, &md, + odp_execute_actions(&aux, packets, c, may_steal, md, actions, actions_len, dp_execute_cb); } -- 2.0.0.rc0 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev