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
, bool reduced
)
30 unsigned int tlv_offset
;
34 if (srh
->type
!= IPV6_SRCRT_TYPE_4
)
37 if (((srh
->hdrlen
+ 1) << 3) != len
)
40 if (!reduced
&& srh
->segments_left
> srh
->first_segment
) {
43 max_last_entry
= (srh
->hdrlen
/ 2) - 1;
45 if (srh
->first_segment
> max_last_entry
)
48 if (srh
->segments_left
> srh
->first_segment
+ 1)
52 tlv_offset
= sizeof(*srh
) + ((srh
->first_segment
+ 1) << 4);
54 trailing
= len
- tlv_offset
;
62 if (trailing
< sizeof(*tlv
))
65 tlv
= (struct sr6_tlv
*)((unsigned char *)srh
+ tlv_offset
);
66 tlv_len
= sizeof(*tlv
) + tlv
->len
;
72 tlv_offset
+= tlv_len
;
78 static struct genl_family seg6_genl_family
;
80 static const struct nla_policy seg6_genl_policy
[SEG6_ATTR_MAX
+ 1] = {
81 [SEG6_ATTR_DST
] = { .type
= NLA_BINARY
,
82 .len
= sizeof(struct in6_addr
) },
83 [SEG6_ATTR_DSTLEN
] = { .type
= NLA_S32
, },
84 [SEG6_ATTR_HMACKEYID
] = { .type
= NLA_U32
, },
85 [SEG6_ATTR_SECRET
] = { .type
= NLA_BINARY
, },
86 [SEG6_ATTR_SECRETLEN
] = { .type
= NLA_U8
, },
87 [SEG6_ATTR_ALGID
] = { .type
= NLA_U8
, },
88 [SEG6_ATTR_HMACINFO
] = { .type
= NLA_NESTED
, },
91 #ifdef CONFIG_IPV6_SEG6_HMAC
93 static int seg6_genl_sethmac(struct sk_buff
*skb
, struct genl_info
*info
)
95 struct net
*net
= genl_info_net(info
);
96 struct seg6_pernet_data
*sdata
;
97 struct seg6_hmac_info
*hinfo
;
104 sdata
= seg6_pernet(net
);
106 if (!info
->attrs
[SEG6_ATTR_HMACKEYID
] ||
107 !info
->attrs
[SEG6_ATTR_SECRETLEN
] ||
108 !info
->attrs
[SEG6_ATTR_ALGID
])
111 hmackeyid
= nla_get_u32(info
->attrs
[SEG6_ATTR_HMACKEYID
]);
112 slen
= nla_get_u8(info
->attrs
[SEG6_ATTR_SECRETLEN
]);
113 algid
= nla_get_u8(info
->attrs
[SEG6_ATTR_ALGID
]);
118 if (slen
> SEG6_HMAC_SECRET_LEN
)
121 mutex_lock(&sdata
->lock
);
122 hinfo
= seg6_hmac_info_lookup(net
, hmackeyid
);
128 err
= seg6_hmac_info_del(net
, hmackeyid
);
133 if (!info
->attrs
[SEG6_ATTR_SECRET
]) {
139 err
= seg6_hmac_info_del(net
, hmackeyid
);
144 secret
= (char *)nla_data(info
->attrs
[SEG6_ATTR_SECRET
]);
146 hinfo
= kzalloc(sizeof(*hinfo
), GFP_KERNEL
);
152 memcpy(hinfo
->secret
, secret
, slen
);
154 hinfo
->alg_id
= algid
;
155 hinfo
->hmackeyid
= hmackeyid
;
157 err
= seg6_hmac_info_add(net
, hmackeyid
, hinfo
);
162 mutex_unlock(&sdata
->lock
);
168 static int seg6_genl_sethmac(struct sk_buff
*skb
, struct genl_info
*info
)
175 static int seg6_genl_set_tunsrc(struct sk_buff
*skb
, struct genl_info
*info
)
177 struct net
*net
= genl_info_net(info
);
178 struct in6_addr
*val
, *t_old
, *t_new
;
179 struct seg6_pernet_data
*sdata
;
181 sdata
= seg6_pernet(net
);
183 if (!info
->attrs
[SEG6_ATTR_DST
])
186 val
= nla_data(info
->attrs
[SEG6_ATTR_DST
]);
187 t_new
= kmemdup(val
, sizeof(*val
), GFP_KERNEL
);
191 mutex_lock(&sdata
->lock
);
193 t_old
= sdata
->tun_src
;
194 rcu_assign_pointer(sdata
->tun_src
, t_new
);
196 mutex_unlock(&sdata
->lock
);
204 static int seg6_genl_get_tunsrc(struct sk_buff
*skb
, struct genl_info
*info
)
206 struct net
*net
= genl_info_net(info
);
207 struct in6_addr
*tun_src
;
211 msg
= genlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
215 hdr
= genlmsg_put(msg
, info
->snd_portid
, info
->snd_seq
,
216 &seg6_genl_family
, 0, SEG6_CMD_GET_TUNSRC
);
221 tun_src
= rcu_dereference(seg6_pernet(net
)->tun_src
);
223 if (nla_put(msg
, SEG6_ATTR_DST
, sizeof(struct in6_addr
), tun_src
))
224 goto nla_put_failure
;
228 genlmsg_end(msg
, hdr
);
229 return genlmsg_reply(msg
, info
);
238 #ifdef CONFIG_IPV6_SEG6_HMAC
240 static int __seg6_hmac_fill_info(struct seg6_hmac_info
*hinfo
,
243 if (nla_put_u32(msg
, SEG6_ATTR_HMACKEYID
, hinfo
->hmackeyid
) ||
244 nla_put_u8(msg
, SEG6_ATTR_SECRETLEN
, hinfo
->slen
) ||
245 nla_put(msg
, SEG6_ATTR_SECRET
, hinfo
->slen
, hinfo
->secret
) ||
246 nla_put_u8(msg
, SEG6_ATTR_ALGID
, hinfo
->alg_id
))
252 static int __seg6_genl_dumphmac_element(struct seg6_hmac_info
*hinfo
,
253 u32 portid
, u32 seq
, u32 flags
,
254 struct sk_buff
*skb
, u8 cmd
)
258 hdr
= genlmsg_put(skb
, portid
, seq
, &seg6_genl_family
, flags
, cmd
);
262 if (__seg6_hmac_fill_info(hinfo
, skb
) < 0)
263 goto nla_put_failure
;
265 genlmsg_end(skb
, hdr
);
269 genlmsg_cancel(skb
, hdr
);
273 static int seg6_genl_dumphmac_start(struct netlink_callback
*cb
)
275 struct net
*net
= sock_net(cb
->skb
->sk
);
276 struct seg6_pernet_data
*sdata
;
277 struct rhashtable_iter
*iter
;
279 sdata
= seg6_pernet(net
);
280 iter
= (struct rhashtable_iter
*)cb
->args
[0];
283 iter
= kmalloc(sizeof(*iter
), GFP_KERNEL
);
287 cb
->args
[0] = (long)iter
;
290 rhashtable_walk_enter(&sdata
->hmac_infos
, iter
);
295 static int seg6_genl_dumphmac_done(struct netlink_callback
*cb
)
297 struct rhashtable_iter
*iter
= (struct rhashtable_iter
*)cb
->args
[0];
299 rhashtable_walk_exit(iter
);
306 static int seg6_genl_dumphmac(struct sk_buff
*skb
, struct netlink_callback
*cb
)
308 struct rhashtable_iter
*iter
= (struct rhashtable_iter
*)cb
->args
[0];
309 struct seg6_hmac_info
*hinfo
;
312 rhashtable_walk_start(iter
);
315 hinfo
= rhashtable_walk_next(iter
);
318 if (PTR_ERR(hinfo
) == -EAGAIN
)
320 ret
= PTR_ERR(hinfo
);
326 ret
= __seg6_genl_dumphmac_element(hinfo
,
327 NETLINK_CB(cb
->skb
).portid
,
330 skb
, SEG6_CMD_DUMPHMAC
);
338 rhashtable_walk_stop(iter
);
344 static int seg6_genl_dumphmac_start(struct netlink_callback
*cb
)
349 static int seg6_genl_dumphmac_done(struct netlink_callback
*cb
)
354 static int seg6_genl_dumphmac(struct sk_buff
*skb
, struct netlink_callback
*cb
)
361 static int __net_init
seg6_net_init(struct net
*net
)
363 struct seg6_pernet_data
*sdata
;
365 sdata
= kzalloc(sizeof(*sdata
), GFP_KERNEL
);
369 mutex_init(&sdata
->lock
);
371 sdata
->tun_src
= kzalloc(sizeof(*sdata
->tun_src
), GFP_KERNEL
);
372 if (!sdata
->tun_src
) {
377 net
->ipv6
.seg6_data
= sdata
;
379 #ifdef CONFIG_IPV6_SEG6_HMAC
380 seg6_hmac_net_init(net
);
386 static void __net_exit
seg6_net_exit(struct net
*net
)
388 struct seg6_pernet_data
*sdata
= seg6_pernet(net
);
390 #ifdef CONFIG_IPV6_SEG6_HMAC
391 seg6_hmac_net_exit(net
);
394 kfree(sdata
->tun_src
);
398 static struct pernet_operations ip6_segments_ops
= {
399 .init
= seg6_net_init
,
400 .exit
= seg6_net_exit
,
403 static const struct genl_ops seg6_genl_ops
[] = {
405 .cmd
= SEG6_CMD_SETHMAC
,
406 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
407 .doit
= seg6_genl_sethmac
,
408 .flags
= GENL_ADMIN_PERM
,
411 .cmd
= SEG6_CMD_DUMPHMAC
,
412 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
413 .start
= seg6_genl_dumphmac_start
,
414 .dumpit
= seg6_genl_dumphmac
,
415 .done
= seg6_genl_dumphmac_done
,
416 .flags
= GENL_ADMIN_PERM
,
419 .cmd
= SEG6_CMD_SET_TUNSRC
,
420 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
421 .doit
= seg6_genl_set_tunsrc
,
422 .flags
= GENL_ADMIN_PERM
,
425 .cmd
= SEG6_CMD_GET_TUNSRC
,
426 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
427 .doit
= seg6_genl_get_tunsrc
,
428 .flags
= GENL_ADMIN_PERM
,
432 static struct genl_family seg6_genl_family __ro_after_init
= {
434 .name
= SEG6_GENL_NAME
,
435 .version
= SEG6_GENL_VERSION
,
436 .maxattr
= SEG6_ATTR_MAX
,
437 .policy
= seg6_genl_policy
,
439 .parallel_ops
= true,
440 .ops
= seg6_genl_ops
,
441 .n_ops
= ARRAY_SIZE(seg6_genl_ops
),
442 .module
= THIS_MODULE
,
445 int __init
seg6_init(void)
449 err
= genl_register_family(&seg6_genl_family
);
453 err
= register_pernet_subsys(&ip6_segments_ops
);
455 goto out_unregister_genl
;
457 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
458 err
= seg6_iptunnel_init();
460 goto out_unregister_pernet
;
462 err
= seg6_local_init();
464 goto out_unregister_pernet
;
467 #ifdef CONFIG_IPV6_SEG6_HMAC
468 err
= seg6_hmac_init();
470 goto out_unregister_iptun
;
473 pr_info("Segment Routing with IPv6\n");
477 #ifdef CONFIG_IPV6_SEG6_HMAC
478 out_unregister_iptun
:
479 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
481 seg6_iptunnel_exit();
484 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
485 out_unregister_pernet
:
486 unregister_pernet_subsys(&ip6_segments_ops
);
489 genl_unregister_family(&seg6_genl_family
);
495 #ifdef CONFIG_IPV6_SEG6_HMAC
498 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
499 seg6_iptunnel_exit();
501 unregister_pernet_subsys(&ip6_segments_ops
);
502 genl_unregister_family(&seg6_genl_family
);