blob: 49fc812c21bcd1ba044bddae55eb72101d8ebcf6 [file] [log] [blame]
Zsolt Harasztia133a452016-12-22 01:26:57 -08001#!/usr/bin/env python
2#
3# Copyright 2016 the original author or authors.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
Zsolt Haraszti80175202016-12-24 00:17:51 -080017
Zsolt Harasztia133a452016-12-22 01:26:57 -080018import readline
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080019from optparse import make_option
Zsolt Haraszti80175202016-12-24 00:17:51 -080020from time import sleep, time
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080021
Zsolt Harasztia133a452016-12-22 01:26:57 -080022import grpc
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080023import requests
24from cmd2 import Cmd, options
25from google.protobuf.empty_pb2 import Empty
Zsolt Harasztia133a452016-12-22 01:26:57 -080026from simplejson import dumps
27
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080028from cli.device import DeviceCli
29from cli.logical_device import LogicalDeviceCli
Zsolt Haraszti85f12852016-12-24 08:30:58 -080030from cli.table import TablePrinter, print_pb_list_as_table
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080031from voltha.core.flow_decomposer import *
Zsolt Harasztia133a452016-12-22 01:26:57 -080032from voltha.protos import third_party
33from voltha.protos import voltha_pb2
Zsolt Haraszti85f12852016-12-24 08:30:58 -080034from voltha.protos.openflow_13_pb2 import FlowTableUpdate, FlowGroupTableUpdate
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080035
Zsolt Harasztia133a452016-12-22 01:26:57 -080036_ = third_party
Zsolt Haraszti80175202016-12-24 00:17:51 -080037from cli.utils import pb2dict, dict2line
Zsolt Harasztia133a452016-12-22 01:26:57 -080038
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080039banner = """\
Zsolt Haraszti80175202016-12-24 00:17:51 -080040 _ _ _ _ _
41__ _____| | |_| |_ __ _ __| (_)
42\ V / _ \ | _| ' \/ _` | / _| | |
43 \_/\___/_|\__|_||_\__,_| \__|_|_|
44(to exit type quit or hit Ctrl-D)
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080045"""
Zsolt Harasztia133a452016-12-22 01:26:57 -080046
47class VolthaCli(Cmd):
48
49 prompt = 'voltha'
50 history_file_name = '.voltha_cli_history'
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080051
52 # Settable CLI parameters
53 voltha_grpc = 'localhost:50055'
54 voltha_sim_rest = 'localhost:18880'
Zsolt Harasztia133a452016-12-22 01:26:57 -080055 max_history_lines = 500
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080056 default_device_id = None
57 default_logical_device_id = None
Zsolt Harasztia133a452016-12-22 01:26:57 -080058
59 Cmd.settable.update(dict(
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080060 voltha_grpc='Voltha GRPC endpoint in form of <host>:<port>',
61 voltha_sim_rest='Voltha simulation back door for testing in form '
62 'of <host>:<port>',
63 max_history_lines='Maximum number of history lines stored across '
64 'sessions',
65 default_device_id='Device id used when no device id is specified',
66 default_logical_device_id='Logical device id used when no device id '
67 'is specified',
Zsolt Harasztia133a452016-12-22 01:26:57 -080068 ))
69
Zsolt Haraszti80175202016-12-24 00:17:51 -080070 # cleanup of superflous commands from cmd2
71 del Cmd.do_cmdenvironment
72 # del Cmd.do_eof
73 del Cmd.do_exit
74 del Cmd.do_q
75 del Cmd.do_hi
76 del Cmd.do_l
77 del Cmd.do_li
78 del Cmd.do_r
79 del Cmd.do__load
80 del Cmd.do__relative_load
81 Cmd.do_edit = Cmd.do_ed
82
83
Zsolt Harasztia133a452016-12-22 01:26:57 -080084 def __init__(self, *args, **kw):
Zsolt Haraszti80175202016-12-24 00:17:51 -080085
Zsolt Harasztia133a452016-12-22 01:26:57 -080086 Cmd.__init__(self, *args, **kw)
87 self.prompt = '(' + self.colorize(
Zsolt Haraszti80175202016-12-24 00:17:51 -080088 self.colorize(self.prompt, 'blue'), 'bold') + ') '
Zsolt Harasztia133a452016-12-22 01:26:57 -080089 self.channel = None
Zsolt Haraszti80175202016-12-24 00:17:51 -080090 self.device_ids_cache = None
91 self.device_ids_cache_ts = time()
92 self.logical_device_ids_cache = None
93 self.logical_device_ids_cache_ts = time()
Zsolt Harasztia133a452016-12-22 01:26:57 -080094
95 def load_history(self):
96 """Load saved command history from local history file"""
97 try:
98 with file(self.history_file_name, 'r') as f:
99 for line in f.readlines():
100 stripped_line = line.strip()
101 self.history.append(stripped_line)
102 readline.add_history(stripped_line)
103 except IOError:
104 pass # ignore if file cannot be read
105
106 def save_history(self):
107 try:
Zsolt Haraszti80175202016-12-24 00:17:51 -0800108 with open(self.history_file_name, 'w') as f:
Zsolt Harasztia133a452016-12-22 01:26:57 -0800109 f.write('\n'.join(self.history[-self.max_history_lines:]))
Zsolt Haraszti80175202016-12-24 00:17:51 -0800110 except IOError as e:
111 self.perror('Could not save history in {}: {}'.format(
112 self.history_file_name, e))
Zsolt Harasztia133a452016-12-22 01:26:57 -0800113 else:
Zsolt Haraszti80175202016-12-24 00:17:51 -0800114 self.perror('History saved as {}'.format(
115 self.history_file_name))
116
117 def perror(self, errmsg, statement=None):
118 # Touch it up to make sure error is prefixed and colored
119 Cmd.perror(self, self.colorize('***ERROR: ', 'red') + errmsg,
120 statement)
Zsolt Harasztia133a452016-12-22 01:26:57 -0800121
122 def get_channel(self):
123 if self.channel is None:
124 self.channel = grpc.insecure_channel(self.voltha_grpc)
125 return self.channel
126
Zsolt Haraszti80175202016-12-24 00:17:51 -0800127 # ~~~~~~~~~~~~~~~~~ ACTUAL COMMAND IMPLEMENTATIONS ~~~~~~~~~~~~~~~~~~~~~~~~
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800128
Zsolt Haraszti80175202016-12-24 00:17:51 -0800129 def do_reset_history(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800130 """Reset CLI history"""
131 while self.history:
132 self.history.pop()
133
Zsolt Haraszti80175202016-12-24 00:17:51 -0800134 def do_launch(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800135 """If Voltha is not running yet, launch it"""
Zsolt Haraszti80175202016-12-24 00:17:51 -0800136 raise NotImplementedError('not implemented yet')
Zsolt Harasztia133a452016-12-22 01:26:57 -0800137
Zsolt Haraszti80175202016-12-24 00:17:51 -0800138 def do_restart(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800139 """Launch Voltha, but if it is already running, terminate it first"""
140 pass
141
Zsolt Haraszti80175202016-12-24 00:17:51 -0800142 def do_adapters(self, line):
143 """List loaded adapter"""
144 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
145 res = stub.ListAdapters(Empty())
146 omit_fields = {}
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800147 print_pb_list_as_table('Adapters:', res.items, omit_fields, self.poutput)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800148
149 def get_devices(self):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800150 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
151 res = stub.ListDevices(Empty())
Zsolt Haraszti80175202016-12-24 00:17:51 -0800152 return res.items
Zsolt Harasztia133a452016-12-22 01:26:57 -0800153
Zsolt Haraszti80175202016-12-24 00:17:51 -0800154 def get_logical_devices(self):
155 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
156 res = stub.ListLogicalDevices(Empty())
157 return res.items
158
159 def do_devices(self, line):
160 """List devices registered in Voltha"""
161 devices = self.get_devices()
162 omit_fields = {
163 'adapter',
164 'vendor',
165 'model',
166 'hardware_version',
167 'software_version',
168 'firmware_version',
169 'serial_number'
170 }
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800171 print_pb_list_as_table('Devices:', devices, omit_fields, self.poutput)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800172
173 def do_logical_devices(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800174 """List logical devices in Voltha"""
175 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
176 res = stub.ListLogicalDevices(Empty())
Zsolt Haraszti80175202016-12-24 00:17:51 -0800177 omit_fields = {
178 'desc.mfr_desc',
179 'desc.hw_desc',
180 'desc.sw_desc',
181 'desc.dp_desc',
182 'desc.serial_number',
183 'switch_features.capabilities'
184 }
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800185 print_pb_list_as_table('Logical devices:', res.items, omit_fields,
186 self.poutput)
Zsolt Harasztia133a452016-12-22 01:26:57 -0800187
Zsolt Haraszti80175202016-12-24 00:17:51 -0800188 def do_device(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800189 """Enter device level command mode"""
Zsolt Haraszti80175202016-12-24 00:17:51 -0800190 device_id = line.strip() or self.default_device_id
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800191 if not device_id:
192 raise Exception('<device-id> parameter needed')
193 sub = DeviceCli(self.get_channel, device_id)
Zsolt Harasztia133a452016-12-22 01:26:57 -0800194 sub.cmdloop()
195
Zsolt Haraszti80175202016-12-24 00:17:51 -0800196 def do_logical_device(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800197 """Enter logical device level command mode"""
Zsolt Haraszti80175202016-12-24 00:17:51 -0800198 logical_device_id = line.strip() or self.default_logical_device_id
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800199 if not logical_device_id:
200 raise Exception('<logical-device-id> parameter needed')
201 sub = LogicalDeviceCli(self.get_channel, logical_device_id)
Zsolt Harasztia133a452016-12-22 01:26:57 -0800202 sub.cmdloop()
203
Zsolt Haraszti80175202016-12-24 00:17:51 -0800204 def device_ids(self, force_refresh=False):
205 if force_refresh or self.device_ids is None or \
206 (time() - self.device_ids_cache_ts) > 1:
207 self.device_ids_cache = [d.id for d in self.get_devices()]
208 self.device_ids_cache_ts = time()
209 return self.device_ids_cache
210
211 def logical_device_ids(self, force_refresh=False):
212 if force_refresh or self.logical_device_ids is None or \
213 (time() - self.logical_device_ids_cache_ts) > 1:
214 self.logical_device_ids_cache = [d.id for d
215 in self.get_logical_devices()]
216 self.logical_device_ids_cache_ts = time()
217 return self.logical_device_ids_cache
218
219 def complete_device(self, text, line, begidx, endidx):
220 if not text:
221 completions = self.device_ids()[:]
222 else:
223 completions = [d for d in self.device_ids() if d.startswith(text)]
224 return completions
225
226 def complete_logical_device(self, text, line, begidx, endidx):
227 if not text:
228 completions = self.logical_device_ids()[:]
229 else:
230 completions = [d for d in self.logical_device_ids()
231 if d.startswith(text)]
232 return completions
233
234 def do_pdb(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800235 """Launch PDB debug prompt in CLI (for CLI development)"""
236 from pdb import set_trace
237 set_trace()
238
Zsolt Haraszti80175202016-12-24 00:17:51 -0800239 def do_health(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800240 """Show connectivity status to Voltha status"""
241 stub = voltha_pb2.HealthServiceStub(self.get_channel())
242 res = stub.GetHealthStatus(Empty())
Zsolt Haraszti80175202016-12-24 00:17:51 -0800243 self.poutput(dumps(pb2dict(res), indent=4))
Zsolt Harasztia133a452016-12-22 01:26:57 -0800244
Zsolt Haraszti80175202016-12-24 00:17:51 -0800245 def do_test(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800246 """Enter test mode, which makes a bunch on new commands available"""
247 sub = TestCli(self.history, self.get_channel)
248 sub.cmdloop()
Zsolt Harasztia133a452016-12-22 01:26:57 -0800249
Zsolt Harasztia133a452016-12-22 01:26:57 -0800250
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800251class TestCli(VolthaCli):
252
253 def __init__(self, history, get_channel):
254 VolthaCli.__init__(self)
255 self.history = history
Zsolt Harasztia133a452016-12-22 01:26:57 -0800256 self.get_channel = get_channel
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800257 self.prompt = '(' + self.colorize(self.colorize('test', 'cyan'),
Zsolt Harasztia133a452016-12-22 01:26:57 -0800258 'bold') + ') '
259
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800260 def get_device(self, device_id, depth=0):
261 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
262 res = stub.GetDevice(voltha_pb2.ID(id=device_id),
263 metadata=(('get-depth', str(depth)), ))
264 return res
265
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800266 @options([
267 make_option('-t', '--device-type', action="store", dest='device_type',
268 help="Device type", default='simulated_olt'),
269 make_option('-m', '--mac-address', action='store', dest='mac_address',
270 default='00:0c:e2:31:40:00'),
271 make_option('-i', '--ip-address', action='store', dest='ip_address'),
272 ])
Zsolt Haraszti80175202016-12-24 00:17:51 -0800273 def do_preprovision_olt(self, line, opts):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800274 """Preprovision a new OLT with given device type"""
Zsolt Harasztia133a452016-12-22 01:26:57 -0800275 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800276 kw = dict(type=opts.device_type)
277 if opts.ip_address:
278 kw['ipv4_address'] = opts.ip_address
279 elif opts.mac_address:
280 kw['mac_address'] = opts.mac_address
281 else:
282 raise Exception('Either IP address or Mac Address is needed')
283 device = voltha_pb2.Device(**kw)
284 device = stub.CreateDevice(device)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800285 self.poutput('success (device id = {})'.format(device.id))
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800286 self.default_device_id = device.id
Zsolt Harasztia133a452016-12-22 01:26:57 -0800287
Zsolt Haraszti80175202016-12-24 00:17:51 -0800288 def do_activate_olt(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800289 """
290 Activate an OLT. If the <id> is not provided, it will be on the last
291 pre-provisioned OLT.
292 """
Zsolt Haraszti80175202016-12-24 00:17:51 -0800293 device_id = line or self.default_device_id
294 self.poutput('activating {}'.format(device_id))
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800295 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
296 stub.ActivateDevice(voltha_pb2.ID(id=device_id))
Zsolt Harasztia133a452016-12-22 01:26:57 -0800297
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800298 # try to acquire logical device id
299 while True:
300 device = stub.GetDevice(voltha_pb2.ID(id=device_id))
301 if device.oper_status == voltha_pb2.OperStatus.ACTIVE:
302 assert device.parent_id
303 self.default_logical_device_id = device.parent_id
304 break
Zsolt Haraszti80175202016-12-24 00:17:51 -0800305 self.poutput('waiting for device to be activated...')
306 sleep(.5)
307 self.poutput('success (logical device id = {})'.format(
308 self.default_logical_device_id))
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800309
Zsolt Haraszti80175202016-12-24 00:17:51 -0800310 complete_activate_olt = VolthaCli.complete_device
311
312 def do_arrive_onus(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800313 """
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800314 Simulate the arrival of ONUs (available only on simulated_olt)
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800315 """
Zsolt Haraszti80175202016-12-24 00:17:51 -0800316 device_id = line or self.default_device_id
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800317
318 # verify that device is of type simulated_olt
319 device = self.get_device(device_id)
320 assert device.type == 'simulated_olt', (
321 'Cannot use it on this device type (only on simulated_olt type)')
322
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800323 requests.get('http://{}/devices/{}/detect_onus'.format(
324 self.voltha_sim_rest, device_id
325 ))
326
Zsolt Haraszti80175202016-12-24 00:17:51 -0800327 complete_arrive_onus = VolthaCli.complete_device
328
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800329 def get_logical_ports(self, logical_device_id):
330 """
331 Return the NNI port number and the first usable UNI port of logical
332 device, and the vlan associated with the latter.
333 """
334 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
335 ports = stub.ListLogicalDevicePorts(
336 voltha_pb2.ID(id=logical_device_id)).items
337 nni = uni = vlan = None
338 for port in ports:
339 if nni is None and port.root_port:
340 nni = port.ofp_port.port_no
341 if uni is None and not port.root_port:
342 uni = port.ofp_port.port_no
343 uni_device = self.get_device(port.device_id)
344 vlan = uni_device.vlan
345 if nni is not None and uni is not None:
346 return nni, uni, vlan
347 raise Exception('No valid port pair found (no ONUs yet?)')
348
Zsolt Haraszti80175202016-12-24 00:17:51 -0800349 def do_install_eapol_flow(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800350 """
351 Install an EAPOL flow on the given logical device. If device is not
352 given, it will be applied to logical device of the last pre-provisioned
353 OLT device.
354 """
Zsolt Haraszti80175202016-12-24 00:17:51 -0800355 logical_device_id = line or self.default_logical_device_id
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800356
357 # gather NNI and UNI port IDs
358 nni_port_no, uni_port_no = self.get_logical_ports(logical_device_id)
359
360 # construct and push flow rule
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800361 update = FlowTableUpdate(
362 id=logical_device_id,
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800363 flow_mod=mk_simple_flow_mod(
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800364 priority=2000,
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800365 match_fields=[in_port(uni_port_no), eth_type(0x888e)],
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800366 actions=[
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800367 # push_vlan(0x8100),
368 # set_field(vlan_vid(4096 + 4000)),
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800369 output(ofp.OFPP_CONTROLLER)
370 ]
371 )
Zsolt Harasztia133a452016-12-22 01:26:57 -0800372 )
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800373 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
374 res = stub.UpdateLogicalDeviceFlowTable(update)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800375 self.poutput('success ({})'.format(res))
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800376
Zsolt Haraszti80175202016-12-24 00:17:51 -0800377 complete_install_eapol_flow = VolthaCli.complete_logical_device
378
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800379 def do_install_all_controller_bound_flows(self, line):
380 """
381 Install all flow rules for controller bound flows, including EAPOL,
382 IGMP and DHCP. If device is not given, it will be applied to logical
383 device of the last pre-provisioned OLT device.
384 """
385 logical_device_id = line or self.default_logical_device_id
386
387 # gather NNI and UNI port IDs
388 nni_port_no, uni_port_no = self.get_logical_ports(logical_device_id)
389
390 # construct and push flow rules
391 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
392
393 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
394 id=logical_device_id,
395 flow_mod=mk_simple_flow_mod(
396 priority=2000,
397 match_fields=[in_port(uni_port_no), eth_type(0x888e)],
398 actions=[
399 # push_vlan(0x8100),
400 # set_field(vlan_vid(4096 + 4000)),
401 output(ofp.OFPP_CONTROLLER)
402 ]
403 )
404 ))
405 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
406 id=logical_device_id,
407 flow_mod=mk_simple_flow_mod(
408 priority=1000,
409 match_fields=[eth_type(0x800), ip_proto(2)],
410 actions=[output(ofp.OFPP_CONTROLLER)]
411 )
412 ))
413 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
414 id=logical_device_id,
415 flow_mod=mk_simple_flow_mod(
416 priority=1000,
417 match_fields=[eth_type(0x800), ip_proto(17), udp_dst(67)],
418 actions=[output(ofp.OFPP_CONTROLLER)]
419 )
420 ))
421
422 self.poutput('success')
423
424 complete_install_all_controller_bound_flows = \
425 VolthaCli.complete_logical_device
426
427 def do_install_all_sample_flows(self, line):
428 """
429 Install all flows that are representative of the virtualized access
430 scenario in a PON network.
431 """
432 logical_device_id = line or self.default_logical_device_id
433
434 # gather NNI and UNI port IDs
435 nni_port_no, uni_port_no, c_vid = \
436 self.get_logical_ports(logical_device_id)
437
438 # construct and push flow rules
439 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
440
441 # Controller-bound flows
442 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
443 id=logical_device_id,
444 flow_mod=mk_simple_flow_mod(
445 priority=2000,
446 match_fields=[in_port(uni_port_no), eth_type(0x888e)],
447 actions=[
448 # push_vlan(0x8100),
449 # set_field(vlan_vid(4096 + 4000)),
450 output(ofp.OFPP_CONTROLLER)
451 ]
452 )
453 ))
454 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
455 id=logical_device_id,
456 flow_mod=mk_simple_flow_mod(
457 priority=1000,
458 match_fields=[eth_type(0x800), ip_proto(2)],
459 actions=[output(ofp.OFPP_CONTROLLER)]
460 )
461 ))
462 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
463 id=logical_device_id,
464 flow_mod=mk_simple_flow_mod(
465 priority=1000,
466 match_fields=[eth_type(0x800), ip_proto(17), udp_dst(67)],
467 actions=[output(ofp.OFPP_CONTROLLER)]
468 )
469 ))
470
471 # Unicast flows:
472 # Downstream flow 1
473 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
474 id=logical_device_id,
475 flow_mod=mk_simple_flow_mod(
476 priority=500,
477 match_fields=[
478 in_port(nni_port_no),
479 vlan_vid(4096 + 1000)
480 ],
481 actions=[pop_vlan()],
482 next_table_id=1
483 )
484 ))
485 # Downstream flow 2
486 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
487 id=logical_device_id,
488 flow_mod=mk_simple_flow_mod(
489 priority=500,
490 match_fields=[in_port(nni_port_no), vlan_vid(4096 + c_vid)],
491 actions=[set_field(vlan_vid(4096 + 0)), output(uni_port_no)]
492 )
493 ))
494 # Upstream flow 1 for 0-tagged case
495 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
496 id=logical_device_id,
497 flow_mod=mk_simple_flow_mod(
498 priority=500,
499 match_fields=[in_port(uni_port_no), vlan_vid(4096 + 0)],
500 actions=[set_field(vlan_vid(4096 + c_vid))],
501 next_table_id=1
502 )
503 ))
504 # Upstream flow 1 for untagged case
505 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
506 id=logical_device_id,
507 flow_mod=mk_simple_flow_mod(
508 priority=500,
509 match_fields=[in_port(uni_port_no), vlan_vid(0)],
510 actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + c_vid))],
511 next_table_id=1
512 )
513 ))
514 # Upstream flow 2 for s-tag
515 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
516 id=logical_device_id,
517 flow_mod=mk_simple_flow_mod(
518 priority=500,
519 match_fields=[in_port(uni_port_no), vlan_vid(4096 + c_vid)],
520 actions=[
521 push_vlan(0x8100),
522 set_field(vlan_vid(4096 + 1000)),
523 output(nni_port_no)
524 ]
525 )
526 ))
527
528 # Push a few multicast flows
529 # 1st with one bucket for our uni
530 stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
531 id=logical_device_id,
532 group_mod=mk_multicast_group_mod(
533 group_id=1,
534 buckets=[
535 ofp.ofp_bucket(actions=[pop_vlan(), output(uni_port_no)])
536 ]
537 )
538 ))
539 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
540 id=logical_device_id,
541 flow_mod=mk_simple_flow_mod(
542 priority=1000,
543 match_fields=[
544 in_port(nni_port_no),
545 eth_type(0x800),
546 vlan_vid(4096 + 140),
547 ipv4_dst(0xe4010101)
548 ],
549 actions=[group(1)]
550 )
551 ))
552 # 2st with one bucket for our uni
553 stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
554 id=logical_device_id,
555 group_mod=mk_multicast_group_mod(
556 group_id=2,
557 buckets=[
558 ofp.ofp_bucket(actions=[pop_vlan(), output(uni_port_no)])
559 ]
560 )
561 ))
562 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
563 id=logical_device_id,
564 flow_mod=mk_simple_flow_mod(
565 priority=1000,
566 match_fields=[
567 in_port(nni_port_no),
568 eth_type(0x800),
569 vlan_vid(4096 + 140),
570 ipv4_dst(0xe4020202)
571 ],
572 actions=[group(2)]
573 )
574 ))
575 # 3rd with empty bucket
576 stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
577 id=logical_device_id,
578 group_mod=mk_multicast_group_mod(
579 group_id=3,
580 buckets=[]
581 )
582 ))
583 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
584 id=logical_device_id,
585 flow_mod=mk_simple_flow_mod(
586 priority=1000,
587 match_fields=[
588 in_port(nni_port_no),
589 eth_type(0x800),
590 vlan_vid(4096 + 140),
591 ipv4_dst(0xe4030303)
592 ],
593 actions=[group(3)]
594 )
595 ))
596
597 self.poutput('success')
598
599 complete_install_all_sample_flows = VolthaCli.complete_logical_device
600
601 def do_delete_all_flows(self, line):
602 """
603 Remove all flows and flow groups from given logical device
604 """
605 logical_device_id = line or self.default_logical_device_id
606 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
607 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
608 id=logical_device_id,
609 flow_mod=ofp.ofp_flow_mod(
610 command=ofp.OFPFC_DELETE,
611 table_id=ofp.OFPTT_ALL,
612 cookie_mask=0,
613 out_port=ofp.OFPP_ANY,
614 out_group=ofp.OFPG_ANY
615 )
616 ))
617 stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
618 id=logical_device_id,
619 group_mod=ofp.ofp_group_mod(
620 command=ofp.OFPGC_DELETE,
621 group_id=ofp.OFPG_ALL
622 )
623 ))
624 self.poutput('success')
625
626 complete_delete_all_flows = VolthaCli.complete_logical_device
627
Zsolt Haraszti80175202016-12-24 00:17:51 -0800628 def do_send_simulated_upstream_eapol(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800629 """
630 Send an EAPOL upstream from a simulated OLT
631 """
Zsolt Haraszti80175202016-12-24 00:17:51 -0800632 device_id = line or self.default_device_id
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800633 requests.get('http://{}/devices/{}/test_eapol_in'.format(
634 self.voltha_sim_rest, device_id
635 ))
636
Zsolt Haraszti80175202016-12-24 00:17:51 -0800637 complete_send_simulated_upstream_eapol = VolthaCli.complete_device
638
639 def do_inject_eapol_start(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800640 """
641 Send out an an EAPOL start message into the given Unix interface
642 """
643 pass
Zsolt Harasztia133a452016-12-22 01:26:57 -0800644
645
646if __name__ == '__main__':
647 c = VolthaCli()
Zsolt Haraszti80175202016-12-24 00:17:51 -0800648 c.poutput(banner)
Zsolt Harasztia133a452016-12-22 01:26:57 -0800649 c.load_history()
650 c.cmdloop()
651 c.save_history()