Skip to content

Commit 2c2493b

Browse files
ebirgerklassert
authored andcommitted
xfrm: lwtunnel: add lwtunnel support for xfrm interfaces in collect_md mode
Allow specifying the xfrm interface if_id and link 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. Or in the context of vrf, one can also specify the "link" property: ip route add <SUBNET> dev ipsec1 encap xfrm if_id 1 link_dev eth15 Note: LWT_XFRM_LINK uses NLA_U32 similar to IFLA_XFRM_LINK even though internally "link" is signed. This is consistent with other _LINK attributes in other devices as well as in bpf and should not have an effect as device indexes can't be negative. Reviewed-by: Nicolas Dichtel <[email protected]> Reviewed-by: Nikolay Aleksandrov <[email protected]> Signed-off-by: Eyal Birger <[email protected]> Signed-off-by: Steffen Klassert <[email protected]>
1 parent abc340b commit 2c2493b

File tree

4 files changed

+107
-0
lines changed

4 files changed

+107
-0
lines changed

include/net/dst_metadata.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,24 @@ skb_tunnel_info(const struct sk_buff *skb)
6060
return NULL;
6161
}
6262

63+
static inline struct xfrm_md_info *lwt_xfrm_info(struct lwtunnel_state *lwt)
64+
{
65+
return (struct xfrm_md_info *)lwt->data;
66+
}
67+
6368
static inline struct xfrm_md_info *skb_xfrm_md_info(const struct sk_buff *skb)
6469
{
6570
struct metadata_dst *md_dst = skb_metadata_dst(skb);
71+
struct dst_entry *dst;
6672

6773
if (md_dst && md_dst->type == METADATA_XFRM)
6874
return &md_dst->u.xfrm_info;
6975

76+
dst = skb_dst(skb);
77+
if (dst && dst->lwtstate &&
78+
dst->lwtstate->type == LWTUNNEL_ENCAP_XFRM)
79+
return lwt_xfrm_info(dst->lwtstate);
80+
7081
return NULL;
7182
}
7283

include/uapi/linux/lwtunnel.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ enum lwtunnel_encap_types {
1515
LWTUNNEL_ENCAP_SEG6_LOCAL,
1616
LWTUNNEL_ENCAP_RPL,
1717
LWTUNNEL_ENCAP_IOAM6,
18+
LWTUNNEL_ENCAP_XFRM,
1819
__LWTUNNEL_ENCAP_MAX,
1920
};
2021

@@ -111,4 +112,13 @@ enum {
111112

112113
#define LWT_BPF_MAX_HEADROOM 256
113114

115+
enum {
116+
LWT_XFRM_UNSPEC,
117+
LWT_XFRM_IF_ID,
118+
LWT_XFRM_LINK,
119+
__LWT_XFRM_MAX,
120+
};
121+
122+
#define LWT_XFRM_MAX (__LWT_XFRM_MAX - 1)
123+
114124
#endif /* _UAPI_LWTUNNEL_H_ */

net/core/lwtunnel.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type)
5050
return "IOAM6";
5151
case LWTUNNEL_ENCAP_IP6:
5252
case LWTUNNEL_ENCAP_IP:
53+
case LWTUNNEL_ENCAP_XFRM:
5354
case LWTUNNEL_ENCAP_NONE:
5455
case __LWTUNNEL_ENCAP_MAX:
5556
/* should not have got here */

net/xfrm/xfrm_interface.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,88 @@ struct xfrmi_net {
6060
struct xfrm_if __rcu *collect_md_xfrmi;
6161
};
6262

63+
static const struct nla_policy xfrm_lwt_policy[LWT_XFRM_MAX + 1] = {
64+
[LWT_XFRM_IF_ID] = NLA_POLICY_MIN(NLA_U32, 1),
65+
[LWT_XFRM_LINK] = NLA_POLICY_MIN(NLA_U32, 1),
66+
};
67+
68+
static void xfrmi_destroy_state(struct lwtunnel_state *lwt)
69+
{
70+
}
71+
72+
static int xfrmi_build_state(struct net *net, struct nlattr *nla,
73+
unsigned int family, const void *cfg,
74+
struct lwtunnel_state **ts,
75+
struct netlink_ext_ack *extack)
76+
{
77+
struct nlattr *tb[LWT_XFRM_MAX + 1];
78+
struct lwtunnel_state *new_state;
79+
struct xfrm_md_info *info;
80+
int ret;
81+
82+
ret = nla_parse_nested(tb, LWT_XFRM_MAX, nla, xfrm_lwt_policy, extack);
83+
if (ret < 0)
84+
return ret;
85+
86+
if (!tb[LWT_XFRM_IF_ID]) {
87+
NL_SET_ERR_MSG(extack, "if_id must be set");
88+
return -EINVAL;
89+
}
90+
91+
new_state = lwtunnel_state_alloc(sizeof(*info));
92+
if (!new_state) {
93+
NL_SET_ERR_MSG(extack, "failed to create encap info");
94+
return -ENOMEM;
95+
}
96+
97+
new_state->type = LWTUNNEL_ENCAP_XFRM;
98+
99+
info = lwt_xfrm_info(new_state);
100+
101+
info->if_id = nla_get_u32(tb[LWT_XFRM_IF_ID]);
102+
103+
if (tb[LWT_XFRM_LINK])
104+
info->link = nla_get_u32(tb[LWT_XFRM_LINK]);
105+
106+
*ts = new_state;
107+
return 0;
108+
}
109+
110+
static int xfrmi_fill_encap_info(struct sk_buff *skb,
111+
struct lwtunnel_state *lwt)
112+
{
113+
struct xfrm_md_info *info = lwt_xfrm_info(lwt);
114+
115+
if (nla_put_u32(skb, LWT_XFRM_IF_ID, info->if_id) ||
116+
(info->link && nla_put_u32(skb, LWT_XFRM_LINK, info->link)))
117+
return -EMSGSIZE;
118+
119+
return 0;
120+
}
121+
122+
static int xfrmi_encap_nlsize(struct lwtunnel_state *lwtstate)
123+
{
124+
return nla_total_size(sizeof(u32)) + /* LWT_XFRM_IF_ID */
125+
nla_total_size(sizeof(u32)); /* LWT_XFRM_LINK */
126+
}
127+
128+
static int xfrmi_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
129+
{
130+
struct xfrm_md_info *a_info = lwt_xfrm_info(a);
131+
struct xfrm_md_info *b_info = lwt_xfrm_info(b);
132+
133+
return memcmp(a_info, b_info, sizeof(*a_info));
134+
}
135+
136+
static const struct lwtunnel_encap_ops xfrmi_encap_ops = {
137+
.build_state = xfrmi_build_state,
138+
.destroy_state = xfrmi_destroy_state,
139+
.fill_encap = xfrmi_fill_encap_info,
140+
.get_encap_size = xfrmi_encap_nlsize,
141+
.cmp_encap = xfrmi_encap_cmp,
142+
.owner = THIS_MODULE,
143+
};
144+
63145
#define for_each_xfrmi_rcu(start, xi) \
64146
for (xi = rcu_dereference(start); xi; xi = rcu_dereference(xi->next))
65147

@@ -1080,6 +1162,8 @@ static int __init xfrmi_init(void)
10801162
if (err < 0)
10811163
goto rtnl_link_failed;
10821164

1165+
lwtunnel_encap_add_ops(&xfrmi_encap_ops, LWTUNNEL_ENCAP_XFRM);
1166+
10831167
xfrm_if_register_cb(&xfrm_if_cb);
10841168

10851169
return err;
@@ -1098,6 +1182,7 @@ static int __init xfrmi_init(void)
10981182
static void __exit xfrmi_fini(void)
10991183
{
11001184
xfrm_if_unregister_cb();
1185+
lwtunnel_encap_del_ops(&xfrmi_encap_ops, LWTUNNEL_ENCAP_XFRM);
11011186
rtnl_link_unregister(&xfrmi_link_ops);
11021187
xfrmi4_fini();
11031188
xfrmi6_fini();

0 commit comments

Comments
 (0)