func TestSetupIPChains(t *testing.T) { // Create a test bridge with a basic bridge configuration (name + IPv4). defer testutils.SetupTestOSContext(t)() nh, err := netlink.NewHandle() if err != nil { t.Fatal(err) } driverconfig := &configuration{ EnableIPTables: true, } d := &driver{ config: driverconfig, } assertChainConfig(d, t) config := getBasicTestConfig() br := &bridgeInterface{nlh: nh} createTestBridge(config, br, t) assertBridgeConfig(config, br, d, t) config.EnableIPMasquerade = true assertBridgeConfig(config, br, d, t) config.EnableICC = true assertBridgeConfig(config, br, d, t) config.EnableIPMasquerade = false assertBridgeConfig(config, br, d, t) }
func TestSetupNewBridge(t *testing.T) { defer testutils.SetupTestOSContext(t)() nh, err := netlink.NewHandle() if err != nil { t.Fatal(err) } defer nh.Delete() config := &networkConfiguration{BridgeName: DefaultBridgeName} br := &bridgeInterface{nlh: nh} if err := setupDevice(config, br); err != nil { t.Fatalf("Bridge creation failed: %v", err) } if br.Link == nil { t.Fatal("bridgeInterface link is nil (expected valid link)") } if _, err := nh.LinkByName(DefaultBridgeName); err != nil { t.Fatalf("Failed to retrieve bridge device: %v", err) } if br.Link.Attrs().Flags&net.FlagUp == net.FlagUp { t.Fatalf("bridgeInterface should be created down") } }
func TestProgramIPTable(t *testing.T) { // Create a test bridge with a basic bridge configuration (name + IPv4). defer testutils.SetupTestOSContext(t)() nh, err := netlink.NewHandle() if err != nil { t.Fatal(err) } createTestBridge(getBasicTestConfig(), &bridgeInterface{nlh: nh}, t) // Store various iptables chain rules we care for. rules := []struct { rule iptRule descr string }{ {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-d", "127.1.2.3", "-i", "lo", "-o", "lo", "-j", "DROP"}}, "Test Loopback"}, {iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: []string{"-s", iptablesTestBridgeIP, "!", "-o", DefaultBridgeName, "-j", "MASQUERADE"}}, "NAT Test"}, {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "!", "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test ACCEPT NON_ICC OUTGOING"}, {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-o", DefaultBridgeName, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}}, "Test ACCEPT INCOMING"}, {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test enable ICC"}, {iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "DROP"}}, "Test disable ICC"}, } // Assert the chain rules' insertion and removal. for _, c := range rules { assertIPTableChainProgramming(c.rule, c.descr, t) } }
func TestSetupGatewayIPv6(t *testing.T) { defer testutils.SetupTestOSContext(t)() _, nw, _ := net.ParseCIDR("2001:db8:ea9:9abc:ffff::/80") gw := net.ParseIP("2001:db8:ea9:9abc:ffff::254") config := &networkConfiguration{ BridgeName: DefaultBridgeName, AddressIPv6: nw, DefaultGatewayIPv6: gw} nh, err := netlink.NewHandle() if err != nil { t.Fatal(err) } defer nh.Delete() br := &bridgeInterface{nlh: nh} if err := setupGatewayIPv6(config, br); err != nil { t.Fatalf("Set Default Gateway failed: %v", err) } if !gw.Equal(br.gatewayIPv6) { t.Fatalf("Set Default Gateway failed. Expected %v, Found %v", gw, br.gatewayIPv6) } }
func TestSetupGatewayIPv4(t *testing.T) { defer testutils.SetupTestOSContext(t)() nh, err := netlink.NewHandle() if err != nil { t.Fatal(err) } defer nh.Delete() ip, nw, _ := net.ParseCIDR("192.168.0.24/16") nw.IP = ip gw := net.ParseIP("192.168.2.254") config := &networkConfiguration{ BridgeName: DefaultBridgeName, DefaultGatewayIPv4: gw} br := &bridgeInterface{bridgeIPv4: nw, nlh: nh} if err := setupGatewayIPv4(config, br); err != nil { t.Fatalf("Set Default Gateway failed: %v", err) } if !gw.Equal(br.gatewayIPv4) { t.Fatalf("Set Default Gateway failed. Expected %v, Found %v", gw, br.gatewayIPv4) } }
// Init initializes a new network namespace func Init() { var err error initNs, err = netns.Get() if err != nil { log.Errorf("could not get initial namespace: %v", err) } initNl, err = netlink.NewHandle(getSupportedNlFamilies()...) if err != nil { log.Errorf("could not create netlink handle on initial namespace: %v", err) } }
func TestInterfaceDefaultName(t *testing.T) { defer testutils.SetupTestOSContext(t)() nh, err := netlink.NewHandle() if err != nil { t.Fatal(err) } config := &networkConfiguration{} if _ = newInterface(nh, config); config.BridgeName != DefaultBridgeName { t.Fatalf("Expected default interface name %q, got %q", DefaultBridgeName, config.BridgeName) } }
// Init initializes a new network namespace func Init() { var err error initNs, err = netns.Get() if err != nil { logrus.Errorf("could not get initial namespace: %v", err) } initNl, err = netlink.NewHandle(getSupportedNlFamilies()...) if err != nil { logrus.Errorf("could not create netlink handle on initial namespace: %v", err) } err = initNl.SetSocketTimeout(NetlinkSocketsTimeout) if err != nil { logrus.Warnf("Failed to set the timeout on the default netlink handle sockets: %v", err) } }
func setupVerifyTest(t *testing.T) *bridgeInterface { nh, err := netlink.NewHandle() if err != nil { t.Fatal(err) } inf := &bridgeInterface{nlh: nh} br := netlink.Bridge{} br.LinkAttrs.Name = "default0" if err := nh.LinkAdd(&br); err == nil { inf.Link = &br } else { t.Fatalf("Failed to create bridge interface: %v", err) } return inf }
func TestAddressesEmptyInterface(t *testing.T) { defer testutils.SetupTestOSContext(t)() nh, err := netlink.NewHandle() if err != nil { t.Fatal(err) } inf := newInterface(nh, &networkConfiguration{}) addrv4, addrsv6, err := inf.addresses() if err != nil { t.Fatalf("Failed to get addresses of default interface: %v", err) } if expected := (netlink.Addr{}); addrv4 != expected { t.Fatalf("Default interface has unexpected IPv4: %s", addrv4) } if len(addrsv6) != 0 { t.Fatalf("Default interface has unexpected IPv6: %v", addrsv6) } }
func TestDisableIPv6DAD(t *testing.T) { if testutils.RunningOnCircleCI() { t.Skipf("Skipping as not supported on CIRCLE CI kernel") } defer testutils.SetupTestOSContext(t)() ipv6, _ := types.ParseCIDR("2001:db8::44/64") iface := &nwIface{addressIPv6: ipv6} veth := &netlink.Veth{ LinkAttrs: netlink.LinkAttrs{Name: "sideA"}, PeerName: "sideB", } nlh, err := netlink.NewHandle(syscall.NETLINK_ROUTE) if err != nil { t.Fatal(err) } err = nlh.LinkAdd(veth) if err != nil { t.Fatal(err) } link, err := nlh.LinkByName("sideA") if err != nil { t.Fatal(err) } err = setInterfaceIPv6(nlh, link, iface) if err != nil { t.Fatal(err) } addrList, err := nlh.AddrList(link, nl.FAMILY_V6) if err != nil { t.Fatal(err) } if addrList[0].Flags&syscall.IFA_F_NODAD == 0 { t.Fatalf("Unexpected interface flags: 0x%x. Expected to contain 0x%x", addrList[0].Flags, syscall.IFA_F_NODAD) } }
func TestSetupIPv6(t *testing.T) { defer testutils.SetupTestOSContext(t)() nh, err := netlink.NewHandle() if err != nil { t.Fatal(err) } defer nh.Delete() config, br := setupTestInterface(t, nh) if err := setupBridgeIPv6(config, br); err != nil { t.Fatalf("Failed to setup bridge IPv6: %v", err) } procSetting, err := ioutil.ReadFile(fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", config.BridgeName)) if err != nil { t.Fatalf("Failed to read disable_ipv6 kernel setting: %v", err) } if expected := []byte("0\n"); bytes.Compare(expected, procSetting) != 0 { t.Fatalf("Invalid kernel setting disable_ipv6: expected %q, got %q", string(expected), string(procSetting)) } addrsv6, err := nh.AddrList(br.Link, netlink.FAMILY_V6) if err != nil { t.Fatalf("Failed to list device IPv6 addresses: %v", err) } var found bool for _, addr := range addrsv6 { if bridgeIPv6Str == addr.IPNet.String() { found = true break } } if !found { t.Fatalf("Bridge device does not have requested IPv6 address %v", bridgeIPv6Str) } }
func TestSetupNewNonDefaultBridge(t *testing.T) { defer testutils.SetupTestOSContext(t)() nh, err := netlink.NewHandle() if err != nil { t.Fatal(err) } defer nh.Delete() config := &networkConfiguration{BridgeName: "test0", DefaultBridge: true} br := &bridgeInterface{nlh: nh} err = setupDevice(config, br) if err == nil { t.Fatal("Expected bridge creation failure with \"non default name\", succeeded") } if _, ok := err.(NonDefaultBridgeExistError); !ok { t.Fatalf("Did not fail with expected error. Actual error: %v", err) } }
func TestSetupBridgeIPv4Fixed(t *testing.T) { defer testutils.SetupTestOSContext(t)() ip, netw, err := net.ParseCIDR("192.168.1.1/24") if err != nil { t.Fatalf("Failed to parse bridge IPv4: %v", err) } nh, err := netlink.NewHandle() if err != nil { t.Fatal(err) } defer nh.Delete() config, br := setupTestInterface(t, nh) config.AddressIPv4 = &net.IPNet{IP: ip, Mask: netw.Mask} if err := setupBridgeIPv4(config, br); err != nil { t.Fatalf("Failed to setup bridge IPv4: %v", err) } addrsv4, err := nh.AddrList(br.Link, netlink.FAMILY_V4) if err != nil { t.Fatalf("Failed to list device IPv4 addresses: %v", err) } var found bool for _, addr := range addrsv4 { if config.AddressIPv4.String() == addr.IPNet.String() { found = true break } } if !found { t.Fatalf("Bridge device does not have requested IPv4 address %v", config.AddressIPv4) } }
func TestSetupDeviceUp(t *testing.T) { defer testutils.SetupTestOSContext(t)() nh, err := netlink.NewHandle() if err != nil { t.Fatal(err) } defer nh.Delete() config := &networkConfiguration{BridgeName: DefaultBridgeName} br := &bridgeInterface{nlh: nh} if err := setupDevice(config, br); err != nil { t.Fatalf("Bridge creation failed: %v", err) } if err := setupDeviceUp(config, br); err != nil { t.Fatalf("Failed to up bridge device: %v", err) } lnk, _ := nh.LinkByName(DefaultBridgeName) if lnk.Attrs().Flags&net.FlagUp != net.FlagUp { t.Fatalf("bridgeInterface should be up") } }
func TestSetInterfaceIP(t *testing.T) { defer testutils.SetupTestOSContext(t)() ipv4, _ := types.ParseCIDR("172.30.0.33/24") ipv6, _ := types.ParseCIDR("2001:db8::44/64") iface := &nwIface{address: ipv4, addressIPv6: ipv6} nlh, err := netlink.NewHandle(syscall.NETLINK_ROUTE) if err != nil { t.Fatal(err) } if err := nlh.LinkAdd(&netlink.Veth{ LinkAttrs: netlink.LinkAttrs{Name: "sideA"}, PeerName: "sideB", }); err != nil { t.Fatal(err) } linkA, err := nlh.LinkByName("sideA") if err != nil { t.Fatal(err) } linkB, err := nlh.LinkByName("sideB") if err != nil { t.Fatal(err) } if err := nlh.LinkSetUp(linkA); err != nil { t.Fatal(err) } if err := nlh.LinkSetUp(linkB); err != nil { t.Fatal(err) } if err := setInterfaceIP(nlh, linkA, iface); err != nil { t.Fatal(err) } if err := setInterfaceIPv6(nlh, linkA, iface); err != nil { t.Fatal(err) } err = setInterfaceIP(nlh, linkB, iface) if err == nil { t.Fatalf("Expected route conflict error, but succeeded") } if !strings.Contains(err.Error(), "conflicts with existing route") { t.Fatalf("Unexpected error: %v", err) } err = setInterfaceIPv6(nlh, linkB, iface) if err == nil { t.Fatalf("Expected route conflict error, but succeeded") } if !strings.Contains(err.Error(), "conflicts with existing route") { t.Fatalf("Unexpected error: %v", err) } }
func (u *NetLinkProbe) start(nsPath string) { var context *common.NetNSContext var err error // Enter the network namespace if necessary if nsPath != "" { context, err = common.NewNetNsContext(nsPath) if err != nil { logging.GetLogger().Errorf("Failed to switch namespace: %s", err.Error()) return } } // Both NewHandle and Subscribe need to done in the network namespace. h, err := netlink.NewHandle(syscall.NETLINK_ROUTE) if err != nil { logging.GetLogger().Errorf("Failed to create netlink handle: %s", err.Error()) context.Close() return } defer h.Delete() s, err := nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_LINK, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR) if err != nil { logging.GetLogger().Errorf("Failed to subscribe to netlink messages: %s", err.Error()) context.Close() return } defer s.Close() u.ethtool, err = ethtool.NewEthtool() if err != nil { logging.GetLogger().Errorf("Failed to create ethtool object: %s", err.Error()) context.Close() return } defer u.ethtool.Close() epfd, e := syscall.EpollCreate1(0) if e != nil { logging.GetLogger().Errorf("Failed to create epoll: %s", err.Error()) return } defer syscall.Close(epfd) // Leave the network namespace context.Close() u.wg.Add(1) defer u.wg.Done() atomic.StoreInt64(&u.state, common.RunningState) defer atomic.StoreInt64(&u.state, common.StoppedState) u.netlink = h u.initialize() fd := s.GetFd() err = syscall.SetNonblock(fd, true) if err != nil { logging.GetLogger().Errorf("Failed to set the netlink fd as non-blocking: %s", err.Error()) return } event := syscall.EpollEvent{Events: syscall.EPOLLIN, Fd: int32(fd)} if err = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, fd, &event); err != nil { logging.GetLogger().Errorf("Failed to control epoll: %s", err.Error()) return } events := make([]syscall.EpollEvent, maxEpollEvents) for atomic.LoadInt64(&u.state) == common.RunningState { n, err := syscall.EpollWait(epfd, events[:], 1000) if err != nil { errno, ok := err.(syscall.Errno) if ok && errno != syscall.EINTR { logging.GetLogger().Errorf("Failed to receive from events from netlink: %s", err.Error()) } continue } if n == 0 { continue } msgs, err := s.Receive() if err != nil { if errno, ok := err.(syscall.Errno); !ok || !errno.Temporary() { logging.GetLogger().Errorf("Failed to receive from netlink messages: %s", err.Error()) return } time.Sleep(1 * time.Second) continue } for _, msg := range msgs { switch msg.Header.Type { case syscall.RTM_NEWLINK: link, err := netlink.LinkDeserialize(msg.Data) if err != nil { logging.GetLogger().Warningf("Failed to deserialize netlink message: %s", err.Error()) continue } u.onLinkAdded(link) case syscall.RTM_DELLINK: link, err := netlink.LinkDeserialize(msg.Data) if err != nil { logging.GetLogger().Warningf("Failed to deserialize netlink message: %s", err.Error()) continue } u.onLinkDeleted(link) case syscall.RTM_NEWADDR: addr, family, ifindex, err := parseAddr(msg.Data) if err != nil { logging.GetLogger().Warningf("Failed to parse newlink message: %s", err.Error()) continue } u.onAddressAdded(addr, family, ifindex) case syscall.RTM_DELADDR: addr, family, ifindex, err := parseAddr(msg.Data) if err != nil { logging.GetLogger().Warningf("Failed to parse newlink message: %s", err.Error()) continue } u.onAddressDeleted(addr, family, ifindex) } } } }