aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2009-11-25 02:54:54 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-26 19:00:36 -0500
commit5e7565930524410f097f5b04f8aba663089a6ffc (patch)
tree7575fb4b06fdad1e2e9796e0dc99ca011e59980e
parentcc83f6d6922018a1b762f67af539867a6b05398e (diff)
vlan: support "loose binding" to the underlying network device
Currently the UP/DOWN state of VLANs is synchronized to the state of the underlying device, meaning all VLANs are set down once the underlying device is set down. This causes all routes to the VLAN devices to vanish. Add a flag to specify a "loose binding" mode, in which only the operstate is transfered, but the VLAN device state is independant. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/if_vlan.h1
-rw-r--r--net/8021q/vlan.c9
-rw-r--r--net/8021q/vlan_dev.c6
-rw-r--r--net/8021q/vlan_netlink.c3
4 files changed, 14 insertions, 5 deletions
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 153f6b9e722c..3d870fda8c4f 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -339,6 +339,7 @@ enum vlan_ioctl_cmds {
339enum vlan_flags { 339enum vlan_flags {
340 VLAN_FLAG_REORDER_HDR = 0x1, 340 VLAN_FLAG_REORDER_HDR = 0x1,
341 VLAN_FLAG_GVRP = 0x2, 341 VLAN_FLAG_GVRP = 0x2,
342 VLAN_FLAG_LOOSE_BINDING = 0x4,
342}; 343};
343 344
344enum vlan_name_types { 345enum vlan_name_types {
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 1483243edf14..225aa2fac0e3 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -431,6 +431,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
431 struct vlan_group *grp; 431 struct vlan_group *grp;
432 int i, flgs; 432 int i, flgs;
433 struct net_device *vlandev; 433 struct net_device *vlandev;
434 struct vlan_dev_info *vlan;
434 LIST_HEAD(list); 435 LIST_HEAD(list);
435 436
436 if (is_vlan_dev(dev)) 437 if (is_vlan_dev(dev))
@@ -507,7 +508,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
507 if (!(flgs & IFF_UP)) 508 if (!(flgs & IFF_UP))
508 continue; 509 continue;
509 510
510 dev_change_flags(vlandev, flgs & ~IFF_UP); 511 vlan = vlan_dev_info(vlandev);
512 if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
513 dev_change_flags(vlandev, flgs & ~IFF_UP);
511 vlan_transfer_operstate(dev, vlandev); 514 vlan_transfer_operstate(dev, vlandev);
512 } 515 }
513 break; 516 break;
@@ -523,7 +526,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
523 if (flgs & IFF_UP) 526 if (flgs & IFF_UP)
524 continue; 527 continue;
525 528
526 dev_change_flags(vlandev, flgs | IFF_UP); 529 vlan = vlan_dev_info(vlandev);
530 if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
531 dev_change_flags(vlandev, flgs | IFF_UP);
527 vlan_transfer_operstate(dev, vlandev); 532 vlan_transfer_operstate(dev, vlandev);
528 } 533 }
529 break; 534 break;
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index de0dc6bacbe8..b7889782047e 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -431,7 +431,8 @@ int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask)
431 struct vlan_dev_info *vlan = vlan_dev_info(dev); 431 struct vlan_dev_info *vlan = vlan_dev_info(dev);
432 u32 old_flags = vlan->flags; 432 u32 old_flags = vlan->flags;
433 433
434 if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP)) 434 if (mask & ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
435 VLAN_FLAG_LOOSE_BINDING))
435 return -EINVAL; 436 return -EINVAL;
436 437
437 vlan->flags = (old_flags & ~mask) | (flags & mask); 438 vlan->flags = (old_flags & ~mask) | (flags & mask);
@@ -456,7 +457,8 @@ static int vlan_dev_open(struct net_device *dev)
456 struct net_device *real_dev = vlan->real_dev; 457 struct net_device *real_dev = vlan->real_dev;
457 int err; 458 int err;
458 459
459 if (!(real_dev->flags & IFF_UP)) 460 if (!(real_dev->flags & IFF_UP) &&
461 !(vlan->flags & VLAN_FLAG_LOOSE_BINDING))
460 return -ENETDOWN; 462 return -ENETDOWN;
461 463
462 if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) { 464 if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) {
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
index 3c9cf6a8e7fb..ddc105734af7 100644
--- a/net/8021q/vlan_netlink.c
+++ b/net/8021q/vlan_netlink.c
@@ -60,7 +60,8 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])
60 if (data[IFLA_VLAN_FLAGS]) { 60 if (data[IFLA_VLAN_FLAGS]) {
61 flags = nla_data(data[IFLA_VLAN_FLAGS]); 61 flags = nla_data(data[IFLA_VLAN_FLAGS]);
62 if ((flags->flags & flags->mask) & 62 if ((flags->flags & flags->mask) &
63 ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP)) 63 ~(VLAN_FLAG_REORDER_HDR | VLAN_FLAG_GVRP |
64 VLAN_FLAG_LOOSE_BINDING))
64 return -EINVAL; 65 return -EINVAL;
65 } 66 }
66 67