github.com/fafucoder/cilium@v1.6.11/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  }