blob: fa778a165c91487e7699d913d5e2803e750e1307 [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 Haraszti9b485fb2016-12-26 23:11:15 -080017import argparse
18import os
Zsolt Harasztia133a452016-12-22 01:26:57 -080019import readline
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080020from optparse import make_option
Zsolt Haraszti80175202016-12-24 00:17:51 -080021from time import sleep, time
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080022
Zsolt Haraszti9b485fb2016-12-26 23:11:15 -080023import sys
24from consul import Consul
Zsolt Harasztia133a452016-12-22 01:26:57 -080025import grpc
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080026import requests
27from cmd2 import Cmd, options
28from google.protobuf.empty_pb2 import Empty
Zsolt Harasztia133a452016-12-22 01:26:57 -080029from simplejson import dumps
30
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080031from cli.device import DeviceCli
32from cli.logical_device import LogicalDeviceCli
Zsolt Haraszti85f12852016-12-24 08:30:58 -080033from cli.table import TablePrinter, print_pb_list_as_table
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080034from voltha.core.flow_decomposer import *
Zsolt Harasztia133a452016-12-22 01:26:57 -080035from voltha.protos import third_party
36from voltha.protos import voltha_pb2
Zsolt Haraszti85f12852016-12-24 08:30:58 -080037from voltha.protos.openflow_13_pb2 import FlowTableUpdate, FlowGroupTableUpdate
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080038
Zsolt Harasztia133a452016-12-22 01:26:57 -080039_ = third_party
Zsolt Haraszti80175202016-12-24 00:17:51 -080040from cli.utils import pb2dict, dict2line
Zsolt Harasztia133a452016-12-22 01:26:57 -080041
Zsolt Haraszti9b485fb2016-12-26 23:11:15 -080042
43defs = dict(
44 # config=os.environ.get('CONFIG', './cli.yml'),
45 consul=os.environ.get('CONSUL', 'localhost:8500'),
46 voltha_grpc_endpoint=os.environ.get('VOLTHA_GRPC_ENDPOINT',
47 'localhost:50055'),
48 voltha_sim_rest_endpoint=os.environ.get('VOLTHA_SIM_REST_ENDPOINT',
49 'localhost:18880'),
50)
51
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080052banner = """\
Zsolt Haraszti313c4be2016-12-27 11:06:53 -080053 _ _ _ ___ _ ___
54__ _____| | |_| |_ __ _ / __| | |_ _|
55\ V / _ \ | _| ' \/ _` | | (__| |__ | |
56 \_/\___/_|\__|_||_\__,_| \___|____|___|
Zsolt Haraszti80175202016-12-24 00:17:51 -080057(to exit type quit or hit Ctrl-D)
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080058"""
Zsolt Harasztia133a452016-12-22 01:26:57 -080059
60class VolthaCli(Cmd):
61
62 prompt = 'voltha'
63 history_file_name = '.voltha_cli_history'
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080064
65 # Settable CLI parameters
66 voltha_grpc = 'localhost:50055'
67 voltha_sim_rest = 'localhost:18880'
Zsolt Harasztia133a452016-12-22 01:26:57 -080068 max_history_lines = 500
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080069 default_device_id = None
70 default_logical_device_id = None
Zsolt Harasztia133a452016-12-22 01:26:57 -080071
72 Cmd.settable.update(dict(
Zsolt Harasztid036b7e2016-12-23 15:36:01 -080073 voltha_grpc='Voltha GRPC endpoint in form of <host>:<port>',
74 voltha_sim_rest='Voltha simulation back door for testing in form '
75 'of <host>:<port>',
76 max_history_lines='Maximum number of history lines stored across '
77 'sessions',
78 default_device_id='Device id used when no device id is specified',
79 default_logical_device_id='Logical device id used when no device id '
80 'is specified',
Zsolt Harasztia133a452016-12-22 01:26:57 -080081 ))
82
Zsolt Haraszti9b485fb2016-12-26 23:11:15 -080083 # cleanup of superfluous commands from cmd2
Zsolt Haraszti80175202016-12-24 00:17:51 -080084 del Cmd.do_cmdenvironment
85 # del Cmd.do_eof
Zsolt Haraszti80175202016-12-24 00:17:51 -080086 del Cmd.do_q
87 del Cmd.do_hi
88 del Cmd.do_l
89 del Cmd.do_li
90 del Cmd.do_r
91 del Cmd.do__load
92 del Cmd.do__relative_load
93 Cmd.do_edit = Cmd.do_ed
94
Zsolt Haraszti9b485fb2016-12-26 23:11:15 -080095 def __init__(self, voltha_grpc, voltha_sim_rest):
96 VolthaCli.voltha_grpc = voltha_grpc
97 VolthaCli.voltha_sim_rest = voltha_sim_rest
98 Cmd.__init__(self)
Zsolt Harasztia133a452016-12-22 01:26:57 -080099 self.prompt = '(' + self.colorize(
Zsolt Haraszti80175202016-12-24 00:17:51 -0800100 self.colorize(self.prompt, 'blue'), 'bold') + ') '
Zsolt Harasztia133a452016-12-22 01:26:57 -0800101 self.channel = None
Zsolt Haraszti80175202016-12-24 00:17:51 -0800102 self.device_ids_cache = None
103 self.device_ids_cache_ts = time()
104 self.logical_device_ids_cache = None
105 self.logical_device_ids_cache_ts = time()
Zsolt Harasztia133a452016-12-22 01:26:57 -0800106
Zsolt Haraszti9b485fb2016-12-26 23:11:15 -0800107 # we override cmd2's method to avoid its optparse conflicting with our
108 # command line parsing
109 def cmdloop(self):
110 self._cmdloop()
111
Zsolt Harasztia133a452016-12-22 01:26:57 -0800112 def load_history(self):
113 """Load saved command history from local history file"""
114 try:
115 with file(self.history_file_name, 'r') as f:
116 for line in f.readlines():
117 stripped_line = line.strip()
118 self.history.append(stripped_line)
119 readline.add_history(stripped_line)
120 except IOError:
121 pass # ignore if file cannot be read
122
123 def save_history(self):
124 try:
Zsolt Haraszti80175202016-12-24 00:17:51 -0800125 with open(self.history_file_name, 'w') as f:
Zsolt Harasztia133a452016-12-22 01:26:57 -0800126 f.write('\n'.join(self.history[-self.max_history_lines:]))
Zsolt Haraszti80175202016-12-24 00:17:51 -0800127 except IOError as e:
128 self.perror('Could not save history in {}: {}'.format(
129 self.history_file_name, e))
Zsolt Harasztia133a452016-12-22 01:26:57 -0800130 else:
Zsolt Haraszti9b485fb2016-12-26 23:11:15 -0800131 self.poutput('History saved as {}'.format(
Zsolt Haraszti80175202016-12-24 00:17:51 -0800132 self.history_file_name))
133
134 def perror(self, errmsg, statement=None):
135 # Touch it up to make sure error is prefixed and colored
136 Cmd.perror(self, self.colorize('***ERROR: ', 'red') + errmsg,
137 statement)
Zsolt Harasztia133a452016-12-22 01:26:57 -0800138
139 def get_channel(self):
140 if self.channel is None:
141 self.channel = grpc.insecure_channel(self.voltha_grpc)
142 return self.channel
143
Zsolt Haraszti80175202016-12-24 00:17:51 -0800144 # ~~~~~~~~~~~~~~~~~ ACTUAL COMMAND IMPLEMENTATIONS ~~~~~~~~~~~~~~~~~~~~~~~~
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800145
Zsolt Haraszti80175202016-12-24 00:17:51 -0800146 def do_reset_history(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800147 """Reset CLI history"""
148 while self.history:
149 self.history.pop()
150
Zsolt Haraszti80175202016-12-24 00:17:51 -0800151 def do_launch(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800152 """If Voltha is not running yet, launch it"""
Zsolt Haraszti80175202016-12-24 00:17:51 -0800153 raise NotImplementedError('not implemented yet')
Zsolt Harasztia133a452016-12-22 01:26:57 -0800154
Zsolt Haraszti80175202016-12-24 00:17:51 -0800155 def do_restart(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800156 """Launch Voltha, but if it is already running, terminate it first"""
157 pass
158
Zsolt Haraszti80175202016-12-24 00:17:51 -0800159 def do_adapters(self, line):
160 """List loaded adapter"""
161 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
162 res = stub.ListAdapters(Empty())
163 omit_fields = {}
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800164 print_pb_list_as_table('Adapters:', res.items, omit_fields, self.poutput)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800165
166 def get_devices(self):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800167 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
168 res = stub.ListDevices(Empty())
Zsolt Haraszti80175202016-12-24 00:17:51 -0800169 return res.items
Zsolt Harasztia133a452016-12-22 01:26:57 -0800170
Zsolt Haraszti80175202016-12-24 00:17:51 -0800171 def get_logical_devices(self):
172 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
173 res = stub.ListLogicalDevices(Empty())
174 return res.items
175
176 def do_devices(self, line):
177 """List devices registered in Voltha"""
178 devices = self.get_devices()
179 omit_fields = {
180 'adapter',
181 'vendor',
182 'model',
183 'hardware_version',
184 'software_version',
185 'firmware_version',
186 'serial_number'
187 }
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800188 print_pb_list_as_table('Devices:', devices, omit_fields, self.poutput)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800189
190 def do_logical_devices(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800191 """List logical devices in Voltha"""
192 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
193 res = stub.ListLogicalDevices(Empty())
Zsolt Haraszti80175202016-12-24 00:17:51 -0800194 omit_fields = {
195 'desc.mfr_desc',
196 'desc.hw_desc',
197 'desc.sw_desc',
198 'desc.dp_desc',
199 'desc.serial_number',
200 'switch_features.capabilities'
201 }
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800202 print_pb_list_as_table('Logical devices:', res.items, omit_fields,
203 self.poutput)
Zsolt Harasztia133a452016-12-22 01:26:57 -0800204
Zsolt Haraszti80175202016-12-24 00:17:51 -0800205 def do_device(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800206 """Enter device level command mode"""
Zsolt Haraszti80175202016-12-24 00:17:51 -0800207 device_id = line.strip() or self.default_device_id
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800208 if not device_id:
209 raise Exception('<device-id> parameter needed')
210 sub = DeviceCli(self.get_channel, device_id)
Zsolt Harasztia133a452016-12-22 01:26:57 -0800211 sub.cmdloop()
212
Zsolt Haraszti80175202016-12-24 00:17:51 -0800213 def do_logical_device(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800214 """Enter logical device level command mode"""
Zsolt Haraszti80175202016-12-24 00:17:51 -0800215 logical_device_id = line.strip() or self.default_logical_device_id
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800216 if not logical_device_id:
217 raise Exception('<logical-device-id> parameter needed')
218 sub = LogicalDeviceCli(self.get_channel, logical_device_id)
Zsolt Harasztia133a452016-12-22 01:26:57 -0800219 sub.cmdloop()
220
Zsolt Haraszti80175202016-12-24 00:17:51 -0800221 def device_ids(self, force_refresh=False):
222 if force_refresh or self.device_ids is None or \
223 (time() - self.device_ids_cache_ts) > 1:
224 self.device_ids_cache = [d.id for d in self.get_devices()]
225 self.device_ids_cache_ts = time()
226 return self.device_ids_cache
227
228 def logical_device_ids(self, force_refresh=False):
229 if force_refresh or self.logical_device_ids is None or \
230 (time() - self.logical_device_ids_cache_ts) > 1:
231 self.logical_device_ids_cache = [d.id for d
232 in self.get_logical_devices()]
233 self.logical_device_ids_cache_ts = time()
234 return self.logical_device_ids_cache
235
236 def complete_device(self, text, line, begidx, endidx):
237 if not text:
238 completions = self.device_ids()[:]
239 else:
240 completions = [d for d in self.device_ids() if d.startswith(text)]
241 return completions
242
243 def complete_logical_device(self, text, line, begidx, endidx):
244 if not text:
245 completions = self.logical_device_ids()[:]
246 else:
247 completions = [d for d in self.logical_device_ids()
248 if d.startswith(text)]
249 return completions
250
251 def do_pdb(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800252 """Launch PDB debug prompt in CLI (for CLI development)"""
253 from pdb import set_trace
254 set_trace()
255
Zsolt Haraszti80175202016-12-24 00:17:51 -0800256 def do_health(self, line):
Zsolt Harasztia133a452016-12-22 01:26:57 -0800257 """Show connectivity status to Voltha status"""
258 stub = voltha_pb2.HealthServiceStub(self.get_channel())
259 res = stub.GetHealthStatus(Empty())
Zsolt Haraszti80175202016-12-24 00:17:51 -0800260 self.poutput(dumps(pb2dict(res), indent=4))
Zsolt Harasztia133a452016-12-22 01:26:57 -0800261
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800262 @options([
263 make_option('-t', '--device-type', action="store", dest='device_type',
264 help="Device type", default='simulated_olt'),
265 make_option('-m', '--mac-address', action='store', dest='mac_address',
266 default='00:0c:e2:31:40:00'),
267 make_option('-i', '--ip-address', action='store', dest='ip_address'),
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800268 make_option('-H', '--host_and_port', action='store',
269 dest='host_and_port'),
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800270 ])
Zsolt Haraszti80175202016-12-24 00:17:51 -0800271 def do_preprovision_olt(self, line, opts):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800272 """Preprovision a new OLT with given device type"""
Zsolt Harasztia133a452016-12-22 01:26:57 -0800273 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800274 kw = dict(type=opts.device_type)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800275 if opts.host_and_port:
276 kw['host_and_port'] = opts.host_and_port
277 elif opts.ip_address:
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800278 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 Haraszti50cae7d2017-01-08 22:27:07 -0800310 complete_activate_olt = complete_device
311
312 def do_test(self, line):
313 """Enter test mode, which makes a bunch on new commands available"""
314 sub = TestCli(self.history, self.get_channel, self.voltha_grpc,
315 self.voltha_sim_rest)
316 sub.cmdloop()
317
318
319class TestCli(VolthaCli):
320
321 def __init__(self, history, get_channel, voltha_grpc, voltha_sim_rest):
322 VolthaCli.__init__(self, voltha_grpc, voltha_sim_rest)
323 self.history = history
324 self.get_channel = get_channel
325 self.prompt = '(' + self.colorize(self.colorize('test', 'cyan'),
326 'bold') + ') '
327
328 def get_device(self, device_id, depth=0):
329 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
330 res = stub.GetDevice(voltha_pb2.ID(id=device_id),
331 metadata=(('get-depth', str(depth)), ))
332 return res
Zsolt Haraszti80175202016-12-24 00:17:51 -0800333
334 def do_arrive_onus(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800335 """
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800336 Simulate the arrival of ONUs (available only on simulated_olt)
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800337 """
Zsolt Haraszti80175202016-12-24 00:17:51 -0800338 device_id = line or self.default_device_id
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800339
340 # verify that device is of type simulated_olt
341 device = self.get_device(device_id)
342 assert device.type == 'simulated_olt', (
343 'Cannot use it on this device type (only on simulated_olt type)')
344
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800345 requests.get('http://{}/devices/{}/detect_onus'.format(
346 self.voltha_sim_rest, device_id
347 ))
348
Zsolt Haraszti80175202016-12-24 00:17:51 -0800349 complete_arrive_onus = VolthaCli.complete_device
350
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800351 def get_logical_ports(self, logical_device_id):
352 """
353 Return the NNI port number and the first usable UNI port of logical
354 device, and the vlan associated with the latter.
355 """
356 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
357 ports = stub.ListLogicalDevicePorts(
358 voltha_pb2.ID(id=logical_device_id)).items
359 nni = uni = vlan = None
360 for port in ports:
361 if nni is None and port.root_port:
362 nni = port.ofp_port.port_no
363 if uni is None and not port.root_port:
364 uni = port.ofp_port.port_no
365 uni_device = self.get_device(port.device_id)
366 vlan = uni_device.vlan
367 if nni is not None and uni is not None:
368 return nni, uni, vlan
369 raise Exception('No valid port pair found (no ONUs yet?)')
370
Zsolt Haraszti80175202016-12-24 00:17:51 -0800371 def do_install_eapol_flow(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800372 """
373 Install an EAPOL flow on the given logical device. If device is not
374 given, it will be applied to logical device of the last pre-provisioned
375 OLT device.
376 """
Zsolt Haraszti80175202016-12-24 00:17:51 -0800377 logical_device_id = line or self.default_logical_device_id
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800378
379 # gather NNI and UNI port IDs
Zsolt Haraszti01bbe882016-12-27 10:43:18 -0800380 nni_port_no, uni_port_no, _ = self.get_logical_ports(logical_device_id)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800381
382 # construct and push flow rule
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800383 update = FlowTableUpdate(
384 id=logical_device_id,
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800385 flow_mod=mk_simple_flow_mod(
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800386 priority=2000,
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800387 match_fields=[in_port(uni_port_no), eth_type(0x888e)],
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800388 actions=[
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800389 # push_vlan(0x8100),
390 # set_field(vlan_vid(4096 + 4000)),
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800391 output(ofp.OFPP_CONTROLLER)
392 ]
393 )
Zsolt Harasztia133a452016-12-22 01:26:57 -0800394 )
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800395 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
396 res = stub.UpdateLogicalDeviceFlowTable(update)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800397 self.poutput('success ({})'.format(res))
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800398
Zsolt Haraszti80175202016-12-24 00:17:51 -0800399 complete_install_eapol_flow = VolthaCli.complete_logical_device
400
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800401 def do_install_all_controller_bound_flows(self, line):
402 """
403 Install all flow rules for controller bound flows, including EAPOL,
404 IGMP and DHCP. If device is not given, it will be applied to logical
405 device of the last pre-provisioned OLT device.
406 """
407 logical_device_id = line or self.default_logical_device_id
408
409 # gather NNI and UNI port IDs
Zsolt Haraszti01bbe882016-12-27 10:43:18 -0800410 nni_port_no, uni_port_no, _ = self.get_logical_ports(logical_device_id)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800411
412 # construct and push flow rules
413 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
414
415 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
416 id=logical_device_id,
417 flow_mod=mk_simple_flow_mod(
418 priority=2000,
419 match_fields=[in_port(uni_port_no), eth_type(0x888e)],
420 actions=[
421 # push_vlan(0x8100),
422 # set_field(vlan_vid(4096 + 4000)),
423 output(ofp.OFPP_CONTROLLER)
424 ]
425 )
426 ))
427 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
428 id=logical_device_id,
429 flow_mod=mk_simple_flow_mod(
430 priority=1000,
431 match_fields=[eth_type(0x800), ip_proto(2)],
432 actions=[output(ofp.OFPP_CONTROLLER)]
433 )
434 ))
435 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
436 id=logical_device_id,
437 flow_mod=mk_simple_flow_mod(
438 priority=1000,
439 match_fields=[eth_type(0x800), ip_proto(17), udp_dst(67)],
440 actions=[output(ofp.OFPP_CONTROLLER)]
441 )
442 ))
443
444 self.poutput('success')
445
446 complete_install_all_controller_bound_flows = \
447 VolthaCli.complete_logical_device
448
449 def do_install_all_sample_flows(self, line):
450 """
451 Install all flows that are representative of the virtualized access
452 scenario in a PON network.
453 """
454 logical_device_id = line or self.default_logical_device_id
455
456 # gather NNI and UNI port IDs
457 nni_port_no, uni_port_no, c_vid = \
458 self.get_logical_ports(logical_device_id)
459
460 # construct and push flow rules
461 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
462
463 # Controller-bound flows
464 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
465 id=logical_device_id,
466 flow_mod=mk_simple_flow_mod(
467 priority=2000,
468 match_fields=[in_port(uni_port_no), eth_type(0x888e)],
469 actions=[
470 # push_vlan(0x8100),
471 # set_field(vlan_vid(4096 + 4000)),
472 output(ofp.OFPP_CONTROLLER)
473 ]
474 )
475 ))
476 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
477 id=logical_device_id,
478 flow_mod=mk_simple_flow_mod(
479 priority=1000,
480 match_fields=[eth_type(0x800), ip_proto(2)],
481 actions=[output(ofp.OFPP_CONTROLLER)]
482 )
483 ))
484 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
485 id=logical_device_id,
486 flow_mod=mk_simple_flow_mod(
487 priority=1000,
488 match_fields=[eth_type(0x800), ip_proto(17), udp_dst(67)],
489 actions=[output(ofp.OFPP_CONTROLLER)]
490 )
491 ))
492
493 # Unicast flows:
494 # Downstream flow 1
495 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
496 id=logical_device_id,
497 flow_mod=mk_simple_flow_mod(
498 priority=500,
499 match_fields=[
500 in_port(nni_port_no),
501 vlan_vid(4096 + 1000)
502 ],
503 actions=[pop_vlan()],
504 next_table_id=1
505 )
506 ))
507 # Downstream flow 2
508 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
509 id=logical_device_id,
510 flow_mod=mk_simple_flow_mod(
511 priority=500,
512 match_fields=[in_port(nni_port_no), vlan_vid(4096 + c_vid)],
513 actions=[set_field(vlan_vid(4096 + 0)), output(uni_port_no)]
514 )
515 ))
516 # Upstream flow 1 for 0-tagged case
517 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
518 id=logical_device_id,
519 flow_mod=mk_simple_flow_mod(
520 priority=500,
521 match_fields=[in_port(uni_port_no), vlan_vid(4096 + 0)],
522 actions=[set_field(vlan_vid(4096 + c_vid))],
523 next_table_id=1
524 )
525 ))
526 # Upstream flow 1 for untagged case
527 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
528 id=logical_device_id,
529 flow_mod=mk_simple_flow_mod(
530 priority=500,
531 match_fields=[in_port(uni_port_no), vlan_vid(0)],
532 actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + c_vid))],
533 next_table_id=1
534 )
535 ))
536 # Upstream flow 2 for s-tag
537 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
538 id=logical_device_id,
539 flow_mod=mk_simple_flow_mod(
540 priority=500,
541 match_fields=[in_port(uni_port_no), vlan_vid(4096 + c_vid)],
542 actions=[
543 push_vlan(0x8100),
544 set_field(vlan_vid(4096 + 1000)),
545 output(nni_port_no)
546 ]
547 )
548 ))
549
550 # Push a few multicast flows
551 # 1st with one bucket for our uni
552 stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
553 id=logical_device_id,
554 group_mod=mk_multicast_group_mod(
555 group_id=1,
556 buckets=[
557 ofp.ofp_bucket(actions=[pop_vlan(), output(uni_port_no)])
558 ]
559 )
560 ))
561 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
562 id=logical_device_id,
563 flow_mod=mk_simple_flow_mod(
564 priority=1000,
565 match_fields=[
566 in_port(nni_port_no),
567 eth_type(0x800),
568 vlan_vid(4096 + 140),
569 ipv4_dst(0xe4010101)
570 ],
571 actions=[group(1)]
572 )
573 ))
574 # 2st with one bucket for our uni
575 stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
576 id=logical_device_id,
577 group_mod=mk_multicast_group_mod(
578 group_id=2,
579 buckets=[
580 ofp.ofp_bucket(actions=[pop_vlan(), output(uni_port_no)])
581 ]
582 )
583 ))
584 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
585 id=logical_device_id,
586 flow_mod=mk_simple_flow_mod(
587 priority=1000,
588 match_fields=[
589 in_port(nni_port_no),
590 eth_type(0x800),
591 vlan_vid(4096 + 140),
592 ipv4_dst(0xe4020202)
593 ],
594 actions=[group(2)]
595 )
596 ))
597 # 3rd with empty bucket
598 stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
599 id=logical_device_id,
600 group_mod=mk_multicast_group_mod(
601 group_id=3,
602 buckets=[]
603 )
604 ))
605 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
606 id=logical_device_id,
607 flow_mod=mk_simple_flow_mod(
608 priority=1000,
609 match_fields=[
610 in_port(nni_port_no),
611 eth_type(0x800),
612 vlan_vid(4096 + 140),
613 ipv4_dst(0xe4030303)
614 ],
615 actions=[group(3)]
616 )
617 ))
618
619 self.poutput('success')
620
621 complete_install_all_sample_flows = VolthaCli.complete_logical_device
622
623 def do_delete_all_flows(self, line):
624 """
625 Remove all flows and flow groups from given logical device
626 """
627 logical_device_id = line or self.default_logical_device_id
628 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
629 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
630 id=logical_device_id,
631 flow_mod=ofp.ofp_flow_mod(
632 command=ofp.OFPFC_DELETE,
633 table_id=ofp.OFPTT_ALL,
634 cookie_mask=0,
635 out_port=ofp.OFPP_ANY,
636 out_group=ofp.OFPG_ANY
637 )
638 ))
639 stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
640 id=logical_device_id,
641 group_mod=ofp.ofp_group_mod(
642 command=ofp.OFPGC_DELETE,
643 group_id=ofp.OFPG_ALL
644 )
645 ))
646 self.poutput('success')
647
648 complete_delete_all_flows = VolthaCli.complete_logical_device
649
Zsolt Haraszti80175202016-12-24 00:17:51 -0800650 def do_send_simulated_upstream_eapol(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800651 """
652 Send an EAPOL upstream from a simulated OLT
653 """
Zsolt Haraszti80175202016-12-24 00:17:51 -0800654 device_id = line or self.default_device_id
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800655 requests.get('http://{}/devices/{}/test_eapol_in'.format(
656 self.voltha_sim_rest, device_id
657 ))
658
Zsolt Haraszti80175202016-12-24 00:17:51 -0800659 complete_send_simulated_upstream_eapol = VolthaCli.complete_device
660
661 def do_inject_eapol_start(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800662 """
663 Send out an an EAPOL start message into the given Unix interface
664 """
665 pass
Zsolt Harasztia133a452016-12-22 01:26:57 -0800666
667
668if __name__ == '__main__':
Zsolt Haraszti9b485fb2016-12-26 23:11:15 -0800669
670 parser = argparse.ArgumentParser()
671
672 _help = '<hostname>:<port> to consul agent (default: %s)' % defs['consul']
673 parser.add_argument(
674 '-C', '--consul', action='store', default=defs['consul'], help=_help)
675
676 _help = 'Lookup Voltha endpoints based on service entries in Consul'
677 parser.add_argument(
678 '-L', '--lookup', action='store_true', help=_help)
679
680 _help = '<hostname>:<port> of Voltha gRPC service (default={})'.format(
681 defs['voltha_grpc_endpoint'])
682 parser.add_argument('-g', '--grpc-endpoint', action='store',
683 default=defs['voltha_grpc_endpoint'], help=_help)
684
685 _help = '<hostname>:<port> of Voltha simulated adapter backend for ' \
686 'testing (default={})'.format(
687 defs['voltha_sim_rest_endpoint'])
688 parser.add_argument('-s', '--sim-rest-endpoint', action='store',
689 default=defs['voltha_sim_rest_endpoint'], help=_help)
690
691 args = parser.parse_args()
692
693 if args.lookup:
694 host = args.consul.split(':')[0].strip()
695 port = int(args.consul.split(':')[1].strip())
696 consul = Consul(host=host, port=port)
697
698 _, services = consul.catalog.service('voltha-grpc')
699 if not services:
700 print('No voltha-grpc service registered in consul; exiting')
701 sys.exit(1)
702 args.grpc_endpoint = '{}:{}'.format(services[0]['ServiceAddress'],
703 services[0]['ServicePort'])
704
705 _, services = consul.catalog.service('voltha-sim-rest')
706 if not services:
707 print('No voltha-sim-rest service registered in consul; exiting')
708 sys.exit(1)
709 args.sim_rest_endpoint = '{}:{}'.format(services[0]['ServiceAddress'],
710 services[0]['ServicePort'])
711
712 c = VolthaCli(args.grpc_endpoint, args.sim_rest_endpoint)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800713 c.poutput(banner)
Zsolt Harasztia133a452016-12-22 01:26:57 -0800714 c.load_history()
715 c.cmdloop()
716 c.save_history()