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 #include <net/seg6_hmac.h>
26 bool seg6_validate_srh(struct ipv6_sr_hdr
*srh
, int len
, bool reduced
)
28 unsigned int tlv_offset
;
32 if (srh
->type
!= IPV6_SRCRT_TYPE_4
)
35 if (((srh
->hdrlen
+ 1) << 3) != len
)
38 if (!reduced
&& srh
->segments_left
> srh
->first_segment
) {
41 max_last_entry
= (srh
->hdrlen
/ 2) - 1;
43 if (srh
->first_segment
> max_last_entry
)
46 if (srh
->segments_left
> srh
->first_segment
+ 1)
50 tlv_offset
= sizeof(*srh
) + ((srh
->first_segment
+ 1) << 4);
52 trailing
= len
- tlv_offset
;
60 if (trailing
< sizeof(*tlv
))
63 tlv
= (struct sr6_tlv
*)((unsigned char *)srh
+ tlv_offset
);
64 tlv_len
= sizeof(*tlv
) + tlv
->len
;
70 tlv_offset
+= tlv_len
;
76 struct ipv6_sr_hdr
*seg6_get_srh(struct sk_buff
*skb
, int flags
)
78 struct ipv6_sr_hdr
*srh
;
81 if (ipv6_find_hdr(skb
, &srhoff
, IPPROTO_ROUTING
, NULL
, &flags
) < 0)
84 if (!pskb_may_pull(skb
, srhoff
+ sizeof(*srh
)))
87 srh
= (struct ipv6_sr_hdr
*)(skb
->data
+ srhoff
);
89 len
= (srh
->hdrlen
+ 1) << 3;
91 if (!pskb_may_pull(skb
, srhoff
+ len
))
94 /* note that pskb_may_pull may change pointers in header;
95 * for this reason it is necessary to reload them when needed.
97 srh
= (struct ipv6_sr_hdr
*)(skb
->data
+ srhoff
);
99 if (!seg6_validate_srh(srh
, len
, true))
105 /* Determine if an ICMP invoking packet contains a segment routing
106 * header. If it does, extract the offset to the true destination
107 * address, which is in the first segment address.
109 void seg6_icmp_srh(struct sk_buff
*skb
, struct inet6_skb_parm
*opt
)
111 __u16 network_header
= skb
->network_header
;
112 struct ipv6_sr_hdr
*srh
;
114 /* Update network header to point to the invoking packet
115 * inside the ICMP packet, so we can use the seg6_get_srh()
118 skb_reset_network_header(skb
);
120 srh
= seg6_get_srh(skb
, 0);
124 if (srh
->type
!= IPV6_SRCRT_TYPE_4
)
127 opt
->flags
|= IP6SKB_SEG6
;
128 opt
->srhoff
= (unsigned char *)srh
- skb
->data
;
131 /* Restore the network header back to the ICMP packet */
132 skb
->network_header
= network_header
;
135 static struct genl_family seg6_genl_family
;
137 static const struct nla_policy seg6_genl_policy
[SEG6_ATTR_MAX
+ 1] = {
138 [SEG6_ATTR_DST
] = { .type
= NLA_BINARY
,
139 .len
= sizeof(struct in6_addr
) },
140 [SEG6_ATTR_DSTLEN
] = { .type
= NLA_S32
, },
141 [SEG6_ATTR_HMACKEYID
] = { .type
= NLA_U32
, },
142 [SEG6_ATTR_SECRET
] = { .type
= NLA_BINARY
, },
143 [SEG6_ATTR_SECRETLEN
] = { .type
= NLA_U8
, },
144 [SEG6_ATTR_ALGID
] = { .type
= NLA_U8
, },
145 [SEG6_ATTR_HMACINFO
] = { .type
= NLA_NESTED
, },
148 #ifdef CONFIG_IPV6_SEG6_HMAC
150 static int seg6_genl_sethmac(struct sk_buff
*skb
, struct genl_info
*info
)
152 struct net
*net
= genl_info_net(info
);
153 struct seg6_pernet_data
*sdata
;
154 struct seg6_hmac_info
*hinfo
;
161 sdata
= seg6_pernet(net
);
163 if (!info
->attrs
[SEG6_ATTR_HMACKEYID
] ||
164 !info
->attrs
[SEG6_ATTR_SECRETLEN
] ||
165 !info
->attrs
[SEG6_ATTR_ALGID
])
168 hmackeyid
= nla_get_u32(info
->attrs
[SEG6_ATTR_HMACKEYID
]);
169 slen
= nla_get_u8(info
->attrs
[SEG6_ATTR_SECRETLEN
]);
170 algid
= nla_get_u8(info
->attrs
[SEG6_ATTR_ALGID
]);
175 if (slen
> SEG6_HMAC_SECRET_LEN
)
178 mutex_lock(&sdata
->lock
);
179 hinfo
= seg6_hmac_info_lookup(net
, hmackeyid
);
182 err
= seg6_hmac_info_del(net
, hmackeyid
);
187 if (!info
->attrs
[SEG6_ATTR_SECRET
]) {
192 if (slen
> nla_len(info
->attrs
[SEG6_ATTR_SECRET
])) {
198 err
= seg6_hmac_info_del(net
, hmackeyid
);
203 secret
= (char *)nla_data(info
->attrs
[SEG6_ATTR_SECRET
]);
205 hinfo
= kzalloc(sizeof(*hinfo
), GFP_KERNEL
);
211 memcpy(hinfo
->secret
, secret
, slen
);
213 hinfo
->alg_id
= algid
;
214 hinfo
->hmackeyid
= hmackeyid
;
216 err
= seg6_hmac_info_add(net
, hmackeyid
, hinfo
);
221 mutex_unlock(&sdata
->lock
);
227 static int seg6_genl_sethmac(struct sk_buff
*skb
, struct genl_info
*info
)
234 static int seg6_genl_set_tunsrc(struct sk_buff
*skb
, struct genl_info
*info
)
236 struct net
*net
= genl_info_net(info
);
237 struct in6_addr
*val
, *t_old
, *t_new
;
238 struct seg6_pernet_data
*sdata
;
240 sdata
= seg6_pernet(net
);
242 if (!info
->attrs
[SEG6_ATTR_DST
])
245 val
= nla_data(info
->attrs
[SEG6_ATTR_DST
]);
246 t_new
= kmemdup(val
, sizeof(*val
), GFP_KERNEL
);
250 mutex_lock(&sdata
->lock
);
252 t_old
= sdata
->tun_src
;
253 rcu_assign_pointer(sdata
->tun_src
, t_new
);
255 mutex_unlock(&sdata
->lock
);
263 static int seg6_genl_get_tunsrc(struct sk_buff
*skb
, struct genl_info
*info
)
265 struct net
*net
= genl_info_net(info
);
266 struct in6_addr
*tun_src
;
270 msg
= genlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
274 hdr
= genlmsg_put(msg
, info
->snd_portid
, info
->snd_seq
,
275 &seg6_genl_family
, 0, SEG6_CMD_GET_TUNSRC
);
280 tun_src
= rcu_dereference(seg6_pernet(net
)->tun_src
);
282 if (nla_put(msg
, SEG6_ATTR_DST
, sizeof(struct in6_addr
), tun_src
))
283 goto nla_put_failure
;
287 genlmsg_end(msg
, hdr
);
288 return genlmsg_reply(msg
, info
);
297 #ifdef CONFIG_IPV6_SEG6_HMAC
299 static int __seg6_hmac_fill_info(struct seg6_hmac_info
*hinfo
,
302 if (nla_put_u32(msg
, SEG6_ATTR_HMACKEYID
, hinfo
->hmackeyid
) ||
303 nla_put_u8(msg
, SEG6_ATTR_SECRETLEN
, hinfo
->slen
) ||
304 nla_put(msg
, SEG6_ATTR_SECRET
, hinfo
->slen
, hinfo
->secret
) ||
305 nla_put_u8(msg
, SEG6_ATTR_ALGID
, hinfo
->alg_id
))
311 static int __seg6_genl_dumphmac_element(struct seg6_hmac_info
*hinfo
,
312 u32 portid
, u32 seq
, u32 flags
,
313 struct sk_buff
*skb
, u8 cmd
)
317 hdr
= genlmsg_put(skb
, portid
, seq
, &seg6_genl_family
, flags
, cmd
);
321 if (__seg6_hmac_fill_info(hinfo
, skb
) < 0)
322 goto nla_put_failure
;
324 genlmsg_end(skb
, hdr
);
328 genlmsg_cancel(skb
, hdr
);
332 static int seg6_genl_dumphmac_start(struct netlink_callback
*cb
)
334 struct net
*net
= sock_net(cb
->skb
->sk
);
335 struct seg6_pernet_data
*sdata
;
336 struct rhashtable_iter
*iter
;
338 sdata
= seg6_pernet(net
);
339 iter
= (struct rhashtable_iter
*)cb
->args
[0];
342 iter
= kmalloc(sizeof(*iter
), GFP_KERNEL
);
346 cb
->args
[0] = (long)iter
;
349 rhashtable_walk_enter(&sdata
->hmac_infos
, iter
);
354 static int seg6_genl_dumphmac_done(struct netlink_callback
*cb
)
356 struct rhashtable_iter
*iter
= (struct rhashtable_iter
*)cb
->args
[0];
358 rhashtable_walk_exit(iter
);
365 static int seg6_genl_dumphmac(struct sk_buff
*skb
, struct netlink_callback
*cb
)
367 struct rhashtable_iter
*iter
= (struct rhashtable_iter
*)cb
->args
[0];
368 struct seg6_hmac_info
*hinfo
;
371 rhashtable_walk_start(iter
);
374 hinfo
= rhashtable_walk_next(iter
);
377 if (PTR_ERR(hinfo
) == -EAGAIN
)
379 ret
= PTR_ERR(hinfo
);
385 ret
= __seg6_genl_dumphmac_element(hinfo
,
386 NETLINK_CB(cb
->skb
).portid
,
389 skb
, SEG6_CMD_DUMPHMAC
);
397 rhashtable_walk_stop(iter
);
403 static int seg6_genl_dumphmac_start(struct netlink_callback
*cb
)
408 static int seg6_genl_dumphmac_done(struct netlink_callback
*cb
)
413 static int seg6_genl_dumphmac(struct sk_buff
*skb
, struct netlink_callback
*cb
)
420 static int __net_init
seg6_net_init(struct net
*net
)
422 struct seg6_pernet_data
*sdata
;
424 sdata
= kzalloc(sizeof(*sdata
), GFP_KERNEL
);
428 mutex_init(&sdata
->lock
);
430 sdata
->tun_src
= kzalloc(sizeof(*sdata
->tun_src
), GFP_KERNEL
);
431 if (!sdata
->tun_src
) {
436 net
->ipv6
.seg6_data
= sdata
;
438 if (seg6_hmac_net_init(net
)) {
439 kfree(rcu_dereference_raw(sdata
->tun_src
));
447 static void __net_exit
seg6_net_exit(struct net
*net
)
449 struct seg6_pernet_data
*sdata
= seg6_pernet(net
);
451 seg6_hmac_net_exit(net
);
453 kfree(rcu_dereference_raw(sdata
->tun_src
));
457 static struct pernet_operations ip6_segments_ops
= {
458 .init
= seg6_net_init
,
459 .exit
= seg6_net_exit
,
462 static const struct genl_ops seg6_genl_ops
[] = {
464 .cmd
= SEG6_CMD_SETHMAC
,
465 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
466 .doit
= seg6_genl_sethmac
,
467 .flags
= GENL_ADMIN_PERM
,
470 .cmd
= SEG6_CMD_DUMPHMAC
,
471 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
472 .start
= seg6_genl_dumphmac_start
,
473 .dumpit
= seg6_genl_dumphmac
,
474 .done
= seg6_genl_dumphmac_done
,
475 .flags
= GENL_ADMIN_PERM
,
478 .cmd
= SEG6_CMD_SET_TUNSRC
,
479 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
480 .doit
= seg6_genl_set_tunsrc
,
481 .flags
= GENL_ADMIN_PERM
,
484 .cmd
= SEG6_CMD_GET_TUNSRC
,
485 .validate
= GENL_DONT_VALIDATE_STRICT
| GENL_DONT_VALIDATE_DUMP
,
486 .doit
= seg6_genl_get_tunsrc
,
487 .flags
= GENL_ADMIN_PERM
,
491 static struct genl_family seg6_genl_family __ro_after_init
= {
493 .name
= SEG6_GENL_NAME
,
494 .version
= SEG6_GENL_VERSION
,
495 .maxattr
= SEG6_ATTR_MAX
,
496 .policy
= seg6_genl_policy
,
498 .parallel_ops
= true,
499 .ops
= seg6_genl_ops
,
500 .n_ops
= ARRAY_SIZE(seg6_genl_ops
),
501 .resv_start_op
= SEG6_CMD_GET_TUNSRC
+ 1,
502 .module
= THIS_MODULE
,
505 int __init
seg6_init(void)
509 err
= register_pernet_subsys(&ip6_segments_ops
);
513 err
= genl_register_family(&seg6_genl_family
);
515 goto out_unregister_pernet
;
517 err
= seg6_iptunnel_init();
519 goto out_unregister_genl
;
521 err
= seg6_local_init();
523 goto out_unregister_iptun
;
525 err
= seg6_hmac_init();
527 goto out_unregister_seg6
;
529 pr_info("Segment Routing with IPv6\n");
535 out_unregister_iptun
:
536 seg6_iptunnel_exit();
538 genl_unregister_family(&seg6_genl_family
);
539 out_unregister_pernet
:
540 unregister_pernet_subsys(&ip6_segments_ops
);
548 seg6_iptunnel_exit();
549 genl_unregister_family(&seg6_genl_family
);
550 unregister_pernet_subsys(&ip6_segments_ops
);