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