blob: d684f85dc6dc92eca24bfddbe538fdd94bf60cc8 [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 Haraszti80175202016-12-24 00:17:51 -080053 _ _ _ _ _
54__ _____| | |_| |_ __ _ __| (_)
55\ V / _ \ | _| ' \/ _` | / _| | |
56 \_/\___/_|\__|_||_\__,_| \__|_|_|
57(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 Haraszti80175202016-12-24 00:17:51 -0800262 def do_test(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800263 """Enter test mode, which makes a bunch on new commands available"""
Zsolt Haraszti9b485fb2016-12-26 23:11:15 -0800264 sub = TestCli(self.history, self.get_channel, self.voltha_grpc,
265 self.voltha_sim_rest)
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800266 sub.cmdloop()
Zsolt Harasztia133a452016-12-22 01:26:57 -0800267
Zsolt Harasztia133a452016-12-22 01:26:57 -0800268
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800269class TestCli(VolthaCli):
270
Zsolt Haraszti9b485fb2016-12-26 23:11:15 -0800271 def __init__(self, history, get_channel, voltha_grpc, voltha_sim_rest):
272 VolthaCli.__init__(self, voltha_grpc, voltha_sim_rest)
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800273 self.history = history
Zsolt Harasztia133a452016-12-22 01:26:57 -0800274 self.get_channel = get_channel
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800275 self.prompt = '(' + self.colorize(self.colorize('test', 'cyan'),
Zsolt Harasztia133a452016-12-22 01:26:57 -0800276 'bold') + ') '
277
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800278 def get_device(self, device_id, depth=0):
279 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
280 res = stub.GetDevice(voltha_pb2.ID(id=device_id),
281 metadata=(('get-depth', str(depth)), ))
282 return res
283
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800284 @options([
285 make_option('-t', '--device-type', action="store", dest='device_type',
286 help="Device type", default='simulated_olt'),
287 make_option('-m', '--mac-address', action='store', dest='mac_address',
288 default='00:0c:e2:31:40:00'),
289 make_option('-i', '--ip-address', action='store', dest='ip_address'),
290 ])
Zsolt Haraszti80175202016-12-24 00:17:51 -0800291 def do_preprovision_olt(self, line, opts):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800292 """Preprovision a new OLT with given device type"""
Zsolt Harasztia133a452016-12-22 01:26:57 -0800293 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800294 kw = dict(type=opts.device_type)
295 if opts.ip_address:
296 kw['ipv4_address'] = opts.ip_address
297 elif opts.mac_address:
298 kw['mac_address'] = opts.mac_address
299 else:
300 raise Exception('Either IP address or Mac Address is needed')
301 device = voltha_pb2.Device(**kw)
302 device = stub.CreateDevice(device)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800303 self.poutput('success (device id = {})'.format(device.id))
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800304 self.default_device_id = device.id
Zsolt Harasztia133a452016-12-22 01:26:57 -0800305
Zsolt Haraszti80175202016-12-24 00:17:51 -0800306 def do_activate_olt(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800307 """
308 Activate an OLT. If the <id> is not provided, it will be on the last
309 pre-provisioned OLT.
310 """
Zsolt Haraszti80175202016-12-24 00:17:51 -0800311 device_id = line or self.default_device_id
312 self.poutput('activating {}'.format(device_id))
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800313 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
314 stub.ActivateDevice(voltha_pb2.ID(id=device_id))
Zsolt Harasztia133a452016-12-22 01:26:57 -0800315
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800316 # try to acquire logical device id
317 while True:
318 device = stub.GetDevice(voltha_pb2.ID(id=device_id))
319 if device.oper_status == voltha_pb2.OperStatus.ACTIVE:
320 assert device.parent_id
321 self.default_logical_device_id = device.parent_id
322 break
Zsolt Haraszti80175202016-12-24 00:17:51 -0800323 self.poutput('waiting for device to be activated...')
324 sleep(.5)
325 self.poutput('success (logical device id = {})'.format(
326 self.default_logical_device_id))
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800327
Zsolt Haraszti80175202016-12-24 00:17:51 -0800328 complete_activate_olt = VolthaCli.complete_device
329
330 def do_arrive_onus(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800331 """
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800332 Simulate the arrival of ONUs (available only on simulated_olt)
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800333 """
Zsolt Haraszti80175202016-12-24 00:17:51 -0800334 device_id = line or self.default_device_id
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800335
336 # verify that device is of type simulated_olt
337 device = self.get_device(device_id)
338 assert device.type == 'simulated_olt', (
339 'Cannot use it on this device type (only on simulated_olt type)')
340
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800341 requests.get('http://{}/devices/{}/detect_onus'.format(
342 self.voltha_sim_rest, device_id
343 ))
344
Zsolt Haraszti80175202016-12-24 00:17:51 -0800345 complete_arrive_onus = VolthaCli.complete_device
346
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800347 def get_logical_ports(self, logical_device_id):
348 """
349 Return the NNI port number and the first usable UNI port of logical
350 device, and the vlan associated with the latter.
351 """
352 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
353 ports = stub.ListLogicalDevicePorts(
354 voltha_pb2.ID(id=logical_device_id)).items
355 nni = uni = vlan = None
356 for port in ports:
357 if nni is None and port.root_port:
358 nni = port.ofp_port.port_no
359 if uni is None and not port.root_port:
360 uni = port.ofp_port.port_no
361 uni_device = self.get_device(port.device_id)
362 vlan = uni_device.vlan
363 if nni is not None and uni is not None:
364 return nni, uni, vlan
365 raise Exception('No valid port pair found (no ONUs yet?)')
366
Zsolt Haraszti80175202016-12-24 00:17:51 -0800367 def do_install_eapol_flow(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800368 """
369 Install an EAPOL flow on the given logical device. If device is not
370 given, it will be applied to logical device of the last pre-provisioned
371 OLT device.
372 """
Zsolt Haraszti80175202016-12-24 00:17:51 -0800373 logical_device_id = line or self.default_logical_device_id
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800374
375 # gather NNI and UNI port IDs
Zsolt Haraszti01bbe882016-12-27 10:43:18 -0800376 nni_port_no, uni_port_no, _ = self.get_logical_ports(logical_device_id)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800377
378 # construct and push flow rule
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800379 update = FlowTableUpdate(
380 id=logical_device_id,
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800381 flow_mod=mk_simple_flow_mod(
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800382 priority=2000,
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800383 match_fields=[in_port(uni_port_no), eth_type(0x888e)],
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800384 actions=[
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800385 # push_vlan(0x8100),
386 # set_field(vlan_vid(4096 + 4000)),
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800387 output(ofp.OFPP_CONTROLLER)
388 ]
389 )
Zsolt Harasztia133a452016-12-22 01:26:57 -0800390 )
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800391 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
392 res = stub.UpdateLogicalDeviceFlowTable(update)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800393 self.poutput('success ({})'.format(res))
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800394
Zsolt Haraszti80175202016-12-24 00:17:51 -0800395 complete_install_eapol_flow = VolthaCli.complete_logical_device
396
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800397 def do_install_all_controller_bound_flows(self, line):
398 """
399 Install all flow rules for controller bound flows, including EAPOL,
400 IGMP and DHCP. If device is not given, it will be applied to logical
401 device of the last pre-provisioned OLT device.
402 """
403 logical_device_id = line or self.default_logical_device_id
404
405 # gather NNI and UNI port IDs
Zsolt Haraszti01bbe882016-12-27 10:43:18 -0800406 nni_port_no, uni_port_no, _ = self.get_logical_ports(logical_device_id)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800407
408 # construct and push flow rules
409 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
410
411 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
412 id=logical_device_id,
413 flow_mod=mk_simple_flow_mod(
414 priority=2000,
415 match_fields=[in_port(uni_port_no), eth_type(0x888e)],
416 actions=[
417 # push_vlan(0x8100),
418 # set_field(vlan_vid(4096 + 4000)),
419 output(ofp.OFPP_CONTROLLER)
420 ]
421 )
422 ))
423 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
424 id=logical_device_id,
425 flow_mod=mk_simple_flow_mod(
426 priority=1000,
427 match_fields=[eth_type(0x800), ip_proto(2)],
428 actions=[output(ofp.OFPP_CONTROLLER)]
429 )
430 ))
431 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
432 id=logical_device_id,
433 flow_mod=mk_simple_flow_mod(
434 priority=1000,
435 match_fields=[eth_type(0x800), ip_proto(17), udp_dst(67)],
436 actions=[output(ofp.OFPP_CONTROLLER)]
437 )
438 ))
439
440 self.poutput('success')
441
442 complete_install_all_controller_bound_flows = \
443 VolthaCli.complete_logical_device
444
445 def do_install_all_sample_flows(self, line):
446 """
447 Install all flows that are representative of the virtualized access
448 scenario in a PON network.
449 """
450 logical_device_id = line or self.default_logical_device_id
451
452 # gather NNI and UNI port IDs
453 nni_port_no, uni_port_no, c_vid = \
454 self.get_logical_ports(logical_device_id)
455
456 # construct and push flow rules
457 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
458
459 # Controller-bound flows
460 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
461 id=logical_device_id,
462 flow_mod=mk_simple_flow_mod(
463 priority=2000,
464 match_fields=[in_port(uni_port_no), eth_type(0x888e)],
465 actions=[
466 # push_vlan(0x8100),
467 # set_field(vlan_vid(4096 + 4000)),
468 output(ofp.OFPP_CONTROLLER)
469 ]
470 )
471 ))
472 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
473 id=logical_device_id,
474 flow_mod=mk_simple_flow_mod(
475 priority=1000,
476 match_fields=[eth_type(0x800), ip_proto(2)],
477 actions=[output(ofp.OFPP_CONTROLLER)]
478 )
479 ))
480 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
481 id=logical_device_id,
482 flow_mod=mk_simple_flow_mod(
483 priority=1000,
484 match_fields=[eth_type(0x800), ip_proto(17), udp_dst(67)],
485 actions=[output(ofp.OFPP_CONTROLLER)]
486 )
487 ))
488
489 # Unicast flows:
490 # Downstream flow 1
491 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
492 id=logical_device_id,
493 flow_mod=mk_simple_flow_mod(
494 priority=500,
495 match_fields=[
496 in_port(nni_port_no),
497 vlan_vid(4096 + 1000)
498 ],
499 actions=[pop_vlan()],
500 next_table_id=1
501 )
502 ))
503 # Downstream flow 2
504 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
505 id=logical_device_id,
506 flow_mod=mk_simple_flow_mod(
507 priority=500,
508 match_fields=[in_port(nni_port_no), vlan_vid(4096 + c_vid)],
509 actions=[set_field(vlan_vid(4096 + 0)), output(uni_port_no)]
510 )
511 ))
512 # Upstream flow 1 for 0-tagged case
513 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
514 id=logical_device_id,
515 flow_mod=mk_simple_flow_mod(
516 priority=500,
517 match_fields=[in_port(uni_port_no), vlan_vid(4096 + 0)],
518 actions=[set_field(vlan_vid(4096 + c_vid))],
519 next_table_id=1
520 )
521 ))
522 # Upstream flow 1 for untagged case
523 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
524 id=logical_device_id,
525 flow_mod=mk_simple_flow_mod(
526 priority=500,
527 match_fields=[in_port(uni_port_no), vlan_vid(0)],
528 actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + c_vid))],
529 next_table_id=1
530 )
531 ))
532 # Upstream flow 2 for s-tag
533 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
534 id=logical_device_id,
535 flow_mod=mk_simple_flow_mod(
536 priority=500,
537 match_fields=[in_port(uni_port_no), vlan_vid(4096 + c_vid)],
538 actions=[
539 push_vlan(0x8100),
540 set_field(vlan_vid(4096 + 1000)),
541 output(nni_port_no)
542 ]
543 )
544 ))
545
546 # Push a few multicast flows
547 # 1st with one bucket for our uni
548 stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
549 id=logical_device_id,
550 group_mod=mk_multicast_group_mod(
551 group_id=1,
552 buckets=[
553 ofp.ofp_bucket(actions=[pop_vlan(), output(uni_port_no)])
554 ]
555 )
556 ))
557 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
558 id=logical_device_id,
559 flow_mod=mk_simple_flow_mod(
560 priority=1000,
561 match_fields=[
562 in_port(nni_port_no),
563 eth_type(0x800),
564 vlan_vid(4096 + 140),
565 ipv4_dst(0xe4010101)
566 ],
567 actions=[group(1)]
568 )
569 ))
570 # 2st with one bucket for our uni
571 stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
572 id=logical_device_id,
573 group_mod=mk_multicast_group_mod(
574 group_id=2,
575 buckets=[
576 ofp.ofp_bucket(actions=[pop_vlan(), output(uni_port_no)])
577 ]
578 )
579 ))
580 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
581 id=logical_device_id,
582 flow_mod=mk_simple_flow_mod(
583 priority=1000,
584 match_fields=[
585 in_port(nni_port_no),
586 eth_type(0x800),
587 vlan_vid(4096 + 140),
588 ipv4_dst(0xe4020202)
589 ],
590 actions=[group(2)]
591 )
592 ))
593 # 3rd with empty bucket
594 stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
595 id=logical_device_id,
596 group_mod=mk_multicast_group_mod(
597 group_id=3,
598 buckets=[]
599 )
600 ))
601 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
602 id=logical_device_id,
603 flow_mod=mk_simple_flow_mod(
604 priority=1000,
605 match_fields=[
606 in_port(nni_port_no),
607 eth_type(0x800),
608 vlan_vid(4096 + 140),
609 ipv4_dst(0xe4030303)
610 ],
611 actions=[group(3)]
612 )
613 ))
614
615 self.poutput('success')
616
617 complete_install_all_sample_flows = VolthaCli.complete_logical_device
618
619 def do_delete_all_flows(self, line):
620 """
621 Remove all flows and flow groups from given logical device
622 """
623 logical_device_id = line or self.default_logical_device_id
624 stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
625 stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
626 id=logical_device_id,
627 flow_mod=ofp.ofp_flow_mod(
628 command=ofp.OFPFC_DELETE,
629 table_id=ofp.OFPTT_ALL,
630 cookie_mask=0,
631 out_port=ofp.OFPP_ANY,
632 out_group=ofp.OFPG_ANY
633 )
634 ))
635 stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
636 id=logical_device_id,
637 group_mod=ofp.ofp_group_mod(
638 command=ofp.OFPGC_DELETE,
639 group_id=ofp.OFPG_ALL
640 )
641 ))
642 self.poutput('success')
643
644 complete_delete_all_flows = VolthaCli.complete_logical_device
645
Zsolt Haraszti80175202016-12-24 00:17:51 -0800646 def do_send_simulated_upstream_eapol(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800647 """
648 Send an EAPOL upstream from a simulated OLT
649 """
Zsolt Haraszti80175202016-12-24 00:17:51 -0800650 device_id = line or self.default_device_id
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800651 requests.get('http://{}/devices/{}/test_eapol_in'.format(
652 self.voltha_sim_rest, device_id
653 ))
654
Zsolt Haraszti80175202016-12-24 00:17:51 -0800655 complete_send_simulated_upstream_eapol = VolthaCli.complete_device
656
657 def do_inject_eapol_start(self, line):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800658 """
659 Send out an an EAPOL start message into the given Unix interface
660 """
661 pass
Zsolt Harasztia133a452016-12-22 01:26:57 -0800662
663
664if __name__ == '__main__':
Zsolt Haraszti9b485fb2016-12-26 23:11:15 -0800665
666 parser = argparse.ArgumentParser()
667
668 _help = '<hostname>:<port> to consul agent (default: %s)' % defs['consul']
669 parser.add_argument(
670 '-C', '--consul', action='store', default=defs['consul'], help=_help)
671
672 _help = 'Lookup Voltha endpoints based on service entries in Consul'
673 parser.add_argument(
674 '-L', '--lookup', action='store_true', help=_help)
675
676 _help = '<hostname>:<port> of Voltha gRPC service (default={})'.format(
677 defs['voltha_grpc_endpoint'])
678 parser.add_argument('-g', '--grpc-endpoint', action='store',
679 default=defs['voltha_grpc_endpoint'], help=_help)
680
681 _help = '<hostname>:<port> of Voltha simulated adapter backend for ' \
682 'testing (default={})'.format(
683 defs['voltha_sim_rest_endpoint'])
684 parser.add_argument('-s', '--sim-rest-endpoint', action='store',
685 default=defs['voltha_sim_rest_endpoint'], help=_help)
686
687 args = parser.parse_args()
688
689 if args.lookup:
690 host = args.consul.split(':')[0].strip()
691 port = int(args.consul.split(':')[1].strip())
692 consul = Consul(host=host, port=port)
693
694 _, services = consul.catalog.service('voltha-grpc')
695 if not services:
696 print('No voltha-grpc service registered in consul; exiting')
697 sys.exit(1)
698 args.grpc_endpoint = '{}:{}'.format(services[0]['ServiceAddress'],
699 services[0]['ServicePort'])
700
701 _, services = consul.catalog.service('voltha-sim-rest')
702 if not services:
703 print('No voltha-sim-rest service registered in consul; exiting')
704 sys.exit(1)
705 args.sim_rest_endpoint = '{}:{}'.format(services[0]['ServiceAddress'],
706 services[0]['ServicePort'])
707
708 c = VolthaCli(args.grpc_endpoint, args.sim_rest_endpoint)
Zsolt Haraszti80175202016-12-24 00:17:51 -0800709 c.poutput(banner)
Zsolt Harasztia133a452016-12-22 01:26:57 -0800710 c.load_history()
711 c.cmdloop()
712 c.save_history()