Skip to content

Commit 4f4853d

Browse files
David Lebrundavem330
David Lebrun
authored andcommitted
ipv6: sr: implement API to control SR HMAC structure
This patch provides an implementation of the genetlink commands to associate a given HMAC key identifier with an hashing algorithm and a secret. Signed-off-by: David Lebrun <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent bf355b8 commit 4f4853d

File tree

1 file changed

+229
-0
lines changed

1 file changed

+229
-0
lines changed

net/ipv6/seg6.c

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
#include <net/genetlink.h>
2626
#include <linux/seg6.h>
2727
#include <linux/seg6_genl.h>
28+
#ifdef CONFIG_IPV6_SEG6_HMAC
29+
#include <net/seg6_hmac.h>
30+
#endif
2831

2932
bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len)
3033
{
@@ -76,11 +79,90 @@ static const struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX + 1] = {
7679
[SEG6_ATTR_HMACINFO] = { .type = NLA_NESTED, },
7780
};
7881

82+
#ifdef CONFIG_IPV6_SEG6_HMAC
83+
84+
static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
85+
{
86+
struct net *net = genl_info_net(info);
87+
struct seg6_pernet_data *sdata;
88+
struct seg6_hmac_info *hinfo;
89+
u32 hmackeyid;
90+
char *secret;
91+
int err = 0;
92+
u8 algid;
93+
u8 slen;
94+
95+
sdata = seg6_pernet(net);
96+
97+
if (!info->attrs[SEG6_ATTR_HMACKEYID] ||
98+
!info->attrs[SEG6_ATTR_SECRETLEN] ||
99+
!info->attrs[SEG6_ATTR_ALGID])
100+
return -EINVAL;
101+
102+
hmackeyid = nla_get_u32(info->attrs[SEG6_ATTR_HMACKEYID]);
103+
slen = nla_get_u8(info->attrs[SEG6_ATTR_SECRETLEN]);
104+
algid = nla_get_u8(info->attrs[SEG6_ATTR_ALGID]);
105+
106+
if (hmackeyid == 0)
107+
return -EINVAL;
108+
109+
if (slen > SEG6_HMAC_SECRET_LEN)
110+
return -EINVAL;
111+
112+
mutex_lock(&sdata->lock);
113+
hinfo = seg6_hmac_info_lookup(net, hmackeyid);
114+
115+
if (!slen) {
116+
if (!hinfo)
117+
err = -ENOENT;
118+
119+
err = seg6_hmac_info_del(net, hmackeyid);
120+
121+
goto out_unlock;
122+
}
123+
124+
if (!info->attrs[SEG6_ATTR_SECRET]) {
125+
err = -EINVAL;
126+
goto out_unlock;
127+
}
128+
129+
if (hinfo) {
130+
err = seg6_hmac_info_del(net, hmackeyid);
131+
if (err)
132+
goto out_unlock;
133+
}
134+
135+
secret = (char *)nla_data(info->attrs[SEG6_ATTR_SECRET]);
136+
137+
hinfo = kzalloc(sizeof(*hinfo), GFP_KERNEL);
138+
if (!hinfo) {
139+
err = -ENOMEM;
140+
goto out_unlock;
141+
}
142+
143+
memcpy(hinfo->secret, secret, slen);
144+
hinfo->slen = slen;
145+
hinfo->alg_id = algid;
146+
hinfo->hmackeyid = hmackeyid;
147+
148+
err = seg6_hmac_info_add(net, hmackeyid, hinfo);
149+
if (err)
150+
kfree(hinfo);
151+
152+
out_unlock:
153+
mutex_unlock(&sdata->lock);
154+
return err;
155+
}
156+
157+
#else
158+
79159
static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
80160
{
81161
return -ENOTSUPP;
82162
}
83163

164+
#endif
165+
84166
static int seg6_genl_set_tunsrc(struct sk_buff *skb, struct genl_info *info)
85167
{
86168
struct net *net = genl_info_net(info);
@@ -145,11 +227,135 @@ static int seg6_genl_get_tunsrc(struct sk_buff *skb, struct genl_info *info)
145227
return -ENOMEM;
146228
}
147229

230+
#ifdef CONFIG_IPV6_SEG6_HMAC
231+
232+
static int __seg6_hmac_fill_info(struct seg6_hmac_info *hinfo,
233+
struct sk_buff *msg)
234+
{
235+
if (nla_put_u32(msg, SEG6_ATTR_HMACKEYID, hinfo->hmackeyid) ||
236+
nla_put_u8(msg, SEG6_ATTR_SECRETLEN, hinfo->slen) ||
237+
nla_put(msg, SEG6_ATTR_SECRET, hinfo->slen, hinfo->secret) ||
238+
nla_put_u8(msg, SEG6_ATTR_ALGID, hinfo->alg_id))
239+
return -1;
240+
241+
return 0;
242+
}
243+
244+
static int __seg6_genl_dumphmac_element(struct seg6_hmac_info *hinfo,
245+
u32 portid, u32 seq, u32 flags,
246+
struct sk_buff *skb, u8 cmd)
247+
{
248+
void *hdr;
249+
250+
hdr = genlmsg_put(skb, portid, seq, &seg6_genl_family, flags, cmd);
251+
if (!hdr)
252+
return -ENOMEM;
253+
254+
if (__seg6_hmac_fill_info(hinfo, skb) < 0)
255+
goto nla_put_failure;
256+
257+
genlmsg_end(skb, hdr);
258+
return 0;
259+
260+
nla_put_failure:
261+
genlmsg_cancel(skb, hdr);
262+
return -EMSGSIZE;
263+
}
264+
265+
static int seg6_genl_dumphmac_start(struct netlink_callback *cb)
266+
{
267+
struct net *net = sock_net(cb->skb->sk);
268+
struct seg6_pernet_data *sdata;
269+
struct rhashtable_iter *iter;
270+
271+
sdata = seg6_pernet(net);
272+
iter = (struct rhashtable_iter *)cb->args[0];
273+
274+
if (!iter) {
275+
iter = kmalloc(sizeof(*iter), GFP_KERNEL);
276+
if (!iter)
277+
return -ENOMEM;
278+
279+
cb->args[0] = (long)iter;
280+
}
281+
282+
rhashtable_walk_enter(&sdata->hmac_infos, iter);
283+
284+
return 0;
285+
}
286+
287+
static int seg6_genl_dumphmac_done(struct netlink_callback *cb)
288+
{
289+
struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
290+
291+
rhashtable_walk_exit(iter);
292+
293+
kfree(iter);
294+
295+
return 0;
296+
}
297+
298+
static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
299+
{
300+
struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
301+
struct net *net = sock_net(skb->sk);
302+
struct seg6_pernet_data *sdata;
303+
struct seg6_hmac_info *hinfo;
304+
int ret;
305+
306+
sdata = seg6_pernet(net);
307+
308+
ret = rhashtable_walk_start(iter);
309+
if (ret && ret != -EAGAIN)
310+
goto done;
311+
312+
for (;;) {
313+
hinfo = rhashtable_walk_next(iter);
314+
315+
if (IS_ERR(hinfo)) {
316+
if (PTR_ERR(hinfo) == -EAGAIN)
317+
continue;
318+
ret = PTR_ERR(hinfo);
319+
goto done;
320+
} else if (!hinfo) {
321+
break;
322+
}
323+
324+
ret = __seg6_genl_dumphmac_element(hinfo,
325+
NETLINK_CB(cb->skb).portid,
326+
cb->nlh->nlmsg_seq,
327+
NLM_F_MULTI,
328+
skb, SEG6_CMD_DUMPHMAC);
329+
if (ret)
330+
goto done;
331+
}
332+
333+
ret = skb->len;
334+
335+
done:
336+
rhashtable_walk_stop(iter);
337+
return ret;
338+
}
339+
340+
#else
341+
342+
static int seg6_genl_dumphmac_start(struct netlink_callback *cb)
343+
{
344+
return 0;
345+
}
346+
347+
static int seg6_genl_dumphmac_done(struct netlink_callback *cb)
348+
{
349+
return 0;
350+
}
351+
148352
static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
149353
{
150354
return -ENOTSUPP;
151355
}
152356

357+
#endif
358+
153359
static int __net_init seg6_net_init(struct net *net)
154360
{
155361
struct seg6_pernet_data *sdata;
@@ -168,13 +374,21 @@ static int __net_init seg6_net_init(struct net *net)
168374

169375
net->ipv6.seg6_data = sdata;
170376

377+
#ifdef CONFIG_IPV6_SEG6_HMAC
378+
seg6_hmac_net_init(net);
379+
#endif
380+
171381
return 0;
172382
}
173383

174384
static void __net_exit seg6_net_exit(struct net *net)
175385
{
176386
struct seg6_pernet_data *sdata = seg6_pernet(net);
177387

388+
#ifdef CONFIG_IPV6_SEG6_HMAC
389+
seg6_hmac_net_exit(net);
390+
#endif
391+
178392
kfree(sdata->tun_src);
179393
kfree(sdata);
180394
}
@@ -193,7 +407,9 @@ static const struct genl_ops seg6_genl_ops[] = {
193407
},
194408
{
195409
.cmd = SEG6_CMD_DUMPHMAC,
410+
.start = seg6_genl_dumphmac_start,
196411
.dumpit = seg6_genl_dumphmac,
412+
.done = seg6_genl_dumphmac_done,
197413
.policy = seg6_genl_policy,
198414
.flags = GENL_ADMIN_PERM,
199415
},
@@ -239,10 +455,20 @@ int __init seg6_init(void)
239455
if (err)
240456
goto out_unregister_pernet;
241457

458+
#ifdef CONFIG_IPV6_SEG6_HMAC
459+
err = seg6_hmac_init();
460+
if (err)
461+
goto out_unregister_iptun;
462+
#endif
463+
242464
pr_info("Segment Routing with IPv6\n");
243465

244466
out:
245467
return err;
468+
#ifdef CONFIG_IPV6_SEG6_HMAC
469+
out_unregister_iptun:
470+
seg6_iptunnel_exit();
471+
#endif
246472
out_unregister_pernet:
247473
unregister_pernet_subsys(&ip6_segments_ops);
248474
out_unregister_genl:
@@ -252,6 +478,9 @@ int __init seg6_init(void)
252478

253479
void seg6_exit(void)
254480
{
481+
#ifdef CONFIG_IPV6_SEG6_HMAC
482+
seg6_hmac_exit();
483+
#endif
255484
seg6_iptunnel_exit();
256485
unregister_pernet_subsys(&ip6_segments_ops);
257486
genl_unregister_family(&seg6_genl_family);

0 commit comments

Comments
 (0)