blob: 8c97b1f407ff5e9c1ca1d3ea3b8dc5d600f4b34f [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.
"""
A set of inter-test utility functions for dealing with OF-DPA
"""
import logging, subprocess, time
import ofp
from oftest import config
from oftest.testutils import *
def forceOfdpaRestart( user ):
output = 1;
credential = user;
test = subprocess.Popen(["ssh", credential, "service ofdpa restart &> /dev/null"]);
time.sleep(1);
while output < 10:
output = int(subprocess.check_output(["ssh", credential, "client_cfg_purge | wc -l"]));
time.sleep(1);
subprocess.Popen(["ssh", credential, "brcm-indigo-ofdpa-ofagent -t 10.128.0.220 &> /dev/null"], stdout=subprocess.PIPE);
def forceOfdpaStop( user ):
subprocess.Popen(["ssh", user, "ps ax | grep 'brcm-indigo-ofdpa-ofagent' | awk '{print $1}' | xargs sudo kill"], stdout=subprocess.PIPE);
class table(object):
""" Metadata on each OFDPA table """
def __init__(self, table_id, table_name):
self.table_id = table_id
self.table_name = table_name
# TODO consider adding type checking verification here
INGRESS_TABLE = table(0, "Ingress")
VLAN_TABLE = table(10, "VLAN")
MACTERM_TABLE = table(20, "MacTerm")
UNICAST_ROUTING_TABLE = table(30, "Unicast Routing")
MULTICAST_ROUTING_TABLE = table(40, "Multicast Routing")
BRIDGING_TABLE = table(50, "Bridging Table")
ACL_TABLE = table(60, "ACL Policy Table")
#.... FIXME add all tables
DEFAULT_VLAN = 1
def enableVlanOnPort(controller, vlan, port=ofp.OFPP_ALL, priority=0):
if port == ofp.OFPP_ALL:
ports = sorted(config["port_map"].keys())
else:
ports = [port]
for port in ports:
tagged_match = ofp.match([
ofp.oxm.in_port(port),
ofp.oxm.vlan_vid(vlan | ofp.OFPVID_PRESENT)
])
request = ofp.message.flow_add(
table_id = VLAN_TABLE.table_id,
cookie = 0xdead,
match = tagged_match,
instructions = [
ofp.instruction.goto_table(MACTERM_TABLE.table_id),
# ofp.instruction.apply_actions(
# actions=[
# ofp.action.push_vlan(ethertype=0x8100), # DO NOT PUT THIS FOR OF-DPA 2.0 EA1 - seems to not matter for EA2
# ofp.action.set_field(ofp.oxm.vlan_vid( ofp.OFPVID_PRESENT | vlan))
# ]),
],
buffer_id = ofp.OFP_NO_BUFFER,
priority = priority)
logging.info("Inserting vlan rule allowing tagged vlan %d on port %d" % (vlan, port))
controller.message_send(request)
do_barrier(controller)
verify_no_errors(controller)
def installDefaultVlan(controller, vlan=DEFAULT_VLAN, port=ofp.OFPP_ALL, priority=0):
""" Insert a rule that maps all untagged traffic to vlan $vlan
In OFDPA, table 10 (the vlan table) requires that all traffic be
mapped to an internal vlan else the packets be dropped. This function
sets up a default vlan mapping all untagged traffic to an internal VLAN.
With OF-DPA, before you can insert a 'untagged to X' rule on a
port, you must first insert a 'X --> X' rule for the same port.
Further, the 'X --> X' rule must set ofp.OFPVID_PRESENT even
though 'X' is non-zero.
The 'controller' variable is self.controller from a test
"""
# OFDPA seems to be dumb and wants each port set individually
# Can't set all ports by using OFPP_ALL
if port == ofp.OFPP_ALL:
ports = sorted(config["port_map"].keys())
else:
ports = [port]
for port in ports:
# enable this vlan on this port before we can map untagged packets to the vlan
enableVlanOnPort(controller, vlan, port)
untagged_match = ofp.match([
ofp.oxm.in_port(port),
# OFDPA 2.0 says untagged is vlan_id=0, mask=ofp.OFPVID_PRESENT
ofp.oxm.vlan_vid_masked(0,ofp.OFPVID_PRESENT) # WTF OFDPA 2.0EA2 -- really!?
])
request = ofp.message.flow_add(
table_id = VLAN_TABLE.table_id,
cookie = 0xbeef,
match = untagged_match,
instructions = [
ofp.instruction.apply_actions(
actions=[
#ofp.action.push_vlan(ethertype=0x8100),
ofp.action.set_field(ofp.oxm.vlan_vid(ofp.OFPVID_PRESENT | vlan))
]),
ofp.instruction.goto_table(MACTERM_TABLE.table_id)
],
buffer_id = ofp.OFP_NO_BUFFER,
priority = priority)
logging.info("Inserting default vlan sending all untagged traffic to vlan %d on port %d" % (vlan, port))
controller.message_send(request)
do_barrier(controller)
verify_no_errors(controller)
_group_types = {
"L2 Interface": 0,
"L2 Rewrite" : 1,
"L3 Unicast" : 2,
"L2 Multicast" : 3,
"L2 Flood" : 4,
"L3 Interface" : 5,
"L3 Multicast": 6,
"L3 ECMP": 7,
"L2 Data Center Overlay": 8,
"MPLS Label" : 9,
"MPLS Forwarding" :10,
"L2 Unfiltered Interface": 11,
"L2 Loopback": 12,
}
def makeGroupID(groupType, local_id):
""" Group IDs in OF-DPA have rich meaning
@param groupType is a key in _group_types
@param local_id is an integer 0<= local_id < 2**27,
but it may have more semantic meaning depending on the
groupType
Read Section 4.3 of the OF-DPA manual on groups for
details
"""
if groupType not in _group_types:
raise KeyError("%s not a valid OF-DPA group type" % groupType)
if local_id < 0 or local_id >=134217728:
raise ValueError("local_id %d must be 0<= local_id < 2**27" % local_id)
return (_group_types[groupType] << 28) + local_id
def delete_all_recursive_groups(controller):
pass