0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/errno.h>
0010 #include <linux/types.h>
0011 #include <linux/socket.h>
0012 #include <linux/net.h>
0013 #include <linux/in6.h>
0014 #include <linux/slab.h>
0015 #include <linux/rhashtable.h>
0016
0017 #include <net/ipv6.h>
0018 #include <net/protocol.h>
0019
0020 #include <net/seg6.h>
0021 #include <net/genetlink.h>
0022 #include <linux/seg6.h>
0023 #include <linux/seg6_genl.h>
0024 #ifdef CONFIG_IPV6_SEG6_HMAC
0025 #include <net/seg6_hmac.h>
0026 #endif
0027
0028 bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len, bool reduced)
0029 {
0030 unsigned int tlv_offset;
0031 int max_last_entry;
0032 int trailing;
0033
0034 if (srh->type != IPV6_SRCRT_TYPE_4)
0035 return false;
0036
0037 if (((srh->hdrlen + 1) << 3) != len)
0038 return false;
0039
0040 if (!reduced && srh->segments_left > srh->first_segment) {
0041 return false;
0042 } else {
0043 max_last_entry = (srh->hdrlen / 2) - 1;
0044
0045 if (srh->first_segment > max_last_entry)
0046 return false;
0047
0048 if (srh->segments_left > srh->first_segment + 1)
0049 return false;
0050 }
0051
0052 tlv_offset = sizeof(*srh) + ((srh->first_segment + 1) << 4);
0053
0054 trailing = len - tlv_offset;
0055 if (trailing < 0)
0056 return false;
0057
0058 while (trailing) {
0059 struct sr6_tlv *tlv;
0060 unsigned int tlv_len;
0061
0062 if (trailing < sizeof(*tlv))
0063 return false;
0064
0065 tlv = (struct sr6_tlv *)((unsigned char *)srh + tlv_offset);
0066 tlv_len = sizeof(*tlv) + tlv->len;
0067
0068 trailing -= tlv_len;
0069 if (trailing < 0)
0070 return false;
0071
0072 tlv_offset += tlv_len;
0073 }
0074
0075 return true;
0076 }
0077
0078 struct ipv6_sr_hdr *seg6_get_srh(struct sk_buff *skb, int flags)
0079 {
0080 struct ipv6_sr_hdr *srh;
0081 int len, srhoff = 0;
0082
0083 if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, &flags) < 0)
0084 return NULL;
0085
0086 if (!pskb_may_pull(skb, srhoff + sizeof(*srh)))
0087 return NULL;
0088
0089 srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
0090
0091 len = (srh->hdrlen + 1) << 3;
0092
0093 if (!pskb_may_pull(skb, srhoff + len))
0094 return NULL;
0095
0096
0097
0098
0099 srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
0100
0101 if (!seg6_validate_srh(srh, len, true))
0102 return NULL;
0103
0104 return srh;
0105 }
0106
0107
0108
0109
0110
0111 void seg6_icmp_srh(struct sk_buff *skb, struct inet6_skb_parm *opt)
0112 {
0113 __u16 network_header = skb->network_header;
0114 struct ipv6_sr_hdr *srh;
0115
0116
0117
0118
0119
0120 skb_reset_network_header(skb);
0121
0122 srh = seg6_get_srh(skb, 0);
0123 if (!srh)
0124 goto out;
0125
0126 if (srh->type != IPV6_SRCRT_TYPE_4)
0127 goto out;
0128
0129 opt->flags |= IP6SKB_SEG6;
0130 opt->srhoff = (unsigned char *)srh - skb->data;
0131
0132 out:
0133
0134 skb->network_header = network_header;
0135 }
0136
0137 static struct genl_family seg6_genl_family;
0138
0139 static const struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX + 1] = {
0140 [SEG6_ATTR_DST] = { .type = NLA_BINARY,
0141 .len = sizeof(struct in6_addr) },
0142 [SEG6_ATTR_DSTLEN] = { .type = NLA_S32, },
0143 [SEG6_ATTR_HMACKEYID] = { .type = NLA_U32, },
0144 [SEG6_ATTR_SECRET] = { .type = NLA_BINARY, },
0145 [SEG6_ATTR_SECRETLEN] = { .type = NLA_U8, },
0146 [SEG6_ATTR_ALGID] = { .type = NLA_U8, },
0147 [SEG6_ATTR_HMACINFO] = { .type = NLA_NESTED, },
0148 };
0149
0150 #ifdef CONFIG_IPV6_SEG6_HMAC
0151
0152 static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
0153 {
0154 struct net *net = genl_info_net(info);
0155 struct seg6_pernet_data *sdata;
0156 struct seg6_hmac_info *hinfo;
0157 u32 hmackeyid;
0158 char *secret;
0159 int err = 0;
0160 u8 algid;
0161 u8 slen;
0162
0163 sdata = seg6_pernet(net);
0164
0165 if (!info->attrs[SEG6_ATTR_HMACKEYID] ||
0166 !info->attrs[SEG6_ATTR_SECRETLEN] ||
0167 !info->attrs[SEG6_ATTR_ALGID])
0168 return -EINVAL;
0169
0170 hmackeyid = nla_get_u32(info->attrs[SEG6_ATTR_HMACKEYID]);
0171 slen = nla_get_u8(info->attrs[SEG6_ATTR_SECRETLEN]);
0172 algid = nla_get_u8(info->attrs[SEG6_ATTR_ALGID]);
0173
0174 if (hmackeyid == 0)
0175 return -EINVAL;
0176
0177 if (slen > SEG6_HMAC_SECRET_LEN)
0178 return -EINVAL;
0179
0180 mutex_lock(&sdata->lock);
0181 hinfo = seg6_hmac_info_lookup(net, hmackeyid);
0182
0183 if (!slen) {
0184 err = seg6_hmac_info_del(net, hmackeyid);
0185
0186 goto out_unlock;
0187 }
0188
0189 if (!info->attrs[SEG6_ATTR_SECRET]) {
0190 err = -EINVAL;
0191 goto out_unlock;
0192 }
0193
0194 if (slen > nla_len(info->attrs[SEG6_ATTR_SECRET])) {
0195 err = -EINVAL;
0196 goto out_unlock;
0197 }
0198
0199 if (hinfo) {
0200 err = seg6_hmac_info_del(net, hmackeyid);
0201 if (err)
0202 goto out_unlock;
0203 }
0204
0205 secret = (char *)nla_data(info->attrs[SEG6_ATTR_SECRET]);
0206
0207 hinfo = kzalloc(sizeof(*hinfo), GFP_KERNEL);
0208 if (!hinfo) {
0209 err = -ENOMEM;
0210 goto out_unlock;
0211 }
0212
0213 memcpy(hinfo->secret, secret, slen);
0214 hinfo->slen = slen;
0215 hinfo->alg_id = algid;
0216 hinfo->hmackeyid = hmackeyid;
0217
0218 err = seg6_hmac_info_add(net, hmackeyid, hinfo);
0219 if (err)
0220 kfree(hinfo);
0221
0222 out_unlock:
0223 mutex_unlock(&sdata->lock);
0224 return err;
0225 }
0226
0227 #else
0228
0229 static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
0230 {
0231 return -ENOTSUPP;
0232 }
0233
0234 #endif
0235
0236 static int seg6_genl_set_tunsrc(struct sk_buff *skb, struct genl_info *info)
0237 {
0238 struct net *net = genl_info_net(info);
0239 struct in6_addr *val, *t_old, *t_new;
0240 struct seg6_pernet_data *sdata;
0241
0242 sdata = seg6_pernet(net);
0243
0244 if (!info->attrs[SEG6_ATTR_DST])
0245 return -EINVAL;
0246
0247 val = nla_data(info->attrs[SEG6_ATTR_DST]);
0248 t_new = kmemdup(val, sizeof(*val), GFP_KERNEL);
0249 if (!t_new)
0250 return -ENOMEM;
0251
0252 mutex_lock(&sdata->lock);
0253
0254 t_old = sdata->tun_src;
0255 rcu_assign_pointer(sdata->tun_src, t_new);
0256
0257 mutex_unlock(&sdata->lock);
0258
0259 synchronize_net();
0260 kfree(t_old);
0261
0262 return 0;
0263 }
0264
0265 static int seg6_genl_get_tunsrc(struct sk_buff *skb, struct genl_info *info)
0266 {
0267 struct net *net = genl_info_net(info);
0268 struct in6_addr *tun_src;
0269 struct sk_buff *msg;
0270 void *hdr;
0271
0272 msg = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
0273 if (!msg)
0274 return -ENOMEM;
0275
0276 hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
0277 &seg6_genl_family, 0, SEG6_CMD_GET_TUNSRC);
0278 if (!hdr)
0279 goto free_msg;
0280
0281 rcu_read_lock();
0282 tun_src = rcu_dereference(seg6_pernet(net)->tun_src);
0283
0284 if (nla_put(msg, SEG6_ATTR_DST, sizeof(struct in6_addr), tun_src))
0285 goto nla_put_failure;
0286
0287 rcu_read_unlock();
0288
0289 genlmsg_end(msg, hdr);
0290 return genlmsg_reply(msg, info);
0291
0292 nla_put_failure:
0293 rcu_read_unlock();
0294 free_msg:
0295 nlmsg_free(msg);
0296 return -ENOMEM;
0297 }
0298
0299 #ifdef CONFIG_IPV6_SEG6_HMAC
0300
0301 static int __seg6_hmac_fill_info(struct seg6_hmac_info *hinfo,
0302 struct sk_buff *msg)
0303 {
0304 if (nla_put_u32(msg, SEG6_ATTR_HMACKEYID, hinfo->hmackeyid) ||
0305 nla_put_u8(msg, SEG6_ATTR_SECRETLEN, hinfo->slen) ||
0306 nla_put(msg, SEG6_ATTR_SECRET, hinfo->slen, hinfo->secret) ||
0307 nla_put_u8(msg, SEG6_ATTR_ALGID, hinfo->alg_id))
0308 return -1;
0309
0310 return 0;
0311 }
0312
0313 static int __seg6_genl_dumphmac_element(struct seg6_hmac_info *hinfo,
0314 u32 portid, u32 seq, u32 flags,
0315 struct sk_buff *skb, u8 cmd)
0316 {
0317 void *hdr;
0318
0319 hdr = genlmsg_put(skb, portid, seq, &seg6_genl_family, flags, cmd);
0320 if (!hdr)
0321 return -ENOMEM;
0322
0323 if (__seg6_hmac_fill_info(hinfo, skb) < 0)
0324 goto nla_put_failure;
0325
0326 genlmsg_end(skb, hdr);
0327 return 0;
0328
0329 nla_put_failure:
0330 genlmsg_cancel(skb, hdr);
0331 return -EMSGSIZE;
0332 }
0333
0334 static int seg6_genl_dumphmac_start(struct netlink_callback *cb)
0335 {
0336 struct net *net = sock_net(cb->skb->sk);
0337 struct seg6_pernet_data *sdata;
0338 struct rhashtable_iter *iter;
0339
0340 sdata = seg6_pernet(net);
0341 iter = (struct rhashtable_iter *)cb->args[0];
0342
0343 if (!iter) {
0344 iter = kmalloc(sizeof(*iter), GFP_KERNEL);
0345 if (!iter)
0346 return -ENOMEM;
0347
0348 cb->args[0] = (long)iter;
0349 }
0350
0351 rhashtable_walk_enter(&sdata->hmac_infos, iter);
0352
0353 return 0;
0354 }
0355
0356 static int seg6_genl_dumphmac_done(struct netlink_callback *cb)
0357 {
0358 struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
0359
0360 rhashtable_walk_exit(iter);
0361
0362 kfree(iter);
0363
0364 return 0;
0365 }
0366
0367 static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
0368 {
0369 struct rhashtable_iter *iter = (struct rhashtable_iter *)cb->args[0];
0370 struct seg6_hmac_info *hinfo;
0371 int ret;
0372
0373 rhashtable_walk_start(iter);
0374
0375 for (;;) {
0376 hinfo = rhashtable_walk_next(iter);
0377
0378 if (IS_ERR(hinfo)) {
0379 if (PTR_ERR(hinfo) == -EAGAIN)
0380 continue;
0381 ret = PTR_ERR(hinfo);
0382 goto done;
0383 } else if (!hinfo) {
0384 break;
0385 }
0386
0387 ret = __seg6_genl_dumphmac_element(hinfo,
0388 NETLINK_CB(cb->skb).portid,
0389 cb->nlh->nlmsg_seq,
0390 NLM_F_MULTI,
0391 skb, SEG6_CMD_DUMPHMAC);
0392 if (ret)
0393 goto done;
0394 }
0395
0396 ret = skb->len;
0397
0398 done:
0399 rhashtable_walk_stop(iter);
0400 return ret;
0401 }
0402
0403 #else
0404
0405 static int seg6_genl_dumphmac_start(struct netlink_callback *cb)
0406 {
0407 return 0;
0408 }
0409
0410 static int seg6_genl_dumphmac_done(struct netlink_callback *cb)
0411 {
0412 return 0;
0413 }
0414
0415 static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
0416 {
0417 return -ENOTSUPP;
0418 }
0419
0420 #endif
0421
0422 static int __net_init seg6_net_init(struct net *net)
0423 {
0424 struct seg6_pernet_data *sdata;
0425
0426 sdata = kzalloc(sizeof(*sdata), GFP_KERNEL);
0427 if (!sdata)
0428 return -ENOMEM;
0429
0430 mutex_init(&sdata->lock);
0431
0432 sdata->tun_src = kzalloc(sizeof(*sdata->tun_src), GFP_KERNEL);
0433 if (!sdata->tun_src) {
0434 kfree(sdata);
0435 return -ENOMEM;
0436 }
0437
0438 net->ipv6.seg6_data = sdata;
0439
0440 #ifdef CONFIG_IPV6_SEG6_HMAC
0441 if (seg6_hmac_net_init(net)) {
0442 kfree(rcu_dereference_raw(sdata->tun_src));
0443 kfree(sdata);
0444 return -ENOMEM;
0445 }
0446 #endif
0447
0448 return 0;
0449 }
0450
0451 static void __net_exit seg6_net_exit(struct net *net)
0452 {
0453 struct seg6_pernet_data *sdata = seg6_pernet(net);
0454
0455 #ifdef CONFIG_IPV6_SEG6_HMAC
0456 seg6_hmac_net_exit(net);
0457 #endif
0458
0459 kfree(rcu_dereference_raw(sdata->tun_src));
0460 kfree(sdata);
0461 }
0462
0463 static struct pernet_operations ip6_segments_ops = {
0464 .init = seg6_net_init,
0465 .exit = seg6_net_exit,
0466 };
0467
0468 static const struct genl_ops seg6_genl_ops[] = {
0469 {
0470 .cmd = SEG6_CMD_SETHMAC,
0471 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0472 .doit = seg6_genl_sethmac,
0473 .flags = GENL_ADMIN_PERM,
0474 },
0475 {
0476 .cmd = SEG6_CMD_DUMPHMAC,
0477 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0478 .start = seg6_genl_dumphmac_start,
0479 .dumpit = seg6_genl_dumphmac,
0480 .done = seg6_genl_dumphmac_done,
0481 .flags = GENL_ADMIN_PERM,
0482 },
0483 {
0484 .cmd = SEG6_CMD_SET_TUNSRC,
0485 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0486 .doit = seg6_genl_set_tunsrc,
0487 .flags = GENL_ADMIN_PERM,
0488 },
0489 {
0490 .cmd = SEG6_CMD_GET_TUNSRC,
0491 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
0492 .doit = seg6_genl_get_tunsrc,
0493 .flags = GENL_ADMIN_PERM,
0494 },
0495 };
0496
0497 static struct genl_family seg6_genl_family __ro_after_init = {
0498 .hdrsize = 0,
0499 .name = SEG6_GENL_NAME,
0500 .version = SEG6_GENL_VERSION,
0501 .maxattr = SEG6_ATTR_MAX,
0502 .policy = seg6_genl_policy,
0503 .netnsok = true,
0504 .parallel_ops = true,
0505 .ops = seg6_genl_ops,
0506 .n_ops = ARRAY_SIZE(seg6_genl_ops),
0507 .module = THIS_MODULE,
0508 };
0509
0510 int __init seg6_init(void)
0511 {
0512 int err;
0513
0514 err = genl_register_family(&seg6_genl_family);
0515 if (err)
0516 goto out;
0517
0518 err = register_pernet_subsys(&ip6_segments_ops);
0519 if (err)
0520 goto out_unregister_genl;
0521
0522 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
0523 err = seg6_iptunnel_init();
0524 if (err)
0525 goto out_unregister_pernet;
0526
0527 err = seg6_local_init();
0528 if (err)
0529 goto out_unregister_pernet;
0530 #endif
0531
0532 #ifdef CONFIG_IPV6_SEG6_HMAC
0533 err = seg6_hmac_init();
0534 if (err)
0535 goto out_unregister_iptun;
0536 #endif
0537
0538 pr_info("Segment Routing with IPv6\n");
0539
0540 out:
0541 return err;
0542 #ifdef CONFIG_IPV6_SEG6_HMAC
0543 out_unregister_iptun:
0544 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
0545 seg6_local_exit();
0546 seg6_iptunnel_exit();
0547 #endif
0548 #endif
0549 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
0550 out_unregister_pernet:
0551 unregister_pernet_subsys(&ip6_segments_ops);
0552 #endif
0553 out_unregister_genl:
0554 genl_unregister_family(&seg6_genl_family);
0555 goto out;
0556 }
0557
0558 void seg6_exit(void)
0559 {
0560 #ifdef CONFIG_IPV6_SEG6_HMAC
0561 seg6_hmac_exit();
0562 #endif
0563 #ifdef CONFIG_IPV6_SEG6_LWTUNNEL
0564 seg6_iptunnel_exit();
0565 #endif
0566 unregister_pernet_subsys(&ip6_segments_ops);
0567 genl_unregister_family(&seg6_genl_family);
0568 }