diff --git a/dash-pipeline/SAI/templates/saiapi.cpp.j2 b/dash-pipeline/SAI/templates/saiapi.cpp.j2 index 573aabbe3..b2cd171d0 100644 --- a/dash-pipeline/SAI/templates/saiapi.cpp.j2 +++ b/dash-pipeline/SAI/templates/saiapi.cpp.j2 @@ -59,15 +59,16 @@ static sai_status_t dash_sai_create_{{ table.name }}( matchActionEntry->set_table_id(tableId); - {% if table['keys'] | length== 1 %} - // SAI object table with single P4 key - object ID itself is the P4 table key - // Generate a SAI object ID and fill it as the P4 table key - auto mf = matchActionEntry->add_match(); - mf->set_field_id({{table['keys'][0].id}}); - auto mf_exact = mf->mutable_exact(); - //{{table['keys'][0].field}}SetVal(objId, mf_exact, {{table['keys'][0].bitwidth}}); - {{table['keys'][0].field}}SetVal(static_cast(objId), mf_exact, {{ table['keys'][0].bitwidth }}); - {% else %} + {% for key in table['keys'] %} + {% if key.is_object_key %} + auto key_mf = matchActionEntry->add_match(); + key_mf->set_field_id({{key.id}}); + auto key_mf_exact = key_mf->mutable_exact(); + // {{key.field}}SetVal(objId, key_mf_exact, {{key.bitwidth}}); + {{key.field}}SetVal(static_cast(objId), key_mf_exact, {{ key.bitwidth }}); + {% endif %} + {% endfor %} + // SAI object table with multiple P4 table keys // Copy P4 table keys from appropriate SAI attributes for (uint32_t i = 0; i < attr_count; i++) @@ -79,6 +80,7 @@ static sai_status_t dash_sai_create_{{ table.name }}( switch(attr_list[i].id) { {% for key in table['keys'] %} + {% if not key.is_object_key %} case SAI_{{ table.name | upper }}_ATTR_{{ key.name | upper }}: { auto mf = matchActionEntry->add_match(); @@ -138,6 +140,7 @@ static sai_status_t dash_sai_create_{{ table.name }}( {% endif %} break; } + {% endif%} {% endfor %} {% if table['keys'] | selectattr('match_type', 'ne', 'exact') | list | length > 0 %} {% if table['keys'] | selectattr('match_type', 'eq', 'lpm') | list | length == 0 %} @@ -154,7 +157,6 @@ static sai_status_t dash_sai_create_{{ table.name }}( break; } } - {% endif %} // If there is only one action, simply set it. // Else, search in the attrs. diff --git a/dash-pipeline/SAI/utils/dash_p4/dash_p4_table.py b/dash-pipeline/SAI/utils/dash_p4/dash_p4_table.py index 103a2332c..67a7c5424 100644 --- a/dash-pipeline/SAI/utils/dash_p4/dash_p4_table.py +++ b/dash-pipeline/SAI/utils/dash_p4/dash_p4_table.py @@ -372,9 +372,13 @@ def create_sai_stats(self, sai_api: SaiApi) -> None: def create_sai_attributes(self, sai_api: SaiApi) -> None: # If the table is an object with more one key (table entry id), we need to add all the keys into the attributes. - if self.is_object == "true" and len(self.keys) > 1: - for key in self.keys: - sai_api.attributes.extend(key.to_sai_attribute(self.name, create_only=True)) + if self.is_object == "true": + if len(self.keys) == 1: + self.keys[0].is_object_key = True + elif len(self.keys) > 1: + for key in self.keys: + if not key.is_object_key: + sai_api.attributes.extend(key.to_sai_attribute(self.name, create_only=True)) # Add all the action parameters into the attributes. for attr in self.sai_attributes: diff --git a/dash-pipeline/SAI/utils/dash_p4/dash_p4_table_attribute.py b/dash-pipeline/SAI/utils/dash_p4/dash_p4_table_attribute.py index 79bd50bee..86699cb4e 100644 --- a/dash-pipeline/SAI/utils/dash_p4/dash_p4_table_attribute.py +++ b/dash-pipeline/SAI/utils/dash_p4/dash_p4_table_attribute.py @@ -19,6 +19,7 @@ def __init__(self): self.skipattr: Optional[str] = None self.match_type: str = "" self.validonly: Optional[str] = None + self.is_object_key: bool = False def _parse_sai_table_attribute_annotation( self, p4rt_anno_list: Dict[str, Any] @@ -66,6 +67,8 @@ def _parse_sai_table_attribute_annotation( self.match_type = str(kv["value"]["stringValue"]) elif kv["key"] == "validonly": self.validonly = str(kv["value"]["stringValue"]) + elif kv["key"] == "is_object_key": + self.is_object_key = kv["value"]["stringValue"] == "true" else: raise ValueError("Unknown attr annotation " + kv["key"]) diff --git a/dash-pipeline/bmv2/dash_metadata.p4 b/dash-pipeline/bmv2/dash_metadata.p4 index 044aa1c52..2defa9610 100644 --- a/dash-pipeline/bmv2/dash_metadata.p4 +++ b/dash-pipeline/bmv2/dash_metadata.p4 @@ -322,6 +322,9 @@ struct metadata_t { encap_data_t tunnel_data; overlay_rewrite_data_t overlay_data; bit<16> dash_tunnel_id; + bit<16> dash_tunnel_member_index; + bit<16> dash_tunnel_member_id; + bit<16> dash_tunnel_next_hop_id; bit<32> meter_class; bit<8> local_region_id; } diff --git a/dash-pipeline/bmv2/stages/tunnel_stage.p4 b/dash-pipeline/bmv2/stages/tunnel_stage.p4 index bf8b878ab..e1b7bfe9c 100644 --- a/dash-pipeline/bmv2/stages/tunnel_stage.p4 +++ b/dash-pipeline/bmv2/stages/tunnel_stage.p4 @@ -6,18 +6,19 @@ control tunnel_stage( inout metadata_t meta) { action set_tunnel_attrs( - @SaiVal[type="sai_ip_address_t"] - IPv4Address dip, - @SaiVal[type="sai_dash_encapsulation_t", default_value="SAI_DASH_ENCAPSULATION_VXLAN"] - dash_encapsulation_t dash_encapsulation, - bit<24> tunnel_key) { - push_action_static_encap(hdr = hdr, - meta = meta, - encap = dash_encapsulation, - vni = tunnel_key, - underlay_sip = hdr.u0_ipv4.src_addr, - underlay_dip = dip, - overlay_dmac = hdr.u0_ethernet.dst_addr); + @SaiVal[type="sai_ip_address_t"] + IPv4Address dip, + @SaiVal[type="sai_dash_encapsulation_t", default_value="SAI_DASH_ENCAPSULATION_VXLAN"] + dash_encapsulation_t dash_encapsulation, + bit<24> tunnel_key) + { + push_action_static_encap(hdr = hdr, + meta = meta, + encap = dash_encapsulation, + vni = tunnel_key, + underlay_sip = hdr.u0_ipv4.src_addr, + underlay_dip = dip, + overlay_dmac = hdr.u0_ethernet.dst_addr); } @SaiTable[name = "dash_tunnel", api = "dash_tunnel", order = 0, isobject="true"] @@ -31,8 +32,84 @@ control tunnel_stage( } } + action select_tunnel_member( + bit<16> dash_tunnel_member_id) + { + meta.dash_tunnel_member_id = dash_tunnel_member_id; + } + + // This table is a helper table that used to select the tunnel member based on the index. + // The entry of this table is created by DASH data plane app, when the tunnel member is created. + @SaiTable[ignored = "true"] + table tunnel_member_select { + key = { + meta.dash_tunnel_member_index : exact @SaiVal[type="sai_object_id_t", is_object_key="true"]; + meta.dash_tunnel_id : exact @SaiVal[type="sai_object_id_t"]; + } + + actions = { + select_tunnel_member; + } + } + + action set_tunnel_member_attrs( + @SaiVal[type="sai_object_id_t"] bit<16> dash_tunnel_id, + @SaiVal[type="sai_object_id_t"] bit<16> dash_tunnel_next_hop_id) + { + // dash_tunnel_id in tunnel member must match the metadata + assert(meta.dash_tunnel_id == dash_tunnel_id); + + meta.dash_tunnel_next_hop_id = dash_tunnel_next_hop_id; + } + + @SaiTable[name = "dash_tunnel_member", api = "dash_tunnel", order = 1, isobject="true"] + table tunnel_member { + key = { + meta.dash_tunnel_member_id : exact @SaiVal[type="sai_object_id_t", is_object_key="true"]; + } + + actions = { + set_tunnel_member_attrs; + } + } + + action set_tunnel_next_hop_attrs( + @SaiVal[type="sai_ip_address_t"] + IPv4Address dip, + @SaiVal[type="sai_dash_encapsulation_t", default_value="SAI_DASH_ENCAPSULATION_VXLAN"] + dash_encapsulation_t dash_encapsulation, + bit<24> tunnel_key) + { + push_action_static_encap(hdr = hdr, + meta = meta, + encap = dash_encapsulation, + vni = tunnel_key, + underlay_sip = hdr.u0_ipv4.src_addr, + underlay_dip = dip, + overlay_dmac = hdr.u0_ethernet.dst_addr); + } + + @SaiTable[name = "dash_tunnel_next_hop", api = "dash_tunnel", order = 2, isobject="true"] + table tunnel_next_hop{ + key = { + meta.dash_tunnel_next_hop_id : exact @SaiVal[type="sai_object_id_t"]; + } + + actions = { + set_tunnel_next_hop_attrs; + } + } + apply { tunnel.apply(); + + // TODO: Calculate based on packet and tunnel member size. + // Currently, we will have to use 0 here, because we don't know how many tunnel members we will have. + meta.dash_tunnel_member_index = 0; + tunnel_member_select.apply(); + + tunnel_member.apply(); + tunnel_next_hop.apply(); } }