def dump_header_types(json_dict, hlir): header_types = [] id_ = 0 for name, p4_header in hlir.p4_headers.items(): header_type_dict = OrderedDict() header_type_dict["name"] = name header_type_dict["id"] = id_ id_ += 1 fixed_width = 0 for field, bit_width in p4_header.layout.items(): if bit_width != p4.P4_AUTO_WIDTH: fixed_width += bit_width fields = [] for field, bit_width in p4_header.layout.items(): if bit_width == p4.P4_AUTO_WIDTH: bit_width = "*" fields.append([field, bit_width]) header_type_dict["fields"] = fields length_exp = None max_length = None if p4_header.flex_width: length_exp = header_length_exp_format(p4_header.length, zip(*fields)[0]) # bm expects a length in bits length_exp = p4.p4_expression(length_exp, "*", 8) length_exp = p4.p4_expression(length_exp, "-", fixed_width) length_exp = dump_expression(length_exp) max_length = p4_header.max_length header_type_dict["length_exp"] = length_exp header_type_dict["max_length"] = max_length header_types.append(header_type_dict) json_dict["header_types"] = header_types
def header_length_exp_format(p4_expression, fields): def find_idx(name): for idx, field in enumerate(fields): if name == field: return idx return -1 if type(p4_expression) is p4.p4_expression: new_expr = p4.p4_expression(op=p4_expression.op) new_expr.left = header_length_exp_format(p4_expression.left, fields) new_expr.right = header_length_exp_format(p4_expression.right, fields) return new_expr elif type(p4_expression) is str: # refers to field in same header idx = find_idx(p4_expression) assert (idx >= 0) # trick so that dump_expression uses local for this return p4.p4_signature_ref(idx) else: return p4_expression
def header_length_exp_format(p4_expression, fields): def find_idx(name): for idx, field in enumerate(fields): if name == field: return idx return -1 if type(p4_expression) is p4.p4_expression: new_expr = p4.p4_expression(op=p4_expression.op) new_expr.left = header_length_exp_format(p4_expression.left, fields) new_expr.right = header_length_exp_format(p4_expression.right, fields) return new_expr elif type(p4_expression) is str: # refers to field in same header idx = find_idx(p4_expression) assert(idx >= 0) # trick so that dump_expression uses local for this return p4.p4_signature_ref(idx) else: return p4_expression
def valid_expression(hi): if isinstance(hi, p4.p4_field): hi = hi.instance return p4.p4_expression(None, "valid", hi)
def dump_actions(json_dict, hlir): actions = [] action_id = 0 table_actions_set = set() for _, table in hlir.p4_tables.items(): for action in table.actions: table_actions_set.add(action) for action in table_actions_set: action_dict = OrderedDict() action_dict["name"] = action.name action_dict["id"] = action_id action_id += 1 runtime_data = [] param_with_bit_widths = OrderedDict() for param, width in zip(action.signature, action.signature_widths): if not width: # pragma: no cover LOG_CRITICAL("unused parameter in action def") param_with_bit_widths[param] = width param_dict = OrderedDict() param_dict["name"] = param param_dict["bitwidth"] = width runtime_data.append(param_dict) action_dict["runtime_data"] = runtime_data primitives = [] for call in action.flat_call_sequence: primitive_dict = OrderedDict() primitive_name = call[0].name primitive_dict["op"] = primitive_name args = call[1] # backwards compatibility with older P4 programs if primitive_name == "modify_field" and len(args) == 3: LOG_WARNING( "Your P4 program uses the modify_field() action primitive " "with 3 arguments (aka masked modify), bmv2 does not " "support it anymore and this compiler will replace your " "modify_field(a, b, c) with " "modify_field(a, (a & ~c) | (b & c))") Lexpr = p4.p4_expression(args[0], "&", p4.p4_expression(None, "~", args[2])) Rexpr = p4.p4_expression(args[1], "&", args[2]) new_arg = p4.p4_expression(Lexpr, "|", Rexpr) args = [args[0], new_arg] primitive_args = [] for arg in args: arg_dict = OrderedDict() if type(arg) is int or type(arg) is long: arg_dict["type"] = "hexstr" arg_dict["value"] = hex(arg) elif type(arg) is p4.p4_field: arg_dict["type"] = "field" arg_dict["value"] = format_field_ref(arg) elif type(arg) is p4.p4_header_instance: arg_dict["type"] = "header" arg_dict["value"] = arg.name elif type(arg) is p4.p4_signature_ref: arg_dict["type"] = "runtime_data" arg_dict["value"] = arg.idx elif type(arg) is p4.p4_field_list: # hack for generate_digest calls if primitive_name == "generate_digest": id_ = field_list_to_learn_id(arg) elif "clone" in primitive_name or\ primitive_name in {"resubmit", "recirculate"}: id_ = field_list_to_id(arg) arg_dict["type"] = "hexstr" arg_dict["value"] = hex(id_) elif type(arg) is p4.p4_field_list_calculation: arg_dict["type"] = "calculation" arg_dict["value"] = arg.name elif type(arg) is p4.p4_meter: arg_dict["type"] = "meter_array" arg_dict["value"] = arg.name elif type(arg) is p4.p4_counter: arg_dict["type"] = "counter_array" arg_dict["value"] = arg.name elif type(arg) is p4.p4_register: arg_dict["type"] = "register_array" arg_dict["value"] = arg.name elif type(arg) is p4.p4_expression: arg_dict["type"] = "expression" arg_dict["value"] = dump_expression(arg) else: # pragma: no cover LOG_CRITICAL("action arg type is not supported: ", type(arg)) if primitive_name in {"push", "pop"} and\ arg_dict["type"] == "header": arg_dict["type"] = "header_stack" arg_dict["value"] = re.sub(r'\[.*\]', '', arg_dict["value"]) primitive_args.append(arg_dict) primitive_dict["parameters"] = primitive_args primitives.append(primitive_dict) action_dict["primitives"] = primitives actions.append(action_dict) json_dict["actions"] = actions