github.com/looshlee/cilium@v1.6.12/plugins/cilium-cni/chaining/generic-veth/generic-veth.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 genericveth 16 17 import ( 18 "context" 19 "errors" 20 "fmt" 21 22 "github.com/cilium/cilium/api/v1/models" 23 endpointid "github.com/cilium/cilium/pkg/endpoint/id" 24 "github.com/cilium/cilium/pkg/logging" 25 "github.com/cilium/cilium/pkg/logging/logfields" 26 chainingapi "github.com/cilium/cilium/plugins/cilium-cni/chaining/api" 27 28 cniTypesVer "github.com/containernetworking/cni/pkg/types/current" 29 cniVersion "github.com/containernetworking/cni/pkg/version" 30 "github.com/containernetworking/plugins/pkg/ns" 31 "github.com/sirupsen/logrus" 32 "github.com/vishvananda/netlink" 33 ) 34 35 var ( 36 log = logging.DefaultLogger.WithField(logfields.LogSubsys, "generic-veth") 37 ) 38 39 type GenericVethChainer struct{} 40 41 func (f *GenericVethChainer) ImplementsAdd() bool { 42 return true 43 } 44 45 func (f *GenericVethChainer) Add(ctx context.Context, pluginCtx chainingapi.PluginContext) (res *cniTypesVer.Result, err error) { 46 err = cniVersion.ParsePrevResult(&pluginCtx.NetConf.NetConf) 47 if err != nil { 48 err = fmt.Errorf("unable to understand network config: %s", err) 49 return 50 } 51 52 var prevRes *cniTypesVer.Result 53 prevRes, err = cniTypesVer.NewResultFromResult(pluginCtx.NetConf.PrevResult) 54 if err != nil { 55 err = fmt.Errorf("unable to get previous network result: %s", err) 56 return 57 } 58 59 defer func() { 60 if err != nil { 61 pluginCtx.Logger.WithError(err). 62 WithFields(logrus.Fields{"cni-pre-result": pluginCtx.NetConf.PrevResult.String()}). 63 Errorf("Unable to create endpoint") 64 } 65 }() 66 var ( 67 hostMac, vethHostName, vethLXCMac, vethIP string 68 vethHostIdx, peerIndex int 69 peer netlink.Link 70 netNs ns.NetNS 71 ) 72 73 netNs, err = ns.GetNS(pluginCtx.Args.Netns) 74 if err != nil { 75 err = fmt.Errorf("failed to open netns %q: %s", pluginCtx.Args.Netns, err) 76 return 77 } 78 defer netNs.Close() 79 80 if err = netNs.Do(func(_ ns.NetNS) error { 81 links, err := netlink.LinkList() 82 if err != nil { 83 return err 84 } 85 86 for _, link := range links { 87 log.Debugf("Found interface in container %+v", link.Attrs()) 88 89 if link.Type() != "veth" { 90 continue 91 } 92 93 vethLXCMac = link.Attrs().HardwareAddr.String() 94 95 veth, ok := link.(*netlink.Veth) 96 if !ok { 97 return fmt.Errorf("link %s is not a veth interface", vethHostName) 98 } 99 100 peerIndex, err = netlink.VethPeerIndex(veth) 101 if err != nil { 102 return fmt.Errorf("unable to retrieve index of veth peer %s: %s", vethHostName, err) 103 } 104 105 addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) 106 if err != nil { 107 return fmt.Errorf("unable to list addresses for link %s: %s", link.Attrs().Name, err) 108 } 109 110 if len(addrs) < 1 { 111 return fmt.Errorf("no address configured inside container") 112 } 113 114 vethIP = addrs[0].IPNet.IP.String() 115 return nil 116 } 117 118 return fmt.Errorf("no link found inside container") 119 }); err != nil { 120 return 121 } 122 123 peer, err = netlink.LinkByIndex(peerIndex) 124 if err != nil { 125 err = fmt.Errorf("unable to lookup link %d: %s", peerIndex, err) 126 return 127 } 128 129 hostMac = peer.Attrs().HardwareAddr.String() 130 vethHostName = peer.Attrs().Name 131 vethHostIdx = peer.Attrs().Index 132 133 switch { 134 case vethHostName == "": 135 err = errors.New("unable to determine name of veth pair on the host side") 136 return 137 case vethLXCMac == "": 138 err = errors.New("unable to determine MAC address of veth pair on the container side") 139 return 140 case vethIP == "": 141 err = errors.New("unable to determine IP address of the container") 142 return 143 case vethHostIdx == 0: 144 err = errors.New("unable to determine index interface of veth pair on the host side") 145 return 146 } 147 148 var disabled = false 149 ep := &models.EndpointChangeRequest{ 150 Addressing: &models.AddressPair{ 151 IPV4: vethIP, 152 }, 153 ContainerID: pluginCtx.Args.ContainerID, 154 State: models.EndpointStateWaitingForIdentity, 155 HostMac: hostMac, 156 InterfaceIndex: int64(vethHostIdx), 157 Mac: vethLXCMac, 158 InterfaceName: vethHostName, 159 K8sPodName: string(pluginCtx.CniArgs.K8S_POD_NAME), 160 K8sNamespace: string(pluginCtx.CniArgs.K8S_POD_NAMESPACE), 161 SyncBuildEndpoint: true, 162 DatapathConfiguration: &models.EndpointDatapathConfiguration{ 163 // aws-cni requires ARP passthrough between Linux and 164 // the pod 165 RequireArpPassthrough: true, 166 167 // The route is pointing directly into the veth of the 168 // pod, install a host-facing egress program to 169 // implement ingress policy and to provide reverse NAT 170 RequireEgressProg: true, 171 172 // The IP is managed by the aws-cni plugin, no need for 173 // Cilium to manage any aspect of addressing 174 ExternalIPAM: true, 175 176 // All routing is performed by the Linux stack 177 RequireRouting: &disabled, 178 }, 179 } 180 181 err = pluginCtx.Client.EndpointCreate(ep) 182 if err != nil { 183 pluginCtx.Logger.WithError(err).WithFields(logrus.Fields{ 184 logfields.ContainerID: ep.ContainerID}).Warn("Unable to create endpoint") 185 err = fmt.Errorf("unable to create endpoint: %s", err) 186 return 187 } 188 189 pluginCtx.Logger.WithFields(logrus.Fields{ 190 logfields.ContainerID: ep.ContainerID}).Debug("Endpoint successfully created") 191 192 res = prevRes 193 194 return 195 } 196 197 func (f *GenericVethChainer) ImplementsDelete() bool { 198 return true 199 } 200 201 func (f *GenericVethChainer) Delete(ctx context.Context, pluginCtx chainingapi.PluginContext) (err error) { 202 id := endpointid.NewID(endpointid.ContainerIdPrefix, pluginCtx.Args.ContainerID) 203 if err := pluginCtx.Client.EndpointDelete(id); err != nil { 204 log.WithError(err).Warning("Errors encountered while deleting endpoint") 205 } 206 return nil 207 } 208 209 func init() { 210 chainingapi.Register("generic-veth", &GenericVethChainer{}) 211 }