blob: f5d09cd5a05503c4d7fb3f2321aeafc9f01897b1 [file] [log] [blame]
# Copyright 2017-present Open Networking Foundation
#
# 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.
from time import time, sleep
from google.protobuf.json_format import MessageToDict
from voltha.core.flow_decomposer import *
from voltha.protos.device_pb2 import Device
from voltha.protos.common_pb2 import AdminState, OperStatus
from voltha.protos import openflow_13_pb2 as ofp
from tests.itests.voltha.rest_base import RestBase
from common.utils.consulhelpers import get_endpoint_from_consul
from structlog import get_logger
from tests.itests.test_utils import get_pod_ip
from testconfig import config
LOCAL_CONSUL = "localhost:8500"
log = get_logger()
orch_env = 'docker-compose'
if 'test_parameters' in config and 'orch_env' in config['test_parameters']:
orch_env = config['test_parameters']['orch_env']
log.debug('orchestration-environment', orch_env=orch_env)
class TestColdActivationSequence(RestBase):
# Retrieve details of the REST entry point
if orch_env == 'k8s-single-node':
rest_endpoint = get_pod_ip('voltha') + ':8443'
elif orch_env == 'swarm-single-node':
rest_endpoint = 'localhost:8443'
else:
rest_endpoint = get_endpoint_from_consul(LOCAL_CONSUL, 'voltha-envoy-8443')
# Construct the base_url
base_url = 'https://' + rest_endpoint
log.debug('cold-activation-test', base_url=base_url)
def wait_till(self, msg, predicate, interval=0.1, timeout=5.0):
deadline = time() + timeout
while time() < deadline:
if predicate():
return
sleep(interval)
self.fail('Timed out while waiting for condition: {}'.format(msg))
def test_cold_activation_sequence(self):
"""Complex test-case to cover device activation sequence"""
self.verify_prerequisites()
olt_id = self.add_olt_device()
self.verify_device_preprovisioned_state(olt_id)
self.activate_device(olt_id)
ldev_id = self.wait_for_logical_device(olt_id)
onu_ids = self.wait_for_onu_discovery(olt_id)
self.verify_logical_ports(ldev_id)
self.simulate_eapol_flow_install(ldev_id, olt_id, onu_ids)
self.verify_olt_eapol_flow(olt_id)
self.verify_onu_forwarding_flows(onu_ids)
self.simulate_eapol_start()
self.simulate_eapol_request_identity()
self.simulate_eapol_response_identity()
self.simulate_eapol_request()
self.simulate_eapol_response()
self.simulate_eapol_success()
self.install_and_verify_dhcp_flows()
self.install_and_verify_igmp_flows()
self.install_and_verifyunicast_flows()
def verify_prerequisites(self):
# all we care is that Voltha is available via REST using the base uri
self.get('/api/v1')
def add_olt_device(self):
device = Device(
type='simulated_olt',
mac_address='00:00:00:00:00:01'
)
device = self.post('/api/v1/devices', MessageToDict(device),
expected_http_code=200)
return device['id']
def verify_device_preprovisioned_state(self, olt_id):
# we also check that so far what we read back is same as what we get
# back on create
device = self.get('/api/v1/devices/{}'.format(olt_id))
self.assertNotEqual(device['id'], '')
self.assertEqual(device['adapter'], 'simulated_olt')
self.assertEqual(device['admin_state'], 'PREPROVISIONED')
self.assertEqual(device['oper_status'], 'UNKNOWN')
def activate_device(self, olt_id):
path = '/api/v1/devices/{}'.format(olt_id)
self.post(path + '/enable', expected_http_code=200)
device = self.get(path)
self.assertEqual(device['admin_state'], 'ENABLED')
self.wait_till(
'admin state moves to ACTIVATING or ACTIVE',
lambda: self.get(path)['oper_status'] in ('ACTIVATING', 'ACTIVE'),
timeout=0.5)
# eventually, it shall move to active state and by then we shall have
# device details filled, connect_state set, and device ports created
self.wait_till(
'admin state ACTIVE',
lambda: self.get(path)['oper_status'] == 'ACTIVE',
timeout=0.5)
device = self.get(path)
images = device['images']
image = images['image']
image_1 = image[0]
version = image_1['version']
self.assertNotEqual(version, '')
self.assertEqual(device['connect_status'], 'REACHABLE')
ports = self.get(path + '/ports')['items']
self.assertEqual(len(ports), 2)
def wait_for_logical_device(self, olt_id):
# we shall find the logical device id from the parent_id of the olt
# (root) device
device = self.get(
'/api/v1/devices/{}'.format(olt_id))
self.assertNotEqual(device['parent_id'], '')
logical_device = self.get(
'/api/v1/logical_devices/{}'.format(device['parent_id']))
# the logical device shall be linked back to the hard device,
# its ports too
self.assertEqual(logical_device['root_device_id'], device['id'])
logical_ports = self.get(
'/api/v1/logical_devices/{}/ports'.format(
logical_device['id'])
)['items']
self.assertGreaterEqual(len(logical_ports), 1)
logical_port = logical_ports[0]
self.assertEqual(logical_port['id'], 'nni')
self.assertEqual(logical_port['ofp_port']['name'], 'nni')
self.assertEqual(logical_port['ofp_port']['port_no'], 129)
self.assertEqual(logical_port['device_id'], device['id'])
self.assertEqual(logical_port['device_port_no'], 2)
return logical_device['id']
def wait_for_onu_discovery(self, olt_id):
# shortly after we shall see the discovery of four new onus, linked to
# the olt device
def find_our_onus():
devices = self.get('/api/v1/devices')['items']
return [
d for d in devices
if d['parent_id'] == olt_id
]
self.wait_till(
'find ONUs linked to the olt device',
lambda: len(find_our_onus()) >= 1,
2
)
# verify that they are properly set
onus = find_our_onus()
for onu in onus:
self.assertEqual(onu['admin_state'], 'ENABLED')
self.assertEqual(onu['oper_status'], 'ACTIVE')
return [onu['id'] for onu in onus]
def verify_logical_ports(self, ldev_id):
# at this point we shall see at least 5 logical ports on the
# logical device
logical_ports = self.get(
'/api/v1/logical_devices/{}/ports'.format(ldev_id)
)['items']
self.assertGreaterEqual(len(logical_ports), 5)
# verify that all logical ports are LIVE (state=4)
for lport in logical_ports:
self.assertEqual(lport['ofp_port']['state'], 4)
def simulate_eapol_flow_install(self, ldev_id, olt_id, onu_ids):
# emulate the flow mod requests that shall arrive from the SDN
# controller, one for each ONU
lports = self.get(
'/api/v1/logical_devices/{}/ports'.format(ldev_id)
)['items']
# device_id -> logical port map, which we will use to construct
# our flows
lport_map = dict((lp['device_id'], lp) for lp in lports)
for onu_id in onu_ids:
# if eth_type == 0x888e => send to controller
_in_port = lport_map[onu_id]['ofp_port']['port_no']
req = ofp.FlowTableUpdate(
id=ldev_id,
flow_mod=mk_simple_flow_mod(
match_fields=[
in_port(_in_port),
vlan_vid(ofp.OFPVID_PRESENT | 0),
eth_type(0x888e)],
actions=[
output(ofp.OFPP_CONTROLLER)
],
priority=1000
)
)
res = self.post('/api/v1/logical_devices/{}/flows'.format(ldev_id),
MessageToDict(req,
preserving_proto_field_name=True),
expected_http_code=200)
# for sanity, verify that flows are in flow table of logical device
flows = self.get(
'/api/v1/logical_devices/{}/flows'.format(ldev_id))['items']
self.assertGreaterEqual(len(flows), 4)
def verify_olt_eapol_flow(self, olt_id):
flows = self.get('/api/v1/devices/{}/flows'.format(olt_id))['items']
self.assertEqual(len(flows), 8)
flow = flows[1]
self.assertEqual(flow['table_id'], 0)
self.assertEqual(flow['priority'], 1000)
# TODO refine this
# self.assertEqual(flow['match'], {})
# self.assertEqual(flow['instructions'], [])
def verify_onu_forwarding_flows(self, onu_ids):
pass
def simulate_eapol_start(self):
pass
def simulate_eapol_request_identity(self):
pass
def simulate_eapol_response_identity(self):
pass
def simulate_eapol_request(self):
pass
def simulate_eapol_response(self):
pass
def simulate_eapol_success(self):
pass
def install_and_verify_dhcp_flows(self):
pass
def install_and_verify_igmp_flows(self):
pass
def install_and_verifyunicast_flows(self):
pass