github.com/cloudfoundry-attic/garden-linux@v0.333.2-candidate/network/devices/link_linux_test.go (about) 1 package devices_test 2 3 import ( 4 "fmt" 5 "net" 6 "os/exec" 7 "strconv" 8 "strings" 9 10 "github.com/cloudfoundry-incubator/garden-linux/network/devices" 11 "github.com/docker/libcontainer/netlink" 12 . "github.com/onsi/ginkgo" 13 . "github.com/onsi/gomega" 14 "github.com/onsi/gomega/gexec" 15 ) 16 17 var _ = Describe("Link Management", func() { 18 var ( 19 l devices.Link 20 name string 21 intf *net.Interface 22 ) 23 24 BeforeEach(func() { 25 cmd, err := gexec.Start(exec.Command("sh", "-c", "mountpoint /sys || mount -t sysfs sysfs /sys"), GinkgoWriter, GinkgoWriter) 26 Expect(err).ToNot(HaveOccurred()) 27 Eventually(cmd).Should(gexec.Exit(0)) 28 29 name = fmt.Sprintf("gdn-test-%d", GinkgoParallelNode()) 30 Expect(netlink.NetworkLinkAdd(name, "dummy")).To(Succeed()) 31 intf, _ = net.InterfaceByName(name) 32 }) 33 34 AfterEach(func() { 35 cleanup(name) 36 }) 37 38 Describe("AddIP", func() { 39 Context("when the interface exists", func() { 40 It("adds the IP succesffuly", func() { 41 ip, subnet, _ := net.ParseCIDR("1.2.3.4/5") 42 Expect(l.AddIP(intf, ip, subnet)).To(Succeed()) 43 44 intf, err := net.InterfaceByName(name) 45 Expect(err).ToNot(HaveOccurred()) 46 addrs, err := intf.Addrs() 47 Expect(err).ToNot(HaveOccurred()) 48 49 Expect(addrs).To(HaveLen(1)) 50 Expect(addrs[0].String()).To(Equal("1.2.3.4/5")) 51 }) 52 }) 53 }) 54 55 Describe("SetUp", func() { 56 Context("when the interface does not exist", func() { 57 It("returns an error", func() { 58 Expect(l.SetUp(&net.Interface{Name: "something"})).ToNot(Succeed()) 59 }) 60 }) 61 62 Context("when the interface exists", func() { 63 Context("and it is down", func() { 64 It("should bring the interface up", func() { 65 Expect(l.SetUp(intf)).To(Succeed()) 66 67 intf, err := net.InterfaceByName(name) 68 Expect(err).ToNot(HaveOccurred()) 69 Expect(intf.Flags & net.FlagUp).To(Equal(net.FlagUp)) 70 }) 71 }) 72 73 Context("and it is already up", func() { 74 It("should still succeed", func() { 75 Expect(l.SetUp(intf)).To(Succeed()) 76 Expect(l.SetUp(intf)).To(Succeed()) 77 78 intf, err := net.InterfaceByName(name) 79 Expect(err).ToNot(HaveOccurred()) 80 Expect(intf.Flags & net.FlagUp).To(Equal(net.FlagUp)) 81 }) 82 }) 83 }) 84 }) 85 86 Describe("SetMTU", func() { 87 Context("when the interface does not exist", func() { 88 It("returns an error", func() { 89 Expect(l.SetMTU(&net.Interface{Name: "something"}, 1234)).ToNot(Succeed()) 90 }) 91 }) 92 93 Context("when the interface exists", func() { 94 It("sets the mtu", func() { 95 Expect(l.SetMTU(intf, 1234)).To(Succeed()) 96 97 intf, err := net.InterfaceByName(name) 98 Expect(err).ToNot(HaveOccurred()) 99 Expect(intf.MTU).To(Equal(1234)) 100 }) 101 }) 102 }) 103 104 Describe("SetNs", func() { 105 BeforeEach(func() { 106 cmd, err := gexec.Start(exec.Command("sh", "-c", "ip netns add gdnsetnstest"), GinkgoWriter, GinkgoWriter) 107 Expect(err).ToNot(HaveOccurred()) 108 Eventually(cmd).Should(gexec.Exit(0)) 109 }) 110 111 AfterEach(func() { 112 cmd, err := gexec.Start(exec.Command("sh", "-c", "ip netns delete gdnsetnstest"), GinkgoWriter, GinkgoWriter) 113 Expect(err).ToNot(HaveOccurred()) 114 Eventually(cmd).Should(gexec.Exit(0)) 115 }) 116 117 It("moves the interface in to the given namespace by pid", func() { 118 // look at this perfectly ordinary hat 119 netns, err := gexec.Start(exec.Command("ip", "netns", "exec", "gdnsetnstest", "sleep", "6312736"), GinkgoWriter, GinkgoWriter) 120 Expect(err).ToNot(HaveOccurred()) 121 defer netns.Kill() 122 123 // (it has the following pid) 124 ps, err := gexec.Start(exec.Command("sh", "-c", "ps -A -opid,command | grep 'sleep 6312736' | head -n 1 | awk '{print $1}'"), GinkgoWriter, GinkgoWriter) // look at my hat 125 Expect(err).ToNot(HaveOccurred()) 126 Eventually(ps).Should(gexec.Exit(0)) 127 pid, err := strconv.Atoi(strings.TrimSuffix(string(ps.Out.Contents()), "\n")) 128 Expect(err).ToNot(HaveOccurred()) 129 130 // I wave the magic wand 131 Expect(l.SetNs(intf, pid)).To(Succeed()) 132 133 // the bunny has vanished! where is the bunny? 134 intfs, _ := net.Interfaces() 135 Expect(intfs).ToNot(ContainElement(intf)) 136 137 // oh my word it's in the hat! 138 session, err := gexec.Start(exec.Command("sh", "-c", fmt.Sprintf("ip netns exec gdnsetnstest ifconfig %s", name)), GinkgoWriter, GinkgoWriter) 139 Expect(err).ToNot(HaveOccurred()) 140 Eventually(session).Should(gexec.Exit(0)) 141 142 }) 143 }) 144 145 Describe("InterfaceByName", func() { 146 Context("when the interface exists", func() { 147 It("returns the interface with the given name, and true", func() { 148 returnedIntf, found, err := l.InterfaceByName(name) 149 Expect(err).ToNot(HaveOccurred()) 150 151 Expect(returnedIntf).To(Equal(intf)) 152 Expect(found).To(BeTrue()) 153 }) 154 }) 155 156 Context("when the interface does not exist", func() { 157 It("does not return an error", func() { 158 _, found, err := l.InterfaceByName("sandwich") 159 Expect(err).ToNot(HaveOccurred()) 160 Expect(found).To(BeFalse()) 161 }) 162 }) 163 }) 164 165 Describe("List", func() { 166 It("lists all the interfaces", func() { 167 names, err := l.List() 168 Expect(err).ToNot(HaveOccurred()) 169 170 Expect(names).To(ContainElement(name)) 171 }) 172 }) 173 174 Describe("Statistics", func() { 175 176 Context("When the interface exist", func() { 177 BeforeEach(func() { 178 cmd, err := gexec.Start(exec.Command( 179 "sh", "-c", ` 180 ip netns add netns1 181 ip link add veth0 type veth peer name veth1 182 ip link set veth1 netns netns1 183 ip netns exec netns1 ifconfig veth1 10.1.1.1/24 up 184 ifconfig veth0 10.1.1.2/24 up 185 `, 186 ), GinkgoWriter, GinkgoWriter) 187 Expect(err).ToNot(HaveOccurred()) 188 Eventually(cmd, "10s").Should(gexec.Exit(0)) 189 }) 190 191 AfterEach(func() { 192 cmd, err := gexec.Start(exec.Command( 193 "sh", "-c", ` 194 ip netns exec netns1 ip link del veth1 195 ip netns delete netns1 196 `, 197 ), GinkgoWriter, GinkgoWriter) 198 Expect(err).ToNot(HaveOccurred()) 199 Eventually(cmd).Should(gexec.Exit(0)) 200 }) 201 202 It("Gets statistics from the interface", func() { 203 link := devices.Link{Name: "veth0"} 204 beforeStat, err := link.Statistics() 205 Expect(err).ToNot(HaveOccurred()) 206 cmd, err := gexec.Start(exec.Command( 207 "sh", "-c", ` 208 ping -c 10 -s 80 10.1.1.1 209 `, 210 ), GinkgoWriter, GinkgoWriter) 211 Expect(err).ToNot(HaveOccurred()) 212 Eventually(cmd, "15s").Should(gexec.Exit(0)) 213 214 afterStat, err := link.Statistics() 215 Expect(err).ToNot(HaveOccurred()) 216 217 // size of ping packet is 42 + payload_size (80 bytes) 218 // there could be additional arp messages transferred and recieved 219 // so check for range instead of absolute values 220 Expect(afterStat.TxBytes).To(BeNumerically(">=", beforeStat.TxBytes+(10*(42+80)))) 221 Expect(afterStat.TxBytes).To(BeNumerically("<", beforeStat.TxBytes+(10*(42+80))+1000)) 222 Expect(afterStat.RxBytes).To(BeNumerically(">=", beforeStat.RxBytes+(10*(42+80)))) 223 Expect(afterStat.RxBytes).To(BeNumerically("<", beforeStat.RxBytes+(10*(42+80))+1000)) 224 }) 225 }) 226 227 Context("when the interface does not exist", func() { 228 It("Gets statistics return an error", func() { 229 link := devices.Link{Name: "non-existent-intf"} 230 _, err := link.Statistics() 231 Expect(err).To(HaveOccurred()) 232 }) 233 }) 234 }) 235 })