github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/virtcontainers/tuntap_endpoint.go (about) 1 // Copyright (c) 2018 Huawei Corporation 2 // Copyright (c) 2019 Intel Corporation 3 // 4 // SPDX-License-Identifier: Apache-2.0 5 // 6 7 package virtcontainers 8 9 import ( 10 "fmt" 11 "net" 12 13 "github.com/containernetworking/plugins/pkg/ns" 14 "github.com/vishvananda/netlink" 15 16 persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api" 17 vcTypes "github.com/kata-containers/runtime/virtcontainers/pkg/types" 18 ) 19 20 // TuntapEndpoint represents just a tap endpoint 21 type TuntapEndpoint struct { 22 NetPair NetworkInterfacePair 23 TuntapInterface TuntapInterface 24 EndpointProperties NetworkInfo 25 EndpointType EndpointType 26 PCIPath vcTypes.PciPath 27 } 28 29 // Properties returns the properties of the tap interface. 30 func (endpoint *TuntapEndpoint) Properties() NetworkInfo { 31 return endpoint.EndpointProperties 32 } 33 34 // Name returns name of the tap interface in the network pair. 35 func (endpoint *TuntapEndpoint) Name() string { 36 return endpoint.TuntapInterface.Name 37 } 38 39 // HardwareAddr returns the mac address that is assigned to the tap interface 40 func (endpoint *TuntapEndpoint) HardwareAddr() string { 41 return endpoint.TuntapInterface.TAPIface.HardAddr 42 } 43 44 // Type identifies the endpoint as a tap endpoint. 45 func (endpoint *TuntapEndpoint) Type() EndpointType { 46 return endpoint.EndpointType 47 } 48 49 // PciPath returns the PCI path of the endpoint. 50 func (endpoint *TuntapEndpoint) PciPath() vcTypes.PciPath { 51 return endpoint.PCIPath 52 } 53 54 // SetPciPath sets the PCI path of the endpoint. 55 func (endpoint *TuntapEndpoint) SetPciPath(pciPath vcTypes.PciPath) { 56 endpoint.PCIPath = pciPath 57 } 58 59 // NetworkPair returns the network pair of the endpoint. 60 func (endpoint *TuntapEndpoint) NetworkPair() *NetworkInterfacePair { 61 return &endpoint.NetPair 62 } 63 64 // SetProperties sets the properties for the endpoint. 65 func (endpoint *TuntapEndpoint) SetProperties(properties NetworkInfo) { 66 endpoint.EndpointProperties = properties 67 } 68 69 // Attach for tap endpoint adds the tap interface to the hypervisor. 70 func (endpoint *TuntapEndpoint) Attach(s *Sandbox) error { 71 h := s.hypervisor 72 if err := xConnectVMNetwork(endpoint, h); err != nil { 73 networkLogger().WithError(err).Error("Error bridging virtual endpoint") 74 return err 75 } 76 return h.addDevice(endpoint, netDev) 77 } 78 79 // Detach for the tap endpoint tears down the tap 80 func (endpoint *TuntapEndpoint) Detach(netNsCreated bool, netNsPath string) error { 81 if !netNsCreated && netNsPath != "" { 82 return nil 83 } 84 85 networkLogger().WithField("endpoint-type", TuntapEndpointType).Info("Detaching endpoint") 86 return doNetNS(netNsPath, func(_ ns.NetNS) error { 87 return unTuntapNetwork(endpoint.TuntapInterface.TAPIface.Name) 88 }) 89 } 90 91 // HotAttach for the tap endpoint uses hot plug device 92 func (endpoint *TuntapEndpoint) HotAttach(h hypervisor) error { 93 networkLogger().Info("Hot attaching tap endpoint") 94 if err := tuntapNetwork(endpoint, h.hypervisorConfig().NumVCPUs, h.hypervisorConfig().DisableVhostNet); err != nil { 95 networkLogger().WithError(err).Error("Error bridging tap ep") 96 return err 97 } 98 99 if _, err := h.hotplugAddDevice(endpoint, netDev); err != nil { 100 networkLogger().WithError(err).Error("Error attach tap ep") 101 return err 102 } 103 return nil 104 } 105 106 // HotDetach for the tap endpoint uses hot pull device 107 func (endpoint *TuntapEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error { 108 networkLogger().Info("Hot detaching tap endpoint") 109 if err := doNetNS(netNsPath, func(_ ns.NetNS) error { 110 return unTuntapNetwork(endpoint.TuntapInterface.TAPIface.Name) 111 }); err != nil { 112 networkLogger().WithError(err).Warn("Error un-bridging tap ep") 113 } 114 115 if _, err := h.hotplugRemoveDevice(endpoint, netDev); err != nil { 116 networkLogger().WithError(err).Error("Error detach tap ep") 117 return err 118 } 119 return nil 120 } 121 122 func createTuntapNetworkEndpoint(idx int, ifName string, hwName net.HardwareAddr, internetworkingModel NetInterworkingModel) (*TuntapEndpoint, error) { 123 if idx < 0 { 124 return &TuntapEndpoint{}, fmt.Errorf("invalid network endpoint index: %d", idx) 125 } 126 127 netPair, err := createNetworkInterfacePair(idx, ifName, internetworkingModel) 128 if err != nil { 129 return nil, err 130 } 131 132 endpoint := &TuntapEndpoint{ 133 NetPair: netPair, 134 TuntapInterface: TuntapInterface{ 135 Name: fmt.Sprintf("eth%d", idx), 136 TAPIface: NetworkInterface{ 137 Name: fmt.Sprintf("tap%d_kata", idx), 138 HardAddr: fmt.Sprintf("%s", hwName), //nolint:gosimple 139 }, 140 }, 141 EndpointType: TuntapEndpointType, 142 } 143 144 if ifName != "" { 145 endpoint.TuntapInterface.Name = ifName 146 } 147 148 return endpoint, nil 149 } 150 151 func tuntapNetwork(endpoint *TuntapEndpoint, numCPUs uint32, disableVhostNet bool) error { 152 netHandle, err := netlink.NewHandle() 153 if err != nil { 154 return err 155 } 156 defer netHandle.Delete() 157 158 tapLink, _, err := createLink(netHandle, endpoint.TuntapInterface.TAPIface.Name, &netlink.Tuntap{}, int(numCPUs)) 159 if err != nil { 160 return fmt.Errorf("Could not create TAP interface: %s", err) 161 } 162 linkAttrs := endpoint.Properties().Iface.LinkAttrs 163 164 // Save the MAC address to the TAP so that it can later be used 165 // to build the QMP command line. This MAC address has to be 166 // the one inside the VM in order to avoid any firewall issues. The 167 // bridge created by the network plugin on the host actually expects 168 // to see traffic from this MAC address and not another one. 169 endpoint.TuntapInterface.TAPIface.HardAddr = linkAttrs.HardwareAddr.String() 170 if err := netHandle.LinkSetMTU(tapLink, linkAttrs.MTU); err != nil { 171 return fmt.Errorf("Could not set TAP MTU %d: %s", linkAttrs.MTU, err) 172 } 173 if err := netHandle.LinkSetUp(tapLink); err != nil { 174 return fmt.Errorf("Could not enable TAP %s: %s", endpoint.TuntapInterface.Name, err) 175 } 176 return nil 177 } 178 179 func unTuntapNetwork(name string) error { 180 netHandle, err := netlink.NewHandle() 181 if err != nil { 182 return err 183 } 184 defer netHandle.Delete() 185 tapLink, err := getLinkByName(netHandle, name, &netlink.Tuntap{}) 186 if err != nil { 187 return fmt.Errorf("Could not get TAP interface: %s", err) 188 } 189 if err := netHandle.LinkSetDown(tapLink); err != nil { 190 return fmt.Errorf("Could not disable TAP %s: %s", name, err) 191 } 192 if err := netHandle.LinkDel(tapLink); err != nil { 193 return fmt.Errorf("Could not remove TAP %s: %s", name, err) 194 } 195 return nil 196 197 } 198 func (endpoint *TuntapEndpoint) save() persistapi.NetworkEndpoint { 199 tuntapif := saveTuntapIf(&endpoint.TuntapInterface) 200 201 return persistapi.NetworkEndpoint{ 202 Type: string(endpoint.Type()), 203 Tuntap: &persistapi.TuntapEndpoint{ 204 TuntapInterface: *tuntapif, 205 }, 206 } 207 } 208 209 func (endpoint *TuntapEndpoint) load(s persistapi.NetworkEndpoint) { 210 endpoint.EndpointType = TuntapEndpointType 211 212 if s.Tuntap != nil { 213 tuntapif := loadTuntapIf(&s.Tuntap.TuntapInterface) 214 endpoint.TuntapInterface = *tuntapif 215 } 216 }