Skip to content

Commit 20a081b

Browse files
skorpion17kuba-moo
authored andcommitted
seg6: add VRF support for SRv6 End.DT6 behavior
SRv6 End.DT6 is defined in the SRv6 Network Programming [1]. The Linux kernel already offers an implementation of the SRv6 End.DT6 behavior which permits IPv6 L3 VPNs over SRv6 networks. This implementation is not particularly suitable in contexts where we need to deploy IPv6 L3 VPNs among different tenants which share the same network address schemes. The underlying problem lies in the fact that the current version of DT6 (called legacy DT6 from now on) needs a complex configuration to be applied on routers which requires ad-hoc routes and routing policy rules to ensure the correct isolation of tenants. Consequently, a new implementation of DT6 has been introduced with the aim of simplifying the construction of IPv6 L3 VPN services in the multi-tenant environment using SRv6 networks. To accomplish this task, we reused the same VRF infrastructure and SRv6 core components already exploited for implementing the SRv6 End.DT4 behavior. Currently the two End.DT6 implementations coexist seamlessly and can be used depending on the context and the user preferences. So, in order to support both versions of DT6 a new attribute (vrftable) has been introduced which allows us to differentiate the implementation of the behavior to be used. A SRv6 End.DT6 legacy behavior is still instantiated using a command like the following one: $ ip -6 route add 2001:db8::1 encap seg6local action End.DT6 table 100 dev eth0 While to instantiate the SRv6 End.DT6 in VRF mode, the command is still pretty straight forward: $ ip -6 route add 2001:db8::1 encap seg6local action End.DT6 vrftable 100 dev eth0. Obviously as in the case of SRv6 End.DT4, the VRF strict_mode parameter must be set (net.vrf.strict_mode=1) and the VRF associated with table 100 must exist. Please note that the instances of SRv6 End.DT6 legacy and End.DT6 VRF mode can coexist in the same system/configuration without problems. [1] https://tools.ietf.org/html/draft-ietf-spring-srv6-network-programming Signed-off-by: Andrea Mayer <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 664d6f8 commit 20a081b

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed

net/ipv6/seg6_local.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,10 @@ static int __seg6_end_dt_vrf_build(struct seg6_local_lwt *slwt, const void *cfg,
497497
info->proto = htons(ETH_P_IP);
498498
info->hdrlen = sizeof(struct iphdr);
499499
break;
500+
case AF_INET6:
501+
info->proto = htons(ETH_P_IPV6);
502+
info->hdrlen = sizeof(struct ipv6hdr);
503+
break;
500504
default:
501505
return -EINVAL;
502506
}
@@ -649,6 +653,47 @@ static int seg6_end_dt4_build(struct seg6_local_lwt *slwt, const void *cfg,
649653
{
650654
return __seg6_end_dt_vrf_build(slwt, cfg, AF_INET, extack);
651655
}
656+
657+
static enum
658+
seg6_end_dt_mode seg6_end_dt6_parse_mode(struct seg6_local_lwt *slwt)
659+
{
660+
unsigned long parsed_optattrs = slwt->parsed_optattrs;
661+
bool legacy, vrfmode;
662+
663+
legacy = !!(parsed_optattrs & (1 << SEG6_LOCAL_TABLE));
664+
vrfmode = !!(parsed_optattrs & (1 << SEG6_LOCAL_VRFTABLE));
665+
666+
if (!(legacy ^ vrfmode))
667+
/* both are absent or present: invalid DT6 mode */
668+
return DT_INVALID_MODE;
669+
670+
return legacy ? DT_LEGACY_MODE : DT_VRF_MODE;
671+
}
672+
673+
static enum seg6_end_dt_mode seg6_end_dt6_get_mode(struct seg6_local_lwt *slwt)
674+
{
675+
struct seg6_end_dt_info *info = &slwt->dt_info;
676+
677+
return info->mode;
678+
}
679+
680+
static int seg6_end_dt6_build(struct seg6_local_lwt *slwt, const void *cfg,
681+
struct netlink_ext_ack *extack)
682+
{
683+
enum seg6_end_dt_mode mode = seg6_end_dt6_parse_mode(slwt);
684+
struct seg6_end_dt_info *info = &slwt->dt_info;
685+
686+
switch (mode) {
687+
case DT_LEGACY_MODE:
688+
info->mode = DT_LEGACY_MODE;
689+
return 0;
690+
case DT_VRF_MODE:
691+
return __seg6_end_dt_vrf_build(slwt, cfg, AF_INET6, extack);
692+
default:
693+
NL_SET_ERR_MSG(extack, "table or vrftable must be specified");
694+
return -EINVAL;
695+
}
696+
}
652697
#endif
653698

654699
static int input_action_end_dt6(struct sk_buff *skb,
@@ -660,6 +705,28 @@ static int input_action_end_dt6(struct sk_buff *skb,
660705
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
661706
goto drop;
662707

708+
#ifdef CONFIG_NET_L3_MASTER_DEV
709+
if (seg6_end_dt6_get_mode(slwt) == DT_LEGACY_MODE)
710+
goto legacy_mode;
711+
712+
/* DT6_VRF_MODE */
713+
skb = end_dt_vrf_core(skb, slwt);
714+
if (!skb)
715+
/* packet has been processed and consumed by the VRF */
716+
return 0;
717+
718+
if (IS_ERR(skb))
719+
return PTR_ERR(skb);
720+
721+
/* note: this time we do not need to specify the table because the VRF
722+
* takes care of selecting the correct table.
723+
*/
724+
seg6_lookup_any_nexthop(skb, NULL, 0, true);
725+
726+
return dst_input(skb);
727+
728+
legacy_mode:
729+
#endif
663730
skb_set_transport_header(skb, sizeof(struct ipv6hdr));
664731

665732
seg6_lookup_any_nexthop(skb, NULL, slwt->table, true);
@@ -851,7 +918,16 @@ static struct seg6_action_desc seg6_action_table[] = {
851918
},
852919
{
853920
.action = SEG6_LOCAL_ACTION_END_DT6,
921+
#ifdef CONFIG_NET_L3_MASTER_DEV
922+
.attrs = 0,
923+
.optattrs = (1 << SEG6_LOCAL_TABLE) |
924+
(1 << SEG6_LOCAL_VRFTABLE),
925+
.slwt_ops = {
926+
.build_state = seg6_end_dt6_build,
927+
},
928+
#else
854929
.attrs = (1 << SEG6_LOCAL_TABLE),
930+
#endif
855931
.input = input_action_end_dt6,
856932
},
857933
{

0 commit comments

Comments
 (0)