github.com/equinix-metal/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/tests/network/dhcp_test.go (about) 1 /* 2 Copyright 2016 Mirantis 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package network 18 19 import ( 20 "fmt" 21 "net" 22 "testing" 23 "time" 24 25 "github.com/containernetworking/cni/pkg/ns" 26 cnitypes "github.com/containernetworking/cni/pkg/types" 27 cnicurrent "github.com/containernetworking/cni/pkg/types/current" 28 "github.com/vishvananda/netlink" 29 30 "github.com/Mirantis/virtlet/pkg/nettools" 31 "github.com/Mirantis/virtlet/pkg/network" 32 ) 33 34 func TestDhcpServer(t *testing.T) { 35 clientMac, _ := net.ParseMAC(clientMacAddrs[0]) 36 for _, tc := range []struct { 37 name string 38 csn network.ContainerSideNetwork 39 expectedSubstrings []string 40 }{ 41 { 42 name: "with classless routes", 43 csn: network.ContainerSideNetwork{ 44 Result: &cnicurrent.Result{ 45 Interfaces: []*cnicurrent.Interface{ 46 { 47 Name: "eth0", 48 Mac: clientMacAddrs[0], 49 // Sandbox is clientNS dependent 50 // so it must be set in runtime 51 }, 52 }, 53 IPs: []*cnicurrent.IPConfig{ 54 { 55 Version: "4", 56 Interface: 0, 57 Address: net.IPNet{ 58 IP: net.IP{10, 1, 90, 5}, 59 Mask: net.IPMask{255, 255, 255, 0}, 60 }, 61 Gateway: net.IP{10, 1, 90, 1}, 62 }, 63 }, 64 Routes: []*cnitypes.Route{ 65 { 66 Dst: net.IPNet{ 67 IP: net.IP{0, 0, 0, 0}, 68 Mask: net.IPMask{0, 0, 0, 0}, 69 }, 70 GW: net.IP{10, 1, 90, 1}, 71 }, 72 { 73 Dst: net.IPNet{ 74 IP: net.IP{10, 10, 42, 0}, 75 Mask: net.IPMask{255, 255, 255, 0}, 76 }, 77 GW: net.IP{10, 1, 90, 90}, 78 }, 79 }, 80 }, 81 Interfaces: []*network.InterfaceDescription{ 82 { 83 HardwareAddr: clientMac, 84 MTU: 9000, 85 }, 86 }, 87 }, 88 expectedSubstrings: []string{ 89 "new_broadcast_address='10.1.90.255'", 90 "new_classless_static_routes='10.10.42.0/24 10.1.90.90 0.0.0.0/0 10.1.90.1'", 91 "new_dhcp_lease_time='86400'", 92 "new_dhcp_rebinding_time='64800'", 93 "new_dhcp_renewal_time='43200'", 94 "new_dhcp_server_identifier='169.254.254.2'", 95 "new_domain_name_servers='8.8.8.8'", 96 "new_ip_address='10.1.90.5'", 97 "new_interface_mtu='9000'", 98 "new_network_number='10.1.90.0'", 99 "new_subnet_cidr='24'", 100 "new_subnet_mask='255.255.255.0'", 101 "veth0: offered 10.1.90.5 from 169.254.254.2", 102 }, 103 }, 104 { 105 name: "without classless routes", 106 csn: network.ContainerSideNetwork{ 107 Result: &cnicurrent.Result{ 108 Interfaces: []*cnicurrent.Interface{ 109 { 110 Name: "eth0", 111 Mac: clientMacAddrs[0], 112 // Sandbox is clientNS dependent 113 // so it must be set in runtime 114 }, 115 }, 116 IPs: []*cnicurrent.IPConfig{ 117 { 118 Version: "4", 119 Interface: 0, 120 Address: net.IPNet{ 121 IP: net.IP{10, 1, 90, 5}, 122 Mask: net.IPMask{255, 255, 255, 0}, 123 }, 124 Gateway: net.IP{10, 1, 90, 1}, 125 }, 126 }, 127 Routes: []*cnitypes.Route{ 128 { 129 Dst: net.IPNet{ 130 IP: net.IP{0, 0, 0, 0}, 131 Mask: net.IPMask{0, 0, 0, 0}, 132 }, 133 GW: net.IP{10, 1, 90, 1}, 134 }, 135 }, 136 }, 137 Interfaces: []*network.InterfaceDescription{ 138 { 139 HardwareAddr: clientMac, 140 MTU: 9000, 141 }, 142 }, 143 }, 144 expectedSubstrings: []string{ 145 "new_broadcast_address='10.1.90.255'", 146 "new_dhcp_lease_time='86400'", 147 "new_dhcp_rebinding_time='64800'", 148 "new_dhcp_renewal_time='43200'", 149 "new_dhcp_server_identifier='169.254.254.2'", 150 "new_domain_name_servers='8.8.8.8'", 151 "new_ip_address='10.1.90.5'", 152 "new_interface_mtu='9000'", 153 "new_network_number='10.1.90.0'", 154 "new_routers='10.1.90.1'", 155 "new_subnet_cidr='24'", 156 "new_subnet_mask='255.255.255.0'", 157 "veth0: offered 10.1.90.5 from 169.254.254.2", 158 }, 159 }, 160 // TODO: add dns test case here 161 } { 162 t.Run(tc.name, func(t *testing.T) { 163 serverNS, err := ns.NewNS() 164 if err != nil { 165 t.Fatalf("Failed to create ns for dhcp server: %v", err) 166 } 167 defer serverNS.Close() 168 clientNS, err := ns.NewNS() 169 if err != nil { 170 t.Fatalf("Failed to create ns for dhcp client: %v", err) 171 } 172 defer clientNS.Close() 173 174 // Sandbox is clientNS dependent so it needs to be set there on all interfaces 175 for _, iface := range tc.csn.Result.Interfaces { 176 iface.Sandbox = clientNS.Path() 177 } 178 179 var clientVeth, serverVeth netlink.Link 180 if err := serverNS.Do(func(ns.NetNS) error { 181 serverVeth, clientVeth, err = nettools.CreateEscapeVethPair(clientNS, "veth0", 1500) 182 if err != nil { 183 return fmt.Errorf("failed to create escape veth pair: %v", err) 184 } 185 addr, err := netlink.ParseAddr("169.254.254.2/24") 186 if err != nil { 187 return fmt.Errorf("failed to parse dhcp interface address: %v", err) 188 } 189 if err = netlink.AddrAdd(serverVeth, addr); err != nil { 190 return fmt.Errorf("failed to add addr for serverVeth: %v", err) 191 } 192 193 return nil 194 }); err != nil { 195 t.Fatal(err) 196 } 197 198 if err := clientNS.Do(func(ns.NetNS) error { 199 mac, _ := net.ParseMAC(clientMacAddrs[0]) 200 if err = nettools.SetHardwareAddr(clientVeth, mac); err != nil { 201 return fmt.Errorf("can't set MAC address on the client interface: %v", err) 202 } 203 204 return nil 205 }); err != nil { 206 t.Fatal(err) 207 } 208 209 g := NewNetTestGroup(t, 15*time.Second) 210 defer g.Stop() 211 g.Add(serverNS, NewDhcpServerTester(&tc.csn)) 212 213 g.Add(clientNS, NewDhcpClient("veth0", tc.expectedSubstrings)) 214 g.Wait() 215 }) 216 } 217 }