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 }