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
)
30 unsigned int tlv_offset
;
34 if (srh
->type
!= IPV6_SRCRT_TYPE_4
)
37 if (((srh
->hdrlen
+ 1) << 3) != len
)
40 max_last_entry
= (srh
->hdrlen
/ 2) - 1;
42 if (srh
->first_segment
> max_last_entry
)
45 if (srh
->segments_left
> srh
->first_segment
+ 1)
48 tlv_offset
= sizeof(*srh
) + ((srh
->first_segment
+ 1) << 4);
50 trailing
= len
- tlv_offset
;
58 if (trailing
< sizeof(*tlv
))
61 tlv
= (struct sr6_tlv
*)((unsigned char *)srh
+ tlv_offset
);
62 tlv_len
= sizeof(*tlv
) + tlv
->len
;
68 tlv_offset
+= tlv_len
;
74 static struct genl_family seg6_genl_family
;
76 static const struct nla_policy seg6_genl_policy
[SEG6_ATTR_MAX
+ 1] = {
77 [SEG6_ATTR_DST
] = { .type
= NLA_BINARY
,
78 .len
= sizeof(struct in6_addr
) },
79 [SEG6_ATTR_DSTLEN
] = { .type
= NLA_S32
, },
80 [SEG6_ATTR_HMACKEYID
] = { .type
= NLA_U32
, },
81 [SEG6_ATTR_SECRET
] = { .type
= NLA_BINARY
, },
82 [SEG6_ATTR_SECRETLEN
] = { .type
= NLA_U8
, },
83 [SEG6_ATTR_ALGID
] = { .type
= NLA_U8
, },
84 [SEG6_ATTR_HMACINFO
] = { .type
= NLA_NESTED
, },
87 #ifdef CONFIG_IPV6_SEG6_HMAC
89 static int seg6_genl_sethmac(struct sk_buff
*skb
, struct genl_info
*info
)
91 struct net
*net
= genl_info_net(info
);
92 struct seg6_pernet_data
*sdata
;
93 struct seg6_hmac_info
*hinfo
;
100 sdata
= seg6_pernet(net
);
102 if (!info
->attrs
[SEG6_ATTR_HMACKEYID
] ||
103 !info
->attrs
[SEG6_ATTR_SECRETLEN
] ||
104 !info
->attrs
[SEG6_ATTR_ALGID
])
107 hmackeyid
= nla_get_u32(info
->attrs
[SEG6_ATTR_HMACKEYID
]);
108 slen
= nla_get_u8(info
->attrs
[SEG6_ATTR_SECRETLEN
]);
109 algid
= nla_get_u8(info
->attrs
[SEG6_ATTR_ALGID
]);
114 if (slen
> SEG6_HMAC_SECRET_LEN
)
117 mutex_lock(&sdata
->lock
);
118 hinfo
= seg6_hmac_info_lookup(net
, hmackeyid
);
124 err
= seg6_hmac_info_del(net
, hmackeyid
);
129 if (!info
->attrs
[SEG6_ATTR_SECRET
]) {
135 err
= seg6_hmac_info_del(net
, hmackeyid
);
140 secret
= (char *)nla_data(info
->attrs
[SEG6_ATTR_SECRET
]);
142 hinfo
= kzalloc(sizeof(*hinfo
), GFP_KERNEL
);
148 memcpy(hinfo
->secret
, secret
, slen
);
150 hinfo
->alg_id
= algid
;
151 hinfo
->hmackeyid
= hmackeyid
;
153 err
= seg6_hmac_info_add(net
, hmackeyid
, hinfo
);
158 mutex_unlock(&sdata
->lock
);
164 static int seg6_genl_sethmac(struct sk_buff
*skb
, struct genl_info
*info
)
171 static int seg6_genl_set_tunsrc(struct sk_buff
*skb
, struct genl_info
*info
)
173 struct net
*net
= genl_info_net(info
);
174 struct in6_addr
*val
, *t_old
, *t_new
;
175 struct seg6_pernet_data
*sdata
;
177 sdata
= seg6_pernet(net
);
179 if (!info
->attrs
[SEG6_ATTR_DST
])
182 val
= nla_data(info
->attrs
[SEG6_ATTR_DST
]);
183 t_new
= kmemdup(val
, sizeof(*val
), GFP_KERNEL
);
187 mutex_lock(&sdata
->lock
);
189 t_old
= sdata
->tun_src
;
190 rcu_assign_pointer(sdata
->tun_src
, t_new
);
192 mutex_unlock(&sdata
->lock
);
200 static int seg6_genl_get_tunsrc(struct sk_buff
*skb
, struct genl_info
*info
)
202 struct net
*net
= genl_info_net(info
);
203 struct in6_addr
*tun_src
;
207 msg
= genlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
211 hdr
= genlmsg_put(msg
, info
->snd_portid
, info
->snd_seq
,
212 &seg6_genl_family
, 0, SEG6_CMD_GET_TUNSRC
);
217 tun_src
= rcu_dereference(seg6_pernet(net
)->tun_src
);
219 if (nla_put(msg
, SEG6_ATTR_DST
, sizeof(struct in6_addr
), tun_src
))
220 goto nla_put_failure
;
224 genlmsg_end(msg
, hdr
);
225 return genlmsg_reply(msg
, info
);
234 #ifdef CONFIG_IPV6_SEG6_HMAC
236 static int __seg6_hmac_fill_info(struct seg6_hmac_info
*hinfo
,
239 if (nla_put_u32(msg
, SEG6_ATTR_HMACKEYID
, hinfo
->hmackeyid
) ||
240 nla_put_u8(msg
, SEG6_ATTR_SECRETLEN
, hinfo
->slen
) ||
241 nla_put(msg
, SEG6_ATTR_SECRET
, hinfo
->slen
, hinfo
->secret
) ||
242 nla_put_u8(msg
, SEG6_ATTR_ALGID
, hinfo
->alg_id
))
248 static int __seg6_genl_dumphmac_element(struct seg6_hmac_info
*hinfo
,
249 u32 portid
, u32 seq
, u32 flags
,
250 struct sk_buff
*skb
, u8 cmd
)
254 hdr
= genlmsg_put(skb
, portid
, seq
, &seg6_genl_family
, flags
, cmd
);
258 if (__seg6_hmac_fill_info(hinfo
, skb
) < 0)
259 goto nla_put_failure
;
261 genlmsg_end(skb
, hdr
);
265 genlmsg_cancel(skb
, hdr
);
269 static int seg6_genl_dumphmac_start(struct netlink_callback
*cb
)
271 struct net
*net
= sock_net(cb
->skb
->sk
);
272 struct seg6_pernet_data
*sdata
;
273 struct rhashtable_iter
*iter
;
275 sdata
= seg6_pernet(net
);
276 iter
= (struct rhashtable_iter
*)cb
->args
[0];
279 iter
= kmalloc(sizeof(*iter
), GFP_KERNEL
);
283 cb
->args
[0] = (long)iter
;
286 rhashtable_walk_enter(&sdata
->hmac_infos
, iter
);
291 static int seg6_genl_dumphmac_done(struct netlink_callback
*cb
)
293 struct rhashtable_iter
*iter
= (struct rhashtable_iter
*)cb
->args
[0];
295 rhashtable_walk_exit(iter
);
302 static int seg6_genl_dumphmac(struct sk_buff
*skb
, struct netlink_callback
*cb
)
304 struct rhashtable_iter
*iter
= (struct rhashtable_iter
*)cb
->args
[0];
305 struct seg6_hmac_info
*hinfo
;
308 rhashtable_walk_start(iter
);
311 hinfo
= rhashtable_walk_next(iter
);
314 if (PTR_ERR(hinfo
) == -EAGAIN
)
316 ret
= PTR_ERR(hinfo
);
322 ret
= __seg6_genl_dumphmac_element(hinfo
,
323 NETLINK_CB(cb
->skb
).portid
,
326 skb
, SEG6_CMD_DUMPHMAC
);
334 rhashtable_walk_stop(iter
);
340 static int seg6_genl_dumphmac_start(struct netlink_callback
*cb
)
345 static int seg6_genl_dumphmac_done(struct netlink_callback
*cb
)
350 static int seg6_genl_dumphmac(struct sk_buff
*skb
, struct netlink_callback
*cb
)
357 static int __net_init
seg6_net_init(struct net
*net
)
359 struct seg6_pernet_data
*sdata
;
361 sdata
= kzalloc(sizeof(*sdata
), GFP_KERNEL
);
365 mutex_init(&sdata
->lock
);
367 sdata
->tun_src
= kzalloc(sizeof(*sdata
->tun_src
), GFP_KERNEL
);
368 if (!sdata
->tun_src
) {
373 net
->ipv6
.seg6_data
= sdata
;
375 #ifdef CONFIG_IPV6_SEG6_HMAC
376 seg6_hmac_net_init(net
);
382 static void __net_exit
seg6_net_exit(struct net
*net
)
384 struct seg6_pernet_data
*sdata
= seg6_pernet(net
);
386 #ifdef CONFIG_IPV6_SEG6_HMAC
387 seg6_hmac_net_exit(net
);
390 kfree(sdata
->tun_src
);
394 static struct pernet_operations ip6_segments_ops
= {
395 .init
= seg6_net_init
,
396 .exit
= seg6_net_exit
,
399 static const struct genl_ops seg6_genl_ops
[] = {
401 .cmd
= SEG6_CMD_SETHMAC
,
402 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
403 .doit
= seg6_genl_sethmac
,
404 .flags
= GENL_ADMIN_PERM
,
407 .cmd
= SEG6_CMD_DUMPHMAC
,
408 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
409 .start
= seg6_genl_dumphmac_start
,
410 .dumpit
= seg6_genl_dumphmac
,
411 .done
= seg6_genl_dumphmac_done
,
412 .flags
= GENL_ADMIN_PERM
,
415 .cmd
= SEG6_CMD_SET_TUNSRC
,
416 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
417 .doit
= seg6_genl_set_tunsrc
,
418 .flags
= GENL_ADMIN_PERM
,
421 .cmd
= SEG6_CMD_GET_TUNSRC
,
422 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
423 .doit
= seg6_genl_get_tunsrc
,
424 .flags
= GENL_ADMIN_PERM
,
428 static struct genl_family seg6_genl_family __ro_after_init
= {
430 .name
= SEG6_GENL_NAME
,
431 .version
= SEG6_GENL_VERSION
,
432 .maxattr
= SEG6_ATTR_MAX
,
433 .policy
= seg6_genl_policy
,
435 .parallel_ops
= true,
436 .ops
= seg6_genl_ops
,
437 .n_ops
= ARRAY_SIZE(seg6_genl_ops
),
438 .module
= THIS_MODULE
,
441 int __init
seg6_init(void)
445 err
= genl_register_family(&seg6_genl_family
);
449 err
= register_pernet_subsys(&ip6_segments_ops
);
451 goto out_unregister_genl
;
453 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
454 err
= seg6_iptunnel_init();
456 goto out_unregister_pernet
;
458 err
= seg6_local_init();
460 goto out_unregister_pernet
;
463 #ifdef CONFIG_IPV6_SEG6_HMAC
464 err
= seg6_hmac_init();
466 goto out_unregister_iptun
;
469 pr_info("Segment Routing with IPv6\n");
473 #ifdef CONFIG_IPV6_SEG6_HMAC
474 out_unregister_iptun
:
475 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
477 seg6_iptunnel_exit();
480 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
481 out_unregister_pernet
:
482 unregister_pernet_subsys(&ip6_segments_ops
);
485 genl_unregister_family(&seg6_genl_family
);
491 #ifdef CONFIG_IPV6_SEG6_HMAC
494 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
495 seg6_iptunnel_exit();
497 unregister_pernet_subsys(&ip6_segments_ops
);
498 genl_unregister_family(&seg6_genl_family
);