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.c125
1 files changed, 122 insertions, 3 deletions
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index db8a2ea6d4de..954810c76a86 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,14 +532,35 @@ 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(mdev);
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;
@@ -536,6 +646,15 @@ int nla_get_labels(const struct nlattr *nla,
536 if ((dec.bos != bos) || dec.ttl || dec.tc) 646 if ((dec.bos != bos) || dec.ttl || dec.tc)
537 return -EINVAL; 647 return -EINVAL;
538 648
649 switch (dec.label) {
650 case LABEL_IMPLICIT_NULL:
651 /* RFC3032: This is a label that an LSR may
652 * assign and distribute, but which never
653 * actually appears in the encapsulation.
654 */
655 return -EINVAL;
656 }
657
539 label[i] = dec.label; 658 label[i] = dec.label;
540 } 659 }
541 *labels = nla_labels; 660 *labels = nla_labels;
@@ -912,7 +1031,7 @@ static int mpls_platform_labels(struct ctl_table *table, int write,
912 return ret; 1031 return ret;
913} 1032}
914 1033
915static struct ctl_table mpls_table[] = { 1034static const struct ctl_table mpls_table[] = {
916 { 1035 {
917 .procname = "platform_labels", 1036 .procname = "platform_labels",
918 .data = NULL, 1037 .data = NULL,