1 Star 0 Fork 0

qzzhang / bmv2

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
runtime_CLI.py 86.08 KB
一键复制 编辑 原始数据 按行查看 历史
qz_zhang 提交于 2021-01-04 19:38 . commit
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407
#!/usr/bin/env python2
# Copyright 2013-present Barefoot Networks, Inc.
#
# 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.
#
#
# Antonin Bas (antonin@barefootnetworks.com)
#
#
import argparse
import cmd
from collections import Counter
import os
import sys
import struct
import json
from functools import wraps
import bmpy_utils as utils
from bm_runtime.standard import Standard
from bm_runtime.standard.ttypes import *
try:
from bm_runtime.simple_pre import SimplePre
except:
pass
try:
from bm_runtime.simple_pre_lag import SimplePreLAG
except:
pass
def enum(type_name, *sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
reverse = dict((value, key) for key, value in enums.iteritems())
@staticmethod
def to_str(x):
return reverse[x]
enums['to_str'] = to_str
@staticmethod
def from_str(x):
return enums[x]
enums['from_str'] = from_str
return type(type_name, (), enums)
PreType = enum('PreType', 'None', 'SimplePre', 'SimplePreLAG')
MeterType = enum('MeterType', 'packets', 'bytes')
TableType = enum('TableType', 'simple', 'indirect', 'indirect_ws')
ResType = enum('ResType', 'table', 'action_prof', 'action', 'meter_array',
'counter_array', 'register_array')
def bytes_to_string(byte_array):
form = 'B' * len(byte_array)
return struct.pack(form, *byte_array)
def table_error_name(x):
return TableOperationErrorCode._VALUES_TO_NAMES[x]
def get_parser():
class ActionToPreType(argparse.Action):
def __init__(self, option_strings, dest, nargs=None, **kwargs):
if nargs is not None:
raise ValueError("nargs not allowed")
super(ActionToPreType, self).__init__(option_strings, dest, **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
assert(type(values) is str)
setattr(namespace, self.dest, PreType.from_str(values))
parser = argparse.ArgumentParser(description='BM runtime CLI')
# One port == one device !!!! This is not a multidevice CLI
parser.add_argument('--thrift-port', help='Thrift server port for table updates',
type=int, action="store", default=9090)
parser.add_argument('--thrift-ip', help='Thrift IP address for table updates',
type=str, action="store", default='localhost')
parser.add_argument('--json', help='JSON description of P4 program',
type=str, action="store", required=False)
parser.add_argument('--pre', help='Packet Replication Engine used by target',
type=str, choices=['None', 'SimplePre', 'SimplePreLAG'],
default=PreType.SimplePre, action=ActionToPreType)
return parser
TABLES = {}
ACTION_PROFS = {}
ACTIONS = {}
METER_ARRAYS = {}
COUNTER_ARRAYS = {}
REGISTER_ARRAYS = {}
CUSTOM_CRC_CALCS = {}
# maps (object type, unique suffix) to object
SUFFIX_LOOKUP_MAP = {}
class MatchType:
EXACT = 0
LPM = 1
TERNARY = 2
VALID = 3
RANGE = 4
@staticmethod
def to_str(x):
return {0: "exact", 1: "lpm", 2: "ternary", 3: "valid", 4: "range"}[x]
@staticmethod
def from_str(x):
return {"exact": 0, "lpm": 1, "ternary": 2, "valid": 3, "range": 4}[x]
class Table:
def __init__(self, name, id_):
self.name = name
self.id_ = id_
self.match_type_ = None
self.actions = {}
self.key = []
self.default_action = None
self.type_ = None
self.support_timeout = False
self.action_prof = None
TABLES[name] = self
def num_key_fields(self):
return len(self.key)
def key_str(self):
return ",\t".join([name + "(" + MatchType.to_str(t) + ", " + str(bw) + ")" for name, t, bw in self.key])
def table_str(self):
ap_str = "implementation={}".format(
"None" if not self.action_prof else self.action_prof.name)
return "{0:30} [{1}, mk={2}]".format(self.name, ap_str, self.key_str())
def get_action(self, action_name):
key = ResType.action, action_name
action = SUFFIX_LOOKUP_MAP.get(key, None)
if action is None or action.name not in self.actions:
return None
return action
class ActionProf:
def __init__(self, name, id_):
self.name = name
self.id_ = id_
self.with_selection = False
self.actions = {}
self.ref_cnt = 0
ACTION_PROFS[name] = self
def action_prof_str(self):
return "{0:30} [{1}]".format(self.name, self.with_selection)
def get_action(self, action_name):
key = ResType.action, action_name
action = SUFFIX_LOOKUP_MAP.get(key, None)
if action is None or action.name not in self.actions:
return None
return action
class Action:
def __init__(self, name, id_):
self.name = name
self.id_ = id_
self.runtime_data = []
ACTIONS[name] = self
def num_params(self):
return len(self.runtime_data)
def runtime_data_str(self):
return ",\t".join([name + "(" + str(bw) + ")" for name, bw in self.runtime_data])
def action_str(self):
return "{0:30} [{1}]".format(self.name, self.runtime_data_str())
class MeterArray:
def __init__(self, name, id_):
self.name = name
self.id_ = id_
self.type_ = None
self.is_direct = None
self.size = None
self.binding = None
self.rate_count = None
METER_ARRAYS[name] = self
def meter_str(self):
return "{0:30} [{1}, {2}]".format(self.name, self.size,
MeterType.to_str(self.type_))
class CounterArray:
def __init__(self, name, id_):
self.name = name
self.id_ = id_
self.is_direct = None
self.size = None
self.binding = None
COUNTER_ARRAYS[name] = self
def counter_str(self):
return "{0:30} [{1}]".format(self.name, self.size)
class RegisterArray:
def __init__(self, name, id_):
self.name = name
self.id_ = id_
self.width = None
self.size = None
REGISTER_ARRAYS[name] = self
def register_str(self):
return "{0:30} [{1}]".format(self.name, self.size)
def reset_config():
TABLES.clear()
ACTION_PROFS.clear()
ACTIONS.clear()
METER_ARRAYS.clear()
COUNTER_ARRAYS.clear()
REGISTER_ARRAYS.clear()
CUSTOM_CRC_CALCS.clear()
SUFFIX_LOOKUP_MAP.clear()
def load_json_str(json_str):
def get_header_type(header_name, j_headers):
for h in j_headers:
if h["name"] == header_name:
return h["header_type"]
assert(0)
def get_field_bitwidth(header_type, field_name, j_header_types):
for h in j_header_types:
if h["name"] != header_type: continue
for t in h["fields"]:
# t can have a third element (field signedness)
f, bw = t[0], t[1]
if f == field_name:
return bw
assert(0)
reset_config()
json_ = json.loads(json_str)
def get_json_key(key):
return json_.get(key, [])
for j_action in get_json_key("actions"):
action = Action(j_action["name"], j_action["id"])
for j_param in j_action["runtime_data"]:
action.runtime_data += [(j_param["name"], j_param["bitwidth"])]
for j_pipeline in get_json_key("pipelines"):
if "action_profiles" in j_pipeline: # new JSON format
for j_aprof in j_pipeline["action_profiles"]:
action_prof = ActionProf(j_aprof["name"], j_aprof["id"])
action_prof.with_selection = "selector" in j_aprof
for j_table in j_pipeline["tables"]:
table = Table(j_table["name"], j_table["id"])
table.match_type = MatchType.from_str(j_table["match_type"])
table.type_ = TableType.from_str(j_table["type"])
table.support_timeout = j_table["support_timeout"]
for action in j_table["actions"]:
table.actions[action] = ACTIONS[action]
if table.type_ in {TableType.indirect, TableType.indirect_ws}:
if "action_profile" in j_table:
action_prof = ACTION_PROFS[j_table["action_profile"]]
else: # for backward compatibility
assert("act_prof_name" in j_table)
action_prof = ActionProf(j_table["act_prof_name"],
table.id_)
action_prof.with_selection = "selector" in j_table
action_prof.actions.update(table.actions)
action_prof.ref_cnt += 1
table.action_prof = action_prof
for j_key in j_table["key"]:
target = j_key["target"]
match_type = MatchType.from_str(j_key["match_type"])
if match_type == MatchType.VALID:
field_name = target + "_valid"
bitwidth = 1
elif target[1] == "$valid$":
field_name = target[0] + "_valid"
bitwidth = 1
else:
field_name = ".".join(target)
header_type = get_header_type(target[0],
json_["headers"])
bitwidth = get_field_bitwidth(header_type, target[1],
json_["header_types"])
table.key += [(field_name, match_type, bitwidth)]
for j_meter in get_json_key("meter_arrays"):
meter_array = MeterArray(j_meter["name"], j_meter["id"])
if "is_direct" in j_meter and j_meter["is_direct"]:
meter_array.is_direct = True
meter_array.binding = j_meter["binding"]
else:
meter_array.is_direct = False
meter_array.size = j_meter["size"]
meter_array.type_ = MeterType.from_str(j_meter["type"])
meter_array.rate_count = j_meter["rate_count"]
for j_counter in get_json_key("counter_arrays"):
counter_array = CounterArray(j_counter["name"], j_counter["id"])
counter_array.is_direct = j_counter["is_direct"]
if counter_array.is_direct:
counter_array.binding = j_counter["binding"]
else:
counter_array.size = j_counter["size"]
for j_register in get_json_key("register_arrays"):
register_array = RegisterArray(j_register["name"], j_register["id"])
register_array.size = j_register["size"]
register_array.width = j_register["bitwidth"]
for j_calc in get_json_key("calculations"):
calc_name = j_calc["name"]
if j_calc["algo"] == "crc16_custom":
CUSTOM_CRC_CALCS[calc_name] = 16
elif j_calc["algo"] == "crc32_custom":
CUSTOM_CRC_CALCS[calc_name] = 32
# Builds a dictionary mapping (object type, unique suffix) to the object
# (Table, Action, etc...). In P4_16 the object name is the fully-qualified
# name, which can be quite long, which is why we accept unique suffixes as
# valid identifiers.
# Auto-complete does not support suffixes, only the fully-qualified names,
# but that can be changed in the future if needed.
suffix_count = Counter()
for res_type, res_dict in [
(ResType.table, TABLES), (ResType.action_prof, ACTION_PROFS),
(ResType.action, ACTIONS), (ResType.meter_array, METER_ARRAYS),
(ResType.counter_array, COUNTER_ARRAYS),
(ResType.register_array, REGISTER_ARRAYS)]:
for name, res in res_dict.items():
suffix = None
for s in reversed(name.split('.')):
suffix = s if suffix is None else s + '.' + suffix
key = (res_type, suffix)
SUFFIX_LOOKUP_MAP[key] = res
suffix_count[key] += 1
for key, c in suffix_count.items():
if c > 1:
del SUFFIX_LOOKUP_MAP[key]
class UIn_Error(Exception):
def __init__(self, info=""):
self.info = info
def __str__(self):
return self.info
class UIn_ResourceError(UIn_Error):
def __init__(self, res_type, name):
self.res_type = res_type
self.name = name
def __str__(self):
return "Invalid %s name (%s)" % (self.res_type, self.name)
class UIn_MatchKeyError(UIn_Error):
def __init__(self, info=""):
self.info = info
def __str__(self):
return self.info
class UIn_RuntimeDataError(UIn_Error):
def __init__(self, info=""):
self.info = info
def __str__(self):
return self.info
class CLI_FormatExploreError(Exception):
def __init__(self):
pass
class UIn_BadParamError(UIn_Error):
def __init__(self, info=""):
self.info = info
def __str__(self):
return self.info
class UIn_BadIPv4Error(UIn_Error):
def __init__(self):
pass
class UIn_BadIPv6Error(UIn_Error):
def __init__(self):
pass
class UIn_BadMacError(UIn_Error):
def __init__(self):
pass
def ipv4Addr_to_bytes(addr):
if not '.' in addr:
raise CLI_FormatExploreError()
s = addr.split('.')
if len(s) != 4:
raise UIn_BadIPv4Error()
try:
return [int(b) for b in s]
except:
raise UIn_BadIPv4Error()
def macAddr_to_bytes(addr):
if not ':' in addr:
raise CLI_FormatExploreError()
s = addr.split(':')
if len(s) != 6:
raise UIn_BadMacError()
try:
return [int(b, 16) for b in s]
except:
raise UIn_BadMacError()
def ipv6Addr_to_bytes(addr):
from ipaddr import IPv6Address
if not ':' in addr:
raise CLI_FormatExploreError()
try:
ip = IPv6Address(addr)
except:
raise UIn_BadIPv6Error()
try:
return [ord(b) for b in ip.packed]
except:
raise UIn_BadIPv6Error()
def int_to_bytes(i, num):
byte_array = []
while i > 0:
byte_array.append(i % 256)
i = i / 256
num -= 1
if num < 0:
raise UIn_BadParamError("Parameter is too large")
while num > 0:
byte_array.append(0)
num -= 1
byte_array.reverse()
return byte_array
def parse_param(input_str, bitwidth):
if bitwidth == 32:
try:
return ipv4Addr_to_bytes(input_str)
except CLI_FormatExploreError:
pass
except UIn_BadIPv4Error:
raise UIn_BadParamError("Invalid IPv4 address")
elif bitwidth == 48:
try:
return macAddr_to_bytes(input_str)
except CLI_FormatExploreError:
pass
except UIn_BadMacError:
raise UIn_BadParamError("Invalid MAC address")
elif bitwidth == 128:
try:
return ipv6Addr_to_bytes(input_str)
except CLI_FormatExploreError:
pass
except UIn_BadIPv6Error:
raise UIn_BadParamError("Invalid IPv6 address")
try:
input_ = int(input_str, 0)
except:
raise UIn_BadParamError(
"Invalid input, could not cast to integer, try in hex with 0x prefix"
)
try:
return int_to_bytes(input_, (bitwidth + 7) / 8)
except UIn_BadParamError:
raise
def parse_runtime_data(action, params):
def parse_param_(field, bw):
try:
return parse_param(field, bw)
except UIn_BadParamError as e:
raise UIn_RuntimeDataError(
"Error while parsing %s - %s" % (field, e)
)
bitwidths = [bw for( _, bw) in action.runtime_data]
byte_array = []
for input_str, bitwidth in zip(params, bitwidths):
byte_array += [bytes_to_string(parse_param_(input_str, bitwidth))]
return byte_array
_match_types_mapping = {
MatchType.EXACT : BmMatchParamType.EXACT,
MatchType.LPM : BmMatchParamType.LPM,
MatchType.TERNARY : BmMatchParamType.TERNARY,
MatchType.VALID : BmMatchParamType.VALID,
MatchType.RANGE : BmMatchParamType.RANGE,
}
def parse_match_key(table, key_fields):
def parse_param_(field, bw):
try:
return parse_param(field, bw)
except UIn_BadParamError as e:
raise UIn_MatchKeyError(
"Error while parsing %s - %s" % (field, e)
)
params = []
match_types = [t for (_, t, _) in table.key]
bitwidths = [bw for (_, _, bw) in table.key]
for idx, field in enumerate(key_fields):
param_type = _match_types_mapping[match_types[idx]]
bw = bitwidths[idx]
if param_type == BmMatchParamType.EXACT:
key = bytes_to_string(parse_param_(field, bw))
param = BmMatchParam(type = param_type,
exact = BmMatchParamExact(key))
elif param_type == BmMatchParamType.LPM:
try:
prefix, length = field.split("/")
except ValueError:
raise UIn_MatchKeyError(
"Invalid LPM value {}, use '/' to separate prefix "
"and length".format(field))
key = bytes_to_string(parse_param_(prefix, bw))
param = BmMatchParam(type = param_type,
lpm = BmMatchParamLPM(key, int(length)))
elif param_type == BmMatchParamType.TERNARY:
try:
key, mask = field.split("&&&")
except ValueError:
raise UIn_MatchKeyError(
"Invalid ternary value {}, use '&&&' to separate key and "
"mask".format(field))
key = bytes_to_string(parse_param_(key, bw))
mask = bytes_to_string(parse_param_(mask, bw))
if len(mask) != len(key):
raise UIn_MatchKeyError(
"Key and mask have different lengths in expression %s" % field
)
param = BmMatchParam(type = param_type,
ternary = BmMatchParamTernary(key, mask))
elif param_type == BmMatchParamType.VALID:
key = bool(int(field))
param = BmMatchParam(type = param_type,
valid = BmMatchParamValid(key))
elif param_type == BmMatchParamType.RANGE:
try:
start, end = field.split("->")
except ValueError:
raise UIn_MatchKeyError(
"Invalid range value {}, use '->' to separate range start "
"and range end".format(field))
start = bytes_to_string(parse_param_(start, bw))
end = bytes_to_string(parse_param_(end, bw))
if len(start) != len(end):
raise UIn_MatchKeyError(
"start and end have different lengths in expression %s" % field
)
if start > end:
raise UIn_MatchKeyError(
"start is less than end in expression %s" % field
)
param = BmMatchParam(type = param_type,
range = BmMatchParamRange(start, end))
else:
assert(0)
params.append(param)
return params
def printable_byte_str(s):
return ":".join("{:02x}".format(ord(c)) for c in s)
def BmMatchParam_to_str(self):
return BmMatchParamType._VALUES_TO_NAMES[self.type] + "-" +\
(self.exact.to_str() if self.exact else "") +\
(self.lpm.to_str() if self.lpm else "") +\
(self.ternary.to_str() if self.ternary else "") +\
(self.valid.to_str() if self.valid else "") +\
(self.range.to_str() if self.range else "")
def BmMatchParamExact_to_str(self):
return printable_byte_str(self.key)
def BmMatchParamLPM_to_str(self):
return printable_byte_str(self.key) + "/" + str(self.prefix_length)
def BmMatchParamTernary_to_str(self):
return printable_byte_str(self.key) + " &&& " + printable_byte_str(self.mask)
def BmMatchParamValid_to_str(self):
return ""
def BmMatchParamRange_to_str(self):
return printable_byte_str(self.start) + " -> " + printable_byte_str(self.end_)
BmMatchParam.to_str = BmMatchParam_to_str
BmMatchParamExact.to_str = BmMatchParamExact_to_str
BmMatchParamLPM.to_str = BmMatchParamLPM_to_str
BmMatchParamTernary.to_str = BmMatchParamTernary_to_str
BmMatchParamValid.to_str = BmMatchParamValid_to_str
BmMatchParamRange.to_str = BmMatchParamRange_to_str
# services is [(service_name, client_class), ...]
def thrift_connect(thrift_ip, thrift_port, services):
return utils.thrift_connect(thrift_ip, thrift_port, services)
def handle_bad_input(f):
@wraps(f)
def handle(*args, **kwargs):
try:
return f(*args, **kwargs)
except UIn_MatchKeyError as e:
print "Invalid match key:", e
except UIn_RuntimeDataError as e:
print "Invalid runtime data:", e
except UIn_Error as e:
print "Error:", e
except InvalidTableOperation as e:
error = TableOperationErrorCode._VALUES_TO_NAMES[e.code]
print "Invalid table operation (%s)" % error
except InvalidCounterOperation as e:
error = CounterOperationErrorCode._VALUES_TO_NAMES[e.code]
print "Invalid counter operation (%s)" % error
except InvalidMeterOperation as e:
error = MeterOperationErrorCode._VALUES_TO_NAMES[e.code]
print "Invalid meter operation (%s)" % error
except InvalidRegisterOperation as e:
error = RegisterOperationErrorCode._VALUES_TO_NAMES[e.code]
print "Invalid register operation (%s)" % error
except InvalidLearnOperation as e:
error = LearnOperationErrorCode._VALUES_TO_NAMES[e.code]
print "Invalid learn operation (%s)" % error
except InvalidSwapOperation as e:
error = SwapOperationErrorCode._VALUES_TO_NAMES[e.code]
print "Invalid swap operation (%s)" % error
except InvalidDevMgrOperation as e:
error = DevMgrErrorCode._VALUES_TO_NAMES[e.code]
print "Invalid device manager operation (%s)" % error
except InvalidCrcOperation as e:
error = CrcErrorCode._VALUES_TO_NAMES[e.code]
print "Invalid crc operation (%s)" % error
return handle
def handle_bad_input_mc(f):
@wraps(f)
def handle(*args, **kwargs):
pre_type = args[0].pre_type
if pre_type == PreType.None:
return handle_bad_input(f)(*args, **kwargs)
EType = {
PreType.SimplePre : SimplePre.InvalidMcOperation,
PreType.SimplePreLAG : SimplePreLAG.InvalidMcOperation
}[pre_type]
Codes = {
PreType.SimplePre : SimplePre.McOperationErrorCode,
PreType.SimplePreLAG : SimplePreLAG.McOperationErrorCode
}[pre_type]
try:
return handle_bad_input(f)(*args, **kwargs)
except EType as e:
error = Codes._VALUES_TO_NAMES[e.code]
print "Invalid PRE operation (%s)" % error
return handle
def deprecated_act_prof(substitute, with_selection=False,
strictly_deprecated=True):
# need two levels here because our decorator takes arguments
def deprecated_act_prof_(f):
# not sure if this is the right place for it, if I want it to play nice
# with @wraps
if strictly_deprecated:
f.__doc__ = "[DEPRECATED!] " + f.__doc__
f.__doc__ += "\nUse '{}' instead".format(substitute)
@wraps(f)
def wrapper(obj, line):
substitute_fn = getattr(obj, "do_" + substitute)
args = line.split()
obj.at_least_n_args(args, 1)
table_name = args[0]
table = obj.get_res("table", table_name, ResType.table)
if with_selection:
obj.check_indirect_ws(table)
else:
obj.check_indirect(table)
assert(table.action_prof is not None)
assert(table.action_prof.ref_cnt > 0)
if strictly_deprecated and table.action_prof.ref_cnt > 1:
raise UIn_Error(
"Legacy command does not work with shared action profiles")
args[0] = table.action_prof.name
if strictly_deprecated:
# writing to stderr in case someone is parsing stdout
sys.stderr.write(
"This is a deprecated command, use '{}' instead\n".format(
substitute))
return substitute_fn(" ".join(args))
# we add the handle_bad_input decorator "programatically"
return handle_bad_input(wrapper)
return deprecated_act_prof_
# thrift does not support unsigned integers
def hex_to_i16(h):
x = int(h, 0)
if (x > 0xFFFF):
raise UIn_Error("Integer cannot fit within 16 bits")
if (x > 0x7FFF): x-= 0x10000
return x
def i16_to_hex(h):
x = int(h)
if (x & 0x8000): x+= 0x10000
return x
def hex_to_i32(h):
x = int(h, 0)
if (x > 0xFFFFFFFF):
raise UIn_Error("Integer cannot fit within 32 bits")
if (x > 0x7FFFFFFF): x-= 0x100000000
return x
def i32_to_hex(h):
x = int(h)
if (x & 0x80000000): x+= 0x100000000
return x
def parse_bool(s):
if s == "true" or s == "True":
return True
if s == "false" or s == "False":
return False
try:
s = int(s, 0)
return bool(s)
except:
pass
raise UIn_Error("Invalid bool parameter")
class RuntimeAPI(cmd.Cmd):
prompt = 'RuntimeCmd: '
intro = "Control utility for runtime P4 table manipulation"
@staticmethod
def get_thrift_services(pre_type):
services = [("standard", Standard.Client)]
if pre_type == PreType.SimplePre:
services += [("simple_pre", SimplePre.Client)]
elif pre_type == PreType.SimplePreLAG:
services += [("simple_pre_lag", SimplePreLAG.Client)]
else:
services += [(None, None)]
return services
def __init__(self, pre_type, standard_client, mc_client=None):
cmd.Cmd.__init__(self)
self.client = standard_client
self.mc_client = mc_client
self.pre_type = pre_type
def do_greet(self, line):
print "hello"
def do_EOF(self, line):
print
return True
def do_shell(self, line):
"Run a shell command"
output = os.popen(line).read()
print output
def get_res(self, type_name, name, res_type):
key = res_type, name
if key not in SUFFIX_LOOKUP_MAP:
raise UIn_ResourceError(type_name, name)
return SUFFIX_LOOKUP_MAP[key]
def at_least_n_args(self, args, n):
if len(args) < n:
raise UIn_Error("Insufficient number of args")
def exactly_n_args(self, args, n):
if len(args) != n:
raise UIn_Error(
"Wrong number of args, expected %d but got %d" % (n, len(args))
)
def _complete_res(self, array, text):
res = sorted(array.keys())
if not text:
return res
return [r for r in res if r.startswith(text)]
@handle_bad_input
def do_show_tables(self, line):
"List tables defined in the P4 program: show_tables"
self.exactly_n_args(line.split(), 0)
for table_name in sorted(TABLES):
print TABLES[table_name].table_str()
@handle_bad_input
def do_show_actions(self, line):
"List actions defined in the P4 program: show_actions"
self.exactly_n_args(line.split(), 0)
for action_name in sorted(ACTIONS):
print ACTIONS[action_name].action_str()
def _complete_tables(self, text):
return self._complete_res(TABLES, text)
def _complete_act_profs(self, text):
return self._complete_res(ACTION_PROFS, text)
@handle_bad_input
def do_table_show_actions(self, line):
"List one table's actions as per the P4 program: table_show_actions <table_name>"
args = line.split()
self.exactly_n_args(args, 1)
table_name = args[0]
table = self.get_res("table", table_name, ResType.table)
for action_name in sorted(table.actions):
print ACTIONS[action_name].action_str()
def complete_table_show_actions(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_table_info(self, line):
"Show info about a table: table_info <table_name>"
args = line.split()
self.exactly_n_args(args, 1)
table_name = args[0]
table = self.get_res("table", table_name, ResType.table)
print table.table_str()
print "*" * 80
for action_name in sorted(table.actions):
print ACTIONS[action_name].action_str()
def complete_table_info(self, text, line, start_index, end_index):
return self._complete_tables(text)
# used for tables but also for action profiles
def _complete_actions(self, text, table_name = None, res = TABLES):
if not table_name:
actions = sorted(ACTIONS.keys())
elif table_name not in res:
return []
actions = sorted(res[table_name].actions.keys())
if not text:
return actions
return [a for a in actions if a.startswith(text)]
def _complete_table_and_action(self, text, line):
tables = sorted(TABLES.keys())
args = line.split()
args_cnt = len(args)
if args_cnt == 1 and not text:
return self._complete_tables(text)
if args_cnt == 2 and text:
return self._complete_tables(text)
table_name = args[1]
if args_cnt == 2 and not text:
return self._complete_actions(text, table_name)
if args_cnt == 3 and text:
return self._complete_actions(text, table_name)
return []
def _complete_act_prof_and_action(self, text, line):
act_profs = sorted(ACTION_PROFS.keys())
args = line.split()
args_cnt = len(args)
if args_cnt == 1 and not text:
return self._complete_act_profs(text)
if args_cnt == 2 and text:
return self._complete_act_profs(text)
act_prof_name = args[1]
if args_cnt == 2 and not text:
return self._complete_actions(text, act_prof_name, ACTION_PROFS)
if args_cnt == 3 and text:
return self._complete_actions(text, act_prof_name, ACTION_PROFS)
return []
# for debugging
def print_set_default(self, table_name, action_name, runtime_data):
print "Setting default action of", table_name
print "{0:20} {1}".format("action:", action_name)
print "{0:20} {1}".format(
"runtime data:",
"\t".join(printable_byte_str(d) for d in runtime_data)
)
@handle_bad_input
def do_table_set_default(self, line):
"Set default action for a match table: table_set_default <table name> <action name> <action parameters>"
args = line.split()
self.at_least_n_args(args, 2)
table_name, action_name = args[0], args[1]
table = self.get_res("table", table_name, ResType.table)
action = table.get_action(action_name)
if action is None:
raise UIn_Error(
"Table %s has no action %s" % (table_name, action_name)
)
if len(args[2:]) != action.num_params():
raise UIn_Error(
"Action %s needs %d parameters" % (action_name, action.num_params())
)
runtime_data = parse_runtime_data(action, args[2:])
self.print_set_default(table_name, action_name, runtime_data)
self.client.bm_mt_set_default_action(0, table.name, action.name, runtime_data)
def complete_table_set_default(self, text, line, start_index, end_index):
return self._complete_table_and_action(text, line)
@handle_bad_input
def do_table_reset_default(self, line):
"Reset default entry for a match table: table_reset_default <table name>"
args = line.split()
self.exactly_n_args(args, 1)
table_name = args[0]
table = self.get_res("table", table_name, ResType.table)
self.client.bm_mt_reset_default_entry(0, table.name)
def complete_table_reset_default(self, text, line, start_index, end_index):
return self._complete_tables(text)
def parse_runtime_data(self, action, action_params):
if len(action_params) != action.num_params():
raise UIn_Error(
"Action %s needs %d parameters" % (action.name, action.num_params())
)
return parse_runtime_data(action, action_params)
# for debugging
def print_table_add(self, match_key, action_name, runtime_data):
print "{0:20} {1}".format(
"match key:",
"\t".join(d.to_str() for d in match_key)
)
print "{0:20} {1}".format("action:", action_name)
print "{0:20} {1}".format(
"runtime data:",
"\t".join(printable_byte_str(d) for d in runtime_data)
)
@handle_bad_input
def do_table_num_entries(self, line):
"Return the number of entries in a match table (direct or indirect): table_num_entries <table name>"
args = line.split()
self.exactly_n_args(args, 1)
table_name = args[0]
table = self.get_res("table", table_name, ResType.table)
print self.client.bm_mt_get_num_entries(0, table.name)
def complete_table_num_entries(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_table_clear(self, line):
"Clear all entries in a match table (direct or indirect), but not the default entry: table_clear <table name>"
args = line.split()
self.exactly_n_args(args, 1)
table_name = args[0]
table = self.get_res("table", table_name, ResType.table)
self.client.bm_mt_clear_entries(0, table.name, False)
def complete_table_clear(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_table_add(self, line):
"Add entry to a match table: table_add <table name> <action name> <match fields> => <action parameters> [priority]"
args = line.split()
self.at_least_n_args(args, 3)
table_name, action_name = args[0], args[1]
table = self.get_res("table", table_name, ResType.table)
action = table.get_action(action_name)
if action is None:
raise UIn_Error(
"Table %s has no action %s" % (table_name, action_name)
)
if table.match_type in {MatchType.TERNARY, MatchType.RANGE}:
try:
priority = int(args.pop(-1))
except:
raise UIn_Error(
"Table is ternary, but could not extract a valid priority from args"
)
else:
priority = 0
for idx, input_ in enumerate(args[2:]):
if input_ == "=>": break
idx += 2
match_key = args[2:idx]
action_params = args[idx+1:]
if len(match_key) != table.num_key_fields():
raise UIn_Error(
"Table %s needs %d key fields" % (table_name, table.num_key_fields())
)
runtime_data = self.parse_runtime_data(action, action_params)
match_key = parse_match_key(table, match_key)
print "Adding entry to", MatchType.to_str(table.match_type), "match table", table_name
# disable, maybe a verbose CLI option?
self.print_table_add(match_key, action_name, runtime_data)
entry_handle = self.client.bm_mt_add_entry(
0, table.name, match_key, action.name, runtime_data,
BmAddEntryOptions(priority = priority)
)
print "Entry has been added with handle", entry_handle
def complete_table_add(self, text, line, start_index, end_index):
return self._complete_table_and_action(text, line)
@handle_bad_input
def do_table_set_timeout(self, line):
"Set a timeout in ms for a given entry; the table has to support timeouts: table_set_timeout <table_name> <entry handle> <timeout (ms)>"
args = line.split()
self.exactly_n_args(args, 3)
table_name = args[0]
table = self.get_res("table", table_name, ResType.table)
if not table.support_timeout:
raise UIn_Error(
"Table {} does not support entry timeouts".format(table_name))
try:
entry_handle = int(args[1])
except:
raise UIn_Error("Bad format for entry handle")
try:
timeout_ms = int(args[2])
except:
raise UIn_Error("Bad format for timeout")
print "Setting a", timeout_ms, "ms timeout for entry", entry_handle
self.client.bm_mt_set_entry_ttl(0, table.name, entry_handle, timeout_ms)
def complete_table_set_timeout(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_table_modify(self, line):
"Add entry to a match table: table_modify <table name> <action name> <entry handle> [action parameters]"
args = line.split()
self.at_least_n_args(args, 3)
table_name, action_name = args[0], args[1]
table = self.get_res("table", table_name, ResType.table)
action = table.get_action(action_name)
if action is None:
raise UIn_Error(
"Table %s has no action %s" % (table_name, action_name)
)
try:
entry_handle = int(args[2])
except:
raise UIn_Error("Bad format for entry handle")
action_params = args[3:]
if args[3] == "=>":
# be more tolerant
action_params = args[4:]
runtime_data = self.parse_runtime_data(action, action_params)
print "Modifying entry", entry_handle, "for", MatchType.to_str(table.match_type), "match table", table_name
entry_handle = self.client.bm_mt_modify_entry(
0, table.name, entry_handle, action.name, runtime_data
)
def complete_table_modify(self, text, line, start_index, end_index):
return self._complete_table_and_action(text, line)
@handle_bad_input
def do_table_delete(self, line):
"Delete entry from a match table: table_delete <table name> <entry handle>"
args = line.split()
self.exactly_n_args(args, 2)
table_name = args[0]
table = self.get_res("table", table_name, ResType.table)
try:
entry_handle = int(args[1])
except:
raise UIn_Error("Bad format for entry handle")
print "Deleting entry", entry_handle, "from", table_name
self.client.bm_mt_delete_entry(0, table.name, entry_handle)
def complete_table_delete(self, text, line, start_index, end_index):
return self._complete_tables(text)
def check_indirect(self, table):
if table.type_ not in {TableType.indirect, TableType.indirect_ws}:
raise UIn_Error("Cannot run this command on non-indirect table")
def check_indirect_ws(self, table):
if table.type_ != TableType.indirect_ws:
raise UIn_Error(
"Cannot run this command on non-indirect table,"\
" or on indirect table with no selector")
def check_act_prof_ws(self, act_prof):
if not act_prof.with_selection:
raise UIn_Error(
"Cannot run this command on an action profile without selector")
@handle_bad_input
def do_act_prof_create_member(self, line):
"Add a member to an action profile: act_prof_create_member <action profile name> <action_name> [action parameters]"
args = line.split()
self.at_least_n_args(args, 2)
act_prof_name, action_name = args[0], args[1]
act_prof = self.get_res("action profile", act_prof_name,
ResType.action_prof)
action = act_prof.get_action(action_name)
if action is None:
raise UIn_Error("Action profile '{}' has no action '{}'".format(
act_prof_name, action_name))
action_params = args[2:]
runtime_data = self.parse_runtime_data(action, action_params)
mbr_handle = self.client.bm_mt_act_prof_add_member(
0, act_prof.name, action.name, runtime_data)
print "Member has been created with handle", mbr_handle
def complete_act_prof_create_member(self, text, line, start_index, end_index):
return self._complete_act_prof_and_action(text, line)
@deprecated_act_prof("act_prof_create_member")
def do_table_indirect_create_member(self, line):
"Add a member to an indirect match table: table_indirect_create_member <table name> <action_name> [action parameters]"
pass
def complete_table_indirect_create_member(self, text, line, start_index, end_index):
return self._complete_table_and_action(text, line)
@handle_bad_input
def do_act_prof_delete_member(self, line):
"Delete a member in an action profile: act_prof_delete_member <action profile name> <member handle>"
args = line.split()
self.exactly_n_args(args, 2)
act_prof_name, action_name = args[0], args[1]
act_prof = self.get_res("action profile", act_prof_name,
ResType.action_prof)
try:
mbr_handle = int(args[1])
except:
raise UIn_Error("Bad format for member handle")
self.client.bm_mt_act_prof_delete_member(0, act_prof.name, mbr_handle)
def complete_act_prof_delete_member(self, text, line, start_index, end_index):
return self._complete_act_profs(text)
@deprecated_act_prof("act_prof_delete_member")
def do_table_indirect_delete_member(self, line):
"Delete a member in an indirect match table: table_indirect_delete_member <table name> <member handle>"
pass
def complete_table_indirect_delete_member(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_act_prof_modify_member(self, line):
"Modify member in an action profile: act_prof_modify_member <action profile name> <action_name> <member_handle> [action parameters]"
args = line.split()
self.at_least_n_args(args, 3)
act_prof_name, action_name = args[0], args[1]
act_prof = self.get_res("action profile", act_prof_name,
ResType.action_prof)
action = act_prof.get_action(action_name)
if action is None:
raise UIn_Error("Action profile '{}' has no action '{}'".format(
act_prof_name, action_name))
try:
mbr_handle = int(args[2])
except:
raise UIn_Error("Bad format for member handle")
action_params = args[3:]
if args[3] == "=>":
# be more tolerant
action_params = args[4:]
runtime_data = self.parse_runtime_data(action, action_params)
mbr_handle = self.client.bm_mt_act_prof_modify_member(
0, act_prof.name, mbr_handle, action.name, runtime_data)
def complete_act_prof_modify_member(self, text, line, start_index, end_index):
return self._complete_act_prof_and_action(text, line)
@deprecated_act_prof("act_prof_modify_member")
def do_table_indirect_modify_member(self, line):
"Modify member in an indirect match table: table_indirect_modify_member <table name> <action_name> <member_handle> [action parameters]"
pass
def complete_table_indirect_modify_member(self, text, line, start_index, end_index):
return self._complete_table_and_action(text, line)
def indirect_add_common(self, line, ws=False):
args = line.split()
self.at_least_n_args(args, 2)
table_name = args[0]
table = self.get_res("table", table_name, ResType.table)
if ws:
self.check_indirect_ws(table)
else:
self.check_indirect(table)
if table.match_type in {MatchType.TERNARY, MatchType.RANGE}:
try:
priority = int(args.pop(-1))
except:
raise UIn_Error(
"Table is ternary, but could not extract a valid priority from args"
)
else:
priority = 0
for idx, input_ in enumerate(args[1:]):
if input_ == "=>": break
idx += 1
match_key = args[1:idx]
if len(args) != (idx + 2):
raise UIn_Error("Invalid arguments, could not find handle")
handle = args[idx+1]
try:
handle = int(handle)
except:
raise UIn_Error("Bad format for handle")
match_key = parse_match_key(table, match_key)
print "Adding entry to indirect match table", table.name
return table.name, match_key, handle, BmAddEntryOptions(priority = priority)
@handle_bad_input
def do_table_indirect_add(self, line):
"Add entry to an indirect match table: table_indirect_add <table name> <match fields> => <member handle> [priority]"
table_name, match_key, handle, options = self.indirect_add_common(line)
entry_handle = self.client.bm_mt_indirect_add_entry(
0, table_name, match_key, handle, options
)
print "Entry has been added with handle", entry_handle
def complete_table_indirect_add(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_table_indirect_add_with_group(self, line):
"Add entry to an indirect match table: table_indirect_add <table name> <match fields> => <group handle> [priority]"
table_name, match_key, handle, options = self.indirect_add_common(line, ws=True)
entry_handle = self.client.bm_mt_indirect_ws_add_entry(
0, table_name, match_key, handle, options
)
print "Entry has been added with handle", entry_handle
def complete_table_indirect_add_with_group(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_table_indirect_delete(self, line):
"Delete entry from an indirect match table: table_indirect_delete <table name> <entry handle>"
args = line.split()
self.exactly_n_args(args, 2)
table_name = args[0]
table = self.get_res("table", table_name, ResType.table)
self.check_indirect(table)
try:
entry_handle = int(args[1])
except:
raise UIn_Error("Bad format for entry handle")
print "Deleting entry", entry_handle, "from", table_name
self.client.bm_mt_indirect_delete_entry(0, table.name, entry_handle)
def complete_table_indirect_delete(self, text, line, start_index, end_index):
return self._complete_tables(text)
def indirect_set_default_common(self, line, ws=False):
args = line.split()
self.exactly_n_args(args, 2)
table_name = args[0]
table = self.get_res("table", table_name, ResType.table)
if ws:
self.check_indirect_ws(table)
else:
self.check_indirect(table)
try:
handle = int(args[1])
except:
raise UIn_Error("Bad format for handle")
return table.name, handle
@handle_bad_input
def do_table_indirect_set_default(self, line):
"Set default member for indirect match table: table_indirect_set_default <table name> <member handle>"
table_name, handle = self.indirect_set_default_common(line)
self.client.bm_mt_indirect_set_default_member(0, table_name, handle)
def complete_table_indirect_set_default(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_table_indirect_set_default_with_group(self, line):
"Set default group for indirect match table: table_indirect_set_default <table name> <group handle>"
table_name, handle = self.indirect_set_default_common(line, ws=True)
self.client.bm_mt_indirect_ws_set_default_group(0, table_name, handle)
def complete_table_indirect_set_default_with_group(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_table_indirect_reset_default(self, line):
"Reset default entry for indirect match table: table_indirect_reset_default <table name>"
args = line.split()
self.exactly_n_args(args, 1)
table_name = args[0]
table = self.get_res("table", table_name, ResType.table)
self.client.bm_mt_indirect_reset_default_entry(0, table.name)
def complete_table_indirect_reset_default(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_act_prof_create_group(self, line):
"Add a group to an action pofile: act_prof_create_group <action profile name>"
args = line.split()
self.exactly_n_args(args, 1)
act_prof_name = args[0]
act_prof = self.get_res("action profile", act_prof_name,
ResType.action_prof)
self.check_act_prof_ws(act_prof)
grp_handle = self.client.bm_mt_act_prof_create_group(0, act_prof.name)
print "Group has been created with handle", grp_handle
def complete_act_prof_create_group(self, text, line, start_index, end_index):
return self._complete_act_profs(text)
@deprecated_act_prof("act_prof_create_group", with_selection=True)
def do_table_indirect_create_group(self, line):
"Add a group to an indirect match table: table_indirect_create_group <table name>"
pass
def complete_table_indirect_create_group(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_act_prof_delete_group(self, line):
"Delete a group from an action profile: act_prof_delete_group <action profile name> <group handle>"
args = line.split()
self.exactly_n_args(args, 2)
act_prof_name = args[0]
act_prof = self.get_res("action profile", act_prof_name,
ResType.action_prof)
self.check_act_prof_ws(act_prof)
try:
grp_handle = int(args[1])
except:
raise UIn_Error("Bad format for group handle")
self.client.bm_mt_act_prof_delete_group(0, act_prof.name, grp_handle)
def complete_act_prof_delete_group(self, text, line, start_index, end_index):
return self._complete_act_profs(text)
@deprecated_act_prof("act_prof_delete_group", with_selection=True)
def do_table_indirect_delete_group(self, line):
"Delete a group: table_indirect_delete_group <table name> <group handle>"
pass
def complete_table_indirect_delete_group(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_act_prof_add_member_to_group(self, line):
"Add member to group in an action profile: act_prof_add_member_to_group <action profile name> <member handle> <group handle>"
args = line.split()
self.exactly_n_args(args, 3)
act_prof_name = args[0]
act_prof = self.get_res("action profile", act_prof_name,
ResType.action_prof)
self.check_act_prof_ws(act_prof)
try:
mbr_handle = int(args[1])
except:
raise UIn_Error("Bad format for member handle")
try:
grp_handle = int(args[2])
except:
raise UIn_Error("Bad format for group handle")
self.client.bm_mt_act_prof_add_member_to_group(
0, act_prof.name, mbr_handle, grp_handle)
def complete_act_prof_add_member_to_group(self, text, line, start_index, end_index):
return self._complete_act_profs(text)
@deprecated_act_prof("act_prof_add_member_to_group", with_selection=True)
def do_table_indirect_add_member_to_group(self, line):
"Add member to group: table_indirect_add_member_to_group <table name> <member handle> <group handle>"
pass
def complete_table_indirect_add_member_to_group(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_act_prof_remove_member_from_group(self, line):
"Remove member from group in action profile: act_prof_remove_member_from_group <action profile name> <member handle> <group handle>"
args = line.split()
self.exactly_n_args(args, 3)
act_prof_name = args[0]
act_prof = self.get_res("action profile", act_prof_name,
ResType.action_prof)
self.check_act_prof_ws(act_prof)
try:
mbr_handle = int(args[1])
except:
raise UIn_Error("Bad format for member handle")
try:
grp_handle = int(args[2])
except:
raise UIn_Error("Bad format for group handle")
self.client.bm_mt_act_prof_remove_member_from_group(
0, act_prof.name, mbr_handle, grp_handle)
def complete_act_prof_remove_member_from_group(self, text, line, start_index, end_index):
return self._complete_act_profs(text)
@deprecated_act_prof("act_prof_remove_member_from_group", with_selection=True)
def do_table_indirect_remove_member_from_group(self, line):
"Remove member from group: table_indirect_remove_member_from_group <table name> <member handle> <group handle>"
pass
def complete_table_indirect_remove_member_from_group(self, text, line, start_index, end_index):
return self._complete_tables(text)
def check_has_pre(self):
if self.pre_type == PreType.None:
raise UIn_Error(
"Cannot execute this command without packet replication engine"
)
def get_mgrp(self, s):
try:
return int(s)
except:
raise UIn_Error("Bad format for multicast group id")
@handle_bad_input_mc
def do_mc_mgrp_create(self, line):
"Create multicast group: mc_mgrp_create <group id>"
self.check_has_pre()
args = line.split()
self.exactly_n_args(args, 1)
mgrp = self.get_mgrp(args[0])
print "Creating multicast group", mgrp
mgrp_hdl = self.mc_client.bm_mc_mgrp_create(0, mgrp)
assert(mgrp == mgrp_hdl)
@handle_bad_input_mc
def do_mc_mgrp_destroy(self, line):
"Destroy multicast group: mc_mgrp_destroy <group id>"
self.check_has_pre()
args = line.split()
self.exactly_n_args(args, 1)
mgrp = self.get_mgrp(args[0])
print "Destroying multicast group", mgrp
self.mc_client.bm_mc_mgrp_destroy(0, mgrp)
def ports_to_port_map_str(self, ports, description="port"):
last_port_num = 0
port_map_str = ""
ports_int = []
for port_num_str in ports:
try:
port_num = int(port_num_str)
except:
raise UIn_Error("'%s' is not a valid %s number"
"" % (port_num_str, description))
if port_num < 0:
raise UIn_Error("'%s' is not a valid %s number"
"" % (port_num_str, description))
ports_int.append(port_num)
ports_int.sort()
for port_num in ports_int:
if port_num == (last_port_num - 1):
raise UIn_Error("Found duplicate %s number '%s'"
"" % (description, port_num))
port_map_str += "0" * (port_num - last_port_num) + "1"
last_port_num = port_num + 1
return port_map_str[::-1]
def parse_ports_and_lags(self, args):
ports = []
i = 1
while (i < len(args) and args[i] != '|'):
ports.append(args[i])
i += 1
port_map_str = self.ports_to_port_map_str(ports)
if self.pre_type == PreType.SimplePreLAG:
i += 1
lags = [] if i == len(args) else args[i:]
lag_map_str = self.ports_to_port_map_str(lags, description="lag")
else:
lag_map_str = None
return port_map_str, lag_map_str
@handle_bad_input_mc
def do_mc_node_create(self, line):
"Create multicast node: mc_node_create <rid> <space-separated port list> [ | <space-separated lag list> ]"
self.check_has_pre()
args = line.split()
self.at_least_n_args(args, 1)
try:
rid = int(args[0])
except:
raise UIn_Error("Bad format for rid")
port_map_str, lag_map_str = self.parse_ports_and_lags(args)
if self.pre_type == PreType.SimplePre:
print "Creating node with rid", rid, "and with port map", port_map_str
l1_hdl = self.mc_client.bm_mc_node_create(0, rid, port_map_str)
else:
print "Creating node with rid", rid, ", port map", port_map_str, "and lag map", lag_map_str
l1_hdl = self.mc_client.bm_mc_node_create(0, rid, port_map_str, lag_map_str)
print "node was created with handle", l1_hdl
def get_node_handle(self, s):
try:
return int(s)
except:
raise UIn_Error("Bad format for node handle")
@handle_bad_input_mc
def do_mc_node_update(self, line):
"Update multicast node: mc_node_update <node handle> <space-separated port list> [ | <space-separated lag list> ]"
self.check_has_pre()
args = line.split()
self.at_least_n_args(args, 2)
l1_hdl = self.get_node_handle(args[0])
port_map_str, lag_map_str = self.parse_ports_and_lags(args)
if self.pre_type == PreType.SimplePre:
print "Updating node", l1_hdl, "with port map", port_map_str
self.mc_client.bm_mc_node_update(0, l1_hdl, port_map_str)
else:
print "Updating node", l1_hdl, "with port map", port_map_str, "and lag map", lag_map_str
self.mc_client.bm_mc_node_update(0, l1_hdl, port_map_str, lag_map_str)
@handle_bad_input_mc
def do_mc_node_associate(self, line):
"Associate node to multicast group: mc_node_associate <group handle> <node handle>"
self.check_has_pre()
args = line.split()
self.exactly_n_args(args, 2)
mgrp = self.get_mgrp(args[0])
l1_hdl = self.get_node_handle(args[1])
print "Associating node", l1_hdl, "to multicast group", mgrp
self.mc_client.bm_mc_node_associate(0, mgrp, l1_hdl)
@handle_bad_input_mc
def do_mc_node_dissociate(self, line):
"Dissociate node from multicast group: mc_node_associate <group handle> <node handle>"
self.check_has_pre()
args = line.split()
self.exactly_n_args(args, 2)
mgrp = self.get_mgrp(args[0])
l1_hdl = self.get_node_handle(args[1])
print "Dissociating node", l1_hdl, "from multicast group", mgrp
self.mc_client.bm_mc_node_dissociate(0, mgrp, l1_hdl)
@handle_bad_input_mc
def do_mc_node_destroy(self, line):
"Destroy multicast node: mc_node_destroy <node handle>"
self.check_has_pre()
args = line.split()
self.exactly_n_args(args, 1)
l1_hdl = int(line.split()[0])
print "Destroying node", l1_hdl
self.mc_client.bm_mc_node_destroy(0, l1_hdl)
@handle_bad_input_mc
def do_mc_set_lag_membership(self, line):
"Set lag membership of port list: mc_set_lag_membership <lag index> <space-separated port list>"
self.check_has_pre()
if self.pre_type != PreType.SimplePreLAG:
raise UIn_Error(
"Cannot execute this command with this type of PRE,"\
" SimplePreLAG is required"
)
args = line.split()
self.at_least_n_args(args, 2)
try:
lag_index = int(args[0])
except:
raise UIn_Error("Bad format for lag index")
port_map_str = self.ports_to_port_map_str(args[1:], description="lag")
print "Setting lag membership:", lag_index, "<-", port_map_str
self.mc_client.bm_mc_set_lag_membership(0, lag_index, port_map_str)
@handle_bad_input_mc
def do_mc_dump(self, line):
"Dump entries in multicast engine"
self.check_has_pre()
json_dump = self.mc_client.bm_mc_get_entries(0)
try:
mc_json = json.loads(json_dump)
except:
print "Exception when retrieving MC entries"
return
l1_handles = {}
for h in mc_json["l1_handles"]:
l1_handles[h["handle"]] = (h["rid"], h["l2_handle"])
l2_handles = {}
for h in mc_json["l2_handles"]:
l2_handles[h["handle"]] = (h["ports"], h["lags"])
print "=========="
print "MC ENTRIES"
for mgrp in mc_json["mgrps"]:
print "**********"
mgid = mgrp["id"]
print "mgrp({})".format(mgid)
for L1h in mgrp["l1_handles"]:
rid, L2h = l1_handles[L1h]
print " -> (L1h={}, rid={})".format(L1h, rid),
ports, lags = l2_handles[L2h]
print "-> (ports=[{}], lags=[{}])".format(
", ".join([str(p) for p in ports]),
", ".join([str(l) for l in lags]))
print "=========="
print "LAGS"
if "lags" in mc_json:
for lag in mc_json["lags"]:
print "lag({})".format(lag["id"]),
print "-> ports=[{}]".format(", ".join([str(p) for p in ports]))
else:
print "None for this PRE type"
print "=========="
@handle_bad_input
def do_load_new_config_file(self, line):
"Load new json config: load_new_config_file <path to .json file>"
args = line.split()
self.exactly_n_args(args, 1)
filename = args[0]
if not os.path.isfile(filename):
raise UIn_Error("Not a valid filename")
print "Loading new Json config"
with open(filename, 'r') as f:
json_str = f.read()
try:
json.loads(json_str)
except:
raise UIn_Error("Not a valid JSON file")
self.client.bm_load_new_config(json_str)
load_json_str(json_str)
@handle_bad_input
def do_swap_configs(self, line):
"Swap the 2 existing configs, need to have called load_new_config_file before"
print "Swapping configs"
self.client.bm_swap_configs()
@handle_bad_input
def do_meter_array_set_rates(self, line):
"Configure rates for an entire meter array: meter_array_set_rates <name> <rate_1>:<burst_1> <rate_2>:<burst_2> ..."
args = line.split()
self.at_least_n_args(args, 1)
meter_name = args[0]
meter = self.get_res("meter", meter_name, ResType.meter_array)
rates = args[1:]
if len(rates) != meter.rate_count:
raise UIn_Error(
"Invalid number of rates, expected %d but got %d"\
% (meter.rate_count, len(rates))
)
new_rates = []
for rate in rates:
try:
r, b = rate.split(':')
r = float(r)
b = int(b)
new_rates.append(BmMeterRateConfig(r, b))
except:
raise UIn_Error("Error while parsing rates")
self.client.bm_meter_array_set_rates(0, meter.name, new_rates)
def complete_meter_array_set_rates(self, text, line, start_index, end_index):
return self._complete_meters(text)
@handle_bad_input
def do_meter_set_rates(self, line):
"Configure rates for a meter: meter_set_rates <name> <index> <rate_1>:<burst_1> <rate_2>:<burst_2> ...\nRate uses units/microsecond and burst uses units where units is bytes or packets"
args = line.split()
self.at_least_n_args(args, 2)
meter_name = args[0]
meter = self.get_res("meter", meter_name, ResType.meter_array)
try:
index = int(args[1])
except:
raise UIn_Error("Bad format for index")
rates = args[2:]
if len(rates) != meter.rate_count:
raise UIn_Error(
"Invalid number of rates, expected %d but got %d"\
% (meter.rate_count, len(rates))
)
new_rates = []
for rate in rates:
try:
r, b = rate.split(':')
r = float(r)
b = int(b)
new_rates.append(BmMeterRateConfig(r, b))
except:
raise UIn_Error("Error while parsing rates")
if meter.is_direct:
table_name = meter.binding
self.client.bm_mt_set_meter_rates(0, table_name, index, new_rates)
else:
self.client.bm_meter_set_rates(0, meter.name, index, new_rates)
def complete_meter_set_rates(self, text, line, start_index, end_index):
return self._complete_meters(text)
@handle_bad_input
def do_meter_get_rates(self, line):
"Retrieve rates for a meter: meter_get_rates <name> <index>"
args = line.split()
self.exactly_n_args(args, 2)
meter_name = args[0]
meter = self.get_res("meter", meter_name, ResType.meter_array)
try:
index = int(args[1])
except:
raise UIn_Error("Bad format for index")
# meter.rate_count
if meter.is_direct:
table_name = meter.binding
rates = self.client.bm_mt_get_meter_rates(0, table_name, index)
else:
rates = self.client.bm_meter_get_rates(0, meter.name, index)
if len(rates) != meter.rate_count:
print "WARNING: expected", meter.rate_count, "rates",
print "but only received", len(rates)
for idx, rate in enumerate(rates):
print "{}: info rate = {}, burst size = {}".format(
idx, rate.units_per_micros, rate.burst_size)
def complete_meter_get_rates(self, text, line, start_index, end_index):
return self._complete_meters(text)
def _complete_meters(self, text):
return self._complete_res(METER_ARRAYS, text)
@handle_bad_input
def do_counter_read(self, line):
"Read counter value: counter_read <name> <index>"
args = line.split()
self.exactly_n_args(args, 2)
counter_name = args[0]
counter = self.get_res("counter", counter_name, ResType.counter_array)
index = args[1]
try:
index = int(index)
except:
raise UIn_Error("Bad format for index")
if counter.is_direct:
table_name = counter.binding
print "this is the direct counter for table", table_name
# index = index & 0xffffffff
value = self.client.bm_mt_read_counter(0, table_name, index)
else:
value = self.client.bm_counter_read(0, counter.name, index)
print "%s[%d]= " % (counter_name, index), value
def complete_counter_read(self, text, line, start_index, end_index):
return self._complete_counters(text)
@handle_bad_input
def do_counter_write(self, line):
"Write counter value: counter_write <name> <index> <packets> <bytes>"
args = line.split()
self.exactly_n_args(args, 4)
counter_name = args[0]
counter = self.get_res("counter", counter_name, ResType.counter_array)
index = args[1]
pkts = args[2]
byts = args[3]
try:
index = int(index)
except:
raise UIn_Error("Bad format for index")
try:
pkts = int(pkts)
except:
raise UIn_Error("Bad format for packets")
try:
byts = int(byts)
except:
raise UIn_Error("Bad format for bytes")
if counter.is_direct:
table_name = counter.binding
print "writing to direct counter for table", table_name
value = self.client.bm_mt_write_counter(0, table_name, index, BmCounterValue(packets=pkts, bytes = byts))
else:
self.client.bm_counter_write(0, counter_name, index, BmCounterValue(packets=pkts, bytes = byts))
print "%s[%d] has been updated" % (counter_name, index)
def complete_counter_write(self, text, line, start_index, end_index):
return self._complete_counters(text)
@handle_bad_input
def do_counter_reset(self, line):
"Reset counter: counter_reset <name>"
args = line.split()
self.exactly_n_args(args, 1)
counter_name = args[0]
counter = self.get_res("counter", counter_name, ResType.counter_array)
if counter.is_direct:
table_name = counter.binding
print "this is the direct counter for table", table_name
value = self.client.bm_mt_reset_counters(0, table_name)
else:
value = self.client.bm_counter_reset_all(0, counter.name)
def complete_counter_reset(self, text, line, start_index, end_index):
return self._complete_counters(text)
def _complete_counters(self, text):
return self._complete_res(COUNTER_ARRAYS, text)
@handle_bad_input
def do_register_read(self, line):
"Read register value: register_read <name> [index]"
args = line.split()
self.at_least_n_args(args, 1)
register_name = args[0]
register = self.get_res("register", register_name,
ResType.register_array)
if len(args) > 1:
self.exactly_n_args(args, 2)
index = args[1]
try:
index = int(index)
except:
raise UIn_Error("Bad format for index")
value = self.client.bm_register_read(0, register.name, index)
print "{}[{}]=".format(register_name, index), value
else:
sys.stderr.write("register index omitted, reading entire array\n")
entries = self.client.bm_register_read_all(0, register.name)
print "{}=".format(register_name), ", ".join(
[str(e) for e in entries])
def complete_register_read(self, text, line, start_index, end_index):
return self._complete_registers(text)
@handle_bad_input
def do_register_write(self, line):
"Write register value: register_write <name> <index> <value>"
args = line.split()
self.exactly_n_args(args, 3)
register_name = args[0]
register = self.get_res("register", register_name,
ResType.register_array)
index = args[1]
try:
index = int(index)
except:
raise UIn_Error("Bad format for index")
value = args[2]
try:
value = int(value)
except:
raise UIn_Error("Bad format for value, must be an integer")
self.client.bm_register_write(0, register.name, index, value)
def complete_register_write(self, text, line, start_index, end_index):
return self._complete_registers(text)
@handle_bad_input
def do_register_reset(self, line):
"Reset all the cells in the register array to 0: register_reset <name>"
args = line.split()
self.exactly_n_args(args, 1)
register_name = args[0]
register = self.get_res("register", register_name,
ResType.register_array)
self.client.bm_register_reset(0, register.name)
def complete_register_reset(self, text, line, start_index, end_index):
return self._complete_registers(text)
def _complete_registers(self, text):
return self._complete_res(REGISTER_ARRAYS, text)
def dump_action_and_data(self, action_name, action_data):
def hexstr(v):
return "".join("{:02x}".format(ord(c)) for c in v)
print "Action entry: {} - {}".format(
action_name, ", ".join([hexstr(a) for a in action_data]))
def dump_action_entry(self, a_entry):
if a_entry.action_type == BmActionEntryType.NONE:
print "EMPTY"
elif a_entry.action_type == BmActionEntryType.ACTION_DATA:
self.dump_action_and_data(a_entry.action_name, a_entry.action_data)
elif a_entry.action_type == BmActionEntryType.MBR_HANDLE:
print "Index: member({})".format(a_entry.mbr_handle)
elif a_entry.action_type == BmActionEntryType.GRP_HANDLE:
print "Index: group({})".format(a_entry.grp_handle)
def dump_one_member(self, member):
print "Dumping member {}".format(member.mbr_handle)
self.dump_action_and_data(member.action_name, member.action_data)
def dump_members(self, members):
for m in members:
print "**********"
self.dump_one_member(m)
def dump_one_group(self, group):
print "Dumping group {}".format(group.grp_handle)
print "Members: [{}]".format(", ".join(
[str(h) for h in group.mbr_handles]))
def dump_groups(self, groups):
for g in groups:
print "**********"
self.dump_one_group(g)
def dump_one_entry(self, table, entry):
if table.key:
out_name_w = max(20, max([len(t[0]) for t in table.key]))
def hexstr(v):
return "".join("{:02x}".format(ord(c)) for c in v)
def dump_exact(p):
return hexstr(p.exact.key)
def dump_lpm(p):
return "{}/{}".format(hexstr(p.lpm.key), p.lpm.prefix_length)
def dump_ternary(p):
return "{} &&& {}".format(hexstr(p.ternary.key),
hexstr(p.ternary.mask))
def dump_range(p):
return "{} -> {}".format(hexstr(p.range.start),
hexstr(p.range.end_))
def dump_valid(p):
return "01" if p.valid.key else "00"
pdumpers = {"exact": dump_exact, "lpm": dump_lpm,
"ternary": dump_ternary, "valid": dump_valid,
"range": dump_range}
print "Dumping entry {}".format(hex(entry.entry_handle))
print "Match key:"
for p, k in zip(entry.match_key, table.key):
assert(k[1] == p.type)
pdumper = pdumpers[MatchType.to_str(p.type)]
print "* {0:{w}}: {1:10}{2}".format(
k[0], MatchType.to_str(p.type).upper(),
pdumper(p), w=out_name_w)
if entry.options.priority >= 0:
print "Priority: {}".format(entry.options.priority)
self.dump_action_entry(entry.action_entry)
if entry.life is not None:
print "Life: {}ms since hit, timeout is {}ms".format(
entry.life.time_since_hit_ms, entry.life.timeout_ms)
@handle_bad_input
def do_table_dump_entry(self, line):
"Display some information about a table entry: table_dump_entry <table name> <entry handle>"
args = line.split()
self.exactly_n_args(args, 2)
table_name = args[0]
table = self.get_res("table", table_name, ResType.table)
try:
entry_handle = int(args[1])
except:
raise UIn_Error("Bad format for entry handle")
entry = self.client.bm_mt_get_entry(0, table.name, entry_handle)
self.dump_one_entry(table, entry)
def complete_table_dump_entry(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_act_prof_dump_member(self, line):
"Display some information about a member: act_prof_dump_member <action profile name> <member handle>"
args = line.split()
self.exactly_n_args(args, 2)
act_prof_name = args[0]
act_prof = self.get_res("action profile", act_prof_name,
ResType.action_prof)
try:
mbr_handle = int(args[1])
except:
raise UIn_Error("Bad format for member handle")
member = self.client.bm_mt_act_prof_get_member(
0, act_prof.name, mbr_handle)
self.dump_one_member(member)
def complete_act_prof_dump_member(self, text, line, start_index, end_index):
return self._complete_act_profs(text)
# notice the strictly_deprecated=False; I don't consider this command to be
# strictly deprecated because it can be convenient and does not modify the
# action profile so won't create problems
@deprecated_act_prof("act_prof_dump_member", with_selection=False,
strictly_deprecated=False)
def do_table_dump_member(self, line):
"Display some information about a member: table_dump_member <table name> <member handle>"
pass
def complete_table_dump_member(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_act_prof_dump_group(self, line):
"Display some information about a group: table_dump_group <action profile name> <group handle>"
args = line.split()
self.exactly_n_args(args, 2)
act_prof_name = args[0]
act_prof = self.get_res("action profile", act_prof_name,
ResType.action_prof)
try:
grp_handle = int(args[1])
except:
raise UIn_Error("Bad format for group handle")
group = self.client.bm_mt_act_prof_get_group(
0, act_prof.name, grp_handle)
self.dump_one_group(group)
def complete_act_prof_dump_group(self, text, line, start_index, end_index):
return self._complete_act_profs(text)
@deprecated_act_prof("act_prof_dump_group", with_selection=False,
strictly_deprecated=False)
def do_table_dump_group(self, line):
"Display some information about a group: table_dump_group <table name> <group handle>"
pass
def complete_table_dump_group(self, text, line, start_index, end_index):
return self._complete_tables(text)
def _dump_act_prof(self, act_prof):
act_prof_name = act_prof.name
members = self.client.bm_mt_act_prof_get_members(0, act_prof.name)
print "=========="
print "MEMBERS"
self.dump_members(members)
if act_prof.with_selection:
groups = self.client.bm_mt_act_prof_get_groups(0, act_prof.name)
print "=========="
print "GROUPS"
self.dump_groups(groups)
@handle_bad_input
def do_act_prof_dump(self, line):
"Display entries in an action profile: act_prof_dump <action profile name>"
args = line.split()
self.exactly_n_args(args, 1)
act_prof_name = args[0]
act_prof = self.get_res("action profile", act_prof_name,
ResType.action_prof)
self._dump_act_prof(act_prof)
def complete_act_prof_dump(self, text, line, start_index, end_index):
return self._complete_act_profs(text)
@handle_bad_input
def do_table_dump(self, line):
"Display entries in a match-table: table_dump <table name>"
args = line.split()
self.exactly_n_args(args, 1)
table_name = args[0]
table = self.get_res("table", table_name, ResType.table)
entries = self.client.bm_mt_get_entries(0, table.name)
print "=========="
print "TABLE ENTRIES"
for e in entries:
print "**********"
self.dump_one_entry(table, e)
if table.type_ == TableType.indirect or\
table.type_ == TableType.indirect_ws:
assert(table.action_prof is not None)
self._dump_act_prof(table.action_prof)
# default entry
default_entry = self.client.bm_mt_get_default_entry(0, table.name)
print "=========="
print "Dumping default entry"
self.dump_action_entry(default_entry)
print "=========="
def complete_table_dump(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_table_dump_entry_from_key(self, line):
"Display some information about a table entry: table_dump_entry_from_key <table name> <match fields> [priority]"
args = line.split()
self.at_least_n_args(args, 1)
table_name = args[0]
table = self.get_res("table", table_name, ResType.table)
if table.match_type in {MatchType.TERNARY, MatchType.RANGE}:
try:
priority = int(args.pop(-1))
except:
raise UIn_Error(
"Table is ternary, but could not extract a valid priority from args"
)
else:
priority = 0
match_key = args[1:]
if len(match_key) != table.num_key_fields():
raise UIn_Error(
"Table %s needs %d key fields" % (table_name, table.num_key_fields())
)
match_key = parse_match_key(table, match_key)
entry = self.client.bm_mt_get_entry_from_key(
0, table.name, match_key, BmAddEntryOptions(priority = priority))
self.dump_one_entry(table, entry)
def complete_table_dump_entry_from_key(self, text, line, start_index, end_index):
return self._complete_tables(text)
@handle_bad_input
def do_port_add(self, line):
"Add a port to the switch (behavior depends on device manager used): port_add <iface_name> <port_num> [pcap_path]"
args = line.split()
self.at_least_n_args(args, 2)
iface_name = args[0]
try:
port_num = int(args[1])
except:
raise UIn_Error("Bad format for port_num, must be an integer")
pcap_path = ""
if len(args) > 2:
pcap_path = args[2]
self.client.bm_dev_mgr_add_port(iface_name, port_num, pcap_path)
@handle_bad_input
def do_port_remove(self, line):
"Removes a port from the switch (behavior depends on device manager used): port_remove <port_num>"
args = line.split()
self.exactly_n_args(args, 1)
try:
port_num = int(args[0])
except:
raise UIn_Error("Bad format for port_num, must be an integer")
self.client.bm_dev_mgr_remove_port(port_num)
@handle_bad_input
def do_show_ports(self, line):
"Shows the ports connected to the switch: show_ports"
self.exactly_n_args(line.split(), 0)
ports = self.client.bm_dev_mgr_show_ports()
print "{:^10}{:^20}{:^10}{}".format(
"port #", "iface name", "status", "extra info")
print "=" * 50
for port_info in ports:
status = "UP" if port_info.is_up else "DOWN"
extra_info = "; ".join(
[k + "=" + v for k, v in port_info.extra.items()])
print "{:^10}{:^20}{:^10}{}".format(
port_info.port_num, port_info.iface_name, status, extra_info)
@handle_bad_input
def do_switch_info(self, line):
"Show some basic info about the switch: switch_info"
self.exactly_n_args(line.split(), 0)
info = self.client.bm_mgmt_get_info()
attributes = [t[2] for t in info.thrift_spec[1:]]
out_attr_w = 5 + max(len(a) for a in attributes)
for a in attributes:
print "{:{w}}: {}".format(a, getattr(info, a), w=out_attr_w)
@handle_bad_input
def do_reset_state(self, line):
"Reset all state in the switch (table entries, registers, ...), but P4 config is preserved: reset_state"
self.exactly_n_args(line.split(), 0)
self.client.bm_reset_state()
@handle_bad_input
def do_write_config_to_file(self, line):
"Retrieves the JSON config currently used by the switch and dumps it to user-specified file"
args = line.split()
self.exactly_n_args(args, 1)
filename = args[0]
json_cfg = self.client.bm_get_config()
with open(filename, 'w') as f:
f.write(json_cfg)
@handle_bad_input
def do_serialize_state(self, line):
"Serialize the switch state and dumps it to user-specified file"
args = line.split()
self.exactly_n_args(args, 1)
filename = args[0]
state = self.client.bm_serialize_state()
with open(filename, 'w') as f:
f.write(state)
def set_crc_parameters_common(self, line, crc_width=16):
conversion_fn = {16: hex_to_i16, 32: hex_to_i32}[crc_width]
config_type = {16: BmCrc16Config, 32: BmCrc32Config}[crc_width]
thrift_fn = {16: self.client.bm_set_crc16_custom_parameters,
32: self.client.bm_set_crc32_custom_parameters}[crc_width]
args = line.split()
self.exactly_n_args(args, 6)
name = args[0]
if name not in CUSTOM_CRC_CALCS or CUSTOM_CRC_CALCS[name] != crc_width:
raise UIn_ResourceError("crc{}_custom".format(crc_width), name)
config_args = [conversion_fn(a) for a in args[1:4]]
config_args += [parse_bool(a) for a in args[4:6]]
crc_config = config_type(*config_args)
thrift_fn(0, name, crc_config)
def _complete_crc(self, text, crc_width=16):
crcs = sorted(
[c for c, w in CUSTOM_CRC_CALCS.items() if w == crc_width])
if not text:
return crcs
return [c for c in crcs if c.startswith(text)]
@handle_bad_input
def do_set_crc16_parameters(self, line):
"Change the parameters for a custom crc16 hash: set_crc16_parameters <name> <polynomial> <initial remainder> <final xor value> <reflect data?> <reflect remainder?>"
self.set_crc_parameters_common(line, 16)
def complete_set_crc16_parameters(self, text, line, start_index, end_index):
return self._complete_crc(text, 16)
@handle_bad_input
def do_set_crc32_parameters(self, line):
"Change the parameters for a custom crc32 hash: set_crc32_parameters <name> <polynomial> <initial remainder> <final xor value> <reflect data?> <reflect remainder?>"
self.set_crc_parameters_common(line, 32)
def complete_set_crc32_parameters(self, text, line, start_index, end_index):
return self._complete_crc(text, 32)
def load_json_config(standard_client=None, json_path=None):
load_json_str(utils.get_json_config(standard_client, json_path))
def main():
args = get_parser().parse_args()
standard_client, mc_client = thrift_connect(
args.thrift_ip, args.thrift_port,
RuntimeAPI.get_thrift_services(args.pre)
)
load_json_config(standard_client, args.json)
RuntimeAPI(args.pre, standard_client, mc_client).cmdloop()
if __name__ == '__main__':
main()
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/qz_zhang/bmv2.git
git@gitee.com:qz_zhang/bmv2.git
qz_zhang
bmv2
bmv2
master

搜索帮助

344bd9b3 5694891 D2dac590 5694891