diff options
author | Daniele Di Proietto <diproiettod@vmware.com> | 2016-04-20 11:19:18 -0700 |
---|---|---|
committer | Daniele Di Proietto <diproiettod@vmware.com> | 2016-07-27 18:52:13 -0700 |
commit | e839d01eeb4bd7648733627764acea14428b5169 (patch) | |
tree | c8ad22a84cc3206df75f20ef42d54e6186584bbc /lib/flow.c | |
parent | 5d9cbb4cb8750dc10e9007b4817dc022bd815225 (diff) | |
download | openvswitch-e839d01eeb4bd7648733627764acea14428b5169.tar.gz |
flow: Generate checksum and udp_len in flow_compose().
This is useful to test the connection tracker, which performs checksum
and udp length verification.
Signed-off-by: Daniele Di Proietto <diproiettod@vmware.com>
Acked-by: Joe Stringer <joe@ovn.org>
Diffstat (limited to 'lib/flow.c')
-rw-r--r-- | lib/flow.c | 62 |
1 files changed, 54 insertions, 8 deletions
diff --git a/lib/flow.c b/lib/flow.c index 8cf707bee..ba4f8c774 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -2238,6 +2238,7 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow) udp = dp_packet_put_zeros(p, l4_len); udp->udp_src = flow->tp_src; udp->udp_dst = flow->tp_dst; + udp->udp_len = htons(l4_len); } else if (flow->nw_proto == IPPROTO_SCTP) { struct sctp_header *sctp; @@ -2252,8 +2253,6 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow) icmp = dp_packet_put_zeros(p, l4_len); icmp->icmp_type = ntohs(flow->tp_src); icmp->icmp_code = ntohs(flow->tp_dst); - /* Checksum has already been zeroed by put_zeros call. */ - icmp->icmp_csum = csum(icmp, ICMP_HEADER_LEN); } else if (flow->nw_proto == IPPROTO_IGMP) { struct igmp_header *igmp; @@ -2262,8 +2261,6 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow) igmp->igmp_type = ntohs(flow->tp_src); igmp->igmp_code = ntohs(flow->tp_dst); put_16aligned_be32(&igmp->group, flow->igmp_group_ip4); - /* Checksum has already been zeroed by put_zeros call. */ - igmp->igmp_csum = csum(igmp, IGMP_HEADER_LEN); } else if (flow->nw_proto == IPPROTO_ICMPV6) { struct icmp6_hdr *icmp; @@ -2297,22 +2294,65 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow) nd_opt->nd_opt_mac = flow->arp_tha; } } - icmp->icmp6_cksum = (OVS_FORCE uint16_t) - csum(icmp, (char *)dp_packet_tail(p) - (char *)icmp); } } return l4_len; } +static void +flow_compose_l4_csum(struct dp_packet *p, const struct flow *flow, + uint32_t pseudo_hdr_csum) +{ + size_t l4_len = (char *) dp_packet_tail(p) - (char *) dp_packet_l4(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 = dp_packet_l4(p); + + /* Checksum has already been zeroed by put_zeros call in + * flow_compose_l4(). */ + tcp->tcp_csum = csum_finish(csum_continue(pseudo_hdr_csum, + tcp, l4_len)); + } else if (flow->nw_proto == IPPROTO_UDP) { + struct udp_header *udp = dp_packet_l4(p); + + /* Checksum has already been zeroed by put_zeros call in + * flow_compose_l4(). */ + udp->udp_csum = csum_finish(csum_continue(pseudo_hdr_csum, + udp, l4_len)); + } else if (flow->nw_proto == IPPROTO_ICMP) { + struct icmp_header *icmp = dp_packet_l4(p); + + /* Checksum has already been zeroed by put_zeros call in + * flow_compose_l4(). */ + icmp->icmp_csum = csum(icmp, l4_len); + } else if (flow->nw_proto == IPPROTO_IGMP) { + struct igmp_header *igmp = dp_packet_l4(p); + + /* Checksum has already been zeroed by put_zeros call in + * flow_compose_l4(). */ + igmp->igmp_csum = csum(igmp, l4_len); + } else if (flow->nw_proto == IPPROTO_ICMPV6) { + struct icmp6_hdr *icmp = dp_packet_l4(p); + + /* Checksum has already been zeroed by put_zeros call in + * flow_compose_l4(). */ + icmp->icmp6_cksum = (OVS_FORCE uint16_t) + csum_finish(csum_continue(pseudo_hdr_csum, icmp, l4_len)); + } + } +} + /* Puts into 'b' a packet that flow_extract() would parse as having the given * 'flow'. * * (This is useful only for testing, obviously, and the packet isn't really - * valid. It hasn't got some checksums filled in, for one, and lots of fields - * are just zeroed.) */ + * valid. Lots of fields are just zeroed.) */ void flow_compose(struct dp_packet *p, const struct flow *flow) { + uint32_t pseudo_hdr_csum; size_t l4_len; /* eth_compose() sets l3 pointer and makes sure it is 32-bit aligned. */ @@ -2353,6 +2393,9 @@ flow_compose(struct dp_packet *p, const struct flow *flow) ip->ip_tot_len = htons(p->l4_ofs - p->l3_ofs + l4_len); /* Checksum has already been zeroed by put_zeros call. */ ip->ip_csum = csum(ip, sizeof *ip); + + pseudo_hdr_csum = packet_csum_pseudoheader(ip); + flow_compose_l4_csum(p, flow, pseudo_hdr_csum); } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { struct ovs_16aligned_ip6_hdr *nh; @@ -2371,6 +2414,9 @@ flow_compose(struct dp_packet *p, const struct flow *flow) 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); } else if (flow->dl_type == htons(ETH_TYPE_ARP) || flow->dl_type == htons(ETH_TYPE_RARP)) { struct arp_eth_header *arp; |