diff options
-rw-r--r-- | net/bridge/br_device.c | 8 | ||||
-rw-r--r-- | net/bridge/br_if.c | 3 | ||||
-rw-r--r-- | net/bridge/br_private.h | 14 | ||||
-rw-r--r-- | net/bridge/br_vlan.c | 118 |
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: | |||
88 | static int br_dev_init(struct net_device *dev) | 88 | static 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 | ||
99 | static int br_dev_open(struct net_device *dev) | 104 | static 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); | |||
605 | void br_recalculate_fwd_mask(struct net_bridge *br); | 605 | void br_recalculate_fwd_mask(struct net_bridge *br); |
606 | int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val); | 606 | int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val); |
607 | int br_vlan_set_proto(struct net_bridge *br, unsigned long val); | 607 | int br_vlan_set_proto(struct net_bridge *br, unsigned long val); |
608 | void br_vlan_init(struct net_bridge *br); | 608 | int br_vlan_init(struct net_bridge *br); |
609 | int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val); | 609 | int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val); |
610 | int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags); | 610 | int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags); |
611 | int nbp_vlan_delete(struct net_bridge_port *port, u16 vid); | 611 | int nbp_vlan_delete(struct net_bridge_port *port, u16 vid); |
612 | void nbp_vlan_flush(struct net_bridge_port *port); | 612 | void nbp_vlan_flush(struct net_bridge_port *port); |
613 | bool nbp_vlan_find(struct net_bridge_port *port, u16 vid); | 613 | bool nbp_vlan_find(struct net_bridge_port *port, u16 vid); |
614 | int nbp_vlan_init(struct net_bridge_port *port); | ||
614 | 615 | ||
615 | static inline struct net_port_vlans *br_get_vlan_info( | 616 | static 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 | ||
644 | static inline u16 br_get_pvid(const struct net_port_vlans *v) | 645 | static 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 | ||
706 | static inline void br_vlan_init(struct net_bridge *br) | 710 | static inline int br_vlan_init(struct net_bridge *br) |
707 | { | 711 | { |
712 | return 0; | ||
708 | } | 713 | } |
709 | 714 | ||
710 | static inline int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags) | 715 | static 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 | ||
745 | static inline int nbp_vlan_init(struct net_bridge_port *port) | ||
746 | { | ||
747 | return 0; | ||
748 | } | ||
749 | |||
740 | static inline u16 br_vlan_get_tag(const struct sk_buff *skb, u16 *tag) | 750 | static 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 | ||
502 | static 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 | |||
507 | static 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 | |||
526 | static 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 | |||
574 | out: | ||
575 | kfree(changed); | ||
576 | return err; | ||
577 | |||
578 | err_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 | |||
502 | int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val) | 600 | int 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 | ||
525 | unlock: | 626 | unlock: |
526 | rtnl_unlock(); | 627 | rtnl_unlock(); |
527 | return err; | 628 | return err; |
528 | } | 629 | } |
529 | 630 | ||
530 | void br_vlan_init(struct net_bridge *br) | 631 | int 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 | |||
729 | int 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 | } | ||