Files
weave/net/bridge.go
T

111 lines
2.5 KiB
Go

package net
import (
"fmt"
"net"
"github.com/Sirupsen/logrus"
"github.com/vishvananda/netlink"
)
type BridgeType int
const (
WeaveBridgeName = "weave"
DatapathName = "datapath"
None BridgeType = iota
Bridge
Fastdp
BridgedFastdp
Inconsistent
)
func DetectBridgeType(weaveBridgeName, datapathName string) BridgeType {
bridge, _ := netlink.LinkByName(weaveBridgeName)
datapath, _ := netlink.LinkByName(datapathName)
switch {
case bridge == nil && datapath == nil:
return None
case isBridge(bridge) && datapath == nil:
return Bridge
case isDatapath(bridge) && datapath == nil:
return Fastdp
case isDatapath(datapath) && isBridge(bridge):
return BridgedFastdp
default:
return Inconsistent
}
}
func isBridge(link netlink.Link) bool {
_, isBridge := link.(*netlink.Bridge)
return isBridge
}
func isDatapath(link netlink.Link) bool {
switch link.(type) {
case *netlink.GenericLink:
return link.Type() == "openvswitch"
case *netlink.Device:
// Assume it's our openvswitch device, and the kernel has not been updated to report the kind.
return true
default:
return false
}
}
func DetectHairpin(portIfName string, log *logrus.Logger) error {
link, err := netlink.LinkByName(portIfName)
if err != nil {
return fmt.Errorf("Unable to find link %q: %s", portIfName, err)
}
ch := make(chan netlink.LinkUpdate)
// See EnsureInterface for why done channel is not passed
if err := netlink.LinkSubscribe(ch, nil); err != nil {
return fmt.Errorf("Unable to subscribe to netlink updates: %s", err)
}
pi, err := netlink.LinkGetProtinfo(link)
if err != nil {
return fmt.Errorf("Unable to get link protinfo %q: %s", portIfName, err)
}
if pi.Hairpin {
return fmt.Errorf("Hairpin mode enabled on %q", portIfName)
}
go func() {
for up := range ch {
if up.Attrs().Name == portIfName && up.Attrs().Protinfo != nil &&
up.Attrs().Protinfo.Hairpin {
log.Errorf("Hairpin mode enabled on %q", portIfName)
}
}
}()
return nil
}
var ErrBridgeNoIP = fmt.Errorf("Bridge has no IP address")
func FindBridgeIP(bridgeName string, subnet *net.IPNet) (net.IP, error) {
netdev, err := GetBridgeNetDev(bridgeName)
if err != nil {
return nil, fmt.Errorf("Failed to get netdev for %q bridge: %s", bridgeName, err)
}
if len(netdev.CIDRs) == 0 {
return nil, ErrBridgeNoIP
}
if subnet != nil {
for _, cidr := range netdev.CIDRs {
if subnet.Contains(cidr.IP) {
return cidr.IP, nil
}
}
}
// No subnet, or none in the required subnet; just return the first one
return netdev.CIDRs[0].IP, nil
}