github.com/zhyoulun/cilium@v1.6.12/pkg/endpoint/connector/veth.go (about) 1 // Copyright 2016-2018 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 connector 16 17 import ( 18 "fmt" 19 "net" 20 21 "github.com/cilium/cilium/api/v1/models" 22 "github.com/cilium/cilium/pkg/datapath/link" 23 "github.com/cilium/cilium/pkg/logging/logfields" 24 "github.com/cilium/cilium/pkg/mac" 25 26 "github.com/containernetworking/plugins/pkg/ns" 27 28 "github.com/vishvananda/netlink" 29 ) 30 31 // SetupVethRemoteNs renames the netdevice in the target namespace to the 32 // provided dstIfName. 33 func SetupVethRemoteNs(netNs ns.NetNS, srcIfName, dstIfName string) (int, int, error) { 34 return 0, 0, netNs.Do(func(_ ns.NetNS) error { 35 err := link.Rename(srcIfName, dstIfName) 36 if err != nil { 37 return fmt.Errorf("failed to rename veth from %q to %q: %s", srcIfName, dstIfName, err) 38 } 39 return nil 40 }) 41 } 42 43 // SetupVeth sets up the net interface, the temporary interface and fills up some endpoint 44 // fields such as LXCMAC, NodeMac, IfIndex and IfName. Returns a pointer for the created 45 // veth, a pointer for the temporary link, the name of the temporary link and error if 46 // something fails. 47 func SetupVeth(id string, mtu int, ep *models.EndpointChangeRequest) (*netlink.Veth, *netlink.Link, string, error) { 48 if id == "" { 49 return nil, nil, "", fmt.Errorf("invalid: empty ID") 50 } 51 52 lxcIfName := Endpoint2IfName(id) 53 tmpIfName := Endpoint2TempIfName(id) 54 55 veth, link, err := SetupVethWithNames(lxcIfName, tmpIfName, mtu, ep) 56 return veth, link, tmpIfName, err 57 } 58 59 // SetupVethWithNames sets up the net interface, the temporary interface and fills up some endpoint 60 // fields such as LXCMAC, NodeMac, IfIndex and IfName. Returns a pointer for the created 61 // veth, a pointer for the temporary link, the name of the temporary link and error if 62 // something fails. 63 func SetupVethWithNames(lxcIfName, tmpIfName string, mtu int, ep *models.EndpointChangeRequest) (*netlink.Veth, *netlink.Link, error) { 64 var ( 65 epHostMAC, epLXCMAC mac.MAC 66 err error 67 ) 68 // systemd 242+ tries to set a "persistent" MAC addr for any virtual device 69 // by default (controlled by MACAddressPolicy). As setting happens 70 // asynchronously after a device has been created, ep.Mac and ep.HostMac 71 // can become stale which has a serious consequence - the kernel will drop 72 // any packet sent to/from the endpoint. However, we can trick systemd by 73 // explicitly setting MAC addrs for both veth ends. This sets 74 // addr_assign_type for NET_ADDR_SET which prevents systemd from changing 75 // the addrs. 76 epHostMAC, err = mac.GenerateRandMAC() 77 if err != nil { 78 return nil, nil, fmt.Errorf("unable to generate rnd mac addr: %s", err) 79 } 80 epLXCMAC, err = mac.GenerateRandMAC() 81 if err != nil { 82 return nil, nil, fmt.Errorf("unable to generate rnd mac addr: %s", err) 83 } 84 85 veth := &netlink.Veth{ 86 LinkAttrs: netlink.LinkAttrs{ 87 Name: lxcIfName, 88 HardwareAddr: net.HardwareAddr(epHostMAC), 89 }, 90 PeerName: tmpIfName, 91 PeerHardwareAddr: net.HardwareAddr(epLXCMAC), 92 } 93 94 if err := netlink.LinkAdd(veth); err != nil { 95 return nil, nil, fmt.Errorf("unable to create veth pair: %s", err) 96 } 97 defer func() { 98 if err != nil { 99 if err = netlink.LinkDel(veth); err != nil { 100 log.WithError(err).WithField(logfields.Veth, veth.Name).Warn("failed to clean up veth") 101 } 102 } 103 }() 104 105 log.WithField(logfields.VethPair, []string{veth.PeerName, lxcIfName}).Debug("Created veth pair") 106 107 // Disable reverse path filter on the host side veth peer to allow 108 // container addresses to be used as source address when the linux 109 // stack performs routing. 110 err = DisableRpFilter(lxcIfName) 111 if err != nil { 112 return nil, nil, err 113 } 114 115 peer, err := netlink.LinkByName(tmpIfName) 116 if err != nil { 117 return nil, nil, fmt.Errorf("unable to lookup veth peer just created: %s", err) 118 } 119 120 if err = netlink.LinkSetMTU(peer, mtu); err != nil { 121 return nil, nil, fmt.Errorf("unable to set MTU to %q: %s", tmpIfName, err) 122 } 123 124 hostVeth, err := netlink.LinkByName(lxcIfName) 125 if err != nil { 126 return nil, nil, fmt.Errorf("unable to lookup veth just created: %s", err) 127 } 128 129 if err = netlink.LinkSetMTU(hostVeth, mtu); err != nil { 130 return nil, nil, fmt.Errorf("unable to set MTU to %q: %s", lxcIfName, err) 131 } 132 133 if err = netlink.LinkSetUp(veth); err != nil { 134 return nil, nil, fmt.Errorf("unable to bring up veth pair: %s", err) 135 } 136 137 ep.Mac = peer.Attrs().HardwareAddr.String() 138 ep.HostMac = hostVeth.Attrs().HardwareAddr.String() 139 ep.InterfaceIndex = int64(hostVeth.Attrs().Index) 140 ep.InterfaceName = lxcIfName 141 142 return veth, &peer, nil 143 }