diff mbox series

[ovs-dev,v11,3/5] flow: Support rt_hdr in parse_ipv6_ext_hdrs().

Message ID 20230328064223.51144-4-nmiki@yahoo-corp.jp
State Changes Requested
Headers show
Series userspace: Add SRv6 tunnel support. | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed
ovsrobot/intel-ovs-compilation success test: success

Commit Message

Nobuhiro MIKI March 28, 2023, 6:42 a.m. UTC
Checks whether IPPROTO_ROUTING exists in the IPv6 extension headers.
If it exists, the first address is retrieved.

If NULL is specified for "frag_hdr" and/or "rt_hdr", those addresses in
the header are not reported to the caller. Of course, "frag_hdr" and
"rt_hdr" are properly parsed inside this function.

Signed-off-by: Nobuhiro MIKI <nmiki@yahoo-corp.jp>
---
 lib/conntrack.c |  4 ++--
 lib/flow.c      | 48 +++++++++++++++++++++++++++++++++++++-----------
 lib/flow.h      |  3 ++-
 lib/ipf.c       | 15 ++++++++-------
 lib/packets.h   |  9 +++++++++
 5 files changed, 58 insertions(+), 21 deletions(-)
diff mbox series

Patch

diff --git a/lib/conntrack.c b/lib/conntrack.c
index 8cf7779c6703..f86fa26f466d 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -1617,8 +1617,8 @@  extract_l3_ipv6(struct conn_key *key, const void *data, size_t size,
     uint8_t nw_proto = ip6->ip6_nxt;
     uint8_t nw_frag = 0;
 
-    const struct ovs_16aligned_ip6_frag *frag_hdr;
-    if (!parse_ipv6_ext_hdrs(&data, &size, &nw_proto, &nw_frag, &frag_hdr)) {
+    if (!parse_ipv6_ext_hdrs(&data, &size, &nw_proto, &nw_frag,
+                             NULL, NULL)) {
         return false;
     }
 
diff --git a/lib/flow.c b/lib/flow.c
index c3a3aa3ce45d..9501a259e9d4 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -479,9 +479,17 @@  invalid:
 static inline bool
 parse_ipv6_ext_hdrs__(const void **datap, size_t *sizep, uint8_t *nw_proto,
                       uint8_t *nw_frag,
-                      const struct ovs_16aligned_ip6_frag **frag_hdr)
+                      const struct ovs_16aligned_ip6_frag **frag_hdr,
+                      const struct ip6_rt_hdr **rt_hdr)
 {
-    *frag_hdr = NULL;
+    if (frag_hdr) {
+        *frag_hdr = NULL;
+    }
+
+    if (rt_hdr) {
+        *rt_hdr = NULL;
+    }
+
     while (1) {
         if (OVS_LIKELY((*nw_proto != IPPROTO_HOPOPTS)
                        && (*nw_proto != IPPROTO_ROUTING)
@@ -504,7 +512,6 @@  parse_ipv6_ext_hdrs__(const void **datap, size_t *sizep, uint8_t *nw_proto,
         }
 
         if ((*nw_proto == IPPROTO_HOPOPTS)
-            || (*nw_proto == IPPROTO_ROUTING)
             || (*nw_proto == IPPROTO_DSTOPTS)) {
             /* These headers, while different, have the fields we care
              * about in the same location and with the same
@@ -515,6 +522,18 @@  parse_ipv6_ext_hdrs__(const void **datap, size_t *sizep, uint8_t *nw_proto,
                                             (ext_hdr->ip6e_len + 1) * 8))) {
                 return false;
             }
+        } else if (*nw_proto == IPPROTO_ROUTING) {
+            const struct ip6_rt_hdr *tmp;
+            if (!rt_hdr) {
+                rt_hdr = &tmp;
+            }
+
+            *rt_hdr = *datap;
+            *nw_proto = (*rt_hdr)->nexthdr;
+            if (OVS_UNLIKELY(!data_try_pull(datap, sizep,
+                                            ((*rt_hdr)->hdrlen + 1) * 8))) {
+                return false;
+            }
         } else if (*nw_proto == IPPROTO_AH) {
             /* A standard AH definition isn't available, but the fields
              * we care about are in the same location as the generic
@@ -527,6 +546,11 @@  parse_ipv6_ext_hdrs__(const void **datap, size_t *sizep, uint8_t *nw_proto,
                 return false;
             }
         } else if (*nw_proto == IPPROTO_FRAGMENT) {
+            const struct ovs_16aligned_ip6_frag *tmp;
+            if (!frag_hdr) {
+                frag_hdr = &tmp;
+            }
+
             *frag_hdr = *datap;
 
             *nw_proto = (*frag_hdr)->ip6f_nxt;
@@ -561,15 +585,19 @@  parse_ipv6_ext_hdrs__(const void **datap, size_t *sizep, uint8_t *nw_proto,
  * has FLOW_NW_FRAG_LATER set.  Both first and later fragments have
  * FLOW_NW_FRAG_ANY set in 'nw_frag'.
  *
+ * If a routing header is found, '*rt_hdr' is set to the routing
+ * header and otherwise set to NULL.
+ *
  * A return value of false indicates that there was a problem parsing
  * the extension headers.*/
 bool
 parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto,
                     uint8_t *nw_frag,
-                    const struct ovs_16aligned_ip6_frag **frag_hdr)
+                    const struct ovs_16aligned_ip6_frag **frag_hdr,
+                    const struct ip6_rt_hdr **rt_hdr)
 {
     return parse_ipv6_ext_hdrs__(datap, sizep, nw_proto, nw_frag,
-                                 frag_hdr);
+                                 frag_hdr, rt_hdr);
 }
 
 bool
@@ -945,9 +973,8 @@  miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
         nw_ttl = nh->ip6_hlim;
         nw_proto = nh->ip6_nxt;
 
-        const struct ovs_16aligned_ip6_frag *frag_hdr;
-        if (!parse_ipv6_ext_hdrs__(&data, &size, &nw_proto, &nw_frag,
-                                   &frag_hdr)) {
+        if (!parse_ipv6_ext_hdrs(&data, &size, &nw_proto, &nw_frag,
+                                 NULL, NULL)) {
             goto out;
         }
 
@@ -1200,10 +1227,9 @@  parse_tcp_flags(struct dp_packet *packet,
         plen = ntohs(nh->ip6_plen); /* Never pull padding. */
         dp_packet_set_l2_pad_size(packet, size - plen);
         size = plen;
-        const struct ovs_16aligned_ip6_frag *frag_hdr;
         nw_proto = nh->ip6_nxt;
-        if (!parse_ipv6_ext_hdrs__(&data, &size, &nw_proto, &nw_frag,
-            &frag_hdr)) {
+        if (!parse_ipv6_ext_hdrs(&data, &size, &nw_proto, &nw_frag,
+                                 NULL, NULL)) {
             return 0;
         }
     } else {
diff --git a/lib/flow.h b/lib/flow.h
index c647ad83c256..a9d026e1ce3b 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -132,7 +132,8 @@  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,
-                         const struct ovs_16aligned_ip6_frag **frag_hdr);
+                         const struct ovs_16aligned_ip6_frag **frag_hdr,
+                         const struct ip6_rt_hdr **rt_hdr);
 bool parse_nsh(const void **datap, size_t *sizep, struct ovs_key_nsh *key);
 uint16_t parse_tcp_flags(struct dp_packet *packet, ovs_be16 *dl_type_p,
                          uint8_t *nw_frag_p, ovs_be16 *first_vlan_tci_p);
diff --git a/lib/ipf.c b/lib/ipf.c
index d452663743c5..affd440f6387 100644
--- a/lib/ipf.c
+++ b/lib/ipf.c
@@ -485,9 +485,9 @@  ipf_reassemble_v6_frags(struct ipf_list *ipf_list)
     const void *data = l3 + 1;
     size_t datasize = pl;
 
-    const struct ovs_16aligned_ip6_frag *frag_hdr = NULL;
-    if (!parse_ipv6_ext_hdrs(&data, &datasize, &nw_proto, &nw_frag, &frag_hdr)
-        || !nw_frag || !frag_hdr) {
+    const struct ovs_16aligned_ip6_frag *frag_hdr;
+    if (!parse_ipv6_ext_hdrs(&data, &datasize, &nw_proto, &nw_frag, &frag_hdr,
+                             NULL) || !nw_frag || !frag_hdr) {
 
         ipf_print_reass_packet("Unparsed reassembled v6 packet; v6 hdr:", l3);
         dp_packet_delete(pkt);
@@ -678,9 +678,9 @@  ipf_is_valid_v6_frag(struct ipf *ipf, struct dp_packet *pkt)
     uint8_t nw_proto = l3->ip6_nxt;
     const void *data = l3 + 1;
     size_t datasize = l3_size - l3_hdr_size;
-    const struct ovs_16aligned_ip6_frag *frag_hdr = NULL;
+    const struct ovs_16aligned_ip6_frag *frag_hdr;
     if (!parse_ipv6_ext_hdrs(&data, &datasize, &nw_proto, &nw_frag,
-                             &frag_hdr) || !nw_frag || !frag_hdr) {
+                             &frag_hdr, NULL) || !nw_frag || !frag_hdr) {
         return false;
     }
 
@@ -721,9 +721,10 @@  ipf_v6_key_extract(struct dp_packet *pkt, ovs_be16 dl_type, uint16_t zone,
     uint8_t nw_proto = l3->ip6_nxt;
     const void *data = l3 + 1;
     size_t datasize = dp_packet_l3_size(pkt) - sizeof *l3;
-    const struct ovs_16aligned_ip6_frag *frag_hdr = NULL;
+    const struct ovs_16aligned_ip6_frag *frag_hdr;
 
-    parse_ipv6_ext_hdrs(&data, &datasize, &nw_proto, &nw_frag, &frag_hdr);
+    parse_ipv6_ext_hdrs(&data, &datasize, &nw_proto, &nw_frag, &frag_hdr,
+                        NULL);
     ovs_assert(nw_frag && frag_hdr);
     ovs_be16 ip6f_offlg = frag_hdr->ip6f_offlg;
     *start_data_byte = ntohs(ip6f_offlg & IP6F_OFF_MASK) +
diff --git a/lib/packets.h b/lib/packets.h
index 8626aac8d53f..70cd072228ae 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -988,6 +988,15 @@  struct ovs_16aligned_ip6_frag {
     ovs_16aligned_be32 ip6f_ident;
 };
 
+#define IP6_RT_HDR_LEN 4
+struct ip6_rt_hdr {
+    uint8_t nexthdr;
+    uint8_t hdrlen;
+    uint8_t type;
+    uint8_t segments_left;
+};
+BUILD_ASSERT_DECL(IP6_RT_HDR_LEN == sizeof(struct ip6_rt_hdr));
+
 #define ICMP6_HEADER_LEN 4
 struct icmp6_header {
     uint8_t icmp6_type;