github.com/looshlee/cilium@v1.6.12/plugins/cilium-cni/chaining/flannel/flannel.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 flannel
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"fmt"
    21  
    22  	"github.com/cilium/cilium/api/v1/models"
    23  	"github.com/cilium/cilium/pkg/logging/logfields"
    24  	chainingapi "github.com/cilium/cilium/plugins/cilium-cni/chaining/api"
    25  
    26  	cniTypesVer "github.com/containernetworking/cni/pkg/types/current"
    27  	cniVersion "github.com/containernetworking/cni/pkg/version"
    28  	"github.com/sirupsen/logrus"
    29  	"github.com/vishvananda/netlink"
    30  )
    31  
    32  type flannelChainer struct{}
    33  
    34  func (f *flannelChainer) ImplementsAdd() bool {
    35  	return true
    36  }
    37  
    38  func (f *flannelChainer) Add(ctx context.Context, pluginCtx chainingapi.PluginContext) (res *cniTypesVer.Result, err error) {
    39  	err = cniVersion.ParsePrevResult(&pluginCtx.NetConf.NetConf)
    40  	if err != nil {
    41  		return nil, fmt.Errorf("unable to understand network config: %s", err)
    42  	}
    43  	r, err := cniTypesVer.GetResult(pluginCtx.NetConf.PrevResult)
    44  	if err != nil {
    45  		return nil, fmt.Errorf("unable to get previous network result: %s", err)
    46  	}
    47  	// We only care about the veth interface that is on the host side
    48  	// and cni0. Interfaces should be similar as:
    49  	//       "interfaces":[
    50  	//         {
    51  	//            "name":"cni0",
    52  	//            "mac":"0a:58:0a:f4:00:01"
    53  	//         },
    54  	//         {
    55  	//            "name":"veth15707e9b",
    56  	//            "mac":"4e:6d:93:35:6b:45"
    57  	//         },
    58  	//         {
    59  	//            "name":"eth0",
    60  	//            "mac":"0a:58:0a:f4:00:06",
    61  	//            "sandbox":"/proc/15259/ns/net"
    62  	//         }
    63  	//       ]
    64  
    65  	defer func() {
    66  		if err != nil {
    67  			pluginCtx.Logger.WithError(err).
    68  				WithFields(logrus.Fields{"cni-pre-result": pluginCtx.NetConf.PrevResult.String()}).
    69  				Errorf("Unable to create endpoint")
    70  		}
    71  	}()
    72  	var (
    73  		hostMac, vethHostName, vethLXCMac, vethIP string
    74  		vethHostIdx, vethSliceIdx                 int
    75  	)
    76  	for i, iDev := range r.Interfaces {
    77  		// We only care about the veth interface mac address on the container side.
    78  		if iDev.Sandbox != "" {
    79  			vethLXCMac = iDev.Mac
    80  			vethSliceIdx = i
    81  			continue
    82  		}
    83  
    84  		l, err := netlink.LinkByName(iDev.Name)
    85  		if err != nil {
    86  			continue
    87  		}
    88  		switch l.Type() {
    89  		case "veth":
    90  			vethHostName = iDev.Name
    91  			vethHostIdx = l.Attrs().Index
    92  		case "bridge":
    93  			// likely to be cni0
    94  			hostMac = iDev.Mac
    95  		}
    96  	}
    97  	for _, ipCfg := range r.IPs {
    98  		if ipCfg.Interface != nil && *ipCfg.Interface == vethSliceIdx {
    99  			vethIP = ipCfg.Address.IP.String()
   100  			break
   101  		}
   102  	}
   103  	switch {
   104  	case hostMac == "":
   105  		return nil, errors.New("unable to determine MAC address of bridge interface (cni0)")
   106  	case vethHostName == "":
   107  		return nil, errors.New("unable to determine name of veth pair on the host side")
   108  	case vethLXCMac == "":
   109  		return nil, errors.New("unable to determine MAC address of veth pair on the container side")
   110  	case vethIP == "":
   111  		return nil, errors.New("unable to determine IP address of the container")
   112  	case vethHostIdx == 0:
   113  		return nil, errors.New("unable to determine index interface of veth pair on the host side")
   114  	}
   115  
   116  	ep := &models.EndpointChangeRequest{
   117  		Addressing: &models.AddressPair{
   118  			IPV4: vethIP,
   119  		},
   120  		ContainerID:       pluginCtx.Args.ContainerID,
   121  		State:             models.EndpointStateWaitingForIdentity,
   122  		HostMac:           hostMac,
   123  		InterfaceIndex:    int64(vethHostIdx),
   124  		Mac:               vethLXCMac,
   125  		InterfaceName:     vethHostName,
   126  		K8sPodName:        string(pluginCtx.CniArgs.K8S_POD_NAME),
   127  		K8sNamespace:      string(pluginCtx.CniArgs.K8S_POD_NAMESPACE),
   128  		SyncBuildEndpoint: true,
   129  	}
   130  
   131  	err = pluginCtx.Client.EndpointCreate(ep)
   132  	if err != nil {
   133  		pluginCtx.Logger.WithError(err).WithFields(logrus.Fields{
   134  			logfields.ContainerID: ep.ContainerID}).Warn("Unable to create endpoint")
   135  		err = fmt.Errorf("unable to create endpoint: %s", err)
   136  		return
   137  	}
   138  
   139  	pluginCtx.Logger.WithFields(logrus.Fields{
   140  		logfields.ContainerID: ep.ContainerID}).Debug("Endpoint successfully created")
   141  	return r, nil
   142  }
   143  
   144  func (f *flannelChainer) ImplementsDelete() bool {
   145  	return false
   146  }
   147  
   148  func (f *flannelChainer) Delete(ctx context.Context, pluginCtx chainingapi.PluginContext) (err error) {
   149  	return nil
   150  }
   151  
   152  func init() {
   153  	chainingapi.Register("cbr0", &flannelChainer{})
   154  }