github.com/cilium/cilium@v1.16.2/pkg/datapath/connector/veth.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package connector 5 6 import ( 7 "fmt" 8 "net" 9 10 "github.com/vishvananda/netlink" 11 12 "github.com/cilium/cilium/api/v1/models" 13 "github.com/cilium/cilium/pkg/datapath/link" 14 "github.com/cilium/cilium/pkg/datapath/linux/sysctl" 15 "github.com/cilium/cilium/pkg/logging/logfields" 16 "github.com/cilium/cilium/pkg/mac" 17 "github.com/cilium/cilium/pkg/netns" 18 ) 19 20 // SetupVethRemoteNs renames the netdevice in the target namespace to the 21 // provided dstIfName. 22 func SetupVethRemoteNs(ns *netns.NetNS, srcIfName, dstIfName string) error { 23 return ns.Do(func() error { 24 err := link.Rename(srcIfName, dstIfName) 25 if err != nil { 26 return fmt.Errorf("failed to rename veth from %q to %q: %w", srcIfName, dstIfName, err) 27 } 28 return nil 29 }) 30 } 31 32 // SetupVeth sets up the net interface, the temporary interface and fills up some endpoint 33 // fields such as mac, NodeMac, ifIndex and ifName. Returns a pointer for the created 34 // veth, a pointer for the temporary link, the name of the temporary link and error if 35 // something fails. 36 func SetupVeth(id string, mtu, groIPv6MaxSize, gsoIPv6MaxSize, groIPv4MaxSize, gsoIPv4MaxSize int, ep *models.EndpointChangeRequest, sysctl sysctl.Sysctl) (*netlink.Veth, netlink.Link, string, error) { 37 if id == "" { 38 return nil, nil, "", fmt.Errorf("invalid: empty ID") 39 } 40 41 lxcIfName := Endpoint2IfName(id) 42 tmpIfName := Endpoint2TempIfName(id) 43 44 veth, link, err := SetupVethWithNames(lxcIfName, tmpIfName, mtu, 45 groIPv6MaxSize, gsoIPv6MaxSize, groIPv4MaxSize, gsoIPv4MaxSize, ep, sysctl) 46 return veth, link, tmpIfName, err 47 } 48 49 // SetupVethWithNames sets up the net interface, the peer interface and fills up some endpoint 50 // fields such as mac, NodeMac, ifIndex and ifName. Returns a pointer for the created 51 // veth, a pointer for the peer link and error if something fails. 52 func SetupVethWithNames(lxcIfName, peerIfName string, mtu, groIPv6MaxSize, gsoIPv6MaxSize, groIPv4MaxSize, gsoIPv4MaxSize int, ep *models.EndpointChangeRequest, sysctl sysctl.Sysctl) (*netlink.Veth, netlink.Link, error) { 53 // systemd 242+ tries to set a "persistent" MAC addr for any virtual device 54 // by default (controlled by MACAddressPolicy). As setting happens 55 // asynchronously after a device has been created, ep.Mac and ep.HostMac 56 // can become stale which has a serious consequence - the kernel will drop 57 // any packet sent to/from the endpoint. However, we can trick systemd by 58 // explicitly setting MAC addrs for both veth ends. This sets 59 // addr_assign_type for NET_ADDR_SET which prevents systemd from changing 60 // the addrs. 61 epHostMAC, err := mac.GenerateRandMAC() 62 if err != nil { 63 return nil, nil, fmt.Errorf("unable to generate rnd mac addr: %w", err) 64 } 65 epLXCMAC, err := mac.GenerateRandMAC() 66 if err != nil { 67 return nil, nil, fmt.Errorf("unable to generate rnd mac addr: %w", err) 68 } 69 70 veth := &netlink.Veth{ 71 LinkAttrs: netlink.LinkAttrs{ 72 Name: lxcIfName, 73 HardwareAddr: net.HardwareAddr(epHostMAC), 74 TxQLen: 1000, 75 }, 76 PeerName: peerIfName, 77 PeerHardwareAddr: net.HardwareAddr(epLXCMAC), 78 } 79 80 if err := netlink.LinkAdd(veth); err != nil { 81 return nil, nil, fmt.Errorf("unable to create veth pair: %w", err) 82 } 83 defer func() { 84 if err != nil { 85 if err = netlink.LinkDel(veth); err != nil { 86 log.WithError(err).WithField(logfields.Veth, veth.Name).Warn("failed to clean up veth") 87 } 88 } 89 }() 90 91 log.WithField(logfields.VethPair, []string{veth.PeerName, lxcIfName}).Debug("Created veth pair") 92 93 // Disable reverse path filter on the host side veth peer to allow 94 // container addresses to be used as source address when the linux 95 // stack performs routing. 96 err = DisableRpFilter(sysctl, lxcIfName) 97 if err != nil { 98 return nil, nil, err 99 } 100 101 peer, err := netlink.LinkByName(peerIfName) 102 if err != nil { 103 return nil, nil, fmt.Errorf("unable to lookup veth peer just created: %w", err) 104 } 105 106 if err = netlink.LinkSetMTU(peer, mtu); err != nil { 107 return nil, nil, fmt.Errorf("unable to set MTU to %q: %w", peerIfName, err) 108 } 109 110 hostVeth, err := netlink.LinkByName(lxcIfName) 111 if err != nil { 112 return nil, nil, fmt.Errorf("unable to lookup veth just created: %w", err) 113 } 114 115 if err = netlink.LinkSetMTU(hostVeth, mtu); err != nil { 116 return nil, nil, fmt.Errorf("unable to set MTU to %q: %w", lxcIfName, err) 117 } 118 119 if err = netlink.LinkSetUp(veth); err != nil { 120 return nil, nil, fmt.Errorf("unable to bring up veth pair: %w", err) 121 } 122 123 if groIPv6MaxSize > 0 { 124 if err = netlink.LinkSetGROMaxSize(hostVeth, groIPv6MaxSize); err != nil { 125 return nil, nil, fmt.Errorf("unable to set GRO max size to %q: %w", 126 lxcIfName, err) 127 } 128 if err = netlink.LinkSetGROMaxSize(peer, groIPv6MaxSize); err != nil { 129 return nil, nil, fmt.Errorf("unable to set GRO max size to %q: %w", 130 peerIfName, err) 131 } 132 } 133 134 if gsoIPv6MaxSize > 0 { 135 if err = netlink.LinkSetGSOMaxSize(hostVeth, gsoIPv6MaxSize); err != nil { 136 return nil, nil, fmt.Errorf("unable to set GSO max size to %q: %w", 137 lxcIfName, err) 138 } 139 if err = netlink.LinkSetGSOMaxSize(peer, gsoIPv6MaxSize); err != nil { 140 return nil, nil, fmt.Errorf("unable to set GSO max size to %q: %w", 141 peerIfName, err) 142 } 143 } 144 145 if groIPv4MaxSize > 0 { 146 if err = netlink.LinkSetGROIPv4MaxSize(hostVeth, groIPv4MaxSize); err != nil { 147 return nil, nil, fmt.Errorf("unable to set GRO max size to %q: %w", 148 lxcIfName, err) 149 } 150 if err = netlink.LinkSetGROIPv4MaxSize(peer, groIPv4MaxSize); err != nil { 151 return nil, nil, fmt.Errorf("unable to set GRO max size to %q: %w", 152 peerIfName, err) 153 } 154 } 155 156 if gsoIPv4MaxSize > 0 { 157 if err = netlink.LinkSetGSOIPv4MaxSize(hostVeth, gsoIPv4MaxSize); err != nil { 158 return nil, nil, fmt.Errorf("unable to set GSO max size to %q: %w", 159 lxcIfName, err) 160 } 161 if err = netlink.LinkSetGSOIPv4MaxSize(peer, gsoIPv4MaxSize); err != nil { 162 return nil, nil, fmt.Errorf("unable to set GSO max size to %q: %w", 163 peerIfName, err) 164 } 165 } 166 167 ep.Mac = peer.Attrs().HardwareAddr.String() 168 ep.HostMac = hostVeth.Attrs().HardwareAddr.String() 169 ep.InterfaceIndex = int64(hostVeth.Attrs().Index) 170 ep.InterfaceName = lxcIfName 171 172 return veth, peer, nil 173 }