On Wed, Jan 25, 2017 at 4:50 PM, Jarno Rajahalme <ja...@ovn.org> wrote:
> Trusting you address the comments below: > > Acked-by: Jarno Rajahalme <ja...@ovn.org> > Thanks for the review. Pushed with fixes. > > > > On Jan 24, 2017, at 10:45 PM, Andy Zhou <az...@ovn.org> wrote: > > > > One common use case of 'struct dp_packet_batch' is to process all > > packets in the batch in order. Add an iterator for this use case > > to simplify the logic of calling sites, > > > > Another common use case is to drop packets in the batch, by reading > > all packets, but writing back pointers of fewer packets. Add macros > > to support this use case. > > > > Signed-off-by: Andy Zhou <az...@ovn.org> > > --- > > lib/dp-packet.h | 140 ++++++++++++++++++++++++++++++ > +------------ > > lib/dpif-netdev.c | 62 +++++++++---------- > > lib/dpif.c | 2 +- > > lib/netdev-dummy.c | 10 ++-- > > lib/netdev-linux.c | 3 +- > > lib/netdev.c | 24 ++++---- > > lib/odp-execute.c | 55 ++++++++--------- > > ofproto/ofproto-dpif-xlate.c | 2 +- > > tests/test-conntrack.c | 56 +++++++---------- > > 9 files changed, 201 insertions(+), 153 deletions(-) > > > > diff --git a/lib/dp-packet.h b/lib/dp-packet.h > > index cf7d247..d0c14a5 100644 > > --- a/lib/dp-packet.h > > +++ b/lib/dp-packet.h > > @@ -632,79 +632,143 @@ reset_dp_packet_checksum_ol_flags(struct > dp_packet *p) > > enum { NETDEV_MAX_BURST = 32 }; /* Maximum number packets in a batch. */ > > > > struct dp_packet_batch { > > - int count; > > + size_t count; > > Is there a reason for widening ‘count’ on 64-bit systems? NETDEV_MAX_BURST > is small enough to fit in 4 bytes, so there is no point making the struct 8 > bytes larger? > The point here is not about 64-bit, but the fact count should not be negative. Since the size of this struct is not critial, I left the change as is. > > > bool trunc; /* true if the batch needs truncate. */ > > struct dp_packet *packets[NETDEV_MAX_BURST]; > > }; > > > > -static inline void dp_packet_batch_init(struct dp_packet_batch *b) > > +static inline void > > +dp_packet_batch_init(struct dp_packet_batch *batch) > > { > > - b->count = 0; > > - b->trunc = false; > > + batch->count = 0; > > + batch->trunc = false; > > } > > Just a note that this change is only aesthetic, which is fine if you want > to use consistent identifiers in all the helper functions. > > > > > static inline void > > -dp_packet_batch_clone(struct dp_packet_batch *dst, > > - struct dp_packet_batch *src) > > +dp_packet_batch_add__(struct dp_packet_batch *batch, > > + struct dp_packet *packet, size_t limit) > > { > > - int i; > > - > > - for (i = 0; i < src->count; i++) { > > - dst->packets[i] = dp_packet_clone(src->packets[i]); > > + if (batch->count < limit) { > > + batch->packets[batch->count++] = packet; > > + } else { > > + dp_packet_delete(packet); > > } > > - dst->count = src->count; > > - dst->trunc = src->trunc; > > } > > > > static inline void > > -packet_batch_init_packet(struct dp_packet_batch *b, struct dp_packet > *p) > > +dp_packet_batch_add(struct dp_packet_batch *batch, struct dp_packet > *packet) > > +{ > > + dp_packet_batch_add__(batch, packet, NETDEV_MAX_BURST); > > +} > > + > > Maybe add a comment above this function about deleting the packet if batch > is full? > Added. > > > +static inline size_t > > +dp_packet_batch_size(const struct dp_packet_batch *batch) > > +{ > > + return batch->count; > > +} > > + > > +/* > > + * Clear 'batch' for refill. Use dp_packet_batch_refill() to add > > + * packets back into the 'batch'. > > + * > > + * Return the original size of the 'batch'. */ > > +static inline void > > +dp_packet_batch_refill_init(struct dp_packet_batch *batch) > > { > > - b->count = 1; > > - b->trunc = false; > > - b->packets[0] = p; > > + batch->count = 0; > > +}; > > + > > +static inline void > > +dp_packet_batch_refill(struct dp_packet_batch *batch, > > + struct dp_packet *packet, size_t idx) > > +{ > > + dp_packet_batch_add__(batch, packet, MIN(NETDEV_MAX_BURST, idx + > 1)); > > +} > > + > > +static inline void > > +dp_packet_batch_init_packet(struct dp_packet_batch *batch, struct > dp_packet *p) > > +{ > > + dp_packet_batch_init(batch); > > + batch->count = 1; > > + batch->packets[0] = p; > > +} > > + > > +static inline bool > > +dp_packet_batch_is_empty(const struct dp_packet_batch *batch) > > +{ > > + return !dp_packet_batch_size(batch); > > +} > > + > > +#define DP_PACKET_BATCH_FOR_EACH(PACKET, BATCH) \ > > + for (size_t i = 0; i < dp_packet_batch_size(BATCH); i++) \ > > + if ((PACKET = BATCH->packets[i]) != NULL) > > + > > While the if within the for without an opening curly brace in between is a > neat technique (I’ll try to memorize this), stopping the iteration on the > first NULL seems odd, unless we document that batch size need not be > accurate and that (trailing) NULL pointer within the range of the size are > allowed. > Thanks for pointing out, The count should be accurate. We don't have use case where the packet pointer can be NULL. I removed the NULL check. > > > +/* Use this macro for cases where some packets in the 'BATCH' may be > > + * dropped after going through each packet in the 'BATCH'. > > + * > > + * For packets to stay in the 'BATCH', they need to be refilled back > > + * into the 'BATCH' by calling dp_packet_batch_refill(). Caller owns > > + * the packets that are not refilled. > > + * > > + * Caller needs to supply 'SIZE', that stores the current number of > > + * packets in 'BATCH'. It is best to declare this variable with > > + * the 'const' modifier since it should not be modified by > > + * the iterator. */ > > +#define DP_PACKET_BATCH_REFILL_FOR_EACH(IDX, SIZE, PACKET, BATCH) > \ > > + for (dp_packet_batch_refill_init(BATCH), IDX=0; IDX < SIZE; > IDX++) \ > > + if ((PACKET = BATCH->packets[IDX]) != NULL) > > + > > Same comment about the NULL pointers in the array. Does some of the call > sites depend on the NULL check? > > > +static inline void > > +dp_packet_batch_clone(struct dp_packet_batch *dst, > > + struct dp_packet_batch *src) > > +{ > > + struct dp_packet *packet; > > + > > + dp_packet_batch_init(dst); > > + DP_PACKET_BATCH_FOR_EACH (packet, src) { > > + dp_packet_batch_add(dst, dp_packet_clone(packet)); > > + } > > } > > > > static inline void > > dp_packet_delete_batch(struct dp_packet_batch *batch, bool may_steal) > > { > > if (may_steal) { > > - int i; > > + struct dp_packet *packet; > > > > - for (i = 0; i < batch->count; i++) { > > - dp_packet_delete(batch->packets[i]); > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > + dp_packet_delete(packet); > > } > > + dp_packet_batch_init(batch); > > } > > } > > > > static inline void > > -dp_packet_batch_apply_cutlen(struct dp_packet_batch *pktb) > > +dp_packet_batch_apply_cutlen(struct dp_packet_batch *batch) > > { > > - int i; > > - > > - if (!pktb->trunc) > > - return; > > + if (batch->trunc) { > > + struct dp_packet *packet; > > > > - for (i = 0; i < pktb->count; i++) { > > - uint32_t cutlen = dp_packet_get_cutlen(pktb->packets[i]); > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > + uint32_t cutlen = dp_packet_get_cutlen(packet); > > > > - dp_packet_set_size(pktb->packets[i], > > - dp_packet_size(pktb->packets[i]) - cutlen); > > - dp_packet_reset_cutlen(pktb->packets[i]); > > + dp_packet_set_size(packet, dp_packet_size(packet) - cutlen); > > + dp_packet_reset_cutlen(packet); > > + } > > + batch->trunc = false; > > } > > - pktb->trunc = false; > > } > > > > static inline void > > -dp_packet_batch_reset_cutlen(struct dp_packet_batch *pktb) > > +dp_packet_batch_reset_cutlen(struct dp_packet_batch *batch) > > { > > - int i; > > + if (batch->trunc) { > > + struct dp_packet *packet; > > > > - if (!pktb->trunc) > > - return; > > - > > - pktb->trunc = false; > > - for (i = 0; i < pktb->count; i++) { > > - dp_packet_reset_cutlen(pktb->packets[i]); > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > + dp_packet_reset_cutlen(packet); > > + } > > + batch->trunc = false; > > } > > } > > > > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c > > index 42631bc..719a518 100644 > > --- a/lib/dpif-netdev.c > > +++ b/lib/dpif-netdev.c > > @@ -2683,7 +2683,7 @@ dpif_netdev_execute(struct dpif *dpif, struct > dpif_execute *execute) > > flow_hash_5tuple(execute->flow, 0)); > > } > > > > - packet_batch_init_packet(&pp, execute->packet); > > + dp_packet_batch_init_packet(&pp, execute->packet); > > dp_netdev_execute_actions(pmd, &pp, false, execute->flow, > > execute->actions, execute->actions_len, > > time_msec()); > > @@ -4073,20 +4073,21 @@ dp_netdev_queue_batches(struct dp_packet *pkt, > > * initialized by this function using 'port_no'. > > */ > > static inline size_t > > -emc_processing(struct dp_netdev_pmd_thread *pmd, struct dp_packet_batch > *packets_, > > +emc_processing(struct dp_netdev_pmd_thread *pmd, > > + struct dp_packet_batch *packets_, > > struct netdev_flow_key *keys, > > struct packet_batch_per_flow batches[], size_t *n_batches, > > bool md_is_valid, odp_port_t port_no) > > { > > struct emc_cache *flow_cache = &pmd->flow_cache; > > struct netdev_flow_key *key = &keys[0]; > > - size_t i, n_missed = 0, n_dropped = 0; > > - struct dp_packet **packets = packets_->packets; > > - int cnt = packets_->count; > > + size_t n_missed = 0, n_dropped = 0; > > + struct dp_packet *packet; > > + const size_t size = dp_packet_batch_size(packets_); > > + int i; > > > > - for (i = 0; i < cnt; i++) { > > + DP_PACKET_BATCH_REFILL_FOR_EACH (i, size, packet, packets_) { > > struct dp_netdev_flow *flow; > > - struct dp_packet *packet = packets[i]; > > > > if (OVS_UNLIKELY(dp_packet_size(packet) < ETH_HEADER_LEN)) { > > dp_packet_delete(packet); > > @@ -4094,7 +4095,8 @@ emc_processing(struct dp_netdev_pmd_thread *pmd, > struct dp_packet_batch *packets > > continue; > > } > > > > - if (i != cnt - 1) { > > + if (i != size - 1) { > > + struct dp_packet **packets = packets_->packets; > > /* Prefetch next packet data and metadata. */ > > OVS_PREFETCH(dp_packet_data(packets[i+1])); > > pkt_metadata_prefetch_init(&packets[i+1]->md); > > @@ -4113,8 +4115,8 @@ emc_processing(struct dp_netdev_pmd_thread *pmd, > struct dp_packet_batch *packets > > n_batches); > > } else { > > /* Exact match cache missed. Group missed packets together at > > - * the beginning of the 'packets' array. */ > > - packets[n_missed] = packet; > > + * the beginning of the 'packets' array. */ > > + dp_packet_batch_refill(packets_, packet, i); > > /* 'key[n_missed]' contains the key of the current packet > and it > > * must be returned to the caller. The next key should be > extracted > > * to 'keys[n_missed + 1]'. */ > > @@ -4122,9 +4124,9 @@ emc_processing(struct dp_netdev_pmd_thread *pmd, > struct dp_packet_batch *packets > > } > > } > > > > - dp_netdev_count_packet(pmd, DP_STAT_EXACT_HIT, cnt - n_dropped - > n_missed); > > + dp_netdev_count_packet(pmd, DP_STAT_EXACT_HIT, size - n_dropped - > n_missed); > > > > - return n_missed; > > + return dp_packet_batch_size(packets_); > > } > > > > static inline void > > @@ -4168,7 +4170,7 @@ handle_packet_upcall(struct dp_netdev_pmd_thread > *pmd, struct dp_packet *packet, > > /* We can't allow the packet batching in the next loop to execute > > * the actions. Otherwise, if there are any slow path actions, > > * we'll send the packet up twice. */ > > - packet_batch_init_packet(&b, packet); > > + dp_packet_batch_init_packet(&b, packet); > > dp_netdev_execute_actions(pmd, &b, true, &match.flow, > > actions->data, actions->size, now); > > > > @@ -4316,14 +4318,13 @@ dp_netdev_input__(struct dp_netdev_pmd_thread > *pmd, > > OVS_ALIGNED_VAR(CACHE_LINE_SIZE) struct netdev_flow_key > keys[PKT_ARRAY_SIZE]; > > struct packet_batch_per_flow batches[PKT_ARRAY_SIZE]; > > long long now = time_msec(); > > - size_t newcnt, n_batches, i; > > + size_t n_batches; > > odp_port_t in_port; > > > > n_batches = 0; > > - newcnt = emc_processing(pmd, packets, keys, batches, &n_batches, > > + emc_processing(pmd, packets, keys, batches, &n_batches, > > md_is_valid, port_no); > > - if (OVS_UNLIKELY(newcnt)) { > > - packets->count = newcnt; > > + if (!dp_packet_batch_is_empty(packets)) { > > /* Get ingress port from first packet's metadata. */ > > in_port = packets->packets[0]->md.in_port.odp_port; > > fast_path_processing(pmd, packets, keys, batches, &n_batches, > in_port, now); > > @@ -4338,6 +4339,7 @@ dp_netdev_input__(struct dp_netdev_pmd_thread *pmd, > > * already its own batches[k] still waiting to be served. So if its > > * ‘batch’ member is not reset, the recirculated packet would be > wrongly > > * appended to batches[k] of the 1st call to dp_netdev_input__(). */ > > + size_t i; > > for (i = 0; i < n_batches; i++) { > > > batches[i].flow->batch = NULL; > > } > > @@ -4512,7 +4514,7 @@ dp_execute_userspace_action(struct > dp_netdev_pmd_thread *pmd, > > DPIF_UC_ACTION, userdata, actions, > > NULL); > > if (!error || error == ENOSPC) { > > - packet_batch_init_packet(&b, packet); > > + dp_packet_batch_init_packet(&b, packet); > > dp_netdev_execute_actions(pmd, &b, may_steal, flow, > > actions->data, actions->size, now); > > } else if (may_steal) { > > @@ -4584,7 +4586,6 @@ dp_execute_cb(void *aux_, struct dp_packet_batch > *packets_, > > p = pmd_tnl_port_cache_lookup(pmd, portno); > > if (p) { > > struct dp_packet_batch tnl_pkt; > > - int i; > > > > if (!may_steal) { > > dp_packet_batch_clone(&tnl_pkt, packets_); > > @@ -4595,12 +4596,13 @@ dp_execute_cb(void *aux_, struct dp_packet_batch > *packets_, > > dp_packet_batch_apply_cutlen(packets_); > > > > netdev_pop_header(p->port->netdev, packets_); > > - if (!packets_->count) { > > + if (dp_packet_batch_is_empty(packets_)) { > > return; > > } > > > > - for (i = 0; i < packets_->count; i++) { > > - packets_->packets[i]->md.in_port.odp_port = portno; > > + struct dp_packet *packet; > > + DP_PACKET_BATCH_FOR_EACH (packet, packets_) { > > + packet->md.in_port.odp_port = portno; > > } > > > > (*depth)++; > > @@ -4614,14 +4616,12 @@ dp_execute_cb(void *aux_, struct dp_packet_batch > *packets_, > > case OVS_ACTION_ATTR_USERSPACE: > > if (!fat_rwlock_tryrdlock(&dp->upcall_rwlock)) { > > struct dp_packet_batch *orig_packets_ = packets_; > > - struct dp_packet **packets = packets_->packets; > > const struct nlattr *userdata; > > struct dp_packet_batch usr_pkt; > > struct ofpbuf actions; > > struct flow flow; > > ovs_u128 ufid; > > bool clone = false; > > - int i; > > > > userdata = nl_attr_find_nested(a, > OVS_USERSPACE_ATTR_USERDATA); > > ofpbuf_init(&actions, 0); > > @@ -4630,7 +4630,6 @@ dp_execute_cb(void *aux_, struct dp_packet_batch > *packets_, > > if (!may_steal) { > > dp_packet_batch_clone(&usr_pkt, packets_); > > packets_ = &usr_pkt; > > - packets = packets_->packets; > > clone = true; > > dp_packet_batch_reset_cutlen(orig_packets_); > > } > > @@ -4638,10 +4637,11 @@ dp_execute_cb(void *aux_, struct dp_packet_batch > *packets_, > > dp_packet_batch_apply_cutlen(packets_); > > } > > > > - for (i = 0; i < packets_->count; i++) { > > - flow_extract(packets[i], &flow); > > + struct dp_packet *packet; > > + DP_PACKET_BATCH_FOR_EACH (packet, packets_) { > > + flow_extract(packet, &flow); > > dpif_flow_hash(dp->dpif, &flow, sizeof flow, &ufid); > > - dp_execute_userspace_action(pmd, packets[i], > may_steal, &flow, > > + dp_execute_userspace_action(pmd, packet, may_steal, > &flow, > > &ufid, &actions, userdata, > now); > > } > > > > @@ -4659,15 +4659,15 @@ dp_execute_cb(void *aux_, struct dp_packet_batch > *packets_, > > case OVS_ACTION_ATTR_RECIRC: > > if (*depth < MAX_RECIRC_DEPTH) { > > struct dp_packet_batch recirc_pkts; > > - int i; > > > > if (!may_steal) { > > dp_packet_batch_clone(&recirc_pkts, packets_); > > packets_ = &recirc_pkts; > > } > > > > - for (i = 0; i < packets_->count; i++) { > > - packets_->packets[i]->md.recirc_id = > nl_attr_get_u32(a); > > + struct dp_packet *packet; > > + DP_PACKET_BATCH_FOR_EACH (packet, packets_) { > > + packet->md.recirc_id = nl_attr_get_u32(a); > > } > > > > (*depth)++; > > diff --git a/lib/dpif.c b/lib/dpif.c > > index 7c953b5..374f013 100644 > > --- a/lib/dpif.c > > +++ b/lib/dpif.c > > @@ -1202,7 +1202,7 @@ dpif_execute_with_help(struct dpif *dpif, struct > dpif_execute *execute) > > > > COVERAGE_INC(dpif_execute_with_help); > > > > - packet_batch_init_packet(&pb, execute->packet); > > + dp_packet_batch_init_packet(&pb, execute->packet); > > odp_execute_actions(&aux, &pb, false, execute->actions, > > execute->actions_len, dpif_execute_helper_cb); > > return aux.error; > > diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c > > index 10df0a7..e02beae 100644 > > --- a/lib/netdev-dummy.c > > +++ b/lib/netdev-dummy.c > > @@ -1061,13 +1061,13 @@ netdev_dummy_send(struct netdev *netdev, int qid > OVS_UNUSED, > > { > > struct netdev_dummy *dev = netdev_dummy_cast(netdev); > > int error = 0; > > - int i; > > > > - for (i = 0; i < batch->count; i++) { > > - const void *buffer = dp_packet_data(batch->packets[i]); > > - size_t size = dp_packet_size(batch->packets[i]); > > + struct dp_packet *packet; > > + DP_PACKET_BATCH_FOR_EACH(packet, batch) { > > + const void *buffer = dp_packet_data(packet); > > + size_t size = dp_packet_size(packet); > > > > - size -= dp_packet_get_cutlen(batch->packets[i]); > > + size -= dp_packet_get_cutlen(packet); > > > > if (size < ETH_HEADER_LEN) { > > error = EMSGSIZE; > > diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c > > index a5a9ec1..9ff1333 100644 > > --- a/lib/netdev-linux.c > > +++ b/lib/netdev-linux.c > > @@ -1125,8 +1125,7 @@ netdev_linux_rxq_recv(struct netdev_rxq *rxq_, > struct dp_packet_batch *batch) > > } > > dp_packet_delete(buffer); > > } else { > > - batch->packets[0] = buffer; > > - batch->count = 1; > > + dp_packet_batch_init_packet(batch, buffer); > > } > > > > return retval; > > diff --git a/lib/netdev.c b/lib/netdev.c > > index 839b1f6..1e6bb2b 100644 > > --- a/lib/netdev.c > > +++ b/lib/netdev.c > > @@ -749,20 +749,19 @@ netdev_send(struct netdev *netdev, int qid, struct > dp_packet_batch *batch, > > void > > netdev_pop_header(struct netdev *netdev, struct dp_packet_batch *batch) > > { > > - int i, n_cnt = 0; > > - struct dp_packet **buffers = batch->packets; > > + struct dp_packet *packet; > > + size_t i, size = dp_packet_batch_size(batch); > > > > - for (i = 0; i < batch->count; i++) { > > - buffers[i] = netdev->netdev_class->pop_header(buffers[i]); > > - if (buffers[i]) { > > + DP_PACKET_BATCH_REFILL_FOR_EACH (i, size, packet, batch) { > > + packet = netdev->netdev_class->pop_header(packet); > > + if (packet) { > > /* Reset the checksum offload flags if present, to avoid > wrong > > * interpretation in the further packet processing when > > * recirculated.*/ > > - reset_dp_packet_checksum_ol_flags(buffers[i]); > > - buffers[n_cnt++] = buffers[i]; > > + reset_dp_packet_checksum_ol_flags(packet); > > + dp_packet_batch_refill(batch, packet, i); > > } > > } > > - batch->count = n_cnt; > > } > > > > void > > @@ -799,11 +798,10 @@ netdev_push_header(const struct netdev *netdev, > > struct dp_packet_batch *batch, > > const struct ovs_action_push_tnl *data) > > { > > - int i; > > - > > - for (i = 0; i < batch->count; i++) { > > - netdev->netdev_class->push_header(batch->packets[i], data); > > - pkt_metadata_init(&batch->packets[i]->md, > u32_to_odp(data->out_port)); > > + struct dp_packet *packet; > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > + netdev->netdev_class->push_header(packet, data); > > + pkt_metadata_init(&packet->md, u32_to_odp(data->out_port)); > > } > > > > return 0; > > diff --git a/lib/odp-execute.c b/lib/odp-execute.c > > index c4ae5ce..465280b 100644 > > --- a/lib/odp-execute.c > > +++ b/lib/odp-execute.c > > @@ -523,7 +523,7 @@ odp_execute_sample(void *dp, struct dp_packet > *packet, bool steal, > > } > > } > > > > - packet_batch_init_packet(&pb, packet); > > + dp_packet_batch_init_packet(&pb, packet); > > odp_execute_actions(dp, &pb, steal, nl_attr_get(subactions), > > nl_attr_get_size(subactions), dp_execute_action); > > } > > @@ -543,7 +543,7 @@ odp_execute_clone(void *dp, struct dp_packet > *packet, bool steal, > > * will free the clone. */ > > packet = dp_packet_clone(packet); > > } > > - packet_batch_init_packet(&pb, packet); > > + dp_packet_batch_init_packet(&pb, packet); > > odp_execute_actions(dp, &pb, true, nl_attr_get(actions), > > nl_attr_get_size(actions), dp_execute_action); > > } > > @@ -588,11 +588,9 @@ odp_execute_actions(void *dp, struct > dp_packet_batch *batch, bool steal, > > const struct nlattr *actions, size_t actions_len, > > odp_execute_cb dp_execute_action) > > { > > - struct dp_packet **packets = batch->packets; > > - int cnt = batch->count; > > + struct dp_packet *packet; > > 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); > > @@ -627,11 +625,10 @@ odp_execute_actions(void *dp, struct > dp_packet_batch *batch, bool steal, > > struct flow flow; > > uint32_t hash; > > > > - for (i = 0; i < cnt; i++) { > > - flow_extract(packets[i], &flow); > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > + flow_extract(packet, &flow); > > hash = flow_hash_5tuple(&flow, hash_act->hash_basis); > > - > > - packets[i]->md.dp_hash = hash; > > + packet->md.dp_hash = hash; > > } > > } else { > > /* Assert on unknown hash algorithm. */ > > @@ -643,48 +640,48 @@ odp_execute_actions(void *dp, struct > dp_packet_batch *batch, bool steal, > > case OVS_ACTION_ATTR_PUSH_VLAN: { > > const struct ovs_action_push_vlan *vlan = nl_attr_get(a); > > > > - for (i = 0; i < cnt; i++) { > > - eth_push_vlan(packets[i], vlan->vlan_tpid, > vlan->vlan_tci); > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > + eth_push_vlan(packet, vlan->vlan_tpid, vlan->vlan_tci); > > } > > break; > > } > > > > case OVS_ACTION_ATTR_POP_VLAN: > > - for (i = 0; i < cnt; i++) { > > - eth_pop_vlan(packets[i]); > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > + eth_pop_vlan(packet); > > } > > break; > > > > case OVS_ACTION_ATTR_PUSH_MPLS: { > > const struct ovs_action_push_mpls *mpls = nl_attr_get(a); > > > > - for (i = 0; i < cnt; i++) { > > - push_mpls(packets[i], mpls->mpls_ethertype, > mpls->mpls_lse); > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > + push_mpls(packet, mpls->mpls_ethertype, mpls->mpls_lse); > > } > > break; > > } > > > > case OVS_ACTION_ATTR_POP_MPLS: > > - for (i = 0; i < cnt; i++) { > > - pop_mpls(packets[i], nl_attr_get_be16(a)); > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > + pop_mpls(packet, nl_attr_get_be16(a)); > > } > > break; > > > > case OVS_ACTION_ATTR_SET: > > - for (i = 0; i < cnt; i++) { > > - odp_execute_set_action(packets[i], nl_attr_get(a)); > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > + odp_execute_set_action(packet, nl_attr_get(a)); > > } > > break; > > > > case OVS_ACTION_ATTR_SET_MASKED: > > - for (i = 0; i < cnt; i++) { > > - odp_execute_masked_set_action(packets[i], > nl_attr_get(a)); > > + DP_PACKET_BATCH_FOR_EACH(packet, batch) { > > + odp_execute_masked_set_action(packet, nl_attr_get(a)); > > } > > break; > > > > case OVS_ACTION_ATTR_SAMPLE: > > - for (i = 0; i < cnt; i++) { > > - odp_execute_sample(dp, packets[i], steal && > last_action, a, > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > + odp_execute_sample(dp, packet, steal && last_action, a, > > dp_execute_action); > > } > > > > @@ -700,15 +697,15 @@ odp_execute_actions(void *dp, struct > dp_packet_batch *batch, bool steal, > > nl_attr_get_unspec(a, sizeof *trunc); > > > > batch->trunc = true; > > - for (i = 0; i < cnt; i++) { > > - dp_packet_set_cutlen(packets[i], trunc->max_len); > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > + dp_packet_set_cutlen(packet, trunc->max_len); > > } > > break; > > } > > > > case OVS_ACTION_ATTR_CLONE: > > - for (i = 0; i < cnt; i++) { > > - odp_execute_clone(dp, packets[i], steal && last_action, > a, > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > + odp_execute_clone(dp, packet, steal && last_action, a, > > dp_execute_action); > > } > > > > @@ -732,8 +729,8 @@ odp_execute_actions(void *dp, struct dp_packet_batch > *batch, bool steal, > > } > > > > if (steal) { > > - for (i = 0; i < cnt; i++) { > > - dp_packet_delete(packets[i]); > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > + dp_packet_delete(packet); > > } > > Maybe it would be prudent to re-init the batch here? > Yes, I replaced the whole block with dp_packet_delete_batch() call. > > > } > > } > > diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c > > index 0513394..48b27a6 100644 > > --- a/ofproto/ofproto-dpif-xlate.c > > +++ b/ofproto/ofproto-dpif-xlate.c > > @@ -3825,7 +3825,7 @@ execute_controller_action(struct xlate_ctx *ctx, > int len, > > } > > > > packet = dp_packet_clone(ctx->xin->packet); > > - packet_batch_init_packet(&batch, packet); > > + dp_packet_batch_init_packet(&batch, packet); > > odp_execute_actions(NULL, &batch, false, > > ctx->odp_actions->data, ctx->odp_actions->size, > NULL); > > > > diff --git a/tests/test-conntrack.c b/tests/test-conntrack.c > > index 803e2b9..e362f8a 100644 > > --- a/tests/test-conntrack.c > > +++ b/tests/test-conntrack.c > > @@ -39,8 +39,6 @@ prepare_packets(size_t n, bool change, unsigned tid, > ovs_be16 *dl_type) > > ovs_assert(n <= ARRAY_SIZE(pkt_batch->packets)); > > > > dp_packet_batch_init(pkt_batch); > > - pkt_batch->count = n; > > - > > for (i = 0; i < n; i++) { > > struct udp_header *udp; > > struct dp_packet *pkt = dp_packet_new(sizeof payload/2); > > @@ -55,11 +53,10 @@ prepare_packets(size_t n, bool change, unsigned tid, > ovs_be16 *dl_type) > > udp->udp_dst = htons(ntohs(udp->udp_dst) + i); > > } > > > > - pkt_batch->packets[i] = pkt; > > + dp_packet_batch_add(pkt_batch, pkt); > > *dl_type = flow.dl_type; > > } > > > > - > > return pkt_batch; > > } > > > > @@ -154,7 +151,6 @@ static void > > pcap_batch_execute_conntrack(struct conntrack *ct, > > struct dp_packet_batch *pkt_batch) > > { > > - size_t i; > > struct dp_packet_batch new_batch; > > ovs_be16 dl_type = htons(0); > > > > @@ -162,15 +158,14 @@ pcap_batch_execute_conntrack(struct conntrack *ct, > > > > /* pkt_batch contains packets with different 'dl_type'. We have to > > * call conntrack_execute() on packets with the same 'dl_type'. */ > > - > > - for (i = 0; i < pkt_batch->count; i++) { > > - struct dp_packet *pkt = pkt_batch->packets[i]; > > + struct dp_packet *packet; > > + DP_PACKET_BATCH_FOR_EACH (packet, pkt_batch) { > > struct flow flow; > > > > /* This also initializes the l3 and l4 pointers. */ > > - flow_extract(pkt, &flow); > > + flow_extract(packet, &flow); > > > > - if (!new_batch.count) { > > + if (dp_packet_batch_is_empty(&new_batch)) { > > dl_type = flow.dl_type; > > } > > > > @@ -179,10 +174,10 @@ pcap_batch_execute_conntrack(struct conntrack *ct, > > NULL); > > dp_packet_batch_init(&new_batch); > > } > > - new_batch.packets[new_batch.count++] = pkt; > > + new_batch.packets[new_batch.count++] = packet;; > > } > > > > - if (new_batch.count) { > > + if (!dp_packet_batch_is_empty(&new_batch)) { > > conntrack_execute(ct, &new_batch, dl_type, true, 0, NULL, NULL, > NULL); > > } > > > > @@ -191,9 +186,9 @@ pcap_batch_execute_conntrack(struct conntrack *ct, > > static void > > test_pcap(struct ovs_cmdl_context *ctx) > > { > > - size_t total_count, i, batch_size; > > + size_t total_count, batch_size; > > FILE *pcap; > > - int err; > > + int err = 0; > > > > pcap = ovs_pcap_open(ctx->argv[1], "rb"); > > if (!pcap) { > > @@ -214,41 +209,36 @@ test_pcap(struct ovs_cmdl_context *ctx) > > > > conntrack_init(&ct); > > total_count = 0; > > - for (;;) { > > - struct dp_packet_batch pkt_batch; > > - > > - dp_packet_batch_init(&pkt_batch); > > + while (!err) { > > + struct dp_packet *packet; > > + struct dp_packet_batch pkt_batch_; > > + struct dp_packet_batch *batch = &pkt_batch_; > > > > - for (i = 0; i < batch_size; i++) { > > - err = ovs_pcap_read(pcap, &pkt_batch.packets[i], NULL); > > - if (err) { > > - break; > > - } > > + dp_packet_batch_init(batch); > > + err = ovs_pcap_read(pcap, &packet, NULL); > > + if (err) { > > + break; > > } > > + dp_packet_batch_add(batch, packet); > > > > - pkt_batch.count = i; > > - if (pkt_batch.count == 0) { > > + if (dp_packet_batch_is_empty(batch)) { > > We just added a packet to the batch above, so the batch cannot be empty > here?' > Good point. Removed. > > > break; > > } > > > > - pcap_batch_execute_conntrack(&ct, &pkt_batch); > > + pcap_batch_execute_conntrack(&ct, batch); > > > > - for (i = 0; i < pkt_batch.count; i++) { > > + DP_PACKET_BATCH_FOR_EACH (packet, batch) { > > struct ds ds = DS_EMPTY_INITIALIZER; > > - struct dp_packet *pkt = pkt_batch.packets[i]; > > > > total_count++; > > > > - format_flags(&ds, ct_state_to_string, pkt->md.ct_state, > '|'); > > + format_flags(&ds, ct_state_to_string, packet->md.ct_state, > '|'); > > printf("%"PRIuSIZE": %s\n", total_count, ds_cstr(&ds)); > > > > ds_destroy(&ds); > > } > > > > - dp_packet_delete_batch(&pkt_batch, true); > > - if (err) { > > - break; > > - } > > + dp_packet_delete_batch(batch, true); > > } > > conntrack_destroy(&ct); > > } > > -- > > 1.9.1 > > > > _______________________________________________ > > dev mailing list > > d...@openvswitch.org > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev