rename dir
Signed-off-by: Nico Schottelius <nico@nico-notebook.schottelius.org>
This commit is contained in:
parent
3e029252a6
commit
50971dc10c
197 changed files with 0 additions and 0 deletions
484
netfpga/minip4/sw/CLI/P4_SWITCH_CLI.py
Executable file
484
netfpga/minip4/sw/CLI/P4_SWITCH_CLI.py
Executable file
|
|
@ -0,0 +1,484 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# Copyright (c) 2017 Stephen Ibanez
|
||||
# All rights reserved.
|
||||
#
|
||||
# This software was developed by Stanford University and the University of Cambridge Computer Laboratory
|
||||
# under National Science Foundation under Grant No. CNS-0855268,
|
||||
# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and
|
||||
# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),
|
||||
# as part of the DARPA MRC research programme.
|
||||
#
|
||||
# @NETFPGA_LICENSE_HEADER_START@
|
||||
#
|
||||
# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor
|
||||
# license agreements. See the NOTICE file distributed with this work for
|
||||
# additional information regarding copyright ownership. NetFPGA licenses this
|
||||
# file to you under the NetFPGA Hardware-Software License, Version 1.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.netfpga-cic.org
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, Work 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.
|
||||
#
|
||||
# @NETFPGA_LICENSE_HEADER_END@
|
||||
#
|
||||
|
||||
|
||||
import os, sys, cmd, re
|
||||
from collections import OrderedDict
|
||||
from pprint import pprint
|
||||
import p4_regs_api, p4_tables_api
|
||||
|
||||
# defines the table_*_add_entry command
|
||||
# also defines convert_to_int()
|
||||
from p4_px_tables import *
|
||||
|
||||
### Global Variables ###
|
||||
P4_EXTERNS = p4_regs_api.P4_EXTERNS
|
||||
P4_REGS = OrderedDict() # just the externs with a control interface
|
||||
for extern_name, extern_dict in P4_EXTERNS.items():
|
||||
if 'control_width' in extern_dict.keys() and extern_dict['control_width'] > 0:
|
||||
P4_REGS[extern_name] = extern_dict
|
||||
|
||||
#p4_tables = p4_tables_api.p4_tables_info
|
||||
PX_CAM_TABLES = p4_tables_api.PX_CAM_TABLES
|
||||
PX_TCAM_TABLES = p4_tables_api.PX_TCAM_TABLES
|
||||
PX_LPM_TABLES = p4_tables_api.PX_LPM_TABLES
|
||||
|
||||
class SimpleSumeSwitch(cmd.Cmd):
|
||||
"""The SimpleSumeSwitch interactive command line tool"""
|
||||
|
||||
prompt = ">> "
|
||||
intro = "The SimpleSumeSwitch interactive command line tool\n type help to see all commands"
|
||||
|
||||
##########################
|
||||
### Register Functions ###
|
||||
##########################
|
||||
"""
|
||||
List the registers defined in the SimpleSumeSwitch
|
||||
"""
|
||||
def do_list_regs(self, line):
|
||||
for reg_name, reg_dict in P4_REGS.items():
|
||||
print '-'*len(reg_name), '\n', reg_name, ':\n', '-'*len(reg_name)
|
||||
pprint(reg_dict)
|
||||
|
||||
def help_list_regs(self):
|
||||
print """
|
||||
list_regs
|
||||
DESCRIPTION: List the registers defined in the SimpleSumeSwitch and their relevant compile time information
|
||||
"""
|
||||
|
||||
def do_reg_read(self, line):
|
||||
fmat = r"(.*)\[(\d*)\]"
|
||||
searchObj = re.search(fmat, line)
|
||||
if searchObj is not None:
|
||||
reg_name = searchObj.group(1)
|
||||
index = int(searchObj.group(2))
|
||||
else:
|
||||
reg_name = line
|
||||
index = 0
|
||||
result = p4_regs_api.reg_read(reg_name, index)
|
||||
print result
|
||||
|
||||
def help_reg_read(self):
|
||||
print """
|
||||
reg_read <REG_NAME>[<INDEX>]
|
||||
DESCRIPTION: Read the current value of the provided register at the given index
|
||||
"""
|
||||
|
||||
def complete_reg_read(self, text, line, begidx, endidx):
|
||||
if not text:
|
||||
completions = P4_REGS.keys()
|
||||
else:
|
||||
completions = [ r for r in P4_REGS.keys() if r.startswith(text)]
|
||||
return completions
|
||||
|
||||
def do_reg_write(self, line):
|
||||
fmat = r"(.*)\[(\d*)\]\s*(\d*)"
|
||||
searchObj = re.search(fmat, line)
|
||||
if searchObj is not None:
|
||||
reg_name = searchObj.group(1)
|
||||
index = int(searchObj.group(2))
|
||||
val = int(searchObj.group(3))
|
||||
else:
|
||||
print >> sys.stderr, "ERROR: usage ..."
|
||||
self.help_reg_write()
|
||||
return
|
||||
result = p4_regs_api.reg_write(reg_name, index, val)
|
||||
print result
|
||||
|
||||
def help_reg_write(self):
|
||||
print """
|
||||
writeReg <REG_NAME>[<INDEX>] <VALUE>
|
||||
DESCRIPTION: Write VALUE to the provided register at the given INDEX
|
||||
"""
|
||||
|
||||
def complete_reg_write(self, text, line, begidx, endidx):
|
||||
if not text:
|
||||
completions = P4_REGS.keys()
|
||||
else:
|
||||
completions = [ r for r in P4_REGS.keys() if r.startswith(text)]
|
||||
return completions
|
||||
|
||||
###########################
|
||||
### CAM Table Functions ###
|
||||
###########################
|
||||
|
||||
"""
|
||||
List the CAM tables and some relevant info
|
||||
"""
|
||||
def do_list_cam_tables(self, line):
|
||||
for table_name, table in PX_CAM_TABLES.items():
|
||||
print '-'*len(table_name), '\n', table_name, ':\n', '-'*len(table_name)
|
||||
pprint(table.info)
|
||||
|
||||
def help_list_cam_tables(self):
|
||||
print """
|
||||
list_cam_tables
|
||||
DESCRIPTION: List the exact match tables defined in the SimpleSumeSwitch and their relevant compile time information
|
||||
"""
|
||||
|
||||
"""
|
||||
Read entry from a table
|
||||
"""
|
||||
def do_table_cam_read_entry(self, line):
|
||||
args = line.split(' ')
|
||||
try:
|
||||
assert(len(args) >= 2)
|
||||
except:
|
||||
print >> sys.stderr, "ERROR: usage ... "
|
||||
self.help_table_cam_read_entry()
|
||||
return
|
||||
table_name = args[0]
|
||||
keys = map(convert_to_int, args[1:])
|
||||
(found, val) = p4_tables_api.table_cam_read_entry(table_name, keys)
|
||||
print "Entry found: ", found
|
||||
print hex(int(val, 16))
|
||||
|
||||
def help_table_cam_read_entry(self):
|
||||
print """
|
||||
table_cam_read_entry <table_name> <keys>
|
||||
DESCRIPTION: Read the entry in table corresponding to the given list of keys
|
||||
PARAMS:
|
||||
<table_name> : name of the table to read from
|
||||
<keys> : space separated list of keys to look for in the table (must correspond to table's keys in the order defined in the P4 program)
|
||||
"""
|
||||
|
||||
def complete_table_cam_read_entry(self, text, line, begidx, endidx):
|
||||
if not text:
|
||||
completions = PX_CAM_TABLES.keys()
|
||||
else:
|
||||
completions = [ t for t in PX_CAM_TABLES.keys() if t.startswith(text)]
|
||||
return completions
|
||||
|
||||
"""
|
||||
Add an entry to a table
|
||||
"""
|
||||
def do_table_cam_add_entry(self, line):
|
||||
# defined in p4_px_tables.py
|
||||
(table_name, keys, action_name, action_data) = parse_table_cam_add_entry(line)
|
||||
p4_tables_api.table_cam_add_entry(table_name, keys, action_name, action_data)
|
||||
|
||||
def help_table_cam_add_entry(self):
|
||||
# defined in p4_px_tables.py
|
||||
print help_table_cam_add_entry()
|
||||
|
||||
def complete_table_cam_add_entry(self, text, line, begidx, endidx):
|
||||
if not text:
|
||||
if len(line.split()) == 1:
|
||||
# table names
|
||||
completions = PX_CAM_TABLES.keys()
|
||||
elif len(line.split()) == 2:
|
||||
# actions names
|
||||
table_name = line.split()[1]
|
||||
if table_name in PX_CAM_TABLES.keys():
|
||||
# the table name is recognized
|
||||
actions = PX_CAM_TABLES[table_name].actions
|
||||
completions = [a['p4_name'] for a in actions]
|
||||
else:
|
||||
completions = []
|
||||
else:
|
||||
if len(line.split()) == 2:
|
||||
# trying to complete table name
|
||||
completions = [ t for t in PX_CAM_TABLES.keys() if t.startswith(text)]
|
||||
elif len(line.split()) == 3:
|
||||
# trying to complete action_name
|
||||
table_name = line.split()[1]
|
||||
if table_name in PX_CAM_TABLES.keys():
|
||||
# the table name is recognized
|
||||
actions = PX_CAM_TABLES[table_name].actions
|
||||
completions = [ a['p4_name'] for a in actions if a['p4_name'].startswith(text)]
|
||||
else:
|
||||
completions = []
|
||||
return completions
|
||||
|
||||
"""
|
||||
Delete an entry from a table
|
||||
"""
|
||||
def do_table_cam_delete_entry(self, line):
|
||||
args = line.split(' ')
|
||||
if (len(args) < 2):
|
||||
print >> sys.stderr, "ERROR: usage..."
|
||||
self.help_table_cam_delete_entry()
|
||||
return
|
||||
table_name = args[0]
|
||||
keys = map(convert_to_int, args[1:])
|
||||
p4_tables_api.table_cam_delete_entry(table_name, keys)
|
||||
|
||||
def help_table_cam_delete_entry(self):
|
||||
print """
|
||||
table_cam_delete_entry <table_name> <keys>
|
||||
DESCRIPTION: Delete the entry in the specified table with the given keys
|
||||
PARAMS:
|
||||
<table_name> : name of the table to delete an entry from
|
||||
<keys> : space separated list of keys (must correspond to table's keys in the order defined in the P4 program)
|
||||
"""
|
||||
|
||||
def complete_table_cam_delete_entry(self, text, line, begidx, endidx):
|
||||
if not text:
|
||||
completions = PX_CAM_TABLES.keys()
|
||||
else:
|
||||
completions = [ t for t in PX_CAM_TABLES.keys() if t.startswith(text)]
|
||||
return completions
|
||||
|
||||
"""
|
||||
Get the current number of entries in the table
|
||||
"""
|
||||
def do_table_cam_get_size(self, line):
|
||||
table_name = line.strip()
|
||||
print p4_tables_api.table_cam_get_size(table_name)
|
||||
|
||||
def help_table_cam_get_size(self):
|
||||
print """
|
||||
table_cam_get_size <table_name>
|
||||
DESCRIPTION: Get the current number of entries in the specified table
|
||||
"""
|
||||
|
||||
def complete_table_cam_get_size(self, text, line, begidx, endidx):
|
||||
if not text:
|
||||
completions = PX_CAM_TABLES.keys()
|
||||
else:
|
||||
completions = [ t for t in p4_tables.keys() if t.startswith(text)]
|
||||
return completions
|
||||
|
||||
def do_EOF(self, line):
|
||||
return True
|
||||
|
||||
|
||||
############################
|
||||
### TCAM Table Functions ###
|
||||
############################
|
||||
|
||||
"""
|
||||
List the TCAM tables and some relevant info
|
||||
"""
|
||||
def do_list_tcam_tables(self, line):
|
||||
for table_name, table in PX_TCAM_TABLES.items():
|
||||
print '-'*len(table_name), '\n', table_name, ':\n', '-'*len(table_name)
|
||||
pprint(table.info)
|
||||
|
||||
def help_list_tcam_tables(self):
|
||||
print """
|
||||
list_tcam_tables
|
||||
DESCRIPTION: List the ternary match tables defined in the SimpleSumeSwitch and their relevant compile time information
|
||||
"""
|
||||
|
||||
def do_table_tcam_clean(self, line):
|
||||
table_name = line.strip()
|
||||
p4_tables_api.table_tcam_clean(table_name)
|
||||
|
||||
def help_table_tcam_clean(self):
|
||||
print """
|
||||
table_tcam_clean <table_name>
|
||||
DESCRIPTION: performs table self-initialization, erasing and invalidating all stored rules
|
||||
"""
|
||||
|
||||
def do_table_tcam_get_addr_size(self, line):
|
||||
print p4_tables_api.table_tcam_get_addr_size()
|
||||
|
||||
def help_table_tcam_get_addr_size(self):
|
||||
print """
|
||||
table_tcam_get_addr_size
|
||||
DESCRIPTION: returns the TCAM_ADDR_SIZE
|
||||
"""
|
||||
|
||||
def do_table_tcam_set_log_level(self, line):
|
||||
args = line.strip().split()
|
||||
if (len(args) < 2):
|
||||
print >> sys.stderr, "ERROR: usage..."
|
||||
self.help_table_tcam_set_log_level()
|
||||
return
|
||||
table_name = args[0]
|
||||
try:
|
||||
msg_level = int(args[1], 0)
|
||||
except:
|
||||
print >> sys.stderr, "ERROR: msg_level must be valid int"
|
||||
return
|
||||
p4_tables_api.table_tcam_set_log_level(table_name, msg_level)
|
||||
|
||||
def help_table_tcam_set_log_level(self):
|
||||
print """
|
||||
table_tcam_set_log_level <table_name> <msg_level>
|
||||
DESCRIPTION: Update the logging level of the table
|
||||
"""
|
||||
|
||||
def do_table_tcam_add_entry(self, line):
|
||||
# defined in p4_px_tables.py
|
||||
(table_name, address, keys, masks, action_name, action_data) = parse_table_tcam_add_entry(line)
|
||||
p4_tables_api.table_tcam_write_entry(table_name, address, keys, masks, action_name, action_data)
|
||||
|
||||
def help_table_tcam_add_entry(self):
|
||||
# defined in p4_px_tables.py
|
||||
print help_table_tcam_add_entry()
|
||||
|
||||
def do_table_tcam_erase_entry(self, line):
|
||||
args = line.strip().split()
|
||||
if (len(args) < 2):
|
||||
print >> sys.stderr, "ERROR: usage..."
|
||||
self.help_table_tcam_erase_entry()
|
||||
return
|
||||
table_name = args[0]
|
||||
try:
|
||||
address = int(args[1], 0)
|
||||
except:
|
||||
print >> sys.stderr, "ERROR: address must be valid int"
|
||||
return
|
||||
p4_tables_api.table_tcam_erase_entry(table_name, address)
|
||||
|
||||
def help_table_tcam_erase_entry(self):
|
||||
print """
|
||||
table_tcam_erase_entry <table_name> <address>
|
||||
DESCRIPTION: invalidates(removes) an entry in the TCAM
|
||||
"""
|
||||
|
||||
def do_table_tcam_verify_entry(self, line):
|
||||
# defined in p4_px_tables.py
|
||||
(table_name, address, keys, masks, action_name, action_data) = parse_table_tcam_add_entry(line)
|
||||
rc = p4_tables_api.table_tcam_verify_entry(table_name, address, keys, masks, action_name, action_data)
|
||||
print p4_tables_api.table_tcam_error_decode(rc)
|
||||
|
||||
def help_table_tcam_verify_entry(self):
|
||||
print """
|
||||
table_tcam_verify_entry <table_name> <address> <action_name> <key1/mask1 ... keyN/maskN> => <action_data>
|
||||
DESCRIPTION: verifies whether an entry exists in TCAM
|
||||
PARAMS:
|
||||
<table_name> : name of the table to add an entry to
|
||||
<address> : address in table at which to add the entry
|
||||
<action_name> : name of the action to use in the entry (must be listed in the table's actions list)
|
||||
<key/mask> : space separated list of key/mask to use as the entry key (must correspond to table's keys in the order defined in the P4 program)
|
||||
<action_data> : space separated list of values to provide as input to the action
|
||||
"""
|
||||
|
||||
###########################
|
||||
### LPM Table Functions ###
|
||||
###########################
|
||||
|
||||
"""
|
||||
List the LPM tables and some relevant info
|
||||
"""
|
||||
def do_list_lpm_tables(self, line):
|
||||
for table_name, table in PX_LPM_TABLES.items():
|
||||
print '-'*len(table_name), '\n', table_name, ':\n', '-'*len(table_name)
|
||||
pprint(table.info)
|
||||
|
||||
def help_list_lpm_tables(self):
|
||||
print """
|
||||
list_lpm_tables
|
||||
DESCRIPTION: List the longest prefix match tables defined in the SimpleSumeSwitch and their relevant compile time information
|
||||
"""
|
||||
|
||||
def do_table_lpm_get_addr_size(self, line):
|
||||
print p4_tables_api.table_lpm_get_addr_size()
|
||||
|
||||
def help_table_lpm_get_addr_size(self):
|
||||
print """
|
||||
table_lpm_get_addr_size
|
||||
DESCRIPTION: returns the LPM_ADDR_SIZE
|
||||
"""
|
||||
|
||||
def do_table_lpm_set_log_level(self, line):
|
||||
args = line.strip().split()
|
||||
if (len(args) < 2):
|
||||
print >> sys.stderr, "ERROR: usage..."
|
||||
self.help_table_lpm_set_log_level()
|
||||
return
|
||||
table_name = args[0]
|
||||
try:
|
||||
msg_level = int(args[1], 0)
|
||||
except:
|
||||
print >> sys.stderr, "ERROR: msg_level must be valid int"
|
||||
return
|
||||
p4_tables_api.table_lpm_set_log_level(table_name, msg_level)
|
||||
|
||||
def help_table_lpm_set_log_level(self):
|
||||
print """
|
||||
table_lpm_set_log_level <table_name> <msg_level>
|
||||
DESCRIPTION: Update the logging level of the table
|
||||
"""
|
||||
|
||||
def do_table_lpm_load_dataset(self, line):
|
||||
args = line.strip().split()
|
||||
if (len(args) < 2):
|
||||
print >> sys.stderr, "ERROR: usage..."
|
||||
self.help_table_lpm_load_dataset()
|
||||
return
|
||||
table_name = args[0]
|
||||
filename = args[1]
|
||||
p4_tables_api.table_lpm_load_dataset(table_name, filename)
|
||||
|
||||
def help_table_lpm_load_dataset(self):
|
||||
print """
|
||||
table_lpm_load_dataset <table_name> <filename>
|
||||
DESCRIPTION: Load new dataset into table
|
||||
"""
|
||||
|
||||
def do_table_lpm_verify_dataset(self, line):
|
||||
args = line.strip().split()
|
||||
if (len(args) < 2):
|
||||
print >> sys.stderr, "ERROR: usage..."
|
||||
self.help_table_lpm_verify_dataset()
|
||||
return
|
||||
table_name = args[0]
|
||||
filename = args[1]
|
||||
rc = p4_tables_api.table_lpm_verify_dataset(table_name, filename)
|
||||
print p4_tables_api.table_lpm_error_decode(rc)
|
||||
|
||||
def help_table_lpm_verify_dataset(self):
|
||||
print """
|
||||
table_lpm_verify_dataset <table_name> <filename>
|
||||
DESCRIPTION: Verify that dataset is in table
|
||||
"""
|
||||
|
||||
def do_table_lpm_set_active_lookup_bank(self, line):
|
||||
args = line.strip().split()
|
||||
if (len(args) < 2):
|
||||
print >> sys.stderr, "ERROR: usage..."
|
||||
self.help_table_lpm_set_log_level()
|
||||
return
|
||||
table_name = args[0]
|
||||
try:
|
||||
bank = int(args[1], 0)
|
||||
except:
|
||||
print >> sys.stderr, "ERROR: bank must be valid int"
|
||||
return
|
||||
p4_tables_api.table_lpm_set_active_lookup_bank(table_name, bank)
|
||||
|
||||
def help_table_lpm_set_active_lookup_bank(self):
|
||||
print """
|
||||
table_lpm_set_log_level <table_name> <bank>
|
||||
DESCRIPTION: sets the active lookup bank
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) > 1:
|
||||
SimpleSumeSwitch().onecmd(' '.join(sys.argv[1:]))
|
||||
else:
|
||||
SimpleSumeSwitch().cmdloop()
|
||||
|
||||
90
netfpga/minip4/sw/CLI/p4_regs_api.py
Normal file
90
netfpga/minip4/sw/CLI/p4_regs_api.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# Copyright (c) 2015 University of Cambridge
|
||||
# All rights reserved.
|
||||
#
|
||||
# This software was developed by Stanford University and the University of Cambridge Computer Laboratory
|
||||
# under National Science Foundation under Grant No. CNS-0855268,
|
||||
# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and
|
||||
# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),
|
||||
# as part of the DARPA MRC research programme.
|
||||
#
|
||||
# @NETFPGA_LICENSE_HEADER_START@
|
||||
#
|
||||
# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor
|
||||
# license agreements. See the NOTICE file distributed with this work for
|
||||
# additional information regarding copyright ownership. NetFPGA licenses this
|
||||
# file to you under the NetFPGA Hardware-Software License, Version 1.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.netfpga-cic.org
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, Work 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.
|
||||
#
|
||||
# @NETFPGA_LICENSE_HEADER_END@
|
||||
#
|
||||
|
||||
from NFTest import *
|
||||
import sys, os, re, json
|
||||
from fcntl import *
|
||||
from ctypes import *
|
||||
from collections import OrderedDict
|
||||
|
||||
# Loading the SUME shared library
|
||||
print "loading libsume.."
|
||||
lib_path=os.path.join(os.environ['SUME_FOLDER'],'lib','sw','std','hwtestlib','libsume.so')
|
||||
libsume=cdll.LoadLibrary(lib_path)
|
||||
|
||||
# argtypes for the functions called from C
|
||||
libsume.regread.argtypes = [c_uint]
|
||||
libsume.regwrite.argtypes= [c_uint, c_uint]
|
||||
|
||||
EXTERN_DEFINES_FILE = os.path.expandvars("$P4_PROJECT_DIR/sw/CLI/SimpleSumeSwitch_extern_defines.json")
|
||||
|
||||
ERROR_CODE = -1
|
||||
|
||||
"""
|
||||
Read the SimpleSumeSwitch_reg_defines.txt file
|
||||
"""
|
||||
def read_extern_defines():
|
||||
with open(EXTERN_DEFINES_FILE) as f:
|
||||
p4_externs = json.load(f)
|
||||
return p4_externs
|
||||
|
||||
def get_address(reg_name, index):
|
||||
global PX_EXTERNS
|
||||
if reg_name not in P4_EXTERNS.keys() and 'control_width' not in P4_EXTERNS[reg_name].keys() and P4_EXTERNS[reg_name]['control_width'] > 0:
|
||||
print >> sys.stderr, "ERROR: {0} is not a recognized register name".format(reg_name)
|
||||
return ERROR_CODE
|
||||
addressable_depth = 2**P4_EXTERNS[reg_name]['control_width']
|
||||
if index >= addressable_depth or index < 0:
|
||||
print >> sys.stderr, "ERROR: cannot access {0}[{1}], index out of bounds".format(reg_name, index)
|
||||
return ERROR_CODE
|
||||
return P4_EXTERNS[reg_name]['base_addr'] + index
|
||||
|
||||
# P4_EXTERNS is indexed by prefix_name
|
||||
P4_EXTERNS = read_extern_defines()
|
||||
|
||||
#####################
|
||||
### API Functions ###
|
||||
#####################
|
||||
|
||||
def reg_read(reg_name, index):
|
||||
address = get_address(reg_name, index)
|
||||
if address == ERROR_CODE:
|
||||
return ERROR_CODE
|
||||
# print "reading address : {0}".format(hex(address))
|
||||
return libsume.regread(address)
|
||||
|
||||
def reg_write(reg_name, index, val):
|
||||
address = get_address(reg_name, index)
|
||||
if address == ERROR_CODE:
|
||||
return ERROR_CODE
|
||||
# print "writing address : {0}".format(hex(address))
|
||||
return libsume.regwrite(address, val)
|
||||
|
||||
283
netfpga/minip4/sw/CLI/p4_tables_api.py
Normal file
283
netfpga/minip4/sw/CLI/p4_tables_api.py
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# Copyright (c) 2017 Stephen Ibanez
|
||||
# All rights reserved.
|
||||
#
|
||||
# This software was developed by Stanford University and the University of Cambridge Computer Laboratory
|
||||
# under National Science Foundation under Grant No. CNS-0855268,
|
||||
# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and
|
||||
# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),
|
||||
# as part of the DARPA MRC research programme.
|
||||
#
|
||||
# @NETFPGA_LICENSE_HEADER_START@
|
||||
#
|
||||
# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor
|
||||
# license agreements. See the NOTICE file distributed with this work for
|
||||
# additional information regarding copyright ownership. NetFPGA licenses this
|
||||
# file to you under the NetFPGA Hardware-Software License, Version 1.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.netfpga-cic.org
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, Work 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.
|
||||
#
|
||||
# @NETFPGA_LICENSE_HEADER_END@
|
||||
#
|
||||
|
||||
from NFTest import *
|
||||
import sys, os, re, json
|
||||
from fcntl import *
|
||||
from ctypes import *
|
||||
|
||||
SWITCH_INFO_FILE = os.path.expandvars("$P4_PROJECT_DIR/src/.sdnet_switch_info.dat")
|
||||
|
||||
# sets PX_TABLES
|
||||
import p4_px_tables
|
||||
p4_px_tables.make_px_tables(SWITCH_INFO_FILE)
|
||||
|
||||
PX_CAM_TABLES = {}
|
||||
PX_TCAM_TABLES = {}
|
||||
PX_LPM_TABLES = {}
|
||||
|
||||
def split_px_tables():
|
||||
for name, table in p4_px_tables.PX_TABLES.items():
|
||||
if table.info['match_type'] == 'EM':
|
||||
PX_CAM_TABLES[name] = table
|
||||
elif table.info['match_type'] == 'TCAM':
|
||||
PX_TCAM_TABLES[name] = table
|
||||
elif table.info['match_type'] == 'LPM':
|
||||
PX_LPM_TABLES[name] = table
|
||||
|
||||
split_px_tables()
|
||||
|
||||
if (len(PX_CAM_TABLES) > 0):
|
||||
print "loading libcam.."
|
||||
libcam=cdll.LoadLibrary(os.path.expandvars('$P4_PROJECT_DIR/sw/CLI/libcam.so'))
|
||||
|
||||
# argtypes for the functions called from C
|
||||
libcam.cam_read_entry.argtypes = [c_uint, c_char_p, c_char_p, c_char_p]
|
||||
libcam.cam_add_entry.argtypes = [c_uint, c_char_p, c_char_p]
|
||||
libcam.cam_delete_entry.argtypes = [c_uint, c_char_p]
|
||||
libcam.cam_error_decode.argtypes = [c_int]
|
||||
libcam.cam_error_decode.restype = c_char_p
|
||||
libcam.cam_get_size.argtypes = [c_uint]
|
||||
libcam.cam_get_size.restype = c_uint
|
||||
|
||||
if (len(PX_TCAM_TABLES) > 0):
|
||||
print "loading libtcam.."
|
||||
libtcam=cdll.LoadLibrary(os.path.expandvars('$P4_PROJECT_DIR/sw/CLI/libtcam.so'))
|
||||
|
||||
# argtypes for the functions called from C
|
||||
libtcam.tcam_clean.argtypes = [c_uint]
|
||||
libtcam.tcam_get_addr_size.argtypes = []
|
||||
libtcam.tcam_set_log_level.argtypes = [c_uint, c_uint]
|
||||
libtcam.tcam_write_entry.argtypes = [c_uint, c_uint, c_char_p, c_char_p, c_char_p]
|
||||
libtcam.tcam_erase_entry.argtypes = [c_uint, c_uint]
|
||||
libtcam.tcam_verify_entry.argtypes = [c_uint, c_uint, c_char_p, c_char_p, c_char_p]
|
||||
libtcam.tcam_verify_entry.restype = c_uint
|
||||
libtcam.tcam_error_decode.argtypes = [c_int]
|
||||
libtcam.tcam_error_decode.restype = c_char_p
|
||||
|
||||
if (len(PX_LPM_TABLES) > 0):
|
||||
print "loading liblpm.."
|
||||
liblpm=cdll.LoadLibrary(os.path.expandvars('$P4_PROJECT_DIR/sw/CLI/liblpm.so'))
|
||||
|
||||
# argtypes for the functions called from C
|
||||
liblpm.lpm_get_addr_size.argtypes = []
|
||||
liblpm.lpm_set_log_level.argtypes = [c_uint, c_uint]
|
||||
liblpm.lpm_load_dataset.argtypes = [c_uint, c_char_p]
|
||||
liblpm.lpm_verify_dataset.argtypes = [c_uint, c_char_p]
|
||||
liblpm.lpm_set_active_lookup_bank.argtypes = [c_uint, c_uint]
|
||||
liblpm.lpm_error_decode.argtypes = [c_int]
|
||||
liblpm.lpm_error_decode.restype = c_char_p
|
||||
|
||||
TABLE_DEFINES_FILE = os.path.expandvars("$P4_PROJECT_DIR/sw/CLI/SimpleSumeSwitch_table_defines.json")
|
||||
|
||||
########################
|
||||
### Helper Functions ###
|
||||
########################
|
||||
|
||||
"""
|
||||
def the SimpleSumeSwitch_table_defines.json file
|
||||
"""
|
||||
def read_table_defines():
|
||||
with open(TABLE_DEFINES_FILE) as f:
|
||||
tables_dict = json.load(f)
|
||||
return tables_dict
|
||||
|
||||
|
||||
p4_tables_info = read_table_defines()
|
||||
|
||||
"""
|
||||
Check if table_name is a valid CAM table
|
||||
"""
|
||||
def check_valid_cam_table_name(table_name):
|
||||
if (table_name not in PX_CAM_TABLES.keys() and table_name not in p4_tables_info['EM'].keys()):
|
||||
print >> sys.stderr, "ERROR: {0} is not a recognized CAM table name".format(table_name)
|
||||
return False
|
||||
return True
|
||||
|
||||
"""
|
||||
Check if table_name is a valid TCAM table
|
||||
"""
|
||||
def check_valid_tcam_table_name(table_name):
|
||||
if (table_name not in PX_TCAM_TABLES.keys() and table_name not in p4_tables_info['TCAM'].keys()):
|
||||
print >> sys.stderr, "ERROR: {0} is not a recognized TCAM table name".format(table_name)
|
||||
return False
|
||||
return True
|
||||
|
||||
"""
|
||||
Check if table_name is a valid LPM table
|
||||
"""
|
||||
def check_valid_lpm_table_name(table_name):
|
||||
if (table_name not in PX_LPM_TABLES.keys() and table_name not in p4_tables_info['LPM'].keys()):
|
||||
print >> sys.stderr, "ERROR: {0} is not a recognized LPM table name".format(table_name)
|
||||
return False
|
||||
return True
|
||||
|
||||
#########################
|
||||
### CAM API Functions ###
|
||||
#########################
|
||||
|
||||
def table_cam_read_entry(table_name, keys):
|
||||
if not check_valid_cam_table_name(table_name):
|
||||
return "NA", "NA"
|
||||
|
||||
tableID = int(p4_tables_info['EM'][table_name]['tableID'])
|
||||
key = PX_CAM_TABLES[table_name].hexify_key(keys)
|
||||
hex_key_buf = create_string_buffer("{:X}".format(key))
|
||||
value = create_string_buffer(1024) # TODO: Fix this ... Must be large enough to hold entire value
|
||||
found = create_string_buffer(10) # Should only need to hold "True" or "False"
|
||||
rc = libcam.cam_read_entry(tableID, hex_key_buf, value, found)
|
||||
print libcam.cam_error_decode(rc)
|
||||
return found.value, value.value
|
||||
|
||||
def table_cam_add_entry(table_name, keys, action_name, action_data):
|
||||
if not check_valid_cam_table_name(table_name):
|
||||
return
|
||||
|
||||
tableID = int(p4_tables_info['EM'][table_name]['tableID'])
|
||||
key = PX_CAM_TABLES[table_name].hexify_key(keys)
|
||||
value = PX_CAM_TABLES[table_name].hexify_value(action_name, action_data)
|
||||
rc = libcam.cam_add_entry(tableID, "{:X}".format(key), "{:X}".format(value))
|
||||
print libcam.cam_error_decode(rc)
|
||||
|
||||
def table_cam_delete_entry(table_name, keys):
|
||||
if not check_valid_cam_table_name(table_name):
|
||||
return
|
||||
|
||||
tableID = int(p4_tables_info['EM'][table_name]['tableID'])
|
||||
key = PX_CAM_TABLES[table_name].hexify_key(keys)
|
||||
rc = libcam.cam_delete_entry(tableID, "{:X}".format(key))
|
||||
print libcam.cam_error_decode(rc)
|
||||
|
||||
def table_cam_get_size(table_name):
|
||||
if not check_valid_cam_table_name(table_name):
|
||||
return 0
|
||||
|
||||
tableID = int(p4_tables_info['EM'][table_name]['tableID'])
|
||||
return libcam.cam_get_size(tableID)
|
||||
|
||||
|
||||
##########################
|
||||
### TCAM API Functions ###
|
||||
##########################
|
||||
|
||||
def table_tcam_clean(table_name):
|
||||
if not check_valid_tcam_table_name(table_name):
|
||||
return
|
||||
|
||||
tableID = int(p4_tables_info['TCAM'][table_name]['tableID'])
|
||||
rc = libtcam.tcam_clean(tableID)
|
||||
print libtcam.tcam_error_decode(rc)
|
||||
|
||||
def table_tcam_get_addr_size():
|
||||
return libtcam.tcam_get_addr_size()
|
||||
|
||||
def table_tcam_set_log_level(table_name, msg_level):
|
||||
if not check_valid_tcam_table_name(table_name):
|
||||
return
|
||||
|
||||
tableID = int(p4_tables_info['TCAM'][table_name]['tableID'])
|
||||
rc = libtcam.tcam_set_log_level(tableID, msg_level)
|
||||
print libtcam.tcam_error_decode(rc)
|
||||
|
||||
def table_tcam_write_entry(table_name, addr, keys, masks, action_name, action_data):
|
||||
if not check_valid_tcam_table_name(table_name):
|
||||
return
|
||||
|
||||
tableID = int(p4_tables_info['TCAM'][table_name]['tableID'])
|
||||
mask = PX_TCAM_TABLES[table_name].hexify_mask(masks)
|
||||
key = PX_TCAM_TABLES[table_name].hexify_key(keys)
|
||||
value = PX_TCAM_TABLES[table_name].hexify_value(action_name, action_data)
|
||||
rc = libtcam.tcam_write_entry(tableID, addr, "{:X}".format(key), "{:X}".format(mask), "{:X}".format(value))
|
||||
print libtcam.tcam_error_decode(rc)
|
||||
|
||||
def table_tcam_erase_entry(table_name, addr):
|
||||
if not check_valid_tcam_table_name(table_name):
|
||||
return
|
||||
|
||||
tableID = int(p4_tables_info['TCAM'][table_name]['tableID'])
|
||||
rc = libtcam.tcam_erase_entry(tableID, addr)
|
||||
print libtcam.tcam_error_decode(rc)
|
||||
|
||||
|
||||
def table_tcam_verify_entry(table_name, addr, keys, masks, action_name, action_data):
|
||||
if not check_valid_tcam_table_name(table_name):
|
||||
return
|
||||
|
||||
tableID = int(p4_tables_info['TCAM'][table_name]['tableID'])
|
||||
mask = PX_TCAM_TABLES[table_name].hexify_mask(masks)
|
||||
key = PX_TCAM_TABLES[table_name].hexify_key(keys)
|
||||
value = PX_TCAM_TABLES[table_name].hexify_value(action_name, action_data)
|
||||
return libtcam.tcam_verify_entry(tableID, addr, "{:X}".format(key), "{:X}".format(mask), "{:X}".format(value))
|
||||
|
||||
def table_tcam_error_decode(error):
|
||||
return libtcam.tcam_error_decode(error)
|
||||
|
||||
|
||||
#########################
|
||||
### LPM API Functions ###
|
||||
#########################
|
||||
|
||||
def table_lpm_get_addr_size():
|
||||
return liblpm.lpm_get_addr_size()
|
||||
|
||||
def table_lpm_set_log_level(table_name):
|
||||
if not check_valid_lpm_table_name(table_name):
|
||||
return
|
||||
|
||||
tableID = int(p4_tables_info['LPM'][table_name]['tableID'])
|
||||
rc = liblpm.lpm_set_log_level(tableID, msg_level)
|
||||
print liblpm.lpm_error_decode(rc)
|
||||
|
||||
def table_lpm_load_dataset(table_name, filename):
|
||||
if not check_valid_lpm_table_name(table_name):
|
||||
return
|
||||
|
||||
tableID = int(p4_tables_info['LPM'][table_name]['tableID'])
|
||||
rc = liblpm.lpm_load_dataset(tableID, filename)
|
||||
print liblpm.lpm_error_decode(rc)
|
||||
|
||||
def table_lpm_verify_dataset(table_name, filename):
|
||||
if not check_valid_lpm_table_name(table_name):
|
||||
return
|
||||
|
||||
tableID = int(p4_tables_info['LPM'][table_name]['tableID'])
|
||||
return liblpm.lpm_verify_dataset(tableID, filename)
|
||||
|
||||
def table_lpm_set_active_lookup_bank(table_name, bank):
|
||||
if not check_valid_lpm_table_name(table_name):
|
||||
return
|
||||
|
||||
tableID = int(p4_tables_info['LPM'][table_name]['tableID'])
|
||||
rc = liblpm.lpm_set_active_lookup_bank(tableID, bank)
|
||||
print liblpm.lpm_error_decode(rc)
|
||||
|
||||
def table_lpm_error_decode(error):
|
||||
return liblpm.lpm_error_decode(error)
|
||||
138
netfpga/minip4/sw/hw_test_tool/switch_calc_tester.py
Executable file
138
netfpga/minip4/sw/hw_test_tool/switch_calc_tester.py
Executable file
|
|
@ -0,0 +1,138 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# Copyright (c) 2017 Stephen Ibanez
|
||||
# All rights reserved.
|
||||
#
|
||||
# This software was developed by Stanford University and the University of Cambridge Computer Laboratory
|
||||
# under National Science Foundation under Grant No. CNS-0855268,
|
||||
# the University of Cambridge Computer Laboratory under EPSRC INTERNET Project EP/H040536/1 and
|
||||
# by the University of Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 ("MRC2"),
|
||||
# as part of the DARPA MRC research programme.
|
||||
#
|
||||
# @NETFPGA_LICENSE_HEADER_START@
|
||||
#
|
||||
# Licensed to NetFPGA C.I.C. (NetFPGA) under one or more contributor
|
||||
# license agreements. See the NOTICE file distributed with this work for
|
||||
# additional information regarding copyright ownership. NetFPGA licenses this
|
||||
# file to you under the NetFPGA Hardware-Software License, Version 1.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.netfpga-cic.org
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, Work 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.
|
||||
#
|
||||
# @NETFPGA_LICENSE_HEADER_END@
|
||||
#
|
||||
|
||||
|
||||
import os, sys, re, cmd, subprocess, shlex, time
|
||||
from threading import Thread
|
||||
|
||||
sys.path.append(os.path.expandvars('$P4_PROJECT_DIR/testdata/'))
|
||||
from switch_calc_headers import *
|
||||
from nf_sim_tools import *
|
||||
|
||||
PKT_SIZE = 64
|
||||
IFACE = "nf0"
|
||||
|
||||
ETH_SRC = "08:11:11:11:11:08"
|
||||
ETH_DST = "08:22:22:22:22:08"
|
||||
|
||||
OPCODE_MAP = {'ADD':ADD_OP, '+':ADD_OP, 'SUB':SUB_OP, '-':SUB_OP, 'LOOKUP':LOOKUP_OP, 'ADD_REG':ADD_REG_OP, 'SET_REG':SET_REG_OP}
|
||||
|
||||
os.system('sudo ifconfig {0} 10.0.0.10 netmask 255.255.255.0'.format(IFACE))
|
||||
|
||||
TCPDUMP = subprocess.Popen(shlex.split("tcpdump -i {0} -w /dev/null".format(IFACE)))
|
||||
time.sleep(0.1)
|
||||
|
||||
class SwitchCalcTester(cmd.Cmd):
|
||||
"""The HW testing tool for the switch_calc design"""
|
||||
|
||||
prompt = "testing> "
|
||||
intro = "The HW testing tool for the switch_calc design\n type help to see all commands"
|
||||
|
||||
def _to_int(self, op):
|
||||
try:
|
||||
val = int(op, 0)
|
||||
assert(val >= 0)
|
||||
return val
|
||||
except:
|
||||
print >> sys.stderr, "ERROR: operands must be valid positive integers"
|
||||
return -1
|
||||
|
||||
"""
|
||||
Submit packet to the switch and print the results
|
||||
"""
|
||||
def _submit_pkt(self, pkt):
|
||||
rcvd_pkt = srp1(pkt, iface=IFACE)
|
||||
|
||||
width = 10
|
||||
n = 9
|
||||
fmat_string = "| ETHERNET | OP1:{0:<{width}} OP_CODE:{1:<{width}} OP2:{2:<{width}} RESULT:{3:<{width}} |"
|
||||
print "Sent pkt: "
|
||||
print "{0:-<{width}}".format("-", width=n*width)
|
||||
print fmat_string.format(pkt[Calc].op1, pkt[Calc].opCode, pkt[Calc].op2, pkt[Calc].result, width=width)
|
||||
print "{0:-<{width}}\n".format("-", width=n*width)
|
||||
|
||||
print "Received pkt: "
|
||||
print "{0:-<{width}}".format("-", width=n*width)
|
||||
print fmat_string.format(rcvd_pkt[Calc].op1, rcvd_pkt[Calc].opCode, rcvd_pkt[Calc].op2, rcvd_pkt[Calc].result, width=width)
|
||||
print "{0:-<{width}}\n".format("-", width=n*width)
|
||||
|
||||
def _parse_line(self, line):
|
||||
args = line.split()
|
||||
if (len(args) != 3):
|
||||
print >> sys.stderr, "ERROR: usage..."
|
||||
self.help_run_test()
|
||||
return
|
||||
op1 = self._to_int(args[0])
|
||||
operation = args[1]
|
||||
op2 = self._to_int(args[2])
|
||||
if op1 == -1 or op2 == -1:
|
||||
return
|
||||
if (operation not in OPCODE_MAP.keys()):
|
||||
print >> sys.stderr, "ERROR: {0} is not a supported operation".format(operation)
|
||||
return
|
||||
opCode = OPCODE_MAP[operation]
|
||||
|
||||
pkt = Ether(dst=ETH_DST, src=ETH_SRC) / Calc(op1=op1, opCode=opCode, op2=op2, result=0)
|
||||
pkt = pad_pkt(pkt, PKT_SIZE) # pad pkt to desired size
|
||||
return pkt
|
||||
|
||||
def do_run_test(self, line):
|
||||
pkt = self._parse_line(line)
|
||||
self._submit_pkt(pkt)
|
||||
|
||||
def help_run_test(self):
|
||||
print """
|
||||
run_test <op1> <operation> <op2>
|
||||
DESCRIPTION: Create a single test packet to test the functionality of the switch_calc implementation
|
||||
NOTES:
|
||||
<operation> : must be one of the following [ADD, +, SUB, -, LOOKUP, ADD_REG, SET_REG]
|
||||
LOOKUP : <op1> = the key to lookup, <op2> = unused
|
||||
ADD_REG / SET_REG : <op1> = register index, <op2> = value
|
||||
"""
|
||||
|
||||
def do_exit(self, line):
|
||||
if (TCPDUMP.poll() is None):
|
||||
TCPDUMP.terminate()
|
||||
sys.exit(0)
|
||||
|
||||
def do_EOF(self, line):
|
||||
print ""
|
||||
if (TCPDUMP.poll() is None):
|
||||
TCPDUMP.terminate()
|
||||
return True
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) > 1:
|
||||
SwitchCalcTester().onecmd(' '.join(sys.argv[1:]))
|
||||
if (TCPDUMP.poll() is None):
|
||||
TCPDUMP.terminate()
|
||||
else:
|
||||
SwitchCalcTester().cmdloop()
|
||||
Loading…
Add table
Add a link
Reference in a new issue