aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorRobert Shearman <rshearma@brocade.com>2015-04-22 06:14:38 -0400
committerDavid S. Miller <davem@davemloft.net>2015-04-22 14:24:54 -0400
commit37bde79979c3862c79294c62ddcef7efc477e4bf (patch)
treea2268a0a600ed3eb1e33df0f43bbd3c72c5e30e0 /net
parent03c57747a7020a28a200e7e920fb48ecdc9b0fb8 (diff)
mpls: Per-device enabling of packet input
An MPLS network is a single trust domain where the edges must be in control of what labels make their way into the core. The simplest way of ensuring this is for the edge device to always impose the labels, and not allow forward labeled traffic from untrusted neighbours. This is achieved by allowing a per-device configuration of whether MPLS traffic input from that interface should be processed or not. To be secure by default, the default state is changed to MPLS being disabled on all interfaces unless explicitly enabled and no global option is provided to change the default. Whilst this differs from other protocols (e.g. IPv6), network operators are used to explicitly enabling MPLS forwarding on interfaces, and with the number of links to the MPLS core typically fairly low this doesn't present too much of a burden on operators. Cc: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Robert Shearman <rshearma@brocade.com> Reviewed-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/mpls/af_mpls.c68
-rw-r--r--net/mpls/internal.h3
2 files changed, 69 insertions, 2 deletions
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index ad45017eed99..9fdd94cba83e 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -150,7 +150,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
150 /* Careful this entire function runs inside of an rcu critical section */ 150 /* Careful this entire function runs inside of an rcu critical section */
151 151
152 mdev = mpls_dev_get(dev); 152 mdev = mpls_dev_get(dev);
153 if (!mdev) 153 if (!mdev || !mdev->input_enabled)
154 goto drop; 154 goto drop;
155 155
156 if (skb->pkt_type != PACKET_HOST) 156 if (skb->pkt_type != PACKET_HOST)
@@ -438,6 +438,60 @@ errout:
438 return err; 438 return err;
439} 439}
440 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
441static struct mpls_dev *mpls_add_dev(struct net_device *dev) 495static struct mpls_dev *mpls_add_dev(struct net_device *dev)
442{ 496{
443 struct mpls_dev *mdev; 497 struct mpls_dev *mdev;
@@ -449,9 +503,17 @@ static struct mpls_dev *mpls_add_dev(struct net_device *dev)
449 if (!mdev) 503 if (!mdev)
450 return ERR_PTR(err); 504 return ERR_PTR(err);
451 505
506 err = mpls_dev_sysctl_register(dev, mdev);
507 if (err)
508 goto free;
509
452 rcu_assign_pointer(dev->mpls_ptr, mdev); 510 rcu_assign_pointer(dev->mpls_ptr, mdev);
453 511
454 return mdev; 512 return mdev;
513
514free:
515 kfree(mdev);
516 return ERR_PTR(err);
455} 517}
456 518
457static void mpls_ifdown(struct net_device *dev) 519static void mpls_ifdown(struct net_device *dev)
@@ -475,6 +537,8 @@ static void mpls_ifdown(struct net_device *dev)
475 if (!mdev) 537 if (!mdev)
476 return; 538 return;
477 539
540 mpls_dev_sysctl_unregister(mdev);
541
478 RCU_INIT_POINTER(dev->mpls_ptr, NULL); 542 RCU_INIT_POINTER(dev->mpls_ptr, NULL);
479 543
480 kfree(mdev); 544 kfree(mdev);
@@ -958,7 +1022,7 @@ static int mpls_platform_labels(struct ctl_table *table, int write,
958 return ret; 1022 return ret;
959} 1023}
960 1024
961static struct ctl_table mpls_table[] = { 1025static const struct ctl_table mpls_table[] = {
962 { 1026 {
963 .procname = "platform_labels", 1027 .procname = "platform_labels",
964 .data = NULL, 1028 .data = NULL,
diff --git a/net/mpls/internal.h b/net/mpls/internal.h
index 8090cb3099b4..693877d69606 100644
--- a/net/mpls/internal.h
+++ b/net/mpls/internal.h
@@ -23,6 +23,9 @@ struct mpls_entry_decoded {
23}; 23};
24 24
25struct mpls_dev { 25struct mpls_dev {
26 int input_enabled;
27
28 struct ctl_table_header *sysctl;
26}; 29};
27 30
28struct sk_buff; 31struct sk_buff;