blob: 6c4346ca1b85d69047e3039388b3aa0471e0f5e9 [file] [log] [blame]
Matteo Scandolo48d3d2d2017-08-08 13:05:27 -07001
2# Copyright 2017-present Open Networking Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16
A R Karthick338268f2016-06-21 17:12:13 -070017#
Chetan Gaonkercfcce782016-05-10 10:10:42 -070018# Copyright 2016-present Ciena Corporation
19#
20# Licensed under the Apache License, Version 2.0 (the "License");
21# you may not use this file except in compliance with the License.
22# You may obtain a copy of the License at
A R Karthick338268f2016-06-21 17:12:13 -070023#
Chetan Gaonkercfcce782016-05-10 10:10:42 -070024# http://www.apache.org/licenses/LICENSE-2.0
A R Karthick338268f2016-06-21 17:12:13 -070025#
Chetan Gaonkercfcce782016-05-10 10:10:42 -070026# Unless required by applicable law or agreed to in writing, software
27# distributed under the License is distributed on an "AS IS" BASIS,
28# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29# See the License for the specific language governing permissions and
30# limitations under the License.
31#
Chetan Gaonkerb424ff82016-03-08 12:11:12 -080032import threading
33import sys
34import os
35import time
36import monotonic
37import random
A.R Karthick2e99c472017-03-22 19:13:51 -070038import logging
39logging.getLogger('scapy.runtime').setLevel(logging.ERROR)
Chetan Gaonkerb424ff82016-03-08 12:11:12 -080040from scapy.all import *
41from McastTraffic import *
42from IGMP import *
43from OnosCtrl import OnosCtrl
A R Karthick76a497a2017-04-12 10:59:39 -070044from CordTestUtils import log_test
Chetan Gaonkerb424ff82016-03-08 12:11:12 -080045from nose.tools import *
A R Karthick76a497a2017-04-12 10:59:39 -070046log_test.setLevel('DEBUG')
Chetan Gaonkerb424ff82016-03-08 12:11:12 -080047
48conf.verb = 0
49
50class IgmpChannel:
51
52 IGMP_DST_MAC = "01:00:5e:00:01:01"
53 IGMP_SRC_MAC = "5a:e1:ac:ec:4d:a1"
54 IP_SRC = '1.2.3.4'
55 IP_DST = '224.0.1.1'
56 igmp_eth = Ether(dst = IGMP_DST_MAC, src = IGMP_SRC_MAC, type = ETH_P_IP)
57 igmp_ip = IP(dst = IP_DST, src = IP_SRC)
A R Karthick338268f2016-06-21 17:12:13 -070058 ssm_list = []
Chetan Gaonkerb424ff82016-03-08 12:11:12 -080059
Thangavelu K S8e413082017-07-13 20:02:14 +000060 def __init__(self, iface = 'veth0', ssm_list = [], src_list = None, delay = 2,controller=None):
61
ChetanGaonker689b3862016-10-17 16:25:01 -070062 self.controller=controller
Chetan Gaonkerb424ff82016-03-08 12:11:12 -080063 self.iface = iface
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -070064 self.ssm_list += ssm_list
Thangavelu K S8e413082017-07-13 20:02:14 +000065 if src_list is None:
66 self.src_list = ['1.2.3.4']
67 else:
68 self.src_list = src_list
Chetan Gaonkerb424ff82016-03-08 12:11:12 -080069 self.delay = delay
A.R Karthick401a1ed2017-05-18 11:08:27 -070070 self.onos_ctrl = OnosCtrl('org.opencord.igmp',controller=self.controller)
Chetan Gaonkerb424ff82016-03-08 12:11:12 -080071 self.onos_ctrl.activate()
A R Karthick338268f2016-06-21 17:12:13 -070072
Thangavelu K S8e413082017-07-13 20:02:14 +000073 def igmp_load_ssm_config(self, ssm_list = [], src_list = None):
A R Karthick2f4e0ba2017-07-17 10:55:36 -070074 if src_list is None:
75 src_list = self.src_list
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -070076 if not ssm_list:
77 ssm_list = self.ssm_list
Thangavelu K S8e413082017-07-13 20:02:14 +000078 self.ssm_table_load(ssm_list, src_list = src_list)
Chetan Gaonkerb424ff82016-03-08 12:11:12 -080079
Thangavelu K S8e413082017-07-13 20:02:14 +000080 def igmp_join(self, groups, src_list = None, record_type = None):
A R Karthick2f4e0ba2017-07-17 10:55:36 -070081 if src_list is None:
82 src_list = self.src_list
Thangavelu K S8e413082017-07-13 20:02:14 +000083 if record_type is None:
84 record_type = IGMP_V3_GR_TYPE_INCLUDE
Chetan Gaonkerb424ff82016-03-08 12:11:12 -080085 igmp = IGMPv3(type = IGMP_TYPE_V3_MEMBERSHIP_REPORT, max_resp_code=30,
86 gaddr='224.0.1.1')
87 for g in groups:
Thangavelu K S8e413082017-07-13 20:02:14 +000088 gr = IGMPv3gr(rtype=record_type, mcaddr=g)
89 gr.sources = src_list
Chetan Gaonkerb424ff82016-03-08 12:11:12 -080090 igmp.grps.append(gr)
91
92 pkt = self.igmp_eth/self.igmp_ip/igmp
93 IGMPv3.fixup(pkt)
94 sendp(pkt, iface=self.iface)
95 if self.delay != 0:
96 time.sleep(self.delay)
97
Thangavelu K S8e413082017-07-13 20:02:14 +000098 def igmp_leave(self, groups, src_list = None):
A R Karthick2f4e0ba2017-07-17 10:55:36 -070099 if src_list is None:
100 src_list = self.src_list
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800101 igmp = IGMPv3(type = IGMP_TYPE_V3_MEMBERSHIP_REPORT, max_resp_code=30,
102 gaddr='224.0.1.1')
103 for g in groups:
Chetan Gaonker38737f82016-05-11 17:44:17 -0700104 gr = IGMPv3gr(rtype=IGMP_V3_GR_TYPE_EXCLUDE, mcaddr=g)
Thangavelu K S8e413082017-07-13 20:02:14 +0000105 gr.sources = src_list
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800106 igmp.grps.append(gr)
107
108 pkt = self.igmp_eth/self.igmp_ip/igmp
109 IGMPv3.fixup(pkt)
110 sendp(pkt, iface = self.iface)
111 if self.delay != 0:
112 time.sleep(self.delay)
113
114 def onos_load_config(self, config):
ChetanGaonker689b3862016-10-17 16:25:01 -0700115 status, code = OnosCtrl.config(config,controller=self.controller)
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800116 if status is False:
A R Karthick76a497a2017-04-12 10:59:39 -0700117 log_test.info('JSON config request returned status %d' %code)
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800118 time.sleep(2)
119
Thangavelu K S8e413082017-07-13 20:02:14 +0000120 def ssm_table_load(self, groups, src_list = None):
A R Karthick2f4e0ba2017-07-17 10:55:36 -0700121 return
122 if src_list is None:
123 src_list = self.src_list
A.R Karthick401a1ed2017-05-18 11:08:27 -0700124 ssm_dict = {'apps' : { 'org.opencord.igmp' : { 'ssmTranslate' : [] } } }
125 ssm_xlate_list = ssm_dict['apps']['org.opencord.igmp']['ssmTranslate']
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800126 for g in groups:
Thangavelu K S8e413082017-07-13 20:02:14 +0000127 for s in src_list:
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800128 d = {}
129 d['source'] = s
130 d['group'] = g
131 ssm_xlate_list.append(d)
132 self.onos_load_config(ssm_dict)
133
Chetan Gaonkera58ab6e2016-03-23 15:04:20 -0700134 def cord_port_table_load(self, cord_port_map):
A R Karthick2f4e0ba2017-07-17 10:55:36 -0700135 return
Chetan Gaonkera58ab6e2016-03-23 15:04:20 -0700136 cord_group_dict = {'apps' : { 'org.ciena.cordigmp' : { 'cordIgmpTranslate' : [] } } }
137 cord_group_xlate_list = cord_group_dict['apps']['org.ciena.cordigmp']['cordIgmpTranslate']
138 for group, ports in cord_port_map.items():
139 d = {}
140 d['group'] = group
141 d['inputPort'] = ports[0]
142 d['outputPort'] = ports[1]
143 cord_group_xlate_list.append(d)
144 self.onos_load_config(cord_group_dict)
145
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800146class Channels(IgmpChannel):
147 Stopped = 0
148 Started = 1
149 Idle = 0
150 Joined = 1
Thangavelu K S8e413082017-07-13 20:02:14 +0000151 def __init__(self, num, channel_start = 0, iface = 'veth0', iface_mcast = 'veth2', mcast_cb = None, src_list = None):
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800152 self.num = num
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700153 self.channel_start = channel_start
154 self.channels = self.generate(self.num, self.channel_start)
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800155 self.group_channel_map = {}
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700156 #assert_equal(len(self.channels), self.num)
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800157 for i in range(self.num):
158 self.group_channel_map[self.channels[i]] = i
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800159 self.state = self.Stopped
160 self.streams = None
161 self.channel_states = {}
162 self.last_chan = None
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800163 self.iface_mcast = iface_mcast
164 self.mcast_cb = mcast_cb
Thangavelu K S8e413082017-07-13 20:02:14 +0000165 self.src_list = src_list
Thangavelu K Sb006b8a2017-07-28 19:29:39 +0000166 self.streams_list = []
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800167 for c in range(self.num):
168 self.channel_states[c] = [self.Idle]
Thangavelu K S8e413082017-07-13 20:02:14 +0000169 IgmpChannel.__init__(self, ssm_list = self.channels, iface=iface, src_list = src_list)
A R Karthick338268f2016-06-21 17:12:13 -0700170
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700171 def generate(self, num, channel_start = 0):
Chetan Gaonker38737f82016-05-11 17:44:17 -0700172 start = (225 << 24) | ( ( (channel_start >> 16) & 0xff) << 16 ) | \
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700173 ( ( (channel_start >> 8) & 0xff ) << 8 ) | (channel_start) & 0xff
174 start += channel_start/256 + 1
175 end = start + num
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800176 group_addrs = []
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700177 count = 0
178 while count != num:
179 for i in range(start, end):
180 if i&255:
181 g = '%s.%s.%s.%s' %((i>>24) &0xff, (i>>16)&0xff, (i>>8)&0xff, i&0xff)
A R Karthick76a497a2017-04-12 10:59:39 -0700182 log_test.debug('Adding group %s' %g)
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700183 group_addrs.append(g)
184 count += 1
185 start = end
186 end = start + 1
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800187 return group_addrs
188
189 def start(self):
190 if self.state == self.Stopped:
191 if self.streams:
192 self.streams.stop()
Thangavelu K Sb006b8a2017-07-28 19:29:39 +0000193 if self.streams_list:
194 for i in range(len(self.streams_list)):
195 self.streams_list[i].stop()
196 if self.src_list:
197 for i in range(len(self.src_list)):
198 self.streams_list.append(McastTraffic(self.channels, iface=self.iface_mcast, cb = self.mcast_cb, src_ip = self.src_list[i]))
199 self.streams_list[i].start()
200# self.streams = McastTraffic(self.channels, iface=self.iface_mcast, cb = self.mcast_cb)
201# self.streams.start()
202
203 else:
204 self.streams = McastTraffic(self.channels, iface=self.iface_mcast, cb = self.mcast_cb)
205 self.streams.start()
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800206 self.state = self.Started
207
Thangavelu K S8e413082017-07-13 20:02:14 +0000208 def join(self, chan = None, src_list = None, record_type = None):
209 #def join(self, chan = None):
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800210 if chan is None:
211 chan = random.randint(0, self.num)
212 else:
213 if chan >= self.num:
214 chan = 0
215
216 if self.get_state(chan) == self.Joined:
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800217 return chan, 0
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800218 groups = [self.channels[chan]]
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800219 join_start = monotonic.monotonic()
Thangavelu K S8e413082017-07-13 20:02:14 +0000220 self.igmp_join(groups, src_list = src_list, record_type = record_type)
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800221 self.set_state(chan, self.Joined)
222 self.last_chan = chan
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800223 return chan, join_start
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800224
Thangavelu K S8e413082017-07-13 20:02:14 +0000225 def leave(self, chan, force = False, src_list = None):
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800226 if chan is None:
227 chan = self.last_chan
228 if chan is None or chan >= self.num:
229 return False
A R Karthick78d1f492017-05-19 14:24:17 -0700230 if force is False and self.get_state(chan) != self.Joined:
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800231 return False
232 groups = [self.channels[chan]]
Thangavelu K S8e413082017-07-13 20:02:14 +0000233 self.igmp_leave(groups, src_list = src_list)
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800234 self.set_state(chan, self.Idle)
235 if chan == self.last_chan:
236 self.last_chan = None
237 return True
A R Karthick338268f2016-06-21 17:12:13 -0700238
Thangavelu K Sb006b8a2017-07-28 19:29:39 +0000239 def join_next(self, chan = None, src_list = None, leave_flag = True):
240 if chan is None and self.last_chan is not None:
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800241 chan = self.last_chan
242 if chan is None:
243 return None
244 leave = chan
Thangavelu K S8e413082017-07-13 20:02:14 +0000245 join = chan+1
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800246 else:
247 leave = chan - 1
248 join = chan
A R Karthick338268f2016-06-21 17:12:13 -0700249
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800250 if join >= self.num:
251 join = 0
252
253 if leave >= 0 and leave != join:
A.R Karthick9d914552017-05-18 11:22:57 -0700254 if leave_flag is True:
Thangavelu K Sb006b8a2017-07-28 19:29:39 +0000255 self.leave(leave, src_list = src_list)
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800256
Thangavelu K Sb006b8a2017-07-28 19:29:39 +0000257 return self.join(join, src_list = src_list)
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800258
259 def jump(self):
260 chan = self.last_chan
261 if chan is not None:
262 self.leave(chan)
263 s_next = chan
264 else:
265 s_next = 0
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800266 if self.num - s_next < 2:
267 s_next = 0
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800268 chan = random.randint(s_next, self.num)
269 return self.join(chan)
270
271 def gaddr(self, chan):
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800272 '''Return the group address for a channel'''
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800273 if chan >= self.num:
274 return None
275 return self.channels[chan]
276
Chetan Gaonkercbe79642016-03-09 17:45:58 -0800277 def caddr(self, group):
278 '''Return a channel given a group addr'''
279 if self.group_channel_map.has_key(group):
280 return self.group_channel_map[group]
281 return None
282
Thangavelu K S8e413082017-07-13 20:02:14 +0000283 def recv_cb(self, pkt, src_list = None):
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800284 '''Default channel receive callback'''
A R Karthick76a497a2017-04-12 10:59:39 -0700285 log_test.debug('Received packet from source %s, destination %s' %(pkt[IP].src, pkt[IP].dst))
Thangavelu K S8e413082017-07-13 20:02:14 +0000286 if src_list is None:
287 send_time = float(pkt[IP].payload.load)
288 recv_time = monotonic.monotonic()
289 log_test.debug('Packet received in %.3f usecs' %(recv_time - send_time))
290 elif(pkt[IP].src == src_list[0]):
291 log_test.debug('Received packet from specified source %s, destination %s' %(pkt[IP].src, pkt[IP].dst))
292 elif(pkt[IP].src != src_list[0]):
293 log_test.debug('Received packet not from specified source %s, destination %s' %(pkt[IP].src, pkt[IP].dst))
294 time.sleep(60)
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800295
Thangavelu K S8e413082017-07-13 20:02:14 +0000296 def recv(self, chan, cb = None, count = 1, timeout = 5, src_list = None):
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800297 if chan is None:
298 return None
299 if type(chan) == type([]) or type(chan) == type(()):
300 channel_list=filter(lambda c: c < self.num, chan)
301 groups = map(lambda c: self.gaddr(c), channel_list)
302 else:
303 groups = (self.gaddr(chan),)
304 if cb is None:
Thangavelu K S8e413082017-07-13 20:02:14 +0000305 cb = self.recv_cb(src_list = src_list)
A R Karthick338268f2016-06-21 17:12:13 -0700306 return sniff(prn = cb, count=count, timeout = timeout,
A.R Karthick3f260212017-05-17 14:37:46 -0700307 lfilter = lambda p: IP in p and p[IP].dst in groups, iface = bytes(self.iface[:15]))
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800308
Thangavelu K S9a637332017-08-01 23:22:23 +0000309 def not_recv(self, chan, cb = None, count = 1, timeout = 5, src_list = None):
310 if chan is None:
311 return None
312 if type(chan) == type([]) or type(chan) == type(()):
313 channel_list=filter(lambda c: c < self.num, chan)
314 groups = map(lambda c: self.gaddr(c), channel_list)
315 else:
316 groups = (self.gaddr(chan),)
317
318 if cb is None:
319 cb = self.recv_cb(src_list = src_list)
320 return sniff(prn = cb, count=count, timeout = timeout,
321 lfilter = lambda p: IP in p and p[IP].dst in groups and p[IP].src in src_list, iface = bytes(self.iface[:15]))
322
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800323 def stop(self):
324 if self.streams:
325 self.streams.stop()
Thangavelu K Sb006b8a2017-07-28 19:29:39 +0000326 if self.streams_list:
327 for i in range(len(self.streams_list)):
328 self.streams_list[i].stop()
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800329 self.state = self.Stopped
330
331 def get_state(self, chan):
Thangavelu K S9a637332017-08-01 23:22:23 +0000332 abc = self.channel_states[chan][0]
333 return abc
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800334
335 def set_state(self, chan, state):
336 self.channel_states[chan][0] = state
337
338if __name__ == '__main__':
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700339 num = 5
340 start = 0
341 ssm_list = []
A R Karthick2f4e0ba2017-07-17 10:55:36 -0700342 src_list = [ '1.2.3.4' ]
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700343 for i in xrange(2):
Thangavelu K S8e413082017-07-13 20:02:14 +0000344 channels = Channels(num, start, src_list = src_list)
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -0700345 ssm_list += channels.channels
346 start += num
Thangavelu K S8e413082017-07-13 20:02:14 +0000347 igmpChannel = IgmpChannel(src_list = src_list)
348 igmpChannel.igmp_load_ssm_config(ssm_list, src_list)
Chetan Gaonkerb424ff82016-03-08 12:11:12 -0800349 channels.start()
350 for i in range(num):
351 channels.join(i)
352 for i in range(num):
353 channels.recv(i)
354 for i in range(num):
355 channels.leave(i)
356 channels.stop()