From: Jarno Rajahalme Date: Fri, 6 Dec 2013 20:43:20 +0000 (-0800) Subject: lib/flow: Add IPv6 support for flow_compose(). X-Git-Tag: sliver-openvswitch-2.0.90-1~1^2~7 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;ds=sidebyside;h=52105b67878c83d16ef86f1b70fe8a076fdf69cb;p=sliver-openvswitch.git lib/flow: Add IPv6 support for flow_compose(). Add the missing code for generating IPv6 packets for testing purposes. Also make flow_compose() set the l4 and l7 pointers more consistently with flow_extract(). Signed-off-by: Jarno Rajahalme Acked-by: Ben Pfaff --- diff --git a/lib/flow.c b/lib/flow.c index 67003b335..0dfd01f09 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -1058,6 +1058,78 @@ flow_set_mpls_bos(struct flow *flow, uint8_t bos) set_mpls_lse_bos(&flow->mpls_lse, bos); } + +static void +flow_compose_l4(struct ofpbuf *b, const struct flow *flow) +{ + 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; + + tcp = ofpbuf_put_zeros(b, sizeof *tcp); + tcp->tcp_src = flow->tp_src; + tcp->tcp_dst = flow->tp_dst; + tcp->tcp_ctl = TCP_CTL(ntohs(flow->tcp_flags), 5); + b->l7 = ofpbuf_tail(b); + } else if (flow->nw_proto == IPPROTO_UDP) { + struct udp_header *udp; + + udp = ofpbuf_put_zeros(b, sizeof *udp); + udp->udp_src = flow->tp_src; + udp->udp_dst = flow->tp_dst; + b->l7 = ofpbuf_tail(b); + } else if (flow->nw_proto == IPPROTO_SCTP) { + struct sctp_header *sctp; + + sctp = ofpbuf_put_zeros(b, sizeof *sctp); + sctp->sctp_src = flow->tp_src; + sctp->sctp_dst = flow->tp_dst; + b->l7 = ofpbuf_tail(b); + } else if (flow->nw_proto == IPPROTO_ICMP) { + struct icmp_header *icmp; + + icmp = ofpbuf_put_zeros(b, sizeof *icmp); + icmp->icmp_type = ntohs(flow->tp_src); + icmp->icmp_code = ntohs(flow->tp_dst); + icmp->icmp_csum = csum(icmp, ICMP_HEADER_LEN); + b->l7 = ofpbuf_tail(b); + } else if (flow->nw_proto == IPPROTO_ICMPV6) { + struct icmp6_hdr *icmp; + + icmp = ofpbuf_put_zeros(b, sizeof *icmp); + icmp->icmp6_type = ntohs(flow->tp_src); + icmp->icmp6_code = ntohs(flow->tp_dst); + + if (icmp->icmp6_code == 0 && + (icmp->icmp6_type == ND_NEIGHBOR_SOLICIT || + icmp->icmp6_type == ND_NEIGHBOR_ADVERT)) { + struct in6_addr *nd_target; + struct nd_opt_hdr *nd_opt; + + nd_target = ofpbuf_put_zeros(b, sizeof *nd_target); + *nd_target = flow->nd_target; + + if (!eth_addr_is_zero(flow->arp_sha)) { + nd_opt = ofpbuf_put_zeros(b, 8); + nd_opt->nd_opt_len = 1; + nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; + memcpy(nd_opt + 1, flow->arp_sha, ETH_ADDR_LEN); + } + if (!eth_addr_is_zero(flow->arp_tha)) { + nd_opt = ofpbuf_put_zeros(b, 8); + nd_opt->nd_opt_len = 1; + nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; + memcpy(nd_opt + 1, flow->arp_tha, ETH_ADDR_LEN); + } + } + icmp->icmp6_cksum = (OVS_FORCE uint16_t) + csum(icmp, (char *)ofpbuf_tail(b) - (char *)icmp); + b->l7 = ofpbuf_tail(b); + } + } +} + /* Puts into 'b' a packet that flow_extract() would parse as having the given * 'flow'. * @@ -1067,6 +1139,7 @@ flow_set_mpls_bos(struct flow *flow, uint8_t bos) void flow_compose(struct ofpbuf *b, const struct flow *flow) { + /* eth_compose() sets l3 pointer and makes sure it is 32-bit aligned. */ eth_compose(b, flow->dl_dst, flow->dl_src, ntohs(flow->dl_type), 0); if (flow->dl_type == htons(FLOW_DL_TYPE_NONE)) { struct eth_header *eth = b->l2; @@ -1081,7 +1154,7 @@ flow_compose(struct ofpbuf *b, const struct flow *flow) if (flow->dl_type == htons(ETH_TYPE_IP)) { struct ip_header *ip; - b->l3 = ip = ofpbuf_put_zeros(b, sizeof *ip); + ip = ofpbuf_put_zeros(b, sizeof *ip); ip->ip_ihl_ver = IP_IHL_VER(5, 4); ip->ip_tos = flow->nw_tos; ip->ip_ttl = flow->nw_ttl; @@ -1095,44 +1168,32 @@ flow_compose(struct ofpbuf *b, const struct flow *flow) ip->ip_frag_off |= htons(100); } } - 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; - - b->l4 = tcp = ofpbuf_put_zeros(b, sizeof *tcp); - tcp->tcp_src = flow->tp_src; - tcp->tcp_dst = flow->tp_dst; - tcp->tcp_ctl = TCP_CTL(ntohs(flow->tcp_flags), 5); - } else if (flow->nw_proto == IPPROTO_UDP) { - struct udp_header *udp; - - b->l4 = udp = ofpbuf_put_zeros(b, sizeof *udp); - udp->udp_src = flow->tp_src; - udp->udp_dst = flow->tp_dst; - } else if (flow->nw_proto == IPPROTO_SCTP) { - struct sctp_header *sctp; - - b->l4 = sctp = ofpbuf_put_zeros(b, sizeof *sctp); - sctp->sctp_src = flow->tp_src; - sctp->sctp_dst = flow->tp_dst; - } else if (flow->nw_proto == IPPROTO_ICMP) { - struct icmp_header *icmp; - - b->l4 = icmp = ofpbuf_put_zeros(b, sizeof *icmp); - icmp->icmp_type = ntohs(flow->tp_src); - icmp->icmp_code = ntohs(flow->tp_dst); - icmp->icmp_csum = csum(icmp, ICMP_HEADER_LEN); - } - b->l7 = ofpbuf_tail(b); - } - ip = b->l3; + b->l4 = ofpbuf_tail(b); + + flow_compose_l4(b, flow); + ip->ip_tot_len = htons((uint8_t *) b->data + b->size - (uint8_t *) b->l3); ip->ip_csum = csum(ip, sizeof *ip); } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { - /* XXX */ + struct ovs_16aligned_ip6_hdr *nh; + + nh = ofpbuf_put_zeros(b, sizeof *nh); + put_16aligned_be32(&nh->ip6_flow, htonl(6 << 28) | + htonl(flow->nw_tos << 20) | flow->ipv6_label); + nh->ip6_hlim = flow->nw_ttl; + nh->ip6_nxt = flow->nw_proto; + + memcpy(&nh->ip6_src, &flow->ipv6_src, sizeof(nh->ip6_src)); + memcpy(&nh->ip6_dst, &flow->ipv6_dst, sizeof(nh->ip6_dst)); + + b->l4 = ofpbuf_tail(b); + + flow_compose_l4(b, flow); + + nh->ip6_plen = + b->l7 ? htons((uint8_t *) b->l7 - (uint8_t *) b->l4) : htons(0); } else if (flow->dl_type == htons(ETH_TYPE_ARP) || flow->dl_type == htons(ETH_TYPE_RARP)) { struct arp_eth_header *arp; diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 48c366a44..4d8d4602d 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -689,13 +689,13 @@ ovs-appctl -t ovs-ofctl exit AT_CHECK([cat ofctl_monitor.log], [0], [dnl NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1 +mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1 +mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1 dnl NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered) -mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1 +mplsm,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1 ]) @@ -1924,7 +1924,7 @@ HEADER pkt_len=64 stripped=4 hdr_len=60 - hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 + hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-67-00-00-00-00-00-0A-80-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-01-FE-80-00-00-00-00-00-00-00-00-00-00-00-00-00-02-00-00-00-00-00-00 ]) AT_CHECK([[sort sflow.log | $EGREP 'IFCOUNTERS|ERROR' | head -6 | sed 's/ /\ @@ -1961,7 +1961,7 @@ IFCOUNTERS ifspeed=100000000 direction=0 status=0 - in_octets=98 + in_octets=138 in_unicasts=3 in_multicasts=0 in_broadcasts=4294967295 @@ -2030,7 +2030,7 @@ IFCOUNTERS ifspeed=100000000 direction=0 status=0 - in_octets=98 + in_octets=138 in_unicasts=3 in_multicasts=0 in_broadcasts=4294967295