diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/flow.c | 126 | ||||
-rw-r--r-- | lib/flow.h | 4 | ||||
-rw-r--r-- | lib/netdev-dummy.c | 15 |
3 files changed, 75 insertions, 70 deletions
diff --git a/lib/flow.c b/lib/flow.c index f9d7c2a74..38ff29c8c 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -2692,56 +2692,66 @@ flow_set_mpls_lse(struct flow *flow, int idx, ovs_be32 lse) flow->mpls_lse[idx] = lse; } +static void +flow_compose_l7(struct dp_packet *p, const void *l7, size_t l7_len) +{ + if (l7_len) { + if (l7) { + dp_packet_put(p, l7, l7_len); + } else { + uint8_t *payload = dp_packet_put_uninit(p, l7_len); + for (size_t i = 0; i < l7_len; i++) { + payload[i] = i; + } + } + } +} + 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, + const void *l7, size_t l7_len) { - size_t l4_len = 0; + size_t orig_len = dp_packet_size(p); 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; - tcp = dp_packet_put_zeros(p, l4_len); + struct tcp_header *tcp = dp_packet_put_zeros(p, sizeof *tcp); tcp->tcp_src = flow->tp_src; tcp->tcp_dst = flow->tp_dst; tcp->tcp_ctl = TCP_CTL(ntohs(flow->tcp_flags), 5); + if (!(flow->tcp_flags & htons(TCP_SYN | TCP_FIN | TCP_RST))) { + flow_compose_l7(p, l7, l7_len); + } } else if (flow->nw_proto == IPPROTO_UDP) { - struct udp_header *udp; - - l4_len = sizeof *udp; - udp = dp_packet_put_zeros(p, l4_len); + struct udp_header *udp = dp_packet_put_zeros(p, sizeof *udp); udp->udp_src = flow->tp_src; udp->udp_dst = flow->tp_dst; - udp->udp_len = htons(l4_len); + udp->udp_len = htons(sizeof *udp + l7_len); + flow_compose_l7(p, l7, l7_len); } else if (flow->nw_proto == IPPROTO_SCTP) { - struct sctp_header *sctp; - - l4_len = sizeof *sctp; - sctp = dp_packet_put_zeros(p, l4_len); + struct sctp_header *sctp = dp_packet_put_zeros(p, sizeof *sctp); sctp->sctp_src = flow->tp_src; sctp->sctp_dst = flow->tp_dst; + /* XXX Someone should figure out what L7 data to include. */ } else if (flow->nw_proto == IPPROTO_ICMP) { - struct icmp_header *icmp; - - l4_len = sizeof *icmp; - icmp = dp_packet_put_zeros(p, l4_len); + struct icmp_header *icmp = dp_packet_put_zeros(p, sizeof *icmp); icmp->icmp_type = ntohs(flow->tp_src); icmp->icmp_code = ntohs(flow->tp_dst); + if ((icmp->icmp_type == ICMP4_ECHO_REQUEST || + icmp->icmp_type == ICMP4_ECHO_REPLY) + && icmp->icmp_code == 0) { + flow_compose_l7(p, l7, l7_len); + } else { + /* XXX Add inner IP packet for e.g. destination unreachable? */ + } } else if (flow->nw_proto == IPPROTO_IGMP) { - struct igmp_header *igmp; - - l4_len = sizeof *igmp; - igmp = dp_packet_put_zeros(p, l4_len); + struct igmp_header *igmp = dp_packet_put_zeros(p, sizeof *igmp); 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; - - l4_len = sizeof *icmp; - icmp = dp_packet_put_zeros(p, l4_len); + struct icmp6_hdr *icmp = dp_packet_put_zeros(p, sizeof *icmp); icmp->icmp6_type = ntohs(flow->tp_src); icmp->icmp6_code = ntohs(flow->tp_dst); @@ -2751,28 +2761,32 @@ 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; 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; 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; 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; } + } else if (icmp->icmp6_code == 0 && + (icmp->icmp6_type == ICMP6_ECHO_REQUEST || + icmp->icmp6_type == ICMP6_ECHO_REPLY)) { + flow_compose_l7(p, l7, l7_len); + } else { + /* XXX Add inner IP packet for e.g. destination unreachable? */ } } } - return l4_len; + + return dp_packet_size(p) - orig_len; } static void @@ -2820,7 +2834,7 @@ flow_compose_l4_csum(struct dp_packet *p, const struct flow *flow, * ip/udp lengths and l3/l4 checksums. * * 'size' needs to be larger then the current packet size. */ -static void +void packet_expand(struct dp_packet *p, const struct flow *flow, size_t size) { size_t extra_size; @@ -2870,10 +2884,19 @@ packet_expand(struct dp_packet *p, const struct flow *flow, size_t size) * (This is useful only for testing, obviously, and the packet isn't really * valid. Lots of fields are just zeroed.) * - * The created packet has minimal packet size, just big enough to hold - * the packet header fields. */ -static void -flow_compose_minimal(struct dp_packet *p, const struct flow *flow) + * For packets whose protocols can encapsulate arbitrary L7 payloads, 'l7' and + * 'l7_len' determine that payload: + * + * - If 'l7_len' is zero, no payload is included. + * + * - If 'l7_len' is nonzero and 'l7' is null, an arbitrary payload 'l7_len' + * bytes long is included. + * + * - If 'l7_len' is nonzero and 'l7' is nonnull, the payload is copied + * from 'l7'. */ +void +flow_compose(struct dp_packet *p, const struct flow *flow, + const void *l7, size_t l7_len) { uint32_t pseudo_hdr_csum; size_t l4_len; @@ -2913,7 +2936,7 @@ flow_compose_minimal(struct dp_packet *p, const struct flow *flow) dp_packet_set_l4(p, dp_packet_tail(p)); - l4_len = flow_compose_l4(p, flow); + l4_len = flow_compose_l4(p, flow, l7, l7_len); ip = dp_packet_l3(p); ip->ip_tot_len = htons(p->l4_ofs - p->l3_ofs + l4_len); @@ -2936,7 +2959,7 @@ flow_compose_minimal(struct dp_packet *p, const struct flow *flow) dp_packet_set_l4(p, dp_packet_tail(p)); - l4_len = flow_compose_l4(p, flow); + l4_len = flow_compose_l4(p, flow, l7, l7_len); nh = dp_packet_l3(p); nh->ip6_plen = htons(l4_len); @@ -2978,33 +3001,6 @@ flow_compose_minimal(struct dp_packet *p, const struct flow *flow) } } } - -/* Puts into 'p' a Ethernet frame of size 'size' that flow_extract() would - * parse as having the given 'flow'. - * - * When 'size' is zero, 'p' is a minimal size packet that only big enough - * to contains all packet headers. - * - * When 'size' is larger than the minimal packet size, the packet will - * be expended to 'size' with the payload set to zero. - * - * Return 'true' if the packet is successfully created. 'false' otherwise. - * Note, when 'size' is set to zero, this function always returns true. */ -bool -flow_compose(struct dp_packet *p, const struct flow *flow, size_t size) -{ - flow_compose_minimal(p, flow); - - if (size && size < dp_packet_size(p)) { - return false; - } - - if (size > dp_packet_size(p)) { - packet_expand(p, flow, size); - } - - return true; -} /* Compressed flow. */ diff --git a/lib/flow.h b/lib/flow.h index eb1e2bfc6..770a07a62 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -124,7 +124,9 @@ 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); -bool flow_compose(struct dp_packet *, const struct flow *, size_t); +void flow_compose(struct dp_packet *, const struct flow *, + const void *l7, size_t l7_len); +void packet_expand(struct dp_packet *, const struct flow *, size_t 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 4246af3b9..0d05759e4 100644 --- a/lib/netdev-dummy.c +++ b/lib/netdev-dummy.c @@ -1520,10 +1520,17 @@ eth_from_flow(const char *s, size_t packet_size) } packet = dp_packet_new(0); - if (!flow_compose(packet, &flow, packet_size)) { - dp_packet_delete(packet); - packet = NULL; - }; + if (packet_size) { + flow_compose(packet, &flow, NULL, 0); + if (dp_packet_size(packet) < packet_size) { + packet_expand(packet, &flow, packet_size); + } else if (dp_packet_size(packet) > packet_size){ + dp_packet_delete(packet); + packet = NULL; + } + } else { + flow_compose(packet, &flow, NULL, 64); + } ofpbuf_uninit(&odp_key); return packet; |