github.com/rkt/rkt@v1.30.1-0.20200224141603-171c416fac02/networking/kvm.go (about) 1 // Copyright 2015 The rkt Authors 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 // kvm.go file provides networking supporting functions for kvm flavor 16 package networking 17 18 import ( 19 "bufio" 20 "crypto/sha512" 21 "encoding/json" 22 "errors" 23 "fmt" 24 "io/ioutil" 25 "net" 26 "os" 27 "path/filepath" 28 "strconv" 29 "strings" 30 "syscall" 31 32 "github.com/appc/spec/schema/types" 33 "github.com/containernetworking/cni/pkg/ip" 34 cnitypes "github.com/containernetworking/cni/pkg/types" 35 cniutils "github.com/containernetworking/cni/pkg/utils" 36 cnisysctl "github.com/containernetworking/cni/pkg/utils/sysctl" 37 "github.com/hashicorp/errwrap" 38 "github.com/vishvananda/netlink" 39 40 "github.com/rkt/rkt/common" 41 commonnet "github.com/rkt/rkt/common/networking" 42 "github.com/rkt/rkt/networking/tuntap" 43 ) 44 45 const ( 46 defaultBrName = "cni0" 47 defaultSubnetFile = "/run/flannel/subnet.env" 48 defaultMTU = 1500 49 ) 50 51 type BridgeNetConf struct { 52 NetConf 53 BrName string `json:"bridge"` 54 IsGw bool `json:"isGateway"` 55 } 56 57 // setupTapDevice creates persistent tap device 58 // and returns a newly created netlink.Link structure 59 func setupTapDevice(podID types.UUID) (netlink.Link, error) { 60 // network device names are limited to 16 characters 61 // the suffix %d will be replaced by the kernel with a suitable number 62 nameTemplate := fmt.Sprintf("rkt-%s-tap%%d", podID.String()[0:4]) 63 ifName, err := tuntap.CreatePersistentIface(nameTemplate, tuntap.Tap) 64 if err != nil { 65 return nil, errwrap.Wrap(errors.New("tuntap persist"), err) 66 } 67 68 link, err := netlink.LinkByName(ifName) 69 if err != nil { 70 return nil, errwrap.Wrap(fmt.Errorf("cannot find link %q", ifName), err) 71 } 72 73 if err := netlink.LinkSetUp(link); err != nil { 74 return nil, errwrap.Wrap(fmt.Errorf("cannot set link up %q", ifName), err) 75 } 76 return link, nil 77 } 78 79 type MacVTapNetConf struct { 80 NetConf 81 Master string `json:"master"` 82 Mode string `json:"mode"` 83 } 84 85 const ( 86 IPv4InterfaceArpProxySysctlTemplate = "net.ipv4.conf.%s.proxy_arp" 87 ) 88 89 // setupTapDevice creates persistent macvtap device 90 // and returns a newly created netlink.Link structure 91 // using part of pod hash and interface number in interface name 92 func setupMacVTapDevice(podID types.UUID, config MacVTapNetConf, interfaceNumber int) (netlink.Link, error) { 93 master, err := netlink.LinkByName(config.Master) 94 if err != nil { 95 return nil, errwrap.Wrap(fmt.Errorf("cannot find master device '%v'", config.Master), err) 96 } 97 var mode netlink.MacvlanMode 98 switch config.Mode { 99 // if not set - defaults to bridge mode as in: 100 // https://github.com/rkt/rkt/blob/master/Documentation/networking.md#macvlan 101 case "", "bridge": 102 mode = netlink.MACVLAN_MODE_BRIDGE 103 case "private": 104 mode = netlink.MACVLAN_MODE_PRIVATE 105 case "vepa": 106 mode = netlink.MACVLAN_MODE_VEPA 107 case "passthru": 108 mode = netlink.MACVLAN_MODE_PASSTHRU 109 default: 110 return nil, fmt.Errorf("unsupported macvtap mode: %v", config.Mode) 111 } 112 mtu := master.Attrs().MTU 113 if config.MTU != 0 { 114 mtu = config.MTU 115 } 116 interfaceName := fmt.Sprintf("rkt-%s-vtap%d", podID.String()[0:4], interfaceNumber) 117 link := &netlink.Macvtap{ 118 Macvlan: netlink.Macvlan{ 119 LinkAttrs: netlink.LinkAttrs{ 120 Name: interfaceName, 121 MTU: mtu, 122 ParentIndex: master.Attrs().Index, 123 }, 124 Mode: mode, 125 }, 126 } 127 128 if err := netlink.LinkAdd(link); err != nil { 129 return nil, errwrap.Wrap(errors.New("cannot create macvtap interface"), err) 130 } 131 132 // TODO: duplicate following lines for ipv6 support, when it will be added in other places 133 ipv4SysctlValueName := fmt.Sprintf(IPv4InterfaceArpProxySysctlTemplate, interfaceName) 134 if _, err := cnisysctl.Sysctl(ipv4SysctlValueName, "1"); err != nil { 135 // remove the newly added link and ignore errors, because we already are in a failed state 136 _ = netlink.LinkDel(link) 137 return nil, errwrap.Wrap(fmt.Errorf("failed to set proxy_arp on newly added interface %q", interfaceName), err) 138 } 139 140 if err := netlink.LinkSetUp(link); err != nil { 141 // remove the newly added link and ignore errors, because we already are in a failed state 142 _ = netlink.LinkDel(link) 143 return nil, errwrap.Wrap(errors.New("cannot set up macvtap interface"), err) 144 } 145 return link, nil 146 } 147 148 // kvmSetupNetAddressing calls IPAM plugin (with a hack) to reserve an IP to be 149 // used by newly create tuntap pair 150 // in result it updates activeNet.runtime configuration 151 func kvmSetupNetAddressing(network *Networking, n activeNet, ifName string) error { 152 // TODO: very ugly hack, that go through upper plugin, down to ipam plugin 153 if err := ip.EnableIP4Forward(); err != nil { 154 return errwrap.Wrap(errors.New("failed to enable forwarding"), err) 155 } 156 157 // patch plugin type only for single IPAM run time, then revert this change 158 original_type := n.conf.Type 159 n.conf.Type = n.conf.IPAM.Type 160 output, err := network.execNetPlugin("ADD", &n, ifName) 161 n.conf.Type = original_type 162 if err != nil { 163 return errwrap.Wrap(fmt.Errorf("problem executing network plugin %q (%q)", n.conf.IPAM.Type, ifName), err) 164 } 165 166 result := cnitypes.Result{} 167 if err = json.Unmarshal(output, &result); err != nil { 168 return errwrap.Wrap(fmt.Errorf("error parsing %q result", n.conf.Name), err) 169 } 170 171 if result.IP4 == nil { 172 return fmt.Errorf("net-plugin returned no IPv4 configuration") 173 } 174 175 n.runtime.MergeCNIResult(result) 176 177 return nil 178 } 179 180 func ensureHasAddr(link netlink.Link, ipn *net.IPNet) error { 181 addrs, err := netlink.AddrList(link, syscall.AF_INET) 182 if err != nil && err != syscall.ENOENT { 183 return errwrap.Wrap(errors.New("could not get list of IP addresses"), err) 184 } 185 186 // if there're no addresses on the interface, it's ok -- we'll add one 187 if len(addrs) > 0 { 188 ipnStr := ipn.String() 189 for _, a := range addrs { 190 // string comp is actually easiest for doing IPNet comps 191 if a.IPNet.String() == ipnStr { 192 return nil 193 } 194 } 195 return fmt.Errorf("%q already has an IP address different from %v", link.Attrs().Name, ipn.String()) 196 } 197 198 addr := &netlink.Addr{IPNet: ipn, Label: link.Attrs().Name} 199 if err := netlink.AddrAdd(link, addr); err != nil { 200 return errwrap.Wrap(fmt.Errorf("could not add IP address to %q", link.Attrs().Name), err) 201 } 202 return nil 203 } 204 205 func bridgeByName(name string) (*netlink.Bridge, error) { 206 l, err := netlink.LinkByName(name) 207 if err != nil { 208 return nil, errwrap.Wrap(fmt.Errorf("could not lookup %q", name), err) 209 } 210 br, ok := l.(*netlink.Bridge) 211 if !ok { 212 return nil, fmt.Errorf("%q already exists but is not a bridge", name) 213 } 214 return br, nil 215 } 216 217 func ensureBridgeIsUp(brName string, mtu int) (*netlink.Bridge, error) { 218 br := &netlink.Bridge{ 219 LinkAttrs: netlink.LinkAttrs{ 220 Name: brName, 221 MTU: mtu, 222 }, 223 } 224 225 if err := netlink.LinkAdd(br); err != nil { 226 if err != syscall.EEXIST { 227 return nil, errwrap.Wrap(fmt.Errorf("could not add %q", brName), err) 228 } 229 230 // it's ok if the device already exists as long as config is similar 231 br, err = bridgeByName(brName) 232 if err != nil { 233 return nil, err 234 } 235 } 236 237 if err := netlink.LinkSetUp(br); err != nil { 238 return nil, err 239 } 240 241 return br, nil 242 } 243 244 func addRoute(link netlink.Link, podIP net.IP) error { 245 route := netlink.Route{ 246 LinkIndex: link.Attrs().Index, 247 Scope: netlink.SCOPE_LINK, 248 Dst: &net.IPNet{ 249 IP: podIP, 250 Mask: net.IPv4Mask(0xff, 0xff, 0xff, 0xff), 251 }, 252 } 253 return netlink.RouteAdd(&route) 254 } 255 256 func removeAllRoutesOnLink(link netlink.Link) error { 257 routes, err := netlink.RouteList(link, netlink.FAMILY_V4) 258 if err != nil { 259 return errwrap.Wrap(fmt.Errorf("cannot list routes on link %q", link.Attrs().Name), err) 260 } 261 262 for _, route := range routes { 263 if err := netlink.RouteDel(&route); err != nil { 264 return errwrap.Wrap(fmt.Errorf("error in time of route removal for route %q", route), err) 265 } 266 } 267 268 return nil 269 } 270 271 func getChainName(podUUIDString, confName string) string { 272 h := sha512.Sum512([]byte(podUUIDString)) 273 return fmt.Sprintf("CNI-%s-%x", confName, h[:8]) 274 } 275 276 type FlannelNetConf struct { 277 NetConf 278 279 SubnetFile string `json:"subnetFile"` 280 Delegate map[string]interface{} `json:"delegate"` 281 } 282 283 func loadFlannelNetConf(bytes []byte) (*FlannelNetConf, error) { 284 n := &FlannelNetConf{ 285 SubnetFile: defaultSubnetFile, 286 } 287 if err := json.Unmarshal(bytes, n); err != nil { 288 return nil, errwrap.Wrap(errors.New("failed to load netconf"), err) 289 } 290 return n, nil 291 } 292 293 type subnetEnv struct { 294 nw *net.IPNet 295 sn *net.IPNet 296 mtu int 297 ipmasq bool 298 } 299 300 func loadFlannelSubnetEnv(fn string) (*subnetEnv, error) { 301 f, err := os.Open(fn) 302 if err != nil { 303 return nil, err 304 } 305 defer f.Close() 306 307 se := &subnetEnv{} 308 309 s := bufio.NewScanner(f) 310 for s.Scan() { 311 parts := strings.SplitN(s.Text(), "=", 2) 312 switch parts[0] { 313 case "FLANNEL_NETWORK": 314 _, se.nw, err = net.ParseCIDR(parts[1]) 315 if err != nil { 316 return nil, err 317 } 318 319 case "FLANNEL_SUBNET": 320 _, se.sn, err = net.ParseCIDR(parts[1]) 321 if err != nil { 322 return nil, err 323 } 324 325 case "FLANNEL_MTU": 326 mtu, err := strconv.ParseUint(parts[1], 10, 32) 327 if err != nil { 328 return nil, err 329 } 330 se.mtu = int(mtu) 331 332 case "FLANNEL_IPMASQ": 333 se.ipmasq = parts[1] == "true" 334 } 335 } 336 if err := s.Err(); err != nil { 337 return nil, err 338 } 339 340 return se, nil 341 } 342 343 func hasKey(m map[string]interface{}, k string) bool { 344 _, ok := m[k] 345 return ok 346 } 347 348 func isString(i interface{}) bool { 349 _, ok := i.(string) 350 return ok 351 } 352 353 func kvmTransformFlannelNetwork(net *activeNet) error { 354 n, err := loadFlannelNetConf(net.confBytes) 355 if err != nil { 356 return err 357 } 358 359 fenv, err := loadFlannelSubnetEnv(n.SubnetFile) 360 if err != nil { 361 return err 362 } 363 364 if n.Delegate == nil { 365 n.Delegate = make(map[string]interface{}) 366 } else { 367 if hasKey(n.Delegate, "type") && !isString(n.Delegate["type"]) { 368 return fmt.Errorf("'delegate' dictionary, if present, must have (string) 'type' field") 369 } 370 if hasKey(n.Delegate, "name") { 371 return fmt.Errorf("'delegate' dictionary must not have 'name' field, it'll be set by flannel") 372 } 373 if hasKey(n.Delegate, "ipam") { 374 return fmt.Errorf("'delegate' dictionary must not have 'ipam' field, it'll be set by flannel") 375 } 376 } 377 378 n.Delegate["name"] = n.Name 379 380 if !hasKey(n.Delegate, "type") { 381 n.Delegate["type"] = "bridge" 382 } 383 384 if !hasKey(n.Delegate, "isDefaultGateway") { 385 n.Delegate["isDefaultGateway"] = false 386 } 387 388 if !hasKey(n.Delegate, "ipMasq") { 389 // if flannel is not doing ipmasq, we should 390 ipmasq := !fenv.ipmasq 391 n.Delegate["ipMasq"] = ipmasq 392 } 393 394 if !hasKey(n.Delegate, "mtu") { 395 mtu := fenv.mtu 396 n.Delegate["mtu"] = mtu 397 } 398 399 if n.Delegate["type"].(string) == "bridge" { 400 if !hasKey(n.Delegate, "isGateway") { 401 n.Delegate["isGateway"] = true 402 } 403 } 404 405 n.Delegate["ipam"] = map[string]interface{}{ 406 "type": "host-local", 407 "subnet": fenv.sn.String(), 408 "routes": []cnitypes.Route{ 409 { 410 Dst: *fenv.nw, 411 }, 412 }, 413 } 414 415 bytes, err := json.Marshal(n.Delegate) 416 if err != nil { 417 return errwrap.Wrap(errors.New("error in marshaling generated network settings"), err) 418 } 419 420 net.runtime.IP4 = &cnitypes.IPConfig{} 421 *net = activeNet{ 422 confBytes: bytes, 423 conf: &NetConf{}, 424 runtime: net.runtime, 425 } 426 net.conf.Name = n.Name 427 net.conf.Type = n.Delegate["type"].(string) 428 net.conf.IPMasq = n.Delegate["ipMasq"].(bool) 429 net.conf.MTU = n.Delegate["mtu"].(int) 430 net.conf.IsDefaultGateway = n.Delegate["isDefaultGateway"].(bool) 431 net.conf.IPAM.Type = "host-local" 432 return nil 433 } 434 435 // kvmSetup prepare new Networking to be used in kvm environment based on tuntap pair interfaces 436 // to allow communication with virtual machine created by lkvm tool 437 func kvmSetup(podRoot string, podID types.UUID, fps []commonnet.ForwardedPort, netList common.NetList, localConfig string, noDNS bool) (*Networking, error) { 438 network := Networking{ 439 podEnv: podEnv{ 440 podRoot: podRoot, 441 podID: podID, 442 netsLoadList: netList, 443 localConfig: localConfig, 444 }, 445 } 446 var e error 447 448 // If there's a network set as default in CNI configuration 449 defaultGatewaySet := false 450 451 _, defaultNet, err := net.ParseCIDR("0.0.0.0/0") 452 if err != nil { 453 return nil, errwrap.Wrap(errors.New("error when parsing net address"), err) 454 } 455 456 network.nets, e = network.loadNets() 457 if e != nil { 458 return nil, errwrap.Wrap(errors.New("error loading network definitions"), e) 459 } 460 461 // did stage0 already make /etc/rkt-resolv.conf (i.e. --dns passed) 462 resolvPath := filepath.Join(common.Stage1RootfsPath(podRoot), "etc/rkt-resolv.conf") 463 _, err = os.Stat(resolvPath) 464 if err != nil && !os.IsNotExist(err) { 465 return nil, errwrap.Wrap(fmt.Errorf("error statting /etc/rkt-resolv.conf"), err) 466 } 467 podHasResolvConf := err == nil 468 469 for i, n := range network.nets { 470 if n.conf.Type == "flannel" { 471 if err := kvmTransformFlannelNetwork(&n); err != nil { 472 return nil, errwrap.Wrap(errors.New("cannot transform flannel network into basic network"), err) 473 } 474 } 475 switch n.conf.Type { 476 case "ptp": 477 link, err := setupTapDevice(podID) 478 if err != nil { 479 return nil, err 480 } 481 ifName := link.Attrs().Name 482 n.runtime.IfName = ifName 483 484 err = kvmSetupNetAddressing(&network, n, ifName) 485 if err != nil { 486 return nil, err 487 } 488 489 // add address to host tap device 490 err = ensureHasAddr( 491 link, 492 &net.IPNet{ 493 IP: n.runtime.IP4.Gateway, 494 Mask: net.IPMask(n.runtime.Mask), 495 }, 496 ) 497 if err != nil { 498 return nil, errwrap.Wrap(fmt.Errorf("cannot add address to host tap device %q", ifName), err) 499 } 500 501 if err := removeAllRoutesOnLink(link); err != nil { 502 return nil, errwrap.Wrap(fmt.Errorf("cannot remove route on host tap device %q", ifName), err) 503 } 504 505 if err := addRoute(link, n.runtime.IP); err != nil { 506 return nil, errwrap.Wrap(errors.New("cannot add on host direct route to pod"), err) 507 } 508 509 case "bridge": 510 config := BridgeNetConf{ 511 NetConf: NetConf{ 512 MTU: defaultMTU, 513 }, 514 BrName: defaultBrName, 515 } 516 if err := json.Unmarshal(n.confBytes, &config); err != nil { 517 return nil, errwrap.Wrap(fmt.Errorf("error parsing %q result", n.conf.Name), err) 518 } 519 520 br, err := ensureBridgeIsUp(config.BrName, config.MTU) 521 if err != nil { 522 return nil, errwrap.Wrap(errors.New("error in time of bridge setup"), err) 523 } 524 link, err := setupTapDevice(podID) 525 if err != nil { 526 return nil, errwrap.Wrap(errors.New("can not setup tap device"), err) 527 } 528 err = netlink.LinkSetMaster(link, br) 529 if err != nil { 530 rErr := tuntap.RemovePersistentIface(n.runtime.IfName, tuntap.Tap) 531 if rErr != nil { 532 stderr.PrintE("warning: could not cleanup tap interface", rErr) 533 } 534 return nil, errwrap.Wrap(errors.New("can not add tap interface to bridge"), err) 535 } 536 537 ifName := link.Attrs().Name 538 n.runtime.IfName = ifName 539 540 err = kvmSetupNetAddressing(&network, n, ifName) 541 if err != nil { 542 return nil, err 543 } 544 545 if n.conf.IsDefaultGateway { 546 n.runtime.IP4.Routes = append( 547 n.runtime.IP4.Routes, 548 cnitypes.Route{Dst: *defaultNet, GW: n.runtime.IP4.Gateway}, 549 ) 550 defaultGatewaySet = true 551 config.IsGw = true 552 } 553 554 if config.IsGw { 555 err = ensureHasAddr( 556 br, 557 &net.IPNet{ 558 IP: n.runtime.IP4.Gateway, 559 Mask: net.IPMask(n.runtime.Mask), 560 }, 561 ) 562 563 if err != nil { 564 return nil, errwrap.Wrap(fmt.Errorf("cannot add address to host bridge device %q", br.Name), err) 565 } 566 } 567 568 case "macvlan": 569 config := MacVTapNetConf{} 570 if err := json.Unmarshal(n.confBytes, &config); err != nil { 571 return nil, errwrap.Wrap(fmt.Errorf("error parsing %q result", n.conf.Name), err) 572 } 573 link, err := setupMacVTapDevice(podID, config, i) 574 if err != nil { 575 return nil, err 576 } 577 ifName := link.Attrs().Name 578 n.runtime.IfName = ifName 579 580 err = kvmSetupNetAddressing(&network, n, ifName) 581 if err != nil { 582 return nil, err 583 } 584 585 default: 586 return nil, fmt.Errorf("network %q have unsupported type: %q", n.conf.Name, n.conf.Type) 587 } 588 589 // Check if there's any other network set as default gateway 590 if defaultGatewaySet { 591 for _, route := range n.runtime.IP4.Routes { 592 if (defaultNet.String() == route.Dst.String()) && !n.conf.IsDefaultGateway { 593 return nil, fmt.Errorf("flannel config enables default gateway and IPAM sets default gateway via %q", n.runtime.IP4.Gateway) 594 } 595 } 596 } 597 598 // Generate rkt-resolv.conf if it's not already there. 599 // The first network plugin that supplies a non-empty 600 // DNS response will win, unless noDNS is true (--dns passed to rkt run) 601 if !common.IsDNSZero(&n.runtime.DNS) && !noDNS { 602 if !podHasResolvConf { 603 err := ioutil.WriteFile( 604 resolvPath, 605 []byte(common.MakeResolvConf(n.runtime.DNS, "Generated by rkt from network "+n.conf.Name)), 606 0644) 607 if err != nil { 608 return nil, errwrap.Wrap(fmt.Errorf("error creating resolv.conf"), err) 609 } 610 podHasResolvConf = true 611 } else { 612 stderr.Printf("Warning: network %v plugin specified DNS configuration, but DNS already supplied", n.conf.Name) 613 } 614 } 615 616 if n.conf.IPMasq { 617 chain := cniutils.FormatChainName(n.conf.Name, podID.String()) 618 comment := cniutils.FormatComment(n.conf.Name, podID.String()) 619 if err := ip.SetupIPMasq(&net.IPNet{ 620 IP: n.runtime.IP, 621 Mask: net.IPMask(n.runtime.Mask), 622 }, chain, comment); err != nil { 623 return nil, err 624 } 625 } 626 network.nets[i] = n 627 } 628 podIP, err := network.GetForwardableNetPodIP() 629 if err != nil { 630 return nil, err 631 } 632 if err := network.setupForwarding(); err != nil { 633 network.teardownForwarding() 634 return nil, err 635 } 636 if err := network.forwardPorts(fps, podIP); err != nil { 637 network.teardownForwarding() 638 return nil, err 639 } 640 641 return &network, nil 642 } 643 644 /* 645 extend Networking struct with methods to clean up kvm specific network configurations 646 */ 647 648 // teardownKvmNets teardown every active networking from networking by 649 // removing tuntap interface and releasing its ip from IPAM plugin 650 func (n *Networking) teardownKvmNets() { 651 for _, an := range n.nets { 652 if an.conf.Type == "flannel" { 653 if err := kvmTransformFlannelNetwork(&an); err != nil { 654 stderr.PrintE("error transforming flannel network", err) 655 continue 656 } 657 } 658 659 switch an.conf.Type { 660 case "ptp", "bridge": 661 // remove tuntap interface 662 tuntap.RemovePersistentIface(an.runtime.IfName, tuntap.Tap) 663 664 case "macvlan": 665 link, err := netlink.LinkByName(an.runtime.IfName) 666 if err != nil { 667 stderr.PrintE(fmt.Sprintf("cannot find link `%v`", an.runtime.IfName), err) 668 continue 669 } else { 670 err := netlink.LinkDel(link) 671 if err != nil { 672 stderr.PrintE(fmt.Sprintf("cannot remove link `%v`", an.runtime.IfName), err) 673 continue 674 } 675 } 676 677 default: 678 stderr.Printf("unsupported network type: %q", an.conf.Type) 679 continue 680 } 681 // ugly hack again to directly call IPAM plugin to release IP 682 an.conf.Type = an.conf.IPAM.Type 683 684 _, err := n.execNetPlugin("DEL", &an, an.runtime.IfName) 685 if err != nil { 686 stderr.PrintE("error executing network plugin", err) 687 } 688 // remove masquerading if it was prepared 689 if an.conf.IPMasq { 690 chain := cniutils.FormatChainName(an.conf.Name, n.podID.String()) 691 comment := cniutils.FormatChainName(an.conf.Name, n.podID.String()) 692 err := ip.TeardownIPMasq(&net.IPNet{ 693 IP: an.runtime.IP, 694 Mask: net.IPMask(an.runtime.Mask), 695 }, chain, comment) 696 if err != nil { 697 stderr.PrintE("error on removing masquerading", err) 698 } 699 } 700 } 701 } 702 703 // kvmTeardown network teardown for kvm flavor based pods 704 // similar to Networking.Teardown but without host namespaces 705 func (n *Networking) kvmTeardown() { 706 707 if err := n.teardownForwarding(); err != nil { 708 stderr.PrintE("error removing forwarded ports (kvm)", err) 709 } 710 n.teardownKvmNets() 711 } 712 713 // Following methods implements behavior of netDescriber by activeNet 714 // (behavior required by stage1/init/kvm package and its kernel parameters configuration) 715 716 func (an activeNet) HostIP() net.IP { 717 return an.runtime.HostIP 718 } 719 func (an activeNet) GuestIP() net.IP { 720 return an.runtime.IP 721 } 722 func (an activeNet) IfName() string { 723 if an.conf.Type == "macvlan" { 724 // macvtap device passed as parameter to lkvm binary have different 725 // kind of name, path to /dev/tapN made with N as link index 726 link, err := netlink.LinkByName(an.runtime.IfName) 727 if err != nil { 728 stderr.PrintE(fmt.Sprintf("cannot get interface '%v'", an.runtime.IfName), err) 729 return "" 730 } 731 return fmt.Sprintf("/dev/tap%d", link.Attrs().Index) 732 } 733 return an.runtime.IfName 734 } 735 func (an activeNet) Mask() net.IP { 736 return an.runtime.Mask 737 } 738 func (an activeNet) Name() string { 739 return an.conf.Name 740 } 741 func (an activeNet) IPMasq() bool { 742 return an.conf.IPMasq 743 } 744 func (an activeNet) Gateway() net.IP { 745 return an.runtime.IP4.Gateway 746 } 747 func (an activeNet) Routes() []cnitypes.Route { 748 return an.runtime.IP4.Routes 749 } 750 751 // GetActiveNetworks returns activeNets to be used as NetDescriptors 752 // by plugins, which are required for stage1 executor to run (only for KVM) 753 func (e *Networking) GetActiveNetworks() []activeNet { 754 return e.nets 755 }