bonding.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. package netconf
  2. import (
  3. "io/ioutil"
  4. "os"
  5. "os/exec"
  6. "strings"
  7. "time"
  8. "github.com/Sirupsen/logrus"
  9. "github.com/vishvananda/netlink"
  10. )
  11. const (
  12. base = "/sys/class/net/"
  13. bondingMasters = "/sys/class/net/bonding_masters"
  14. )
  15. type Bonding struct {
  16. name string
  17. }
  18. func (b *Bonding) init() error {
  19. _, err := os.Stat(bondingMasters)
  20. if os.IsNotExist(err) {
  21. logrus.Info("Loading bonding kernel module")
  22. cmd := exec.Command("modprobe", "bonding")
  23. cmd.Stderr = os.Stderr
  24. cmd.Stdout = os.Stdin
  25. err = cmd.Run()
  26. if err != nil {
  27. for i := 0; i < 30; i++ {
  28. if _, err = os.Stat(bondingMasters); err == nil {
  29. break
  30. }
  31. time.Sleep(100 * time.Millisecond)
  32. }
  33. }
  34. }
  35. _, err = os.Stat(bondingMasters)
  36. return err
  37. }
  38. func contains(file, word string) (bool, error) {
  39. words, err := ioutil.ReadFile(file)
  40. if err != nil {
  41. return false, err
  42. }
  43. for _, s := range strings.Split(strings.TrimSpace(string(words)), " ") {
  44. if s == strings.TrimSpace(word) {
  45. return true, nil
  46. }
  47. }
  48. return false, nil
  49. }
  50. func (b *Bonding) linkDown() error {
  51. link, err := netlink.LinkByName(b.name)
  52. if err != nil {
  53. return err
  54. }
  55. return netlink.LinkSetDown(link)
  56. }
  57. func (b *Bonding) ListSlaves() ([]string, error) {
  58. file := base + b.name + "/bonding/slaves"
  59. words, err := ioutil.ReadFile(file)
  60. if err != nil {
  61. return nil, err
  62. }
  63. result := []string{}
  64. for _, s := range strings.Split(strings.TrimSpace(string(words)), " ") {
  65. if s != "" {
  66. result = append(result, s)
  67. }
  68. }
  69. return result, nil
  70. }
  71. func (b *Bonding) RemoveSlave(slave string) error {
  72. if ok, err := contains(base+b.name+"/bonding/slaves", slave); err != nil {
  73. return err
  74. } else if !ok {
  75. return nil
  76. }
  77. p := base + b.name + "/bonding/slaves"
  78. logrus.Infof("Removing slave %s from master %s", slave, b.name)
  79. return ioutil.WriteFile(p, []byte("-"+slave), 0644)
  80. }
  81. func (b *Bonding) AddSlave(slave string) error {
  82. if ok, err := contains(base+b.name+"/bonding/slaves", slave); err != nil {
  83. return err
  84. } else if ok {
  85. return nil
  86. }
  87. p := base + b.name + "/bonding/slaves"
  88. logrus.Infof("Adding slave %s to master %s", slave, b.name)
  89. return ioutil.WriteFile(p, []byte("+"+slave), 0644)
  90. }
  91. func (b *Bonding) Opt(key, value string) error {
  92. if key == "mode" {
  93. // Don't care about errors here
  94. b.linkDown()
  95. slaves, _ := b.ListSlaves()
  96. for _, slave := range slaves {
  97. b.RemoveSlave(slave)
  98. }
  99. }
  100. p := base + b.name + "/bonding/" + key
  101. if err := ioutil.WriteFile(p, []byte(value), 0644); err != nil {
  102. logrus.Errorf("Failed to set %s=%s on %s: %v", key, value, b.name, err)
  103. return err
  104. } else {
  105. logrus.Infof("Set %s=%s on %s", key, value, b.name)
  106. }
  107. return nil
  108. }
  109. func Bond(name string) (*Bonding, error) {
  110. b := &Bonding{name: name}
  111. if err := b.init(); err != nil {
  112. return nil, err
  113. }
  114. if ok, err := contains(bondingMasters, name); err != nil {
  115. return nil, err
  116. } else if ok {
  117. return b, nil
  118. }
  119. logrus.Infof("Creating bond %s", name)
  120. return b, ioutil.WriteFile(bondingMasters, []byte("+"+name), 0644)
  121. }