aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_vlan.c
diff options
context:
space:
mode:
authorVlad Yasevich <vyasevich@gmail.com>2014-10-03 11:29:18 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-05 21:21:37 -0400
commit5be5a2df40f005ea7fb7e280e87bbbcfcf1c2fc0 (patch)
tree6aa782488f47684f803657acca74aa42b1303e59 /net/bridge/br_vlan.c
parent3df6bf45ec008942f16f1814123c4bdebcf50741 (diff)
bridge: Add filtering support for default_pvid
Currently when vlan filtering is turned on on the bridge, the bridge will drop all traffic untill the user configures the filter. This isn't very nice for ports that don't care about vlans and just want untagged traffic. A concept of a default_pvid was recently introduced. This patch adds filtering support for default_pvid. Now, ports that don't care about vlans and don't define there own filter will belong to the VLAN of the default_pvid and continue to receive untagged traffic. This filtering can be disabled by setting default_pvid to 0. Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_vlan.c')
-rw-r--r--net/bridge/br_vlan.c118
1 files changed, 115 insertions, 3 deletions
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index e11c9932e706..150048fb99b0 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -499,12 +499,110 @@ err_filt:
499 goto unlock; 499 goto unlock;
500} 500}
501 501
502static bool vlan_default_pvid(struct net_port_vlans *pv, u16 vid)
503{
504 return pv && vid == pv->pvid && test_bit(vid, pv->untagged_bitmap);
505}
506
507static void br_vlan_disable_default_pvid(struct net_bridge *br)
508{
509 struct net_bridge_port *p;
510 u16 pvid = br->default_pvid;
511
512 /* Disable default_pvid on all ports where it is still
513 * configured.
514 */
515 if (vlan_default_pvid(br_get_vlan_info(br), pvid))
516 br_vlan_delete(br, pvid);
517
518 list_for_each_entry(p, &br->port_list, list) {
519 if (vlan_default_pvid(nbp_get_vlan_info(p), pvid))
520 nbp_vlan_delete(p, pvid);
521 }
522
523 br->default_pvid = 0;
524}
525
526static int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid)
527{
528 struct net_bridge_port *p;
529 u16 old_pvid;
530 int err = 0;
531 unsigned long *changed;
532
533 changed = kcalloc(BITS_TO_LONGS(BR_MAX_PORTS), sizeof(unsigned long),
534 GFP_KERNEL);
535 if (!changed)
536 return -ENOMEM;
537
538 old_pvid = br->default_pvid;
539
540 /* Update default_pvid config only if we do not conflict with
541 * user configuration.
542 */
543 if ((!old_pvid || vlan_default_pvid(br_get_vlan_info(br), old_pvid)) &&
544 !br_vlan_find(br, pvid)) {
545 err = br_vlan_add(br, pvid,
546 BRIDGE_VLAN_INFO_PVID |
547 BRIDGE_VLAN_INFO_UNTAGGED);
548 if (err)
549 goto out;
550 br_vlan_delete(br, old_pvid);
551 set_bit(0, changed);
552 }
553
554 list_for_each_entry(p, &br->port_list, list) {
555 /* Update default_pvid config only if we do not conflict with
556 * user configuration.
557 */
558 if ((old_pvid &&
559 !vlan_default_pvid(nbp_get_vlan_info(p), old_pvid)) ||
560 nbp_vlan_find(p, pvid))
561 continue;
562
563 err = nbp_vlan_add(p, pvid,
564 BRIDGE_VLAN_INFO_PVID |
565 BRIDGE_VLAN_INFO_UNTAGGED);
566 if (err)
567 goto err_port;
568 nbp_vlan_delete(p, old_pvid);
569 set_bit(p->port_no, changed);
570 }
571
572 br->default_pvid = pvid;
573
574out:
575 kfree(changed);
576 return err;
577
578err_port:
579 list_for_each_entry_continue_reverse(p, &br->port_list, list) {
580 if (!test_bit(p->port_no, changed))
581 continue;
582
583 if (old_pvid)
584 nbp_vlan_add(p, old_pvid,
585 BRIDGE_VLAN_INFO_PVID |
586 BRIDGE_VLAN_INFO_UNTAGGED);
587 nbp_vlan_delete(p, pvid);
588 }
589
590 if (test_bit(0, changed)) {
591 if (old_pvid)
592 br_vlan_add(br, old_pvid,
593 BRIDGE_VLAN_INFO_PVID |
594 BRIDGE_VLAN_INFO_UNTAGGED);
595 br_vlan_delete(br, pvid);
596 }
597 goto out;
598}
599
502int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val) 600int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val)
503{ 601{
504 u16 pvid = val; 602 u16 pvid = val;
505 int err = 0; 603 int err = 0;
506 604
507 if (!val || val >= VLAN_VID_MASK) 605 if (val >= VLAN_VID_MASK)
508 return -EINVAL; 606 return -EINVAL;
509 607
510 if (!rtnl_trylock()) 608 if (!rtnl_trylock())
@@ -520,17 +618,22 @@ int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val)
520 goto unlock; 618 goto unlock;
521 } 619 }
522 620
523 br->default_pvid = pvid; 621 if (!pvid)
622 br_vlan_disable_default_pvid(br);
623 else
624 err = __br_vlan_set_default_pvid(br, pvid);
524 625
525unlock: 626unlock:
526 rtnl_unlock(); 627 rtnl_unlock();
527 return err; 628 return err;
528} 629}
529 630
530void br_vlan_init(struct net_bridge *br) 631int br_vlan_init(struct net_bridge *br)
531{ 632{
532 br->vlan_proto = htons(ETH_P_8021Q); 633 br->vlan_proto = htons(ETH_P_8021Q);
533 br->default_pvid = 1; 634 br->default_pvid = 1;
635 return br_vlan_add(br, 1,
636 BRIDGE_VLAN_INFO_PVID | BRIDGE_VLAN_INFO_UNTAGGED);
534} 637}
535 638
536/* Must be protected by RTNL. 639/* Must be protected by RTNL.
@@ -622,3 +725,12 @@ out:
622 rcu_read_unlock(); 725 rcu_read_unlock();
623 return found; 726 return found;
624} 727}
728
729int nbp_vlan_init(struct net_bridge_port *p)
730{
731 return p->br->default_pvid ?
732 nbp_vlan_add(p, p->br->default_pvid,
733 BRIDGE_VLAN_INFO_PVID |
734 BRIDGE_VLAN_INFO_UNTAGGED) :
735 0;
736}