[TASK] make yanic babel compatible (#104)
This commit is contained in:
parent
950ad8457f
commit
c660e175f0
|
@ -15,7 +15,7 @@ func TestReadConfig(t *testing.T) {
|
||||||
assert.NotNil(config)
|
assert.NotNil(config)
|
||||||
|
|
||||||
assert.True(config.Respondd.Enable)
|
assert.True(config.Respondd.Enable)
|
||||||
assert.Equal([]string{"br-ffhb"}, config.Respondd.Interfaces)
|
assert.Equal("br-ffhb", config.Respondd.Interfaces[0].InterfaceName)
|
||||||
assert.Equal(time.Minute, config.Respondd.CollectInterval.Duration)
|
assert.Equal(time.Minute, config.Respondd.CollectInterval.Duration)
|
||||||
assert.Equal(time.Hour*24*7, config.Nodes.PruneAfter.Duration)
|
assert.Equal(time.Hour*24*7, config.Nodes.PruneAfter.Duration)
|
||||||
assert.Equal(time.Hour*24*7, config.Database.DeleteAfter.Duration)
|
assert.Equal(time.Hour*24*7, config.Database.DeleteAfter.Duration)
|
||||||
|
|
41
cmd/query.go
41
cmd/query.go
|
@ -1,8 +1,10 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/FreifunkBremen/yanic/respond"
|
"github.com/FreifunkBremen/yanic/respond"
|
||||||
|
@ -10,32 +12,55 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
var wait int
|
var (
|
||||||
|
wait int
|
||||||
|
port int
|
||||||
|
ipAddress string
|
||||||
|
)
|
||||||
|
|
||||||
// queryCmd represents the query command
|
// queryCmd represents the query command
|
||||||
var queryCmd = &cobra.Command{
|
var queryCmd = &cobra.Command{
|
||||||
Use: "query <interface> <destination>",
|
Use: "query <interfaces> <destination>",
|
||||||
Short: "Sends a query on the interface to the destination and waits for a response",
|
Short: "Sends a query on the interface to the destination and waits for a response",
|
||||||
Example: `yanic query wlan0 "fe80::eade:27ff:dead:beef"`,
|
Example: `yanic query "eth0,wlan0" "fe80::eade:27ff:dead:beef"`,
|
||||||
Args: cobra.ExactArgs(2),
|
Args: cobra.ExactArgs(2),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
iface := args[0]
|
ifaces := strings.Split(args[0], ",")
|
||||||
dstAddress := net.ParseIP(args[1])
|
dstAddress := net.ParseIP(args[1])
|
||||||
|
|
||||||
log.Printf("Sending request address=%s iface=%s", dstAddress, iface)
|
log.Printf("Sending request address=%s ifaces=%s", dstAddress, ifaces)
|
||||||
|
|
||||||
|
var ifacesConfigs []respond.InterfaceConfig
|
||||||
|
for _, iface := range ifaces {
|
||||||
|
ifaceConfig := respond.InterfaceConfig{
|
||||||
|
InterfaceName: iface,
|
||||||
|
Port: port,
|
||||||
|
IPAddress: ipAddress,
|
||||||
|
}
|
||||||
|
ifacesConfigs = append(ifacesConfigs, ifaceConfig)
|
||||||
|
}
|
||||||
|
|
||||||
nodes := runtime.NewNodes(&runtime.NodesConfig{})
|
nodes := runtime.NewNodes(&runtime.NodesConfig{})
|
||||||
|
|
||||||
sitesDomains := make(map[string][]string)
|
sitesDomains := make(map[string][]string)
|
||||||
|
collector := respond.NewCollector(nil, nodes, sitesDomains, ifacesConfigs)
|
||||||
collector := respond.NewCollector(nil, nodes, sitesDomains, []string{iface}, 0)
|
|
||||||
defer collector.Close()
|
defer collector.Close()
|
||||||
collector.SendPacket(dstAddress)
|
collector.SendPacket(dstAddress)
|
||||||
|
|
||||||
time.Sleep(time.Second * time.Duration(wait))
|
time.Sleep(time.Second * time.Duration(wait))
|
||||||
|
|
||||||
for id, data := range nodes.List {
|
for id, data := range nodes.List {
|
||||||
|
jq, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
log.Printf("%s: %+v", id, data)
|
log.Printf("%s: %+v", id, data)
|
||||||
|
} else {
|
||||||
|
jqNeighbours, err := json.Marshal(data.Neighbours)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("%s: %s neighbours: %+v", id, string(jq), data.Neighbours)
|
||||||
|
} else {
|
||||||
|
log.Printf("%s: %s neighbours: %s", id, string(jq), string(jqNeighbours))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -43,4 +68,6 @@ var queryCmd = &cobra.Command{
|
||||||
func init() {
|
func init() {
|
||||||
RootCmd.AddCommand(queryCmd)
|
RootCmd.AddCommand(queryCmd)
|
||||||
queryCmd.Flags().IntVar(&wait, "wait", 1, "Seconds to wait for a response")
|
queryCmd.Flags().IntVar(&wait, "wait", 1, "Seconds to wait for a response")
|
||||||
|
queryCmd.Flags().IntVar(&port, "port", 0, "define a port to listen (if not set or set to 0 the kernel will use a random free port at its own)")
|
||||||
|
queryCmd.Flags().StringVar(&ipAddress, "ip", "", "ip address which is used for sending (optional - without definition used the link-local address)")
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ var serveCmd = &cobra.Command{
|
||||||
time.Sleep(delay)
|
time.Sleep(delay)
|
||||||
}
|
}
|
||||||
|
|
||||||
collector = respond.NewCollector(allDatabase.Conn, nodes, config.Respondd.SitesDomains(), config.Respondd.Interfaces, config.Respondd.Port)
|
collector = respond.NewCollector(allDatabase.Conn, nodes, config.Respondd.SitesDomains(), config.Respondd.Interfaces)
|
||||||
collector.Start(config.Respondd.CollectInterval.Duration)
|
collector.Start(config.Respondd.CollectInterval.Duration)
|
||||||
defer collector.Close()
|
defer collector.Close()
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,6 @@ enable = true
|
||||||
synchronize = "1m"
|
synchronize = "1m"
|
||||||
# how often request per multicast
|
# how often request per multicast
|
||||||
collect_interval = "1m"
|
collect_interval = "1m"
|
||||||
# interface that has an IP in your mesh network
|
|
||||||
interfaces = ["br-ffhb"]
|
|
||||||
# define a port to listen
|
|
||||||
# if not set or set to 0 the kernel will use a random free port at its own
|
|
||||||
#port = 10001
|
|
||||||
|
|
||||||
# table of a site to save stats for (not exists for global only)
|
# table of a site to save stats for (not exists for global only)
|
||||||
#[respondd.sites.example]
|
#[respondd.sites.example]
|
||||||
|
@ -23,6 +18,20 @@ interfaces = ["br-ffhb"]
|
||||||
[respondd.sites.ffhb]
|
[respondd.sites.ffhb]
|
||||||
domains = ["city"]
|
domains = ["city"]
|
||||||
|
|
||||||
|
# interface that has an IP in your mesh network
|
||||||
|
[[respondd.interfaces]]
|
||||||
|
# name of interface on which this collector is running
|
||||||
|
ifname = "br-ffhb"
|
||||||
|
# ip address which is used for sending
|
||||||
|
# (optional - without definition used a address of ifname)
|
||||||
|
ip_address = "fd2f:5119:f2d::5"
|
||||||
|
# multicast address to destination of respondd
|
||||||
|
# (optional - without definition used batman default ff02::2:1001)
|
||||||
|
multicast_address = "ff05::2:1001"
|
||||||
|
# define a port to listen
|
||||||
|
# if not set or set to 0 the kernel will use a random free port at its own
|
||||||
|
#port = 10001
|
||||||
|
|
||||||
# A little build-in webserver, which statically serves a directory.
|
# A little build-in webserver, which statically serves a directory.
|
||||||
# This is useful for testing purposes or for a little standalone installation.
|
# This is useful for testing purposes or for a little standalone installation.
|
||||||
[webserver]
|
[webserver]
|
||||||
|
|
|
@ -3,6 +3,7 @@ package data
|
||||||
// Neighbours struct
|
// Neighbours struct
|
||||||
type Neighbours struct {
|
type Neighbours struct {
|
||||||
Batadv map[string]BatadvNeighbours `json:"batadv"`
|
Batadv map[string]BatadvNeighbours `json:"batadv"`
|
||||||
|
Babel map[string]BabelNeighbours `json:"babel"`
|
||||||
LLDP map[string]LLDPNeighbours `json:"lldp"`
|
LLDP map[string]LLDPNeighbours `json:"lldp"`
|
||||||
//WifiNeighbours map[string]WifiNeighbours `json:"wifi"`
|
//WifiNeighbours map[string]WifiNeighbours `json:"wifi"`
|
||||||
NodeID string `json:"node_id"`
|
NodeID string `json:"node_id"`
|
||||||
|
@ -27,11 +28,27 @@ type LLDPLink struct {
|
||||||
Description string `json:"descr"`
|
Description string `json:"descr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BabelLink struct
|
||||||
|
type BabelLink struct {
|
||||||
|
// How need this:
|
||||||
|
RXCost int `json:"rxcost"`
|
||||||
|
TXCost int `json:"txcost"`
|
||||||
|
Cost int `json:"cost"`
|
||||||
|
Reachability int `json:"reachability"`
|
||||||
|
}
|
||||||
|
|
||||||
// BatadvNeighbours struct
|
// BatadvNeighbours struct
|
||||||
type BatadvNeighbours struct {
|
type BatadvNeighbours struct {
|
||||||
Neighbours map[string]BatmanLink `json:"neighbours"`
|
Neighbours map[string]BatmanLink `json:"neighbours"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BabelNeighbours struct
|
||||||
|
type BabelNeighbours struct {
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
|
LinkLocalAddress string `json:"ll-addr"`
|
||||||
|
Neighbours map[string]BabelLink `json:"neighbours"`
|
||||||
|
}
|
||||||
|
|
||||||
// WifiNeighbours struct
|
// WifiNeighbours struct
|
||||||
type WifiNeighbours struct {
|
type WifiNeighbours struct {
|
||||||
Neighbours map[string]WifiLink `json:"neighbours"`
|
Neighbours map[string]WifiLink `json:"neighbours"`
|
||||||
|
|
|
@ -14,8 +14,8 @@ type NodeInfo struct {
|
||||||
Wireless *Wireless `json:"wireless,omitempty"`
|
Wireless *Wireless `json:"wireless,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BatInterface struct
|
// NetworkInterface struct
|
||||||
type BatInterface struct {
|
type NetworkInterface struct {
|
||||||
Interfaces struct {
|
Interfaces struct {
|
||||||
Wireless []string `json:"wireless,omitempty"`
|
Wireless []string `json:"wireless,omitempty"`
|
||||||
Other []string `json:"other,omitempty"`
|
Other []string `json:"other,omitempty"`
|
||||||
|
@ -24,7 +24,7 @@ type BatInterface struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Addresses returns a flat list of all MAC addresses
|
// Addresses returns a flat list of all MAC addresses
|
||||||
func (iface *BatInterface) Addresses() []string {
|
func (iface *NetworkInterface) Addresses() []string {
|
||||||
return append(append(iface.Interfaces.Other, iface.Interfaces.Tunnel...), iface.Interfaces.Wireless...)
|
return append(append(iface.Interfaces.Other, iface.Interfaces.Tunnel...), iface.Interfaces.Wireless...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,8 @@ func (iface *BatInterface) Addresses() []string {
|
||||||
type Network struct {
|
type Network struct {
|
||||||
Mac string `json:"mac"`
|
Mac string `json:"mac"`
|
||||||
Addresses []string `json:"addresses"`
|
Addresses []string `json:"addresses"`
|
||||||
Mesh map[string]*BatInterface `json:"mesh"`
|
Mesh map[string]*NetworkInterface `json:"mesh"`
|
||||||
|
// still used in gluon?
|
||||||
MeshInterfaces []string `json:"mesh_interfaces"`
|
MeshInterfaces []string `json:"mesh_interfaces"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +65,9 @@ type Software struct {
|
||||||
Version string `json:"version,omitempty"`
|
Version string `json:"version,omitempty"`
|
||||||
Compat int `json:"compat,omitempty"`
|
Compat int `json:"compat,omitempty"`
|
||||||
} `json:"batman-adv,omitempty"`
|
} `json:"batman-adv,omitempty"`
|
||||||
|
Babeld struct {
|
||||||
|
Version string `json:"version,omitempty"`
|
||||||
|
} `json:"babeld,omitempty"`
|
||||||
Fastd struct {
|
Fastd struct {
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
Version string `json:"version,omitempty"`
|
Version string `json:"version,omitempty"`
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
|
|
||||||
func TestNodeinfoBatAddresses(t *testing.T) {
|
func TestNodeinfoBatAddresses(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
batIface := &BatInterface{
|
iface := &NetworkInterface{
|
||||||
Interfaces: struct {
|
Interfaces: struct {
|
||||||
Wireless []string `json:"wireless,omitempty"`
|
Wireless []string `json:"wireless,omitempty"`
|
||||||
Other []string `json:"other,omitempty"`
|
Other []string `json:"other,omitempty"`
|
||||||
|
@ -20,7 +20,7 @@ func TestNodeinfoBatAddresses(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
addr := batIface.Addresses()
|
addr := iface.Addresses()
|
||||||
assert.NotNil(addr)
|
assert.NotNil(addr)
|
||||||
assert.Equal([]string{"aa:aa:aa:aa:aa", "aa:aa:aa:aa:ab"}, addr)
|
assert.Equal([]string{"aa:aa:aa:aa:aa", "aa:aa:aa:aa:ab"}, addr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,9 @@ import (
|
||||||
func (conn *Connection) InsertLink(link *runtime.Link, t time.Time) {
|
func (conn *Connection) InsertLink(link *runtime.Link, t time.Time) {
|
||||||
tags := models.Tags{}
|
tags := models.Tags{}
|
||||||
tags.SetString("source.id", link.SourceID)
|
tags.SetString("source.id", link.SourceID)
|
||||||
tags.SetString("source.mac", link.SourceMAC)
|
tags.SetString("source.addr", link.SourceAddress)
|
||||||
tags.SetString("target.id", link.TargetID)
|
tags.SetString("target.id", link.TargetID)
|
||||||
tags.SetString("target.mac", link.TargetMAC)
|
tags.SetString("target.addr", link.TargetAddress)
|
||||||
|
|
||||||
conn.addPoint(MeasurementLink, tags, models.Fields{"tq": float32(link.TQ) / 2.55}, t)
|
conn.addPoint(MeasurementLink, tags, models.Fields{"tq": link.TQ * 100}, t)
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,9 +159,9 @@ func TestToInflux(t *testing.T) {
|
||||||
assert.EqualValues("link", nPoint.Name())
|
assert.EqualValues("link", nPoint.Name())
|
||||||
assert.EqualValues(map[string]string{
|
assert.EqualValues(map[string]string{
|
||||||
"source.id": "deadbeef",
|
"source.id": "deadbeef",
|
||||||
"source.mac": "a-interface",
|
"source.addr": "a-interface",
|
||||||
"target.id": "foobar",
|
"target.id": "foobar",
|
||||||
"target.mac": "BAFF1E5",
|
"target.addr": "BAFF1E5",
|
||||||
}, tags)
|
}, tags)
|
||||||
assert.EqualValues(80, fields["tq"])
|
assert.EqualValues(80, fields["tq"])
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,15 @@ Group for configuration of respondd request.
|
||||||
enable = true
|
enable = true
|
||||||
# synchronize = "1m"
|
# synchronize = "1m"
|
||||||
collect_interval = "1m"
|
collect_interval = "1m"
|
||||||
interfaces = ["br-ffhb"]
|
|
||||||
#port = 10001
|
|
||||||
#[respondd.sites.example]
|
#[respondd.sites.example]
|
||||||
#domains = ["city"]
|
#domains = ["city"]
|
||||||
|
|
||||||
|
[[respondd.interfaces]]
|
||||||
|
ifname = "br-ffhb"
|
||||||
|
#ip_address = "fe80::..."
|
||||||
|
#multicast_address = "ff02::2:1001"
|
||||||
|
#port = 10001
|
||||||
```
|
```
|
||||||
{% endmethod %}
|
{% endmethod %}
|
||||||
|
|
||||||
|
@ -46,7 +51,7 @@ synchronize = "1m"
|
||||||
{% method %}
|
{% method %}
|
||||||
How often send request per respondd.
|
How often send request per respondd.
|
||||||
|
|
||||||
It will send UDP packets with multicast group `ff02::2:1001` and port `1001`.
|
It will send UDP packets with multicast address `ff02::2:1001` and port `1001`.
|
||||||
If a node does not answer after the half time, it will request with the last know address under the port `1001`.
|
If a node does not answer after the half time, it will request with the last know address under the port `1001`.
|
||||||
{% sample lang="toml" %}
|
{% sample lang="toml" %}
|
||||||
```toml
|
```toml
|
||||||
|
@ -55,26 +60,16 @@ collect_interval = "1m"
|
||||||
{% endmethod %}
|
{% endmethod %}
|
||||||
|
|
||||||
|
|
||||||
### interfaces
|
### sites
|
||||||
{% method %}
|
{% method %}
|
||||||
Interface that has an IP in your mesh network
|
List of sites to save stats for (empty for global only)
|
||||||
{% sample lang="toml" %}
|
{% sample lang="toml" %}
|
||||||
```toml
|
```toml
|
||||||
interfaces = ["br-ffhb"]
|
sites = ["ffhb"]
|
||||||
```
|
```
|
||||||
{% endmethod %}
|
{% endmethod %}
|
||||||
|
|
||||||
|
|
||||||
### port
|
|
||||||
{% method %}
|
|
||||||
Define a port to listen and send the respondd packages.
|
|
||||||
If not set or set to 0 the kernel will use a random free port at its own.
|
|
||||||
{% sample lang="toml" %}
|
|
||||||
```toml
|
|
||||||
port = 10001
|
|
||||||
```
|
|
||||||
{% endmethod %}
|
|
||||||
|
|
||||||
### [respondd.sites.example]
|
### [respondd.sites.example]
|
||||||
{% method %}
|
{% method %}
|
||||||
Tables of sites to save stats for (not exists for global only).
|
Tables of sites to save stats for (not exists for global only).
|
||||||
|
@ -85,6 +80,7 @@ Here is the site _ffhb_.
|
||||||
domains = ["city"]
|
domains = ["city"]
|
||||||
```
|
```
|
||||||
{% endmethod %}
|
{% endmethod %}
|
||||||
|
|
||||||
#### domains
|
#### domains
|
||||||
{% method %}
|
{% method %}
|
||||||
list of domains on this site to save stats for (empty for global only)
|
list of domains on this site to save stats for (empty for global only)
|
||||||
|
@ -95,6 +91,60 @@ domains = ["city"]
|
||||||
{% endmethod %}
|
{% endmethod %}
|
||||||
|
|
||||||
|
|
||||||
|
### [[respondd.interfaces]]
|
||||||
|
{% method %}
|
||||||
|
Interface that has an ip address in your mesh network.
|
||||||
|
It is possible to have multiple interfaces, just add this group again with new parameters (see toml [[array of table]]).
|
||||||
|
{% sample lang="toml" %}
|
||||||
|
```toml
|
||||||
|
[[respondd.interfaces]]
|
||||||
|
ifname = "br-ffhb"
|
||||||
|
#ip_address = "fe80::..."
|
||||||
|
#multicast_address = "ff02::2:1001"
|
||||||
|
#port = 10001
|
||||||
|
```
|
||||||
|
{% endmethod %}
|
||||||
|
|
||||||
|
### ifname
|
||||||
|
{% method %}
|
||||||
|
name of interface on which this collector is running.
|
||||||
|
{% sample lang="toml" %}
|
||||||
|
```toml
|
||||||
|
ifname = "br-ffhb"
|
||||||
|
```
|
||||||
|
{% endmethod %}
|
||||||
|
|
||||||
|
### ip_address
|
||||||
|
{% method %}
|
||||||
|
ip address is the own address which is used for sending.
|
||||||
|
If not set or set with empty string it will take an address of ifname.
|
||||||
|
{% sample lang="toml" %}
|
||||||
|
```toml
|
||||||
|
ip_address = "fe80::..."
|
||||||
|
```
|
||||||
|
{% endmethod %}
|
||||||
|
|
||||||
|
### multicast_address
|
||||||
|
{% method %}
|
||||||
|
Multicast address to destination of respondd.
|
||||||
|
If not set or set with empty string it will take the batman default multicast address `ff02::2:1001`
|
||||||
|
(Needed in babel for a mesh-network wide routeable multicast addreess `ff05::2:1001`)
|
||||||
|
{% sample lang="toml" %}
|
||||||
|
```toml
|
||||||
|
multicast_address = "ff02::2:1001"
|
||||||
|
```
|
||||||
|
{% endmethod %}
|
||||||
|
|
||||||
|
### port
|
||||||
|
{% method %}
|
||||||
|
Define a port to listen and send the respondd packages.
|
||||||
|
If not set or set to 0 the kernel will use a random free port at its own.
|
||||||
|
{% sample lang="toml" %}
|
||||||
|
```toml
|
||||||
|
port = 10001
|
||||||
|
```
|
||||||
|
{% endmethod %}
|
||||||
|
|
||||||
|
|
||||||
## [webserver]
|
## [webserver]
|
||||||
{% method %}
|
{% method %}
|
||||||
|
|
|
@ -5,7 +5,7 @@ cp /opt/go/src/github.com/FreifunkBremen/yanic/config_example.toml /etc/yanic.co
|
||||||
```
|
```
|
||||||
|
|
||||||
# Quick configuration
|
# Quick configuration
|
||||||
For an easy startup you only need to edit the `interfaces` in section
|
For an easy startup you only need to edit the `[[respondd.interfaces]]` in section
|
||||||
`[respondd]` in file `/etc/yanic.conf`.
|
`[respondd]` in file `/etc/yanic.conf`.
|
||||||
|
|
||||||
Then create the following files and folders:
|
Then create the following files and folders:
|
||||||
|
|
|
@ -7,7 +7,7 @@ A little overview of yanic in connection with other software:
|
||||||
|
|
||||||
It sends the `gluon-neighbour-info` request and collects the answers.
|
It sends the `gluon-neighbour-info` request and collects the answers.
|
||||||
|
|
||||||
It will send UDP packets with multicast group `ff02:0:0:0:0:0:2:1001` and port `1001`.
|
It will send UDP packets with multicast address `ff02:0:0:0:0:0:2:1001` and port `1001`.
|
||||||
|
|
||||||
If a node does not answer, it will request with the last know address under the port `1001`.
|
If a node does not answer, it will request with the last know address under the port `1001`.
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,12 @@ import (
|
||||||
"github.com/FreifunkBremen/yanic/runtime"
|
"github.com/FreifunkBremen/yanic/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LINK_TYPE_WIRELESS = "wifi"
|
||||||
|
LINK_TYPE_TUNNEL = "vpn"
|
||||||
|
LINK_TYPE_FALLBACK = "other"
|
||||||
|
)
|
||||||
|
|
||||||
func transform(nodes *runtime.Nodes) *Meshviewer {
|
func transform(nodes *runtime.Nodes) *Meshviewer {
|
||||||
|
|
||||||
meshviewer := &Meshviewer{
|
meshviewer := &Meshviewer{
|
||||||
|
@ -34,11 +40,11 @@ func transform(nodes *runtime.Nodes) *Meshviewer {
|
||||||
if nodeinfo := nodeOrigin.Nodeinfo; nodeinfo != nil {
|
if nodeinfo := nodeOrigin.Nodeinfo; nodeinfo != nil {
|
||||||
if meshes := nodeinfo.Network.Mesh; meshes != nil {
|
if meshes := nodeinfo.Network.Mesh; meshes != nil {
|
||||||
for _, mesh := range meshes {
|
for _, mesh := range meshes {
|
||||||
for _, mac := range mesh.Interfaces.Wireless {
|
for _, addr := range mesh.Interfaces.Wireless {
|
||||||
typeList[mac] = "wifi"
|
typeList[addr] = LINK_TYPE_WIRELESS
|
||||||
}
|
}
|
||||||
for _, mac := range mesh.Interfaces.Tunnel {
|
for _, addr := range mesh.Interfaces.Tunnel {
|
||||||
typeList[mac] = "vpn"
|
typeList[addr] = LINK_TYPE_TUNNEL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,52 +53,70 @@ func transform(nodes *runtime.Nodes) *Meshviewer {
|
||||||
for _, linkOrigin := range nodes.NodeLinks(nodeOrigin) {
|
for _, linkOrigin := range nodes.NodeLinks(nodeOrigin) {
|
||||||
var key string
|
var key string
|
||||||
// keep source and target in the same order
|
// keep source and target in the same order
|
||||||
switchSourceTarget := strings.Compare(linkOrigin.SourceMAC, linkOrigin.TargetMAC) > 0
|
switchSourceTarget := strings.Compare(linkOrigin.SourceAddress, linkOrigin.TargetAddress) > 0
|
||||||
if switchSourceTarget {
|
if switchSourceTarget {
|
||||||
key = fmt.Sprintf("%s-%s", linkOrigin.SourceMAC, linkOrigin.TargetMAC)
|
key = fmt.Sprintf("%s-%s", linkOrigin.SourceAddress, linkOrigin.TargetAddress)
|
||||||
} else {
|
} else {
|
||||||
key = fmt.Sprintf("%s-%s", linkOrigin.TargetMAC, linkOrigin.SourceMAC)
|
key = fmt.Sprintf("%s-%s", linkOrigin.TargetAddress, linkOrigin.SourceAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
if link := links[key]; link != nil {
|
if link := links[key]; link != nil {
|
||||||
|
linkType, linkTypeFound := typeList[linkOrigin.SourceAddress]
|
||||||
|
if !linkTypeFound {
|
||||||
|
linkType, linkTypeFound = typeList[linkOrigin.TargetAddress]
|
||||||
|
}
|
||||||
|
|
||||||
if switchSourceTarget {
|
if switchSourceTarget {
|
||||||
link.TargetTQ = float32(linkOrigin.TQ) / 255.0
|
link.TargetTQ = linkOrigin.TQ
|
||||||
if link.Type == "other" {
|
|
||||||
link.Type = typeList[linkOrigin.TargetMAC]
|
linkType, linkTypeFound = typeList[linkOrigin.TargetAddress]
|
||||||
} else if link.Type != typeList[linkOrigin.TargetMAC] {
|
if !linkTypeFound {
|
||||||
log.Printf("different linktypes %s:%s current: %s source: %s target: %s", linkOrigin.SourceMAC, linkOrigin.TargetMAC, link.Type, typeList[linkOrigin.SourceMAC], typeList[linkOrigin.TargetMAC])
|
linkType, linkTypeFound = typeList[linkOrigin.SourceAddress]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
link.SourceTQ = float32(linkOrigin.TQ) / 255.0
|
link.SourceTQ = linkOrigin.TQ
|
||||||
if link.Type == "other" {
|
}
|
||||||
link.Type = typeList[linkOrigin.SourceMAC]
|
|
||||||
} else if link.Type != typeList[linkOrigin.SourceMAC] {
|
if linkTypeFound && linkType != link.Type {
|
||||||
log.Printf("different linktypes %s:%s current: %s source: %s target: %s", linkOrigin.SourceMAC, linkOrigin.TargetMAC, link.Type, typeList[linkOrigin.SourceMAC], typeList[linkOrigin.TargetMAC])
|
if link.Type == LINK_TYPE_FALLBACK {
|
||||||
|
link.Type = linkType
|
||||||
|
} else {
|
||||||
|
log.Printf("different linktypes for '%s' - '%s' prev: '%s' new: '%s' source: '%s' target: '%s'", linkOrigin.SourceAddress, linkOrigin.TargetAddress, link.Type, linkType, typeList[linkOrigin.SourceAddress], typeList[linkOrigin.TargetAddress])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if link.Type == "" {
|
|
||||||
link.Type = "other"
|
|
||||||
}
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tq := float32(linkOrigin.TQ) / 255.0
|
|
||||||
link := &Link{
|
link := &Link{
|
||||||
Type: typeList[linkOrigin.SourceMAC],
|
|
||||||
Source: linkOrigin.SourceID,
|
Source: linkOrigin.SourceID,
|
||||||
SourceMAC: linkOrigin.SourceMAC,
|
SourceAddress: linkOrigin.SourceAddress,
|
||||||
Target: linkOrigin.TargetID,
|
Target: linkOrigin.TargetID,
|
||||||
TargetMAC: linkOrigin.TargetMAC,
|
TargetAddress: linkOrigin.TargetAddress,
|
||||||
SourceTQ: tq,
|
SourceTQ: linkOrigin.TQ,
|
||||||
TargetTQ: tq,
|
TargetTQ: linkOrigin.TQ,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linkType, linkTypeFound := typeList[linkOrigin.SourceAddress]
|
||||||
|
if !linkTypeFound {
|
||||||
|
linkType, linkTypeFound = typeList[linkOrigin.TargetAddress]
|
||||||
|
}
|
||||||
|
|
||||||
if switchSourceTarget {
|
if switchSourceTarget {
|
||||||
link.Type = typeList[linkOrigin.TargetMAC]
|
|
||||||
link.Source = linkOrigin.TargetID
|
link.Source = linkOrigin.TargetID
|
||||||
link.SourceMAC = linkOrigin.TargetMAC
|
link.SourceAddress = linkOrigin.TargetAddress
|
||||||
link.Target = linkOrigin.SourceID
|
link.Target = linkOrigin.SourceID
|
||||||
link.TargetMAC = linkOrigin.SourceMAC
|
link.TargetAddress = linkOrigin.SourceAddress
|
||||||
|
|
||||||
|
linkType, linkTypeFound = typeList[linkOrigin.TargetAddress]
|
||||||
|
if !linkTypeFound {
|
||||||
|
linkType, linkTypeFound = typeList[linkOrigin.SourceAddress]
|
||||||
}
|
}
|
||||||
if link.Type == "" {
|
}
|
||||||
link.Type = "other"
|
|
||||||
|
if linkTypeFound {
|
||||||
|
link.Type = linkType
|
||||||
|
} else {
|
||||||
|
link.Type = LINK_TYPE_FALLBACK
|
||||||
}
|
}
|
||||||
links[key] = link
|
links[key] = link
|
||||||
meshviewer.Links = append(meshviewer.Links, link)
|
meshviewer.Links = append(meshviewer.Links, link)
|
||||||
|
|
|
@ -18,7 +18,7 @@ func TestTransform(t *testing.T) {
|
||||||
NodeID: "node_a",
|
NodeID: "node_a",
|
||||||
Network: data.Network{
|
Network: data.Network{
|
||||||
Mac: "node:a:mac",
|
Mac: "node:a:mac",
|
||||||
Mesh: map[string]*data.BatInterface{
|
Mesh: map[string]*data.NetworkInterface{
|
||||||
"bat0": {
|
"bat0": {
|
||||||
Interfaces: struct {
|
Interfaces: struct {
|
||||||
Wireless []string `json:"wireless,omitempty"`
|
Wireless []string `json:"wireless,omitempty"`
|
||||||
|
@ -55,7 +55,7 @@ func TestTransform(t *testing.T) {
|
||||||
NodeID: "node_c",
|
NodeID: "node_c",
|
||||||
Network: data.Network{
|
Network: data.Network{
|
||||||
Mac: "node:c:mac",
|
Mac: "node:c:mac",
|
||||||
Mesh: map[string]*data.BatInterface{
|
Mesh: map[string]*data.NetworkInterface{
|
||||||
"bat0": {
|
"bat0": {
|
||||||
Interfaces: struct {
|
Interfaces: struct {
|
||||||
Wireless []string `json:"wireless,omitempty"`
|
Wireless []string `json:"wireless,omitempty"`
|
||||||
|
@ -85,7 +85,7 @@ func TestTransform(t *testing.T) {
|
||||||
NodeID: "node_b",
|
NodeID: "node_b",
|
||||||
Network: data.Network{
|
Network: data.Network{
|
||||||
Mac: "node:b:mac",
|
Mac: "node:b:mac",
|
||||||
Mesh: map[string]*data.BatInterface{
|
Mesh: map[string]*data.NetworkInterface{
|
||||||
"bat0": {
|
"bat0": {
|
||||||
Interfaces: struct {
|
Interfaces: struct {
|
||||||
Wireless []string `json:"wireless,omitempty"`
|
Wireless []string `json:"wireless,omitempty"`
|
||||||
|
@ -121,7 +121,7 @@ func TestTransform(t *testing.T) {
|
||||||
NodeID: "node_d",
|
NodeID: "node_d",
|
||||||
Network: data.Network{
|
Network: data.Network{
|
||||||
Mac: "node:d:mac",
|
Mac: "node:d:mac",
|
||||||
Mesh: map[string]*data.BatInterface{
|
Mesh: map[string]*data.NetworkInterface{
|
||||||
"bat0": {
|
"bat0": {
|
||||||
Interfaces: struct {
|
Interfaces: struct {
|
||||||
Wireless []string `json:"wireless,omitempty"`
|
Wireless []string `json:"wireless,omitempty"`
|
||||||
|
@ -159,27 +159,27 @@ func TestTransform(t *testing.T) {
|
||||||
assert.Len(links, 3)
|
assert.Len(links, 3)
|
||||||
|
|
||||||
for _, link := range links {
|
for _, link := range links {
|
||||||
switch link.SourceMAC {
|
switch link.SourceAddress {
|
||||||
case "node:a:mac:lan":
|
case "node:a:mac:lan":
|
||||||
assert.Equal("other", link.Type)
|
assert.Equal("other", link.Type)
|
||||||
assert.Equal("node:b:mac:lan", link.TargetMAC)
|
assert.Equal("node:b:mac:lan", link.TargetAddress)
|
||||||
assert.Equal(float32(0.2), link.SourceTQ)
|
assert.Equal(float32(0.2), link.SourceTQ)
|
||||||
assert.Equal(float32(0.2), link.TargetTQ)
|
assert.Equal(float32(0.2), link.TargetTQ)
|
||||||
break
|
break
|
||||||
|
|
||||||
case "node:a:mac:wifi":
|
case "node:a:mac:wifi":
|
||||||
assert.Equal("wifi", link.Type)
|
assert.Equal("wifi", link.Type)
|
||||||
assert.Equal("node:b:mac:wifi", link.TargetMAC)
|
assert.Equal("node:b:mac:wifi", link.TargetAddress)
|
||||||
assert.Equal(float32(0.6), link.SourceTQ)
|
assert.Equal(float32(0.6), link.SourceTQ)
|
||||||
assert.Equal(float32(0.8), link.TargetTQ)
|
assert.Equal(float32(0.8), link.TargetTQ)
|
||||||
case "node:b:mac:lan":
|
case "node:b:mac:lan":
|
||||||
assert.Equal("other", link.Type)
|
assert.Equal("other", link.Type)
|
||||||
assert.Equal("node:c:mac:lan", link.TargetMAC)
|
assert.Equal("node:c:mac:lan", link.TargetAddress)
|
||||||
assert.Equal(float32(0.8), link.SourceTQ)
|
assert.Equal(float32(0.8), link.SourceTQ)
|
||||||
assert.Equal(float32(0.4), link.TargetTQ)
|
assert.Equal(float32(0.4), link.TargetTQ)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
assert.False(true, "invalid link.SourceMAC found")
|
assert.False(true, "invalid link.SourceAddress found")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,8 +69,8 @@ type Link struct {
|
||||||
Target string `json:"target"`
|
Target string `json:"target"`
|
||||||
SourceTQ float32 `json:"source_tq"`
|
SourceTQ float32 `json:"source_tq"`
|
||||||
TargetTQ float32 `json:"target_tq"`
|
TargetTQ float32 `json:"target_tq"`
|
||||||
SourceMAC string `json:"source_mac"`
|
SourceAddress string `json:"source_addr"`
|
||||||
TargetMAC string `json:"target_mac"`
|
TargetAddress string `json:"target_addr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNode(nodes *runtime.Nodes, n *runtime.Node) *Node {
|
func NewNode(nodes *runtime.Nodes, n *runtime.Node) *Node {
|
||||||
|
@ -134,15 +134,15 @@ func NewNode(nodes *runtime.Nodes, n *runtime.Node) *Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
node.Uptime = jsontime.Now().Add(time.Duration(statistic.Uptime) * -time.Second)
|
node.Uptime = jsontime.Now().Add(time.Duration(statistic.Uptime) * -time.Second)
|
||||||
node.GatewayNexthop = nodes.GetNodeIDbyMAC(statistic.GatewayNexthop)
|
node.GatewayNexthop = nodes.GetNodeIDbyAddress(statistic.GatewayNexthop)
|
||||||
if node.GatewayNexthop == "" {
|
if node.GatewayNexthop == "" {
|
||||||
node.GatewayNexthop = statistic.GatewayNexthop
|
node.GatewayNexthop = statistic.GatewayNexthop
|
||||||
}
|
}
|
||||||
node.GatewayIPv4 = nodes.GetNodeIDbyMAC(statistic.GatewayIPv4)
|
node.GatewayIPv4 = nodes.GetNodeIDbyAddress(statistic.GatewayIPv4)
|
||||||
if node.GatewayIPv4 == "" {
|
if node.GatewayIPv4 == "" {
|
||||||
node.GatewayIPv4 = statistic.GatewayIPv4
|
node.GatewayIPv4 = statistic.GatewayIPv4
|
||||||
}
|
}
|
||||||
node.GatewayIPv6 = nodes.GetNodeIDbyMAC(statistic.GatewayIPv6)
|
node.GatewayIPv6 = nodes.GetNodeIDbyAddress(statistic.GatewayIPv6)
|
||||||
if node.GatewayIPv6 == "" {
|
if node.GatewayIPv6 == "" {
|
||||||
node.GatewayIPv6 = statistic.GatewayIPv6
|
node.GatewayIPv6 = statistic.GatewayIPv6
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,7 @@ import (
|
||||||
|
|
||||||
// Collector for a specificle respond messages
|
// Collector for a specificle respond messages
|
||||||
type Collector struct {
|
type Collector struct {
|
||||||
connections []*net.UDPConn // UDP sockets
|
connections []multicastConn // UDP sockets
|
||||||
ifaceToConn map[string]*net.UDPConn // map from interface name to UDP socket
|
|
||||||
port int
|
port int
|
||||||
|
|
||||||
queue chan *Response // received responses
|
queue chan *Response // received responses
|
||||||
|
@ -29,17 +28,20 @@ type Collector struct {
|
||||||
stop chan interface{}
|
stop chan interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type multicastConn struct {
|
||||||
|
Conn *net.UDPConn
|
||||||
|
MulticastAddress net.IP
|
||||||
|
}
|
||||||
|
|
||||||
// NewCollector creates a Collector struct
|
// NewCollector creates a Collector struct
|
||||||
func NewCollector(db database.Connection, nodes *runtime.Nodes, sitesDomains map[string][]string, ifaces []string, port int) *Collector {
|
func NewCollector(db database.Connection, nodes *runtime.Nodes, sitesDomains map[string][]string, ifaces []InterfaceConfig) *Collector {
|
||||||
|
|
||||||
coll := &Collector{
|
coll := &Collector{
|
||||||
db: db,
|
db: db,
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
sitesDomains: sitesDomains,
|
sitesDomains: sitesDomains,
|
||||||
port: port,
|
|
||||||
queue: make(chan *Response, 400),
|
queue: make(chan *Response, 400),
|
||||||
stop: make(chan interface{}),
|
stop: make(chan interface{}),
|
||||||
ifaceToConn: make(map[string]*net.UDPConn),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, iface := range ifaces {
|
for _, iface := range ifaces {
|
||||||
|
@ -55,35 +57,47 @@ func NewCollector(db database.Connection, nodes *runtime.Nodes, sitesDomains map
|
||||||
return coll
|
return coll
|
||||||
}
|
}
|
||||||
|
|
||||||
func (coll *Collector) listenUDP(iface string) {
|
func (coll *Collector) listenUDP(iface InterfaceConfig) {
|
||||||
if _, found := coll.ifaceToConn[iface]; found {
|
|
||||||
log.Panicf("can not listen twice on %s", iface)
|
var addr net.IP
|
||||||
}
|
|
||||||
linkLocalAddr, err := getLinkLocalAddr(iface)
|
var err error
|
||||||
|
if iface.IPAddress != "" {
|
||||||
|
addr = net.ParseIP(iface.IPAddress)
|
||||||
|
} else {
|
||||||
|
addr, err = getUnicastAddr(iface.InterfaceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panic(err)
|
log.Panic(err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
multicastAddress := multicastAddressDefault
|
||||||
|
if iface.MulticastAddress != "" {
|
||||||
|
multicastAddress = iface.MulticastAddress
|
||||||
|
}
|
||||||
|
|
||||||
// Open socket
|
// Open socket
|
||||||
conn, err := net.ListenUDP("udp", &net.UDPAddr{
|
conn, err := net.ListenUDP("udp", &net.UDPAddr{
|
||||||
IP: linkLocalAddr,
|
IP: addr,
|
||||||
Port: coll.port,
|
Port: iface.Port,
|
||||||
Zone: iface,
|
Zone: iface.InterfaceName,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panic(err)
|
log.Panic(err)
|
||||||
}
|
}
|
||||||
conn.SetReadBuffer(maxDataGramSize)
|
conn.SetReadBuffer(maxDataGramSize)
|
||||||
|
|
||||||
coll.ifaceToConn[iface] = conn
|
coll.connections = append(coll.connections, multicastConn{
|
||||||
coll.connections = append(coll.connections, conn)
|
Conn: conn,
|
||||||
|
MulticastAddress: net.ParseIP(multicastAddress),
|
||||||
|
})
|
||||||
|
|
||||||
// Start receiver
|
// Start receiver
|
||||||
go coll.receiver(conn)
|
go coll.receiver(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the first link local unicast address for the given interface name
|
// Returns a unicast address of given interface (prefer global unicast address over link local address)
|
||||||
func getLinkLocalAddr(ifname string) (net.IP, error) {
|
func getUnicastAddr(ifname string) (net.IP, error) {
|
||||||
iface, err := net.InterfaceByName(ifname)
|
iface, err := net.InterfaceByName(ifname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -93,13 +107,23 @@ func getLinkLocalAddr(ifname string) (net.IP, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
var ip net.IP
|
||||||
|
|
||||||
for _, addr := range addresses {
|
for _, addr := range addresses {
|
||||||
if ipnet := addr.(*net.IPNet); ipnet.IP.IsLinkLocalUnicast() {
|
ipnet, ok := addr.(*net.IPNet)
|
||||||
return ipnet.IP, nil
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ipnet.IP.IsGlobalUnicast() {
|
||||||
|
ip = ipnet.IP
|
||||||
|
} else if ipnet.IP.IsLinkLocalUnicast() && ip == nil {
|
||||||
|
ip = ipnet.IP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unable to find link local unicast address for %s", ifname)
|
if ip != nil {
|
||||||
|
return ip, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unable to find a unicast address for %s", ifname)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start Collector
|
// Start Collector
|
||||||
|
@ -122,7 +146,7 @@ func (coll *Collector) Start(interval time.Duration) {
|
||||||
func (coll *Collector) Close() {
|
func (coll *Collector) Close() {
|
||||||
close(coll.stop)
|
close(coll.stop)
|
||||||
for _, conn := range coll.connections {
|
for _, conn := range coll.connections {
|
||||||
conn.Close()
|
conn.Conn.Close()
|
||||||
}
|
}
|
||||||
close(coll.queue)
|
close(coll.queue)
|
||||||
}
|
}
|
||||||
|
@ -139,7 +163,7 @@ func (coll *Collector) sendOnce() {
|
||||||
func (coll *Collector) sendMulticast() {
|
func (coll *Collector) sendMulticast() {
|
||||||
log.Println("sending multicasts")
|
log.Println("sending multicasts")
|
||||||
for _, conn := range coll.connections {
|
for _, conn := range coll.connections {
|
||||||
coll.sendPacket(conn, multiCastGroup)
|
coll.sendPacket(conn.Conn, conn.MulticastAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,21 +177,29 @@ func (coll *Collector) sendUnicasts(seenBefore jsontime.Time) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Send unicast packets
|
// Send unicast packets
|
||||||
log.Printf("sending unicast to %d nodes", len(nodes))
|
count := 0
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
conn := coll.ifaceToConn[node.Address.Zone]
|
send := 0
|
||||||
if conn == nil {
|
for _, conn := range coll.connections {
|
||||||
log.Printf("unable to find connection for %s", node.Address.Zone)
|
if node.Address.Zone != "" && conn.Conn.LocalAddr().(*net.UDPAddr).Zone != node.Address.Zone {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
coll.sendPacket(conn, node.Address.IP)
|
coll.sendPacket(conn.Conn, node.Address.IP)
|
||||||
time.Sleep(10 * time.Millisecond)
|
send++
|
||||||
}
|
}
|
||||||
|
if send == 0 {
|
||||||
|
log.Printf("unable to find connection for %s", node.Address.Zone)
|
||||||
|
} else {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
count += send
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Printf("sending %d unicast pkg for %d nodes", count, len(nodes))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendPacket sends a UDP request to the given unicast or multicast address on the first UDP socket
|
// SendPacket sends a UDP request to the given unicast or multicast address on the first UDP socket
|
||||||
func (coll *Collector) SendPacket(destination net.IP) {
|
func (coll *Collector) SendPacket(destination net.IP) {
|
||||||
coll.sendPacket(coll.connections[0], destination)
|
coll.sendPacket(coll.connections[0].Conn, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendPacket sends a UDP request to the given unicast or multicast address on the given UDP socket
|
// sendPacket sends a UDP request to the given unicast or multicast address on the given UDP socket
|
||||||
|
@ -201,7 +233,7 @@ func (coll *Collector) sender() {
|
||||||
func (coll *Collector) parser() {
|
func (coll *Collector) parser() {
|
||||||
for obj := range coll.queue {
|
for obj := range coll.queue {
|
||||||
if data, err := obj.parse(); err != nil {
|
if data, err := obj.parse(); err != nil {
|
||||||
log.Println("unable to decode response from", obj.Address.String(), err, "\n", string(obj.Raw))
|
log.Println("unable to decode response from", obj.Address.String(), err)
|
||||||
} else {
|
} else {
|
||||||
coll.saveResponse(obj.Address, data)
|
coll.saveResponse(obj.Address, data)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ const (
|
||||||
func TestCollector(t *testing.T) {
|
func TestCollector(t *testing.T) {
|
||||||
nodes := runtime.NewNodes(&runtime.NodesConfig{})
|
nodes := runtime.NewNodes(&runtime.NodesConfig{})
|
||||||
|
|
||||||
collector := NewCollector(nil, nodes, map[string][]string{SITE_TEST: {DOMAIN_TEST}}, []string{}, 10001)
|
collector := NewCollector(nil, nodes, map[string][]string{SITE_TEST: {DOMAIN_TEST}}, []InterfaceConfig{})
|
||||||
collector.Start(time.Millisecond)
|
collector.Start(time.Millisecond)
|
||||||
time.Sleep(time.Millisecond * 10)
|
time.Sleep(time.Millisecond * 10)
|
||||||
collector.Close()
|
collector.Close()
|
||||||
|
|
|
@ -5,9 +5,8 @@ import "github.com/FreifunkBremen/yanic/lib/duration"
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Enable bool `toml:"enable"`
|
Enable bool `toml:"enable"`
|
||||||
Synchronize duration.Duration `toml:"synchronize"`
|
Synchronize duration.Duration `toml:"synchronize"`
|
||||||
Interfaces []string `toml:"interfaces"`
|
Interfaces []InterfaceConfig `toml:"interfaces"`
|
||||||
Sites map[string]SiteConfig `toml:"sites"`
|
Sites map[string]SiteConfig `toml:"sites"`
|
||||||
Port int `toml:"port"`
|
|
||||||
CollectInterval duration.Duration `toml:"collect_interval"`
|
CollectInterval duration.Duration `toml:"collect_interval"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,3 +21,10 @@ func (c *Config) SitesDomains() (result map[string][]string) {
|
||||||
type SiteConfig struct {
|
type SiteConfig struct {
|
||||||
Domains []string `toml:"domains"`
|
Domains []string `toml:"domains"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InterfaceConfig struct {
|
||||||
|
InterfaceName string `toml:"ifname"`
|
||||||
|
IPAddress string `toml:"ip_address"`
|
||||||
|
MulticastAddress string `toml:"multicast_address"`
|
||||||
|
Port int `toml:"port"`
|
||||||
|
}
|
||||||
|
|
|
@ -4,10 +4,10 @@ import (
|
||||||
"net"
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
// default multicast group used by announced
|
|
||||||
var multiCastGroup = net.ParseIP("ff02:0:0:0:0:0:2:1001")
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// default multicast group used by announced
|
||||||
|
multicastAddressDefault = "ff02:0:0:0:0:0:2:1001"
|
||||||
|
|
||||||
// default udp port used by announced
|
// default udp port used by announced
|
||||||
port = 1001
|
port = 1001
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,10 @@ type Node struct {
|
||||||
// Link represents a link between two nodes
|
// Link represents a link between two nodes
|
||||||
type Link struct {
|
type Link struct {
|
||||||
SourceID string
|
SourceID string
|
||||||
SourceMAC string
|
SourceAddress string
|
||||||
TargetID string
|
TargetID string
|
||||||
TargetMAC string
|
TargetAddress string
|
||||||
TQ int
|
TQ float32
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsGateway returns whether the node is a gateway
|
// IsGateway returns whether the node is a gateway
|
||||||
|
|
|
@ -100,8 +100,8 @@ func (nodes *Nodes) Select(f func(*Node) bool) []*Node {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nodes *Nodes) GetNodeIDbyMAC(mac string) string {
|
func (nodes *Nodes) GetNodeIDbyAddress(addr string) string {
|
||||||
return nodes.ifaceToNodeID[mac]
|
return nodes.ifaceToNodeID[addr]
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeLinks returns a list of links to known neighbours
|
// NodeLinks returns a list of links to known neighbours
|
||||||
|
@ -117,10 +117,23 @@ func (nodes *Nodes) NodeLinks(node *Node) (result []Link) {
|
||||||
if neighbourID := nodes.ifaceToNodeID[neighbourMAC]; neighbourID != "" {
|
if neighbourID := nodes.ifaceToNodeID[neighbourMAC]; neighbourID != "" {
|
||||||
result = append(result, Link{
|
result = append(result, Link{
|
||||||
SourceID: neighbours.NodeID,
|
SourceID: neighbours.NodeID,
|
||||||
SourceMAC: sourceMAC,
|
SourceAddress: sourceMAC,
|
||||||
TargetID: neighbourID,
|
TargetID: neighbourID,
|
||||||
TargetMAC: neighbourMAC,
|
TargetAddress: neighbourMAC,
|
||||||
TQ: link.Tq,
|
TQ: float32(link.Tq) / 255.0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, iface := range neighbours.Babel {
|
||||||
|
for neighbourIP, link := range iface.Neighbours {
|
||||||
|
if neighbourID := nodes.ifaceToNodeID[neighbourIP]; neighbourID != "" {
|
||||||
|
result = append(result, Link{
|
||||||
|
SourceID: neighbours.NodeID,
|
||||||
|
SourceAddress: iface.LinkLocalAddress,
|
||||||
|
TargetID: neighbourID,
|
||||||
|
TargetAddress: neighbourIP,
|
||||||
|
TQ: 1.0 - (float32(link.Cost) / 65535.0),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,19 +192,19 @@ func (nodes *Nodes) readIfaces(nodeinfo *data.NodeInfo) {
|
||||||
|
|
||||||
addresses := []string{network.Mac}
|
addresses := []string{network.Mac}
|
||||||
|
|
||||||
for _, batinterface := range network.Mesh {
|
for _, iface := range network.Mesh {
|
||||||
addresses = append(addresses, batinterface.Addresses()...)
|
addresses = append(addresses, iface.Addresses()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, mac := range addresses {
|
for _, addr := range addresses {
|
||||||
if mac == "" {
|
if addr == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if oldNodeID, _ := nodes.ifaceToNodeID[mac]; oldNodeID != nodeID {
|
if oldNodeID, _ := nodes.ifaceToNodeID[addr]; oldNodeID != nodeID {
|
||||||
if oldNodeID != "" {
|
if oldNodeID != "" {
|
||||||
log.Printf("override nodeID from %s to %s on MAC address %s", oldNodeID, nodeID, mac)
|
log.Printf("override nodeID from %s to %s on MAC address %s", oldNodeID, nodeID, addr)
|
||||||
}
|
}
|
||||||
nodes.ifaceToNodeID[mac] = nodeID
|
nodes.ifaceToNodeID[addr] = nodeID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,7 +179,7 @@ func TestLinksNodes(t *testing.T) {
|
||||||
"f4:f2:6d:d7:a3:0b": {
|
"f4:f2:6d:d7:a3:0b": {
|
||||||
Neighbours: map[string]data.BatmanLink{
|
Neighbours: map[string]data.BatmanLink{
|
||||||
"f4:f2:6d:d7:a3:0a": {
|
"f4:f2:6d:d7:a3:0a": {
|
||||||
Tq: 200, Lastseen: 0.42,
|
Tq: 204, Lastseen: 0.42,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -198,11 +198,11 @@ func TestLinksNodes(t *testing.T) {
|
||||||
assert.Len(links, 1)
|
assert.Len(links, 1)
|
||||||
link := links[0]
|
link := links[0]
|
||||||
assert.Equal(link.SourceID, "f4f26dd7a30b")
|
assert.Equal(link.SourceID, "f4f26dd7a30b")
|
||||||
assert.Equal(link.SourceMAC, "f4:f2:6d:d7:a3:0b")
|
assert.Equal(link.SourceAddress, "f4:f2:6d:d7:a3:0b")
|
||||||
assert.Equal(link.TargetID, "f4f26dd7a30a")
|
assert.Equal(link.TargetID, "f4f26dd7a30a")
|
||||||
assert.Equal(link.TargetMAC, "f4:f2:6d:d7:a3:0a")
|
assert.Equal(link.TargetAddress, "f4:f2:6d:d7:a3:0a")
|
||||||
assert.Equal(link.TQ, 200)
|
assert.Equal(link.TQ, float32(0.8))
|
||||||
|
|
||||||
nodeid := nodes.GetNodeIDbyMAC("f4:f2:6d:d7:a3:0a")
|
nodeid := nodes.GetNodeIDbyAddress("f4:f2:6d:d7:a3:0a")
|
||||||
assert.Equal("f4f26dd7a30a", nodeid)
|
assert.Equal("f4f26dd7a30a", nodeid)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue