aboutsummaryrefslogtreecommitdiffstats
path: root/net/mpls
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2015-03-03 20:13:56 -0500
committerDavid S. Miller <davem@davemloft.net>2015-03-04 00:26:06 -0500
commit03c0566542f4c7a45ce3193f27cbf5700b506c18 (patch)
tree97389268330933037ffe3cd5e4184f4c6b870359 /net/mpls
parent966bae3349da22bb6286f6f3874c279177b8633f (diff)
mpls: Netlink commands to add, remove, and dump routes
This change adds two new netlink routing attributes: RTA_VIA and RTA_NEWDST. RTA_VIA specifies the specifies the next machine to send a packet to like RTA_GATEWAY. RTA_VIA differs from RTA_GATEWAY in that it includes the address family of the address of the next machine to send a packet to. Currently the MPLS code supports addresses in AF_INET, AF_INET6 and AF_PACKET. For AF_INET and AF_INET6 the destination mac address is acquired from the neighbour table. For AF_PACKET the destination mac_address is specified in the netlink configuration. I think raw destination mac address support with the family AF_PACKET will prove useful. There is MPLS-TP which is defined to operate on machines that do not support internet packets of any flavor. Further seem to be corner cases where it can be useful. At this point I don't care much either way. RTA_NEWDST specifies the destination address to forward the packet with. MPLS typically changes it's destination address at every hop. For a swap operation RTA_NEWDST is specified with a length of one label. For a push operation RTA_NEWDST is specified with two or more labels. For a pop operation RTA_NEWDST is not specified or equivalently an emtpy RTAN_NEWDST is specified. Those new netlink attributes are used to implement handling of rt-netlink RTM_NEWROUTE, RTM_DELROUTE, and RTM_GETROUTE messages, to maintain the MPLS label table. rtm_to_route_config parses a netlink RTM_NEWROUTE or RTM_DELROUTE message, verify no unhandled attributes or unhandled values are present and sets up the data structures for mpls_route_add and mpls_route_del. I did my best to match up with the existing conventions with the caveats that MPLS addresses are all destination-specific-addresses, and so don't properly have a scope. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mpls')
-rw-r--r--net/mpls/af_mpls.c229
1 files changed, 229 insertions, 0 deletions
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 2d6612a10e30..b4d7cec398d2 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -212,6 +212,11 @@ static struct packet_type mpls_packet_type __read_mostly = {
212 .func = mpls_forward, 212 .func = mpls_forward,
213}; 213};
214 214
215const struct nla_policy rtm_mpls_policy[RTA_MAX+1] = {
216 [RTA_DST] = { .type = NLA_U32 },
217 [RTA_OIF] = { .type = NLA_U32 },
218};
219
215struct mpls_route_config { 220struct mpls_route_config {
216 u32 rc_protocol; 221 u32 rc_protocol;
217 u32 rc_ifindex; 222 u32 rc_ifindex;
@@ -410,6 +415,22 @@ static struct notifier_block mpls_dev_notifier = {
410 .notifier_call = mpls_dev_notify, 415 .notifier_call = mpls_dev_notify,
411}; 416};
412 417
418static int nla_put_via(struct sk_buff *skb,
419 u16 family, const void *addr, int alen)
420{
421 struct nlattr *nla;
422 struct rtvia *via;
423
424 nla = nla_reserve(skb, RTA_VIA, alen + 2);
425 if (!nla)
426 return -EMSGSIZE;
427
428 via = nla_data(nla);
429 via->rtvia_family = family;
430 memcpy(via->rtvia_addr, addr, alen);
431 return 0;
432}
433
413int nla_put_labels(struct sk_buff *skb, int attrtype, 434int nla_put_labels(struct sk_buff *skb, int attrtype,
414 u8 labels, const u32 label[]) 435 u8 labels, const u32 label[])
415{ 436{
@@ -467,6 +488,210 @@ int nla_get_labels(const struct nlattr *nla,
467 return 0; 488 return 0;
468} 489}
469 490
491static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
492 struct mpls_route_config *cfg)
493{
494 struct rtmsg *rtm;
495 struct nlattr *tb[RTA_MAX+1];
496 int index;
497 int err;
498
499 err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_mpls_policy);
500 if (err < 0)
501 goto errout;
502
503 err = -EINVAL;
504 rtm = nlmsg_data(nlh);
505 memset(cfg, 0, sizeof(*cfg));
506
507 if (rtm->rtm_family != AF_MPLS)
508 goto errout;
509 if (rtm->rtm_dst_len != 20)
510 goto errout;
511 if (rtm->rtm_src_len != 0)
512 goto errout;
513 if (rtm->rtm_tos != 0)
514 goto errout;
515 if (rtm->rtm_table != RT_TABLE_MAIN)
516 goto errout;
517 /* Any value is acceptable for rtm_protocol */
518
519 /* As mpls uses destination specific addresses
520 * (or source specific address in the case of multicast)
521 * all addresses have universal scope.
522 */
523 if (rtm->rtm_scope != RT_SCOPE_UNIVERSE)
524 goto errout;
525 if (rtm->rtm_type != RTN_UNICAST)
526 goto errout;
527 if (rtm->rtm_flags != 0)
528 goto errout;
529
530 cfg->rc_label = LABEL_NOT_SPECIFIED;
531 cfg->rc_protocol = rtm->rtm_protocol;
532 cfg->rc_nlflags = nlh->nlmsg_flags;
533 cfg->rc_nlinfo.portid = NETLINK_CB(skb).portid;
534 cfg->rc_nlinfo.nlh = nlh;
535 cfg->rc_nlinfo.nl_net = sock_net(skb->sk);
536
537 for (index = 0; index <= RTA_MAX; index++) {
538 struct nlattr *nla = tb[index];
539 if (!nla)
540 continue;
541
542 switch(index) {
543 case RTA_OIF:
544 cfg->rc_ifindex = nla_get_u32(nla);
545 break;
546 case RTA_NEWDST:
547 if (nla_get_labels(nla, MAX_NEW_LABELS,
548 &cfg->rc_output_labels,
549 cfg->rc_output_label))
550 goto errout;
551 break;
552 case RTA_DST:
553 {
554 u32 label_count;
555 if (nla_get_labels(nla, 1, &label_count,
556 &cfg->rc_label))
557 goto errout;
558
559 /* The first 16 labels are reserved, and may not be set */
560 if (cfg->rc_label < 16)
561 goto errout;
562
563 break;
564 }
565 case RTA_VIA:
566 {
567 struct rtvia *via = nla_data(nla);
568 cfg->rc_via_family = via->rtvia_family;
569 cfg->rc_via_alen = nla_len(nla) - 2;
570 if (cfg->rc_via_alen > MAX_VIA_ALEN)
571 goto errout;
572
573 /* Validate the address family */
574 switch(cfg->rc_via_family) {
575 case AF_PACKET:
576 break;
577 case AF_INET:
578 if (cfg->rc_via_alen != 4)
579 goto errout;
580 break;
581 case AF_INET6:
582 if (cfg->rc_via_alen != 16)
583 goto errout;
584 break;
585 default:
586 /* Unsupported address family */
587 goto errout;
588 }
589
590 memcpy(cfg->rc_via, via->rtvia_addr, cfg->rc_via_alen);
591 break;
592 }
593 default:
594 /* Unsupported attribute */
595 goto errout;
596 }
597 }
598
599 err = 0;
600errout:
601 return err;
602}
603
604static int mpls_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)
605{
606 struct mpls_route_config cfg;
607 int err;
608
609 err = rtm_to_route_config(skb, nlh, &cfg);
610 if (err < 0)
611 return err;
612
613 return mpls_route_del(&cfg);
614}
615
616
617static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
618{
619 struct mpls_route_config cfg;
620 int err;
621
622 err = rtm_to_route_config(skb, nlh, &cfg);
623 if (err < 0)
624 return err;
625
626 return mpls_route_add(&cfg);
627}
628
629static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
630 u32 label, struct mpls_route *rt, int flags)
631{
632 struct nlmsghdr *nlh;
633 struct rtmsg *rtm;
634
635 nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), flags);
636 if (nlh == NULL)
637 return -EMSGSIZE;
638
639 rtm = nlmsg_data(nlh);
640 rtm->rtm_family = AF_MPLS;
641 rtm->rtm_dst_len = 20;
642 rtm->rtm_src_len = 0;
643 rtm->rtm_tos = 0;
644 rtm->rtm_table = RT_TABLE_MAIN;
645 rtm->rtm_protocol = rt->rt_protocol;
646 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
647 rtm->rtm_type = RTN_UNICAST;
648 rtm->rtm_flags = 0;
649
650 if (rt->rt_labels &&
651 nla_put_labels(skb, RTA_NEWDST, rt->rt_labels, rt->rt_label))
652 goto nla_put_failure;
653 if (nla_put_via(skb, rt->rt_via_family, rt->rt_via, rt->rt_via_alen))
654 goto nla_put_failure;
655 if (rt->rt_dev && nla_put_u32(skb, RTA_OIF, rt->rt_dev->ifindex))
656 goto nla_put_failure;
657 if (nla_put_labels(skb, RTA_DST, 1, &label))
658 goto nla_put_failure;
659
660 nlmsg_end(skb, nlh);
661 return 0;
662
663nla_put_failure:
664 nlmsg_cancel(skb, nlh);
665 return -EMSGSIZE;
666}
667
668static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
669{
670 struct net *net = sock_net(skb->sk);
671 unsigned int index;
672
673 ASSERT_RTNL();
674
675 index = cb->args[0];
676 if (index < 16)
677 index = 16;
678
679 for (; index < net->mpls.platform_labels; index++) {
680 struct mpls_route *rt;
681 rt = net->mpls.platform_label[index];
682 if (!rt)
683 continue;
684
685 if (mpls_dump_route(skb, NETLINK_CB(cb->skb).portid,
686 cb->nlh->nlmsg_seq, RTM_NEWROUTE,
687 index, rt, NLM_F_MULTI) < 0)
688 break;
689 }
690 cb->args[0] = index;
691
692 return skb->len;
693}
694
470static int resize_platform_label_table(struct net *net, size_t limit) 695static int resize_platform_label_table(struct net *net, size_t limit)
471{ 696{
472 size_t size = sizeof(struct mpls_route *) * limit; 697 size_t size = sizeof(struct mpls_route *) * limit;
@@ -662,6 +887,9 @@ static int __init mpls_init(void)
662 887
663 dev_add_pack(&mpls_packet_type); 888 dev_add_pack(&mpls_packet_type);
664 889
890 rtnl_register(PF_MPLS, RTM_NEWROUTE, mpls_rtm_newroute, NULL, NULL);
891 rtnl_register(PF_MPLS, RTM_DELROUTE, mpls_rtm_delroute, NULL, NULL);
892 rtnl_register(PF_MPLS, RTM_GETROUTE, NULL, mpls_dump_routes, NULL);
665 err = 0; 893 err = 0;
666out: 894out:
667 return err; 895 return err;
@@ -674,6 +902,7 @@ module_init(mpls_init);
674 902
675static void __exit mpls_exit(void) 903static void __exit mpls_exit(void)
676{ 904{
905 rtnl_unregister_all(PF_MPLS);
677 dev_remove_pack(&mpls_packet_type); 906 dev_remove_pack(&mpls_packet_type);
678 unregister_netdevice_notifier(&mpls_dev_notifier); 907 unregister_netdevice_notifier(&mpls_dev_notifier);
679 unregister_pernet_subsys(&mpls_net_ops); 908 unregister_pernet_subsys(&mpls_net_ops);