diff mbox series

[net-next,1/1] net: seg6: Add support for SRv6 Headend Reduced Encapsulation

Message ID 20220608112646.9331-1-anton.makarov11235@gmail.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series [net-next,1/1] net: seg6: Add support for SRv6 Headend Reduced Encapsulation | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Single patches do not need cover letters
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 29 this patch: 30
netdev/cc_maintainers warning 4 maintainers not CCed: yoshfuji@linux-ipv6.org pabeni@redhat.com dsahern@kernel.org edumazet@google.com
netdev/build_clang success Errors and warnings before: 6 this patch: 6
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 29 this patch: 30
netdev/checkpatch warning CHECK: Alignment should match open parenthesis CHECK: extern prototypes should be avoided in .h files WARNING: From:/Signed-off-by: email address mismatch: 'From: Anton Makarov <antonmakarov11235@gmail.com>' != 'Signed-off-by: Anton Makarov <anton.makarov11235@gmail.com>' WARNING: line length of 83 exceeds 80 columns WARNING: line length of 87 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Anton Makarov June 8, 2022, 11:26 a.m. UTC
SRv6 Headend H.Encaps.Red and H.Encaps.L2.Red behaviors are implemented
accordingly to RFC 8986. The H.Encaps.Red is an optimization of
The H.Encaps behavior. The H.Encaps.L2.Red is an optimization of
the H.Encaps.L2 behavior. Both new behaviors reduce the length of
the SRH by excluding the first SID in the SRH of the pushed IPv6 header.
The first SID is only placed in the Destination Address field
of the pushed IPv6 header.

The push of the SRH is omitted when the SRv6 Policy only contains
one segment.

Signed-off-by: Anton Makarov <anton.makarov11235@gmail.com>
---
 include/net/seg6.h                 |  2 +
 include/uapi/linux/seg6_iptunnel.h |  2 +
 net/ipv6/seg6_iptunnel.c           | 95 +++++++++++++++++++++++++++++-
 3 files changed, 97 insertions(+), 2 deletions(-)

Comments

Jakub Kicinski June 9, 2022, 3:45 a.m. UTC | #1
On Wed,  8 Jun 2022 14:26:46 +0300 Anton Makarov wrote:
> SRv6 Headend H.Encaps.Red and H.Encaps.L2.Red behaviors are implemented
> accordingly to RFC 8986. The H.Encaps.Red is an optimization of
> The H.Encaps behavior. The H.Encaps.L2.Red is an optimization of
> the H.Encaps.L2 behavior. Both new behaviors reduce the length of
> the SRH by excluding the first SID in the SRH of the pushed IPv6 header.
> The first SID is only placed in the Destination Address field
> of the pushed IPv6 header.
> 
> The push of the SRH is omitted when the SRv6 Policy only contains
> one segment.

missing byte swaps (install sparse and build with C=1 to catch it):

net/ipv6/seg6_iptunnel.c:237:56: warning: incorrect type in argument 1 (different base types)
net/ipv6/seg6_iptunnel.c:237:56:    expected restricted __be32 [usertype] flowinfo
net/ipv6/seg6_iptunnel.c:237:56:    got unsigned char [usertype] tos

Other random notes on things that jumped out:

> +	memset(skb->cb, 0, 48);

sizeof() is better

> +EXPORT_SYMBOL_GPL(seg6_do_srh_encap_red);

Why the export, this function should be static it seems, it's only used
in a since C source.
kernel test robot June 10, 2022, 12:52 a.m. UTC | #2
Hi Anton,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Anton-Makarov/net-seg6-Add-support-for-SRv6-Headend-Reduced-Encapsulation/20220608-193600
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git da6e113ff010815fdd21ee1e9af2e8d179a2680f
config: parisc-randconfig-s032-20220608 (https://download.01.org/0day-ci/archive/20220610/202206100834.gCKYSSPQ-lkp@intel.com/config)
compiler: hppa-linux-gcc (GCC) 11.3.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # apt-get install sparse
        # sparse version: v0.6.4-26-gb3cf30ba-dirty
        # https://github.com/intel-lab-lkp/linux/commit/16ea0251e14bdf1f5dea8a1a90318df7aac69038
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Anton-Makarov/net-seg6-Add-support-for-SRv6-Headend-Reduced-Encapsulation/20220608-193600
        git checkout 16ea0251e14bdf1f5dea8a1a90318df7aac69038
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.3.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=parisc SHELL=/bin/bash net/ipv6/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)
>> net/ipv6/seg6_iptunnel.c:237:56: sparse: sparse: incorrect type in argument 1 (different base types) @@     expected restricted __be32 [usertype] flowinfo @@     got unsigned char [usertype] tos @@
   net/ipv6/seg6_iptunnel.c:237:56: sparse:     expected restricted __be32 [usertype] flowinfo
   net/ipv6/seg6_iptunnel.c:237:56: sparse:     got unsigned char [usertype] tos

vim +237 net/ipv6/seg6_iptunnel.c

   199	
   200	/* encapsulate an IPv6 packet within an outer IPv6 header with reduced SRH */
   201	int seg6_do_srh_encap_red(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
   202	{
   203		struct dst_entry *dst = skb_dst(skb);
   204		struct net *net = dev_net(dst->dev);
   205		struct ipv6hdr *hdr, *inner_hdr6;
   206		struct iphdr *inner_hdr4;
   207		struct ipv6_sr_hdr *isrh;
   208		int hdrlen = 0, tot_len, err;
   209		__be32 flowlabel = 0;
   210	
   211		if (osrh->first_segment > 0)
   212			hdrlen = (osrh->hdrlen - 1) << 3;
   213	
   214		tot_len = hdrlen + sizeof(struct ipv6hdr);
   215	
   216		err = skb_cow_head(skb, tot_len + skb->mac_len);
   217		if (unlikely(err))
   218			return err;
   219	
   220		inner_hdr6 = ipv6_hdr(skb);
   221		inner_hdr4 = ip_hdr(skb);
   222		flowlabel = seg6_make_flowlabel(net, skb, inner_hdr6);
   223	
   224		skb_push(skb, tot_len);
   225		skb_reset_network_header(skb);
   226		skb_mac_header_rebuild(skb);
   227		hdr = ipv6_hdr(skb);
   228	
   229		memset(skb->cb, 0, 48);
   230		IP6CB(skb)->iif = skb->skb_iif;
   231	
   232		if (skb->protocol == htons(ETH_P_IPV6)) {
   233			ip6_flow_hdr(hdr, ip6_tclass(ip6_flowinfo(inner_hdr6)),
   234				     flowlabel);
   235			hdr->hop_limit = inner_hdr6->hop_limit;
   236		} else if (skb->protocol == htons(ETH_P_IP)) {
 > 237			ip6_flow_hdr(hdr, ip6_tclass(inner_hdr4->tos), flowlabel);
   238			hdr->hop_limit = inner_hdr4->ttl;
   239		}
   240	
   241		skb->protocol = htons(ETH_P_IPV6);
   242	
   243		hdr->daddr = osrh->segments[osrh->first_segment];
   244		hdr->version = 6;
   245	
   246		if (osrh->first_segment > 0) {
   247			hdr->nexthdr = NEXTHDR_ROUTING;
   248	
   249			isrh = (void *)hdr + sizeof(struct ipv6hdr);
   250			memcpy(isrh, osrh, hdrlen);
   251	
   252			isrh->nexthdr = proto;
   253			isrh->first_segment--;
   254			isrh->hdrlen -= 2;
   255		} else {
   256			hdr->nexthdr = proto;
   257		}
   258	
   259		set_tun_src(net, dst->dev, &hdr->daddr, &hdr->saddr);
   260
diff mbox series

Patch

diff --git a/include/net/seg6.h b/include/net/seg6.h
index af668f17b398..8d0ce782f830 100644
--- a/include/net/seg6.h
+++ b/include/net/seg6.h
@@ -62,6 +62,8 @@  extern struct ipv6_sr_hdr *seg6_get_srh(struct sk_buff *skb, int flags);
 extern void seg6_icmp_srh(struct sk_buff *skb, struct inet6_skb_parm *opt);
 extern int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh,
 			     int proto);
+extern int seg6_do_srh_encap_red(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);
diff --git a/include/uapi/linux/seg6_iptunnel.h b/include/uapi/linux/seg6_iptunnel.h
index eb815e0d0ac3..a9fa777f16de 100644
--- a/include/uapi/linux/seg6_iptunnel.h
+++ b/include/uapi/linux/seg6_iptunnel.h
@@ -35,6 +35,8 @@  enum {
 	SEG6_IPTUN_MODE_INLINE,
 	SEG6_IPTUN_MODE_ENCAP,
 	SEG6_IPTUN_MODE_L2ENCAP,
+	SEG6_IPTUN_MODE_ENCAP_RED,
+	SEG6_IPTUN_MODE_L2ENCAP_RED,
 };
 
 #endif
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index d64855010948..430975b03597 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -36,9 +36,11 @@  static size_t seg6_lwt_headroom(struct seg6_iptunnel_encap *tuninfo)
 	case SEG6_IPTUN_MODE_INLINE:
 		break;
 	case SEG6_IPTUN_MODE_ENCAP:
+	case SEG6_IPTUN_MODE_ENCAP_RED:
 		head = sizeof(struct ipv6hdr);
 		break;
 	case SEG6_IPTUN_MODE_L2ENCAP:
+	case SEG6_IPTUN_MODE_L2ENCAP_RED:
 		return 0;
 	}
 
@@ -195,6 +197,81 @@  int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
 }
 EXPORT_SYMBOL_GPL(seg6_do_srh_encap);
 
+/* encapsulate an IPv6 packet within an outer IPv6 header with reduced SRH */
+int seg6_do_srh_encap_red(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
+{
+	struct dst_entry *dst = skb_dst(skb);
+	struct net *net = dev_net(dst->dev);
+	struct ipv6hdr *hdr, *inner_hdr6;
+	struct iphdr *inner_hdr4;
+	struct ipv6_sr_hdr *isrh;
+	int hdrlen = 0, tot_len, err;
+	__be32 flowlabel = 0;
+
+	if (osrh->first_segment > 0)
+		hdrlen = (osrh->hdrlen - 1) << 3;
+
+	tot_len = hdrlen + sizeof(struct ipv6hdr);
+
+	err = skb_cow_head(skb, tot_len + skb->mac_len);
+	if (unlikely(err))
+		return err;
+
+	inner_hdr6 = ipv6_hdr(skb);
+	inner_hdr4 = ip_hdr(skb);
+	flowlabel = seg6_make_flowlabel(net, skb, inner_hdr6);
+
+	skb_push(skb, tot_len);
+	skb_reset_network_header(skb);
+	skb_mac_header_rebuild(skb);
+	hdr = ipv6_hdr(skb);
+
+	memset(skb->cb, 0, 48);
+	IP6CB(skb)->iif = skb->skb_iif;
+
+	if (skb->protocol == htons(ETH_P_IPV6)) {
+		ip6_flow_hdr(hdr, ip6_tclass(ip6_flowinfo(inner_hdr6)),
+			     flowlabel);
+		hdr->hop_limit = inner_hdr6->hop_limit;
+	} else if (skb->protocol == htons(ETH_P_IP)) {
+		ip6_flow_hdr(hdr, ip6_tclass(inner_hdr4->tos), flowlabel);
+		hdr->hop_limit = inner_hdr4->ttl;
+	}
+
+	skb->protocol = htons(ETH_P_IPV6);
+
+	hdr->daddr = osrh->segments[osrh->first_segment];
+	hdr->version = 6;
+
+	if (osrh->first_segment > 0) {
+		hdr->nexthdr = NEXTHDR_ROUTING;
+
+		isrh = (void *)hdr + sizeof(struct ipv6hdr);
+		memcpy(isrh, osrh, hdrlen);
+
+		isrh->nexthdr = proto;
+		isrh->first_segment--;
+		isrh->hdrlen -= 2;
+	} else {
+		hdr->nexthdr = proto;
+	}
+
+	set_tun_src(net, dst->dev, &hdr->daddr, &hdr->saddr);
+
+#ifdef CONFIG_IPV6_SEG6_HMAC
+	if (osrh->first_segment > 0 && sr_has_hmac(isrh)) {
+		err = seg6_push_hmac(net, &hdr->saddr, isrh);
+		if (unlikely(err))
+			return err;
+	}
+#endif
+
+	skb_postpush_rcsum(skb, hdr, tot_len);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(seg6_do_srh_encap_red);
+
 /* insert an SRH within an IPv6 packet, just after the IPv6 header */
 int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
 {
@@ -265,6 +342,7 @@  static int seg6_do_srh(struct sk_buff *skb)
 			return err;
 		break;
 	case SEG6_IPTUN_MODE_ENCAP:
+	case SEG6_IPTUN_MODE_ENCAP_RED:
 		err = iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6);
 		if (err)
 			return err;
@@ -276,7 +354,11 @@  static int seg6_do_srh(struct sk_buff *skb)
 		else
 			return -EINVAL;
 
-		err = seg6_do_srh_encap(skb, tinfo->srh, proto);
+		if (tinfo->mode == SEG6_IPTUN_MODE_ENCAP)
+			err = seg6_do_srh_encap(skb, tinfo->srh, proto);
+		else
+			err = seg6_do_srh_encap_red(skb, tinfo->srh, proto);
+
 		if (err)
 			return err;
 
@@ -285,6 +367,7 @@  static int seg6_do_srh(struct sk_buff *skb)
 		skb->protocol = htons(ETH_P_IPV6);
 		break;
 	case SEG6_IPTUN_MODE_L2ENCAP:
+	case SEG6_IPTUN_MODE_L2ENCAP_RED:
 		if (!skb_mac_header_was_set(skb))
 			return -EINVAL;
 
@@ -294,7 +377,11 @@  static int seg6_do_srh(struct sk_buff *skb)
 		skb_mac_header_rebuild(skb);
 		skb_push(skb, skb->mac_len);
 
-		err = seg6_do_srh_encap(skb, tinfo->srh, IPPROTO_ETHERNET);
+		if (tinfo->mode == SEG6_IPTUN_MODE_L2ENCAP)
+			err = seg6_do_srh_encap(skb, tinfo->srh, IPPROTO_ETHERNET);
+		else
+			err = seg6_do_srh_encap_red(skb, tinfo->srh, IPPROTO_ETHERNET);
+
 		if (err)
 			return err;
 
@@ -514,6 +601,10 @@  static int seg6_build_state(struct net *net, struct nlattr *nla,
 		break;
 	case SEG6_IPTUN_MODE_L2ENCAP:
 		break;
+	case SEG6_IPTUN_MODE_ENCAP_RED:
+		break;
+	case SEG6_IPTUN_MODE_L2ENCAP_RED:
+		break;
 	default:
 		return -EINVAL;
 	}