Repository: sonic-net/DASH
Pull request #672: [dash-p4] Add ENI mode and trusted vni stage
Author: login: jimmyzhai
Labels: name: Ready to merge?
Created: 2025-03-22T07:31:21Z | Merged: 2025-04-17T03:33:42Z

Referring to https://github.com/sonic-net/SONiC/pull/1911 and https://github.com/sonic-net/DASH/pull/665, to support FNIC pipeline, this PR adds the followings:
- ENI mode VM, FNIC
- ENI drop counter `eni_trusted_vni_entry_miss_drop`
- Action `set_inbound_direction` is not defaultonly at table `direction_lookup`
- table `global_trusted_vni` and `eni_trusted_vni`




Diff:
diff --git a/dash-pipeline/SAI/specs/dash_direction_lookup.yaml b/dash-pipeline/SAI/specs/dash_direction_lookup.yaml
index 9720a8ca1..de1f8761a 100644
--- a/dash-pipeline/SAI/specs/dash_direction_lookup.yaml
+++ b/dash-pipeline/SAI/specs/dash_direction_lookup.yaml
@@ -16,6 +16,10 @@ sai_apis:
       name: SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_OUTBOUND_DIRECTION
       description: ''
       value: '0'
+    - !!python/object:utils.sai_spec.sai_enum_member.SaiEnumMember
+      name: SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_INBOUND_DIRECTION
+      description: ''
+      value: '1'
   structs:
   - !!python/object:utils.sai_spec.sai_struct.SaiStruct
     name: sai_direction_lookup_entry_t
@@ -57,7 +61,8 @@ sai_apis:
     flags: CREATE_AND_SET
     object_name: null
     allow_null: false
-    valid_only: null
+    valid_only: SAI_DIRECTION_LOOKUP_ENTRY_ATTR_ACTION == SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_OUTBOUND_DIRECTION
+      or SAI_DIRECTION_LOOKUP_ENTRY_ATTR_ACTION == SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_INBOUND_DIRECTION
     is_vlan: false
     deprecated: false
   stats: []
@@ -87,3 +92,13 @@ sai_apis:
               bitwidth: 8
               ip_is_v6_field_id: 0
               skipattr: null
+        SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_INBOUND_DIRECTION: !!python/object:utils.sai_spec.sai_api_p4_meta.SaiApiP4MetaAction
+          name: SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_INBOUND_DIRECTION
+          id: 30583207
+          attr_params:
+            SAI_DIRECTION_LOOKUP_ENTRY_ATTR_DASH_ENI_MAC_OVERRIDE_TYPE: !!python/object:utils.sai_spec.sai_api_p4_meta.SaiApiP4MetaActionParam
+              id: 1
+              field: s32
+              bitwidth: 8
+              ip_is_v6_field_id: 0
+              skipattr: null
diff --git a/dash-pipeline/SAI/specs/dash_eni.yaml b/dash-pipeline/SAI/specs/dash_eni.yaml
index 6ae67b7be..7511f6654 100644
--- a/dash-pipeline/SAI/specs/dash_eni.yaml
+++ b/dash-pipeline/SAI/specs/dash_eni.yaml
@@ -653,6 +653,19 @@ sai_apis:
     valid_only: null
     is_vlan: false
     deprecated: false
+  - !!python/object:utils.sai_spec.sai_attribute.SaiAttribute
+    name: SAI_ENI_ATTR_DASH_ENI_MODE
+    description: Action parameter DASH ENI mode
+    type: sai_dash_eni_mode_t
+    attr_value_field: s32
+    default: SAI_DASH_ENI_MODE_VM
+    isresourcetype: false
+    flags: CREATE_ONLY
+    object_name: null
+    allow_null: false
+    valid_only: null
+    is_vlan: false
+    deprecated: false
   stats:
   - !!python/object:utils.sai_spec.sai_attribute.SaiAttribute
     name: SAI_ENI_STAT_RX_BYTES
@@ -1695,6 +1708,19 @@ sai_apis:
     valid_only: null
     is_vlan: false
     deprecated: false
+  - !!python/object:utils.sai_spec.sai_attribute.SaiAttribute
+    name: SAI_ENI_STAT_ENI_TRUSTED_VNI_ENTRY_MISS_DROP_PACKETS
+    description: DASH ENI ENI_TRUSTED_VNI_ENTRY_MISS_DROP_PACKETS stat count
+    type: sai_uint64_t
+    attr_value_field: u64
+    default: null
+    isresourcetype: false
+    flags: READ_ONLY
+    object_name: null
+    allow_null: false
+    valid_only: null
+    is_vlan: false
+    deprecated: false
   p4_meta: !!python/object:utils.sai_spec.sai_api_p4_meta.SaiApiP4Meta
     tables:
     - !!python/object:utils.sai_spec.sai_api_p4_meta.SaiApiP4MetaTable
@@ -1973,3 +1999,9 @@ sai_apis:
               bitwidth: 16
               ip_is_v6_field_id: 0
               skipattr: null
+            SAI_ENI_ATTR_DASH_ENI_MODE: !!python/object:utils.sai_spec.sai_api_p4_meta.SaiApiP4MetaActionParam
+              id: 44
+              field: s32
+              bitwidth: 8
+              ip_is_v6_field_id: 0
+              skipattr: null
diff --git a/dash-pipeline/SAI/specs/dash_trusted_vni.yaml b/dash-pipeline/SAI/specs/dash_trusted_vni.yaml
new file mode 100644
index 000000000..b414a24b7
--- /dev/null
+++ b/dash-pipeline/SAI/specs/dash_trusted_vni.yaml
@@ -0,0 +1,149 @@
+!!python/object:utils.sai_spec.sai_api_group.SaiApiGroup
+name: dash_trusted_vni
+description: DASH trusted VNI
+api_type: overlay
+sai_apis:
+- !!python/object:utils.sai_spec.sai_api.SaiApi
+  name: global_trusted_vni_entry
+  description: global trusted VNI entry
+  is_object: false
+  enums:
+  - !!python/object:utils.sai_spec.sai_enum.SaiEnum
+    name: sai_global_trusted_vni_entry_action_t
+    description: 'Attribute data for #SAI_GLOBAL_TRUSTED_VNI_ENTRY_ATTR_ACTION'
+    members:
+    - !!python/object:utils.sai_spec.sai_enum_member.SaiEnumMember
+      name: SAI_GLOBAL_TRUSTED_VNI_ENTRY_ACTION_PERMIT
+      description: ''
+      value: '0'
+  structs:
+  - !!python/object:utils.sai_spec.sai_struct.SaiStruct
+    name: sai_global_trusted_vni_entry_t
+    description: Entry for global_trusted_vni_entry
+    members:
+    - !!python/object:utils.sai_spec.sai_struct_entry.SaiStructEntry
+      name: switch_id
+      description: Switch ID
+      type: sai_object_id_t
+      objects: SAI_OBJECT_TYPE_SWITCH
+      valid_only: null
+    - !!python/object:utils.sai_spec.sai_struct_entry.SaiStructEntry
+      name: vni_range
+      description: Range matched key vni_range
+      type: sai_u32_range_t
+      objects: null
+      valid_only: null
+  attributes:
+  - !!python/object:utils.sai_spec.sai_attribute.SaiAttribute
+    name: SAI_GLOBAL_TRUSTED_VNI_ENTRY_ATTR_ACTION
+    description: Action
+    type: sai_global_trusted_vni_entry_action_t
+    attr_value_field: null
+    default: SAI_GLOBAL_TRUSTED_VNI_ENTRY_ACTION_PERMIT
+    isresourcetype: false
+    flags: CREATE_AND_SET
+    object_name: null
+    allow_null: false
+    valid_only: null
+    is_vlan: false
+    deprecated: false
+  stats: []
+  p4_meta: !!python/object:utils.sai_spec.sai_api_p4_meta.SaiApiP4Meta
+    tables:
+    - !!python/object:utils.sai_spec.sai_api_p4_meta.SaiApiP4MetaTable
+      id: 45800410
+      single_match_priority: true
+      stage: null
+      keys:
+      - !!python/object:utils.sai_spec.sai_api_p4_meta.SaiApiP4MetaKey
+        name: vni_range
+        id: 1
+        match_type: range
+        field: u32range
+        bitwidth: 24
+        ip_is_v6_field_id: 0
+        is_object_key: false
+      actions:
+        SAI_GLOBAL_TRUSTED_VNI_ENTRY_ACTION_PERMIT: !!python/object:utils.sai_spec.sai_api_p4_meta.SaiApiP4MetaAction
+          name: SAI_GLOBAL_TRUSTED_VNI_ENTRY_ACTION_PERMIT
+          id: 29028174
+          attr_params: {}
+- !!python/object:utils.sai_spec.sai_api.SaiApi
+  name: eni_trusted_vni_entry
+  description: ENI trusted VNI entry
+  is_object: false
+  enums:
+  - !!python/object:utils.sai_spec.sai_enum.SaiEnum
+    name: sai_eni_trusted_vni_entry_action_t
+    description: 'Attribute data for #SAI_ENI_TRUSTED_VNI_ENTRY_ATTR_ACTION'
+    members:
+    - !!python/object:utils.sai_spec.sai_enum_member.SaiEnumMember
+      name: SAI_ENI_TRUSTED_VNI_ENTRY_ACTION_PERMIT
+      description: ''
+      value: '0'
+  structs:
+  - !!python/object:utils.sai_spec.sai_struct.SaiStruct
+    name: sai_eni_trusted_vni_entry_t
+    description: Entry for eni_trusted_vni_entry
+    members:
+    - !!python/object:utils.sai_spec.sai_struct_entry.SaiStructEntry
+      name: switch_id
+      description: Switch ID
+      type: sai_object_id_t
+      objects: SAI_OBJECT_TYPE_SWITCH
+      valid_only: null
+    - !!python/object:utils.sai_spec.sai_struct_entry.SaiStructEntry
+      name: eni_id
+      description: Exact matched key eni_id
+      type: sai_object_id_t
+      objects: SAI_OBJECT_TYPE_ENI
+      valid_only: null
+    - !!python/object:utils.sai_spec.sai_struct_entry.SaiStructEntry
+      name: vni_range
+      description: Range matched key vni_range
+      type: sai_u32_range_t
+      objects: null
+      valid_only: null
+  attributes:
+  - !!python/object:utils.sai_spec.sai_attribute.SaiAttribute
+    name: SAI_ENI_TRUSTED_VNI_ENTRY_ATTR_ACTION
+    description: Action
+    type: sai_eni_trusted_vni_entry_action_t
+    attr_value_field: null
+    default: SAI_ENI_TRUSTED_VNI_ENTRY_ACTION_PERMIT
+    isresourcetype: false
+    flags: CREATE_AND_SET
+    object_name: null
+    allow_null: false
+    valid_only: null
+    is_vlan: false
+    deprecated: false
+  stats: []
+  p4_meta: !!python/object:utils.sai_spec.sai_api_p4_meta.SaiApiP4Meta
+    tables:
+    - !!python/object:utils.sai_spec.sai_api_p4_meta.SaiApiP4MetaTable
+      id: 49840895
+      single_match_priority: true
+      stage: null
+      keys:
+      - !!python/object:utils.sai_spec.sai_api_p4_meta.SaiApiP4MetaKey
+        name: eni_id
+        id: 1
+        match_type: exact
+        field: u16
+        bitwidth: 16
+        ip_is_v6_field_id: 0
+        is_object_key: false
+      - !!python/object:utils.sai_spec.sai_api_p4_meta.SaiApiP4MetaKey
+        name: vni_range
+        id: 2
+        match_type: range
+        field: u32range
+        bitwidth: 24
+        ip_is_v6_field_id: 0
+        is_object_key: false
+      actions:
+        SAI_ENI_TRUSTED_VNI_ENTRY_ACTION_PERMIT: !!python/object:utils.sai_spec.sai_api_p4_meta.SaiApiP4MetaAction
+          name: SAI_ENI_TRUSTED_VNI_ENTRY_ACTION_PERMIT
+          id: 29028174
+          attr_params: {}
diff --git a/dash-pipeline/SAI/specs/sai_spec.yaml b/dash-pipeline/SAI/specs/sai_spec.yaml
index 4305e7171..62c6cd932 100644
--- a/dash-pipeline/SAI/specs/sai_spec.yaml
+++ b/dash-pipeline/SAI/specs/sai_spec.yaml
@@ -16,6 +16,7 @@ api_types:
 - SAI_API_DASH_FLOW
 - SAI_API_DASH_APPLIANCE
 - SAI_API_DASH_OUTBOUND_PORT_MAP
+- SAI_API_DASH_TRUSTED_VNI
 object_types:
 - SAI_OBJECT_TYPE_DASH_ACL_GROUP
 - SAI_OBJECT_TYPE_DASH_ACL_RULE
@@ -46,6 +47,8 @@ object_types:
 - SAI_OBJECT_TYPE_DASH_TUNNEL_NEXT_HOP
 - SAI_OBJECT_TYPE_OUTBOUND_PORT_MAP
 - SAI_OBJECT_TYPE_OUTBOUND_PORT_MAP_PORT_RANGE_ENTRY
+- SAI_OBJECT_TYPE_GLOBAL_TRUSTED_VNI_ENTRY
+- SAI_OBJECT_TYPE_ENI_TRUSTED_VNI_ENTRY
 object_entries:
 - !!python/object:utils.sai_spec.sai_struct_entry.SaiStructEntry
   name: direction_lookup_entry
@@ -113,6 +116,18 @@ object_entries:
   type: sai_outbound_port_map_port_range_entry_t
   objects: null
   valid_only: object_type == SAI_OBJECT_TYPE_OUTBOUND_PORT_MAP_PORT_RANGE_ENTRY,
+- !!python/object:utils.sai_spec.sai_struct_entry.SaiStructEntry
+  name: global_trusted_vni_entry
+  description: Object entry for DASH API global_trusted_vni_entry
+  type: sai_global_trusted_vni_entry_t
+  objects: null
+  valid_only: object_type == SAI_OBJECT_TYPE_GLOBAL_TRUSTED_VNI_ENTRY,
+- !!python/object:utils.sai_spec.sai_struct_entry.SaiStructEntry
+  name: eni_trusted_vni_entry
+  description: Object entry for DASH API eni_trusted_vni_entry
+  type: sai_eni_trusted_vni_entry_t
+  objects: null
+  valid_only: object_type == SAI_OBJECT_TYPE_ENI_TRUSTED_VNI_ENTRY,
 enums:
 - !!python/object:utils.sai_spec.sai_enum.SaiEnum
   name: sai_dash_direction_t
@@ -478,6 +493,18 @@ enums:
     name: FLOW_PENDING_RESIMULATION
     description: ''
     value: '4'
+- !!python/object:utils.sai_spec.sai_enum.SaiEnum
+  name: sai_dash_eni_mode_t
+  description: ''
+  members:
+  - !!python/object:utils.sai_spec.sai_enum_member.SaiEnumMember
+    name: VM
+    description: ''
+    value: '0'
+  - !!python/object:utils.sai_spec.sai_enum_member.SaiEnumMember
+    name: FNIC
+    description: ''
+    value: '1'
 port_extenstion: !!python/object:utils.sai_spec.sai_api_extension.SaiApiExtension
   attributes: []
   stats:
@@ -576,3 +603,4 @@ api_groups:
 - !inc 'dash_flow.yaml'
 - !inc 'dash_appliance.yaml'
 - !inc 'dash_outbound_port_map.yaml'
+- !inc 'dash_trusted_vni.yaml'
diff --git a/dash-pipeline/bmv2/dash_counters.p4 b/dash-pipeline/bmv2/dash_counters.p4
index 5cb13327e..4dd8397e7 100644
--- a/dash-pipeline/bmv2/dash_counters.p4
+++ b/dash-pipeline/bmv2/dash_counters.p4
@@ -104,5 +104,6 @@ DEFINE_ENI_PACKET_COUNTER(outbound_routing_group_miss_drop)
 DEFINE_ENI_PACKET_COUNTER(outbound_routing_group_disabled_drop)
 DEFINE_ENI_PACKET_COUNTER(outbound_port_map_miss_drop)
 DEFINE_ENI_PACKET_COUNTER(outbound_port_map_port_range_entry_miss_drop)
+DEFINE_ENI_PACKET_COUNTER(eni_trusted_vni_entry_miss_drop)
 
 #endif // __DASH_COUNTERS__
diff --git a/dash-pipeline/bmv2/dash_metadata.p4 b/dash-pipeline/bmv2/dash_metadata.p4
index d9d8e26c4..9ba66e7a8 100644
--- a/dash-pipeline/bmv2/dash_metadata.p4
+++ b/dash-pipeline/bmv2/dash_metadata.p4
@@ -37,6 +37,11 @@ enum bit<8> dash_eni_mac_type_t {
     DST_MAC = 1
 };
 
+enum bit<8> dash_eni_mode_t {
+    VM = 0,
+    FNIC = 1
+};
+
 struct conntrack_data_t {
     bool allow_in;
     bool allow_out;
@@ -64,6 +69,7 @@ struct eni_data_t {
     dash_tunnel_dscp_mode_t dscp_mode;
     outbound_routing_group_data_t outbound_routing_group_data;
     IPv4Address vip;
+    dash_eni_mode_t eni_mode;
 }
 
 struct port_map_context_t {
@@ -257,4 +263,8 @@ struct metadata_t {
     EthernetAddress cpu_mac;
 }
 
+action deny(inout metadata_t meta) {
+    meta.dropped = true;
+}
+
 #endif /* _SIRIUS_METADATA_P4_ */
diff --git a/dash-pipeline/bmv2/dash_pipeline.p4 b/dash-pipeline/bmv2/dash_pipeline.p4
index 45e79cf0a..b78c2cc49 100644
--- a/dash-pipeline/bmv2/dash_pipeline.p4
+++ b/dash-pipeline/bmv2/dash_pipeline.p4
@@ -16,6 +16,7 @@
 #include "stages/ha.p4"
 #include "stages/routing_action_apply.p4"
 #include "stages/metering_update.p4"
+#include "stages/trusted_vni.p4"
 #include "underlay.p4"
 
 control dash_eni_stage(
@@ -23,10 +24,6 @@ control dash_eni_stage(
     , inout metadata_t meta
     )
 {
-    action deny() {
-        meta.dropped = true;
-    }
-
 #define ACL_GROUPS_PARAM(prefix) \
     @SaiVal[type="sai_object_id_t"] bit<16> ## prefix ##_stage1_dash_acl_group_id, \
     @SaiVal[type="sai_object_id_t"] bit<16> ## prefix ##_stage2_dash_acl_group_id, \
@@ -67,7 +64,8 @@ control dash_eni_stage(
                          bit<1> enable_reverse_tunnel_learning,
                          @SaiVal[type="sai_ip_address_t"] IPv4Address reverse_tunnel_sip,
                          bit<1> is_ha_flow_owner,
-                         @SaiVal[type="sai_object_id_t"] bit<16> flow_table_id)
+                         @SaiVal[type="sai_object_id_t"] bit<16> flow_table_id,
+                         @SaiVal[type="sai_dash_eni_mode_t", create_only="true"] dash_eni_mode_t dash_eni_mode)
     {
         meta.eni_data.cps                                                   = cps;
         meta.eni_data.pps                                                   = pps;
@@ -76,6 +74,7 @@ control dash_eni_stage(
         meta.eni_data.pl_sip                                                = pl_sip;
         meta.eni_data.pl_sip_mask                                           = pl_sip_mask;
         meta.eni_data.pl_underlay_sip                                       = pl_underlay_sip;
+        meta.eni_data.eni_mode                                              = dash_eni_mode;
         meta.u0_encap_data.underlay_dip                                     = vm_underlay_dip;
         meta.eni_data.outbound_routing_group_data.outbound_routing_group_id = outbound_routing_group_id;
         if (dash_tunnel_dscp_mode == dash_tunnel_dscp_mode_t.PIPE_MODEL) {
@@ -125,9 +124,9 @@ control dash_eni_stage(
 
         actions = {
             set_eni_attrs;
-            @defaultonly deny;
+            @defaultonly deny(meta);
         }
-        const default_action = deny;
+        const default_action = deny(meta);
     }
 
     apply {
@@ -143,10 +142,6 @@ control dash_lookup_stage(
     , inout metadata_t meta
     )
 {
-    action deny() {
-        meta.dropped = true;
-    }
-
     apply {
         pre_pipeline_stage.apply(hdr, meta);
         direction_lookup_stage.apply(hdr, meta);
@@ -155,7 +150,7 @@ control dash_lookup_stage(
         dash_eni_stage.apply(hdr, meta);
 
         if (meta.eni_data.admin_state == 0) {
-            deny();
+            deny(meta);
         }
         
         UPDATE_ENI_COUNTER(eni_rx);
@@ -202,6 +197,10 @@ control dash_match_stage(
     }
 
     apply {
+        if (meta.dropped) {
+            return;
+        }
+
         acl_group.apply();
 
         if (meta.direction == dash_direction_t.OUTBOUND) {
@@ -278,6 +277,8 @@ control dash_ingress(
             (meta.flow_sync_state == dash_flow_sync_state_t.FLOW_MISS &&
              hdr.packet_meta.packet_source == dash_packet_source_t.EXTERNAL))
         {
+            // TODO: revisit it after inbound route HLD done
+            trusted_vni_stage.apply(hdr, meta);
             dash_match_stage.apply(hdr, meta);
             if (meta.dropped) {
                 drop_action();
diff --git a/dash-pipeline/bmv2/stages/direction_lookup.p4 b/dash-pipeline/bmv2/stages/direction_lookup.p4
index a75d35528..e26a6d3a9 100644
--- a/dash-pipeline/bmv2/stages/direction_lookup.p4
+++ b/dash-pipeline/bmv2/stages/direction_lookup.p4
@@ -25,9 +25,11 @@ control direction_lookup_stage(
         set_eni_mac_type(dash_eni_mac_type_t.SRC_MAC, dash_eni_mac_override_type);
     }
 
-    action set_inbound_direction() {
+    action set_inbound_direction(
+        @SaiVal[type="sai_dash_eni_mac_override_type_t"] dash_eni_mac_override_type_t dash_eni_mac_override_type
+    ) {
         meta.direction = dash_direction_t.INBOUND;
-        meta.eni_mac_type = dash_eni_mac_type_t.DST_MAC;
+        set_eni_mac_type(dash_eni_mac_type_t.DST_MAC, dash_eni_mac_override_type);
     }
 
     @SaiTable[name = "direction_lookup", api = "dash_direction_lookup"]
@@ -38,10 +40,10 @@ control direction_lookup_stage(
 
         actions = {
             set_outbound_direction;
-            @defaultonly set_inbound_direction;
+            set_inbound_direction;
         }
 
-        const default_action = set_inbound_direction;
+        const default_action = set_inbound_direction(dash_eni_mac_override_type_t.NONE);
     }
 
     apply {
@@ -50,4 +52,4 @@ control direction_lookup_stage(
     }
 }
 
-#endif /* _DASH_STAGE_DIRECTION_LOOKUP_P4_ */
\ No newline at end of file
+#endif /* _DASH_STAGE_DIRECTION_LOOKUP_P4_ */
diff --git a/dash-pipeline/bmv2/stages/eni_lookup.p4 b/dash-pipeline/bmv2/stages/eni_lookup.p4
index 5c9352013..2ee07f627 100644
--- a/dash-pipeline/bmv2/stages/eni_lookup.p4
+++ b/dash-pipeline/bmv2/stages/eni_lookup.p4
@@ -9,10 +9,6 @@ control eni_lookup_stage(
         meta.eni_id = eni_id;
     }
 
-    action deny() {
-        meta.dropped = true;
-    }
-    
     @SaiTable[name = "eni_ether_address_map", api = "dash_eni", order=0]
     table eni_ether_address_map {
         key = {
@@ -21,9 +17,9 @@ control eni_lookup_stage(
 
         actions = {
             set_eni;
-            @defaultonly deny;
+            @defaultonly deny(meta);
         }
-        const default_action = deny;
+        const default_action = deny(meta);
     }
 
     apply {
@@ -44,4 +40,4 @@ control eni_lookup_stage(
     }
 }
 
-#endif /* _DASH_STAGE_ENI_LOOKUP_P4_ */
\ No newline at end of file
+#endif /* _DASH_STAGE_ENI_LOOKUP_P4_ */
diff --git a/dash-pipeline/bmv2/stages/trusted_vni.p4 b/dash-pipeline/bmv2/stages/trusted_vni.p4
new file mode 100644
index 000000000..9c42209bf
--- /dev/null
+++ b/dash-pipeline/bmv2/stages/trusted_vni.p4
@@ -0,0 +1,46 @@
+#ifndef _DASH_STAGE_TRUSTED_VNI_P4_
+#define _DASH_STAGE_TRUSTED_VNI_P4_
+
+control trusted_vni_stage(
+    inout headers_t hdr,
+    inout metadata_t meta)
+{
+    action permit() {}
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni", order=0, isobject="false"]
+    table global_trusted_vni {
+        key = {
+            meta.rx_encap.vni: range @SaiVal[name = "vni_range"];
+        }
+
+        actions = {
+            permit;
+        }
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni", order=1]
+    table eni_trusted_vni {
+        key = {
+            meta.eni_id : exact @SaiVal[type="sai_object_id_t"];
+            meta.rx_encap.vni: range @SaiVal[name = "vni_range"];
+        }
+
+        actions = {
+            permit;
+            @defaultonly deny(meta);
+        }
+        const default_action = deny(meta);
+    }
+
+    apply {
+        if (global_trusted_vni.apply().hit) {
+            return;
+        }
+
+        if (!eni_trusted_vni.apply().hit) {
+            UPDATE_ENI_COUNTER(eni_trusted_vni_entry_miss_drop);
+        }
+    }
+}
+
+#endif /* _DASH_STAGE_TRUSTED_VNI_P4_ */
diff --git a/test/test-cases/functional/ptf/sai_dash_utils.py b/test/test-cases/functional/ptf/sai_dash_utils.py
index 563e1381b..c203a97c0 100644
--- a/test/test-cases/functional/ptf/sai_dash_utils.py
+++ b/test/test-cases/functional/ptf/sai_dash_utils.py
@@ -16,6 +16,7 @@
 Thrift SAI interface basic DASH utils.
 """
 
+import functools
 from sai_thrift.sai_headers import *
 from sai_base_test import *
 
@@ -471,6 +472,22 @@ def configure_underlay(self, *neighbors, add_routes=True):
             #if add_routes is True:
             #    self.route_create(neighbor.ip_prefix, nhop)
 
+    def global_trusted_vni_create(self, vni):
+        """
+        Create global trusted vni
+        """
+
+        global_trusted_vni_entry = sai_thrift_global_trusted_vni_entry_t(switch_id=self.switch_id,
+                vni_range=sai_thrift_u32_range_t(min=vni, max=vni))
+        sai_thrift_create_global_trusted_vni_entry(self.client, global_trusted_vni_entry)
+        self.assertEqual(self.status(), SAI_STATUS_SUCCESS)
+        self.add_teardown_obj(self.global_trusted_vni_remove, global_trusted_vni_entry)
+
+        return global_trusted_vni_entry
+
+    def global_trusted_vni_remove(self, global_trusted_vni_entry):
+        sai_thrift_remove_global_trusted_vni_entry(self.client, global_trusted_vni_entry)
+
 
 class VnetApiEndpoints(VnetAPI):
     """
@@ -1520,3 +1537,22 @@ def update_tcp_pkt(pkt, seq, ack, tcp_flag=None):
 
         pkt.getlayer("TCP").seq = seq
         pkt.getlayer("TCP").ack = ack
+
+def configureTrustedVni(func):
+    @functools.wraps(func)
+    def wrapper_configureTrustedVni(self):
+        value = func(self)
+
+        vni_set = set()
+        tx_hosts = ["tx_host", "tx_host_1", "tx_host_2", "tx_host_3", "tx_host_4"]
+        for name in tx_hosts:
+            host = getattr(self, name, None)
+            if host and host.client:
+                vni_set.add(host.client.vni)
+
+        for vni in list(vni_set):
+                self.global_trusted_vni_create(vni)
+
+        return value
+
+    return wrapper_configureTrustedVni
diff --git a/test/test-cases/functional/ptf/saidashacl.py b/test/test-cases/functional/ptf/saidashacl.py
index 34dff83f2..3fd48f0bb 100644
--- a/test/test-cases/functional/ptf/saidashacl.py
+++ b/test/test-cases/functional/ptf/saidashacl.py
@@ -150,6 +150,11 @@ def setUpSwitch(self):
         self.create_entry(sai_thrift_create_direction_lookup_entry, sai_thrift_remove_direction_lookup_entry,
                           self.dle, action=SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_OUTBOUND_DIRECTION)
 
+        self.gtve = sai_thrift_global_trusted_vni_entry_t(switch_id=self.switch_id,
+                vni_range=sai_thrift_u32_range_t(min=self.outbound_vni, max=self.outbound_vni))
+        self.create_entry(sai_thrift_create_global_trusted_vni_entry, sai_thrift_remove_global_trusted_vni_entry,
+                          self.gtve)
+
         self.in_v4_stage1_acl_group_id = self.create_obj(
             sai_thrift_create_dash_acl_group, sai_thrift_remove_dash_acl_group, ip_addr_family=SAI_IP_ADDR_FAMILY_IPV4)
         self.in_v4_stage2_acl_group_id = self.create_obj(
diff --git a/test/test-cases/functional/ptf/saidashdpapp_sanity.py b/test/test-cases/functional/ptf/saidashdpapp_sanity.py
index 7f32900a1..367a22adf 100644
--- a/test/test-cases/functional/ptf/saidashdpapp_sanity.py
+++ b/test/test-cases/functional/ptf/saidashdpapp_sanity.py
@@ -46,6 +46,11 @@ def configureVnet(self):
                                                           action=SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_OUTBOUND_DIRECTION)
         assert(status == SAI_STATUS_SUCCESS)
 
+        self.gtve = sai_thrift_global_trusted_vni_entry_t(switch_id=self.switch_id,
+                vni_range=sai_thrift_u32_range_t(min=self.outbound_vni, max=self.outbound_vni))
+        status = sai_thrift_create_global_trusted_vni_entry(self.client, self.gtve)
+        assert(status == SAI_STATUS_SUCCESS)
+
         self.in_acl_group_id = sai_thrift_create_dash_acl_group(self.client,
                                                                 ip_addr_family=self.sai_ip_addr_family)
         assert (self.in_acl_group_id != SAI_NULL_OBJECT_ID)
@@ -322,6 +327,7 @@ def tearDown(self):
             status &= sai_thrift_remove_vnet(self.client, self.vnet)
             status &= sai_thrift_remove_dash_acl_group(self.client, self.out_acl_group_id)
             status &= sai_thrift_remove_dash_acl_group(self.client, self.in_acl_group_id)
+            status &= sai_thrift_remove_global_trusted_vni_entry(self.client, self.gtve)
             status &= sai_thrift_remove_direction_lookup_entry(self.client, self.dle)
             status &= sai_thrift_remove_vip_entry(self.client, self.vpe)
             status &= sai_thrift_remove_route_entry(self.client, self.pa_route_entry)
diff --git a/test/test-cases/functional/ptf/saidashvnet.py b/test/test-cases/functional/ptf/saidashvnet.py
index 068b403e9..14b882bbd 100644
--- a/test/test-cases/functional/ptf/saidashvnet.py
+++ b/test/test-cases/functional/ptf/saidashvnet.py
@@ -38,6 +38,7 @@ def runTest(self):
         self.l3UnderlayHost1toHost2RoutingTest()
         self.l3UnderlayHost2toHost1RoutingTest()
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -137,6 +138,7 @@ def runTest(self):
         self.vnet2VnetInboundRoutingTest(tx_equal_to_rx=True)
         self.vnet2VnetInboundNegativeTest()
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -268,6 +270,7 @@ class Vnet2VnetInboundDecapSinglePortTest(Vnet2VnetInboundDecapPaValidateSingleP
     Verifies positive and negative scenarios
     """
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT overlay in accordance with test purpose
@@ -397,6 +400,7 @@ def runTest(self):
         self.vnet2VnetInboundRoutingPositiveTest(tx_equal_to_rx=True)
         self.vnet2VnetInboundRoutingNegativeTest()
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -582,6 +586,7 @@ def runTest(self):
 
         self.vnet2VnetInboundRoutingPositiveTest(tx_equal_to_rx=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -777,6 +782,7 @@ def runTest(self):
         self.vnet2VnetInboundRoutingPositiveTest(tx_equal_to_rx=True)
         self.vnet2VnetInboundRoutingNegativeTest()
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -949,6 +955,7 @@ def runTest(self):
 
         self.vnet2VnetInboundRoutingPositiveTest(tx_equal_to_rx=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -1128,6 +1135,7 @@ def runTest(self):
 
         self.vnet2VnetInboundRoutingTest(tx_equal_to_rx=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -1251,6 +1259,7 @@ def runTest(self):
 
         self.vnet2VnetInboundRoutingTest(tx_equal_to_rx=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -1383,6 +1392,7 @@ def runTest(self):
         self.eni_set_admin_state(self.eni_id, "up")
         self.vnet2VnetEniUpTrafficTest(tx_equal_to_rx=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT overlay in accordance with test purpose
@@ -1463,6 +1473,7 @@ def runTest(self):
         self.vnet2VnetOutboundRoutingTest(tx_equal_to_rx=True)
         self.vnet2VnetOutboundNegativeTest()
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -1535,6 +1546,7 @@ class Vnet2VnetOutboundRouteVnetDirectSinglePortOverlayIpv6Test(Vnet2VnetOutboun
     def setUp(self):
         super(Vnet2VnetOutboundRouteVnetDirectSinglePortOverlayIpv6Test, self).setUp(overlay_ipv6=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -1635,6 +1647,7 @@ def runTest(self):
         self.vnet2VnetOutboundRoutingTest(tx_equal_to_rx=True)
         self.vnet2VnetOutboundNegativeTest()
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -1713,6 +1726,7 @@ class Vnet2VnetOutboundRouteVnetSinglePortOverlayIpv6Test(Vnet2VnetOutboundRoute
     def setUp(self):
         super(Vnet2VnetOutboundRouteVnetSinglePortOverlayIpv6Test, self).setUp(overlay_ipv6=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -1823,6 +1837,7 @@ def runTest(self):
         self.eni_set_admin_state(self.eni_id, "up")
         self.vnet2VnetEniUpTrafficTest(tx_equal_to_rx=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -1910,6 +1925,7 @@ def runTest(self):
         self.outboundRouteDirectTest(tx_equal_to_rx=True)
         self.outboundRouteDirectNegativeTest()
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -1978,6 +1994,7 @@ class Vnet2VnetOutboundRouteDirectSinglePortOverlayIpv6Test(Vnet2VnetOutboundRou
     def setUp(self):
         super(Vnet2VnetOutboundRouteDirectSinglePortOverlayIpv6Test, self).setUp(overlay_ipv6=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -2076,6 +2093,7 @@ def runTest(self):
         self.vnet2VnetOutboundRoutingTest(tx_equal_to_rx=True)
         self.vnet2VnetOutboundNegativeTest()
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -2218,6 +2236,7 @@ class Vnet2VnetSingleOutboundRouteMultipleCa2PaSinglePortIpv6Test(Vnet2VnetSingl
     def setUp(self):
         super(Vnet2VnetSingleOutboundRouteMultipleCa2PaSinglePortIpv6Test, self).setUp(overlay_ipv6=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -2372,6 +2391,7 @@ def runTest(self):
         self.vnet2VnetOutboundDstVnetIdTrueTest(tx_equal_to_rx=True)
         self.vnet2VnetOutboundDstVnetIdFalseTest(tx_equal_to_rx=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -2459,6 +2479,7 @@ class Vnet2VnetOutboundDstVnetIdRouteVnetSinglePortOverlayIpv6Test(Vnet2VnetOutb
     def setUp(self):
         super(Vnet2VnetOutboundDstVnetIdRouteVnetSinglePortOverlayIpv6Test, self).setUp(overlay_ipv6=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -2570,6 +2591,7 @@ def runTest(self):
         self.vnet2VnetOutboundDstVnetIdTrueTest(tx_equal_to_rx=True)
         self.vnet2VnetOutboundDstVnetIdFalseTest(tx_equal_to_rx=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -2642,6 +2664,7 @@ class Vnet2VnetOutboundDstVnetIdRouteVnetDirectSinglePortOverlayIpv6Test(Vnet2Vn
     def setUp(self):
         super(Vnet2VnetOutboundDstVnetIdRouteVnetDirectSinglePortOverlayIpv6Test, self).setUp(overlay_ipv6=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -2758,6 +2781,7 @@ def runTest(self):
         self.outboundHost3toHost1Test(tx_equal_to_rx=True)
         self.inboundHost1toHost3Test(tx_equal_to_rx=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -2901,6 +2925,7 @@ class Vnet2VnetInboundOutboundMultipleConfigsSinglePortOverlayIpv6Test(Vnet2Vnet
     with underlay config (neighbour + next hop) but without underlay routes
     """
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -3054,6 +3079,7 @@ def runTest(self):
         self.outboundEni1Test(tx_equal_to_rx=True)
         self.outboundEni2Test(tx_equal_to_rx=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -3228,6 +3254,7 @@ class Vnet2VnetOutboundMultipleEniSameIpPrefixSinglePortOverlayIpv6Test(Vnet2Vne
     def setUp(self):
         super(Vnet2VnetOutboundMultipleEniSameIpPrefixSinglePortOverlayIpv6Test, self).setUp(overlay_ipv6=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -3410,6 +3437,7 @@ def runTest(self):
         self.singleEniToOutboundVm2Test(tx_equal_to_rx=True)
         self.singleEniToOutboundVm3Test(tx_equal_to_rx=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -3564,6 +3592,7 @@ class Vnet2VnetOutboundSingleEniMultipleIpPrefixSinglePortOverlayIpv6Test(Vnet2V
     def setUp(self):
         super(Vnet2VnetOutboundSingleEniMultipleIpPrefixSinglePortOverlayIpv6Test, self).setUp(overlay_ipv6=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
@@ -3708,6 +3737,7 @@ def runTest(self):
 
         self.vnet2VnetOutboundRouteVnetTest(tx_equal_to_rx=True)
 
+    @configureTrustedVni
     def configureTest(self):
         """
         Setup DUT in accordance with test purpose
diff --git a/test/test-cases/functional/ptf/saidashvnet_sanity.py b/test/test-cases/functional/ptf/saidashvnet_sanity.py
index a315dcd0b..368d8e2ec 100644
--- a/test/test-cases/functional/ptf/saidashvnet_sanity.py
+++ b/test/test-cases/functional/ptf/saidashvnet_sanity.py
@@ -54,6 +54,11 @@ def configureVnet(self):
                                                           action=SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_OUTBOUND_DIRECTION)
         assert(status == SAI_STATUS_SUCCESS)
 
+        self.gtve = sai_thrift_global_trusted_vni_entry_t(switch_id=self.switch_id,
+                vni_range=sai_thrift_u32_range_t(min=self.outbound_vni, max=self.outbound_vni))
+        status = sai_thrift_create_global_trusted_vni_entry(self.client, self.gtve)
+        assert(status == SAI_STATUS_SUCCESS)
+
         self.in_acl_group_id = sai_thrift_create_dash_acl_group(self.client,
                                                                 ip_addr_family=self.sai_ip_addr_family)
         assert (self.in_acl_group_id != SAI_NULL_OBJECT_ID)
@@ -278,6 +283,7 @@ def tearDown(self):
             status &= sai_thrift_remove_vnet(self.client, self.vnet)
             status &= sai_thrift_remove_dash_acl_group(self.client, self.out_acl_group_id)
             status &= sai_thrift_remove_dash_acl_group(self.client, self.in_acl_group_id)
+            status &= sai_thrift_remove_global_trusted_vni_entry(self.client, self.gtve)
             status &= sai_thrift_remove_direction_lookup_entry(self.client, self.dle)
             status &= sai_thrift_remove_vip_entry(self.client, self.vpe)
             if self.configured:


Reviews:
user: login: r12f
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-01T06:16:45Z
user: login: r12f
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-01T06:18:53Z
user: login: r12f
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-01T06:19:28Z
user: login: r12f
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-01T06:21:07Z
user: login: jimmyzhai
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T00:44:54Z
user: login: jimmyzhai
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T00:47:33Z
user: login: jimmyzhai
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T00:47:43Z
user: login: jimmyzhai
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T00:54:41Z
user: login: jimmyzhai
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T02:01:09Z
user: login: jimmyzhai
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T02:02:26Z
user: login: r12f
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T05:48:19Z
user: login: r12f
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-03T05:59:31Z
user: login: r12f
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-09T03:04:59Z
user: login: jimmyzhai
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-09T04:59:33Z
user: login: jimmyzhai
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-09T05:00:32Z
user: login: jimmyzhai
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-09T05:02:46Z
user: login: r12f
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-09T05:54:07Z

Review comments:
diff_hunk: @@ -16,6 +16,10 @@ sai_apis:
       name: SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_OUTBOUND_DIRECTION
path: dash-pipeline/SAI/specs/dash_direction_lookup.yaml
user: login: r12f
body: Will be great to update the title to cover all changes in this PR.
created_at: 2025-03-27T02:47:35Z
author_association: COLLABORATOR
diff_hunk: @@ -134,6 +137,9 @@ control dash_eni_stage(
         if (!eni.apply().hit) {
             UPDATE_COUNTER(eni_miss_drop, 0);
         }
+        else if (meta.eni_data.eni_mode == dash_eni_mode_t.FNIC) {
+            trusted_vni_stage.apply(hdr, meta);
path: dash-pipeline/bmv2/dash_pipeline.p4
user: login: r12f
body: this one should be in global, shared by all ENIs.
created_at: 2025-03-27T02:48:53Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,48 @@
+#ifndef _DASH_STAGE_TRUSTED_VNI_P4_
+#define _DASH_STAGE_TRUSTED_VNI_P4_
+
+control trusted_vni_stage(
+    inout headers_t hdr,
+    inout metadata_t meta)
+{
+    action permit() {}
+
+    action deny() {
+        meta.dropped = true;
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni", order=1, isobject="false"]
+    table global_trusted_vni {
+        key = {
+            meta.rx_encap.vni: range @SaiVal[name = "vni_range"];
+        }
+
+        actions = {
+            permit;
+        }
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni"]
+    table trusted_vni {
path: dash-pipeline/bmv2/stages/trusted_vni.p4
user: login: r12f
body: eni_trusted_vni
created_at: 2025-04-01T06:18:53Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,48 @@
+#ifndef _DASH_STAGE_TRUSTED_VNI_P4_
+#define _DASH_STAGE_TRUSTED_VNI_P4_
+
+control trusted_vni_stage(
+    inout headers_t hdr,
+    inout metadata_t meta)
+{
+    action permit() {}
+
+    action deny() {
+        meta.dropped = true;
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni", order=1, isobject="false"]
path: dash-pipeline/bmv2/stages/trusted_vni.p4
user: login: r12f
body: will be better to split the files, so we can have both batch API working.
created_at: 2025-04-01T06:19:28Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,48 @@
+#ifndef _DASH_STAGE_TRUSTED_VNI_P4_
+#define _DASH_STAGE_TRUSTED_VNI_P4_
+
+control trusted_vni_stage(
+    inout headers_t hdr,
+    inout metadata_t meta)
+{
+    action permit() {}
+
+    action deny() {
path: dash-pipeline/bmv2/stages/trusted_vni.p4
user: login: r12f
body: iirc, we have a global deny function and maybe we can use that instead.
created_at: 2025-04-01T06:20:50Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,48 @@
+#ifndef _DASH_STAGE_TRUSTED_VNI_P4_
+#define _DASH_STAGE_TRUSTED_VNI_P4_
+
+control trusted_vni_stage(
+    inout headers_t hdr,
+    inout metadata_t meta)
+{
+    action permit() {}
+
+    action deny() {
+        meta.dropped = true;
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni", order=1, isobject="false"]
+    table global_trusted_vni {
+        key = {
+            meta.rx_encap.vni: range @SaiVal[name = "vni_range"];
+        }
+
+        actions = {
+            permit;
+        }
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni"]
+    table trusted_vni {
+        key = {
+            meta.eni_id : exact @SaiVal[type="sai_object_id_t"];
+            meta.rx_encap.vni: range @SaiVal[name = "vni_range"];
+        }
+
+        actions = {
+            permit;
+            @defaultonly deny;
+        }
+        const default_action = deny;
+    }
+
+    apply {
+        if (global_trusted_vni.apply().hit) {
+            return;
+        }
+
+        trusted_vni.apply();
path: dash-pipeline/bmv2/stages/trusted_vni.p4
user: login: r12f
body: need counter to track the drops.
created_at: 2025-04-01T06:21:02Z
author_association: COLLABORATOR
diff_hunk: @@ -16,6 +16,10 @@ sai_apis:
       name: SAI_DIRECTION_LOOKUP_ENTRY_ACTION_SET_OUTBOUND_DIRECTION
path: dash-pipeline/SAI/specs/dash_direction_lookup.yaml
user: login: jimmyzhai
body: Updated
created_at: 2025-04-03T00:44:53Z
author_association: COLLABORATOR
diff_hunk: @@ -134,6 +137,9 @@ control dash_eni_stage(
         if (!eni.apply().hit) {
             UPDATE_COUNTER(eni_miss_drop, 0);
         }
+        else if (meta.eni_data.eni_mode == dash_eni_mode_t.FNIC) {
+            trusted_vni_stage.apply(hdr, meta);
path: dash-pipeline/bmv2/dash_pipeline.p4
user: login: jimmyzhai
body: Fixed
created_at: 2025-04-03T00:47:33Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,48 @@
+#ifndef _DASH_STAGE_TRUSTED_VNI_P4_
+#define _DASH_STAGE_TRUSTED_VNI_P4_
+
+control trusted_vni_stage(
+    inout headers_t hdr,
+    inout metadata_t meta)
+{
+    action permit() {}
+
+    action deny() {
+        meta.dropped = true;
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni", order=1, isobject="false"]
+    table global_trusted_vni {
+        key = {
+            meta.rx_encap.vni: range @SaiVal[name = "vni_range"];
+        }
+
+        actions = {
+            permit;
+        }
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni"]
+    table trusted_vni {
path: dash-pipeline/bmv2/stages/trusted_vni.p4
user: login: jimmyzhai
body: Fixed
created_at: 2025-04-03T00:47:43Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,48 @@
+#ifndef _DASH_STAGE_TRUSTED_VNI_P4_
+#define _DASH_STAGE_TRUSTED_VNI_P4_
+
+control trusted_vni_stage(
+    inout headers_t hdr,
+    inout metadata_t meta)
+{
+    action permit() {}
+
+    action deny() {
+        meta.dropped = true;
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni", order=1, isobject="false"]
path: dash-pipeline/bmv2/stages/trusted_vni.p4
user: login: jimmyzhai
body: The one file is better organized for same category of trusted vni objects, and their batch APIs are working in orchagent.
created_at: 2025-04-03T00:54:41Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,48 @@
+#ifndef _DASH_STAGE_TRUSTED_VNI_P4_
+#define _DASH_STAGE_TRUSTED_VNI_P4_
+
+control trusted_vni_stage(
+    inout headers_t hdr,
+    inout metadata_t meta)
+{
+    action permit() {}
+
+    action deny() {
path: dash-pipeline/bmv2/stages/trusted_vni.p4
user: login: jimmyzhai
body: Use global deny function
created_at: 2025-04-03T02:01:09Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,48 @@
+#ifndef _DASH_STAGE_TRUSTED_VNI_P4_
+#define _DASH_STAGE_TRUSTED_VNI_P4_
+
+control trusted_vni_stage(
+    inout headers_t hdr,
+    inout metadata_t meta)
+{
+    action permit() {}
+
+    action deny() {
+        meta.dropped = true;
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni", order=1, isobject="false"]
+    table global_trusted_vni {
+        key = {
+            meta.rx_encap.vni: range @SaiVal[name = "vni_range"];
+        }
+
+        actions = {
+            permit;
+        }
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni"]
+    table trusted_vni {
+        key = {
+            meta.eni_id : exact @SaiVal[type="sai_object_id_t"];
+            meta.rx_encap.vni: range @SaiVal[name = "vni_range"];
+        }
+
+        actions = {
+            permit;
+            @defaultonly deny;
+        }
+        const default_action = deny;
+    }
+
+    apply {
+        if (global_trusted_vni.apply().hit) {
+            return;
+        }
+
+        trusted_vni.apply();
path: dash-pipeline/bmv2/stages/trusted_vni.p4
user: login: jimmyzhai
body: Add counter `eni_trusted_vni_entry_miss_drop`
created_at: 2025-04-03T02:02:26Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,46 @@
+#ifndef _DASH_STAGE_TRUSTED_VNI_P4_
+#define _DASH_STAGE_TRUSTED_VNI_P4_
+
+control trusted_vni_stage(
+    inout headers_t hdr,
+    inout metadata_t meta)
+{
+    action permit() {}
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni", order=1, isobject="false"]
+    table global_trusted_vni {
+        key = {
+            meta.rx_encap.vni: range @SaiVal[name = "vni_range"];
+        }
+
+        actions = {
+            permit;
+        }
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni"]
path: dash-pipeline/bmv2/stages/trusted_vni.p4
user: login: r12f
body: Add order.
created_at: 2025-04-03T05:48:19Z
author_association: COLLABORATOR
diff_hunk: @@ -278,6 +277,7 @@ control dash_ingress(
             (meta.flow_sync_state == dash_flow_sync_state_t.FLOW_MISS &&
              hdr.packet_meta.packet_source == dash_packet_source_t.EXTERNAL))
         {
+            trusted_vni_stage.apply(hdr, meta);
path: dash-pipeline/bmv2/dash_pipeline.p4
user: login: r12f
body: maybe we missed the inbound routing table for the VNI matching, if we simply return it here.
created_at: 2025-04-03T05:59:31Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,46 @@
+#ifndef _DASH_STAGE_TRUSTED_VNI_P4_
+#define _DASH_STAGE_TRUSTED_VNI_P4_
+
+control trusted_vni_stage(
+    inout headers_t hdr,
+    inout metadata_t meta)
+{
+    action permit() {}
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni", order=0, isobject="false"]
+    table global_trusted_vni {
+        key = {
+            meta.rx_encap.vni: range @SaiVal[name = "vni_range"];
+        }
+
+        actions = {
+            permit;
+        }
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni", order=1]
+    table eni_trusted_vni {
+        key = {
+            meta.eni_id : exact @SaiVal[type="sai_object_id_t"];
+            meta.rx_encap.vni: range @SaiVal[name = "vni_range"];
+        }
+
+        actions = {
+            permit;
+            @defaultonly deny(meta);
+        }
+        const default_action = deny(meta);
+    }
+
+    apply {
+        if (global_trusted_vni.apply().hit) {
+            return;
+        }
+
+        if (!eni_trusted_vni.apply().hit) {
path: dash-pipeline/bmv2/stages/trusted_vni.p4
user: login: r12f
body: better add a TODO comment to make sure the pipeline can capture the behavior right.
created_at: 2025-04-09T03:04:59Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,46 @@
+#ifndef _DASH_STAGE_TRUSTED_VNI_P4_
+#define _DASH_STAGE_TRUSTED_VNI_P4_
+
+control trusted_vni_stage(
+    inout headers_t hdr,
+    inout metadata_t meta)
+{
+    action permit() {}
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni", order=1, isobject="false"]
+    table global_trusted_vni {
+        key = {
+            meta.rx_encap.vni: range @SaiVal[name = "vni_range"];
+        }
+
+        actions = {
+            permit;
+        }
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni"]
path: dash-pipeline/bmv2/stages/trusted_vni.p4
user: login: jimmyzhai
body: Added
created_at: 2025-04-09T04:59:33Z
author_association: COLLABORATOR
diff_hunk: @@ -278,6 +277,7 @@ control dash_ingress(
             (meta.flow_sync_state == dash_flow_sync_state_t.FLOW_MISS &&
              hdr.packet_meta.packet_source == dash_packet_source_t.EXTERNAL))
         {
+            trusted_vni_stage.apply(hdr, meta);
path: dash-pipeline/bmv2/dash_pipeline.p4
user: login: jimmyzhai
body: Add a TODO comment and will revisit it after inbound routing HLD done.
created_at: 2025-04-09T05:00:32Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,46 @@
+#ifndef _DASH_STAGE_TRUSTED_VNI_P4_
+#define _DASH_STAGE_TRUSTED_VNI_P4_
+
+control trusted_vni_stage(
+    inout headers_t hdr,
+    inout metadata_t meta)
+{
+    action permit() {}
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni", order=0, isobject="false"]
+    table global_trusted_vni {
+        key = {
+            meta.rx_encap.vni: range @SaiVal[name = "vni_range"];
+        }
+
+        actions = {
+            permit;
+        }
+    }
+
+    @SaiTable[single_match_priority = "true", api = "dash_trusted_vni", order=1]
+    table eni_trusted_vni {
+        key = {
+            meta.eni_id : exact @SaiVal[type="sai_object_id_t"];
+            meta.rx_encap.vni: range @SaiVal[name = "vni_range"];
+        }
+
+        actions = {
+            permit;
+            @defaultonly deny(meta);
+        }
+        const default_action = deny(meta);
+    }
+
+    apply {
+        if (global_trusted_vni.apply().hit) {
+            return;
+        }
+
+        if (!eni_trusted_vni.apply().hit) {
path: dash-pipeline/bmv2/stages/trusted_vni.p4
user: login: jimmyzhai
body: Have added TODO comment before `trusted_vni_stage.apply(hdr, meta)`. 
created_at: 2025-04-09T05:02:46Z
author_association: COLLABORATOR

PR comments:
user: login: mssonicbld
created_at: 2025-03-22T07:31:29Z
body: /azp run
author_association: NONE
user: login: azure-pipelines[bot]
created_at: 2025-03-22T07:31:35Z
body: <samp>
Commenter does not have sufficient privileges for PR 672 in repo sonic-net/DASH<br>

</samp>
author_association: NONE
user: login: mssonicbld
created_at: 2025-03-25T01:24:20Z
body: /azp run
author_association: NONE
user: login: azure-pipelines[bot]
created_at: 2025-03-25T01:24:26Z
body: <samp>
Commenter does not have sufficient privileges for PR 672 in repo sonic-net/DASH<br>

</samp>
author_association: NONE
user: login: mssonicbld
created_at: 2025-03-25T12:22:55Z
body: /azp run
author_association: NONE
user: login: azure-pipelines[bot]
created_at: 2025-03-25T12:23:01Z
body: <samp>
Commenter does not have sufficient privileges for PR 672 in repo sonic-net/DASH<br>

</samp>
author_association: NONE
user: login: mssonicbld
created_at: 2025-03-31T13:32:42Z
body: /azp run
author_association: NONE
user: login: azure-pipelines[bot]
created_at: 2025-03-31T13:32:48Z
body: <samp>
Commenter does not have sufficient privileges for PR 672 in repo sonic-net/DASH<br>

</samp>
author_association: NONE
user: login: mssonicbld
created_at: 2025-04-03T01:50:12Z
body: /azp run
author_association: NONE
user: login: azure-pipelines[bot]
created_at: 2025-04-03T01:50:18Z
body: <samp>
Commenter does not have sufficient privileges for PR 672 in repo sonic-net/DASH<br>

</samp>
author_association: NONE
user: login: mssonicbld
created_at: 2025-04-03T04:05:29Z
body: /azp run
author_association: NONE
user: login: azure-pipelines[bot]
created_at: 2025-04-03T04:05:34Z
body: <samp>
Commenter does not have sufficient privileges for PR 672 in repo sonic-net/DASH<br>

</samp>
author_association: NONE
user: login: mssonicbld
created_at: 2025-04-03T14:51:58Z
body: /azp run
author_association: NONE
user: login: azure-pipelines[bot]
created_at: 2025-04-03T14:52:04Z
body: <samp>
Commenter does not have sufficient privileges for PR 672 in repo sonic-net/DASH<br>

</samp>
author_association: NONE
user: login: mssonicbld
created_at: 2025-04-09T04:56:42Z
body: /azp run
author_association: NONE
user: login: azure-pipelines[bot]
created_at: 2025-04-09T04:56:48Z
body: <samp>
Commenter does not have sufficient privileges for PR 672 in repo sonic-net/DASH<br>

</samp>
author_association: NONE
user: login: mssonicbld
created_at: 2025-04-09T05:11:17Z
body: /azp run
author_association: NONE
user: login: azure-pipelines[bot]
created_at: 2025-04-09T05:11:23Z
body: <samp>
Commenter does not have sufficient privileges for PR 672 in repo sonic-net/DASH<br>

</samp>
author_association: NONE