vlan_sync.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. package bridge
  2. import (
  3. "fmt"
  4. "os/exec"
  5. "strconv"
  6. )
  7. type vlanMember struct {
  8. Device string
  9. VID int
  10. Untagged bool
  11. Self bool
  12. }
  13. func members(v *BridgeVLAN) map[vlanMember]bool {
  14. result := map[vlanMember]bool{}
  15. if v == nil || v.Disabled {
  16. return result
  17. }
  18. for _, vid := range parseVLANRange(v.VlanIDs) {
  19. for _, dev := range v.Tagged {
  20. result[vlanMember{dev, vid, false, dev == v.Bridge}] = true
  21. }
  22. for _, dev := range v.Untagged {
  23. result[vlanMember{dev, vid, true, dev == v.Bridge}] = true
  24. }
  25. }
  26. return result
  27. }
  28. func changeMember(action string, m vlanMember) error {
  29. args := []string{"vlan", action, "dev", m.Device, "vid", strconv.Itoa(m.VID)}
  30. if m.Self {
  31. args = append(args, "self")
  32. }
  33. if action == "add" && m.Untagged {
  34. args = append(args, "untagged")
  35. }
  36. out, err := exec.Command("bridge", args...).CombinedOutput()
  37. if err != nil {
  38. return fmt.Errorf("bridge VLAN %v failed: %s: %w", args, out, err)
  39. }
  40. return nil
  41. }
  42. func syncMembers(old, next *BridgeVLAN) error {
  43. before, after := members(old), members(next)
  44. var removed, added []vlanMember
  45. rollback := func() {
  46. for _, m := range added {
  47. _ = changeMember("del", m)
  48. }
  49. for _, m := range removed {
  50. _ = changeMember("add", m)
  51. }
  52. }
  53. for m := range before {
  54. if !after[m] {
  55. if err := changeMember("del", m); err != nil {
  56. rollback()
  57. return err
  58. }
  59. removed = append(removed, m)
  60. }
  61. }
  62. for m := range after {
  63. if !before[m] {
  64. if err := changeMember("add", m); err != nil {
  65. rollback()
  66. return err
  67. }
  68. added = append(added, m)
  69. }
  70. }
  71. return nil
  72. }