From 99819829a422fd4abc2e6baba9adea24be40122f Mon Sep 17 00:00:00 2001 From: Martin/Geno Date: Wed, 10 Apr 2019 21:57:31 +0200 Subject: [PATCH] respondd batman support --- config-respondd_example.toml | 2 +- respond/daemon/batman.go | 89 ++++++++++++++++++++++++++++++++++++ respond/daemon/config.go | 5 +- respond/daemon/neighbours.go | 11 ++++- respond/daemon/nodeinfo.go | 43 +++++++++-------- respond/daemon/statistics.go | 2 +- 6 files changed, 128 insertions(+), 24 deletions(-) create mode 100644 respond/daemon/batman.go diff --git a/config-respondd_example.toml b/config-respondd_example.toml index 2c25c71e..4360e3bd 100644 --- a/config-respondd_example.toml +++ b/config-respondd_example.toml @@ -1,7 +1,7 @@ # how ofter the cache respond of a respondd request is calculated data_interval = "3m" -interfaces = [ "wlp4s0" ] +batman = "[::1]:33123" [[listen]] address = "ff02::2:1001" diff --git a/respond/daemon/batman.go b/respond/daemon/batman.go new file mode 100644 index 00000000..f20ca991 --- /dev/null +++ b/respond/daemon/batman.go @@ -0,0 +1,89 @@ +package respondd + +import ( + "strings" + "os/exec" + "net" + "regexp" + "strconv" + + "github.com/bdlm/log" + + "github.com/FreifunkBremen/yanic/data" +) + +type Batman struct { + Bridge string + Interfaces []string +} + +func NewBatman(iface string) *Batman { + out, err := exec.Command("batctl", "-m", iface, "if").Output() + if err != nil { + log.WithField("iface", iface).Error("not able to run batctl") + return nil + } + b := &Batman{Bridge: iface} + for _, line := range strings.Split(string(out), "\n") { + i := strings.Split(line,":")[0] + if i != "" { + b.Interfaces = append(b.Interfaces, i) + } + } + return b +} +func(b *Batman) Address(iface string) string { + i, err := net.InterfaceByName(iface) + if err != nil { + return "" + } + return i.HardwareAddr.String() +} +func(b *Batman) Neighbours() (map[string]data.BatadvNeighbours) { + out, err := exec.Command("batctl", "-m", b.Bridge, "o").Output() + if err != nil { + log.WithField("iface", b.Bridge).Error("not able to run batctl") + return nil + } + + lines := strings.Split(string(out), "\n") + neighbours := make(map[string]data.BatadvNeighbours) + + re := regexp.MustCompile(`([0-9a-f:]+)\s+(\d+\.\d+)s\s+\((\d+)\)\s+([0-9a-f:]+)\s+\[\s*([a-z0-9-]+)\]`) + + for _, i := range b.Interfaces { + mac := b.Address(i) + neighbour := data.BatadvNeighbours{ + Neighbours: make(map[string]data.BatmanLink), + } + + for _, line := range lines { + fields := re.FindStringSubmatch(line) + if len(fields) != 6 { + continue + } + if i == fields[5] && fields[1] == fields[4] { + lastseen, err := strconv.ParseFloat(fields[2], 64) + if err != nil { + log.WithField("value", fields[2]).Warnf("unable to parse lastseen: %s", err) + continue + } + + tq, err := strconv.Atoi(fields[3]) + if err != nil { + log.WithField("value", fields[3]).Warnf("unable to parse tq: %s", err) + continue + } + + nMAC := fields[1] + + neighbour.Neighbours[nMAC] = data.BatmanLink{ + Lastseen: lastseen, + Tq: tq, + } + } + } + neighbours[mac] = neighbour + } + return neighbours +} diff --git a/respond/daemon/config.go b/respond/daemon/config.go index 376a1d8a..42892098 100644 --- a/respond/daemon/config.go +++ b/respond/daemon/config.go @@ -19,8 +19,9 @@ type Daemon struct { Interface string `toml:"interface"` Port int `toml:"port"` } `toml:"listen"` - InterfacesBatman []string `toml:"interfaces_batman"` - Interfaces []string `toml:"interfaces"` + + Batman []string `toml:"batman"` + Babel string `toml:"babel"` dataByInterface map[string]*data.ResponseData diff --git a/respond/daemon/neighbours.go b/respond/daemon/neighbours.go index b9344b0f..a91f46a7 100644 --- a/respond/daemon/neighbours.go +++ b/respond/daemon/neighbours.go @@ -4,7 +4,14 @@ import ( "github.com/FreifunkBremen/yanic/data" ) -func (d *Daemon) updateNeighbours(iface string, data *data.ResponseData) { +func (d *Daemon) updateNeighbours(iface string, resp *data.ResponseData) { _, nodeID := d.getAnswer(iface) - data.Neighbours.NodeID = nodeID + resp.Neighbours.NodeID = nodeID + resp.Neighbours.Batadv = make(map[string]data.BatadvNeighbours) + for _, bface := range d.Batman { + b := NewBatman(bface) + for bfaceAddr, n := range b.Neighbours() { + resp.Neighbours.Batadv[bfaceAddr] = n + } + } } diff --git a/respond/daemon/nodeinfo.go b/respond/daemon/nodeinfo.go index b7bbb045..663604cc 100644 --- a/respond/daemon/nodeinfo.go +++ b/respond/daemon/nodeinfo.go @@ -9,36 +9,43 @@ import ( "github.com/FreifunkBremen/yanic/data" ) -func (d *Daemon) updateNodeinfo(iface string, data *data.ResponseData) { +func (d *Daemon) updateNodeinfo(iface string, resp *data.ResponseData) { config, nodeID := d.getAnswer(iface) - data.Nodeinfo.NodeID = nodeID + resp.Nodeinfo.NodeID = nodeID if config.Hostname == "" { - data.Nodeinfo.Hostname, _ = os.Hostname() + resp.Nodeinfo.Hostname, _ = os.Hostname() } else { - data.Nodeinfo.Hostname = config.Hostname + resp.Nodeinfo.Hostname = config.Hostname } - data.Nodeinfo.VPN = config.VPN - data.Nodeinfo.Location = config.Location + resp.Nodeinfo.VPN = config.VPN + resp.Nodeinfo.Location = config.Location - data.Nodeinfo.System.SiteCode = config.SiteCode - data.Nodeinfo.System.DomainCode = config.DomainCode + resp.Nodeinfo.System.SiteCode = config.SiteCode + resp.Nodeinfo.System.DomainCode = config.DomainCode - data.Nodeinfo.Hardware.Nproc = runtime.NumCPU() + resp.Nodeinfo.Hardware.Nproc = runtime.NumCPU() - if data.Nodeinfo.Network.Mac == "" { - data.Nodeinfo.Network.Mac = fmt.Sprintf("%s:%s:%s:%s:%s:%s", nodeID[0:2], nodeID[2:4], nodeID[4:6], nodeID[6:8], nodeID[8:10], nodeID[10:12]) + if resp.Nodeinfo.Network.Mac == "" { + resp.Nodeinfo.Network.Mac = fmt.Sprintf("%s:%s:%s:%s:%s:%s", nodeID[0:2], nodeID[2:4], nodeID[4:6], nodeID[6:8], nodeID[8:10], nodeID[10:12]) } - if iface == "" { - data.Nodeinfo.Network.Addresses = []string{} - for _, i := range d.Interfaces { - addrs := getAddresses(i) - data.Nodeinfo.Network.Addresses = append(data.Nodeinfo.Network.Addresses, addrs...) + if iface != "" { + resp.Nodeinfo.Network.Addresses = getAddresses(iface) + } + + resp.Nodeinfo.Network.Mesh = make(map[string]*data.NetworkInterface) + for _, bface := range d.Batman { + b := NewBatman(bface) + mesh := data.NetworkInterface{} + for _, bbface := range b.Interfaces { + addr := b.Address(bbface) + if addr != "" { + mesh.Interfaces.Tunnel = append(mesh.Interfaces.Tunnel, addr) + } } - } else { - data.Nodeinfo.Network.Addresses = getAddresses(iface) + resp.Nodeinfo.Network.Mesh[bface] = &mesh } } diff --git a/respond/daemon/statistics.go b/respond/daemon/statistics.go index d414f22f..d5ce2597 100644 --- a/respond/daemon/statistics.go +++ b/respond/daemon/statistics.go @@ -1,8 +1,8 @@ package respondd import ( - "github.com/shirou/gopsutil/load" "github.com/shirou/gopsutil/host" + "github.com/shirou/gopsutil/load" "github.com/shirou/gopsutil/mem" "github.com/FreifunkBremen/yanic/data"