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  })