Skip to content

Commit 37bde79

Browse files
rshearmandavem330
authored andcommitted
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>
1 parent 03c5774 commit 37bde79

File tree

3 files changed

+78
-2
lines changed

3 files changed

+78
-2
lines changed

Documentation/networking/mpls-sysctl.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,12 @@ platform_labels - INTEGER
1818

1919
Possible values: 0 - 1048575
2020
Default: 0
21+
22+
conf/<interface>/input - BOOL
23+
Control whether packets can be input on this interface.
24+
25+
If disabled, packets will be discarded without further
26+
processing.
27+
28+
0 - disabled (default)
29+
not 0 - enabled

net/mpls/af_mpls.c

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
150150
/* Careful this entire function runs inside of an rcu critical section */
151151

152152
mdev = mpls_dev_get(dev);
153-
if (!mdev)
153+
if (!mdev || !mdev->input_enabled)
154154
goto drop;
155155

156156
if (skb->pkt_type != PACKET_HOST)
@@ -438,6 +438,60 @@ static int mpls_route_del(struct mpls_route_config *cfg)
438438
return err;
439439
}
440440

441+
#define MPLS_PERDEV_SYSCTL_OFFSET(field) \
442+
(&((struct mpls_dev *)0)->field)
443+
444+
static 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+
455+
static 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+
480+
free:
481+
kfree(table);
482+
out:
483+
return -ENOBUFS;
484+
}
485+
486+
static 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+
441495
static struct mpls_dev *mpls_add_dev(struct net_device *dev)
442496
{
443497
struct mpls_dev *mdev;
@@ -449,9 +503,17 @@ static struct mpls_dev *mpls_add_dev(struct net_device *dev)
449503
if (!mdev)
450504
return ERR_PTR(err);
451505

506+
err = mpls_dev_sysctl_register(dev, mdev);
507+
if (err)
508+
goto free;
509+
452510
rcu_assign_pointer(dev->mpls_ptr, mdev);
453511

454512
return mdev;
513+
514+
free:
515+
kfree(mdev);
516+
return ERR_PTR(err);
455517
}
456518

457519
static void mpls_ifdown(struct net_device *dev)
@@ -475,6 +537,8 @@ static void mpls_ifdown(struct net_device *dev)
475537
if (!mdev)
476538
return;
477539

540+
mpls_dev_sysctl_unregister(mdev);
541+
478542
RCU_INIT_POINTER(dev->mpls_ptr, NULL);
479543

480544
kfree(mdev);
@@ -958,7 +1022,7 @@ static int mpls_platform_labels(struct ctl_table *table, int write,
9581022
return ret;
9591023
}
9601024

961-
static struct ctl_table mpls_table[] = {
1025+
static const struct ctl_table mpls_table[] = {
9621026
{
9631027
.procname = "platform_labels",
9641028
.data = NULL,

net/mpls/internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ struct mpls_entry_decoded {
2323
};
2424

2525
struct mpls_dev {
26+
int input_enabled;
27+
28+
struct ctl_table_header *sysctl;
2629
};
2730

2831
struct sk_buff;

0 commit comments

Comments
 (0)