Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ycai
simbricks
Commits
d1826c0e
Commit
d1826c0e
authored
Oct 03, 2022
by
Jialin Li
Browse files
add mem_switch p4 control program
parent
f7051bf0
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
214 additions
and
0 deletions
+214
-0
sims/net/tofino/p4/mem_switch_setup.py
sims/net/tofino/p4/mem_switch_setup.py
+214
-0
No files found.
sims/net/tofino/p4/mem_switch_setup.py
0 → 100644
View file @
d1826c0e
from
bfrtcli
import
*
class
mem_switch
():
#
# Helper Functions to deal with ports
#
def
devport
(
self
,
pipe
,
port
):
return
((
pipe
&
3
)
<<
7
)
|
(
port
&
0x7F
)
def
pipeport
(
self
,
dp
):
return
((
dp
&
0x180
)
>>
7
,
(
dp
&
0x7F
))
def
mcport
(
self
,
pipe
,
port
):
return
pipe
*
72
+
port
def
devport_to_mcport
(
self
,
dp
):
return
self
.
mcport
(
*
self
.
pipeport
(
dp
))
# This is a useful bfrt_python function that should potentially allow one
# to quickly clear all the logical tables (including the fixed ones) in
# their data plane program.
#
# This function can clear all P4 tables and later other fixed objects
# (once proper BfRt support is added). As of SDE-9.2.0 the support is mixed.
# As a result the function contains some workarounds.
def
clear_all
(
self
,
verbose
=
True
,
batching
=
True
,
clear_ports
=
False
):
table_list
=
bfrt
.
info
(
return_info
=
True
,
print_info
=
False
)
# Remove port tables from the list
port_types
=
[
'PORT_CFG'
,
'PORT_FRONT_PANEL_IDX_INFO'
,
'PORT_HDL_INFO'
,
'PORT_STR_INFO'
]
if
not
clear_ports
:
for
table
in
list
(
table_list
):
if
table
[
'type'
]
in
port_types
:
table_list
.
remove
(
table
)
# The order is important. We do want to clear from the top,
# i.e. delete objects that use other objects. For example,
# table entries use selector groups and selector groups
# use action profile members.
#
# Same is true for the fixed tables. However, the list of
# table types grows, so we will first clean the tables we
# know and then clear the rest
for
table_types
in
([
'MATCH_DIRECT'
,
'MATCH_INDIRECT_SELECTOR'
],
[
'SELECTOR'
],
[
'ACTION_PROFILE'
],
[
'PRE_MGID'
],
[
'PRE_ECMP'
],
[
'PRE_NODE'
],
[]):
# This is catch-all
for
table
in
list
(
table_list
):
if
table
[
'type'
]
in
table_types
or
len
(
table_types
)
==
0
:
try
:
if
verbose
:
print
(
'Clearing table {:<40} ... '
.
format
(
table
[
'full_name'
]),
end
=
''
,
flush
=
True
)
table
[
'node'
].
clear
(
batch
=
batching
)
table_list
.
remove
(
table
)
if
verbose
:
print
(
'Done'
)
use_entry_list
=
False
except
:
use_entry_list
=
True
# Some tables do not support clear(). Thus we'll try
# to get a list of entries and clear them one-by-one
if
use_entry_list
:
try
:
if
batching
:
bfrt
.
batch_begin
()
# This line can result in an exception,
# since # not all tables support get()
entry_list
=
table
[
'node'
].
get
(
regex
=
True
,
return_ents
=
True
,
print_ents
=
False
)
# Not every table supports delete() method.
# For those tables we'll try to push in an
# entry with everything being zeroed out
has_delete
=
hasattr
(
table
[
'node'
],
'delete'
)
if
entry_list
!=
-
1
:
if
has_delete
:
for
entry
in
entry_list
:
entry
.
remove
()
else
:
clear_entry
=
table
[
'node'
].
entry
()
for
entry
in
entry_list
:
entry
.
data
=
clear_entry
.
data
# We can still have an exception
# here, since not all tables
# support add()/mod()
entry
.
push
()
if
verbose
:
print
(
'Done'
)
else
:
print
(
'Empty'
)
table_list
.
remove
(
table
)
except
BfRtTableError
as
e
:
print
(
'Empty'
)
table_list
.
remove
(
table
)
except
Exception
as
e
:
# We can have in a number of ways: no get(),
# no add() etc. Another reason is that the
# table is read-only.
if
verbose
:
print
(
'Failed'
)
finally
:
if
batching
:
bfrt
.
batch_end
()
bfrt
.
complete_operations
()
def
__init__
(
self
,
default_ttl
=
60000
):
self
.
p4
=
bfrt
.
mem_switch
.
pipe
self
.
all_ports
=
[
port
.
key
[
b
'$DEV_PORT'
]
for
port
in
bfrt
.
port
.
port
.
get
(
regex
=
1
,
return_ents
=
True
,
print_ents
=
False
)]
self
.
l2_age_ttl
=
default_ttl
def
setup
(
self
):
self
.
clear_all
()
self
.
__init__
()
# Enable learning on SMAC
print
(
'Initializing learning on SMAC ... '
,
end
=
''
,
flush
=
True
)
try
:
self
.
p4
.
IngressDeparser
.
l2_digest
.
callback_deregister
()
except
:
pass
self
.
p4
.
IngressDeparser
.
l2_digest
.
callback_register
(
self
.
learning_cb
)
print
(
'Done'
)
# Disable aging on SMAC
print
(
'Inializing Aging on SMAC ... '
,
end
=
''
,
flush
=
True
)
try
:
self
.
p4
.
Ingress
.
smac
.
idle_table_set_notify
(
enable
=
False
,
callback
=
None
)
except
:
pass
print
(
'Done'
)
@
staticmethod
def
aging_cb
(
dev_id
,
pipe_id
,
direction
,
parser_id
,
entry
):
smac
=
bfrt
.
mem_switch
.
pipe
.
Ingress
.
smac
dmac
=
bfrt
.
mem_switch
.
pipe
.
Ingress
.
dmac
mac_addr
=
entry
.
key
[
b
'hdr.ethernet.src_addr'
]
print
(
'Aging out: MAC: {}'
.
format
(
mac
(
mac_addr
)))
entry
.
remove
()
# from smac
try
:
dmac
.
delete
(
dst_addr
=
mac_addr
)
except
:
print
(
'WARNING: Could not find the matching DMAC entry'
)
@
staticmethod
def
learning_cb
(
dev_id
,
pipe_id
,
direction
,
parser_id
,
session
,
msg
):
smac
=
bfrt
.
mem_switch
.
pipe
.
Ingress
.
smac
dmac
=
bfrt
.
mem_switch
.
pipe
.
Ingress
.
dmac
for
digest
in
msg
:
port
=
digest
[
'ingress_port'
]
mac_move
=
digest
[
'mac_move'
]
mac_addr
=
digest
[
'src_mac'
]
old_port
=
port
^
mac_move
# Because mac_move = ingress_port ^ port
print
(
'MAC: {}, Port={}'
.
format
(
mac
(
mac_addr
),
port
),
end
=
''
)
if
mac_move
!=
0
:
print
(
'(Move from port={})'
.
format
(
old_port
))
else
:
print
(
'(New)'
)
# Since we do not have access to self, we have to use
# the hardcoded value for the TTL :(
smac
.
entry_with_smac_hit
(
src_addr
=
mac_addr
,
port
=
port
,
is_static
=
False
,
ENTRY_TTL
=
60000
).
push
()
dmac
.
entry_with_dmac_unicast
(
dst_addr
=
mac_addr
,
port
=
port
).
push
()
return
0
def
l2_add_smac_drop
(
self
,
vid
,
mac_addr
):
mac_addr
=
mac
(
mac_addr
)
self
.
p4
.
Ingress
.
smac
.
entry_with_smac_drop
(
src_addr
=
mac_addr
).
push
()
def
set_bcast
():
all_ports
=
[
p
for
p
in
range
(
8
)]
# Broadcast
bfrt
.
pre
.
node
.
entry
(
MULTICAST_NODE_ID
=
0
,
MULTICAST_RID
=
0
,
MULTICAST_LAG_ID
=
[],
DEV_PORT
=
all_ports
).
push
()
bfrt
.
pre
.
mgid
.
entry
(
MGID
=
1
,
MULTICAST_NODE_ID
=
[
0
],
MULTICAST_NODE_L1_XID_VALID
=
[
False
],
MULTICAST_NODE_L1_XID
=
[
0
]).
push
()
### Setup mem switch
msw
=
mem_switch
(
default_ttl
=
10000
)
msw
.
setup
()
msw
.
l2_add_smac_drop
(
1
,
'00:00:00:00:00:00'
)
set_bcast
()
bfrt
.
complete_operations
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment