github.com/looshlee/cilium@v1.6.12/plugins/cilium-cni/eni.go (about)

     1  // Copyright 2019 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"fmt"
    19  	"net"
    20  	"strings"
    21  
    22  	"github.com/cilium/cilium/api/v1/models"
    23  	"github.com/cilium/cilium/pkg/datapath/linux/route"
    24  
    25  	"github.com/containernetworking/cni/pkg/types/current"
    26  	"github.com/vishvananda/netlink"
    27  )
    28  
    29  func prepareENI(mac string, mtu int) (index int, err error) {
    30  	var links []netlink.Link
    31  
    32  	mac = strings.ToLower(mac)
    33  
    34  	links, err = netlink.LinkList()
    35  	if err != nil {
    36  		err = fmt.Errorf("unable to list interfaces: %s", err)
    37  		return
    38  	}
    39  
    40  	for _, link := range links {
    41  		if link.Attrs().HardwareAddr.String() == mac {
    42  			index = link.Attrs().Index
    43  
    44  			if err = netlink.LinkSetMTU(link, mtu); err != nil {
    45  				err = fmt.Errorf("unable to change MTU of link %s to %d: %s", link.Attrs().Name, mtu, err)
    46  				return
    47  			}
    48  
    49  			if err = netlink.LinkSetUp(link); err != nil {
    50  				err = fmt.Errorf("unable to up link %s: %s", link.Attrs().Name, err)
    51  				return
    52  			}
    53  
    54  			return
    55  		}
    56  	}
    57  
    58  	err = fmt.Errorf("interface with MAC %s not found", mac)
    59  	return
    60  }
    61  
    62  func eniAdd(ipConfig *current.IPConfig, ipam *models.IPAMAddressResponse, conf models.DaemonConfigurationStatus) error {
    63  	for _, cidrString := range ipam.Cidrs {
    64  		_, _, err := net.ParseCIDR(cidrString)
    65  		if err != nil {
    66  			return fmt.Errorf("invalid CIDR '%s': %s", cidrString, err)
    67  		}
    68  	}
    69  
    70  	if ipam.MasterMac == "" {
    71  		return fmt.Errorf("ENI master interface MAC address is not set")
    72  	}
    73  
    74  	ifindex, err := prepareENI(ipam.MasterMac, int(conf.DeviceMTU))
    75  	if err != nil {
    76  		return err
    77  	}
    78  
    79  	gatewayIP := net.ParseIP(ipam.Gateway)
    80  	if gatewayIP == nil {
    81  		return fmt.Errorf("unable to parse gateway IP %s", ipam.Gateway)
    82  	}
    83  
    84  	// Route all traffic to the ENI address via the main routing table
    85  	if err := route.ReplaceRule(route.Rule{
    86  		Priority: 20, // After encryption and proxy rules, before local table
    87  		To:       &ipConfig.Address,
    88  		Table:    route.MainTable,
    89  	}); err != nil {
    90  		return fmt.Errorf("unable to install ip rule: %s", err)
    91  	}
    92  
    93  	if conf.Masquerade {
    94  		for _, cidrString := range ipam.Cidrs {
    95  			// The cidr string is already verified, this can't fail
    96  			_, cidr, _ := net.ParseCIDR(cidrString)
    97  
    98  			// Lookup a VPC specific table for all traffic from an endpoint
    99  			// to the list of CIDRs configured for the VPC on which the
   100  			// endpoint has the IP on
   101  			if err := route.ReplaceRule(route.Rule{
   102  				Priority: 110, // After local table
   103  				From:     &ipConfig.Address,
   104  				To:       cidr,
   105  				Table:    ifindex,
   106  			}); err != nil {
   107  				return fmt.Errorf("unable to install ip rule: %s", err)
   108  			}
   109  		}
   110  	} else {
   111  		// Lookup a VPC specific table for all traffic from an endpoint
   112  		if err := route.ReplaceRule(route.Rule{
   113  			Priority: 110, // After local table
   114  			From:     &ipConfig.Address,
   115  			Table:    ifindex,
   116  		}); err != nil {
   117  			return fmt.Errorf("unable to install ip rule: %s", err)
   118  		}
   119  	}
   120  
   121  	// Nexthop route to the VPC or subnet gateway
   122  	//
   123  	// Note: This is a /32 route to avoid any L2. The endpoint does
   124  	// no L2 either.
   125  	if err := netlink.RouteReplace(&netlink.Route{
   126  		LinkIndex: ifindex,
   127  		Dst:       &net.IPNet{IP: gatewayIP, Mask: net.CIDRMask(32, 32)},
   128  		Scope:     netlink.SCOPE_LINK,
   129  		Table:     ifindex,
   130  	}); err != nil {
   131  		return fmt.Errorf("unable to add L2 nexthop route: %s", err)
   132  	}
   133  
   134  	// Default route to the VPC or subnet gateway
   135  	if err := netlink.RouteReplace(&netlink.Route{
   136  		Dst:   &net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)},
   137  		Table: ifindex,
   138  		Gw:    gatewayIP,
   139  	}); err != nil {
   140  		return fmt.Errorf("unable to add L2 nexthop route: %s", err)
   141  	}
   142  
   143  	return nil
   144  }