Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Robert Shearman and committed by
David S. Miller
37bde799 03c57747

+78 -2
+9
Documentation/networking/mpls-sysctl.txt
··· 18 18 19 19 Possible values: 0 - 1048575 20 20 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
+66 -2
net/mpls/af_mpls.c
··· 150 150 /* Careful this entire function runs inside of an rcu critical section */ 151 151 152 152 mdev = mpls_dev_get(dev); 153 - if (!mdev) 153 + if (!mdev || !mdev->input_enabled) 154 154 goto drop; 155 155 156 156 if (skb->pkt_type != PACKET_HOST) ··· 438 438 return err; 439 439 } 440 440 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 + 441 495 static struct mpls_dev *mpls_add_dev(struct net_device *dev) 442 496 { 443 497 struct mpls_dev *mdev; ··· 503 449 if (!mdev) 504 450 return ERR_PTR(err); 505 451 452 + err = mpls_dev_sysctl_register(dev, mdev); 453 + if (err) 454 + goto free; 455 + 506 456 rcu_assign_pointer(dev->mpls_ptr, mdev); 507 457 508 458 return mdev; 459 + 460 + free: 461 + kfree(mdev); 462 + return ERR_PTR(err); 509 463 } 510 464 511 465 static void mpls_ifdown(struct net_device *dev) ··· 536 474 mdev = mpls_dev_get(dev); 537 475 if (!mdev) 538 476 return; 477 + 478 + mpls_dev_sysctl_unregister(mdev); 539 479 540 480 RCU_INIT_POINTER(dev->mpls_ptr, NULL); 541 481 ··· 1022 958 return ret; 1023 959 } 1024 960 1025 - static struct ctl_table mpls_table[] = { 961 + static const struct ctl_table mpls_table[] = { 1026 962 { 1027 963 .procname = "platform_labels", 1028 964 .data = NULL,
+3
net/mpls/internal.h
··· 23 23 }; 24 24 25 25 struct mpls_dev { 26 + int input_enabled; 27 + 28 + struct ctl_table_header *sysctl; 26 29 }; 27 30 28 31 struct sk_buff;