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