github.com/zhyoulun/cilium@v1.6.12/pkg/endpoint/connector/add.go (about) 1 // Copyright 2016-2017 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 "crypto/sha256" 19 "fmt" 20 "math/rand" 21 "net" 22 "os" 23 "path/filepath" 24 25 "github.com/cilium/cilium/api/v1/models" 26 "github.com/cilium/cilium/pkg/logging" 27 "github.com/cilium/cilium/pkg/logging/logfields" 28 29 "github.com/containernetworking/plugins/pkg/ns" 30 "github.com/vishvananda/netlink" 31 "golang.org/x/sys/unix" 32 ) 33 34 var log = logging.DefaultLogger.WithField(logfields.LogSubsys, "endpoint-connector") 35 36 const ( 37 // hostInterfacePrefix is the Host interface prefix. 38 hostInterfacePrefix = "lxc" 39 // temporaryInterfacePrefix is the temporary interface prefix while setting up libNetwork interface. 40 temporaryInterfacePrefix = "tmp" 41 ) 42 43 // Endpoint2IfName returns the host interface name for the given endpointID. 44 func Endpoint2IfName(endpointID string) string { 45 sum := fmt.Sprintf("%x", sha256.Sum256([]byte(endpointID))) 46 // returned string length should be < unix.IFNAMSIZ 47 truncateLength := uint(unix.IFNAMSIZ - len(temporaryInterfacePrefix) - 1) 48 return hostInterfacePrefix + truncateString(sum, truncateLength) 49 } 50 51 // Endpoint2TempIfName returns the temporary interface name for the given 52 // endpointID. 53 func Endpoint2TempIfName(endpointID string) string { 54 return temporaryInterfacePrefix + truncateString(endpointID, 5) 55 } 56 57 func randIfStr(num int) string { 58 str := make([]rune, num) 59 for i := range str { 60 str[i] = ifChars[rand.Intn(len(ifChars))] 61 } 62 return string(str) 63 } 64 65 // Endpoint2TempRandIfName returns a random, temporary interface name for the 66 // given endpointID. This is similar to Endpoint2TempIfName() but uses a 67 // random string instead of endpoint ID. 68 func Endpoint2TempRandIfName() string { 69 return temporaryInterfacePrefix + "_" + randIfStr(5) 70 } 71 72 var ifChars = []rune("abcdefghijklmnopqrstuvwxyz") 73 74 func truncateString(epID string, maxLen uint) string { 75 if maxLen <= uint(len(epID)) { 76 return epID[:maxLen] 77 } 78 return epID 79 } 80 81 // WriteSysConfig tries to emulate a sysctl call by writing directly to the 82 // given fileName the given value. 83 func WriteSysConfig(fileName, value string) error { 84 f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) 85 if err != nil { 86 return fmt.Errorf("unable to open configuration file: %s", err) 87 } 88 _, err = f.WriteString(value) 89 if err != nil { 90 f.Close() 91 return fmt.Errorf("unable to write value: %s", err) 92 } 93 err = f.Close() 94 if err != nil { 95 return fmt.Errorf("unable to close configuration file: %s", err) 96 } 97 return nil 98 } 99 100 // DisableRpFilter tries to disable rpfilter on specified interface 101 func DisableRpFilter(ifName string) error { 102 rpFilterPath := filepath.Join("/proc", "sys", "net", "ipv4", "conf", ifName, "rp_filter") 103 if err := WriteSysConfig(rpFilterPath, "0\n"); err != nil { 104 return fmt.Errorf("unable to disable %s: %s", rpFilterPath, err) 105 } 106 return nil 107 } 108 109 // GetNetInfoFromPID returns the index of the interface parent, the MAC address 110 // and IP address of the first interface that contains an IP address with global 111 // scope. 112 func GetNetInfoFromPID(pid int) (int, string, net.IP, error) { 113 netNs, err := ns.GetNS(fmt.Sprintf("/proc/%d/ns/net", pid)) 114 if err != nil { 115 return 0, "", nil, err 116 } 117 defer netNs.Close() 118 119 var ( 120 lxcMAC string 121 parentIndex int 122 ip net.IP 123 ) 124 125 err = netNs.Do(func(_ ns.NetNS) error { 126 links, err := netlink.LinkList() 127 if err != nil { 128 return err 129 } 130 for _, l := range links { 131 addrs, err := netlink.AddrList(l, netlink.FAMILY_V4) 132 if err != nil { 133 return err 134 } 135 for _, addr := range addrs { 136 if addr.IP.IsGlobalUnicast() { 137 ip = addr.IP 138 lxcMAC = l.Attrs().HardwareAddr.String() 139 parentIndex = l.Attrs().ParentIndex 140 log.Debugf("link found: %+v", l.Attrs()) 141 return nil 142 } 143 } 144 } 145 return nil 146 }) 147 return parentIndex, lxcMAC, ip, err 148 } 149 150 // GetVethInfo populates the given endpoint with the arguments provided where 151 // * nodeIfName - Node Interface Name 152 // * parentIdx - Interface Index of the container veth pair in the host side. 153 // * netNSMac - MAC address of the veth pair in the container side. 154 func GetVethInfo(nodeIfName string, parentIdx int, netNSMac string, ep *models.EndpointChangeRequest) error { 155 nodeVet, err := netlink.LinkByName(nodeIfName) 156 if err != nil { 157 return fmt.Errorf("unable to lookup veth just created: %s", err) 158 } 159 l, err := netlink.LinkByIndex(parentIdx) 160 if err != nil { 161 return err 162 } 163 ep.Mac = netNSMac 164 ep.HostMac = nodeVet.Attrs().HardwareAddr.String() 165 ep.InterfaceIndex = int64(parentIdx) 166 ep.InterfaceName = l.Attrs().Name 167 return nil 168 } 169 170 func DeriveEndpointFrom(hostDevice, containerID string, pid int) (*models.EndpointChangeRequest, error) { 171 parentIdx, lxcMAC, ip, err := GetNetInfoFromPID(pid) 172 if err != nil { 173 return nil, fmt.Errorf("unable to get net info from PID %d: %s", pid, err) 174 } 175 if parentIdx == 0 { 176 return nil, fmt.Errorf("unable to find master index interface for %s: %s", ip, err) 177 } 178 // _, ip6, err := ipam.AllocateNext("ipv6") 179 // if err != nil { 180 // return nil, fmt.Errorf("unable to allocate IPv6 address: %s", err) 181 // } 182 epModel := &models.EndpointChangeRequest{ 183 Addressing: &models.AddressPair{ 184 IPV4: ip.String(), 185 // IPV6: ip6.String(), 186 }, 187 ContainerID: containerID, 188 State: models.EndpointStateWaitingForIdentity, 189 } 190 err = GetVethInfo(hostDevice, parentIdx, lxcMAC, epModel) 191 if err != nil { 192 return nil, fmt.Errorf("unable to get veth info: %s", err) 193 194 } 195 return epModel, nil 196 }