diff options
author | Robert Shearman <rshearma@brocade.com> | 2015-04-22 06:14:37 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-04-22 14:24:54 -0400 |
commit | 03c57747a7020a28a200e7e920fb48ecdc9b0fb8 (patch) | |
tree | 012bd8131aa759a62667ea02fe87fa3328b16d65 | |
parent | 909d9faae2a447110aa061070145297fffe129cb (diff) |
mpls: Per-device MPLS state
Add per-device MPLS state to supported interfaces. Use the presence of
this state in mpls_route_add to determine that this is a supported
interface.
Use the presence of mpls_dev to drop packets that arrived on an
unsupported interface - previously they were allowed through.
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>
-rw-r--r-- | include/linux/netdevice.h | 4 | ||||
-rw-r--r-- | net/mpls/af_mpls.c | 50 | ||||
-rw-r--r-- | net/mpls/internal.h | 3 |
3 files changed, 55 insertions, 2 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index bcbde799ec69..dae106a3a998 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -60,6 +60,7 @@ struct phy_device; | |||
60 | struct wireless_dev; | 60 | struct wireless_dev; |
61 | /* 802.15.4 specific */ | 61 | /* 802.15.4 specific */ |
62 | struct wpan_dev; | 62 | struct wpan_dev; |
63 | struct mpls_dev; | ||
63 | 64 | ||
64 | void netdev_set_default_ethtool_ops(struct net_device *dev, | 65 | void netdev_set_default_ethtool_ops(struct net_device *dev, |
65 | const struct ethtool_ops *ops); | 66 | const struct ethtool_ops *ops); |
@@ -1627,6 +1628,9 @@ struct net_device { | |||
1627 | void *ax25_ptr; | 1628 | void *ax25_ptr; |
1628 | struct wireless_dev *ieee80211_ptr; | 1629 | struct wireless_dev *ieee80211_ptr; |
1629 | struct wpan_dev *ieee802154_ptr; | 1630 | struct wpan_dev *ieee802154_ptr; |
1631 | #if IS_ENABLED(CONFIG_MPLS_ROUTING) | ||
1632 | struct mpls_dev __rcu *mpls_ptr; | ||
1633 | #endif | ||
1630 | 1634 | ||
1631 | /* | 1635 | /* |
1632 | * Cache lines mostly used on receive path (including eth_type_trans()) | 1636 | * Cache lines mostly used on receive path (including eth_type_trans()) |
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index db8a2ea6d4de..ad45017eed99 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 | ||
56 | static inline struct mpls_dev *mpls_dev_get(const struct net_device *dev) | ||
57 | { | ||
58 | return rcu_dereference_rtnl(dev->mpls_ptr); | ||
59 | } | ||
60 | |||
56 | static bool mpls_output_possible(const struct net_device *dev) | 61 | static 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) | ||
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,27 @@ errout: | |||
428 | return err; | 438 | return err; |
429 | } | 439 | } |
430 | 440 | ||
441 | static struct mpls_dev *mpls_add_dev(struct net_device *dev) | ||
442 | { | ||
443 | struct mpls_dev *mdev; | ||
444 | int err = -ENOMEM; | ||
445 | |||
446 | ASSERT_RTNL(); | ||
447 | |||
448 | mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); | ||
449 | if (!mdev) | ||
450 | return ERR_PTR(err); | ||
451 | |||
452 | rcu_assign_pointer(dev->mpls_ptr, mdev); | ||
453 | |||
454 | return mdev; | ||
455 | } | ||
456 | |||
431 | static void mpls_ifdown(struct net_device *dev) | 457 | static void mpls_ifdown(struct net_device *dev) |
432 | { | 458 | { |
433 | struct mpls_route __rcu **platform_label; | 459 | struct mpls_route __rcu **platform_label; |
434 | struct net *net = dev_net(dev); | 460 | struct net *net = dev_net(dev); |
461 | struct mpls_dev *mdev; | ||
435 | unsigned index; | 462 | unsigned index; |
436 | 463 | ||
437 | platform_label = rtnl_dereference(net->mpls.platform_label); | 464 | platform_label = rtnl_dereference(net->mpls.platform_label); |
@@ -443,14 +470,33 @@ static void mpls_ifdown(struct net_device *dev) | |||
443 | continue; | 470 | continue; |
444 | rt->rt_dev = NULL; | 471 | rt->rt_dev = NULL; |
445 | } | 472 | } |
473 | |||
474 | mdev = mpls_dev_get(dev); | ||
475 | if (!mdev) | ||
476 | return; | ||
477 | |||
478 | RCU_INIT_POINTER(dev->mpls_ptr, NULL); | ||
479 | |||
480 | kfree(mdev); | ||
446 | } | 481 | } |
447 | 482 | ||
448 | static int mpls_dev_notify(struct notifier_block *this, unsigned long event, | 483 | static int mpls_dev_notify(struct notifier_block *this, unsigned long event, |
449 | void *ptr) | 484 | void *ptr) |
450 | { | 485 | { |
451 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | 486 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
487 | struct mpls_dev *mdev; | ||
452 | 488 | ||
453 | switch(event) { | 489 | switch(event) { |
490 | case NETDEV_REGISTER: | ||
491 | /* For now just support ethernet devices */ | ||
492 | if ((dev->type == ARPHRD_ETHER) || | ||
493 | (dev->type == ARPHRD_LOOPBACK)) { | ||
494 | mdev = mpls_add_dev(dev); | ||
495 | if (IS_ERR(mdev)) | ||
496 | return notifier_from_errno(PTR_ERR(mdev)); | ||
497 | } | ||
498 | break; | ||
499 | |||
454 | case NETDEV_UNREGISTER: | 500 | case NETDEV_UNREGISTER: |
455 | mpls_ifdown(dev); | 501 | mpls_ifdown(dev); |
456 | break; | 502 | break; |
diff --git a/net/mpls/internal.h b/net/mpls/internal.h index fb6de92052c4..8090cb3099b4 100644 --- a/net/mpls/internal.h +++ b/net/mpls/internal.h | |||
@@ -22,6 +22,9 @@ struct mpls_entry_decoded { | |||
22 | u8 bos; | 22 | u8 bos; |
23 | }; | 23 | }; |
24 | 24 | ||
25 | struct mpls_dev { | ||
26 | }; | ||
27 | |||
25 | struct sk_buff; | 28 | struct sk_buff; |
26 | 29 | ||
27 | static inline struct mpls_shim_hdr *mpls_hdr(const struct sk_buff *skb) | 30 | static inline struct mpls_shim_hdr *mpls_hdr(const struct sk_buff *skb) |