Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consolidate ecs-eni plugin into vpc-eni plugin #101

Merged
merged 1 commit into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion network/eni/eni_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,18 @@ func (eni *ENI) SetOpState(up bool) error {
}

// SetNetNS sets the network namespace of the ENI.
// If ns argument is nil, the ENI is reset to the host network namespace.
func (eni *ENI) SetNetNS(ns netns.NetNS) error {
la := netlink.NewLinkAttrs()
la.Name = eni.linkName
link := &netlink.Dummy{LinkAttrs: la}
return netlink.LinkSetNsFd(link, int(ns.GetFd()))
if ns != nil {
// Move the ENI to the given network namespace.
return netlink.LinkSetNsFd(link, int(ns.GetFd()))
} else {
// PID 1 init is running in the host network namespace.
return netlink.LinkSetNsPid(link, 1)
}
}

// SetMACAddress sets the MAC address of the ENI.
Expand Down
3 changes: 3 additions & 0 deletions plugins/vpc-eni/config/netconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type NetConfig struct {
ENIMACAddress net.HardwareAddr
ENIIPAddresses []net.IPNet
GatewayIPAddresses []net.IP
OpState bool
UseExistingNetwork bool
BlockIMDS bool
}
Expand All @@ -43,6 +44,7 @@ type netConfigJSON struct {
ENIMACAddress string `json:"eniMACAddress"`
ENIIPAddresses []string `json:"eniIPAddresses"`
GatewayIPAddresses []string `json:"gatewayIPAddresses"`
OpStateDown bool `json:"opStateDown"`
UseExistingNetwork bool `json:"useExistingNetwork"`
BlockIMDS bool `json:"blockInstanceMetadata"`
}
Expand Down Expand Up @@ -79,6 +81,7 @@ func New(args *cniSkel.CmdArgs) (*NetConfig, error) {
netConfig := NetConfig{
NetConf: config.NetConf,
ENIName: config.ENIName,
OpState: !config.OpStateDown,
UseExistingNetwork: config.UseExistingNetwork,
BlockIMDS: config.BlockIMDS,
}
Expand Down
2 changes: 2 additions & 0 deletions plugins/vpc-eni/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ type Network struct {
type Endpoint struct {
ContainerID string
NetNSName string
ENIName string
MACAddress net.HardwareAddr
IPAddresses []net.IPNet
OpState bool
BlockIMDS bool
}
140 changes: 140 additions & 0 deletions plugins/vpc-eni/network/network_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,165 @@

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 {
amogh09 marked this conversation as resolved.
Show resolved Hide resolved
// 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
}
2 changes: 2 additions & 0 deletions plugins/vpc-eni/plugin/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,10 @@ func (plugin *Plugin) Add(args *cniSkel.CmdArgs) error {
ep := network.Endpoint{
ContainerID: args.ContainerID,
NetNSName: args.Netns,
ENIName: args.IfName,
MACAddress: netConfig.ENIMACAddress,
IPAddresses: netConfig.ENIIPAddresses,
OpState: netConfig.OpState,
BlockIMDS: netConfig.BlockIMDS,
}

Expand Down
6 changes: 4 additions & 2 deletions plugins/vpc-eni/vpc-eni.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
"cniVersion": "0.3.1",
"name": "vpc",
"type": "vpc-eni",
"eniName": "Ethernet 4",
"eniName": "eth1",
"eniMACAddress": "12:34:56:78:9a:bc",
"eniIPAddresses": ["192.168.1.42/24"],
"gatewayIPAddresses": ["192.168.1.1"],
"useExistingNetwork": "false"
"opStateDown": "false",
"useExistingNetwork": "false",
"blockInstanceMetadata": "false"
}