[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1559321320-9444-4-git-send-email-tom@quantonium.net>
Date: Fri, 31 May 2019 09:48:37 -0700
From: Tom Herbert <tom@...bertland.com>
To: davem@...emloft.net, netdev@...r.kernel.org, dlebrun@...gle.com,
ahabdels.dev@...il.com
Cc: Tom Herbert <tom@...ntonium.net>
Subject: [RFC PATCH 3/6] seg6: Obsolete unused SRH flags
Currently no flags are defined for segment routing in
draft-ietf-6man-segment-routing-header-19. Mark them as being
obsolete.
The HMAC flag is the only one used by the stack. This needs
additional consideration.
Rewrite sr_has_hmac in uapi/linux/seg6.h to properly parse a
segment routing header as opposed to relying on the now obsolete
code.
Implement seg6_find_hmac_tlv for internal stack use. That function
parses (via __seg6_parse_srh) a TLV list and returns the pointer to
an HMAC TLV if one exists. The parsing function also eliminates the
assumption in seg6_get_tlv_hmac that the HMAC TLV must be the first TLV.
Signed-off-by: Tom Herbert <tom@...ntonium.net>
---
include/net/seg6.h | 12 +++++++++++-
include/uapi/linux/seg6.h | 49 ++++++++++++++++++++++++++++++++++++++++-------
net/ipv6/exthdrs.c | 2 +-
net/ipv6/seg6.c | 12 ++++++++++--
net/ipv6/seg6_hmac.c | 8 +++-----
net/ipv6/seg6_iptunnel.c | 4 ++--
6 files changed, 69 insertions(+), 18 deletions(-)
diff --git a/include/net/seg6.h b/include/net/seg6.h
index 563d4a6..47e7c90 100644
--- a/include/net/seg6.h
+++ b/include/net/seg6.h
@@ -17,6 +17,7 @@
#include <linux/net.h>
#include <linux/ipv6.h>
#include <linux/seg6.h>
+#include <linux/seg6_hmac.h>
#include <linux/rhashtable-types.h>
static inline void update_csum_diff4(struct sk_buff *skb, __be32 from,
@@ -67,11 +68,20 @@ extern void seg6_iptunnel_exit(void);
extern int seg6_local_init(void);
extern void seg6_local_exit(void);
-extern bool __seg6_parse_srh(struct ipv6_sr_hdr *srh);
+extern bool __seg6_parse_srh(struct ipv6_sr_hdr *srh,
+ struct sr6_tlv_hmac **hmacp);
extern bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len);
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);
extern int seg6_lookup_nexthop(struct sk_buff *skb, struct in6_addr *nhaddr,
u32 tbl_id);
+
+static inline struct sr6_tlv_hmac *seg6_find_hmac_tlv(struct ipv6_sr_hdr *srh)
+{
+ struct sr6_tlv_hmac *hmacp = NULL;
+
+ return __seg6_parse_srh(srh, &hmacp) ? hmacp : NULL;
+}
+
#endif
diff --git a/include/uapi/linux/seg6.h b/include/uapi/linux/seg6.h
index 9117113..890420b0 100644
--- a/include/uapi/linux/seg6.h
+++ b/include/uapi/linux/seg6.h
@@ -33,11 +33,10 @@ struct ipv6_sr_hdr {
struct in6_addr segments[0];
};
-#define SR6_FLAG1_PROTECTED (1 << 6)
-#define SR6_FLAG1_OAM (1 << 5)
-#define SR6_FLAG1_ALERT (1 << 4)
-#define SR6_FLAG1_HMAC (1 << 3)
-
+#define SR6_FLAG1_PROTECTED (1 << 6) /* obsoleted */
+#define SR6_FLAG1_OAM (1 << 5) /* obsoleted */
+#define SR6_FLAG1_ALERT (1 << 4) /* obsoleted */
+#define SR6_FLAG1_HMAC (1 << 3) /* obsoleted */
#define SR6_TLV_INGRESS 1 /* obsoleted */
#define SR6_TLV_EGRESS 2 /* obsoleted */
@@ -47,12 +46,48 @@ struct ipv6_sr_hdr {
#define SR6_TLV_PADDING 1
#define SR6_TLV_HMAC 5
-#define sr_has_hmac(srh) ((srh)->flags & SR6_FLAG1_HMAC)
-
struct sr6_tlv {
__u8 type;
__u8 len;
__u8 data[0];
};
+static inline bool __sr_has_hmac(struct ipv6_sr_hdr *srh)
+{
+ unsigned char *opt = (unsigned char *)srh;
+ int len = (srh->hdrlen + 1) << 8;
+ unsigned int off;
+
+ off = sizeof(*srh) + ((srh->first_segment + 1) << 4);
+ len -= off;
+
+ while (len > 0) {
+ struct sr6_tlv *tlv;
+ unsigned int optlen;
+
+ switch (opt[off]) {
+ case SR6_TLV_PAD1:
+ optlen = 1;
+ break;
+ case SR6_TLV_HMAC:
+ return true;
+ default:
+ if (len < sizeof(*tlv))
+ return false;
+
+ tlv = (struct sr6_tlv *)&opt[off];
+ optlen = sizeof(*tlv) + tlv->len;
+
+ break;
+ }
+
+ off += optlen;
+ len -= optlen;
+ }
+
+ return false;
+}
+
+#define sr_has_hmac(srh) __sr_has_hmac(srh)
+
#endif
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 20291c2..112e2fd 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -922,7 +922,7 @@ static void ipv6_push_rthdr4(struct sk_buff *skb, u8 *proto,
}
#ifdef CONFIG_IPV6_SEG6_HMAC
- if (sr_has_hmac(sr_phdr)) {
+ if (seg6_find_hmac_tlv(sr_phdr)) {
struct net *net = NULL;
if (skb->dev)
diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c
index e461357..1e782a6 100644
--- a/net/ipv6/seg6.c
+++ b/net/ipv6/seg6.c
@@ -30,7 +30,7 @@
#include <net/seg6_hmac.h>
#endif
-bool __seg6_parse_srh(struct ipv6_sr_hdr *srh)
+bool __seg6_parse_srh(struct ipv6_sr_hdr *srh, struct sr6_tlv_hmac **hmacp)
{
int len = ipv6_optlen((struct ipv6_opt_hdr *)srh);
unsigned char *opt = (unsigned char *)srh;
@@ -39,6 +39,8 @@ bool __seg6_parse_srh(struct ipv6_sr_hdr *srh)
off = seg6_tlv_offset(srh);
len -= off;
+ *hmacp = NULL;
+
while (len > 0) {
struct sr6_tlv *tlv;
unsigned int optlen;
@@ -47,6 +49,10 @@ bool __seg6_parse_srh(struct ipv6_sr_hdr *srh)
case SR6_TLV_PAD1:
optlen = 1;
break;
+ case SR6_TLV_HMAC:
+ if (!*hmacp)
+ *hmacp = (struct sr6_tlv_hmac *)&opt[off];
+ /* Fall through */
default:
if (len < sizeof(*tlv))
return false;
@@ -66,6 +72,8 @@ bool __seg6_parse_srh(struct ipv6_sr_hdr *srh)
bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len)
{
+ struct sr6_tlv_hmac *hmacp;
+
if (srh->type != IPV6_SRCRT_TYPE_4)
return false;
@@ -75,7 +83,7 @@ bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len)
if (srh->segments_left > srh->first_segment)
return false;
- return __seg6_parse_srh(srh);
+ return __seg6_parse_srh(srh, &hmacp);
}
static struct genl_family seg6_genl_family;
diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c
index 8546f94..92b398c 100644
--- a/net/ipv6/seg6_hmac.c
+++ b/net/ipv6/seg6_hmac.c
@@ -95,13 +95,11 @@ static struct sr6_tlv_hmac *seg6_get_tlv_hmac(struct ipv6_sr_hdr *srh)
if (srh->hdrlen < (srh->first_segment + 1) * 2 + 5)
return NULL;
- if (!sr_has_hmac(srh))
+ tlv = seg6_find_hmac_tlv(srh);
+ if (!tlv)
return NULL;
- tlv = (struct sr6_tlv_hmac *)
- ((char *)srh + ((srh->hdrlen + 1) << 3) - 40);
-
- if (tlv->tlvhdr.type != SR6_TLV_HMAC || tlv->tlvhdr.len != 38)
+ if (tlv->tlvhdr.len != sizeof(*tlv) - 2)
return NULL;
return tlv;
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index 7a525fd..5344bee 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -161,7 +161,7 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
set_tun_src(net, dst->dev, &hdr->daddr, &hdr->saddr);
#ifdef CONFIG_IPV6_SEG6_HMAC
- if (sr_has_hmac(isrh)) {
+ if (seg6_find_hmac_tlv(isrh)) {
err = seg6_push_hmac(net, &hdr->saddr, isrh);
if (unlikely(err))
return err;
@@ -211,7 +211,7 @@ int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
hdr->daddr = isrh->segments[isrh->first_segment];
#ifdef CONFIG_IPV6_SEG6_HMAC
- if (sr_has_hmac(isrh)) {
+ if (seg6_find_hmac_tlv(isrh)) {
struct net *net = dev_net(skb_dst(skb)->dev);
err = seg6_push_hmac(net, &hdr->saddr, isrh);
--
2.7.4
Powered by blists - more mailing lists