func()

in plugins/vpc-shared-eni/network/bridge_linux.go [108:240]


func (nb *BridgeBuilder) FindOrCreateEndpoint(nw *Network, ep *Endpoint) error {
	// Derive endpoint names.
	cid := ep.ContainerID
	if len(cid) > 8 {
		cid = cid[:8]
	}
	vethLinkName := fmt.Sprintf(vethLinkNameFormat, cid)
	vethPeerName := vethLinkName + "-2"

	// Find the target network namespace.
	log.Infof("Searching for netns %s.", ep.NetNSName)
	targetNetNS, err := netns.GetNetNS(ep.NetNSName)
	if err != nil {
		log.Errorf("Failed to find netns %s: %v.", ep.NetNSName, err)
		return err
	}

	// Connect the bridge to the target network namespace with a veth pair.
	err = nb.createVethPair(nw.BridgeIndex, targetNetNS, vethLinkName, vethPeerName)
	if err != nil {
		log.Errorf("Failed to create veth pair %s: %v.", vethLinkName, err)
		return err
	}

	var epIPAddresses []net.IPNet
	var gatewayIPv4Address net.IP
	var gatewayIPv6Address net.IP
	var gatewayIPAddresses []net.IP
	var gatewayMACAddress net.HardwareAddr

	if nw.BridgeType == config.BridgeTypeL3 {
		// Configure the endpoint to relay the default gateway traffic to the on-link bridge.
		bridgeLink, err := netlink.LinkByIndex(nw.BridgeIndex)
		if err == nil {
			gatewayMACAddress = bridgeLink.Attrs().HardwareAddr
		}

		for _, ipAddr := range ep.IPAddresses {
			// Route ingress traffic for this IP address to the bridge.
			dst := ipAddr
			_, maskSize := dst.Mask.Size()
			dst.Mask = net.CIDRMask(maskSize, maskSize)

			route := &netlink.Route{
				LinkIndex: nw.BridgeIndex,
				Scope:     netlink.SCOPE_LINK,
				Dst:       &dst,
			}

			log.Infof("Adding IP route %+v to bridge.", route)
			err = netlink.RouteAdd(route)
			if err != nil && !os.IsExist(err) {
				log.Errorf("Failed to add IP route %+v: %v.", route, err)
				return err
			}

			// The endpoint IP addresses and default gateways are set differently based on the
			// address family.
			if ipAddr.IP.To4() != nil {
				// Assign the endpoint IPv4 address as-is with the actual subnet prefix length.
				epIPAddresses = append(epIPAddresses, ipAddr)

				// For IPv4, the actual VPC subnet default gateway is used as the default gateway.
				// If a gateway address was not specified, derive it from the endpoint's IP address.
				if gatewayIPv4Address == nil {
					if nw.GatewayIPAddress == nil {
						subnet, _ := vpc.NewSubnet(vpc.GetSubnetPrefix(&ipAddr))
						gatewayIPv4Address = subnet.Gateways[0]
					} else {
						gatewayIPv4Address = nw.GatewayIPAddress
					}
					gatewayIPAddresses = append(gatewayIPAddresses, gatewayIPv4Address)
				}
			} else {
				// Set the endpoint IPv6 address prefix length to address size. This essentially
				// disables neighbor discovery and forces the endpoint to send all egress traffic
				// to the default gateway.
				addr := ipAddr
				_, maskSize := addr.Mask.Size()
				addr.Mask = net.CIDRMask(maskSize, maskSize)
				epIPAddresses = append(epIPAddresses, addr)

				// For IPv6, the link-local address of the bridge is used as the default gateway.
				if gatewayIPv6Address == nil {
					addrs, _ := netlink.AddrList(bridgeLink, netlink.FAMILY_V6)
					for _, addr := range addrs {
						if netlink.Scope(addr.Scope) == netlink.SCOPE_LINK {
							gatewayIPv6Address = addr.IP
						}
					}
					gatewayIPAddresses = append(gatewayIPAddresses, gatewayIPv6Address)
				}
			}
		}
	}

	// Setup the target network namespace.
	err = targetNetNS.Run(func() error {
		ep.MACAddress, err = nb.setupTargetNetNS(
			vethPeerName, ep.IfType, ep.TapUserID, ep.IfName, epIPAddresses,
			gatewayIPAddresses, gatewayMACAddress)
		return err
	})
	if err != nil {
		log.Errorf("Failed to setup target netns: %v.", err)
		return err
	}

	if nw.BridgeType == config.BridgeTypeL2 {
		// Set MAC DNAT rule for translating ingress IP datagrams arriving on the shared ENI
		// sent to the endpoint IP address to endpoint MAC address.
		err = ebtables.NAT.Append(
			ebtables.PreRouting,
			&ebtables.Rule{
				Protocol: "IPv4",
				In:       nw.SharedENI.GetLinkName(),
				Match: &ebtables.IPv4Match{
					Dst: ep.IPAddresses[0].IP,
				},
				Target: &ebtables.DNATTarget{
					ToDst:  ep.MACAddress,
					Target: ebtables.Accept,
				},
			},
		)

		if err != nil {
			log.Errorf("Failed to append DNAT rule for veth link %s: %v.", vethLinkName, err)
		}
	}

	return nil
}