aboutsummaryrefslogtreecommitdiffstats
path: root/net/mpls/af_mpls.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mpls/af_mpls.c')
-rw-r--r--net/mpls/af_mpls.c152
1 files changed, 141 insertions, 11 deletions
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index db8a2ea6d4de..1f93a5978f2a 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -53,6 +53,11 @@ static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
53 return rt; 53 return rt;
54} 54}
55 55
56static inline struct mpls_dev *mpls_dev_get(const struct net_device *dev)
57{
58 return rcu_dereference_rtnl(dev->mpls_ptr);
59}
60
56static bool mpls_output_possible(const struct net_device *dev) 61static bool mpls_output_possible(const struct net_device *dev)
57{ 62{
58 return dev && (dev->flags & IFF_UP) && netif_carrier_ok(dev); 63 return dev && (dev->flags & IFF_UP) && netif_carrier_ok(dev);
@@ -136,6 +141,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
136 struct mpls_route *rt; 141 struct mpls_route *rt;
137 struct mpls_entry_decoded dec; 142 struct mpls_entry_decoded dec;
138 struct net_device *out_dev; 143 struct net_device *out_dev;
144 struct mpls_dev *mdev;
139 unsigned int hh_len; 145 unsigned int hh_len;
140 unsigned int new_header_size; 146 unsigned int new_header_size;
141 unsigned int mtu; 147 unsigned int mtu;
@@ -143,6 +149,10 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
143 149
144 /* Careful this entire function runs inside of an rcu critical section */ 150 /* Careful this entire function runs inside of an rcu critical section */
145 151
152 mdev = mpls_dev_get(dev);
153 if (!mdev || !mdev->input_enabled)
154 goto drop;
155
146 if (skb->pkt_type != PACKET_HOST) 156 if (skb->pkt_type != PACKET_HOST)
147 goto drop; 157 goto drop;
148 158
@@ -352,9 +362,9 @@ static int mpls_route_add(struct mpls_route_config *cfg)
352 if (!dev) 362 if (!dev)
353 goto errout; 363 goto errout;
354 364
355 /* For now just support ethernet devices */ 365 /* Ensure this is a supported device */
356 err = -EINVAL; 366 err = -EINVAL;
357 if ((dev->type != ARPHRD_ETHER) && (dev->type != ARPHRD_LOOPBACK)) 367 if (!mpls_dev_get(dev))
358 goto errout; 368 goto errout;
359 369
360 err = -EINVAL; 370 err = -EINVAL;
@@ -428,10 +438,89 @@ errout:
428 return err; 438 return err;
429} 439}
430 440
441#define MPLS_PERDEV_SYSCTL_OFFSET(field) \
442 (&((struct mpls_dev *)0)->field)
443
444static const struct ctl_table mpls_dev_table[] = {
445 {
446 .procname = "input",
447 .maxlen = sizeof(int),
448 .mode = 0644,
449 .proc_handler = proc_dointvec,
450 .data = MPLS_PERDEV_SYSCTL_OFFSET(input_enabled),
451 },
452 { }
453};
454
455static int mpls_dev_sysctl_register(struct net_device *dev,
456 struct mpls_dev *mdev)
457{
458 char path[sizeof("net/mpls/conf/") + IFNAMSIZ];
459 struct ctl_table *table;
460 int i;
461
462 table = kmemdup(&mpls_dev_table, sizeof(mpls_dev_table), GFP_KERNEL);
463 if (!table)
464 goto out;
465
466 /* Table data contains only offsets relative to the base of
467 * the mdev at this point, so make them absolute.
468 */
469 for (i = 0; i < ARRAY_SIZE(mpls_dev_table); i++)
470 table[i].data = (char *)mdev + (uintptr_t)table[i].data;
471
472 snprintf(path, sizeof(path), "net/mpls/conf/%s", dev->name);
473
474 mdev->sysctl = register_net_sysctl(dev_net(dev), path, table);
475 if (!mdev->sysctl)
476 goto free;
477
478 return 0;
479
480free:
481 kfree(table);
482out:
483 return -ENOBUFS;
484}
485
486static void mpls_dev_sysctl_unregister(struct mpls_dev *mdev)
487{
488 struct ctl_table *table;
489
490 table = mdev->sysctl->ctl_table_arg;
491 unregister_net_sysctl_table(mdev->sysctl);
492 kfree(table);
493}
494
495static struct mpls_dev *mpls_add_dev(struct net_device *dev)
496{
497 struct mpls_dev *mdev;
498 int err = -ENOMEM;
499
500 ASSERT_RTNL();
501
502 mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
503 if (!mdev)
504 return ERR_PTR(err);
505
506 err = mpls_dev_sysctl_register(dev, mdev);
507 if (err)
508 goto free;
509
510 rcu_assign_pointer(dev->mpls_ptr, mdev);
511
512 return mdev;
513
514free:
515 kfree(mdev);
516 return ERR_PTR(err);
517}
518
431static void mpls_ifdown(struct net_device *dev) 519static void mpls_ifdown(struct net_device *dev)
432{ 520{
433 struct mpls_route __rcu **platform_label; 521 struct mpls_route __rcu **platform_label;
434 struct net *net = dev_net(dev); 522 struct net *net = dev_net(dev);
523 struct mpls_dev *mdev;
435 unsigned index; 524 unsigned index;
436 525
437 platform_label = rtnl_dereference(net->mpls.platform_label); 526 platform_label = rtnl_dereference(net->mpls.platform_label);
@@ -443,17 +532,49 @@ static void mpls_ifdown(struct net_device *dev)
443 continue; 532 continue;
444 rt->rt_dev = NULL; 533 rt->rt_dev = NULL;
445 } 534 }
535
536 mdev = mpls_dev_get(dev);
537 if (!mdev)
538 return;
539
540 mpls_dev_sysctl_unregister(mdev);
541
542 RCU_INIT_POINTER(dev->mpls_ptr, NULL);
543
544 kfree_rcu(mdev, rcu);
446} 545}
447 546
448static int mpls_dev_notify(struct notifier_block *this, unsigned long event, 547static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
449 void *ptr) 548 void *ptr)
450{ 549{
451 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 550 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
551 struct mpls_dev *mdev;
452 552
453 switch(event) { 553 switch(event) {
554 case NETDEV_REGISTER:
555 /* For now just support ethernet devices */
556 if ((dev->type == ARPHRD_ETHER) ||
557 (dev->type == ARPHRD_LOOPBACK)) {
558 mdev = mpls_add_dev(dev);
559 if (IS_ERR(mdev))
560 return notifier_from_errno(PTR_ERR(mdev));
561 }
562 break;
563
454 case NETDEV_UNREGISTER: 564 case NETDEV_UNREGISTER:
455 mpls_ifdown(dev); 565 mpls_ifdown(dev);
456 break; 566 break;
567 case NETDEV_CHANGENAME:
568 mdev = mpls_dev_get(dev);
569 if (mdev) {
570 int err;
571
572 mpls_dev_sysctl_unregister(mdev);
573 err = mpls_dev_sysctl_register(dev, mdev);
574 if (err)
575 return notifier_from_errno(err);
576 }
577 break;
457 } 578 }
458 return NOTIFY_OK; 579 return NOTIFY_OK;
459} 580}
@@ -536,6 +657,15 @@ int nla_get_labels(const struct nlattr *nla,
536 if ((dec.bos != bos) || dec.ttl || dec.tc) 657 if ((dec.bos != bos) || dec.ttl || dec.tc)
537 return -EINVAL; 658 return -EINVAL;
538 659
660 switch (dec.label) {
661 case MPLS_LABEL_IMPLNULL:
662 /* RFC3032: This is a label that an LSR may
663 * assign and distribute, but which never
664 * actually appears in the encapsulation.
665 */
666 return -EINVAL;
667 }
668
539 label[i] = dec.label; 669 label[i] = dec.label;
540 } 670 }
541 *labels = nla_labels; 671 *labels = nla_labels;
@@ -816,7 +946,7 @@ static int resize_platform_label_table(struct net *net, size_t limit)
816 } 946 }
817 947
818 /* In case the predefined labels need to be populated */ 948 /* In case the predefined labels need to be populated */
819 if (limit > LABEL_IPV4_EXPLICIT_NULL) { 949 if (limit > MPLS_LABEL_IPV4NULL) {
820 struct net_device *lo = net->loopback_dev; 950 struct net_device *lo = net->loopback_dev;
821 rt0 = mpls_rt_alloc(lo->addr_len); 951 rt0 = mpls_rt_alloc(lo->addr_len);
822 if (!rt0) 952 if (!rt0)
@@ -826,7 +956,7 @@ static int resize_platform_label_table(struct net *net, size_t limit)
826 rt0->rt_via_table = NEIGH_LINK_TABLE; 956 rt0->rt_via_table = NEIGH_LINK_TABLE;
827 memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len); 957 memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len);
828 } 958 }
829 if (limit > LABEL_IPV6_EXPLICIT_NULL) { 959 if (limit > MPLS_LABEL_IPV6NULL) {
830 struct net_device *lo = net->loopback_dev; 960 struct net_device *lo = net->loopback_dev;
831 rt2 = mpls_rt_alloc(lo->addr_len); 961 rt2 = mpls_rt_alloc(lo->addr_len);
832 if (!rt2) 962 if (!rt2)
@@ -854,15 +984,15 @@ static int resize_platform_label_table(struct net *net, size_t limit)
854 memcpy(labels, old, cp_size); 984 memcpy(labels, old, cp_size);
855 985
856 /* If needed set the predefined labels */ 986 /* If needed set the predefined labels */
857 if ((old_limit <= LABEL_IPV6_EXPLICIT_NULL) && 987 if ((old_limit <= MPLS_LABEL_IPV6NULL) &&
858 (limit > LABEL_IPV6_EXPLICIT_NULL)) { 988 (limit > MPLS_LABEL_IPV6NULL)) {
859 RCU_INIT_POINTER(labels[LABEL_IPV6_EXPLICIT_NULL], rt2); 989 RCU_INIT_POINTER(labels[MPLS_LABEL_IPV6NULL], rt2);
860 rt2 = NULL; 990 rt2 = NULL;
861 } 991 }
862 992
863 if ((old_limit <= LABEL_IPV4_EXPLICIT_NULL) && 993 if ((old_limit <= MPLS_LABEL_IPV4NULL) &&
864 (limit > LABEL_IPV4_EXPLICIT_NULL)) { 994 (limit > MPLS_LABEL_IPV4NULL)) {
865 RCU_INIT_POINTER(labels[LABEL_IPV4_EXPLICIT_NULL], rt0); 995 RCU_INIT_POINTER(labels[MPLS_LABEL_IPV4NULL], rt0);
866 rt0 = NULL; 996 rt0 = NULL;
867 } 997 }
868 998
@@ -912,7 +1042,7 @@ static int mpls_platform_labels(struct ctl_table *table, int write,
912 return ret; 1042 return ret;
913} 1043}
914 1044
915static struct ctl_table mpls_table[] = { 1045static const struct ctl_table mpls_table[] = {
916 { 1046 {
917 .procname = "platform_labels", 1047 .procname = "platform_labels",
918 .data = NULL, 1048 .data = NULL,