[ovs-dev] [PATCH v4 2/6] lib/flow: Add IPv6 support for flow_compose().

Jarno Rajahalme jrajahalme at nicira.com
Tue Nov 26 19:24:48 UTC 2013


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 <jrajahalme at nicira.com>
---
 lib/flow.c            |   94 +++++++++++++++++++++++++++++++++++++++++++++----
 lib/packets.c         |    4 +--
 lib/packets.h         |    2 ++
 tests/ofproto-dpif.at |   12 +++----
 4 files changed, 97 insertions(+), 15 deletions(-)

diff --git a/lib/flow.c b/lib/flow.c
index c6683a5..3f2fb19 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -1077,44 +1077,124 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
                 ip->ip_frag_off |= htons(100);
             }
         }
+
+        b->l4 = ofpbuf_tail(b);
+
         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 = 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;
 
-                b->l4 = udp = ofpbuf_put_zeros(b, sizeof *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;
 
-                b->l4 = sctp = ofpbuf_put_zeros(b, sizeof *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;
 
-                b->l4 = icmp = ofpbuf_put_zeros(b, sizeof *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);
             }
-            b->l7 = ofpbuf_tail(b);
         }
 
-        ip = b->l3;
         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;
+
+        b->l3 = nh = ofpbuf_put_zeros(b, sizeof *nh);
+        nh->ip6_vfc = IP_IHL_VER(0, 6);
+        packet_set_ipv6_tc(&nh->ip6_flow, flow->nw_tos);
+        packet_set_ipv6_flow_label(&nh->ip6_flow, 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);
+
+        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_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);
+            }
+        }
+
+        nh->ip6_plen = b->l7
+            ? htons((uint8_t *) b->l7 - (uint8_t *) b->l4)
+            : CONSTANT_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/lib/packets.c b/lib/packets.c
index 4bec4d1..5349d41 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -752,7 +752,7 @@ packet_set_ipv6_addr(struct ofpbuf *packet, uint8_t proto,
     memcpy(addr, new_addr, sizeof(*addr));
 }
 
-static void
+void
 packet_set_ipv6_flow_label(ovs_16aligned_be32 *flow_label, ovs_be32 flow_key)
 {
     ovs_be32 old_label = get_16aligned_be32(flow_label);
@@ -760,7 +760,7 @@ packet_set_ipv6_flow_label(ovs_16aligned_be32 *flow_label, ovs_be32 flow_key)
     put_16aligned_be32(flow_label, new_label);
 }
 
-static void
+void
 packet_set_ipv6_tc(ovs_16aligned_be32 *flow_label, uint8_t tc)
 {
     ovs_be32 old_label = get_16aligned_be32(flow_label);
diff --git a/lib/packets.h b/lib/packets.h
index ef8c00c..a1e1859 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -637,6 +637,8 @@ void packet_set_ipv4(struct ofpbuf *, ovs_be32 src, ovs_be32 dst, uint8_t tos,
 void packet_set_ipv6(struct ofpbuf *, uint8_t proto, const ovs_be32 src[4],
                      const ovs_be32 dst[4], uint8_t tc,
                      ovs_be32 fl, uint8_t hlmit);
+void packet_set_ipv6_tc(ovs_16aligned_be32 *, uint8_t tc);
+void packet_set_ipv6_flow_label(ovs_16aligned_be32 *, ovs_be32 flow_key);
 void packet_set_tcp_port(struct ofpbuf *, ovs_be16 src, ovs_be16 dst);
 void packet_set_udp_port(struct ofpbuf *, ovs_be16 src, ovs_be16 dst);
 void packet_set_sctp_port(struct ofpbuf *, ovs_be16 src, ovs_be16 dst);
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index b78e156..e817061 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
-- 
1.7.10.4




More information about the dev mailing list