mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	seg6: add NEXT-C-SID support for SRv6 End.X behavior
The NEXT-C-SID mechanism described in [1] offers the possibility of
encoding several SRv6 segments within a single 128 bit SID address. Such
a SID address is called a Compressed SID (C-SID) container. In this way,
the length of the SID List can be drastically reduced.
A SID instantiated with the NEXT-C-SID flavor considers an IPv6 address
logically structured in three main blocks: i) Locator-Block; ii)
Locator-Node Function; iii) Argument.
                        C-SID container
+------------------------------------------------------------------+
|     Locator-Block      |Loc-Node|            Argument            |
|                        |Function|                                |
+------------------------------------------------------------------+
<--------- B -----------> <- NF -> <------------- A --------------->
   (i) The Locator-Block can be any IPv6 prefix available to the provider;
  (ii) The Locator-Node Function represents the node and the function to
       be triggered when a packet is received on the node;
 (iii) The Argument carries the remaining C-SIDs in the current C-SID
       container.
This patch leverages the NEXT-C-SID mechanism previously introduced in the
Linux SRv6 subsystem [2] to support SID compression capabilities in the
SRv6 End.X behavior [3].
An SRv6 End.X behavior with NEXT-C-SID flavor works as an End.X behavior
but it is capable of processing the compressed SID List encoded in C-SID
containers.
An SRv6 End.X behavior with NEXT-C-SID flavor can be configured to support
user-provided Locator-Block and Locator-Node Function lengths. In this
implementation, such lengths must be evenly divisible by 8 (i.e. must be
byte-aligned), otherwise the kernel informs the user about invalid
values with a meaningful error code and message through netlink_ext_ack.
If Locator-Block and/or Locator-Node Function lengths are not provided
by the user during configuration of an SRv6 End.X behavior instance with
NEXT-C-SID flavor, the kernel will choose their default values i.e.,
32-bit Locator-Block and 16-bit Locator-Node Function.
[1] - https://datatracker.ietf.org/doc/html/draft-ietf-spring-srv6-srh-compression
[2] - https://lore.kernel.org/all/20220912171619.16943-1-andrea.mayer@uniroma2.it/
[3] - https://datatracker.ietf.org/doc/html/rfc8986#name-endx-l3-cross-connect
Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
Reviewed-by: Hangbin Liu <liuhangbin@gmail.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://lore.kernel.org/r/20230812180926.16689-2-andrea.mayer@uniroma2.it
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
			
			
This commit is contained in:
		
							parent
							
								
									c65dffc6f2
								
							
						
					
					
						commit
						7458575a07
					
				
					 1 changed files with 88 additions and 20 deletions
				
			
		| 
						 | 
					@ -109,15 +109,19 @@ struct bpf_lwt_prog {
 | 
				
			||||||
#define next_csid_chk_lcnode_fn_bits(flen)		\
 | 
					#define next_csid_chk_lcnode_fn_bits(flen)		\
 | 
				
			||||||
	next_csid_chk_lcblock_bits(flen)
 | 
						next_csid_chk_lcblock_bits(flen)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* flag indicating that flavors are set up for a given End* behavior */
 | 
				
			||||||
 | 
					#define SEG6_F_LOCAL_FLAVORS		SEG6_F_ATTR(SEG6_LOCAL_FLAVORS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SEG6_F_LOCAL_FLV_OP(flvname)	BIT(SEG6_LOCAL_FLV_OP_##flvname)
 | 
					#define SEG6_F_LOCAL_FLV_OP(flvname)	BIT(SEG6_LOCAL_FLV_OP_##flvname)
 | 
				
			||||||
 | 
					#define SEG6_F_LOCAL_FLV_NEXT_CSID	SEG6_F_LOCAL_FLV_OP(NEXT_CSID)
 | 
				
			||||||
#define SEG6_F_LOCAL_FLV_PSP		SEG6_F_LOCAL_FLV_OP(PSP)
 | 
					#define SEG6_F_LOCAL_FLV_PSP		SEG6_F_LOCAL_FLV_OP(PSP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Supported RFC8986 Flavor operations are reported in this bitmask */
 | 
					/* Supported RFC8986 Flavor operations are reported in this bitmask */
 | 
				
			||||||
#define SEG6_LOCAL_FLV8986_SUPP_OPS	SEG6_F_LOCAL_FLV_PSP
 | 
					#define SEG6_LOCAL_FLV8986_SUPP_OPS	SEG6_F_LOCAL_FLV_PSP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Supported Flavor operations are reported in this bitmask */
 | 
					#define SEG6_LOCAL_END_FLV_SUPP_OPS	(SEG6_F_LOCAL_FLV_NEXT_CSID | \
 | 
				
			||||||
#define SEG6_LOCAL_FLV_SUPP_OPS		(SEG6_F_LOCAL_FLV_OP(NEXT_CSID) | \
 | 
					 | 
				
			||||||
					 SEG6_LOCAL_FLV8986_SUPP_OPS)
 | 
										 SEG6_LOCAL_FLV8986_SUPP_OPS)
 | 
				
			||||||
 | 
					#define SEG6_LOCAL_END_X_FLV_SUPP_OPS	SEG6_F_LOCAL_FLV_NEXT_CSID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct seg6_flavors_info {
 | 
					struct seg6_flavors_info {
 | 
				
			||||||
	/* Flavor operations */
 | 
						/* Flavor operations */
 | 
				
			||||||
| 
						 | 
					@ -411,9 +415,72 @@ static int end_next_csid_core(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 | 
				
			||||||
	return input_action_end_finish(skb, slwt);
 | 
						return input_action_end_finish(skb, slwt);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int input_action_end_x_finish(struct sk_buff *skb,
 | 
				
			||||||
 | 
									     struct seg6_local_lwt *slwt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						seg6_lookup_nexthop(skb, &slwt->nh6, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return dst_input(skb);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int input_action_end_x_core(struct sk_buff *skb,
 | 
				
			||||||
 | 
									   struct seg6_local_lwt *slwt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ipv6_sr_hdr *srh;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						srh = get_and_validate_srh(skb);
 | 
				
			||||||
 | 
						if (!srh)
 | 
				
			||||||
 | 
							goto drop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						advance_nextseg(srh, &ipv6_hdr(skb)->daddr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return input_action_end_x_finish(skb, slwt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					drop:
 | 
				
			||||||
 | 
						kfree_skb(skb);
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int end_x_next_csid_core(struct sk_buff *skb,
 | 
				
			||||||
 | 
									struct seg6_local_lwt *slwt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct seg6_flavors_info *finfo = &slwt->flv_info;
 | 
				
			||||||
 | 
						struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (seg6_next_csid_is_arg_zero(daddr, finfo))
 | 
				
			||||||
 | 
							return input_action_end_x_core(skb, slwt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* update DA */
 | 
				
			||||||
 | 
						seg6_next_csid_advance_arg(daddr, finfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return input_action_end_x_finish(skb, slwt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool seg6_next_csid_enabled(__u32 fops)
 | 
					static bool seg6_next_csid_enabled(__u32 fops)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return fops & BIT(SEG6_LOCAL_FLV_OP_NEXT_CSID);
 | 
						return fops & SEG6_F_LOCAL_FLV_NEXT_CSID;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Processing of SRv6 End, End.X, and End.T behaviors can be extended through
 | 
				
			||||||
 | 
					 * the flavors framework. These behaviors must report the subset of (flavor)
 | 
				
			||||||
 | 
					 * operations they currently implement. In this way, if a user specifies a
 | 
				
			||||||
 | 
					 * flavor combination that is not supported by a given End* behavior, the
 | 
				
			||||||
 | 
					 * kernel refuses to instantiate the tunnel reporting the error.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int seg6_flv_supp_ops_by_action(int action, __u32 *fops)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (action) {
 | 
				
			||||||
 | 
						case SEG6_LOCAL_ACTION_END:
 | 
				
			||||||
 | 
							*fops = SEG6_LOCAL_END_FLV_SUPP_OPS;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SEG6_LOCAL_ACTION_END_X:
 | 
				
			||||||
 | 
							*fops = SEG6_LOCAL_END_X_FLV_SUPP_OPS;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* We describe the packet state in relation to the absence/presence of the SRH
 | 
					/* We describe the packet state in relation to the absence/presence of the SRH
 | 
				
			||||||
| 
						 | 
					@ -746,21 +813,14 @@ static int input_action_end(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 | 
				
			||||||
/* regular endpoint, and forward to specified nexthop */
 | 
					/* regular endpoint, and forward to specified nexthop */
 | 
				
			||||||
static int input_action_end_x(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 | 
					static int input_action_end_x(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ipv6_sr_hdr *srh;
 | 
						const struct seg6_flavors_info *finfo = &slwt->flv_info;
 | 
				
			||||||
 | 
						__u32 fops = finfo->flv_ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	srh = get_and_validate_srh(skb);
 | 
						/* check for the presence of NEXT-C-SID since it applies first */
 | 
				
			||||||
	if (!srh)
 | 
						if (seg6_next_csid_enabled(fops))
 | 
				
			||||||
		goto drop;
 | 
							return end_x_next_csid_core(skb, slwt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	advance_nextseg(srh, &ipv6_hdr(skb)->daddr);
 | 
						return input_action_end_x_core(skb, slwt);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	seg6_lookup_nexthop(skb, &slwt->nh6, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return dst_input(skb);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
drop:
 | 
					 | 
				
			||||||
	kfree_skb(skb);
 | 
					 | 
				
			||||||
	return -EINVAL;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int input_action_end_t(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 | 
					static int input_action_end_t(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 | 
				
			||||||
| 
						 | 
					@ -1404,13 +1464,14 @@ static struct seg6_action_desc seg6_action_table[] = {
 | 
				
			||||||
		.action		= SEG6_LOCAL_ACTION_END,
 | 
							.action		= SEG6_LOCAL_ACTION_END,
 | 
				
			||||||
		.attrs		= 0,
 | 
							.attrs		= 0,
 | 
				
			||||||
		.optattrs	= SEG6_F_LOCAL_COUNTERS |
 | 
							.optattrs	= SEG6_F_LOCAL_COUNTERS |
 | 
				
			||||||
				  SEG6_F_ATTR(SEG6_LOCAL_FLAVORS),
 | 
									  SEG6_F_LOCAL_FLAVORS,
 | 
				
			||||||
		.input		= input_action_end,
 | 
							.input		= input_action_end,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.action		= SEG6_LOCAL_ACTION_END_X,
 | 
							.action		= SEG6_LOCAL_ACTION_END_X,
 | 
				
			||||||
		.attrs		= SEG6_F_ATTR(SEG6_LOCAL_NH6),
 | 
							.attrs		= SEG6_F_ATTR(SEG6_LOCAL_NH6),
 | 
				
			||||||
		.optattrs	= SEG6_F_LOCAL_COUNTERS,
 | 
							.optattrs	= SEG6_F_LOCAL_COUNTERS |
 | 
				
			||||||
 | 
									  SEG6_F_LOCAL_FLAVORS,
 | 
				
			||||||
		.input		= input_action_end_x,
 | 
							.input		= input_action_end_x,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -2070,7 +2131,8 @@ static int parse_nla_flavors(struct nlattr **attrs, struct seg6_local_lwt *slwt,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct seg6_flavors_info *finfo = &slwt->flv_info;
 | 
						struct seg6_flavors_info *finfo = &slwt->flv_info;
 | 
				
			||||||
	struct nlattr *tb[SEG6_LOCAL_FLV_MAX + 1];
 | 
						struct nlattr *tb[SEG6_LOCAL_FLV_MAX + 1];
 | 
				
			||||||
	unsigned long fops;
 | 
						int action = slwt->action;
 | 
				
			||||||
 | 
						__u32 fops, supp_fops;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = nla_parse_nested_deprecated(tb, SEG6_LOCAL_FLV_MAX,
 | 
						rc = nla_parse_nested_deprecated(tb, SEG6_LOCAL_FLV_MAX,
 | 
				
			||||||
| 
						 | 
					@ -2086,7 +2148,8 @@ static int parse_nla_flavors(struct nlattr **attrs, struct seg6_local_lwt *slwt,
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fops = nla_get_u32(tb[SEG6_LOCAL_FLV_OPERATION]);
 | 
						fops = nla_get_u32(tb[SEG6_LOCAL_FLV_OPERATION]);
 | 
				
			||||||
	if (fops & ~SEG6_LOCAL_FLV_SUPP_OPS) {
 | 
						rc = seg6_flv_supp_ops_by_action(action, &supp_fops);
 | 
				
			||||||
 | 
						if (rc < 0 || (fops & ~supp_fops)) {
 | 
				
			||||||
		NL_SET_ERR_MSG(extack, "Unsupported Flavor operation(s)");
 | 
							NL_SET_ERR_MSG(extack, "Unsupported Flavor operation(s)");
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -2618,6 +2681,11 @@ int __init seg6_local_init(void)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	BUILD_BUG_ON(SEG6_LOCAL_MAX + 1 > BITS_PER_TYPE(unsigned long));
 | 
						BUILD_BUG_ON(SEG6_LOCAL_MAX + 1 > BITS_PER_TYPE(unsigned long));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Check whether the number of defined flavors exceeds the maximum
 | 
				
			||||||
 | 
						 * allowed value.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						BUILD_BUG_ON(SEG6_LOCAL_FLV_OP_MAX + 1 > BITS_PER_TYPE(__u32));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If the default NEXT-C-SID Locator-Block/Node Function lengths (in
 | 
						/* If the default NEXT-C-SID Locator-Block/Node Function lengths (in
 | 
				
			||||||
	 * bits) have been changed with invalid values, kernel build stops
 | 
						 * bits) have been changed with invalid values, kernel build stops
 | 
				
			||||||
	 * here.
 | 
						 * here.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue