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