[net-next,1/2] seg6: add NEXT-C-SID support for SRv6 End.X behavior
Commit Message
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>
---
net/ipv6/seg6_local.c | 108 ++++++++++++++++++++++++++++++++++--------
1 file changed, 88 insertions(+), 20 deletions(-)
Comments
On Mon, Jul 31, 2023 at 07:51:16PM +0200, Andrea Mayer wrote:
> +/* 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;
> }
>
...
> @@ -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 nlattr *tb[SEG6_LOCAL_FLV_MAX + 1];
> - unsigned long fops;
> + int action = slwt->action;
> + __u32 fops, supp_fops = 0;
> int rc;
>
> 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;
>
> 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 || !supp_fops || (fops & ~supp_fops)) {
if rc == 0, the supp_fops won't be 0.
Thanks
Hangbin
Hi Hangbin,
thanks for your time. Please see below.
On Thu, 3 Aug 2023 17:30:28 +0800
Hangbin Liu <liuhangbin@gmail.com> wrote:
> On Mon, Jul 31, 2023 at 07:51:16PM +0200, Andrea Mayer wrote:
> > +/* 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;
> > }
> >
>
> ...
>
> > @@ -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 nlattr *tb[SEG6_LOCAL_FLV_MAX + 1];
> > - unsigned long fops;
> > + int action = slwt->action;
> > + __u32 fops, supp_fops = 0;
> > int rc;
> >
> > 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;
> >
> > 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 || !supp_fops || (fops & ~supp_fops)) {
>
> if rc == 0, the supp_fops won't be 0.
>
Yes, you're right.
In this patch, supp_fops is always set properly when rc == 0.
Since seg6_flv_supp_ops_by_action() should be extended in the event that other
behaviors receive flavors support, I added this check in case the "supp_fops"
field was set incorrectly or not set at all.
Note that supp_fops == 0 must be considered an inadmissible value.
So, I think we have two possibilities:
i) remove this "defensive" check, assuming that supp_fops will always be set
correctly by seg6_flv_supp_ops_by_action() (when rc == 0, like in this
patch);
ii) improve the check by explicitly indicating with a pr_warn_once, for
example, the condition that is occurring is unexpected.
for (ii), something like this:
parse_nla_flavors(...)
{
[...]
supp_fops = 0;
[...]
rc = seg6_flv_supp_ops_by_action(action, &supp_fops);
if (!rc && !supp_fops) {
/* supported flavors mask cannot be zero as it is considered to
* be invalid.
*/
pr_warn_once("seg6local: invalid Flavor operation(s)");
return -EINVAL;
}
fops = nla_get_u32(tb[SEG6_LOCAL_FLV_OPERATION]);
if (rc < 0 || (fops & ~supp_fops)) {
NL_SET_ERR_MSG(extack, "Unsupported Flavor operation(s)");
return -EOPNOTSUPP;
}
finfo->flv_ops = fops;
[...]
}
parse_nla_flavors() is called in the control path so another check would not
hit performance. I am more inclined to consider solution (ii).
What do you think?
> Thanks
> Hangbin
Ciao,
Andrea
On Fri, Aug 04, 2023 at 02:41:18PM +0200, Andrea Mayer wrote:
> Hi Hangbin,
> thanks for your time. Please see below.
>
> On Thu, 3 Aug 2023 17:30:28 +0800
> Hangbin Liu <liuhangbin@gmail.com> wrote:
>
> > On Mon, Jul 31, 2023 at 07:51:16PM +0200, Andrea Mayer wrote:
> > > +/* 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;
> > > }
> > >
> >
> > ...
> >
> > > @@ -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 nlattr *tb[SEG6_LOCAL_FLV_MAX + 1];
> > > - unsigned long fops;
> > > + int action = slwt->action;
> > > + __u32 fops, supp_fops = 0;
> > > int rc;
> > >
> > > 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;
> > >
> > > 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 || !supp_fops || (fops & ~supp_fops)) {
> >
> > if rc == 0, the supp_fops won't be 0.
> >
>
> Yes, you're right.
>
> In this patch, supp_fops is always set properly when rc == 0.
> Since seg6_flv_supp_ops_by_action() should be extended in the event that other
> behaviors receive flavors support, I added this check in case the "supp_fops"
> field was set incorrectly or not set at all.
> Note that supp_fops == 0 must be considered an inadmissible value.
>
>
> So, I think we have two possibilities:
> i) remove this "defensive" check, assuming that supp_fops will always be set
> correctly by seg6_flv_supp_ops_by_action() (when rc == 0, like in this
> patch);
> ii) improve the check by explicitly indicating with a pr_warn_once, for
> example, the condition that is occurring is unexpected.
>
> for (ii), something like this:
>
> parse_nla_flavors(...)
> {
> [...]
> supp_fops = 0;
> [...]
>
> rc = seg6_flv_supp_ops_by_action(action, &supp_fops);
> if (!rc && !supp_fops) {
> /* supported flavors mask cannot be zero as it is considered to
> * be invalid.
> */
> pr_warn_once("seg6local: invalid Flavor operation(s)");
> return -EINVAL;
> }
Do you mean there is a possibility *in future* that the supp_fops could be 0
with rc == 0? If yes, this check would make sense(although we can add this
check when it's true). If not. I don't see a need to have this check.
And some static analysis tool would report warn for this code.
Thanks
Hangbin
>
> fops = nla_get_u32(tb[SEG6_LOCAL_FLV_OPERATION]);
> if (rc < 0 || (fops & ~supp_fops)) {
> NL_SET_ERR_MSG(extack, "Unsupported Flavor operation(s)");
> return -EOPNOTSUPP;
> }
>
> finfo->flv_ops = fops;
>
> [...]
> }
>
> parse_nla_flavors() is called in the control path so another check would not
> hit performance. I am more inclined to consider solution (ii).
>
> What do you think?
>
> > Thanks
> > Hangbin
>
> Ciao,
> Andrea
On Sat, 5 Aug 2023 16:17:03 +0800
Hangbin Liu <liuhangbin@gmail.com> wrote:
> On Fri, Aug 04, 2023 at 02:41:18PM +0200, Andrea Mayer wrote:
> > Hi Hangbin,
> > thanks for your time. Please see below.
> >
> > On Thu, 3 Aug 2023 17:30:28 +0800
> > Hangbin Liu <liuhangbin@gmail.com> wrote:
> >
> > > On Mon, Jul 31, 2023 at 07:51:16PM +0200, Andrea Mayer wrote:
> > > > +/* 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;
> > > > }
> > > >
> > >
> > > ...
> > >
> > > > @@ -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 nlattr *tb[SEG6_LOCAL_FLV_MAX + 1];
> > > > - unsigned long fops;
> > > > + int action = slwt->action;
> > > > + __u32 fops, supp_fops = 0;
> > > > int rc;
> > > >
> > > > 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;
> > > >
> > > > 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 || !supp_fops || (fops & ~supp_fops)) {
> > >
> > > if rc == 0, the supp_fops won't be 0.
> > >
> >
> > Yes, you're right.
> >
> > In this patch, supp_fops is always set properly when rc == 0.
> > Since seg6_flv_supp_ops_by_action() should be extended in the event that other
> > behaviors receive flavors support, I added this check in case the "supp_fops"
> > field was set incorrectly or not set at all.
> > Note that supp_fops == 0 must be considered an inadmissible value.
> >
> >
> > So, I think we have two possibilities:
> > i) remove this "defensive" check, assuming that supp_fops will always be set
> > correctly by seg6_flv_supp_ops_by_action() (when rc == 0, like in this
> > patch);
> > ii) improve the check by explicitly indicating with a pr_warn_once, for
> > example, the condition that is occurring is unexpected.
> >
> > for (ii), something like this:
> >
> > parse_nla_flavors(...)
> > {
> > [...]
> > supp_fops = 0;
> > [...]
> >
> > rc = seg6_flv_supp_ops_by_action(action, &supp_fops);
> > if (!rc && !supp_fops) {
> > /* supported flavors mask cannot be zero as it is considered to
> > * be invalid.
> > */
> > pr_warn_once("seg6local: invalid Flavor operation(s)");
> > return -EINVAL;
> > }
>
> Do you mean there is a possibility *in future* that the supp_fops could be 0
> with rc == 0? If yes, this check would make sense(although we can add this
> check when it's true). If not. I don't see a need to have this check.
>
> And some static analysis tool would report warn for this code.
>
Good points, thanks.
There is no possibility at the moment that supp_fops could be 0 with rc == 0.
That check is going to be removed in v2.
> Thanks
> Hangbin
Ciao,
Andrea
> >
> > fops = nla_get_u32(tb[SEG6_LOCAL_FLV_OPERATION]);
> > if (rc < 0 || (fops & ~supp_fops)) {
> > NL_SET_ERR_MSG(extack, "Unsupported Flavor operation(s)");
> > return -EOPNOTSUPP;
> > }
> >
> > finfo->flv_ops = fops;
> >
> > [...]
> > }
> >
> > parse_nla_flavors() is called in the control path so another check would not
> > hit performance. I am more inclined to consider solution (ii).
> >
> > What do you think?
> >
> > > Thanks
> > > Hangbin
> >
> > Ciao,
> > Andrea
@@ -109,15 +109,19 @@ struct bpf_lwt_prog {
#define next_csid_chk_lcnode_fn_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_NEXT_CSID SEG6_F_LOCAL_FLV_OP(NEXT_CSID)
#define SEG6_F_LOCAL_FLV_PSP SEG6_F_LOCAL_FLV_OP(PSP)
/* Supported RFC8986 Flavor operations are reported in this bitmask */
#define SEG6_LOCAL_FLV8986_SUPP_OPS SEG6_F_LOCAL_FLV_PSP
-/* Supported Flavor operations are reported in this bitmask */
-#define SEG6_LOCAL_FLV_SUPP_OPS (SEG6_F_LOCAL_FLV_OP(NEXT_CSID) | \
+#define SEG6_LOCAL_END_FLV_SUPP_OPS (SEG6_F_LOCAL_FLV_NEXT_CSID | \
SEG6_LOCAL_FLV8986_SUPP_OPS)
+#define SEG6_LOCAL_END_X_FLV_SUPP_OPS SEG6_F_LOCAL_FLV_NEXT_CSID
struct seg6_flavors_info {
/* 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);
}
+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)
{
- 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
@@ -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 */
static int input_action_end_x(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);
-
- seg6_lookup_nexthop(skb, &slwt->nh6, 0);
+ const struct seg6_flavors_info *finfo = &slwt->flv_info;
+ __u32 fops = finfo->flv_ops;
- return dst_input(skb);
+ /* check for the presence of NEXT-C-SID since it applies first */
+ if (seg6_next_csid_enabled(fops))
+ return end_x_next_csid_core(skb, slwt);
-drop:
- kfree_skb(skb);
- return -EINVAL;
+ return input_action_end_x_core(skb, 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,
.attrs = 0,
.optattrs = SEG6_F_LOCAL_COUNTERS |
- SEG6_F_ATTR(SEG6_LOCAL_FLAVORS),
+ SEG6_F_LOCAL_FLAVORS,
.input = input_action_end,
},
{
.action = SEG6_LOCAL_ACTION_END_X,
.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,
},
{
@@ -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 nlattr *tb[SEG6_LOCAL_FLV_MAX + 1];
- unsigned long fops;
+ int action = slwt->action;
+ __u32 fops, supp_fops = 0;
int rc;
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;
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 || !supp_fops || (fops & ~supp_fops)) {
NL_SET_ERR_MSG(extack, "Unsupported Flavor operation(s)");
return -EOPNOTSUPP;
}
@@ -2618,6 +2681,11 @@ int __init seg6_local_init(void)
*/
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
* bits) have been changed with invalid values, kernel build stops
* here.