This allows to compose packets with different real lenghts from odp flows i.e. memory will be allocated for requested packet size and all required headers like ip->tot_len filled correctly.
Will be used in netdev-dummy to properly handle '--len' option. Signed-off-by: Ilya Maximets <[email protected]> --- lib/flow.c | 65 ++++++++++++++++++++++++++++++-------------- lib/flow.h | 2 +- lib/netdev-dummy.c | 2 +- ofproto/ofproto-dpif-trace.c | 2 +- ofproto/ofproto-dpif.c | 2 +- ovn/controller/ofctrl.c | 2 +- tests/test-ovn.c | 2 +- 7 files changed, 51 insertions(+), 26 deletions(-) diff --git a/lib/flow.c b/lib/flow.c index e1597fa..fd0fac4 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -2613,16 +2613,14 @@ flow_set_mpls_lse(struct flow *flow, int idx, ovs_be32 lse) } static size_t -flow_compose_l4(struct dp_packet *p, const struct flow *flow) +flow_compose_l4(struct dp_packet *p, const struct flow *flow, size_t l4_len) { - size_t l4_len = 0; - if (!(flow->nw_frag & FLOW_NW_FRAG_ANY) || !(flow->nw_frag & FLOW_NW_FRAG_LATER)) { if (flow->nw_proto == IPPROTO_TCP) { struct tcp_header *tcp; - l4_len = sizeof *tcp; + l4_len = MAX(l4_len, sizeof *tcp); tcp = dp_packet_put_zeros(p, l4_len); tcp->tcp_src = flow->tp_src; tcp->tcp_dst = flow->tp_dst; @@ -2630,7 +2628,7 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow) } else if (flow->nw_proto == IPPROTO_UDP) { struct udp_header *udp; - l4_len = sizeof *udp; + l4_len = MAX(l4_len, sizeof *udp); udp = dp_packet_put_zeros(p, l4_len); udp->udp_src = flow->tp_src; udp->udp_dst = flow->tp_dst; @@ -2638,30 +2636,31 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow) } else if (flow->nw_proto == IPPROTO_SCTP) { struct sctp_header *sctp; - l4_len = sizeof *sctp; + l4_len = MAX(l4_len, sizeof *sctp); sctp = dp_packet_put_zeros(p, l4_len); sctp->sctp_src = flow->tp_src; sctp->sctp_dst = flow->tp_dst; } else if (flow->nw_proto == IPPROTO_ICMP) { struct icmp_header *icmp; - l4_len = sizeof *icmp; + l4_len = MAX(l4_len, sizeof *icmp); icmp = dp_packet_put_zeros(p, l4_len); icmp->icmp_type = ntohs(flow->tp_src); icmp->icmp_code = ntohs(flow->tp_dst); } else if (flow->nw_proto == IPPROTO_IGMP) { struct igmp_header *igmp; - l4_len = sizeof *igmp; + l4_len = MAX(l4_len, sizeof *igmp); igmp = dp_packet_put_zeros(p, l4_len); igmp->igmp_type = ntohs(flow->tp_src); igmp->igmp_code = ntohs(flow->tp_dst); put_16aligned_be32(&igmp->group, flow->igmp_group_ip4); } else if (flow->nw_proto == IPPROTO_ICMPV6) { struct icmp6_hdr *icmp; + size_t icmpv6_len; - l4_len = sizeof *icmp; - icmp = dp_packet_put_zeros(p, l4_len); + icmpv6_len = sizeof *icmp; + icmp = dp_packet_put_zeros(p, icmpv6_len); icmp->icmp6_type = ntohs(flow->tp_src); icmp->icmp6_code = ntohs(flow->tp_dst); @@ -2671,26 +2670,33 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow) struct in6_addr *nd_target; struct ovs_nd_lla_opt *lla_opt; - l4_len += sizeof *nd_target; + icmpv6_len += sizeof *nd_target; nd_target = dp_packet_put_zeros(p, sizeof *nd_target); *nd_target = flow->nd_target; if (!eth_addr_is_zero(flow->arp_sha)) { - l4_len += 8; + icmpv6_len += 8; lla_opt = dp_packet_put_zeros(p, 8); lla_opt->len = 1; lla_opt->type = ND_OPT_SOURCE_LINKADDR; lla_opt->mac = flow->arp_sha; } if (!eth_addr_is_zero(flow->arp_tha)) { - l4_len += 8; + icmpv6_len += 8; lla_opt = dp_packet_put_zeros(p, 8); lla_opt->len = 1; lla_opt->type = ND_OPT_TARGET_LINKADDR; lla_opt->mac = flow->arp_tha; } } + if (icmpv6_len < l4_len) { + dp_packet_put_zeros(p, l4_len - icmpv6_len); + } else { + l4_len = icmpv6_len; + } } + } else { + dp_packet_put_zeros(p, l4_len); } return l4_len; } @@ -2741,20 +2747,28 @@ flow_compose_l4_csum(struct dp_packet *p, const struct flow *flow, } /* Puts into 'p' a packet that flow_extract() would parse as having the given - * 'flow'. + * 'flow'. Tries to create packet with size equal to 'packet_size'. Resulted + * packet could be larger in case all required headers do not fit in the + * requested size. * * (This is useful only for testing, obviously, and the packet isn't really * valid. Lots of fields are just zeroed.) */ void -flow_compose(struct dp_packet *p, const struct flow *flow) +flow_compose(struct dp_packet *p, const struct flow *flow, size_t packet_size) { uint32_t pseudo_hdr_csum; size_t l4_len; + int extra_size; /* eth_compose() sets l3 pointer and makes sure it is 32-bit aligned. */ eth_compose(p, flow->dl_dst, flow->dl_src, ntohs(flow->dl_type), 0); if (flow->dl_type == htons(FLOW_DL_TYPE_NONE)) { struct eth_header *eth = dp_packet_eth(p); + + extra_size = packet_size - dp_packet_size(p); + if (extra_size > 0) { + dp_packet_put_zeros(p, extra_size); + } eth->eth_type = htons(dp_packet_size(p)); return; } @@ -2786,7 +2800,8 @@ flow_compose(struct dp_packet *p, const struct flow *flow) dp_packet_set_l4(p, dp_packet_tail(p)); - l4_len = flow_compose_l4(p, flow); + extra_size = packet_size - dp_packet_size(p); + l4_len = flow_compose_l4(p, flow, (extra_size > 0) ? extra_size : 0); ip = dp_packet_l3(p); ip->ip_tot_len = htons(p->l4_ofs - p->l3_ofs + l4_len); @@ -2795,6 +2810,9 @@ flow_compose(struct dp_packet *p, const struct flow *flow) pseudo_hdr_csum = packet_csum_pseudoheader(ip); flow_compose_l4_csum(p, flow, pseudo_hdr_csum); + + return; + } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { struct ovs_16aligned_ip6_hdr *nh; @@ -2809,13 +2827,17 @@ flow_compose(struct dp_packet *p, const struct flow *flow) dp_packet_set_l4(p, dp_packet_tail(p)); - l4_len = flow_compose_l4(p, flow); + extra_size = packet_size - dp_packet_size(p); + l4_len = flow_compose_l4(p, flow, (extra_size > 0) ? extra_size : 0); nh = dp_packet_l3(p); nh->ip6_plen = htons(l4_len); pseudo_hdr_csum = packet_csum_pseudoheader6(nh); flow_compose_l4_csum(p, flow, pseudo_hdr_csum); + + return; + } else if (flow->dl_type == htons(ETH_TYPE_ARP) || flow->dl_type == htons(ETH_TYPE_RARP)) { struct arp_eth_header *arp; @@ -2835,9 +2857,7 @@ flow_compose(struct dp_packet *p, const struct flow *flow) arp->ar_sha = flow->arp_sha; arp->ar_tha = flow->arp_tha; } - } - - if (eth_type_mpls(flow->dl_type)) { + } else if (eth_type_mpls(flow->dl_type)) { int n; p->l2_5_ofs = p->l3_ofs; @@ -2850,6 +2870,11 @@ flow_compose(struct dp_packet *p, const struct flow *flow) push_mpls(p, flow->dl_type, flow->mpls_lse[--n]); } } + + extra_size = packet_size - dp_packet_size(p); + if (extra_size > 0) { + dp_packet_put_zeros(p, extra_size); + } } /* Compressed flow. */ diff --git a/lib/flow.h b/lib/flow.h index 9297842..651c0ef 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -124,7 +124,7 @@ void flow_set_mpls_tc(struct flow *, int idx, uint8_t tc); void flow_set_mpls_bos(struct flow *, int idx, uint8_t stack); void flow_set_mpls_lse(struct flow *, int idx, ovs_be32 lse); -void flow_compose(struct dp_packet *, const struct flow *); +void flow_compose(struct dp_packet *, const struct flow *, size_t packet_size); bool parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto, uint8_t *nw_frag); diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c index 51d29d5..6ee6a6a 100644 --- a/lib/netdev-dummy.c +++ b/lib/netdev-dummy.c @@ -1478,7 +1478,7 @@ eth_from_flow(const char *s) } packet = dp_packet_new(0); - flow_compose(packet, &flow); + flow_compose(packet, &flow, 0); ofpbuf_uninit(&odp_key); return packet; diff --git a/ofproto/ofproto-dpif-trace.c b/ofproto/ofproto-dpif-trace.c index b3f3cbc..38d1100 100644 --- a/ofproto/ofproto-dpif-trace.c +++ b/ofproto/ofproto-dpif-trace.c @@ -376,7 +376,7 @@ parse_flow_and_packet(int argc, const char *argv[], /* Generate a packet, if requested. */ if (packet) { if (!dp_packet_size(packet)) { - flow_compose(packet, flow); + flow_compose(packet, flow, 0); } else { /* Use the metadata from the flow and the packet argument * to reconstruct the flow. */ diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 7cf1a40..eb4e493 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -1287,7 +1287,7 @@ check_ct_eventmask(struct dpif_backer *backer) /* Compose a dummy UDP packet. */ dp_packet_init(&packet, 0); - flow_compose(&packet, &flow); + flow_compose(&packet, &flow, 0); /* Execute the actions. On older datapaths this fails with EINVAL, on * newer datapaths it succeeds. */ diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c index 5aff230..7164ff0 100644 --- a/ovn/controller/ofctrl.c +++ b/ovn/controller/ofctrl.c @@ -1150,7 +1150,7 @@ ofctrl_inject_pkt(const struct ovsrec_bridge *br_int, const char *flow_s, uint64_t packet_stub[128 / 8]; struct dp_packet packet; dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub); - flow_compose(&packet, &uflow); + flow_compose(&packet, &uflow, 0); uint64_t ofpacts_stub[1024 / 8]; struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); diff --git a/tests/test-ovn.c b/tests/test-ovn.c index ca27a0f..a216b82 100644 --- a/tests/test-ovn.c +++ b/tests/test-ovn.c @@ -1164,7 +1164,7 @@ test_expr_to_packets(struct ovs_cmdl_context *ctx OVS_UNUSED) uint64_t packet_stub[128 / 8]; struct dp_packet packet; dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub); - flow_compose(&packet, &uflow); + flow_compose(&packet, &uflow, 0); struct ds output = DS_EMPTY_INITIALIZER; const uint8_t *buf = dp_packet_data(&packet); -- 2.7.4 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
