@@ -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. */
@@ -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);
@@ -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;
@@ -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. */
@@ -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. */
@@ -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);
@@ -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);
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 <i.maximets@samsung.com> --- 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(-)