1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * SR-IPv6 implementation
6 * David Lebrun <david.lebrun@uclouvain.be>
9 #include <linux/errno.h>
10 #include <linux/types.h>
11 #include <linux/socket.h>
12 #include <linux/net.h>
13 #include <linux/in6.h>
14 #include <linux/slab.h>
15 #include <linux/rhashtable.h>
18 #include <net/protocol.h>
21 #include <net/genetlink.h>
22 #include <linux/seg6.h>
23 #include <linux/seg6_genl.h>
24 #ifdef CONFIG_IPV6_SEG6_HMAC
25 #include <net/seg6_hmac.h>
28 bool seg6_validate_srh(struct ipv6_sr_hdr
*srh
, int len
)
31 unsigned int tlv_offset
;
33 if (srh
->type
!= IPV6_SRCRT_TYPE_4
)
36 if (((srh
->hdrlen
+ 1) << 3) != len
)
39 if (srh
->segments_left
> srh
->first_segment
)
42 tlv_offset
= sizeof(*srh
) + ((srh
->first_segment
+ 1) << 4);
44 trailing
= len
- tlv_offset
;
52 if (trailing
< sizeof(*tlv
))
55 tlv
= (struct sr6_tlv
*)((unsigned char *)srh
+ tlv_offset
);
56 tlv_len
= sizeof(*tlv
) + tlv
->len
;
62 tlv_offset
+= tlv_len
;
68 static struct genl_family seg6_genl_family
;
70 static const struct nla_policy seg6_genl_policy
[SEG6_ATTR_MAX
+ 1] = {
71 [SEG6_ATTR_DST
] = { .type
= NLA_BINARY
,
72 .len
= sizeof(struct in6_addr
) },
73 [SEG6_ATTR_DSTLEN
] = { .type
= NLA_S32
, },
74 [SEG6_ATTR_HMACKEYID
] = { .type
= NLA_U32
, },
75 [SEG6_ATTR_SECRET
] = { .type
= NLA_BINARY
, },
76 [SEG6_ATTR_SECRETLEN
] = { .type
= NLA_U8
, },
77 [SEG6_ATTR_ALGID
] = { .type
= NLA_U8
, },
78 [SEG6_ATTR_HMACINFO
] = { .type
= NLA_NESTED
, },
81 #ifdef CONFIG_IPV6_SEG6_HMAC
83 static int seg6_genl_sethmac(struct sk_buff
*skb
, struct genl_info
*info
)
85 struct net
*net
= genl_info_net(info
);
86 struct seg6_pernet_data
*sdata
;
87 struct seg6_hmac_info
*hinfo
;
94 sdata
= seg6_pernet(net
);
96 if (!info
->attrs
[SEG6_ATTR_HMACKEYID
] ||
97 !info
->attrs
[SEG6_ATTR_SECRETLEN
] ||
98 !info
->attrs
[SEG6_ATTR_ALGID
])
101 hmackeyid
= nla_get_u32(info
->attrs
[SEG6_ATTR_HMACKEYID
]);
102 slen
= nla_get_u8(info
->attrs
[SEG6_ATTR_SECRETLEN
]);
103 algid
= nla_get_u8(info
->attrs
[SEG6_ATTR_ALGID
]);
108 if (slen
> SEG6_HMAC_SECRET_LEN
)
111 mutex_lock(&sdata
->lock
);
112 hinfo
= seg6_hmac_info_lookup(net
, hmackeyid
);
118 err
= seg6_hmac_info_del(net
, hmackeyid
);
123 if (!info
->attrs
[SEG6_ATTR_SECRET
]) {
129 err
= seg6_hmac_info_del(net
, hmackeyid
);
134 secret
= (char *)nla_data(info
->attrs
[SEG6_ATTR_SECRET
]);
136 hinfo
= kzalloc(sizeof(*hinfo
), GFP_KERNEL
);
142 memcpy(hinfo
->secret
, secret
, slen
);
144 hinfo
->alg_id
= algid
;
145 hinfo
->hmackeyid
= hmackeyid
;
147 err
= seg6_hmac_info_add(net
, hmackeyid
, hinfo
);
152 mutex_unlock(&sdata
->lock
);
158 static int seg6_genl_sethmac(struct sk_buff
*skb
, struct genl_info
*info
)
165 static int seg6_genl_set_tunsrc(struct sk_buff
*skb
, struct genl_info
*info
)
167 struct net
*net
= genl_info_net(info
);
168 struct in6_addr
*val
, *t_old
, *t_new
;
169 struct seg6_pernet_data
*sdata
;
171 sdata
= seg6_pernet(net
);
173 if (!info
->attrs
[SEG6_ATTR_DST
])
176 val
= nla_data(info
->attrs
[SEG6_ATTR_DST
]);
177 t_new
= kmemdup(val
, sizeof(*val
), GFP_KERNEL
);
181 mutex_lock(&sdata
->lock
);
183 t_old
= sdata
->tun_src
;
184 rcu_assign_pointer(sdata
->tun_src
, t_new
);
186 mutex_unlock(&sdata
->lock
);
194 static int seg6_genl_get_tunsrc(struct sk_buff
*skb
, struct genl_info
*info
)
196 struct net
*net
= genl_info_net(info
);
197 struct in6_addr
*tun_src
;
201 msg
= genlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
205 hdr
= genlmsg_put(msg
, info
->snd_portid
, info
->snd_seq
,
206 &seg6_genl_family
, 0, SEG6_CMD_GET_TUNSRC
);
211 tun_src
= rcu_dereference(seg6_pernet(net
)->tun_src
);
213 if (nla_put(msg
, SEG6_ATTR_DST
, sizeof(struct in6_addr
), tun_src
))
214 goto nla_put_failure
;
218 genlmsg_end(msg
, hdr
);
219 return genlmsg_reply(msg
, info
);
228 #ifdef CONFIG_IPV6_SEG6_HMAC
230 static int __seg6_hmac_fill_info(struct seg6_hmac_info
*hinfo
,
233 if (nla_put_u32(msg
, SEG6_ATTR_HMACKEYID
, hinfo
->hmackeyid
) ||
234 nla_put_u8(msg
, SEG6_ATTR_SECRETLEN
, hinfo
->slen
) ||
235 nla_put(msg
, SEG6_ATTR_SECRET
, hinfo
->slen
, hinfo
->secret
) ||
236 nla_put_u8(msg
, SEG6_ATTR_ALGID
, hinfo
->alg_id
))
242 static int __seg6_genl_dumphmac_element(struct seg6_hmac_info
*hinfo
,
243 u32 portid
, u32 seq
, u32 flags
,
244 struct sk_buff
*skb
, u8 cmd
)
248 hdr
= genlmsg_put(skb
, portid
, seq
, &seg6_genl_family
, flags
, cmd
);
252 if (__seg6_hmac_fill_info(hinfo
, skb
) < 0)
253 goto nla_put_failure
;
255 genlmsg_end(skb
, hdr
);
259 genlmsg_cancel(skb
, hdr
);
263 static int seg6_genl_dumphmac_start(struct netlink_callback
*cb
)
265 struct net
*net
= sock_net(cb
->skb
->sk
);
266 struct seg6_pernet_data
*sdata
;
267 struct rhashtable_iter
*iter
;
269 sdata
= seg6_pernet(net
);
270 iter
= (struct rhashtable_iter
*)cb
->args
[0];
273 iter
= kmalloc(sizeof(*iter
), GFP_KERNEL
);
277 cb
->args
[0] = (long)iter
;
280 rhashtable_walk_enter(&sdata
->hmac_infos
, iter
);
285 static int seg6_genl_dumphmac_done(struct netlink_callback
*cb
)
287 struct rhashtable_iter
*iter
= (struct rhashtable_iter
*)cb
->args
[0];
289 rhashtable_walk_exit(iter
);
296 static int seg6_genl_dumphmac(struct sk_buff
*skb
, struct netlink_callback
*cb
)
298 struct rhashtable_iter
*iter
= (struct rhashtable_iter
*)cb
->args
[0];
299 struct seg6_hmac_info
*hinfo
;
302 rhashtable_walk_start(iter
);
305 hinfo
= rhashtable_walk_next(iter
);
308 if (PTR_ERR(hinfo
) == -EAGAIN
)
310 ret
= PTR_ERR(hinfo
);
316 ret
= __seg6_genl_dumphmac_element(hinfo
,
317 NETLINK_CB(cb
->skb
).portid
,
320 skb
, SEG6_CMD_DUMPHMAC
);
328 rhashtable_walk_stop(iter
);
334 static int seg6_genl_dumphmac_start(struct netlink_callback
*cb
)
339 static int seg6_genl_dumphmac_done(struct netlink_callback
*cb
)
344 static int seg6_genl_dumphmac(struct sk_buff
*skb
, struct netlink_callback
*cb
)
351 static int __net_init
seg6_net_init(struct net
*net
)
353 struct seg6_pernet_data
*sdata
;
355 sdata
= kzalloc(sizeof(*sdata
), GFP_KERNEL
);
359 mutex_init(&sdata
->lock
);
361 sdata
->tun_src
= kzalloc(sizeof(*sdata
->tun_src
), GFP_KERNEL
);
362 if (!sdata
->tun_src
) {
367 net
->ipv6
.seg6_data
= sdata
;
369 #ifdef CONFIG_IPV6_SEG6_HMAC
370 seg6_hmac_net_init(net
);
376 static void __net_exit
seg6_net_exit(struct net
*net
)
378 struct seg6_pernet_data
*sdata
= seg6_pernet(net
);
380 #ifdef CONFIG_IPV6_SEG6_HMAC
381 seg6_hmac_net_exit(net
);
384 kfree(sdata
->tun_src
);
388 static struct pernet_operations ip6_segments_ops
= {
389 .init
= seg6_net_init
,
390 .exit
= seg6_net_exit
,
393 static const struct genl_ops seg6_genl_ops
[] = {
395 .cmd
= SEG6_CMD_SETHMAC
,
396 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
397 .doit
= seg6_genl_sethmac
,
398 .flags
= GENL_ADMIN_PERM
,
401 .cmd
= SEG6_CMD_DUMPHMAC
,
402 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
403 .start
= seg6_genl_dumphmac_start
,
404 .dumpit
= seg6_genl_dumphmac
,
405 .done
= seg6_genl_dumphmac_done
,
406 .flags
= GENL_ADMIN_PERM
,
409 .cmd
= SEG6_CMD_SET_TUNSRC
,
410 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
411 .doit
= seg6_genl_set_tunsrc
,
412 .flags
= GENL_ADMIN_PERM
,
415 .cmd
= SEG6_CMD_GET_TUNSRC
,
416 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
417 .doit
= seg6_genl_get_tunsrc
,
418 .flags
= GENL_ADMIN_PERM
,
422 static struct genl_family seg6_genl_family __ro_after_init
= {
424 .name
= SEG6_GENL_NAME
,
425 .version
= SEG6_GENL_VERSION
,
426 .maxattr
= SEG6_ATTR_MAX
,
427 .policy
= seg6_genl_policy
,
429 .parallel_ops
= true,
430 .ops
= seg6_genl_ops
,
431 .n_ops
= ARRAY_SIZE(seg6_genl_ops
),
432 .module
= THIS_MODULE
,
435 int __init
seg6_init(void)
439 err
= genl_register_family(&seg6_genl_family
);
443 err
= register_pernet_subsys(&ip6_segments_ops
);
445 goto out_unregister_genl
;
447 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
448 err
= seg6_iptunnel_init();
450 goto out_unregister_pernet
;
452 err
= seg6_local_init();
454 goto out_unregister_pernet
;
457 #ifdef CONFIG_IPV6_SEG6_HMAC
458 err
= seg6_hmac_init();
460 goto out_unregister_iptun
;
463 pr_info("Segment Routing with IPv6\n");
467 #ifdef CONFIG_IPV6_SEG6_HMAC
468 out_unregister_iptun
:
469 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
471 seg6_iptunnel_exit();
474 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
475 out_unregister_pernet
:
476 unregister_pernet_subsys(&ip6_segments_ops
);
479 genl_unregister_family(&seg6_genl_family
);
485 #ifdef CONFIG_IPV6_SEG6_HMAC
488 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
489 seg6_iptunnel_exit();
491 unregister_pernet_subsys(&ip6_segments_ops
);
492 genl_unregister_family(&seg6_genl_family
);