22
33/*
44 * Copyright (C) 2019 Red Hat, Inc.
5+ * Copyright (c) 2019 PANTHEON.tech s.r.o.
56 *
67 * Licensed under the Apache License, Version 2.0 (the "License");
78 * you may not use this file except in compliance with the License.
@@ -27,9 +28,15 @@ import (
2728 "time"
2829
2930 "github.com/skydive-project/skydive/graffiti/graph"
31+ "github.com/skydive-project/skydive/gremlin"
3032 "github.com/skydive-project/skydive/topology/probes/vpp"
3133)
3234
35+ const (
36+ dockerImageWithRunningVPP = "ligato/vpp-base:19.04"
37+ vppWaitScript = "sh -c 'retry=%d;until docker exec %s vppctl sh version || [ $retry -eq 0 ]; do retry=$(( retry-1 ));sleep 0.5s;echo \" VPP not ready-retries left \" $retry;done'"
38+ )
39+
3340func createLoopback (t * testing.T ) string {
3441 cmd := "vppctl loopback create-interface"
3542 out , err := exec .Command ("/bin/sh" , "-c" , cmd ).CombinedOutput ()
@@ -99,3 +106,120 @@ func TestVPPLoopback(t *testing.T) {
99106 }
100107 RunTest (t , test )
101108}
109+
110+ func TestVPPInDocker (t * testing.T ) {
111+ test := & Test {
112+ setupCmds : []Cmd {
113+ {fmt .Sprintf ("docker run -d -t -i --privileged --name test-skydive-docker-running-vpp %s" , dockerImageWithRunningVPP ), false },
114+ {fmt .Sprintf (vppWaitScript , 30 , "test-skydive-docker-running-vpp" ), true },
115+ },
116+
117+ tearDownCmds : []Cmd {
118+ {"docker rm -f test-skydive-docker-running-vpp" , false },
119+ },
120+
121+ mode : Replay ,
122+
123+ checks : []CheckFunction {func (c * CheckContext ) error {
124+ return assertOneEndNode (c , c .gremlin .V ().Has ("Type" , "netns" ).
125+ Out ("Type" , "vpp" ))
126+ }},
127+ }
128+
129+ RunTest (t , test )
130+ }
131+
132+ func TestVPPConnectingToVeth (t * testing.T ) {
133+ test := & Test {
134+ setupCmds : []Cmd {
135+ {fmt .Sprintf ("docker run -d -t -i --privileged --name test-skydive-docker-vpp-to-veth %s" , dockerImageWithRunningVPP ), false },
136+ {fmt .Sprintf (vppWaitScript , 30 , "test-skydive-docker-vpp-to-veth" ), true },
137+ {"docker exec test-skydive-docker-vpp-to-veth ip link add name veth-container type veth peer name veth-host" , true }, // creating veth tunnel (that can be used to tunnel docker container and docker host)
138+ {"docker exec test-skydive-docker-vpp-to-veth ip link set dev veth-container up" , true },
139+ {"docker exec test-skydive-docker-vpp-to-veth ip link set dev veth-host up" , true }, // no need for this test to actually push veth-host to network namespace of docker host OS
140+ {"docker exec test-skydive-docker-vpp-to-veth vppctl create host-interface name veth-container" , true }, // grabbing and using veth-container end of tunnel in VPP
141+ {"docker exec test-skydive-docker-vpp-to-veth vppctl set int state host-veth-container up" , true },
142+ },
143+
144+ tearDownCmds : []Cmd {
145+ {"docker rm -f test-skydive-docker-vpp-to-veth" , false },
146+ },
147+
148+ mode : Replay ,
149+
150+ checks : []CheckFunction {func (c * CheckContext ) error {
151+ return assertOneEndNode (c , c .gremlin .V ().Has ("Type" , "interface" , "Driver" , "vpp" , "Name" , "host-veth-container" ).
152+ In ("Type" , "veth" , "Name" , "veth-container" ))
153+ }},
154+ }
155+
156+ RunTest (t , test )
157+ }
158+
159+ func TestVPPMemifTunnel (t * testing.T ) {
160+ vpp1Container := "test-skydive-docker-vpp1-with-memif-tunnel"
161+ vpp2Container := "test-skydive-docker-vpp2-with-memif-tunnel"
162+ test := & Test {
163+ setupCmds : []Cmd {
164+ // prepare container-shared folder (docker would create it automatically, but creating it now and with user that is running test resolves permission problems in teardown)
165+ {"mkdir /tmp/skydivetests-dockervpp-sockets" , false },
166+
167+ // starting docker contrainers
168+ {fmt .Sprintf ("docker run -d -t -i -v /tmp/skydivetests-dockervpp-sockets/:/run/othersockets/ --privileged --name %s %s" , vpp1Container , dockerImageWithRunningVPP ), false },
169+ {fmt .Sprintf ("docker run -d -t -i -v /tmp/skydivetests-dockervpp-sockets/:/run/othersockets/ --privileged --name %s %s" , vpp2Container , dockerImageWithRunningVPP ), false },
170+
171+ // waiting for VPPs to start inside containers
172+ {fmt .Sprintf (vppWaitScript , 30 , vpp1Container ), true },
173+ {fmt .Sprintf (vppWaitScript , 30 , vpp2Container ), true },
174+
175+ // creating memif tunnel
176+ {fmt .Sprintf ("docker exec %s vppctl create memif socket id 1 filename /run/othersockets/another-memif.sock" , vpp1Container ), true },
177+ {fmt .Sprintf ("docker exec %s vppctl create interface memif socket-id 1 id 0 master" , vpp1Container ), true },
178+ {fmt .Sprintf ("docker exec %s vppctl set int state memif1/0 up" , vpp1Container ), true },
179+ {fmt .Sprintf ("docker exec %s vppctl create memif socket id 1 filename /run/othersockets/another-memif.sock" , vpp2Container ), true },
180+ {fmt .Sprintf ("docker exec %s vppctl create interface memif socket-id 1 id 0 slave" , vpp2Container ), true },
181+ {fmt .Sprintf ("docker exec %s vppctl set int state memif1/0 up" , vpp2Container ), true },
182+ },
183+
184+ tearDownCmds : []Cmd {
185+ // removing memif socket file (it was created by VPP,but removing it from VPP doesn't remove the physical
186+ // file->removing reference from VPPs and removing it on docker container level to prevent permission problems)
187+ {fmt .Sprintf ("docker exec %s vppctl delete interface memif memif1/0" , vpp1Container ), true },
188+ {fmt .Sprintf ("docker exec %s vppctl delete interface memif memif1/0" , vpp2Container ), true },
189+ {fmt .Sprintf ("docker exec %s vppctl delete memif socket id 1" , vpp1Container ), true },
190+ {fmt .Sprintf ("docker exec %s vppctl delete memif socket id 1" , vpp2Container ), true },
191+ {fmt .Sprintf ("docker exec %s rm -rf /run/othersockets/another-memif.sock" , vpp1Container ), true },
192+
193+ // removing docker containers
194+ {fmt .Sprintf ("docker rm -f %s" , vpp1Container ), false },
195+ {fmt .Sprintf ("docker rm -f %s" , vpp2Container ), false },
196+
197+ // removing container-shared folder for memif socket file
198+ {"rm -rf /tmp/skydivetests-dockervpp-sockets" , true },
199+ },
200+
201+ mode : Replay ,
202+
203+ checks : []CheckFunction {func (c * CheckContext ) error {
204+ return assertOneEndNode (c , c .gremlin .V ().Has ("Type" , "vpp" , "Program" , "vpe" ).
205+ Out ("Type" , "interface" , "Name" , "memif1/0" , "VPP.SocketFilename" , "/run/othersockets/another-memif.sock" , "VPP.Master" , true ).
206+ Out ("Type" , "interface" , "Name" , "memif1/0" , "VPP.SocketFilename" , "/run/othersockets/another-memif.sock" , "VPP.Master" , false ).
207+ In ("Type" , "vpp" , "Program" , "vpe" ))
208+ }},
209+ }
210+
211+ RunTest (t , test )
212+ }
213+
214+ func assertOneEndNode (c * CheckContext , queryString gremlin.QueryString ) error {
215+ nodes , err := c .gh .GetNodes (queryString )
216+ if err != nil {
217+ return err
218+ }
219+
220+ if len (nodes ) != 1 {
221+ return fmt .Errorf ("expected 1 end node, got %+v" , nodes )
222+ }
223+
224+ return nil
225+ }
0 commit comments