On Jun 3, 2014, at 6:05 PM, Ethan Jackson <et...@nicira.com> wrote: > Couple of questions. > > First, this patch adds a bit of code which extends beyond 79 characters. > Sorry, fixed those.
> dp_netdev_input() does this rather interesting stuff with two keys > that mfk switches between. This is definitely not obvious when first > looking at it. Minimally it needs a comment explaining why. That > said I don't totally understand it, why can't we ruse the same key > after each batch is executed? If we can't, why is using only two keys > sufficient? This seems a bit odd. > > Actually on that note, do we need miniflowkey at all? Could it just > be embedded at the end of batch_pkt_execute? > Sure, we can use only one miniflow key, with the code being as it is. If we want to match on the miniflow in the future (without involving the classifier) we need at least two keys > After this patch, both the hash and recirc and set actions have the > wrong behavior. I'd rather they abort() the switch than silently > misbehave. Looking at this now, I think this is a rather deep issue > that we need to think through. Let's discuss it tomorrow. > You’re right. The hash action is problematic, because the miniflow might not be the same for the same batch. We could group packets by miniflow, or store the miniflow for each packet. Thanks, Daniele > Ethan > > On Tue, Jun 3, 2014 at 5:10 PM, Daniele Di Proietto > <ddiproie...@vmware.com> wrote: >> This change in dpif-netdev allows faster packet processing for devices which >> implement batching (netdev-dpdk currently). >> >> Signed-off-by: Daniele Di Proietto <ddiproie...@vmware.com> >> --- >> lib/dpif-netdev.c | 240 >> ++++++++++++++++++++++++++++++------------- >> lib/dpif.c | 7 +- >> lib/odp-execute.c | 49 ++++++--- >> lib/odp-execute.h | 4 +- >> ofproto/ofproto-dpif-xlate.c | 2 +- >> 5 files changed, 211 insertions(+), 91 deletions(-) >> >> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c >> index e0e5ad8..fba1d65 100644 >> --- a/lib/dpif-netdev.c >> +++ b/lib/dpif-netdev.c >> @@ -331,18 +331,18 @@ 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 cnt, 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 ofpbuf **, int cnt, 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 >> *packet, >> - struct pkt_metadata *); >> +static void dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf >> **packets, >> + int cnt, odp_port_t port_no); >> >> static void dp_netdev_set_pmd_threads(struct dp_netdev *, int n); >> >> @@ -1518,7 +1518,6 @@ static int >> dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute) >> { >> struct dp_netdev *dp = get_dp_netdev(dpif); >> - struct pkt_metadata *md = &execute->md; >> struct { >> struct miniflow flow; >> uint32_t buf[FLOW_U32S]; >> @@ -1531,9 +1530,9 @@ dpif_netdev_execute(struct dpif *dpif, struct >> dpif_execute *execute) >> >> /* Extract flow key. */ >> miniflow_initialize(&key.flow, key.buf); >> - miniflow_extract(execute->packet, md, &key.flow); >> + miniflow_extract(execute->packet, &execute->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, >> &execute->md, >> execute->actions, execute->actions_len); >> >> return 0; >> @@ -1747,17 +1746,12 @@ dp_netdev_process_rxq_port(struct dp_netdev *dp, >> struct dp_netdev_port *port, >> struct netdev_rxq *rxq) >> { >> - struct ofpbuf *packet[NETDEV_MAX_RX_BATCH]; >> - int error, c; >> + struct ofpbuf *packets[NETDEV_MAX_RX_BATCH]; >> + int error, cnt; >> >> - error = netdev_rxq_recv(rxq, packet, &c); >> + error = netdev_rxq_recv(rxq, packets, &cnt); >> if (!error) { >> - struct pkt_metadata md = PKT_METADATA_INITIALIZER(port->port_no); >> - int i; >> - >> - for (i = 0; i < c; i++) { >> - dp_netdev_port_input(dp, packet[i], &md); >> - } >> + dp_netdev_port_input(dp, packets, cnt, port->port_no); >> } else if (error != EAGAIN && error != EOPNOTSUPP) { >> static struct vlog_rate_limit rl >> = VLOG_RATE_LIMIT_INIT(1, 5); >> @@ -1954,7 +1948,7 @@ dp_netdev_flow_stats_new_cb(void) >> >> static void >> dp_netdev_flow_used(struct dp_netdev_flow *netdev_flow, >> - const struct ofpbuf *packet, >> + int cnt, int size, >> const struct miniflow *key) >> { >> uint16_t tcp_flags = miniflow_get_tcp_flags(key); >> @@ -1966,8 +1960,8 @@ dp_netdev_flow_used(struct dp_netdev_flow *netdev_flow, >> >> ovs_mutex_lock(&bucket->mutex); >> bucket->used = MAX(now, bucket->used); >> - bucket->packet_count++; >> - bucket->byte_count += ofpbuf_size(packet); >> + bucket->packet_count += cnt; >> + bucket->byte_count += size; >> bucket->tcp_flags |= tcp_flags; >> ovs_mutex_unlock(&bucket->mutex); >> } >> @@ -1981,74 +1975,143 @@ dp_netdev_stats_new_cb(void) >> } >> >> static void >> -dp_netdev_count_packet(struct dp_netdev *dp, enum dp_stat_type type) >> +dp_netdev_count_packet(struct dp_netdev *dp, enum dp_stat_type type, int >> cnt) >> { >> struct dp_netdev_stats *bucket; >> >> bucket = ovsthread_stats_bucket_get(&dp->stats, dp_netdev_stats_new_cb); >> ovs_mutex_lock(&bucket->mutex); >> - bucket->n[type]++; >> + bucket->n[type] += cnt; >> ovs_mutex_unlock(&bucket->mutex); >> } >> >> +struct batch_pkt_execute { >> + unsigned int packet_count; >> + unsigned int byte_count; >> + >> + struct dp_netdev_flow *flow; >> + const struct miniflow *mf; >> + >> + struct ofpbuf *packets[NETDEV_MAX_RX_BATCH]; >> + struct pkt_metadata md; >> +}; >> + >> +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 = *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) >> +{ >> + 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 *packet, >> +dp_netdev_input(struct dp_netdev *dp, struct ofpbuf **packets, int cnt, >> struct pkt_metadata *md) >> { >> - struct dp_netdev_flow *netdev_flow; >> - struct { >> + struct batch_pkt_execute batch; >> + >> + struct miniflowkey{ >> struct miniflow flow; >> uint32_t buf[FLOW_U32S]; >> - } key; >> + } keys[2]; >> >> - if (ofpbuf_size(packet) < ETH_HEADER_LEN) { >> - ofpbuf_delete(packet); >> - return; >> + struct miniflowkey *mfk = &keys[0]; >> + >> + int i; >> + >> + batch.flow = NULL; >> + batch.mf = NULL; >> + >> + for (i = 0; i < ARRAY_SIZE(keys); i++) { >> + miniflow_initialize(&keys[i].flow, keys[i].buf); >> } >> - miniflow_initialize(&key.flow, key.buf); >> - miniflow_extract(packet, md, &key.flow); >> >> - netdev_flow = dp_netdev_lookup_flow(dp, &key.flow); >> - if (netdev_flow) { >> - struct dp_netdev_actions *actions; >> + for (i = 0; i < cnt; i++) { >> + struct dp_netdev_flow *netdev_flow; >> + >> + if (ofpbuf_size(packets[i]) < ETH_HEADER_LEN) { >> + ofpbuf_delete(packets[i]); >> + continue; >> + } >> + >> + miniflow_extract(packets[i], md, &mfk->flow); >> + >> + netdev_flow = dp_netdev_lookup_flow(dp, &mfk->flow); >> >> - dp_netdev_flow_used(netdev_flow, packet, &key.flow); >> + if (netdev_flow) { >> + if (!batch.flow) { >> + packet_batch_init(&batch, netdev_flow, packets[i], md, >> &mfk->flow); >> + mfk = (batch.mf == &keys[0].flow) ? &keys[1] : &keys[0]; >> + } else if (batch.flow == netdev_flow) { >> + packet_batch_update(&batch, packets[i]); >> + } else { >> + packet_batch_execute(&batch, dp); >> + packet_batch_init(&batch, netdev_flow, packets[i], md, >> &mfk->flow); >> + mfk = (batch.mf == &keys[0].flow) ? &keys[1] : &keys[0]; >> + } >> + } else if (dp->handler_queues) { >> + dp_netdev_count_packet(dp, DP_STAT_MISS, 1); >> + dp_netdev_output_userspace(dp, &packets[i], 1, >> + miniflow_hash_5tuple(&mfk->flow, 0) >> + % dp->n_handlers, >> + DPIF_UC_MISS, &mfk->flow, NULL); >> + ofpbuf_delete(packets[i]); >> + } >> + } >> >> - actions = dp_netdev_flow_get_actions(netdev_flow); >> - dp_netdev_execute_actions(dp, &key.flow, packet, true, md, >> - actions->actions, actions->size); >> - dp_netdev_count_packet(dp, DP_STAT_HIT); >> - } else if (dp->handler_queues) { >> - dp_netdev_count_packet(dp, DP_STAT_MISS); >> - dp_netdev_output_userspace(dp, packet, >> - miniflow_hash_5tuple(&key.flow, 0) >> - % dp->n_handlers, >> - DPIF_UC_MISS, &key.flow, NULL); >> - ofpbuf_delete(packet); >> + if (batch.flow) { >> + packet_batch_execute(&batch, dp); >> } >> } >> >> static void >> -dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet, >> - struct pkt_metadata *md) >> +dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf **packets, >> + int cnt, odp_port_t port_no) >> { >> uint32_t *recirc_depth = recirc_depth_get(); >> + struct pkt_metadata md = PKT_METADATA_INITIALIZER(port_no); >> >> *recirc_depth = 0; >> - dp_netdev_input(dp, packet, md); >> + dp_netdev_input(dp, packets, cnt, &md); >> } >> >> static int >> -dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet, >> - int queue_no, int type, const struct miniflow >> *key, >> - const struct nlattr *userdata) >> +dp_netdev_queue_userspace_packet(struct dp_netdev_queue *q, >> + struct ofpbuf *packet, int type, >> + const struct miniflow *key, >> + const struct nlattr *userdata) >> { >> - struct dp_netdev_queue *q; >> - int error; >> - >> - 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; >> @@ -2075,19 +2138,42 @@ dp_netdev_output_userspace(struct dp_netdev *dp, >> struct ofpbuf *packet, >> /* Put userdata. */ >> if (userdata) { >> upcall->userdata = ofpbuf_put(buf, userdata, >> - NLA_ALIGN(userdata->nla_len)); >> + NLA_ALIGN(userdata->nla_len)); >> } >> >> ofpbuf_set_data(&upcall->packet, >> - ofpbuf_put(buf, ofpbuf_data(packet), >> ofpbuf_size(packet))); >> + ofpbuf_put(buf, ofpbuf_data(packet), >> + ofpbuf_size(packet))); >> ofpbuf_set_size(&upcall->packet, ofpbuf_size(packet)); >> >> seq_change(q->seq); >> >> - error = 0; >> + return 0; >> } else { >> - dp_netdev_count_packet(dp, DP_STAT_LOST); >> - error = ENOBUFS; >> + return ENOBUFS; >> + } >> + >> +} >> + >> +static int >> +dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf **packets, >> int cnt, >> + 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); >> + for (i = 0; i < cnt; i++) { >> + struct ofpbuf *packet = packets[i]; >> + >> + error = dp_netdev_queue_userspace_packet(q, packet, type, key, >> userdata); >> + if (error == ENOBUFS) { >> + dp_netdev_count_packet(dp, DP_STAT_LOST, 1); >> + } >> } >> ovs_mutex_unlock(&q->mutex); >> fat_rwlock_unlock(&dp->queue_rwlock); >> @@ -2101,7 +2187,7 @@ struct dp_netdev_execute_aux { >> }; >> >> static void >> -dp_execute_cb(void *aux_, struct ofpbuf *packet, >> +dp_execute_cb(void *aux_, struct ofpbuf **packets, int cnt, >> struct pkt_metadata *md, >> const struct nlattr *a, bool may_steal) >> OVS_NO_THREAD_SAFETY_ANALYSIS >> @@ -2110,12 +2196,13 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, >> int type = nl_attr_type(a); >> struct dp_netdev_port *p; >> uint32_t *depth = recirc_depth_get(); >> + 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, 1, may_steal); >> + netdev_send(p->netdev, packets, cnt, may_steal); >> } >> break; >> >> @@ -2124,14 +2211,16 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, >> >> userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA); >> >> - dp_netdev_output_userspace(aux->dp, packet, >> + dp_netdev_output_userspace(aux->dp, packets, cnt, >> 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 < cnt; i++) { >> + ofpbuf_delete(packets[i]); >> + } >> } >> break; >> } >> @@ -2144,6 +2233,7 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, >> if (hash_act->hash_alg == OVS_HASH_ALG_L4) { >> /* Hash need not be symmetric, nor does it need to include >> * L2 fields. */ >> + /* TODO: hash the miniflow, but a batch could have different >> miniflows */ >> hash = miniflow_hash_5tuple(aux->key, hash_act->hash_basis); >> if (!hash) { >> hash = 1; /* 0 is not valid */ >> @@ -2155,19 +2245,25 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, >> } >> >> md->dp_hash = hash; >> + >> break; >> } >> >> case OVS_ACTION_ATTR_RECIRC: >> if (*depth < MAX_RECIRC_DEPTH) { >> + struct ofpbuf *recirc_packets[cnt]; >> struct pkt_metadata recirc_md = *md; >> - struct ofpbuf *recirc_packet; >> >> - recirc_packet = may_steal ? packet : ofpbuf_clone(packet); >> + if (!may_steal) { >> + for (i = 0; i < cnt; i++) >> + recirc_packets[i] = ofpbuf_clone(packets[i]); >> + } >> + >> recirc_md.recirc_id = nl_attr_get_u32(a); >> >> (*depth)++; >> - dp_netdev_input(aux->dp, recirc_packet, &recirc_md); >> + dp_netdev_input(aux->dp, may_steal ? packets : recirc_packets, >> + cnt, &recirc_md); >> (*depth)--; >> >> break; >> @@ -2190,13 +2286,13 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, >> >> static void >> dp_netdev_execute_actions(struct dp_netdev *dp, const struct miniflow *key, >> - struct ofpbuf *packet, bool may_steal, >> + struct ofpbuf **packets, int cnt, 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, may_steal, md, >> + odp_execute_actions(&aux, packets, cnt, may_steal, md, >> actions, actions_len, dp_execute_cb); >> } >> >> diff --git a/lib/dpif.c b/lib/dpif.c >> index 84dba28..852fcd6 100644 >> --- a/lib/dpif.c >> +++ b/lib/dpif.c >> @@ -1058,13 +1058,16 @@ struct dpif_execute_helper_aux { >> /* This is called for actions that need the context of the datapath to be >> * meaningful. */ >> static void >> -dpif_execute_helper_cb(void *aux_, struct ofpbuf *packet, >> +dpif_execute_helper_cb(void *aux_, struct ofpbuf **packets, int cnt, >> struct pkt_metadata *md, >> const struct nlattr *action, bool may_steal >> OVS_UNUSED) >> { >> struct dpif_execute_helper_aux *aux = aux_; >> struct dpif_execute execute; >> int type = nl_attr_type(action); >> + struct ofpbuf * packet = packets[0]; >> + >> + ovs_assert(cnt == 1); >> >> switch ((enum ovs_action_attr)type) { >> case OVS_ACTION_ATTR_OUTPUT: >> @@ -1103,7 +1106,7 @@ dpif_execute_with_help(struct dpif *dpif, struct >> dpif_execute *execute) >> >> COVERAGE_INC(dpif_execute_with_help); >> >> - odp_execute_actions(&aux, execute->packet, false, &execute->md, >> + odp_execute_actions(&aux, &execute->packet, 1, false, &execute->md, >> execute->actions, execute->actions_len, >> dpif_execute_helper_cb); >> return aux.error; >> diff --git a/lib/odp-execute.c b/lib/odp-execute.c >> index 12ad679..db67150 100644 >> --- a/lib/odp-execute.c >> +++ b/lib/odp-execute.c >> @@ -151,7 +151,7 @@ odp_execute_set_action(struct ofpbuf *packet, const >> struct nlattr *a, >> } >> >> static void >> -odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, >> +odp_execute_actions__(void *dp, struct ofpbuf **packets, int cnt, bool >> steal, >> struct pkt_metadata *, >> const struct nlattr *actions, size_t actions_len, >> odp_execute_cb dp_execute_action, bool more_actions); >> @@ -186,13 +186,13 @@ odp_execute_sample(void *dp, struct ofpbuf *packet, >> bool steal, >> } >> } >> >> - odp_execute_actions__(dp, packet, steal, md, nl_attr_get(subactions), >> + odp_execute_actions__(dp, &packet, 1, steal, md, >> nl_attr_get(subactions), >> nl_attr_get_size(subactions), dp_execute_action, >> more_actions); >> } >> >> static void >> -odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, >> +odp_execute_actions__(void *dp, struct ofpbuf **packets, int cnt, bool >> steal, >> struct pkt_metadata *md, >> const struct nlattr *actions, size_t actions_len, >> odp_execute_cb dp_execute_action, bool more_actions) >> @@ -200,6 +200,8 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, >> bool steal, >> const struct nlattr *a; >> unsigned int left; >> >> + int i; >> + >> NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) { >> int type = nl_attr_type(a); >> >> @@ -215,37 +217,52 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, >> bool steal, >> bool may_steal = steal && (!more_actions >> && left <= NLA_ALIGN(a->nla_len) >> && type != >> OVS_ACTION_ATTR_RECIRC); >> - dp_execute_action(dp, packet, md, a, may_steal); >> + dp_execute_action(dp, packets, cnt, md, a, may_steal); >> } >> break; >> >> case OVS_ACTION_ATTR_PUSH_VLAN: { >> const struct ovs_action_push_vlan *vlan = nl_attr_get(a); >> - eth_push_vlan(packet, htons(ETH_TYPE_VLAN), vlan->vlan_tci); >> + >> + for (i = 0; i < cnt; i++) { >> + eth_push_vlan(packets[i], htons(ETH_TYPE_VLAN), >> vlan->vlan_tci); >> + } >> break; >> } >> >> case OVS_ACTION_ATTR_POP_VLAN: >> - eth_pop_vlan(packet); >> + for (i = 0; i < cnt; i++) { >> + eth_pop_vlan(packets[i]); >> + } >> break; >> >> case OVS_ACTION_ATTR_PUSH_MPLS: { >> const struct ovs_action_push_mpls *mpls = nl_attr_get(a); >> - push_mpls(packet, mpls->mpls_ethertype, mpls->mpls_lse); >> + for (i = 0; i < cnt; i++) { >> + push_mpls(packets[i], mpls->mpls_ethertype, mpls->mpls_lse); >> + } >> break; >> } >> >> case OVS_ACTION_ATTR_POP_MPLS: >> - pop_mpls(packet, nl_attr_get_be16(a)); >> + for (i = 0; i < cnt; i++) { >> + pop_mpls(packets[i], nl_attr_get_be16(a)); >> + } >> break; >> >> case OVS_ACTION_ATTR_SET: >> - odp_execute_set_action(packet, nl_attr_get(a), md); >> + for (i = 0; i < cnt; i++) { >> + /* TODO: if setting metadata could do it only once */ >> + odp_execute_set_action(packets[i], nl_attr_get(a), md); >> + } >> break; >> >> case OVS_ACTION_ATTR_SAMPLE: >> - odp_execute_sample(dp, packet, steal, md, a, dp_execute_action, >> - more_actions || left > >> NLA_ALIGN(a->nla_len)); >> + for (i = 0; i < cnt; i++) { >> + odp_execute_sample(dp, packets[i], steal, md, a, >> + dp_execute_action, >> + more_actions || left > >> NLA_ALIGN(a->nla_len)); >> + } >> break; >> >> case OVS_ACTION_ATTR_UNSPEC: >> @@ -256,16 +273,20 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, >> bool steal, >> } >> >> void >> -odp_execute_actions(void *dp, struct ofpbuf *packet, bool steal, >> +odp_execute_actions(void *dp, struct ofpbuf **packets, int cnt, bool steal, >> struct pkt_metadata *md, >> const struct nlattr *actions, size_t actions_len, >> odp_execute_cb dp_execute_action) >> { >> - odp_execute_actions__(dp, packet, steal, md, actions, actions_len, >> + odp_execute_actions__(dp, packets, cnt, steal, md, actions, actions_len, >> dp_execute_action, false); >> >> if (!actions_len && steal) { >> /* Drop action. */ >> - ofpbuf_delete(packet); >> + int i = 0; >> + >> + for (i = 0; i < cnt; i++) { >> + ofpbuf_delete(packets[i]); >> + } >> } >> } >> diff --git a/lib/odp-execute.h b/lib/odp-execute.h >> index 91f0c51..006deda 100644 >> --- a/lib/odp-execute.h >> +++ b/lib/odp-execute.h >> @@ -27,7 +27,7 @@ struct nlattr; >> struct ofpbuf; >> struct pkt_metadata; >> >> -typedef void (*odp_execute_cb)(void *dp, struct ofpbuf *packet, >> +typedef void (*odp_execute_cb)(void *dp, struct ofpbuf **packets, int cnt, >> struct pkt_metadata *, >> const struct nlattr *action, bool may_steal); >> >> @@ -35,7 +35,7 @@ typedef void (*odp_execute_cb)(void *dp, struct ofpbuf >> *packet, >> * to 'dp_execute_action', if non-NULL. Currently this is called only for >> * actions OVS_ACTION_ATTR_OUTPUT and OVS_ACTION_ATTR_USERSPACE so >> * 'dp_execute_action' needs to handle only these. */ >> -void odp_execute_actions(void *dp, struct ofpbuf *packet, bool steal, >> +void odp_execute_actions(void *dp, struct ofpbuf **packets, int cnt, bool >> steal, >> struct pkt_metadata *, >> const struct nlattr *actions, size_t actions_len, >> odp_execute_cb dp_execute_action); >> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c >> index 068d54f..875c9e8 100644 >> --- a/ofproto/ofproto-dpif-xlate.c >> +++ b/ofproto/ofproto-dpif-xlate.c >> @@ -2655,7 +2655,7 @@ execute_controller_action(struct xlate_ctx *ctx, int >> len, >> &ctx->xout->odp_actions, >> &ctx->xout->wc); >> >> - odp_execute_actions(NULL, packet, false, &md, >> + odp_execute_actions(NULL, &packet, 1, false, &md, >> ofpbuf_data(&ctx->xout->odp_actions), >> ofpbuf_size(&ctx->xout->odp_actions), NULL); >> >> -- >> 2.0.0.rc2 >> >> _______________________________________________ >> dev mailing list >> dev@openvswitch.org >> https://urldefense.proofpoint.com/v1/url?u=http://openvswitch.org/mailman/listinfo/dev&k=oIvRg1%2BdGAgOoM1BIlLLqw%3D%3D%0A&r=MV9BdLjtFIdhBDBaw5z%2BU6SSA2gAfY4L%2F1HCy3VjlKU%3D%0A&m=ViNpaoTBsjLneADfoun9TXBp0en%2BGN9YL9hvvpypVdQ%3D%0A&s=02ec810eb69b4d2c3436d347287b69d1bf491b77228bcf8a038e0fc5c71c9cb3 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev