// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may // not use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either // express or implied. See the License for the specific language governing // permissions and limitations under the License. package network import ( "fmt" "github.com/aws/amazon-vpc-cni-plugins/network/imds" "github.com/aws/amazon-vpc-cni-plugins/network/netns" log "github.com/cihub/seelog" "github.com/vishvananda/netlink" ) // NetBuilder implements the Builder interface for Linux. type NetBuilder struct{} // FindOrCreateNetwork creates a new network. func (nb *NetBuilder) FindOrCreateNetwork(nw *Network) error { // Vpc-eni does not need any network-level setup on Linux. return nil } // DeleteNetwork deletes an existing network. func (nb *NetBuilder) DeleteNetwork(nw *Network) error { // Vpc-eni does not need any network-level cleanup on Linux. return nil } // FindOrCreateEndpoint creates a new endpoint in the network. func (nb *NetBuilder) FindOrCreateEndpoint(nw *Network, ep *Endpoint) error { // Find the network namespace. log.Infof("Searching for netns %s.", ep.NetNSName) ns, err := netns.GetNetNS(ep.NetNSName) if err != nil { log.Errorf("Failed to find netns %s: %v.", ep.NetNSName, err) return err } eni := nw.ENI err = eni.AttachToLink() if err != nil { log.Errorf("Failed to find ENI %s: %v", eni, err) return err } log.Infof("Moving ENI link %s to netns %s.", eni, ep.NetNSName) err = eni.SetNetNS(ns) if err != nil { log.Errorf("Failed to move eni: %v.", err) return err } // If operational state is down, there is no need to configure anything else. if !ep.OpState { return nil } // Complete the remaining setup in target network namespace. err = ns.Run(func() error { // Rename the ENI link to the requested interface name. if eni.GetLinkName() != ep.ENIName { log.Infof("Renaming ENI link %v to %s.", eni, ep.ENIName) err := eni.SetLinkName(ep.ENIName) if err != nil { log.Errorf("Failed to rename ENI link %v: %v.", eni, err) return err } } // Add a blackhole route for IMDS endpoint if required. if ep.BlockIMDS { err = imds.BlockInstanceMetadataEndpoint() if err != nil { return err } } // Set ENI IP addresses if specified. for _, ipAddress := range ep.IPAddresses { // Assign the IP address. err = eni.AddIPAddress(&ipAddress) if err != nil { log.Errorf("Failed to assign IP address to eni %v: %v.", eni, err) return err } } log.Infof("Setting ENI link state up.") err = eni.SetOpState(true) if err != nil { log.Errorf("Failed to set link %v state: %v.", eni, err) return err } // Set default gateways if specified. for _, gatewayIPAddress := range nw.GatewayIPAddresses { // Add default route via ENI link. route := &netlink.Route{ Gw: gatewayIPAddress, LinkIndex: eni.GetLinkIndex(), } log.Infof("Adding default IP route %+v.", route) err = netlink.RouteAdd(route) if err != nil { log.Errorf("Failed to add IP route %+v via ENI %v: %v.", route, eni, err) return err } } return err }) return nil } // DeleteEndpoint deletes an existing endpoint. func (nb *NetBuilder) DeleteEndpoint(nw *Network, ep *Endpoint) error { // Search for the target network namespace. netns, err := netns.GetNetNS(ep.NetNSName) if err != nil { // Log and ignore the failure. DEL can be called multiple times and thus must be idempotent. log.Errorf("Failed to find netns %s, ignoring: %v.", ep.NetNSName, err) return nil } // In target network namespace... err = netns.Run(func() error { eni := nw.ENI err = eni.AttachToLink() if err != nil { log.Errorf("Failed to find ENI %s: %v", eni, err) return err } log.Infof("Setting ENI link state down.") err = eni.SetOpState(false) if err != nil { log.Errorf("Failed to set link %v state: %v.", eni, err) return err } // Rename the ENI link to its MAC address to avoid naming conflicts in host netns. eniName := fmt.Sprintf("ecs%x%x%x", ep.MACAddress[0], ep.MACAddress[1], ep.MACAddress[2]) log.Infof("Renaming ENI link %v to %s.", eni, eniName) err := eni.SetLinkName(eniName) if err != nil { log.Errorf("Failed to rename ENI link %v: %v.", eni, err) return err } log.Infof("Moving ENI link %s to host netns.", eni) err = eni.SetNetNS(nil) if err != nil { log.Errorf("Failed to move eni: %v.", err) return err } return nil }) if err != nil { log.Errorf("Failed to set netns to host, ignoring: %v.", err) } return nil }