Message ID | 20220823154557.1400380-4-eyal.birger@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | xfrm: support collect metadata mode for xfrm interfaces | expand |
Le 23/08/2022 à 17:45, Eyal Birger a écrit : > Allow specifying the xfrm interface if_id as part of a route metadata > using the lwtunnel infrastructure. > > This allows for example using a single xfrm interface in collect_md > mode as the target of multiple routes each specifying a different if_id. > > With the appropriate changes to iproute2, considering an xfrm device > ipsec1 in collect_md mode one can for example add a route specifying > an if_id like so: > > ip route add <SUBNET> dev ipsec1 encap xfrm if_id 1 It would be nice to be able to specify the link also. It may help to combine this with vrf. Something like ip route add <SUBNET> dev ipsec1 encap xfrm if_id 1 dev eth0
Hi Nicolas, On Wed, Aug 24, 2022 at 6:21 PM Nicolas Dichtel <nicolas.dichtel@6wind.com> wrote: > > > Le 23/08/2022 à 17:45, Eyal Birger a écrit : > > Allow specifying the xfrm interface if_id as part of a route metadata > > using the lwtunnel infrastructure. > > > > This allows for example using a single xfrm interface in collect_md > > mode as the target of multiple routes each specifying a different if_id. > > > > With the appropriate changes to iproute2, considering an xfrm device > > ipsec1 in collect_md mode one can for example add a route specifying > > an if_id like so: > > > > ip route add <SUBNET> dev ipsec1 encap xfrm if_id 1 > It would be nice to be able to specify the link also. It may help to combine > this with vrf. Something like > ip route add <SUBNET> dev ipsec1 encap xfrm if_id 1 dev eth0 I think I understand how this would work on xmit - if you mean adding link to the metadata and using it to set fl.flowi_oif in xfrmi_xmit() - in which case the link would be used in the underlying lookup such that routes in a vrf could specify a device which is part of the vrf for egress. On RX we could assign the link in the metadata in xfrmi_rcv_cb() to the original skb->dev. I suspect this would be aligned with the link device, but any input you may have on this would be useful. Eyal.
Le 24/08/2022 à 20:56, Eyal Birger a écrit : > Hi Nicolas, > > On Wed, Aug 24, 2022 at 6:21 PM Nicolas Dichtel > <nicolas.dichtel@6wind.com> wrote: >> >> >> Le 23/08/2022 à 17:45, Eyal Birger a écrit : >>> Allow specifying the xfrm interface if_id as part of a route metadata >>> using the lwtunnel infrastructure. >>> >>> This allows for example using a single xfrm interface in collect_md >>> mode as the target of multiple routes each specifying a different if_id. >>> >>> With the appropriate changes to iproute2, considering an xfrm device >>> ipsec1 in collect_md mode one can for example add a route specifying >>> an if_id like so: >>> >>> ip route add <SUBNET> dev ipsec1 encap xfrm if_id 1 >> It would be nice to be able to specify the link also. It may help to combine >> this with vrf. Something like >> ip route add <SUBNET> dev ipsec1 encap xfrm if_id 1 dev eth0 > > I think I understand how this would work on xmit - if you mean adding link > to the metadata and using it to set fl.flowi_oif in xfrmi_xmit() - in which > case the link would be used in the underlying lookup such that routes in > a vrf could specify a device which is part of the vrf for egress. Yes. > > On RX we could assign the link in the metadata in xfrmi_rcv_cb() to the original > skb->dev. I suspect this would be aligned with the link device, but any input > you may have on this would be useful. The link is not used in the rx path, only in the tx path to perform the route lookup in the right vrf. You can assign the input iface to the link device, but the if_id should be enough to identify the tunnel. Thank you, Nicolas
On Thu, Aug 25, 2022 at 1:07 PM Nicolas Dichtel <nicolas.dichtel@6wind.com> wrote: > > > Le 24/08/2022 à 20:56, Eyal Birger a écrit : > > Hi Nicolas, > > > > On Wed, Aug 24, 2022 at 6:21 PM Nicolas Dichtel > > <nicolas.dichtel@6wind.com> wrote: > >> > >> > >> Le 23/08/2022 à 17:45, Eyal Birger a écrit : > >>> Allow specifying the xfrm interface if_id as part of a route metadata > >>> using the lwtunnel infrastructure. > >>> > >>> This allows for example using a single xfrm interface in collect_md > >>> mode as the target of multiple routes each specifying a different if_id. > >>> > >>> With the appropriate changes to iproute2, considering an xfrm device > >>> ipsec1 in collect_md mode one can for example add a route specifying > >>> an if_id like so: > >>> > >>> ip route add <SUBNET> dev ipsec1 encap xfrm if_id 1 > >> It would be nice to be able to specify the link also. It may help to combine > >> this with vrf. Something like > >> ip route add <SUBNET> dev ipsec1 encap xfrm if_id 1 dev eth0 > > > > I think I understand how this would work on xmit - if you mean adding link > > to the metadata and using it to set fl.flowi_oif in xfrmi_xmit() - in which > > case the link would be used in the underlying lookup such that routes in > > a vrf could specify a device which is part of the vrf for egress. > Yes. > > > > > On RX we could assign the link in the metadata in xfrmi_rcv_cb() to the original > > skb->dev. I suspect this would be aligned with the link device, but any input > > you may have on this would be useful. > The link is not used in the rx path, only in the tx path to perform the route > lookup in the right vrf. You can assign the input iface to the link device, but > the if_id should be enough to identify the tunnel. Thanks. I tested this in the context of VRF and it works well. I'll include it in v2. Eyal.
diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h index 7e13210b868f..122066595966 100644 --- a/include/net/dst_metadata.h +++ b/include/net/dst_metadata.h @@ -62,10 +62,16 @@ skb_tunnel_info(const struct sk_buff *skb) static inline struct xfrm_md_info *skb_xfrm_md_info(const struct sk_buff *skb) { struct metadata_dst *md_dst = skb_metadata_dst(skb); + struct dst_entry *dst; if (md_dst && md_dst->type == METADATA_XFRM) return &md_dst->u.xfrm_info; + dst = skb_dst(skb); + if (dst && dst->lwtstate && + dst->lwtstate->type == LWTUNNEL_ENCAP_XFRM) + return (struct xfrm_md_info *)dst->lwtstate->data; + return NULL; } diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h index 2e206919125c..d26bace86332 100644 --- a/include/uapi/linux/lwtunnel.h +++ b/include/uapi/linux/lwtunnel.h @@ -15,6 +15,7 @@ enum lwtunnel_encap_types { LWTUNNEL_ENCAP_SEG6_LOCAL, LWTUNNEL_ENCAP_RPL, LWTUNNEL_ENCAP_IOAM6, + LWTUNNEL_ENCAP_XFRM, __LWTUNNEL_ENCAP_MAX, }; @@ -111,4 +112,12 @@ enum { #define LWT_BPF_MAX_HEADROOM 256 +enum { + LWT_XFRM_UNSPEC, + LWT_XFRM_IF_ID, + __LWT_XFRM_MAX, +}; + +#define LWT_XFRM_MAX (__LWT_XFRM_MAX - 1) + #endif /* _UAPI_LWTUNNEL_H_ */ diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c index 9ccd64e8a666..6fac2f0ef074 100644 --- a/net/core/lwtunnel.c +++ b/net/core/lwtunnel.c @@ -50,6 +50,7 @@ static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type) return "IOAM6"; case LWTUNNEL_ENCAP_IP6: case LWTUNNEL_ENCAP_IP: + case LWTUNNEL_ENCAP_XFRM: case LWTUNNEL_ENCAP_NONE: case __LWTUNNEL_ENCAP_MAX: /* should not have got here */ diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c index efb8263e1c22..9f0a5cc2895d 100644 --- a/net/xfrm/xfrm_interface.c +++ b/net/xfrm/xfrm_interface.c @@ -60,6 +60,91 @@ struct xfrmi_net { struct xfrm_if __rcu *collect_md_xfrmi; }; +static inline struct xfrm_md_info *xfrm_lwt(struct lwtunnel_state *lwt) +{ + return (struct xfrm_md_info *)lwt->data; +} + +static const struct nla_policy xfrm_lwt_policy[LWT_XFRM_MAX + 1] = { + [LWT_XFRM_UNSPEC] = { .type = NLA_REJECT }, + [LWT_XFRM_IF_ID] = { .type = NLA_U32 }, +}; + +static void xfrmi_destroy_state(struct lwtunnel_state *lwt) +{ +} + +static int xfrmi_build_state(struct net *net, struct nlattr *nla, + unsigned int family, const void *cfg, + struct lwtunnel_state **ts, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[LWT_XFRM_MAX + 1]; + struct lwtunnel_state *new_state; + struct xfrm_md_info *info; + int ret; + + ret = nla_parse_nested(tb, LWT_XFRM_MAX, nla, xfrm_lwt_policy, extack); + if (ret < 0) + return ret; + + if (!tb[LWT_XFRM_IF_ID]) + return -EINVAL; + + new_state = lwtunnel_state_alloc(sizeof(*info)); + if (!new_state) + return -ENOMEM; + + new_state->type = LWTUNNEL_ENCAP_XFRM; + + info = xfrm_lwt(new_state); + info->if_id = nla_get_u32(tb[LWT_XFRM_IF_ID]); + if (!info->if_id) { + ret = -EINVAL; + goto errout; + } + *ts = new_state; + return 0; + +errout: + xfrmi_destroy_state(new_state); + kfree(new_state); + return ret; +} + +static int xfrmi_fill_encap_info(struct sk_buff *skb, + struct lwtunnel_state *lwt) +{ + struct xfrm_md_info *info = xfrm_lwt(lwt); + + if (nla_put_u32(skb, LWT_XFRM_IF_ID, info->if_id)) + return -EMSGSIZE; + + return 0; +} + +static int xfrmi_encap_nlsize(struct lwtunnel_state *lwtstate) +{ + return nla_total_size(4); /* LWT_XFRM_IF_ID */ +} + +static int xfrmi_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b) +{ + struct xfrm_md_info *a_info = xfrm_lwt(a); + struct xfrm_md_info *b_info = xfrm_lwt(b); + + return memcmp(a_info, b_info, sizeof(*a_info)); +} + +static const struct lwtunnel_encap_ops xfrmi_encap_ops = { + .build_state = xfrmi_build_state, + .destroy_state = xfrmi_destroy_state, + .fill_encap = xfrmi_fill_encap_info, + .get_encap_size = xfrmi_encap_nlsize, + .cmp_encap = xfrmi_encap_cmp, + .owner = THIS_MODULE, +}; + #define for_each_xfrmi_rcu(start, xi) \ for (xi = rcu_dereference(start); xi; xi = rcu_dereference(xi->next)) @@ -1076,6 +1161,8 @@ static int __init xfrmi_init(void) if (err < 0) goto rtnl_link_failed; + lwtunnel_encap_add_ops(&xfrmi_encap_ops, LWTUNNEL_ENCAP_XFRM); + xfrm_if_register_cb(&xfrm_if_cb); return err; @@ -1094,6 +1181,7 @@ static int __init xfrmi_init(void) static void __exit xfrmi_fini(void) { xfrm_if_unregister_cb(); + lwtunnel_encap_del_ops(&xfrmi_encap_ops, LWTUNNEL_ENCAP_XFRM); rtnl_link_unregister(&xfrmi_link_ops); xfrmi4_fini(); xfrmi6_fini();
Allow specifying the xfrm interface if_id as part of a route metadata using the lwtunnel infrastructure. This allows for example using a single xfrm interface in collect_md mode as the target of multiple routes each specifying a different if_id. With the appropriate changes to iproute2, considering an xfrm device ipsec1 in collect_md mode one can for example add a route specifying an if_id like so: ip route add <SUBNET> dev ipsec1 encap xfrm if_id 1 In which case traffic routed to the device via this route would use if_id in the xfrm interface policy lookup. Signed-off-by: Eyal Birger <eyal.birger@gmail.com> --- include/net/dst_metadata.h | 6 +++ include/uapi/linux/lwtunnel.h | 9 ++++ net/core/lwtunnel.c | 1 + net/xfrm/xfrm_interface.c | 88 +++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+)