aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
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
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')
-rw-r--r--net/bridge/br_device.c8
-rw-r--r--net/bridge/br_if.c3
-rw-r--r--net/bridge/br_private.h14
-rw-r--r--net/bridge/br_vlan.c118
4 files changed, 136 insertions, 7 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 659cac15c0df..ffd379db5938 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -88,12 +88,17 @@ out:
88static int br_dev_init(struct net_device *dev) 88static int br_dev_init(struct net_device *dev)
89{ 89{
90 struct net_bridge *br = netdev_priv(dev); 90 struct net_bridge *br = netdev_priv(dev);
91 int err;
91 92
92 br->stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); 93 br->stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
93 if (!br->stats) 94 if (!br->stats)
94 return -ENOMEM; 95 return -ENOMEM;
95 96
96 return 0; 97 err = br_vlan_init(br);
98 if (err)
99 free_percpu(br->stats);
100
101 return err;
97} 102}
98 103
99static int br_dev_open(struct net_device *dev) 104static int br_dev_open(struct net_device *dev)
@@ -389,5 +394,4 @@ void br_dev_setup(struct net_device *dev)
389 br_netfilter_rtable_init(br); 394 br_netfilter_rtable_init(br);
390 br_stp_timer_init(br); 395 br_stp_timer_init(br);
391 br_multicast_init(br); 396 br_multicast_init(br);
392 br_vlan_init(br);
393} 397}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 7b7289ca2992..ed307db7a12b 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -500,6 +500,9 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
500 if (br_fdb_insert(br, p, dev->dev_addr, 0)) 500 if (br_fdb_insert(br, p, dev->dev_addr, 0))
501 netdev_err(dev, "failed insert local address bridge forwarding table\n"); 501 netdev_err(dev, "failed insert local address bridge forwarding table\n");
502 502
503 if (nbp_vlan_init(p))
504 netdev_err(dev, "failed to initialize vlan filtering on this port\n");
505
503 spin_lock_bh(&br->lock); 506 spin_lock_bh(&br->lock);
504 changed_addr = br_stp_recalculate_bridge_id(br); 507 changed_addr = br_stp_recalculate_bridge_id(br);
505 508
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index f671561b3053..d8cbaa694227 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -605,12 +605,13 @@ bool br_vlan_find(struct net_bridge *br, u16 vid);
605void br_recalculate_fwd_mask(struct net_bridge *br); 605void br_recalculate_fwd_mask(struct net_bridge *br);
606int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val); 606int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val);
607int br_vlan_set_proto(struct net_bridge *br, unsigned long val); 607int br_vlan_set_proto(struct net_bridge *br, unsigned long val);
608void br_vlan_init(struct net_bridge *br); 608int br_vlan_init(struct net_bridge *br);
609int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val); 609int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val);
610int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags); 610int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags);
611int nbp_vlan_delete(struct net_bridge_port *port, u16 vid); 611int nbp_vlan_delete(struct net_bridge_port *port, u16 vid);
612void nbp_vlan_flush(struct net_bridge_port *port); 612void nbp_vlan_flush(struct net_bridge_port *port);
613bool nbp_vlan_find(struct net_bridge_port *port, u16 vid); 613bool nbp_vlan_find(struct net_bridge_port *port, u16 vid);
614int nbp_vlan_init(struct net_bridge_port *port);
614 615
615static inline struct net_port_vlans *br_get_vlan_info( 616static inline struct net_port_vlans *br_get_vlan_info(
616 const struct net_bridge *br) 617 const struct net_bridge *br)
@@ -643,6 +644,9 @@ static inline int br_vlan_get_tag(const struct sk_buff *skb, u16 *vid)
643 644
644static inline u16 br_get_pvid(const struct net_port_vlans *v) 645static inline u16 br_get_pvid(const struct net_port_vlans *v)
645{ 646{
647 if (!v)
648 return 0;
649
646 smp_rmb(); 650 smp_rmb();
647 return v->pvid; 651 return v->pvid;
648} 652}
@@ -703,8 +707,9 @@ static inline void br_recalculate_fwd_mask(struct net_bridge *br)
703{ 707{
704} 708}
705 709
706static inline void br_vlan_init(struct net_bridge *br) 710static inline int br_vlan_init(struct net_bridge *br)
707{ 711{
712 return 0;
708} 713}
709 714
710static inline int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags) 715static inline int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags)
@@ -737,6 +742,11 @@ static inline bool nbp_vlan_find(struct net_bridge_port *port, u16 vid)
737 return false; 742 return false;
738} 743}
739 744
745static inline int nbp_vlan_init(struct net_bridge_port *port)
746{
747 return 0;
748}
749
740static inline u16 br_vlan_get_tag(const struct sk_buff *skb, u16 *tag) 750static inline u16 br_vlan_get_tag(const struct sk_buff *skb, u16 *tag)
741{ 751{
742 return 0; 752 return 0;
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}