Commit d9486a08 by David Hancock

Eliminate unnecessary HP4C class variables, explore mapping problem.

In parserSample02, I illustrate an issue that will be difficult to resolve: each path through the parse tree could result in a different mapping between HyPer4's consolidated extracted.data field and the source .p4's header fields. Thus has several implications: 1) tset_control_state_nextbits is insufficient as it incorrectly assumes that of all paths leading to a given parse state, those paths that incur the same bit extraction requirement prior to entering the parse state may all be represented by this value (the number of bits that have been extracted). This is incorrect because for some paths the number may represent explicit 'extract' statements while for other paths the number may include (or completely consist of) support for handling 'current' expressions in preceding parse states' return statements. 2) We will have to store each possible extracted.data -> source.p4 field mapping, indexed by the final path taken through the parse tree from start to ingress, and for each possible path incurring a different mapping, we will have to supply different match table entries, meaning the path ID will have to be added to the match fields, resulting in a multiplication of the memory required for emulating source.p4 table entries. 3) Back in the parse tree compilation, we will have to deal with implications for issuing the correct tset_inspect_XX_XX entries, where different paths may require different entries and even different tset_inspect_XX_XX tables (if the different mappings mean the select expression, in the parse state's return statement, has to look at different sets of bytes crossing tset_inspect_XX_XX boundaries).
parent f6253030
......@@ -38,12 +38,9 @@ class HP4C:
def __init__(self, h):
self.actionUIDs = {}
self.parseStateUIDs = {}
self.tables = OrderedDict()
self.actioncounter = 0
self.tablecounter = 0
self.tableUIDs = OrderedDict()
self.bits_needed_local = {}
self.bits_needed_total = {}
self.bits_needed_currents = {}
self.tset_control_state_nextbits = {}
self.commands = []
self.h = h
......@@ -164,8 +161,6 @@ class HP4C:
mparams,
aparams))
# Time to change the paradigm for this function s.t. it computes
# the offset from entry to exit
def collect_local_bits_needed(self, state):
numbits = 0
......@@ -189,14 +184,13 @@ class HP4C:
print("ERROR: Unknown directive in return statement: %s" % state.return_statement[0])
exit()
self.bits_needed_currents[state] = maxcurr
self.bits_needed_local[state] = numbits
self.bits_needed_local[state] = (numbits, maxcurr)
def collect_total_bits_needed(self, state, preceding_states):
numbits = self.bits_needed_local[state]
numbits = self.bits_needed_local[state][0]
for precstate in preceding_states:
numbits += self.bits_needed_local[precstate]
numbits -= self.bits_needed_currents[precstate]
numbits += self.bits_needed_local[precstate][0]
numbits -= self.bits_needed_local[precstate][1]
self.bits_needed_total[(state, tuple(preceding_states))] = numbits
next_states = []
......@@ -220,11 +214,12 @@ class HP4C:
self.collect_total_bits_needed(next_state, next_preceding_states)
def collectActions(self):
i = 0
for table in self.h.p4_tables.values():
for action in table.actions:
if action not in self.actionUIDs:
self.actioncounter += 1
self.actionUIDs[action] = self.actioncounter
i += 1
self.actionUIDs[action] = i
# if first.match_fields[0][1] == p4_match_types.P4_MATCH_EXACT:
......@@ -250,12 +245,13 @@ class HP4C:
dfs_walk(self.h.p4_ingress_ptr.keys()[0])
order.reverse()
i = 0
for table in order:
self.tablecounter += 1
self.tables[table] = self.tablecounter
i += 1
self.tableUIDs[table] = i
def printTables(self):
for table in self.tables.keys():
for table in self.tableUIDs.keys():
print(table.name)
def main():
......
header_type ext_t {
fields {
data : 8;
}
}
header ext_t ext[100];
parser start {
extract(ext[next]);
return select(ext[0]) {
0x00: p_A;
0x01: p_B;
default: ingress;
}
}
parser p_A {
extract(ext[next]);
return p_C;
}
parser p_B {
return select(current(0, 8)) {
0x00: p_C;
default: ingress;
}
}
parser p_C {
extract(ext[next]);
return ingress;
}
control ingress {
}
/*
Say we have 'real' headers P, Q, R, each one byte.
After start, we have header P. Based on the value of the single field within
P, we proceed to p_A or p_B.
In p_A, we extract Q.
In p_B, we extract nothing.
In p_C, we extract R. But mapping R to the correct element in ext depends on
whether the preceding state was p_A or p_B. If p_A, R is at ext[2]. If p_B,
R is at ext[1].
But notice how because of p_B's current expression in its return statement,
when running in HyPer4, we arrive at p_C with the same number of bits extracted.
To solve this, we can represent each parse_node with multiple IDs, each
corresponding to a different path.
The implication is that we will need multiple entries for a tset_inspect_XX_XX
table to represent a select statement in a parse state, where each entry shifts
the values to look for to different ext elements, as required by each path
preceding the parse state. What's more, the shift may cross tset_inspect_XX_XX
boundaries.
I worry, too, about maintaining the ext -> represented header field mapping for
use by the ingress pipeline. We may need to add one more match parameter to
each table: the final parse ID. This parse ID may serve as a lookup into a
conceptual data structure storing all possible mappings.
By doing this, we multiply the number of table entries required.
*/
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment