github.com/stackdocker/rkt@v0.10.1-0.20151109095037-1aa827478248/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 "crypto/sha512" 20 "encoding/json" 21 "fmt" 22 "log" 23 "net" 24 25 "github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/cni/pkg/ip" 26 cnitypes "github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/cni/pkg/types" 27 "github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/spec/schema/types" 28 "github.com/coreos/rkt/Godeps/_workspace/src/github.com/vishvananda/netlink" 29 30 "github.com/coreos/rkt/common" 31 "github.com/coreos/rkt/networking/tuntap" 32 ) 33 34 // setupTapDevice creates persistent tap devices 35 // and returns a newly created netlink.Link structure 36 func setupTapDevice(podID types.UUID) (netlink.Link, error) { 37 // network device names are limited to 16 characters 38 // the suffix %d will be replaced by the kernel with a suitable number 39 nameTemplate := fmt.Sprintf("rkt-%s-tap%%d", podID.String()[0:4]) 40 ifName, err := tuntap.CreatePersistentIface(nameTemplate, tuntap.Tap) 41 if err != nil { 42 return nil, fmt.Errorf("tuntap persist %v", err) 43 } 44 link, err := netlink.LinkByName(ifName) 45 if err != nil { 46 return nil, fmt.Errorf("cannot find link %q: %v", ifName, err) 47 } 48 err = netlink.LinkSetUp(link) 49 if err != nil { 50 return nil, fmt.Errorf("cannot set link up %q: %v", ifName, err) 51 } 52 return link, nil 53 } 54 55 // kvmSetupNetAddressing calls IPAM plugin (with a hack) to reserve an IP to be 56 // used by newly create tuntap pair 57 // in result it updates activeNet.runtime configuration with IP, Mask and HostIP 58 func kvmSetupNetAddressing(network *Networking, n activeNet, ifName string) error { 59 // TODO: very ugly hack, that go through upper plugin, down to ipam plugin 60 if err := ip.EnableIP4Forward(); err != nil { 61 return fmt.Errorf("failed to enable forwarding: %v", err) 62 } 63 n.conf.Type = n.conf.IPAM.Type 64 output, err := network.execNetPlugin("ADD", &n, ifName) 65 if err != nil { 66 return fmt.Errorf("problem executing network plugin %q (%q): %v", n.conf.Type, ifName, err) 67 } 68 69 result := cnitypes.Result{} 70 if err = json.Unmarshal(output, &result); err != nil { 71 return fmt.Errorf("error parsing %q result: %v", n.conf.Name, err) 72 } 73 74 if result.IP4 == nil { 75 return fmt.Errorf("net-plugin returned no IPv4 configuration") 76 } 77 78 n.runtime.IP, n.runtime.Mask, n.runtime.HostIP = result.IP4.IP.IP, net.IP(result.IP4.IP.Mask), result.IP4.Gateway 79 return nil 80 } 81 82 // kvmSetup prepare new Networking to be used in kvm environment based on tuntap pair interfaces 83 // to allow communication with virtual machine created by lkvm tool 84 // right now it only supports default "ptp" network type (other types ends with error) 85 func kvmSetup(podRoot string, podID types.UUID, fps []ForwardedPort, netList common.NetList, localConfig string) (*Networking, error) { 86 network := Networking{ 87 podEnv: podEnv{ 88 podRoot: podRoot, 89 podID: podID, 90 netsLoadList: netList, 91 localConfig: localConfig, 92 }, 93 } 94 var e error 95 network.nets, e = network.loadNets() 96 if e != nil { 97 return nil, fmt.Errorf("error loading network definitions: %v", e) 98 } 99 100 for _, n := range network.nets { 101 switch n.conf.Type { 102 case "ptp": 103 link, err := setupTapDevice(podID) 104 if err != nil { 105 return nil, err 106 } 107 ifName := link.Attrs().Name 108 n.runtime.IfName = ifName 109 110 err = kvmSetupNetAddressing(&network, n, ifName) 111 if err != nil { 112 return nil, err 113 } 114 115 // add address to host tap device 116 err = netlink.AddrAdd( 117 link, 118 &netlink.Addr{ 119 IPNet: &net.IPNet{ 120 IP: n.runtime.HostIP, 121 Mask: net.IPMask(n.runtime.Mask), 122 }, 123 Label: ifName, 124 }) 125 if err != nil { 126 return nil, fmt.Errorf("cannot add address to host tap device %q: %v", ifName, err) 127 } 128 129 if n.conf.IPMasq { 130 h := sha512.Sum512([]byte(podID.String())) 131 chain := fmt.Sprintf("CNI-%s-%x", n.conf.Name, h[:8]) 132 if err = ip.SetupIPMasq(&net.IPNet{ 133 IP: n.runtime.IP, 134 Mask: net.IPMask(n.runtime.Mask), 135 }, chain); err != nil { 136 return nil, err 137 } 138 } 139 default: 140 return nil, fmt.Errorf("network %q have unsupported type: %q", n.conf.Name, n.conf.Type) 141 } 142 } 143 err := network.forwardPorts(fps, network.GetDefaultIP()) 144 if err != nil { 145 return nil, err 146 } 147 148 return &network, nil 149 } 150 151 /* 152 extend Networking struct with methods to clean up kvm specific network configurations 153 */ 154 155 // teardownKvmNets teardown every active networking from networking by 156 // removing tuntap interface and releasing its ip from IPAM plugin 157 func (n *Networking) teardownKvmNets() { 158 for _, an := range n.nets { 159 switch an.conf.Type { 160 case "ptp": 161 // remove tuntap interface 162 tuntap.RemovePersistentIface(an.runtime.IfName, tuntap.Tap) 163 // remove masquerading if it was prepared 164 if an.conf.IPMasq { 165 h := sha512.Sum512([]byte(n.podID.String())) 166 chain := fmt.Sprintf("CNI-%s-%x", an.conf.Name, h[:8]) 167 err := ip.TeardownIPMasq(&net.IPNet{ 168 IP: an.runtime.IP, 169 Mask: net.IPMask(an.runtime.Mask), 170 }, chain) 171 if err != nil { 172 log.Printf("Error on removing masquerading: %q", err) 173 } 174 } 175 // ugly hack again to directly call IPAM plugin to release IP 176 an.conf.Type = an.conf.IPAM.Type 177 178 _, err := n.execNetPlugin("DEL", &an, an.runtime.IfName) 179 if err != nil { 180 log.Printf("Error executing network plugin: %q", err) 181 } 182 default: 183 log.Printf("Unsupported network type: %q", an.conf.Type) 184 } 185 } 186 } 187 188 // kvmTeardown network teardown for kvm flavor based pods 189 // similar to Networking.Teardown but without host namespaces 190 func (n *Networking) kvmTeardown() { 191 192 if err := n.unforwardPorts(); err != nil { 193 log.Printf("Error removing forwarded ports (kvm): %v", err) 194 } 195 n.teardownKvmNets() 196 197 } 198 199 // Following methods implements behavior of netDescriber by activeNet 200 // (behavior required by stage1/init/kvm package and its kernel parameters configuration) 201 202 func (an activeNet) HostIP() net.IP { 203 return an.runtime.HostIP 204 } 205 func (an activeNet) GuestIP() net.IP { 206 return an.runtime.IP 207 } 208 func (an activeNet) IfName() string { 209 return an.runtime.IfName 210 } 211 func (an activeNet) Mask() net.IP { 212 return an.runtime.Mask 213 } 214 func (an activeNet) Name() string { 215 return an.conf.Name 216 } 217 func (an activeNet) IPMasq() bool { 218 return an.conf.IPMasq 219 } 220 221 // GetActiveNetworks returns activeNets to be used as NetDescriptors 222 // by plugins, which are required for stage1 executor to run (only for KVM) 223 func (e *Networking) GetActiveNetworks() []activeNet { 224 return e.nets 225 }