Skip to content

Commit 1d03df4

Browse files
committed
[quagga]: update quagga submodule (sonic-net#1698)
* [quagga]: update quagga submodule 0bc6bd6 2018-05-11 | ignore nexthop attribute when NLRI is present (#18) (HEAD, origin/debian/0.99.24.1, origin/HEAD) [lguohan] Signed-off-by: Guohan Lu <gulv@microsoft.com> * add vs bgp test Signed-off-by: Guohan Lu <gulv@microsoft.com>
1 parent 0dca563 commit 1d03df4

File tree

7 files changed

+295
-2
lines changed

7 files changed

+295
-2
lines changed

platform/vs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ sw-srv0 (id: 5)
4444
2. Start sonic virtual switch docker
4545

4646
```
47-
$ docker run --privileged --network container:sw -d docker-sonic-vs
47+
$ docker run --privileged --network container:sw --name vs -d docker-sonic-vs
4848
```
4949

5050
3. Setup IP in the virtual switch docker

platform/vs/tests/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Requirements:
2+
3+
- Enable IPv6 for docker engine
4+
- pip install exabgp
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
router bgp 65501
2+
bgp router-id 1.1.1.1
3+
no bgp default ipv4-unicast
4+
neighbor fc00::2 remote-as 65502
5+
address-family ipv6
6+
neighbor fc00::2 activate
7+
exit-address-family
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
neighbor fc00::1 {
2+
router-id 1.2.3.4;
3+
local-address fc00::2;
4+
local-as 65502;
5+
peer-as 65501;
6+
group-updates false;
7+
8+
family {
9+
ipv4 unicast;
10+
ipv6 unicast;
11+
}
12+
13+
static {
14+
route 3333::0/64 {
15+
next-hop 0.0.0.0;
16+
next-hop fc00::2;
17+
}
18+
}
19+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from swsscommon import swsscommon
2+
import os
3+
import re
4+
import time
5+
import json
6+
7+
def test_InvalidNexthop(dvs):
8+
9+
dvs.copy_file("/etc/quagga/", "bgp/files/bgpd.conf")
10+
dvs.runcmd("supervisorctl start bgpd")
11+
dvs.runcmd("ip addr add fc00::1/126 dev Ethernet0")
12+
dvs.runcmd("ifconfig Ethernet0 up")
13+
14+
dvs.servers[0].runcmd("ip addr add fc00::2/126 dev eth0")
15+
dvs.servers[0].runcmd("ifconfig eth0 up")
16+
17+
time.sleep(5)
18+
19+
print dvs.runcmd("supervisorctl status")
20+
21+
p = dvs.servers[0].runcmd_async("exabgp -d bgp/files/invalid_nexthop.conf")
22+
23+
time.sleep(10)
24+
25+
output = dvs.runcmd(["vtysh", "-c", "show ipv6 bgp"])
26+
27+
p.terminate()
28+
p = p.wait()
29+
30+
print output
31+
32+
assert "3333::/64" in output

platform/vs/tests/conftest.py

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
import os
2+
import os.path
3+
import re
4+
import time
5+
import docker
6+
import pytest
7+
import commands
8+
import tarfile
9+
import StringIO
10+
import subprocess
11+
from swsscommon import swsscommon
12+
13+
def pytest_addoption(parser):
14+
parser.addoption("--dvsname", action="store", default=None,
15+
help="dvs name")
16+
17+
class AsicDbValidator(object):
18+
def __init__(self, dvs):
19+
self.adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)
20+
21+
# get default dot1q vlan id
22+
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN")
23+
24+
keys = atbl.getKeys()
25+
assert len(keys) == 1
26+
self.default_vlan_id = keys[0]
27+
28+
# build port oid to front port name mapping
29+
self.portoidmap = {}
30+
self.portnamemap = {}
31+
self.hostifoidmap = {}
32+
self.hostifnamemap = {}
33+
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF")
34+
keys = atbl.getKeys()
35+
36+
assert len(keys) == 32
37+
for k in keys:
38+
(status, fvs) = atbl.get(k)
39+
40+
assert status == True
41+
42+
for fv in fvs:
43+
if fv[0] == "SAI_HOSTIF_ATTR_OBJ_ID":
44+
port_oid = fv[1]
45+
elif fv[0] == "SAI_HOSTIF_ATTR_NAME":
46+
port_name = fv[1]
47+
48+
self.portoidmap[port_oid] = port_name
49+
self.portnamemap[port_name] = port_oid
50+
self.hostifoidmap[k] = port_name
51+
self.hostifnamemap[port_name] = k
52+
53+
# get default acl table and acl rules
54+
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE")
55+
keys = atbl.getKeys()
56+
57+
assert len(keys) == 1
58+
self.default_acl_table = keys[0]
59+
60+
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY")
61+
keys = atbl.getKeys()
62+
63+
assert len(keys) == 2
64+
self.default_acl_entries = keys
65+
66+
class VirtualServer(object):
67+
def __init__(self, ctn_name, pid, i):
68+
self.nsname = "%s-srv%d" % (ctn_name, i)
69+
self.vifname = "vEthernet%d" % (i * 4)
70+
self.cleanup = True
71+
72+
# create netns
73+
if os.path.exists("/var/run/netns/%s" % self.nsname):
74+
self.cleanup = False
75+
else:
76+
os.system("ip netns add %s" % self.nsname)
77+
78+
# create vpeer link
79+
os.system("ip link add %s type veth peer name %s" % (self.nsname[0:12], self.vifname))
80+
os.system("ip link set %s netns %s" % (self.nsname[0:12], self.nsname))
81+
os.system("ip link set %s netns %d" % (self.vifname, pid))
82+
83+
# bring up link in the virtual server
84+
os.system("ip netns exec %s ip link set dev %s name eth0" % (self.nsname, self.nsname[0:12]))
85+
os.system("ip netns exec %s ip link set dev eth0 up" % (self.nsname))
86+
os.system("ip netns exec %s ethtool -K eth0 tx off" % (self.nsname))
87+
88+
# bring up link in the virtual switch
89+
os.system("nsenter -t %d -n ip link set dev %s up" % (pid, self.vifname))
90+
91+
def __del__(self):
92+
if self.cleanup:
93+
os.system("ip netns delete %s" % self.nsname)
94+
95+
def runcmd(self, cmd):
96+
os.system("ip netns exec %s %s" % (self.nsname, cmd))
97+
98+
def runcmd_async(self, cmd):
99+
return subprocess.Popen("ip netns exec %s %s" % (self.nsname, cmd), shell=True)
100+
101+
class DockerVirtualSwitch(object):
102+
def __init__(self, name=None):
103+
self.pnames = ['fpmsyncd',
104+
'intfmgrd',
105+
'intfsyncd',
106+
'neighsyncd',
107+
'orchagent',
108+
'portsyncd',
109+
'redis-server',
110+
'rsyslogd',
111+
'syncd',
112+
'teamsyncd',
113+
'vlanmgrd',
114+
'zebra']
115+
self.mount = "/var/run/redis-vs"
116+
self.redis_sock = self.mount + '/' + "redis.sock"
117+
self.client = docker.from_env()
118+
119+
self.ctn = None
120+
self.cleanup = True
121+
if name != None:
122+
# get virtual switch container
123+
for ctn in self.client.containers.list():
124+
if ctn.name == name:
125+
self.ctn = ctn
126+
(status, output) = commands.getstatusoutput("docker inspect --format '{{.HostConfig.NetworkMode}}' %s" % name)
127+
ctn_sw_id = output.split(':')[1]
128+
self.cleanup = False
129+
if self.ctn == None:
130+
raise NameError("cannot find container %s" % name)
131+
132+
# get base container
133+
for ctn in self.client.containers.list():
134+
if ctn.id == ctn_sw_id or ctn.name == ctn_sw_id:
135+
ctn_sw_name = ctn.name
136+
137+
(status, output) = commands.getstatusoutput("docker inspect --format '{{.State.Pid}}' %s" % ctn_sw_name)
138+
self.ctn_sw_pid = int(output)
139+
140+
# create virtual servers
141+
self.servers = []
142+
for i in range(32):
143+
server = VirtualServer(ctn_sw_name, self.ctn_sw_pid, i)
144+
self.servers.append(server)
145+
146+
self.restart()
147+
else:
148+
self.ctn_sw = self.client.containers.run('debian:jessie', privileged=True, detach=True,
149+
command="bash", stdin_open=True)
150+
(status, output) = commands.getstatusoutput("docker inspect --format '{{.State.Pid}}' %s" % self.ctn_sw.name)
151+
self.ctn_sw_pid = int(output)
152+
153+
# create virtual server
154+
self.servers = []
155+
for i in range(32):
156+
server = VirtualServer(self.ctn_sw.name, self.ctn_sw_pid, i)
157+
self.servers.append(server)
158+
159+
# create virtual switch container
160+
self.ctn = self.client.containers.run('docker-sonic-vs', privileged=True, detach=True,
161+
network_mode="container:%s" % self.ctn_sw.name,
162+
volumes={ self.mount: { 'bind': '/var/run/redis', 'mode': 'rw' } })
163+
164+
self.ctn.exec_run("sysctl -w net.ipv6.conf.all.disable_ipv6=0")
165+
self.check_ready()
166+
self.init_asicdb_validator()
167+
168+
def destroy(self):
169+
if self.cleanup:
170+
self.ctn.remove(force=True)
171+
self.ctn_sw.remove(force=True)
172+
for s in self.servers:
173+
del(s)
174+
175+
def check_ready(self, timeout=30):
176+
'''check if all processes in the dvs is ready'''
177+
178+
re_space = re.compile('\s+')
179+
process_status = {}
180+
ready = False
181+
started = 0
182+
while True:
183+
# get process status
184+
out = self.ctn.exec_run("supervisorctl status")
185+
for l in out.split('\n'):
186+
fds = re_space.split(l)
187+
if len(fds) < 2:
188+
continue
189+
process_status[fds[0]] = fds[1]
190+
191+
# check if all processes are running
192+
ready = True
193+
for pname in self.pnames:
194+
try:
195+
if process_status[pname] != "RUNNING":
196+
ready = False
197+
except KeyError:
198+
ready = False
199+
200+
if ready == True:
201+
break
202+
203+
started += 1
204+
if started > timeout:
205+
raise ValueError(out)
206+
207+
time.sleep(1)
208+
209+
def restart(self):
210+
self.ctn.restart()
211+
212+
def init_asicdb_validator(self):
213+
self.asicdb = AsicDbValidator(self)
214+
215+
def runcmd(self, cmd):
216+
return self.ctn.exec_run(cmd)
217+
218+
def copy_file(self, path, filename):
219+
tarstr = StringIO.StringIO()
220+
tar = tarfile.open(fileobj=tarstr, mode="w")
221+
tar.add(filename, os.path.basename(filename))
222+
tar.close()
223+
self.ctn.put_archive(path, tarstr.getvalue())
224+
tarstr.close()
225+
226+
@pytest.yield_fixture(scope="module")
227+
def dvs(request):
228+
name = request.config.getoption("--dvsname")
229+
dvs = DockerVirtualSwitch(name)
230+
yield dvs
231+
dvs.destroy()

src/sonic-quagga

0 commit comments

Comments
 (0)