blob: 6b7e9ffdd1a18dfeeff9ba8c5b19555a6807ed8a [file] [log] [blame]
Chetan Gaonkercbe79642016-03-09 17:45:58 -08001import unittest
2from nose.tools import *
3from nose.twistedtools import reactor, deferred
4from twisted.internet import defer
5from scapy.all import *
6import time, monotonic
7import os, sys
8import tempfile
9import random
10import threading
11from Stats import Stats
12from OnosCtrl import OnosCtrl
13from DHCP import DHCPTest
14from EapTLS import TLSAuthTest
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -070015from Channels import Channels, IgmpChannel
Chetan Gaonker41d2e072016-03-15 16:41:31 -070016from subscriberDb import SubscriberDB
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -070017from threadPool import ThreadPool
Chetan Gaonkercbe79642016-03-09 17:45:58 -080018log.setLevel('INFO')
19
20class Subscriber(Channels):
21
22 STATS_RX = 0
23 STATS_TX = 1
24 STATS_JOIN = 2
25 STATS_LEAVE = 3
Chetan Gaonker41d2e072016-03-15 16:41:31 -070026 SUBSCRIBER_SERVICES = 'DHCP IGMP TLS'
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -070027 def __init__(self, name = 'sub', service = SUBSCRIBER_SERVICES, num = 1, channel_start = 0,
28 iface = 'veth0', iface_mcast = 'veth2',
Chetan Gaonkercbe79642016-03-09 17:45:58 -080029 mcast_cb = None, loginType = 'wireless'):
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -070030 Channels.__init__(self, num, channel_start = channel_start,
31 iface = iface, iface_mcast = iface_mcast, mcast_cb = mcast_cb)
Chetan Gaonker41d2e072016-03-15 16:41:31 -070032 self.name = name
33 self.service = service
34 self.service_map = {}
35 services = self.service.strip().split(' ')
36 for s in services:
37 self.service_map[s] = True
Chetan Gaonkercbe79642016-03-09 17:45:58 -080038 self.loginType = loginType
39 ##start streaming channels
40 self.join_map = {}
41 ##accumulated join recv stats
42 self.join_rx_stats = Stats()
43
Chetan Gaonker41d2e072016-03-15 16:41:31 -070044 def has_service(self, service):
45 if self.service_map.has_key(service):
46 return self.service_map[service]
47 if self.service_map.has_key(service.upper()):
48 return self.service_map[service.upper()]
49 return False
50
Chetan Gaonkercbe79642016-03-09 17:45:58 -080051 def channel_join_update(self, chan, join_time):
52 self.join_map[chan] = ( Stats(), Stats(), Stats(), Stats() )
53 self.channel_update(chan, self.STATS_JOIN, 1, t = join_time)
54
55 def channel_join(self, chan = 0, delay = 2):
56 '''Join a channel and create a send/recv stats map'''
57 if self.join_map.has_key(chan):
58 del self.join_map[chan]
59 self.delay = delay
60 chan, join_time = self.join(chan)
61 self.channel_join_update(chan, join_time)
62 return chan
63
64 def channel_join_next(self, delay = 2):
65 '''Joins the next channel leaving the last channel'''
66 if self.last_chan:
67 if self.join_map.has_key(self.last_chan):
68 del self.join_map[self.last_chan]
69 self.delay = delay
70 chan, join_time = self.join_next()
71 self.channel_join_update(chan, join_time)
72 return chan
73
74 def channel_jump(self, delay = 2):
75 '''Jumps randomly to the next channel leaving the last channel'''
76 if self.last_chan is not None:
77 if self.join_map.has_key(self.last_chan):
78 del self.join_map[self.last_chan]
79 self.delay = delay
80 chan, join_time = self.jump()
81 self.channel_join_update(chan, join_time)
82 return chan
83
84 def channel_leave(self, chan = 0):
85 if self.join_map.has_key(chan):
86 del self.join_map[chan]
87 self.leave(chan)
88
89 def channel_update(self, chan, stats_type, packets, t=0):
90 if type(chan) == type(0):
91 chan_list = (chan,)
92 else:
93 chan_list = chan
94 for c in chan_list:
95 if self.join_map.has_key(c):
96 self.join_map[c][stats_type].update(packets = packets, t = t)
97
98 def channel_receive(self, chan, cb = None, count = 1):
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -070099 log.info('Subscriber %s receiving from group %s, channel %d' %(self.name, self.gaddr(chan), chan))
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800100 self.recv(chan, cb = cb, count = count)
101
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700102 def recv_channel_cb(self, pkt):
103 ##First verify that we have received the packet for the joined instance
104 log.debug('Packet received for group %s, subscriber %s' %(pkt[IP].dst, self.name))
105 chan = self.caddr(pkt[IP].dst)
106 assert_equal(chan in self.join_map.keys(), True)
107 recv_time = monotonic.monotonic() * 1000000
108 join_time = self.join_map[chan][self.STATS_JOIN].start
109 delta = recv_time - join_time
110 self.join_rx_stats.update(packets=1, t = delta, usecs = True)
111 self.channel_update(chan, self.STATS_RX, 1, t = delta)
112 log.debug('Packet received in %.3f usecs for group %s after join' %(delta, pkt[IP].dst))
113
114class subscriber_pool:
115
116 def __init__(self, subscriber, test_cbs):
117 self.subscriber = subscriber
118 self.test_cbs = test_cbs
119
120 def pool_cb(self):
121 for cb in self.test_cbs:
122 if cb:
123 cb(self.subscriber)
124
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800125class subscriber_exchange(unittest.TestCase):
126
127 apps = [ 'org.onosproject.aaa', 'org.onosproject.dhcp' ]
128
129 dhcp_server_config = {
130 "ip": "10.1.11.50",
131 "mac": "ca:fe:ca:fe:ca:fe",
132 "subnet": "255.255.252.0",
133 "broadcast": "10.1.11.255",
134 "router": "10.1.8.1",
135 "domain": "8.8.8.8",
136 "ttl": "63",
137 "delay": "2",
138 "startip": "10.1.11.51",
139 "endip": "10.1.11.100"
140 }
141
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700142 aaa_loaded = False
143
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800144 def setUp(self):
145 ''' Activate the dhcp and igmp apps'''
146 for app in self.apps:
147 onos_ctrl = OnosCtrl(app)
148 status, _ = onos_ctrl.activate()
149 assert_equal(status, True)
150 time.sleep(2)
151
152 def teardown(self):
153 '''Deactivate the dhcp app'''
154 for app in self.apps:
155 onos_ctrl = OnosCtrl(app)
156 onos_ctrl.deactivate()
157
158 def onos_aaa_load(self):
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700159 if self.aaa_loaded:
160 return
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800161 aaa_dict = {'apps' : { 'org.onosproject.aaa' : { 'AAA' : { 'radiusSecret': 'radius_password',
162 'radiusIp': '172.17.0.2' } } } }
163 radius_ip = os.getenv('ONOS_AAA_IP') or '172.17.0.2'
164 aaa_dict['apps']['org.onosproject.aaa']['AAA']['radiusIp'] = radius_ip
165 self.onos_load_config('org.onosproject.aaa', aaa_dict)
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700166 self.aaa_loaded = True
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800167
168 def onos_dhcp_table_load(self, config = None):
169 dhcp_dict = {'apps' : { 'org.onosproject.dhcp' : { 'dhcp' : copy.copy(self.dhcp_server_config) } } }
170 dhcp_config = dhcp_dict['apps']['org.onosproject.dhcp']['dhcp']
171 if config:
172 for k in config.keys():
173 if dhcp_config.has_key(k):
174 dhcp_config[k] = config[k]
175 self.onos_load_config('org.onosproject.dhcp', dhcp_dict)
176
177 def onos_load_config(self, app, config):
178 onos_ctrl = OnosCtrl(app)
179 status, code = onos_ctrl.config(config)
180 if status is False:
181 log.info('JSON config request for app %s returned status %d' %(app, code))
182 assert_equal(status, True)
183 time.sleep(2)
184
185 def dhcp_sndrcv(self, update_seed = False):
186 cip, sip = self.dhcp.discover(update_seed = update_seed)
187 assert_not_equal(cip, None)
188 assert_not_equal(sip, None)
189 log.info('Got dhcp client IP %s from server %s for mac %s' %
190 (cip, sip, self.dhcp.get_mac(cip)[0]))
191 return cip,sip
192
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700193 def dhcp_request(self, seed_ip = '10.10.10.1', iface = 'veth0', update_seed = False):
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800194 config = {'startip':'10.10.10.20', 'endip':'10.10.10.69',
195 'ip':'10.10.10.2', 'mac': "ca:fe:ca:fe:ca:fe",
196 'subnet': '255.255.255.0', 'broadcast':'10.10.10.255', 'router':'10.10.10.1'}
197 self.onos_dhcp_table_load(config)
198 self.dhcp = DHCPTest(seed_ip = seed_ip, iface = iface)
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700199 cip, sip = self.dhcp_sndrcv(update_seed = update_seed)
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800200 return cip, sip
201
202 def recv_channel_cb(self, pkt):
203 ##First verify that we have received the packet for the joined instance
204 chan = self.subscriber.caddr(pkt[IP].dst)
205 assert_equal(chan in self.subscriber.join_map.keys(), True)
206 recv_time = monotonic.monotonic() * 1000000
207 join_time = self.subscriber.join_map[chan][self.subscriber.STATS_JOIN].start
208 delta = recv_time - join_time
209 self.subscriber.join_rx_stats.update(packets=1, t = delta, usecs = True)
210 self.subscriber.channel_update(chan, self.subscriber.STATS_RX, 1, t = delta)
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700211 log.debug('Packet received in %.3f usecs for group %s after join' %(delta, pkt[IP].dst))
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800212 self.test_status = True
213
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700214 def tls_verify(self, subscriber):
215 if subscriber.has_service('TLS'):
216 time.sleep(2)
217 tls = TLSAuthTest()
218 log.info('Running subscriber %s tls auth test' %subscriber.name)
219 tls.runTest()
220 self.test_status = True
221
222 def dhcp_verify(self, subscriber):
223 cip, sip = self.dhcp_request(iface = subscriber.iface, update_seed = True)
224 log.info('Subscriber %s got client ip %s from server %s' %(subscriber.name, cip, sip))
225 subscriber.src_list = [cip]
226 self.test_status = True
227
228 def dhcp_jump_verify(self, subscriber):
229 cip, sip = self.dhcp_request(seed_ip = '10.10.200.1', iface = subscriber.iface)
230 log.info('Subscriber %s got client ip %s from server %s' %(subscriber.name, cip, sip))
231 subscriber.src_list = [cip]
232 self.test_status = True
233
234 def dhcp_next_verify(self, subscriber):
235 cip, sip = self.dhcp_request(seed_ip = '10.10.150.1', iface = subscriber.iface)
236 log.info('Subscriber %s got client ip %s from server %s' %(subscriber.name, cip, sip))
237 subscriber.src_list = [cip]
238 self.test_status = True
239
240 def igmp_verify(self, subscriber):
241 chan = 0
242 if subscriber.has_service('IGMP'):
243 for i in range(5):
244 log.info('Joining channel %d for subscriber %s' %(chan, subscriber.name))
245 subscriber.channel_join(chan, delay = 0)
246 subscriber.channel_receive(chan, cb = subscriber.recv_channel_cb, count = 1)
247 log.info('Leaving channel %d for subscriber %s' %(chan, subscriber.name))
248 subscriber.channel_leave(chan)
249 time.sleep(3)
250 log.info('Join RX stats for subscriber %s, %s' %(subscriber.name,subscriber.join_rx_stats))
251 self.test_status = True
252
253 def igmp_jump_verify(self, subscriber):
254 if subscriber.has_service('IGMP'):
255 for i in xrange(subscriber.num):
256 log.info('Subscriber %s jumping channel' %subscriber.name)
257 chan = subscriber.channel_jump(delay=0)
258 subscriber.channel_receive(chan, cb = subscriber.recv_channel_cb, count = 1)
259 log.info('Verified receive for channel %d, subscriber %s' %(chan, subscriber.name))
260 time.sleep(3)
261 log.info('Join RX stats for subscriber %s, %s' %(subscriber.name, subscriber.join_rx_stats))
262 self.test_status = True
263
264 def igmp_next_verify(self, subscriber):
265 if subscriber.has_service('IGMP'):
266 for i in xrange(subscriber.num):
267 if i:
268 chan = subscriber.channel_join_next(delay=0)
269 else:
270 chan = subscriber.channel_join(i, delay=0)
271 log.info('Joined next channel %d for subscriber %s' %(chan, subscriber.name))
272 subscriber.channel_receive(chan, cb = subscriber.recv_channel_cb, count=1)
273 log.info('Verified receive for channel %d, subscriber %s' %(chan, subscriber.name))
274 time.sleep(3)
275 log.info('Join Next RX stats for subscriber %s, %s' %(subscriber.name, subscriber.join_rx_stats))
276 self.test_status = True
277
278 def subscriber_load(self, create = True, num = 10, num_channels = 1, channel_start = 0):
Chetan Gaonker41d2e072016-03-15 16:41:31 -0700279 '''Load the subscriber from the database'''
280 self.subscriber_db = SubscriberDB(create = create)
281 if create is True:
282 self.subscriber_db.generate(num)
283 self.subscriber_info = self.subscriber_db.read(num)
284 self.subscriber_list = []
285 for info in self.subscriber_info:
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700286 self.subscriber_list.append(Subscriber(name=info['Name'],
287 service=info['Service'],
288 num=num_channels,
289 channel_start = channel_start))
290 channel_start += num_channels
291
292 #load the ssm list for all subscriber channels
293 igmpChannel = IgmpChannel()
294 ssm_groups = map(lambda sub: sub.channels, self.subscriber_list)
295 ssm_list = reduce(lambda ssm1, ssm2: ssm1+ssm2, ssm_groups)
296 igmpChannel.igmp_load_ssm_config(ssm_list)
Chetan Gaonker41d2e072016-03-15 16:41:31 -0700297
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700298 def subscriber_join_verify( self, num_subscribers = 10, num_channels = 1,
299 channel_start = 0, cbs = None):
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800300 self.test_status = False
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700301 self.num_subscribers = num_subscribers
302 self.subscriber_load(create = True, num = self.num_subscribers,
303 num_channels = num_channels, channel_start = channel_start)
Chetan Gaonker55fc7882016-03-15 17:46:47 -0700304 self.onos_aaa_load()
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700305 self.thread_pool = ThreadPool(min(100, self.num_subscribers), queue_size=1, wait_timeout=1)
306 if cbs is None:
307 cbs = (self.tls_verify, self.dhcp_verify, self.igmp_verify)
Chetan Gaonker41d2e072016-03-15 16:41:31 -0700308 for subscriber in self.subscriber_list:
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700309 subscriber.start()
310 pool_object = subscriber_pool(subscriber, cbs)
311 self.thread_pool.addTask(pool_object.pool_cb)
312 self.thread_pool.cleanUpThreads()
313 for subscriber in self.subscriber_list:
314 subscriber.stop()
315 return self.test_status
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800316
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700317 def test_subscriber_join_recv(self):
318 """Test subscriber join and receive"""
319 test_status = self.subscriber_join_verify(num_subscribers = 50, num_channels = 1)
320 assert_equal(test_status, True)
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800321
322 def test_subscriber_join_jump(self):
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700323 """Test subscriber join and receive for channel surfing"""
324 test_status = self.subscriber_join_verify(num_subscribers = 5,
325 num_channels = 50,
326 cbs = (self.tls_verify, self.dhcp_jump_verify, self.igmp_jump_verify))
327 assert_equal(test_status, True)
Chetan Gaonker4b959fc2016-03-09 19:20:16 -0800328
329 def test_subscriber_join_next(self):
330 """Test subscriber join next for channels"""
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700331 test_status = self.subscriber_join_verify(num_subscribers = 5,
332 num_channels = 50,
333 cbs = (self.tls_verify, self.dhcp_next_verify, self.igmp_next_verify))
334 assert_equal(test_status, True)