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
}