seg6: export get_srh() for ICMP handling
authorAndrew Lunn <andrew@lunn.ch>
Mon, 3 Jan 2022 17:11:30 +0000 (18:11 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 4 Jan 2022 12:17:35 +0000 (12:17 +0000)
An ICMP error message can contain in its message body part of an IPv6
packet which invoked the error. Such a packet might contain a segment
router header. Export get_srh() so the ICMP code can make use of it.

Since his changes the scope of the function from local to global, add
the seg6_ prefix to keep the namespace clean. And move it into seg6.c
so it is always available, not just when IPV6_SEG6_LWTUNNEL is
enabled.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/seg6.h
net/ipv6/seg6.c
net/ipv6/seg6_local.c

index 9d19c15..a6f2598 100644 (file)
@@ -58,6 +58,7 @@ extern int seg6_local_init(void);
 extern void seg6_local_exit(void);
 
 extern bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len, bool reduced);
+extern struct ipv6_sr_hdr *seg6_get_srh(struct sk_buff *skb, int flags);
 extern int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh,
                             int proto);
 extern int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh);
index a8b5784..5bc9bf8 100644 (file)
@@ -75,6 +75,35 @@ bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len, bool reduced)
        return true;
 }
 
+struct ipv6_sr_hdr *seg6_get_srh(struct sk_buff *skb, int flags)
+{
+       struct ipv6_sr_hdr *srh;
+       int len, srhoff = 0;
+
+       if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, &flags) < 0)
+               return NULL;
+
+       if (!pskb_may_pull(skb, srhoff + sizeof(*srh)))
+               return NULL;
+
+       srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
+
+       len = (srh->hdrlen + 1) << 3;
+
+       if (!pskb_may_pull(skb, srhoff + len))
+               return NULL;
+
+       /* note that pskb_may_pull may change pointers in header;
+        * for this reason it is necessary to reload them when needed.
+        */
+       srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
+
+       if (!seg6_validate_srh(srh, len, true))
+               return NULL;
+
+       return srh;
+}
+
 static struct genl_family seg6_genl_family;
 
 static const struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX + 1] = {
index 2dc40b3..ef88489 100644 (file)
@@ -150,40 +150,11 @@ static struct seg6_local_lwt *seg6_local_lwtunnel(struct lwtunnel_state *lwt)
        return (struct seg6_local_lwt *)lwt->data;
 }
 
-static struct ipv6_sr_hdr *get_srh(struct sk_buff *skb, int flags)
-{
-       struct ipv6_sr_hdr *srh;
-       int len, srhoff = 0;
-
-       if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, &flags) < 0)
-               return NULL;
-
-       if (!pskb_may_pull(skb, srhoff + sizeof(*srh)))
-               return NULL;
-
-       srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
-
-       len = (srh->hdrlen + 1) << 3;
-
-       if (!pskb_may_pull(skb, srhoff + len))
-               return NULL;
-
-       /* note that pskb_may_pull may change pointers in header;
-        * for this reason it is necessary to reload them when needed.
-        */
-       srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
-
-       if (!seg6_validate_srh(srh, len, true))
-               return NULL;
-
-       return srh;
-}
-
 static struct ipv6_sr_hdr *get_and_validate_srh(struct sk_buff *skb)
 {
        struct ipv6_sr_hdr *srh;
 
-       srh = get_srh(skb, IP6_FH_F_SKIP_RH);
+       srh = seg6_get_srh(skb, IP6_FH_F_SKIP_RH);
        if (!srh)
                return NULL;
 
@@ -200,7 +171,7 @@ static bool decap_and_validate(struct sk_buff *skb, int proto)
        struct ipv6_sr_hdr *srh;
        unsigned int off = 0;
 
-       srh = get_srh(skb, 0);
+       srh = seg6_get_srh(skb, 0);
        if (srh && srh->segments_left > 0)
                return false;