blob: 3a30a0dc8a21aaea9a0c798c05a6c01bbfc6e668 [file] [log] [blame]
#!/usr/bin/env python
#
# Copyright 2016 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import argparse
import os
import readline
import sys
from optparse import make_option
from time import sleep, time
import etcd3
import grpc
import requests
from cmd2 import Cmd, options
from consul import Consul
from google.protobuf.empty_pb2 import Empty
from simplejson import dumps
from cli.device import DeviceCli
from cli.xpon import XponCli
from cli.omci import OmciCli
from cli.alarm_filters import AlarmFiltersCli
from cli.logical_device import LogicalDeviceCli
from cli.table import print_pb_list_as_table
from voltha.protos import third_party
from voltha.protos import voltha_pb2, voltha_pb2_grpc, health_pb2_grpc
from voltha.protos.openflow_13_pb2 import FlowTableUpdate, FlowGroupTableUpdate
_ = third_party
from cli.utils import pb2dict
defs = dict(
# config=os.environ.get('CONFIG', './cli.yml'),
etcd=os.environ.get('ETCD', 'etcd-cluster.default.svc.cluster.local:2379'),
consul=os.environ.get('CONSUL', 'localhost:8500'),
voltha_grpc_endpoint=os.environ.get('VOLTHA_GRPC_ENDPOINT',
'localhost:50055'),
voltha_sim_rest_endpoint=os.environ.get('VOLTHA_SIM_REST_ENDPOINT',
'localhost:18880'),
global_request=os.environ.get('GLOBAL_REQUEST', False)
)
banner = """\
_ _ _ ___ _ ___
__ _____| | |_| |_ __ _ / __| | |_ _|
\ V / _ \ | _| ' \/ _` | | (__| |__ | |
\_/\___/_|\__|_||_\__,_| \___|____|___|
(to exit type quit or exit or hit Ctrl-D)
"""
class VolthaCli(Cmd):
prompt = 'voltha'
history_file_name = '.voltha_cli_history'
# Settable CLI parameters
voltha_grpc = 'localhost:50055'
voltha_sim_rest = 'localhost:18880'
global_request = False
max_history_lines = 500
default_device_id = None
default_logical_device_id = None
Cmd.settable.update(dict(
voltha_grpc='Voltha GRPC endpoint in form of <host>:<port>',
voltha_sim_rest='Voltha simulation back door for testing in form '
'of <host>:<port>',
max_history_lines='Maximum number of history lines stored across '
'sessions',
default_device_id='Device id used when no device id is specified',
default_logical_device_id='Logical device id used when no device id '
'is specified',
))
# cleanup of superfluous commands from cmd2
del Cmd.do_cmdenvironment
del Cmd.do_load
del Cmd.do__relative_load
def __init__(self, voltha_grpc, voltha_sim_rest, etcd, global_request=False):
VolthaCli.voltha_grpc = voltha_grpc
VolthaCli.voltha_sim_rest = voltha_sim_rest
VolthaCli.global_request = global_request
VolthaCli.etcd = etcd
Cmd.__init__(self)
self.prompt = '(' + self.colorize(
self.colorize(self.prompt, 'blue'), 'bold') + ') '
self.channel = None
self.stub = None
self.device_ids_cache = None
self.device_ids_cache_ts = time()
self.logical_device_ids_cache = None
self.logical_device_ids_cache_ts = time()
# we override cmd2's method to avoid its optparse conflicting with our
# command line parsing
def cmdloop(self):
self._cmdloop()
def load_history(self):
"""Load saved command history from local history file"""
try:
with file(self.history_file_name, 'r') as f:
for line in f.readlines():
stripped_line = line.strip()
self.history.append(stripped_line)
readline.add_history(stripped_line)
except IOError:
pass # ignore if file cannot be read
def save_history(self):
try:
with open(self.history_file_name, 'w') as f:
f.write('\n'.join(self.history[-self.max_history_lines:]))
except IOError as e:
self.perror('Could not save history in {}: {}'.format(
self.history_file_name, e))
else:
self.poutput('History saved as {}'.format(
self.history_file_name))
def perror(self, errmsg, statement=None):
# Touch it up to make sure error is prefixed and colored
Cmd.perror(self, self.colorize('***ERROR: ', 'red') + errmsg,
statement)
def get_channel(self):
if self.channel is None:
self.channel = grpc.insecure_channel(self.voltha_grpc)
return self.channel
def get_stub(self):
if self.stub is None:
self.stub = \
voltha_pb2_grpc.VolthaGlobalServiceStub(self.get_channel()) \
if self.global_request else \
voltha_pb2_grpc.VolthaLocalServiceStub(self.get_channel())
return self.stub
# ~~~~~~~~~~~~~~~~~ ACTUAL COMMAND IMPLEMENTATIONS ~~~~~~~~~~~~~~~~~~~~~~~~
def do_reset_history(self, line):
"""Reset CLI history"""
while self.history:
self.history.pop()
def do_exit(self,line):
"""exit from CLI"""
quit()
def do_launch(self, line):
"""If Voltha is not running yet, launch it"""
raise NotImplementedError('not implemented yet')
def do_restart(self, line):
"""Launch Voltha, but if it is already running, terminate it first"""
pass
def do_adapters(self, line):
"""List loaded adapter"""
stub = self.get_stub()
res = stub.ListAdapters(Empty())
omit_fields = {'config.log_level', 'logical_device_ids'}
print_pb_list_as_table('Adapters:', res.items, omit_fields, self.poutput)
def get_devices(self):
stub = self.get_stub()
res = stub.ListDevices(Empty())
return res.items
def get_logical_devices(self):
stub = self.get_stub()
res = stub.ListLogicalDevices(Empty())
return res.items
def do_devices(self, line):
"""List devices registered in Voltha"""
devices = self.get_devices()
omit_fields = {
'adapter',
'vendor',
'model',
'hardware_version',
'images',
'firmware_version',
'vendor_id'
}
print_pb_list_as_table('Devices:', devices, omit_fields, self.poutput)
def do_logical_devices(self, line):
"""List logical devices in Voltha"""
stub = self.get_stub()
res = stub.ListLogicalDevices(Empty())
omit_fields = {
'desc.mfr_desc',
'desc.hw_desc',
'desc.sw_desc',
'desc.dp_desc',
'desc.serial_number',
'switch_features.capabilities'
}
presfns = {
'datapath_id': lambda x: "{0:0{1}x}".format(int(x), 16)
}
print_pb_list_as_table('Logical devices:', res.items, omit_fields,
self.poutput, presfns=presfns)
def do_device(self, line):
"""Enter device level command mode"""
device_id = line.strip() or self.default_device_id
if not device_id:
raise Exception('<device-id> parameter needed')
if device_id not in self.device_ids():
self.poutput( self.colorize('Error: ', 'red') +
'There is no such device')
raise Exception('<device-id> is not a valid one')
sub = DeviceCli(device_id, self.get_stub, self.etcd)
sub.cmdloop()
def do_logical_device(self, line):
"""Enter logical device level command mode"""
logical_device_id = line.strip() or self.default_logical_device_id
if not logical_device_id:
raise Exception('<logical-device-id> parameter needed')
if logical_device_id not in self.logical_device_ids():
self.poutput( self.colorize('Error: ', 'red') +
'There is no such device')
raise Exception('<logical-device-id> is not a valid one')
sub = LogicalDeviceCli(logical_device_id, self.get_stub)
sub.cmdloop()
def device_ids(self, force_refresh=False):
if force_refresh or self.device_ids is None or \
(time() - self.device_ids_cache_ts) > 1:
self.device_ids_cache = [d.id for d in self.get_devices()]
self.device_ids_cache_ts = time()
return self.device_ids_cache
def logical_device_ids(self, force_refresh=False):
if force_refresh or self.logical_device_ids is None or \
(time() - self.logical_device_ids_cache_ts) > 1:
self.logical_device_ids_cache = [d.id for d
in self.get_logical_devices()]
self.logical_device_ids_cache_ts = time()
return self.logical_device_ids_cache
def complete_device(self, text, line, begidx, endidx):
if not text:
completions = self.device_ids()[:]
else:
completions = [d for d in self.device_ids() if d.startswith(text)]
return completions
def complete_logical_device(self, text, line, begidx, endidx):
if not text:
completions = self.logical_device_ids()[:]
else:
completions = [d for d in self.logical_device_ids()
if d.startswith(text)]
return completions
def do_xpon(self, line):
"""xpon <optional> [device_ID] - Enter xpon level command mode"""
device_id = line.strip()
if device_id:
stub = self.get_stub()
try:
res = stub.GetDevice(voltha_pb2.ID(id=device_id))
except Exception:
self.poutput(
self.colorize('Error: ', 'red') + 'No device id ' +
self.colorize(device_id, 'blue') + ' is found')
return
sub = XponCli(self.get_channel, device_id)
sub.cmdloop()
def do_omci(self, line):
"""omci <device_ID> - Enter OMCI level command mode"""
device_id = line.strip() or self.default_device_id
if not device_id:
raise Exception('<device-id> parameter needed')
sub = OmciCli(device_id, self.get_stub)
sub.cmdloop()
def do_pdb(self, line):
"""Launch PDB debug prompt in CLI (for CLI development)"""
from pdb import set_trace
set_trace()
def do_version(self, line):
"""Show the VOLTHA core version"""
stub = self.get_stub()
voltha = stub.GetVoltha(Empty())
self.poutput('{}'.format(voltha.version))
def do_health(self, line):
"""Show connectivity status to Voltha status"""
stub = health_pb2_grpc.HealthServiceStub(self.get_channel())
res = stub.GetHealthStatus(Empty())
self.poutput(dumps(pb2dict(res), indent=4))
@options([
make_option('-t', '--device-type', action="store", dest='device_type',
help="Device type", default='simulated_olt'),
make_option('-m', '--mac-address', action='store', dest='mac_address',
default='00:0c:e2:31:40:00'),
make_option('-i', '--ip-address', action='store', dest='ip_address'),
make_option('-H', '--host_and_port', action='store',
dest='host_and_port'),
])
def do_preprovision_olt(self, line, opts):
"""Preprovision a new OLT with given device type"""
stub = self.get_stub()
kw = dict(type=opts.device_type)
if opts.host_and_port:
kw['host_and_port'] = opts.host_and_port
elif opts.ip_address:
kw['ipv4_address'] = opts.ip_address
elif opts.mac_address:
kw['mac_address'] = opts.mac_address.lower()
else:
raise Exception('Either IP address or Mac Address is needed')
# Pass any extra arguments past '--' to the device as custom arguments
kw['extra_args'] = line
device = voltha_pb2.Device(**kw)
device = stub.CreateDevice(device)
self.poutput('success (device id = {})'.format(device.id))
self.default_device_id = device.id
def do_enable(self, line):
"""
Enable a device. If the <id> is not provided, it will be on the last
pre-provisioned device.
"""
device_id = line or self.default_device_id
if device_id not in self.device_ids():
self.poutput('Error: There is no such preprovisioned device')
return
try:
stub = self.get_stub()
device = stub.GetDevice(voltha_pb2.ID(id=device_id))
if device.admin_state == voltha_pb2.AdminState.ENABLED:
if device.oper_status != voltha_pb2.OperStatus.ACTIVATING:
self.poutput('Error: Device is already enabled')
return
else:
stub.EnableDevice(voltha_pb2.ID(id=device_id))
self.poutput('enabling {}'.format(device_id))
while True:
device = stub.GetDevice(voltha_pb2.ID(id=device_id))
# If this is an OLT then acquire logical device id
if device.oper_status == voltha_pb2.OperStatus.ACTIVE:
if device.type.endswith('_olt'):
assert device.parent_id
self.default_logical_device_id = device.parent_id
self.poutput('success (logical device id = {})'.format(
self.default_logical_device_id))
else:
self.poutput('success (device id = {})'.format(device.id))
break
self.poutput('waiting for device to be enabled...')
sleep(.5)
except Exception as e:
self.poutput('Error enabling {}. Error:{}'.format(device_id, e))
complete_activate_olt = complete_device
def do_reboot(self, line):
"""
Rebooting a device. ID of the device needs to be provided
"""
device_id = line or self.default_device_id
self.poutput('rebooting {}'.format(device_id))
try:
stub = self.get_stub()
stub.RebootDevice(voltha_pb2.ID(id=device_id))
self.poutput('rebooted {}'.format(device_id))
except Exception as e:
self.poutput('Error rebooting {}. Error:{}'.format(device_id, e))
def do_self_test(self, line):
"""
Self Test a device. ID of the device needs to be provided
"""
device_id = line or self.default_device_id
self.poutput('Self Testing {}'.format(device_id))
try:
stub = self.get_stub()
res = stub.SelfTest(voltha_pb2.ID(id=device_id))
self.poutput('Self Tested {}'.format(device_id))
self.poutput(dumps(pb2dict(res), indent=4))
except Exception as e:
self.poutput('Error in self test {}. Error:{}'.format(device_id, e))
def do_delete(self, line):
"""
Deleting a device. ID of the device needs to be provided
"""
device_id = line or self.default_device_id
self.poutput('deleting {}'.format(device_id))
try:
stub = self.get_stub()
stub.DeleteDevice(voltha_pb2.ID(id=device_id))
self.poutput('deleted {}'.format(device_id))
except Exception as e:
self.poutput('Error deleting {}. Error:{}'.format(device_id, e))
def do_disable(self, line):
"""
Disable a device. ID of the device needs to be provided
"""
device_id = line
if device_id not in self.device_ids():
self.poutput('Error: There is no such device')
return
try:
stub = self.get_stub()
device = stub.GetDevice(voltha_pb2.ID(id=device_id))
if device.admin_state == voltha_pb2.AdminState.DISABLED:
self.poutput('Error: Device is already disabled')
return
stub.DisableDevice(voltha_pb2.ID(id=device_id))
self.poutput('disabling {}'.format(device_id))
# Do device query and verify that the device admin status is
# DISABLED and Operational Status is unknown
device = stub.GetDevice(voltha_pb2.ID(id=device_id))
if device.admin_state == voltha_pb2.AdminState.DISABLED:
self.poutput('disabled successfully {}'.format(device_id))
else:
self.poutput('disabling failed {}. Admin State:{} '
'Operation State: {}'.format(device_id,
device.admin_state,
device.oper_status))
except Exception as e:
self.poutput('Error disabling {}. Error:{}'.format(device_id, e))
def do_test(self, line):
"""Enter test mode, which makes a bunch on new commands available"""
sub = TestCli(self.history, self.voltha_grpc,
self.get_stub, self.voltha_sim_rest)
sub.cmdloop()
def do_alarm_filters(self, line):
sub = AlarmFiltersCli(self.get_stub)
sub.cmdloop()
class TestCli(VolthaCli):
def __init__(self, history, voltha_grpc, get_stub, voltha_sim_rest):
VolthaCli.__init__(self, voltha_grpc, voltha_sim_rest)
self.history = history
self.get_stub = get_stub
self.prompt = '(' + self.colorize(self.colorize('test', 'cyan'),
'bold') + ') '
def get_device(self, device_id, depth=0):
stub = self.get_stub()
res = stub.GetDevice(voltha_pb2.ID(id=device_id),
metadata=(('get-depth', str(depth)),))
return res
def do_arrive_onus(self, line):
"""
Simulate the arrival of ONUs (available only on simulated_olt)
"""
device_id = line or self.default_device_id
# verify that device is of type simulated_olt
device = self.get_device(device_id)
assert device.type == 'simulated_olt', (
'Cannot use it on this device type (only on simulated_olt type)')
requests.get('http://{}/devices/{}/detect_onus'.format(
self.voltha_sim_rest, device_id
))
complete_arrive_onus = VolthaCli.complete_device
def get_logical_ports(self, logical_device_id):
"""
Return the NNI port number and the first usable UNI port of logical
device, and the vlan associated with the latter.
"""
stub = self.get_stub()
ports = stub.ListLogicalDevicePorts(
voltha_pb2.ID(id=logical_device_id)).items
nni = None
unis = []
for port in ports:
if port.root_port:
assert nni is None, "There shall be only one root port"
nni = port.ofp_port.port_no
else:
uni = port.ofp_port.port_no
uni_device = self.get_device(port.device_id)
vlan = uni_device.vlan
unis.append((uni, vlan))
assert nni is not None, "No NNI port found"
assert unis, "Not a single UNI?"
return nni, unis
def do_install_eapol_flow(self, line):
"""
Install an EAPOL flow on the given logical device. If device is not
given, it will be applied to logical device of the last pre-provisioned
OLT device.
"""
logical_device_id = line or self.default_logical_device_id
# gather NNI and UNI port IDs
nni_port_no, unis = self.get_logical_ports(logical_device_id)
# construct and push flow rule
stub = self.get_stub()
for uni_port_no, _ in unis:
update = FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=2000,
match_fields=[in_port(uni_port_no), eth_type(0x888e)],
actions=[
# push_vlan(0x8100),
# set_field(vlan_vid(4096 + 4000)),
output(ofp.OFPP_CONTROLLER)
]
)
)
res = stub.UpdateLogicalDeviceFlowTable(update)
self.poutput('success for uni {} ({})'.format(uni_port_no, res))
complete_install_eapol_flow = VolthaCli.complete_logical_device
def do_install_all_controller_bound_flows(self, line):
"""
Install all flow rules for controller bound flows, including EAPOL,
IGMP and DHCP. If device is not given, it will be applied to logical
device of the last pre-provisioned OLT device.
"""
logical_device_id = line or self.default_logical_device_id
# gather NNI and UNI port IDs
nni_port_no, unis = self.get_logical_ports(logical_device_id)
# construct and push flow rules
stub = self.get_stub()
for uni_port_no, _ in unis:
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=2000,
match_fields=[
in_port(uni_port_no),
eth_type(0x888e)
],
actions=[output(ofp.OFPP_CONTROLLER)]
)
))
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=1000,
match_fields=[
in_port(uni_port_no),
eth_type(0x800),
ip_proto(2)
],
actions=[output(ofp.OFPP_CONTROLLER)]
)
))
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=1000,
match_fields=[
in_port(uni_port_no),
eth_type(0x800),
ip_proto(17),
udp_dst(67)
],
actions=[output(ofp.OFPP_CONTROLLER)]
)
))
self.poutput('success')
complete_install_all_controller_bound_flows = \
VolthaCli.complete_logical_device
def do_install_all_sample_flows(self, line):
"""
Install all flows that are representative of the virtualized access
scenario in a PON network.
"""
logical_device_id = line or self.default_logical_device_id
# gather NNI and UNI port IDs
nni_port_no, unis = self.get_logical_ports(logical_device_id)
# construct and push flow rules
stub = self.get_stub()
for uni_port_no, c_vid in unis:
# Controller-bound flows
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=2000,
match_fields=[in_port(uni_port_no), eth_type(0x888e)],
actions=[
# push_vlan(0x8100),
# set_field(vlan_vid(4096 + 4000)),
output(ofp.OFPP_CONTROLLER)
]
)
))
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=1000,
match_fields=[eth_type(0x800), ip_proto(2)],
actions=[output(ofp.OFPP_CONTROLLER)]
)
))
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=1000,
match_fields=[eth_type(0x800), ip_proto(17), udp_dst(67)],
actions=[output(ofp.OFPP_CONTROLLER)]
)
))
# Unicast flows:
# Downstream flow 1
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=500,
match_fields=[
in_port(nni_port_no),
vlan_vid(4096 + 1000),
metadata(c_vid) # here to mimic an ONOS artifact
],
actions=[pop_vlan()],
next_table_id=1
)
))
# Downstream flow 2
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=500,
table_id=1,
match_fields=[in_port(nni_port_no), vlan_vid(4096 + c_vid)],
actions=[set_field(vlan_vid(4096 + 0)), output(uni_port_no)]
)
))
# Upstream flow 1 for 0-tagged case
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=500,
match_fields=[in_port(uni_port_no), vlan_vid(4096 + 0)],
actions=[set_field(vlan_vid(4096 + c_vid))],
next_table_id=1
)
))
# Upstream flow 1 for untagged case
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=500,
match_fields=[in_port(uni_port_no), vlan_vid(0)],
actions=[push_vlan(0x8100), set_field(vlan_vid(4096 + c_vid))],
next_table_id=1
)
))
# Upstream flow 2 for s-tag
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=500,
table_id=1,
match_fields=[in_port(uni_port_no), vlan_vid(4096 + c_vid)],
actions=[
push_vlan(0x8100),
set_field(vlan_vid(4096 + 1000)),
output(nni_port_no)
]
)
))
# Push a few multicast flows
# 1st with one bucket for our uni 0
stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
id=logical_device_id,
group_mod=mk_multicast_group_mod(
group_id=1,
buckets=[
ofp.ofp_bucket(actions=[
pop_vlan(),
output(unis[0][0])
])
]
)
))
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=1000,
match_fields=[
in_port(nni_port_no),
eth_type(0x800),
vlan_vid(4096 + 140),
ipv4_dst(0xe4010101)
],
actions=[group(1)]
)
))
# 2nd with one bucket for uni 0 and 1
stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
id=logical_device_id,
group_mod=mk_multicast_group_mod(
group_id=2,
buckets=[
ofp.ofp_bucket(actions=[pop_vlan(), output(unis[0][0])])
# ofp.ofp_bucket(actions=[pop_vlan(), output(unis[1][0])])
]
)
))
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=1000,
match_fields=[
in_port(nni_port_no),
eth_type(0x800),
vlan_vid(4096 + 140),
ipv4_dst(0xe4020202)
],
actions=[group(2)]
)
))
# 3rd with empty bucket
stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
id=logical_device_id,
group_mod=mk_multicast_group_mod(
group_id=3,
buckets=[]
)
))
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=1000,
match_fields=[
in_port(nni_port_no),
eth_type(0x800),
vlan_vid(4096 + 140),
ipv4_dst(0xe4030303)
],
actions=[group(3)]
)
))
self.poutput('success')
complete_install_all_sample_flows = VolthaCli.complete_logical_device
def do_install_dhcp_flows(self, line):
"""
Install all dhcp flows that are representative of the virtualized access
scenario in a PON network.
"""
logical_device_id = line or self.default_logical_device_id
# gather NNI and UNI port IDs
nni_port_no, unis = self.get_logical_ports(logical_device_id)
# construct and push flow rules
stub = self.get_stub()
# Controller-bound flows
for uni_port_no, _ in unis:
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=mk_simple_flow_mod(
priority=1000,
match_fields=[
in_port(uni_port_no),
eth_type(0x800),
ip_proto(17),
udp_dst(67)
],
actions=[output(ofp.OFPP_CONTROLLER)]
)
))
self.poutput('success')
complete_install_dhcp_flows = VolthaCli.complete_logical_device
def do_delete_all_flows(self, line):
"""
Remove all flows and flow groups from given logical device
"""
logical_device_id = line or self.default_logical_device_id
stub = self.get_stub()
stub.UpdateLogicalDeviceFlowTable(FlowTableUpdate(
id=logical_device_id,
flow_mod=ofp.ofp_flow_mod(
command=ofp.OFPFC_DELETE,
table_id=ofp.OFPTT_ALL,
cookie_mask=0,
out_port=ofp.OFPP_ANY,
out_group=ofp.OFPG_ANY
)
))
stub.UpdateLogicalDeviceFlowGroupTable(FlowGroupTableUpdate(
id=logical_device_id,
group_mod=ofp.ofp_group_mod(
command=ofp.OFPGC_DELETE,
group_id=ofp.OFPG_ALL
)
))
self.poutput('success')
complete_delete_all_flows = VolthaCli.complete_logical_device
def do_send_simulated_upstream_eapol(self, line):
"""
Send an EAPOL upstream from a simulated OLT
"""
device_id = line or self.default_device_id
requests.get('http://{}/devices/{}/test_eapol_in'.format(
self.voltha_sim_rest, device_id
))
complete_send_simulated_upstream_eapol = VolthaCli.complete_device
def do_inject_eapol_start(self, line):
"""
Send out an an EAPOL start message into the given Unix interface
"""
pass
if __name__ == '__main__':
parser = argparse.ArgumentParser()
_help = '<hostname>:<port> to consul agent (default: %s)' % defs['consul']
parser.add_argument(
'-C', '--consul', action='store', default=defs['consul'], help=_help)
_help = '<hostname>:<port> to etcd container (default: %s)' % defs['etcd']
parser.add_argument(
'-E', '--etcd', action='store', default=defs['etcd'], help=_help)
_help = 'Lookup Voltha endpoints based on service entries in Consul'
parser.add_argument(
'-L', '--lookup', action='store_true', help=_help)
_help = 'All requests to the Voltha gRPC service are global'
parser.add_argument(
'-G', '--global_request', action='store_true', help=_help)
_help = '<hostname>:<port> of Voltha gRPC service (default={})'.format(
defs['voltha_grpc_endpoint'])
parser.add_argument('-g', '--grpc-endpoint', action='store',
default=defs['voltha_grpc_endpoint'], help=_help)
_help = '<hostname>:<port> of Voltha simulated adapter backend for ' \
'testing (default={})'.format(
defs['voltha_sim_rest_endpoint'])
parser.add_argument('-s', '--sim-rest-endpoint', action='store',
default=defs['voltha_sim_rest_endpoint'], help=_help)
args = parser.parse_args()
if args.lookup:
host = args.consul.split(':')[0].strip()
port = int(args.consul.split(':')[1].strip())
consul = Consul(host=host, port=port)
_, services = consul.catalog.service('voltha-grpc')
if not services:
print('No voltha-grpc service registered in consul; exiting')
sys.exit(1)
args.grpc_endpoint = '{}:{}'.format(services[0]['ServiceAddress'],
services[0]['ServicePort'])
_, services = consul.catalog.service('voltha-sim-rest')
if not services:
print('No voltha-sim-rest service registered in consul; exiting')
sys.exit(1)
args.sim_rest_endpoint = '{}:{}'.format(services[0]['ServiceAddress'],
services[0]['ServicePort'])
host = args.etcd.split(':')[0].strip()
port = int(args.etcd.split(':')[1].strip())
etcd = etcd3.client(host=host, port=port)
c = VolthaCli(args.grpc_endpoint, args.sim_rest_endpoint, etcd,
args.global_request)
c.poutput(banner)
c.load_history()
c.cmdloop()
c.save_history()