123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- package netconf
- import (
- "io/ioutil"
- "os"
- "os/exec"
- "strings"
- "time"
- "github.com/Sirupsen/logrus"
- "github.com/vishvananda/netlink"
- )
- const (
- base = "/sys/class/net/"
- bondingMasters = "/sys/class/net/bonding_masters"
- )
- type Bonding struct {
- name string
- }
- func (b *Bonding) init() error {
- _, err := os.Stat(bondingMasters)
- if os.IsNotExist(err) {
- logrus.Info("Loading bonding kernel module")
- cmd := exec.Command("modprobe", "bonding")
- cmd.Stderr = os.Stderr
- cmd.Stdout = os.Stdin
- err = cmd.Run()
- if err != nil {
- for i := 0; i < 30; i++ {
- if _, err = os.Stat(bondingMasters); err == nil {
- break
- }
- time.Sleep(100 * time.Millisecond)
- }
- }
- }
- _, err = os.Stat(bondingMasters)
- return err
- }
- func contains(file, word string) (bool, error) {
- words, err := ioutil.ReadFile(file)
- if err != nil {
- return false, err
- }
- for _, s := range strings.Split(strings.TrimSpace(string(words)), " ") {
- if s == strings.TrimSpace(word) {
- return true, nil
- }
- }
- return false, nil
- }
- func (b *Bonding) linkDown() error {
- link, err := netlink.LinkByName(b.name)
- if err != nil {
- return err
- }
- return netlink.LinkSetDown(link)
- }
- func (b *Bonding) ListSlaves() ([]string, error) {
- file := base + b.name + "/bonding/slaves"
- words, err := ioutil.ReadFile(file)
- if err != nil {
- return nil, err
- }
- result := []string{}
- for _, s := range strings.Split(strings.TrimSpace(string(words)), " ") {
- if s != "" {
- result = append(result, s)
- }
- }
- return result, nil
- }
- func (b *Bonding) RemoveSlave(slave string) error {
- if ok, err := contains(base+b.name+"/bonding/slaves", slave); err != nil {
- return err
- } else if !ok {
- return nil
- }
- p := base + b.name + "/bonding/slaves"
- logrus.Infof("Removing slave %s from master %s", slave, b.name)
- return ioutil.WriteFile(p, []byte("-"+slave), 0644)
- }
- func (b *Bonding) AddSlave(slave string) error {
- if ok, err := contains(base+b.name+"/bonding/slaves", slave); err != nil {
- return err
- } else if ok {
- return nil
- }
- p := base + b.name + "/bonding/slaves"
- logrus.Infof("Adding slave %s to master %s", slave, b.name)
- return ioutil.WriteFile(p, []byte("+"+slave), 0644)
- }
- func (b *Bonding) Opt(key, value string) error {
- if key == "mode" {
- // Don't care about errors here
- b.linkDown()
- slaves, _ := b.ListSlaves()
- for _, slave := range slaves {
- b.RemoveSlave(slave)
- }
- }
- p := base + b.name + "/bonding/" + key
- if err := ioutil.WriteFile(p, []byte(value), 0644); err != nil {
- logrus.Errorf("Failed to set %s=%s on %s: %v", key, value, b.name, err)
- return err
- } else {
- logrus.Infof("Set %s=%s on %s", key, value, b.name)
- }
- return nil
- }
- func Bond(name string) (*Bonding, error) {
- b := &Bonding{name: name}
- if err := b.init(); err != nil {
- return nil, err
- }
- if ok, err := contains(bondingMasters, name); err != nil {
- return nil, err
- } else if ok {
- return b, nil
- }
- logrus.Infof("Creating bond %s", name)
- return b, ioutil.WriteFile(bondingMasters, []byte("+"+name), 0644)
- }
|