Skip to content

Commit

Permalink
[SAIP4] Models IPFIX mirroring encap. (sonic-net#628)
Browse files Browse the repository at this point in the history
Co-authored-by: kishanps <[email protected]>
  • Loading branch information
divyagayathri-hcl and kishanps authored Oct 19, 2024
1 parent eb418f0 commit b0e15b8
Show file tree
Hide file tree
Showing 17 changed files with 702 additions and 89 deletions.
5 changes: 5 additions & 0 deletions sai_p4/fixed/headers.p4
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ header ipv6_t {
ipv6_addr_t dst_addr;
}

#define UDP_HEADER_BYTES 8

header udp_t {
bit<16> src_port;
bit<16> dst_port;
Expand Down Expand Up @@ -143,6 +145,8 @@ header gre_t {
bit<16> protocol;
}

#define IPFIX_HEADER_BYTES 16

// IP Flow Information Export (IPFIX) header, pursuant to RFC 7011 section 3.1.
header ipfix_t {
// Version of IPFIX to which this Message conforms.
Expand All @@ -161,6 +165,7 @@ header ipfix_t {
bit<32> observation_domain_id;
}

#define PSAMP_EXTENDED_BYTES 28
// PSAMP extended header, pursuant to RFC5476.
header psamp_extended_t {
bit<16> template_id;
Expand Down
2 changes: 1 addition & 1 deletion sai_p4/fixed/ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
#define ROUTING_SET_MULTICAST_SRC_MAC_ACTION_ID 0x01000019 // 16777241
#define MIRRORING_MIRROR_AS_IPV4_ERSPAN_ACTION_ID 0x01000007 // 16777223
#define CLONING_INGRESS_CLONE_ACTION_ID 0x0100001C // 16777244
#define CLONING_MIRROR_WITH_IPFIX_ENCAPSULATION_ACTION_ID \
#define CLONING_MIRROR_WITH_VLAN_TAG_AND_IPFIX_ENCAPSULATION_ACTION_ID \
0x0100001D // 16777245
#define L3_ADMIT_ACTION_ID 0x01000008 // 16777224
#define MIRRORING_SET_PRE_SESSION_ACTION_ID 0x01000009 // 16777225
Expand Down
26 changes: 25 additions & 1 deletion sai_p4/fixed/metadata.p4
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,15 @@ struct headers_t {
// PacketOut header; extracted only for packets received from the controller.
packet_out_header_t packet_out_header;

// -- mirroring encap headers ------------------------------------------------
ethernet_t mirror_encap_ethernet;
vlan_t mirror_encap_vlan;
ipv6_t mirror_encap_ipv6;
udp_t mirror_encap_udp;
ipfix_t ipfix;
psamp_extended_t psamp_extended;
// -- end of mirroring encap headers -----------------------------------------

ethernet_t ethernet;
vlan_t vlan;

Expand Down Expand Up @@ -214,7 +223,7 @@ struct local_metadata_t {
// pipeline.
bool marked_to_copy;

// Mirroring related fields.
// -- Mirroring related fields -----------------------------------------------
// We can't group them into a struct as BMv2 doesn't support passing structs
// into clone3.
// If true, the packet needs to be mirrored at the end of the ingress
Expand All @@ -224,6 +233,21 @@ struct local_metadata_t {
// Valid iff marked_to_mirror is true.
mirror_session_id_t mirror_session_id;
port_id_t mirror_egress_port;
@field_list(PreservedFieldList.MIRROR_AND_PACKET_IN_COPY)
ethernet_addr_t mirror_encap_src_mac;
@field_list(PreservedFieldList.MIRROR_AND_PACKET_IN_COPY)
ethernet_addr_t mirror_encap_dst_mac;
@field_list(PreservedFieldList.MIRROR_AND_PACKET_IN_COPY)
vlan_id_t mirror_encap_vlan_id;
@field_list(PreservedFieldList.MIRROR_AND_PACKET_IN_COPY)
ipv6_addr_t mirror_encap_src_ip;
@field_list(PreservedFieldList.MIRROR_AND_PACKET_IN_COPY)
ipv6_addr_t mirror_encap_dst_ip;
@field_list(PreservedFieldList.MIRROR_AND_PACKET_IN_COPY)
bit<16> mirror_encap_udp_src_port;
@field_list(PreservedFieldList.MIRROR_AND_PACKET_IN_COPY)
bit<16> mirror_encap_udp_dst_port;
// -- end of mirroring related fields ----------------------------------------

// Packet-in related fields, which we can't group into a struct, because BMv2
// doesn't support passing structs in clone3.
Expand Down
90 changes: 84 additions & 6 deletions sai_p4/fixed/mirroring.p4
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ control mirror_session_lookup(inout headers_t headers,
// SAI_MIRROR_SESSION_ATTR_TTL
// SAI_MIRROR_SESSION_ATTR_TOS
// TODO: Remove mirror_as_ipv4_erspan once the the switch
// supports mirror_with_psamp_encapsulation. This action is currently needed
// supports mirror_with_ipfix_encapsulation. This action is currently needed
// for mirror_session_table since it is the only action by the switch in this
// table.
@id(MIRRORING_MIRROR_AS_IPV4_ERSPAN_ACTION_ID)
Expand All @@ -43,13 +43,39 @@ control mirror_session_lookup(inout headers_t headers,
// * SAI_MIRROR_SESSION_ATTR_IPFIX_ENCAPSULATION_TYPE to
// SAI_IPFIX_ENCAPSULATION_TYPE_EXTENDED
// * SAI_MIRROR_SESSION_ATTR_MONITOR_PORT to `monitor_port`
@id(CLONING_MIRROR_WITH_IPFIX_ENCAPSULATION_ACTION_ID)
// TODO: Add params needed for IPFIX mirroring.
// * SAI_MIRROR_SESSION_ATTR_MONITOR_FAILOVER_PORT to
// `monitor_failover_port
// * SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS
// * SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS
// * SAI_MIRROR_SESSION_ATTR_VLAN_TPID
// * SAI_MIRROR_SESSION_ATTR_VLAN_ID
// * SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS
// * SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS
// * SAI_MIRROR_SESSION_ATTR_UDP_SRC_PORT
// * SAI_MIRROR_SESSION_ATTR_UDP_DST_PORT
@id(CLONING_MIRROR_WITH_VLAN_TAG_AND_IPFIX_ENCAPSULATION_ACTION_ID)
// TODO: Remove unsupported annotation once the switch stack
// supports this table.
@unsupported
action mirror_with_ipfix_encapsulation(@id(1) port_id_t monitor_port) {
action mirror_with_vlan_tag_and_ipfix_encapsulation(
@id(1) port_id_t monitor_port,
@id(2) port_id_t monitor_failover_port,
@id(3) @format(MAC_ADDRESS) ethernet_addr_t mirror_encap_src_mac,
@id(4) @format(MAC_ADDRESS) ethernet_addr_t mirror_encap_dst_mac,
@id(6) vlan_id_t mirror_encap_vlan_id,
@id(7) @format(IPV6_ADDRESS) ipv6_addr_t mirror_encap_dst_ip,
@id(8) @format(IPV6_ADDRESS) ipv6_addr_t mirror_encap_src_ip,
@id(9) bit<16> mirror_encap_udp_src_port,
@id(10) bit<16> mirror_encap_udp_dst_port) {
local_metadata.mirror_egress_port = monitor_port;
// monitor_failover_port's effect is not modeled.
local_metadata.mirror_encap_src_mac = mirror_encap_src_mac;
local_metadata.mirror_encap_dst_mac = mirror_encap_dst_mac;
local_metadata.mirror_encap_vlan_id = mirror_encap_vlan_id;
local_metadata.mirror_encap_src_ip = mirror_encap_src_ip;
local_metadata.mirror_encap_dst_ip = mirror_encap_dst_ip;
local_metadata.mirror_encap_udp_src_port = mirror_encap_udp_src_port;
local_metadata.mirror_encap_udp_dst_port = mirror_encap_udp_dst_port;
}

// Corresponding SAI object: SAI_OBJECT_TYPE_MIRROR_SESSION
Expand All @@ -63,7 +89,7 @@ control mirror_session_lookup(inout headers_t headers,
}
actions = {
@proto_id(1) mirror_as_ipv4_erspan;
@proto_id(2) mirror_with_ipfix_encapsulation;
@proto_id(2) mirror_with_vlan_tag_and_ipfix_encapsulation;
@defaultonly NoAction;
}

Expand All @@ -83,8 +109,60 @@ control mirroring_encap(inout headers_t headers,
inout local_metadata_t local_metadata,
inout standard_metadata_t standard_metadata) {
apply {
// All mirrored packets are encapped with
// ==================================================================
// | Ethernet + vlan | IPv6 | UDP | IPFIX + PSAMP extended| payload |
// ==================================================================
// headers. Fields for headers mostly come from mirror-related
// local_metadata.
if (IS_MIRROR_COPY(standard_metadata)) {
// TODO: Implements mirroring encap.
headers.mirror_encap_ethernet.setValid();
headers.mirror_encap_ethernet.src_addr =
local_metadata.mirror_encap_src_mac;
headers.mirror_encap_ethernet.dst_addr =
local_metadata.mirror_encap_dst_mac;
headers.mirror_encap_ethernet.ether_type = ETHERTYPE_8021Q; // VLAN

headers.mirror_encap_vlan.setValid();
headers.mirror_encap_vlan.ether_type = ETHERTYPE_IPV6;
headers.mirror_encap_vlan.vlan_id = local_metadata.mirror_encap_vlan_id;

headers.mirror_encap_ipv6.setValid();
headers.mirror_encap_ipv6.version = 4w6;
// Mirrored packets' traffic class is 0.
headers.mirror_encap_ipv6.dscp = 0;
headers.mirror_encap_ipv6.ecn = 0;
// Mirrored packets' hop_limit is 16.
headers.mirror_encap_ipv6.hop_limit = 16;
headers.mirror_encap_ipv6.flow_label = 0;
// payload_lentgh for ipv6 packets is the byte length of headers after
// ipv6 + payload. in our case, that's the UDP, IPFIX and PSAMP headers.
// The mirror replicated packet becomes the new payload during mirror
// encap, so standard_metadata.packet_length becomes the payload length.
// contains the length of payload + all headers.
headers.mirror_encap_ipv6.payload_length =
(bit<16>)standard_metadata.packet_length
+ UDP_HEADER_BYTES
+ IPFIX_HEADER_BYTES
+ PSAMP_EXTENDED_BYTES;
headers.mirror_encap_ipv6.next_header = IP_PROTOCOL_UDP;
headers.mirror_encap_ipv6.src_addr = local_metadata.mirror_encap_src_ip;
headers.mirror_encap_ipv6.dst_addr = local_metadata.mirror_encap_dst_ip;

headers.mirror_encap_udp.setValid();
headers.mirror_encap_udp.src_port =
local_metadata.mirror_encap_udp_src_port;
headers.mirror_encap_udp.dst_port =
local_metadata.mirror_encap_udp_dst_port;
headers.mirror_encap_udp.hdr_length =
headers.mirror_encap_ipv6.payload_length;
// Mirrored packets' UDP checksum is 0.
headers.mirror_encap_udp.checksum = 0;

// IPFIX and PSAMP fields are opaque to P4 so we only set their headers
// as valid.
headers.ipfix.setValid();
headers.psamp_extended.setValid();
}
}
} // control mirroring_encap
Expand Down
6 changes: 6 additions & 0 deletions sai_p4/fixed/parser.p4
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,12 @@ control packet_deparser(packet_out packet, in headers_t headers) {
#if defined(PLATFORM_BMV2) || defined(PLATFORM_P4SYMBOLIC)
packet.emit(headers.packet_in_header);
#endif
packet.emit(headers.mirror_encap_ethernet);
packet.emit(headers.mirror_encap_vlan);
packet.emit(headers.mirror_encap_ipv6);
packet.emit(headers.mirror_encap_udp);
packet.emit(headers.ipfix);
packet.emit(headers.psamp_extended);
packet.emit(headers.ethernet);
packet.emit(headers.tunnel_encap_ipv6);
packet.emit(headers.tunnel_encap_gre);
Expand Down
28 changes: 20 additions & 8 deletions sai_p4/fixed/vlan.p4
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ control vlan_untag(inout headers_t headers,
}
} // control vlan_untag

// Apply VLAN checks for packets in ingress pipeline.
// This control block assumes vlan_untag control block has been called
// and VLAN-related information is stored in metadata instead of in headers.
control ingress_vlan_checks(inout headers_t headers,
inout local_metadata_t local_metadata,
inout standard_metadata_t standard_metadata) {
Expand All @@ -77,15 +80,23 @@ control ingress_vlan_checks(inout headers_t headers,
}
} // control ingress_vlan_checks

// Apply VLAN checks for forwarded packets.
// TODO: Add VLAN checks for mirrored packets.
// Apply VLAN checks for packets in egress pipeline (except for punted packets).
// This control block assumes vlan_tag control block has not been called and
// VLAN-related information is stored in metadata, instead of in headers.
control egress_vlan_checks(inout headers_t headers,
inout local_metadata_t local_metadata,
inout standard_metadata_t standard_metadata) {
apply {
if (local_metadata.enable_vlan_checks &&
!IS_RESERVED_VLAN_ID(local_metadata.vlan_id)) {
mark_to_drop(standard_metadata);
if (local_metadata.enable_vlan_checks) {
// For mirrored-encapped packets, the encapped VLAN header's VLAN ID
// metadata is different from that of normal VLAN header.
if (IS_MIRROR_COPY(standard_metadata) &&
!IS_RESERVED_VLAN_ID(local_metadata.mirror_encap_vlan_id)) {
mark_to_drop(standard_metadata);
} else if (!IS_PACKET_IN_COPY(standard_metadata) &&
!IS_RESERVED_VLAN_ID(local_metadata.vlan_id)) {
mark_to_drop(standard_metadata);
}
}
}
} // control egress_vlan_checks
Expand All @@ -95,9 +106,10 @@ control vlan_tag(inout headers_t headers,
inout local_metadata_t local_metadata,
inout standard_metadata_t standard_metadata) {
apply {
// TODO: Forward and Multicast packets should be vlan tagged
// but not mirrored packets.
if (!IS_RESERVED_VLAN_ID(local_metadata.vlan_id)) {
if (!IS_RESERVED_VLAN_ID(local_metadata.vlan_id) &&
!IS_MIRROR_COPY(standard_metadata)) {
// Mirroring encapsulates a series of headers, including a VLAN header.
// To seperate concerns, vlan encapping for mirroring is skipped here.
headers.vlan.setValid();
headers.vlan.priority_code_point = 0;
headers.vlan.drop_eligible_indicator = 0;
Expand Down
50 changes: 48 additions & 2 deletions sai_p4/instantiations/google/fabric_border_router.p4info.pb.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1422,8 +1422,8 @@ actions {
actions {
preamble {
id: 16777245
name: "ingress.mirror_session_lookup.mirror_with_ipfix_encapsulation"
alias: "mirror_with_ipfix_encapsulation"
name: "ingress.mirror_session_lookup.mirror_with_vlan_tag_and_ipfix_encapsulation"
alias: "mirror_with_vlan_tag_and_ipfix_encapsulation"
annotations: "@unsupported"
}
params {
Expand All @@ -1433,6 +1433,52 @@ actions {
name: "port_id_t"
}
}
params {
id: 2
name: "monitor_failover_port"
type_name {
name: "port_id_t"
}
}
params {
id: 3
name: "mirror_encap_src_mac"
annotations: "@format(MAC_ADDRESS)"
bitwidth: 48
}
params {
id: 4
name: "mirror_encap_dst_mac"
annotations: "@format(MAC_ADDRESS)"
bitwidth: 48
}
params {
id: 6
name: "mirror_encap_vlan_id"
bitwidth: 12
}
params {
id: 7
name: "mirror_encap_dst_ip"
annotations: "@format(IPV6_ADDRESS)"
bitwidth: 128
}
params {
id: 8
name: "mirror_encap_src_ip"
annotations: "@format(IPV6_ADDRESS)"
bitwidth: 128
}
params {
id: 9
name: "mirror_encap_udp_src_port"
bitwidth: 16
}
params {
id: 10
name: "mirror_encap_udp_dst_port"
bitwidth: 16
}
}
actions {
preamble {
Expand Down
50 changes: 48 additions & 2 deletions sai_p4/instantiations/google/middleblock.p4info.pb.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1467,8 +1467,8 @@ actions {
actions {
preamble {
id: 16777245
name: "ingress.mirror_session_lookup.mirror_with_ipfix_encapsulation"
alias: "mirror_with_ipfix_encapsulation"
name: "ingress.mirror_session_lookup.mirror_with_vlan_tag_and_ipfix_encapsulation"
alias: "mirror_with_vlan_tag_and_ipfix_encapsulation"
annotations: "@unsupported"
}
params {
Expand All @@ -1478,6 +1478,52 @@ actions {
name: "port_id_t"
}
}
params {
id: 2
name: "monitor_failover_port"
type_name {
name: "port_id_t"
}
}
params {
id: 3
name: "mirror_encap_src_mac"
annotations: "@format(MAC_ADDRESS)"
bitwidth: 48
}
params {
id: 4
name: "mirror_encap_dst_mac"
annotations: "@format(MAC_ADDRESS)"
bitwidth: 48
}
params {
id: 6
name: "mirror_encap_vlan_id"
bitwidth: 12
}
params {
id: 7
name: "mirror_encap_dst_ip"
annotations: "@format(IPV6_ADDRESS)"
bitwidth: 128
}
params {
id: 8
name: "mirror_encap_src_ip"
annotations: "@format(IPV6_ADDRESS)"
bitwidth: 128
}
params {
id: 9
name: "mirror_encap_udp_src_port"
bitwidth: 16
}
params {
id: 10
name: "mirror_encap_udp_dst_port"
bitwidth: 16
}
}
actions {
preamble {
Expand Down
Loading

0 comments on commit b0e15b8

Please sign in to comment.