Commit 5e7565930524410f097f5b04f8aba663089a6ffc

Authored by Patrick McHardy
Committed by David S. Miller
1 parent cc83f6d692

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>

Showing 4 changed files with 14 additions and 5 deletions Side-by-side Diff

include/linux/if_vlan.h
... ... @@ -339,6 +339,7 @@
339 339 enum vlan_flags {
340 340 VLAN_FLAG_REORDER_HDR = 0x1,
341 341 VLAN_FLAG_GVRP = 0x2,
  342 + VLAN_FLAG_LOOSE_BINDING = 0x4,
342 343 };
343 344  
344 345 enum vlan_name_types {
... ... @@ -431,6 +431,7 @@
431 431 struct vlan_group *grp;
432 432 int i, flgs;
433 433 struct net_device *vlandev;
  434 + struct vlan_dev_info *vlan;
434 435 LIST_HEAD(list);
435 436  
436 437 if (is_vlan_dev(dev))
... ... @@ -507,7 +508,9 @@
507 508 if (!(flgs & IFF_UP))
508 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 514 vlan_transfer_operstate(dev, vlandev);
512 515 }
513 516 break;
... ... @@ -523,7 +526,9 @@
523 526 if (flgs & IFF_UP)
524 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 532 vlan_transfer_operstate(dev, vlandev);
528 533 }
529 534 break;
net/8021q/vlan_dev.c
... ... @@ -431,7 +431,8 @@
431 431 struct vlan_dev_info *vlan = vlan_dev_info(dev);
432 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 436 return -EINVAL;
436 437  
437 438 vlan->flags = (old_flags & ~mask) | (flags & mask);
... ... @@ -456,7 +457,8 @@
456 457 struct net_device *real_dev = vlan->real_dev;
457 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 462 return -ENETDOWN;
461 463  
462 464 if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) {
net/8021q/vlan_netlink.c
... ... @@ -60,7 +60,8 @@
60 60 if (data[IFLA_VLAN_FLAGS]) {
61 61 flags = nla_data(data[IFLA_VLAN_FLAGS]);
62 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 65 return -EINVAL;
65 66 }
66 67