def build(self, hlir): for idx, set_statement in enumerate(self.set_statements): metadata_field_ref = set_statement[1] metadata_value = set_statement[2] metadata_field_ref = p4_field_reference(hlir, metadata_field_ref) # metadata_value can either be latest.*, or *.* or int or # (*, *) (for current) if type(metadata_value) is int: metadata_value = metadata_value elif type(metadata_value) is tuple: metadata_value = (metadata_value[1], metadata_value[2]) elif type(metadata_value) is str: hdr, field = metadata_value.split(".") if hdr == "latest": metadata_value = p4_field_reference( hlir, self.latest_extraction.name + "." + field ) else: metadata_value = p4_field_reference(hlir, metadata_value) else: assert(False) self.set_statements[idx] = (parse_call.set, metadata_field_ref, metadata_value) if self.return_or_drop != P4_PARSER_DROP: self.return_or_drop = hlir.p4_control_flows[self.return_or_drop]
def build_return(self, hlir): return_type = self.return_statement[0] if return_type == "immediate": next_state = self.resolve_parse_target(hlir, self.return_statement[1]) self.branch_on = [] self.branch_to = OrderedDict({P4_DEFAULT: next_state}) elif return_type == "select": select_exp = self.return_statement[1] select_cases = self.return_statement[2] # select_exp is a list of field_references self.branch_on = [] for field_ref in select_exp: if type(field_ref) is tuple: # current field_ref = (field_ref[0], field_ref[1]) elif field_ref[:6] == "latest": field_ref = p4_field_reference( hlir, self.latest_extraction.name + "." + field_ref[7:]) elif "." in field_ref: field_ref = p4_field_reference(hlir, field_ref) self.branch_on.append(field_ref) self.branch_to = OrderedDict() for case in select_cases: value_list = case[0] next_state = self.resolve_parse_target(hlir, case[1]) for value_or_masked in value_list: value_type = value_or_masked[0] if value_type == "value_set": # still need to check that this is a valid reference value_set_name = value_or_masked[1] branch_case = hlir.p4_parse_value_sets[value_set_name] elif value_type == "default": branch_case = P4_DEFAULT elif value_type == "value": branch_case = value_or_masked[1] elif value_type == "masked_value": branch_case = (value_or_masked[1], value_or_masked[2]) self.branch_to[branch_case] = next_state else: assert (False)
def build_return (self, hlir): return_type = self.return_statement[0] if return_type == "immediate": next_state = self.resolve_parse_target(hlir, self.return_statement[1]) self.branch_on = [] self.branch_to = OrderedDict({P4_DEFAULT:next_state}) elif return_type == "select": select_exp = self.return_statement[1] select_cases = self.return_statement[2] # select_exp is a list of field_references self.branch_on = [] for field_ref in select_exp: if type(field_ref) is tuple: # current field_ref = (field_ref[0], field_ref[1]) elif field_ref[:6] == "latest": field_ref = p4_field_reference( hlir, self.latest_extraction.name + "." + field_ref[7:] ) elif "." in field_ref: field_ref = p4_field_reference(hlir, field_ref) self.branch_on.append(field_ref) self.branch_to = OrderedDict() for case in select_cases: value_list = case[0] next_state = self.resolve_parse_target(hlir, case[1]) for value_or_masked in value_list: value_type = value_or_masked[0] if value_type == "value_set": # still need to check that this is a valid reference value_set_name = value_or_masked[1] branch_case = hlir.p4_parse_value_sets[value_set_name] elif value_type == "default": branch_case = P4_DEFAULT elif value_type == "value": branch_case = value_or_masked[1] elif value_type == "masked_value": branch_case = (value_or_masked[1], value_or_masked[2]) self.branch_to[branch_case] = next_state else: assert(False)
def build(self, hlir): self.register = p4_stateful.p4_register.get_from_hlir( hlir, self.register_name) # I thought this was done earlier but it appears that string idices are # never resolved before this point if type(self.idx) is str: self.idx = p4_headers.p4_field_reference(hlir, self.idx)
def build_body(self, hlir): for idx, call in enumerate(self.call_sequence): call_type = call[0] if call_type == "extract": extract_ref = call[1] extract_ref = hlir.p4_header_instances[extract_ref] self.latest_extraction = extract_ref self.call_sequence[idx] = (parse_call.extract, extract_ref) elif call_type == "set_metadata": metadata_field_ref = call[1] metadata_value = call[2] metadata_field_ref = p4_field_reference( hlir, metadata_field_ref) # metadata_value can either be latest.*, or *.* or int or # (*, *) (for current) if type(metadata_value) is int: metadata_value = metadata_value elif type(metadata_value) is tuple: metadata_value = (metadata_value[1], metadata_value[2]) elif type(metadata_value) is str: hdr, field = metadata_value.split(".") if hdr == "latest": metadata_value = p4_field_reference( hlir, self.latest_extraction.name + "." + field) else: metadata_value = p4_field_reference( hlir, metadata_value) elif type(metadata_value) is p4_expression: metadata_value = metadata_value metadata_value.resolve_names(hlir) else: print type(metadata_value) assert (False) self.call_sequence[idx] = (parse_call.set, metadata_field_ref, metadata_value)
def build_body (self, hlir): for idx, call in enumerate(self.call_sequence): call_type = call[0] if call_type == "extract": extract_ref = call[1] extract_ref = hlir.p4_header_instances[extract_ref] self.latest_extraction = extract_ref self.call_sequence[idx] = (parse_call.extract, extract_ref) elif call_type == "set_metadata": metadata_field_ref = call[1] metadata_value = call[2] metadata_field_ref = p4_field_reference(hlir, metadata_field_ref) # metadata_value can either be latest.*, or *.* or int or # (*, *) (for current) if type(metadata_value) is int: metadata_value = metadata_value elif type(metadata_value) is tuple: metadata_value = (metadata_value[0], metadata_value[1]) elif type(metadata_value) is str: hdr, field = metadata_value.split(".") if hdr == "latest": metadata_value = p4_field_reference( hlir, self.latest_extraction.name + "." + field ) else: metadata_value = p4_field_reference(hlir, metadata_value) elif type(metadata_value) is p4_expression: metadata_value = metadata_value metadata_value.resolve_names(hlir) else: print type(metadata_value) assert(False) self.call_sequence[idx] = (parse_call.set, metadata_field_ref, metadata_value)
def build_return (self, hlir): return_type = self.return_statement[0] if return_type == "immediate": next_state = self.resolve_parse_target(hlir, self.return_statement[1]) self.branch_on = [] self.branch_to = OrderedDict({P4_DEFAULT:next_state}) elif return_type == "select": select_exp = self.return_statement[1] select_cases = self.return_statement[2] # select_exp is a list of field_references self.branch_on = [] self.bitwidths = [] for field_ref in select_exp: if type(field_ref) is tuple: # current field_ref = (field_ref[0], field_ref[1]) self.bitwidths.append(field_ref[1]) elif field_ref[:6] == "latest": field_ref = p4_field_reference( hlir, self.latest_extraction.name + "." + field_ref[7:] ) self.bitwidths.append(field_ref.width) elif "." in field_ref: field_ref = p4_field_reference(hlir, field_ref) self.bitwidths.append(field_ref.width) self.branch_on.append(field_ref) self.branch_to = OrderedDict() normalized_values = [] def mask(): width = sum(self.bitwidths) return (1 << width) - 1 def normalize(value): return value & mask() def validate_normalized(normalized, original): if P4_DEFAULT in normalized_values: p4_compiler_msg( "Select case '{}' in state '{}' appears after 'default' case and will be ignored".format(original, self.name), self.filename, self.lineno, logging.WARN) return False if normalized == P4_DEFAULT: return True if isinstance(normalized, p4_parse_value_set): if normalized in normalized_values: p4_compiler_msg( "Select case '{}' in state '{}' is a duplicate and will be ignored".format(original, self.name), self.filename, self.lineno, logging.WARN) return False return True for existing in normalized_values: if isinstance(existing, p4_parse_value_set): continue v1, m1 = existing v2, m2 = normalized # This is not complete; detecting that "v2 mask m2" is # included in "v1 mask m1" is non-trivial so we only check # for the most basic case if ((v2 & m1) == (v1 & m1)) and m2 == mask(): p4_compiler_msg( "Select case '{}' in state '{}' is redundant with a previous one and will be ignored".format(original, self.name), self.filename, self.lineno, logging.WARN) return False return True for case in select_cases: value_list = case[0] next_state = self.resolve_parse_target(hlir, case[1]) for value_or_masked in value_list: value_type = value_or_masked[0] if value_type == "value_set": # still need to check that this is a valid reference value_set_name = value_or_masked[1] branch_case = hlir.p4_parse_value_sets[value_set_name] normalized = branch_case original = value_set_name elif value_type == "default": branch_case = P4_DEFAULT normalized = branch_case original = "default" elif value_type == "value": branch_case = value_or_masked[1] normalized = (normalize(value_or_masked[1]), mask()) original = "{}".format(value_or_masked[1]) elif value_type == "masked_value": branch_case = (value_or_masked[1], value_or_masked[2]) normalized = (normalize(value_or_masked[1]), normalize(value_or_masked[2])) original = "{} mask {}".format( value_or_masked[1], value_or_masked[2]) if validate_normalized(normalized, original): normalized_values.append(normalized) # We should really not be adding this case to the branch_to # dictionary if validate_normalized returned False. However, # a lot of existing P4 code relies on so-called "dummy # transitions" in parser states which happen after the # DEFAULT transition. These dummy transitions are used to # increase the number of edges in the parse graph and # therefore constrain the topological sorting of headers # which determines the deparser flow. if branch_case not in self.branch_to: self.branch_to[branch_case] = next_state else: assert(False)
def build_body(self, hlir): for idx, call in enumerate(self.call_sequence): call_type = call[0] if call_type == "extract": extract_ref = call[1] extract_ref = hlir.p4_header_instances[extract_ref] self.latest_extraction = extract_ref self.call_sequence[idx] = (parse_call.extract, extract_ref) elif call_type == "set_metadata": metadata_field_ref = call[1] metadata_value = call[2] metadata_field_ref = p4_field_reference( hlir, metadata_field_ref) # metadata_value can either be latest.*, or *.* or int or # (*, *) (for current) if type(metadata_value) is int: metadata_value = metadata_value elif type(metadata_value) is tuple: metadata_value = (metadata_value[0], metadata_value[1]) elif type(metadata_value) is str: hdr, field = metadata_value.split(".") if hdr == "latest": metadata_value = p4_field_reference( hlir, self.latest_extraction.name + "." + field) else: metadata_value = p4_field_reference( hlir, metadata_value) elif type(metadata_value) is p4_expression: metadata_value = metadata_value metadata_value.resolve_names(hlir) else: print type(metadata_value) assert (False) self.call_sequence[idx] = (parse_call.set, metadata_field_ref, metadata_value) elif call_type == "method": bbox = hlir.p4_extern_instances.get(call[1], None) if bbox: method_obj = bbox.methods.get(call[2], None) if method_obj: call_args = call[3] try: method_obj.validate_arguments(hlir, call_args) except p4_compiler_msg as p: p.filename = self.filename p.lineno = self.lineno raise self.call_sequence[idx] = (parse_call.method, method_obj, call_args) else: raise p4_compiler_msg( "Reference to undefined method '%s.%s'" % (bbox.name, call[2]), self.filename, self.lineno) else: raise p4_compiler_msg( "Reference to undefined extern '%s'" % call[1], self.filename, self.lineno)