func setupENINetwork()

in pkg/networkutils/network.go [907:1020]


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)
	}

	_, ipnet, err := net.ParseCIDR(eniSubnetCIDR)
	if err != nil {
		return errors.Wrapf(err, "setupENINetwork: invalid IPv4 CIDR block %s", eniSubnetCIDR)
	}

	gw, err := IncrementIPv4Addr(ipnet.IP)
	if err != nil {
		return errors.Wrapf(err, "setupENINetwork: failed to define gateway address from %v", ipnet.IP)
	}

	// Explicitly set the IP on the device if not already set.
	// Required for older kernels.
	// ip addr show
	// ip add del <eniIP> dev <link> (if necessary)
	// ip add add <eniIP> dev <link>
	log.Debugf("Setting up ENI's primary IP %s", eniIP)
	addrs, err := netLink.AddrList(link, unix.AF_INET)
	if err != nil {
		return errors.Wrap(err, "setupENINetwork: failed to list IP address for ENI")
	}

	for _, addr := range addrs {
		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")
		}
	}
	eniAddr := &net.IPNet{
		IP:   net.ParseIP(eniIP),
		Mask: ipnet.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)
	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(32, 32)},
			Scope:     netlink.SCOPE_LINK,
			Table:     tableNumber,
		},
		// Route all other traffic via the host's ENI IP
		{
			LinkIndex: linkIndex,
			Dst:       &net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)},
			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
	_, cidr, err := net.ParseCIDR(eniSubnetCIDR)
	if err != nil {
		return errors.Wrapf(err, "setupENINetwork: invalid IPv4 CIDR block %s", eniSubnetCIDR)
	}
	defaultRoute := netlink.Route{
		Dst:   cidr,
		Src:   net.ParseIP(eniIP),
		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", cidr.String(), eniIP)
		}
	}
	return nil
}