| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475 |
- package bridge
- import (
- "fmt"
- "os/exec"
- "strconv"
- )
- type vlanMember struct {
- Device string
- VID int
- Untagged bool
- Self bool
- }
- func members(v *BridgeVLAN) map[vlanMember]bool {
- result := map[vlanMember]bool{}
- if v == nil || v.Disabled {
- return result
- }
- for _, vid := range parseVLANRange(v.VlanIDs) {
- for _, dev := range v.Tagged {
- result[vlanMember{dev, vid, false, dev == v.Bridge}] = true
- }
- for _, dev := range v.Untagged {
- result[vlanMember{dev, vid, true, dev == v.Bridge}] = true
- }
- }
- return result
- }
- func changeMember(action string, m vlanMember) error {
- args := []string{"vlan", action, "dev", m.Device, "vid", strconv.Itoa(m.VID)}
- if m.Self {
- args = append(args, "self")
- }
- if action == "add" && m.Untagged {
- args = append(args, "untagged")
- }
- out, err := exec.Command("bridge", args...).CombinedOutput()
- if err != nil {
- return fmt.Errorf("bridge VLAN %v failed: %s: %w", args, out, err)
- }
- return nil
- }
- func syncMembers(old, next *BridgeVLAN) error {
- before, after := members(old), members(next)
- var removed, added []vlanMember
- rollback := func() {
- for _, m := range added {
- _ = changeMember("del", m)
- }
- for _, m := range removed {
- _ = changeMember("add", m)
- }
- }
- for m := range before {
- if !after[m] {
- if err := changeMember("del", m); err != nil {
- rollback()
- return err
- }
- removed = append(removed, m)
- }
- }
- for m := range after {
- if !before[m] {
- if err := changeMember("add", m); err != nil {
- rollback()
- return err
- }
- added = append(added, m)
- }
- }
- return nil
- }
|