github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/stage1/init/kvm/network.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 package kvm 16 17 import ( 18 "crypto/rand" 19 "errors" 20 "fmt" 21 "io/ioutil" 22 "net" 23 "path/filepath" 24 25 "github.com/appc/cni/pkg/types" 26 "github.com/coreos/go-systemd/unit" 27 "github.com/coreos/rkt/networking" 28 "github.com/hashicorp/errwrap" 29 ) 30 31 // GetNetworkDescriptions explicitly convert slice of activeNets to slice of netDescribers 32 // which is slice required by GetKVMNetArgs 33 func GetNetworkDescriptions(n *networking.Networking) []netDescriber { 34 var nds []netDescriber 35 for _, an := range n.GetActiveNetworks() { 36 nds = append(nds, an) 37 } 38 return nds 39 } 40 41 // netDescriber is something that describes network configuration 42 type netDescriber interface { 43 GuestIP() net.IP 44 Mask() net.IP 45 IfName() string 46 IPMasq() bool 47 Name() string 48 Gateway() net.IP 49 Routes() []types.Route 50 } 51 52 // GetKVMNetArgs returns additional arguments that need to be passed 53 // to lkvm tool to configure networks properly. 54 // Logic is based on Network configuration extracted from Networking struct 55 // and essentially from activeNets that expose netDescriber behavior 56 func GetKVMNetArgs(nds []netDescriber) ([]string, error) { 57 58 var lkvmArgs []string 59 60 for _, nd := range nds { 61 lkvmArgs = append(lkvmArgs, "--network") 62 lkvmArg := fmt.Sprintf("mode=tap,tapif=%s,host_ip=%s,guest_ip=%s", nd.IfName(), nd.Gateway(), nd.GuestIP()) 63 lkvmArgs = append(lkvmArgs, lkvmArg) 64 } 65 66 return lkvmArgs, nil 67 } 68 69 // generateMacAddress returns net.HardwareAddr filled with fixed 3 byte prefix 70 // complemented by 3 random bytes. 71 func generateMacAddress() (net.HardwareAddr, error) { 72 mac := []byte{ 73 2, // locally administered unicast 74 0x65, 0x02, // OUI (randomly choosen by jell) 75 0, 0, 0, // bytes to randomly overwrite 76 } 77 78 _, err := rand.Read(mac[3:6]) 79 if err != nil { 80 return nil, errwrap.Wrap(errors.New("cannot generate random mac address"), err) 81 } 82 83 return mac, nil 84 } 85 86 func setMacCommand(ifName, mac string) string { 87 return fmt.Sprintf("/bin/ip link set dev %s address %s", ifName, mac) 88 } 89 90 func addAddressCommand(address, ifName string) string { 91 return fmt.Sprintf("/bin/ip address add %s dev %s", address, ifName) 92 } 93 94 func addRouteCommand(destination, router string) string { 95 return fmt.Sprintf("/bin/ip route add %s via %s", destination, router) 96 } 97 98 func downInterfaceCommand(ifName string) string { 99 return fmt.Sprintf("/bin/ip link set dev %s down", ifName) 100 } 101 102 func upInterfaceCommand(ifName string) string { 103 return fmt.Sprintf("/bin/ip link set dev %s up", ifName) 104 } 105 106 func GenerateNetworkInterfaceUnits(unitsPath string, netDescriptions []netDescriber) error { 107 108 for i, netDescription := range netDescriptions { 109 ifName := fmt.Sprintf(networking.IfNamePattern, i) 110 netAddress := net.IPNet{ 111 IP: netDescription.GuestIP(), 112 Mask: net.IPMask(netDescription.Mask()), 113 } 114 115 address := netAddress.String() 116 117 mac, err := generateMacAddress() 118 if err != nil { 119 return err 120 } 121 122 opts := []*unit.UnitOption{ 123 unit.NewUnitOption("Unit", "Description", fmt.Sprintf("Network configuration for device: %v", ifName)), 124 unit.NewUnitOption("Unit", "DefaultDependencies", "false"), 125 unit.NewUnitOption("Service", "Type", "oneshot"), 126 unit.NewUnitOption("Service", "RemainAfterExit", "true"), 127 unit.NewUnitOption("Service", "ExecStartPre", downInterfaceCommand(ifName)), 128 unit.NewUnitOption("Service", "ExecStartPre", setMacCommand(ifName, mac.String())), 129 unit.NewUnitOption("Service", "ExecStartPre", upInterfaceCommand(ifName)), 130 unit.NewUnitOption("Service", "ExecStart", addAddressCommand(address, ifName)), 131 unit.NewUnitOption("Install", "RequiredBy", "default.target"), 132 } 133 134 for _, route := range netDescription.Routes() { 135 gw := route.GW 136 if gw == nil { 137 gw = netDescription.Gateway() 138 } 139 140 opts = append( 141 opts, 142 unit.NewUnitOption( 143 "Service", 144 "ExecStartPost", 145 addRouteCommand(route.Dst.String(), gw.String()), 146 ), 147 ) 148 } 149 150 unitName := fmt.Sprintf("interface-%s", ifName) + ".service" 151 unitBytes, err := ioutil.ReadAll(unit.Serialize(opts)) 152 if err != nil { 153 return errwrap.Wrap(fmt.Errorf("failed to serialize network unit file to bytes %q", unitName), err) 154 } 155 156 err = ioutil.WriteFile(filepath.Join(unitsPath, unitName), unitBytes, 0644) 157 if err != nil { 158 return errwrap.Wrap(fmt.Errorf("failed to create network unit file %q", unitName), err) 159 } 160 161 rlog.Printf("network unit created: %q in %q (iface=%q, addr=%q)", unitName, unitsPath, ifName, address) 162 } 163 return nil 164 }