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