func setupENINetwork()

in pkg/networkutils/network.go [1022:1161]


func setupENINetwork(eniIP string, eniMAC string, deviceNumber int, eniSubnetCIDR string, netLink netlinkwrapper.NetLink,
	retryLinkByMacInterval time.Duration, retryRouteAddInterval time.Duration, mtu int) error {
	if deviceNumber == 0 {
		return errors.New("setupENINetwork should never be called on the primary ENI")
	}
	tableNumber := deviceNumber + 1
	log.Infof("Setting up network for an ENI with IP address %s, MAC address %s, CIDR %s and route table %d",
		eniIP, eniMAC, eniSubnetCIDR, tableNumber)
	link, err := linkByMac(eniMAC, netLink, retryLinkByMacInterval)
	if err != nil {
		return errors.Wrapf(err, "setupENINetwork: failed to find the link which uses MAC address %s", eniMAC)
	}

	if err = netLink.LinkSetMTU(link, mtu); err != nil {
		return errors.Wrapf(err, "setupENINetwork: failed to set MTU to %d for %s", mtu, eniIP)
	}

	if err = netLink.LinkSetUp(link); err != nil {
		return errors.Wrapf(err, "setupENINetwork: failed to bring up ENI %s", eniIP)
	}

	isV6 := strings.Contains(eniSubnetCIDR, ":")
	_, eniSubnetIPNet, err := net.ParseCIDR(eniSubnetCIDR)
	if err != nil {
		return errors.Wrapf(err, "setupENINetwork: invalid IP CIDR block %s", eniSubnetCIDR)
	}
	// Get gateway IP address for ENI
	var gw net.IP
	if isV6 {
		gw = GetIPv6Gateway()
	} else {
		gw = GetIPv4Gateway(eniSubnetIPNet)
	}

	// Explicitly delete IP addresses assigned to the device before assign ENI IP.
	// For IPv6, do not delete the link-local address.
	log.Debugf("Setting up ENI's primary IP %s", eniIP)
	var family int
	if isV6 {
		family = unix.AF_INET6
	} else {
		family = unix.AF_INET
	}
	var addrs []netlink.Addr
	addrs, err = netLink.AddrList(link, family)
	if err != nil {
		return errors.Wrap(err, "setupENINetwork: failed to list IP address for ENI")
	}

	for _, addr := range addrs {
		if addr.IP.IsGlobalUnicast() {
			log.Debugf("Deleting existing IP address %s", addr.String())
			if err = netLink.AddrDel(link, &addr); err != nil {
				return errors.Wrap(err, "setupENINetwork: failed to delete IP addr from ENI")
			}
		}
	}

	eniIPNet := net.ParseIP(eniIP)
	eniAddr := &net.IPNet{
		IP:   eniIPNet,
		Mask: eniSubnetIPNet.Mask,
	}
	log.Debugf("Adding IP address %s", eniAddr.String())
	if err = netLink.AddrAdd(link, &netlink.Addr{IPNet: eniAddr}); err != nil {
		return errors.Wrap(err, "setupENINetwork: failed to add IP addr to ENI")
	}

	linkIndex := link.Attrs().Index
	log.Debugf("Setting up ENI's default gateway %v, table %d, linkIndex %d", gw, tableNumber, linkIndex)
	mask := 32
	zeroAddr := net.IPv4zero
	if isV6 {
		mask = 128
		zeroAddr = net.IPv6zero
	}
	routes := []netlink.Route{
		// Add a direct link route for the host's ENI IP only
		{
			LinkIndex: linkIndex,
			Dst:       &net.IPNet{IP: gw, Mask: net.CIDRMask(mask, mask)},
			Scope:     netlink.SCOPE_LINK,
			Table:     tableNumber,
		},
		// Route all other traffic via the host's ENI IP
		{
			LinkIndex: linkIndex,
			Dst:       &net.IPNet{IP: zeroAddr, Mask: net.CIDRMask(0, mask)},
			Scope:     netlink.SCOPE_UNIVERSE,
			Gw:        gw,
			Table:     tableNumber,
		},
	}
	for _, r := range routes {
		err := netLink.RouteDel(&r)
		if err != nil && !netlinkwrapper.IsNotExistsError(err) {
			return errors.Wrap(err, "setupENINetwork: failed to clean up old routes")
		}

		err = retry.NWithBackoff(retry.NewSimpleBackoff(500*time.Millisecond, retryRouteAddInterval, 0.15, 2.0), maxRetryRouteAdd, func() error {
			if err := netLink.RouteReplace(&r); err != nil {
				log.Debugf("Not able to set route %s/0 via %s table %d", r.Dst.IP.String(), gw.String(), tableNumber)
				return errors.Wrapf(err, "setupENINetwork: unable to replace route entry %s", r.Dst.IP.String())
			}
			log.Debugf("Successfully added/replaced route to be %s/0", r.Dst.IP.String())
			return nil
		})
		if err != nil {
			return err
		}
	}

	// Remove the route that default out to ENI-x out of main route table
	var defaultRoute netlink.Route
	if isV6 {
		defaultRoute = netlink.Route{
			LinkIndex: linkIndex,
			Dst:       eniSubnetIPNet,
			Table:     mainRoutingTable,
		}
	} else {
		// eniSubnetIPNet was modified by GetIPv4Gateway, so the string must be parsed again
		_, eniSubnetCIDRNet, err := net.ParseCIDR(eniSubnetCIDR)
		if err != nil {
			return errors.Wrapf(err, "setupENINetwork: invalid IPv4 CIDR block: %s", eniSubnetCIDR)
		}
		defaultRoute = netlink.Route{
			Dst:   eniSubnetCIDRNet,
			Src:   eniIPNet,
			Table: mainRoutingTable,
			Scope: netlink.SCOPE_LINK,
		}
	}
	if err := netLink.RouteDel(&defaultRoute); err != nil {
		if !netlinkwrapper.IsNotExistsError(err) {
			return errors.Wrapf(err, "setupENINetwork: unable to delete default route %s for source IP %s", eniSubnetIPNet.String(), eniIP)
		}
	}
	return nil
}