[SDFAB-357] Backport slicing in fabric and add support for QFI in PDR and fabric
Change-Id: Ieb10140dc0029a0cbf59ddfbb77f64f9a8c7379e
(cherry picked from commit 411f6f7f461db6491d627c2cb31642bdd6e7c8d8)
diff --git a/pipelines/fabric/impl/src/main/resources/include/control/acl.p4 b/pipelines/fabric/impl/src/main/resources/include/control/acl.p4
index ae86e3b..9d7c7ba 100644
--- a/pipelines/fabric/impl/src/main/resources/include/control/acl.p4
+++ b/pipelines/fabric/impl/src/main/resources/include/control/acl.p4
@@ -21,29 +21,22 @@
#include "../header.p4"
control Acl (inout parsed_headers_t hdr,
- inout fabric_metadata_t fabric_metadata,
+ inout fabric_metadata_t fabric_md,
inout standard_metadata_t standard_metadata) {
-
- ipv4_addr_t ipv4_src = 0;
- ipv4_addr_t ipv4_dst = 0;
- bit<8> ip_proto = 0;
- l4_port_t l4_sport = 0;
- l4_port_t l4_dport = 0;
-
/*
* ACL Table.
*/
direct_counter(CounterType.packets_and_bytes) acl_counter;
action set_next_id_acl(next_id_t next_id) {
- fabric_metadata.next_id = next_id;
+ fabric_md.next_id = next_id;
acl_counter.count();
}
// Send immendiatelly to CPU - skip the rest of ingress.
action punt_to_cpu() {
standard_metadata.egress_spec = CPU_PORT;
- fabric_metadata.skip_next = _TRUE;
+ fabric_md.skip_next = _TRUE;
acl_counter.count();
}
@@ -55,7 +48,7 @@
action drop() {
mark_to_drop(standard_metadata);
- fabric_metadata.skip_next = _TRUE;
+ fabric_md.skip_next = _TRUE;
acl_counter.count();
}
@@ -70,14 +63,14 @@
hdr.ethernet.src_addr : ternary @name("eth_src"); // 48
hdr.vlan_tag.vlan_id : ternary @name("vlan_id"); // 12
hdr.eth_type.value : ternary @name("eth_type"); // 16
- ipv4_src : ternary @name("ipv4_src"); // 32
- ipv4_dst : ternary @name("ipv4_dst"); // 32
- ip_proto : ternary @name("ip_proto"); // 8
+ fabric_md.lkp.ipv4_src : ternary @name("ipv4_src"); // 32
+ fabric_md.lkp.ipv4_dst : ternary @name("ipv4_dst"); // 32
+ fabric_md.lkp.ip_proto : ternary @name("ip_proto"); // 8
hdr.icmp.icmp_type : ternary @name("icmp_type"); // 8
hdr.icmp.icmp_code : ternary @name("icmp_code"); // 8
- l4_sport : ternary @name("l4_sport"); // 16
- l4_dport : ternary @name("l4_dport"); // 16
- fabric_metadata.port_type : ternary @name("port_type"); // 2
+ fabric_md.lkp.l4_sport : ternary @name("l4_sport"); // 16
+ fabric_md.lkp.l4_dport : ternary @name("l4_dport"); // 16
+ fabric_md.port_type : ternary @name("port_type"); // 2
}
actions = {
@@ -94,29 +87,6 @@
}
apply {
- if (hdr.gtpu.isValid() && hdr.inner_ipv4.isValid()) {
- ipv4_src = hdr.inner_ipv4.src_addr;
- ipv4_dst = hdr.inner_ipv4.dst_addr;
- ip_proto = hdr.inner_ipv4.protocol;
- if (hdr.inner_tcp.isValid()) {
- l4_sport = hdr.inner_tcp.sport;
- l4_dport = hdr.inner_tcp.dport;
- } else if (hdr.inner_udp.isValid()) {
- l4_sport = hdr.inner_udp.sport;
- l4_dport = hdr.inner_udp.dport;
- }
- } else if (hdr.ipv4.isValid()) {
- ipv4_src = hdr.ipv4.src_addr;
- ipv4_dst = hdr.ipv4.dst_addr;
- ip_proto = hdr.ipv4.protocol;
- if (hdr.tcp.isValid()) {
- l4_sport = hdr.tcp.sport;
- l4_dport = hdr.tcp.dport;
- } else if (hdr.udp.isValid()) {
- l4_sport = hdr.udp.sport;
- l4_dport = hdr.udp.dport;
- }
- }
acl.apply();
}
}
diff --git a/pipelines/fabric/impl/src/main/resources/include/control/lookup_md_init.p4 b/pipelines/fabric/impl/src/main/resources/include/control/lookup_md_init.p4
new file mode 100644
index 0000000..c672bc9
--- /dev/null
+++ b/pipelines/fabric/impl/src/main/resources/include/control/lookup_md_init.p4
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LOOKUP__
+#define __LOOKUP__
+
+control LookupMdInit (in parsed_headers_t hdr,
+ out lookup_metadata_t lkp_md) {
+ apply {
+ lkp_md.is_ipv4 = _FALSE;
+ lkp_md.ipv4_src = 0;
+ lkp_md.ipv4_dst = 0;
+ lkp_md.ip_proto = 0;
+ lkp_md.l4_sport = 0;
+ lkp_md.l4_dport = 0;
+ lkp_md.icmp_type = 0;
+ lkp_md.icmp_code = 0;
+ if (hdr.inner_ipv4.isValid()) {
+ lkp_md.is_ipv4 = true;
+ lkp_md.ipv4_src = hdr.inner_ipv4.src_addr;
+ lkp_md.ipv4_dst = hdr.inner_ipv4.dst_addr;
+ lkp_md.ip_proto = hdr.inner_ipv4.protocol;
+ if (hdr.inner_tcp.isValid()) {
+ lkp_md.l4_sport = hdr.inner_tcp.sport;
+ lkp_md.l4_dport = hdr.inner_tcp.dport;
+ } else if (hdr.inner_udp.isValid()) {
+ lkp_md.l4_sport = hdr.inner_udp.sport;
+ lkp_md.l4_dport = hdr.inner_udp.dport;
+ } else if (hdr.inner_icmp.isValid()) {
+ lkp_md.icmp_type = hdr.inner_icmp.icmp_type;
+ lkp_md.icmp_code = hdr.inner_icmp.icmp_code;
+ }
+ } else if (hdr.ipv4.isValid()) {
+ lkp_md.is_ipv4 = true;
+ lkp_md.ipv4_src = hdr.ipv4.src_addr;
+ lkp_md.ipv4_dst = hdr.ipv4.dst_addr;
+ lkp_md.ip_proto = hdr.ipv4.protocol;
+ if (hdr.tcp.isValid()) {
+ lkp_md.l4_sport = hdr.tcp.sport;
+ lkp_md.l4_dport = hdr.tcp.dport;
+ } else if (hdr.udp.isValid()) {
+ lkp_md.l4_sport = hdr.udp.sport;
+ lkp_md.l4_dport = hdr.udp.dport;
+ } else if (hdr.icmp.isValid()) {
+ lkp_md.icmp_type = hdr.icmp.icmp_type;
+ lkp_md.icmp_code = hdr.icmp.icmp_code;
+ }
+ }
+ }
+}
+
+#endif
+
diff --git a/pipelines/fabric/impl/src/main/resources/include/control/slicing.p4 b/pipelines/fabric/impl/src/main/resources/include/control/slicing.p4
new file mode 100644
index 0000000..87d887a
--- /dev/null
+++ b/pipelines/fabric/impl/src/main/resources/include/control/slicing.p4
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SLICING__
+#define __SLICING__
+
+// ACL-like classification, maps lookup metadata to slice_id and tc. For UE
+// traffic, values can be overriden later by the SPGW PDR tables.
+// To apply the same slicing and QoS treatment end-to-end, we use the IPv4 DSCP
+// field to piggyback slice_id and tc (see EgressDscpRewriter). This is
+// especially important for UE traffic, where classification based on PDRs can
+// only happen at the ingress leaf switch (implementing the UPF function).
+// As such, for traffic coming from selected ports, we allow trusting the
+// slice_id and tc values carried in the dscp.
+control IngressSliceTcClassifier (in parsed_headers_t hdr,
+ inout fabric_metadata_t fabric_md,
+ in standard_metadata_t standard_metadata) {
+
+ direct_counter(CounterType.packets) classifier_stats;
+
+ action set_slice_id_tc(slice_id_t slice_id, tc_t tc) {
+ fabric_md.slice_id = slice_id;
+ fabric_md.tc = tc;
+ classifier_stats.count();
+ }
+
+ // Should be used only for infrastructure ports (leaf-leaf, or leaf-spine),
+ // or ports facing servers that implement early classification based on the
+ // SDFAB DSCP encoding (slice_id++tc).
+ action trust_dscp() {
+ fabric_md.slice_id = hdr.ipv4.dscp[SLICE_ID_WIDTH+TC_WIDTH-1:TC_WIDTH];
+ fabric_md.tc = hdr.ipv4.dscp[TC_WIDTH-1:0];
+ classifier_stats.count();
+ }
+
+ table classifier {
+ key = {
+ standard_metadata.ingress_port : ternary @name("ig_port");
+ fabric_md.lkp.ipv4_src : ternary @name("ipv4_src");
+ fabric_md.lkp.ipv4_dst : ternary @name("ipv4_dst");
+ fabric_md.lkp.ip_proto : ternary @name("ip_proto");
+ fabric_md.lkp.l4_sport : ternary @name("l4_sport");
+ fabric_md.lkp.l4_dport : ternary @name("l4_dport");
+ }
+ actions = {
+ set_slice_id_tc;
+ trust_dscp;
+ }
+ const default_action = set_slice_id_tc(DEFAULT_SLICE_ID, DEFAULT_TC);
+ counters = classifier_stats;
+ size = QOS_CLASSIFIER_TABLE_SIZE;
+ }
+
+ apply {
+ classifier.apply();
+ }
+}
+
+// Provides metering and mapping to queues based on slice_id and tc. Should be
+// applied after any other block writing slice_id and tc.
+control IngressQos (inout fabric_metadata_t fabric_md,
+ inout standard_metadata_t standard_metadata) {
+
+ // One meter per tc per slice. The index should be slice_id++tc.
+ meter(1 << SLICE_TC_WIDTH, MeterType.bytes) slice_tc_meter;
+
+ direct_counter(CounterType.packets) queues_stats;
+
+ action set_queue(qid_t qid) {
+ // We can't set the queue id in bmv2.
+ queues_stats.count();
+ }
+
+ // For policing.
+ action meter_drop() {
+ mark_to_drop(standard_metadata);
+ queues_stats.count();
+ }
+
+ table queues {
+ key = {
+ fabric_md.slice_id: exact @name("slice_id");
+ fabric_md.tc: exact @name("tc");
+ fabric_md.packet_color: ternary @name("color"); // 0=GREEN, 1=YELLOW, 2=RED
+ }
+ actions = {
+ set_queue;
+ meter_drop;
+ }
+ const default_action = set_queue(0); // 0 = Best Effort
+ counters = queues_stats;
+ // Two times the number of tcs for all slices, because we might need to
+ // match on different colors for the same slice and tc.
+ size = 1 << (SLICE_TC_WIDTH + 1);
+ }
+
+ slice_tc_t slice_tc = fabric_md.slice_id++fabric_md.tc;
+
+ apply {
+ // Meter index should be 0 for all packets with default slice_id and tc.
+ slice_tc_meter.execute_meter((bit<32>) slice_tc, fabric_md.packet_color);
+ fabric_md.dscp = slice_tc;
+ queues.apply();
+ }
+}
+
+// Allows per-egress port rewriting of the outermost IPv4 DSCP field to
+// piggyback slice_id and tc across the fabric.
+control EgressDscpRewriter (inout parsed_headers_t hdr,
+ in fabric_metadata_t fabric_md,
+ in standard_metadata_t standard_metadata) {
+
+ bit<6> tmp_dscp = fabric_md.dscp;
+
+ action rewrite() {
+ // Do nothing, tmp_dscp is already initialized.
+ }
+
+ // Sets the DSCP field to zero. Should be used for edge ports facing devices
+ // that do not support the SDFAB DSCP encoding.
+ action clear() {
+ tmp_dscp = 0;
+ }
+
+ table rewriter {
+ key = {
+ standard_metadata.egress_port : exact @name("eg_port");
+ }
+ actions = {
+ rewrite;
+ clear;
+ @defaultonly nop;
+ }
+ const default_action = nop;
+ size = DSCP_REWRITER_TABLE_SIZE;
+ }
+
+ apply {
+ if (rewriter.apply().hit) {
+#ifdef WITH_SPGW
+ if (hdr.gtpu_ipv4.isValid()) {
+ hdr.ipv4.dscp = tmp_dscp;
+ } else
+#endif // WITH_SPGW
+ if (hdr.ipv4.isValid()) {
+ hdr.inner_ipv4.dscp = tmp_dscp;
+ }
+ }
+ }
+}
+
+#endif
diff --git a/pipelines/fabric/impl/src/main/resources/include/control/spgw.p4 b/pipelines/fabric/impl/src/main/resources/include/control/spgw.p4
index adacd9a..6750dbd 100644
--- a/pipelines/fabric/impl/src/main/resources/include/control/spgw.p4
+++ b/pipelines/fabric/impl/src/main/resources/include/control/spgw.p4
@@ -45,6 +45,8 @@
hdr.ipv4 = hdr.inner_ipv4;
hdr.inner_ipv4.setInvalid();
hdr.gtpu.setInvalid();
+ hdr.gtpu_options.setInvalid();
+ hdr.gtpu_ext_psc.setInvalid();
}
@hidden
action decap_inner_tcp() {
@@ -115,10 +117,11 @@
//===== Interface Tables ======//
//=============================//
- action load_iface(spgw_interface_t src_iface) {
+ action load_iface(spgw_interface_t src_iface, slice_id_t slice_id) {
// Interface type can be access, core, from_dbuf (see InterfaceType enum)
fabric_md.spgw.src_iface = src_iface;
fabric_md.spgw.skip_spgw = _FALSE;
+ fabric_md.slice_id = slice_id;
}
action iface_miss() {
fabric_md.spgw.src_iface = SPGW_IFACE_UNKNOWN;
@@ -143,21 +146,26 @@
//=============================//
//===== PDR Tables ======//
//=============================//
-
action load_pdr(pdr_ctr_id_t ctr_id,
far_id_t far_id,
- bit<1> needs_gtpu_decap) {
+ bit<1> needs_gtpu_decap,
+ tc_t tc) {
fabric_md.spgw.ctr_id = ctr_id;
fabric_md.spgw.far_id = far_id;
fabric_md.spgw.needs_gtpu_decap = (_BOOL)needs_gtpu_decap;
+ fabric_md.tc = tc;
}
- action load_pdr_qos(pdr_ctr_id_t ctr_id,
- far_id_t far_id,
- bit<1> needs_gtpu_decap,
- qid_t qid) {
- load_pdr(ctr_id, far_id, needs_gtpu_decap);
- // we cannot set the qid, since bmv2 does not support it
+ action load_pdr_qos(pdr_ctr_id_t ctr_id,
+ far_id_t far_id,
+ bit<1> needs_gtpu_decap,
+ // Used to push QFI, valid for 5G traffic only
+ bit<1> needs_qfi_push,
+ qfi_t qfi,
+ tc_t tc) {
+ load_pdr(ctr_id, far_id, needs_gtpu_decap, tc);
+ fabric_md.spgw.qfi = qfi;
+ fabric_md.spgw.needs_qfi_push = (_BOOL)needs_qfi_push;
}
// These two tables scale well and cover the average case PDR
@@ -177,6 +185,10 @@
key = {
hdr.ipv4.dst_addr : exact @name("tunnel_ipv4_dst");
hdr.gtpu.teid : exact @name("teid");
+ // Match valid only for 5G traffic
+ hdr.gtpu_ext_psc.isValid() : exact @name("has_qfi");
+ // QFI metadata is 0 when gptu_ext_psc is invalid.
+ fabric_md.spgw.qfi : exact @name("qfi");
}
actions = {
load_pdr;
@@ -294,7 +306,6 @@
counter(MAX_PDR_COUNTERS, CounterType.packets_and_bytes) pdr_counter;
-
@hidden
action gtpu_encap() {
hdr.gtpu_ipv4.setValid();
@@ -320,7 +331,6 @@
+ (UDP_HDR_SIZE + GTP_HDR_SIZE);
hdr.gtpu_udp.checksum = 0; // Updated later, if WITH_SPGW_UDP_CSUM_UPDATE
-
hdr.outer_gtpu.setValid();
hdr.outer_gtpu.version = GTP_V1;
hdr.outer_gtpu.pt = GTP_PROTOCOL_TYPE_GTP;
@@ -333,10 +343,35 @@
hdr.outer_gtpu.teid = fabric_md.spgw.teid;
}
+ @hidden
+ action gtpu_encap_qfi() {
+ gtpu_encap();
+ hdr.gtpu_ipv4.total_len = hdr.ipv4.total_len
+ + IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE
+ + GTPU_OPTIONS_HDR_BYTES + GTPU_EXT_PSC_HDR_BYTES;
+ hdr.gtpu_udp.len = fabric_md.spgw.ipv4_len
+ + UDP_HDR_SIZE + GTP_HDR_SIZE
+ + GTPU_OPTIONS_HDR_BYTES + GTPU_EXT_PSC_HDR_BYTES;
+ hdr.outer_gtpu.msglen = fabric_md.spgw.ipv4_len
+ + GTPU_OPTIONS_HDR_BYTES + GTPU_EXT_PSC_HDR_BYTES;
+ hdr.outer_gtpu.ex_flag = 1;
+ hdr.outer_gtpu_options.setValid();
+ hdr.outer_gtpu_options.next_ext = GTPU_NEXT_EXT_PSC;
+ hdr.outer_gtpu_ext_psc.setValid();
+ hdr.outer_gtpu_ext_psc.type = GTPU_EXT_PSC_TYPE_DL;
+ hdr.outer_gtpu_ext_psc.len = GTPU_EXT_PSC_LEN;
+ hdr.outer_gtpu_ext_psc.qfi = fabric_md.spgw.qfi;
+ hdr.outer_gtpu_ext_psc.next_ext = GTPU_NEXT_EXT_NONE;
+ }
+
apply {
if (fabric_md.spgw.skip_spgw == _FALSE) {
if (fabric_md.spgw.needs_gtpu_encap == _TRUE) {
- gtpu_encap();
+ if (fabric_md.spgw.needs_qfi_push == _TRUE) {
+ gtpu_encap_qfi();
+ } else {
+ gtpu_encap();
+ }
}
if (fabric_md.spgw.skip_egress_pdr_ctr == _FALSE) {
pdr_counter.count(fabric_md.spgw.ctr_id);
diff --git a/pipelines/fabric/impl/src/main/resources/include/define.p4 b/pipelines/fabric/impl/src/main/resources/include/define.p4
index 36a5ec7..519d454 100644
--- a/pipelines/fabric/impl/src/main/resources/include/define.p4
+++ b/pipelines/fabric/impl/src/main/resources/include/define.p4
@@ -73,10 +73,20 @@
#define UDP_HDR_SIZE 8
#define GTP_HDR_SIZE 8
+#define GTPU_OPTIONS_HDR_BYTES 4
+#define GTPU_EXT_PSC_HDR_BYTES 4
+
#define UDP_PORT_GTPU 2152
#define GTP_GPDU 0xff
#define GTP_V1 0x01
#define GTP_PROTOCOL_TYPE_GTP 0x01
+#define GTPU_NEXT_EXT_NONE 0x0
+#define GTPU_NEXT_EXT_PSC 0x85
+// 1*4-octets
+#define GTPU_EXT_PSC_LEN 8w1
+
+const bit<4> GTPU_EXT_PSC_TYPE_DL = 4w0; // Downlink
+const bit<4> GTPU_EXT_PSC_TYPE_UL = 4w1; // Uplink
#define PKT_INSTANCE_TYPE_NORMAL 0
#define PKT_INSTANCE_TYPE_INGRESS_CLONE 1
@@ -95,6 +105,12 @@
typedef bit<12> vlan_id_t;
typedef bit<32> ipv4_addr_t;
typedef bit<16> l4_port_t;
+typedef bit<SLICE_ID_WIDTH> slice_id_t;
+typedef bit<TC_WIDTH> tc_t; // Traffic Class (for QoS) within a slice
+typedef bit<SLICE_TC_WIDTH> slice_tc_t; // Slice and TC identifier
+
+const slice_id_t DEFAULT_SLICE_ID = 0;
+const tc_t DEFAULT_TC = 0;
// SPGW types
typedef bit<2> direction_t;
@@ -105,6 +121,7 @@
typedef bit<32> far_id_t;
typedef bit<32> pdr_ctr_id_t;
typedef bit<32> teid_t;
+typedef bit<6> qfi_t;
typedef bit<5> qid_t;
const spgw_interface_t SPGW_IFACE_UNKNOWN = 8w0;
diff --git a/pipelines/fabric/impl/src/main/resources/include/header.p4 b/pipelines/fabric/impl/src/main/resources/include/header.p4
index b76ea01..8e3537e 100644
--- a/pipelines/fabric/impl/src/main/resources/include/header.p4
+++ b/pipelines/fabric/impl/src/main/resources/include/header.p4
@@ -139,6 +139,25 @@
teid_t teid; /* tunnel endpoint id */
}
+// Follows gtpu_t if any of ex_flag, seq_flag, or npdu_flag is 1.
+header gtpu_options_t {
+ bit<16> seq_num; /* Sequence number */
+ bit<8> n_pdu_num; /* N-PDU number */
+ bit<8> next_ext; /* Next extension header */
+}
+
+// GTPU extension: PDU Session Container (PSC) -- 3GPP TS 38.415 version 15.2.0
+// https://www.etsi.org/deliver/etsi_ts/138400_138499/138415/15.02.00_60/ts_138415v150200p.pdf
+header gtpu_ext_psc_t {
+ bit<8> len; /* Length in 4-octet units (common to all extensions) */
+ bit<4> type; /* Uplink or downlink */
+ bit<4> spare0; /* Reserved */
+ bit<1> ppp; /* Paging Policy Presence (UL only, not supported) */
+ bit<1> rqi; /* Reflective QoS Indicator (UL only) */
+ qfi_t qfi; /* QoS Flow Identifier */
+ bit<8> next_ext;
+}
+
#ifdef WITH_SPGW
struct spgw_meta_t {
bit<16> ipv4_len;
@@ -149,11 +168,13 @@
pdr_ctr_id_t ctr_id;
far_id_t far_id;
spgw_interface_t src_iface;
+ qfi_t qfi;
_BOOL skip_spgw;
_BOOL notify_spgwc;
_BOOL needs_gtpu_encap;
_BOOL needs_gtpu_decap;
_BOOL skip_egress_pdr_ctr;
+ _BOOL needs_qfi_push;
}
#endif // WITH_SPGW
@@ -174,8 +195,25 @@
}
#endif // WITH_BNG
+// Used for table lookup. Initialized with the parsed headers, or 0 if invalid.
+// Never updated by the pipe. When both outer and inner IPv4 headers are valid,
+// this should always carry the inner ones. The assumption is that we terminate
+// GTP tunnels in the fabric, so we are more interested in observing/blocking
+// the inner flows. We might revisit this decision in the future.
+struct lookup_metadata_t {
+ _BOOL is_ipv4;
+ bit<32> ipv4_src;
+ bit<32> ipv4_dst;
+ bit<8> ip_proto;
+ l4_port_t l4_sport;
+ l4_port_t l4_dport;
+ bit<8> icmp_type;
+ bit<8> icmp_code;
+}
+
//Custom metadata definition
struct fabric_metadata_t {
+ lookup_metadata_t lkp;
bit<16> ip_eth_type;
vlan_id_t vlan_id;
bit<3> vlan_pri;
@@ -199,6 +237,10 @@
bit<16> l4_dport;
bit<32> ipv4_src_addr;
bit<32> ipv4_dst_addr;
+ slice_id_t slice_id;
+ bit<2> packet_color;
+ tc_t tc;
+ bit<6> dscp;
#ifdef WITH_SPGW
bit<16> inner_l4_sport;
bit<16> inner_l4_dport;
@@ -228,8 +270,12 @@
ipv4_t gtpu_ipv4;
udp_t gtpu_udp;
gtpu_t outer_gtpu;
+ gtpu_options_t outer_gtpu_options;
+ gtpu_ext_psc_t outer_gtpu_ext_psc;
#endif // WITH_SPGW
gtpu_t gtpu;
+ gtpu_options_t gtpu_options;
+ gtpu_ext_psc_t gtpu_ext_psc;
ipv4_t inner_ipv4;
udp_t inner_udp;
tcp_t inner_tcp;
diff --git a/pipelines/fabric/impl/src/main/resources/include/parser.p4 b/pipelines/fabric/impl/src/main/resources/include/parser.p4
index fb9e764..0a77d4c 100644
--- a/pipelines/fabric/impl/src/main/resources/include/parser.p4
+++ b/pipelines/fabric/impl/src/main/resources/include/parser.p4
@@ -200,7 +200,30 @@
state parse_gtpu {
packet.extract(hdr.gtpu);
- transition parse_inner_ipv4;
+ transition select(hdr.gtpu.ex_flag, hdr.gtpu.seq_flag, hdr.gtpu.npdu_flag) {
+ (0, 0, 0): parse_inner_ipv4;
+ default: parse_gtpu_options;
+ }
+ }
+
+ state parse_gtpu_options {
+ packet.extract(hdr.gtpu_options);
+ bit<8> gtpu_ext_len = packet.lookahead<bit<8>>();
+ transition select(hdr.gtpu_options.next_ext, gtpu_ext_len) {
+ (GTPU_NEXT_EXT_PSC, GTPU_EXT_PSC_LEN): parse_gtpu_ext_psc;
+ default: accept;
+ }
+ }
+
+ state parse_gtpu_ext_psc {
+ packet.extract(hdr.gtpu_ext_psc);
+#ifdef WITH_SPGW
+ fabric_metadata.spgw.qfi = hdr.gtpu_ext_psc.qfi;
+#endif // WITH_SPGW
+ transition select(hdr.gtpu_ext_psc.next_ext) {
+ GTPU_NEXT_EXT_NONE: parse_inner_ipv4;
+ default: accept;
+ }
}
state parse_inner_ipv4 {
@@ -307,6 +330,8 @@
packet.emit(hdr.gtpu_ipv4);
packet.emit(hdr.gtpu_udp);
packet.emit(hdr.outer_gtpu);
+ packet.emit(hdr.outer_gtpu_options);
+ packet.emit(hdr.outer_gtpu_ext_psc);
#endif // WITH_SPGW
packet.emit(hdr.ipv4);
#ifdef WITH_IPV6
@@ -317,6 +342,8 @@
packet.emit(hdr.icmp);
// if we parsed a GTPU packet but did not decap it
packet.emit(hdr.gtpu);
+ packet.emit(hdr.gtpu_options);
+ packet.emit(hdr.gtpu_ext_psc);
packet.emit(hdr.inner_ipv4);
packet.emit(hdr.inner_tcp);
packet.emit(hdr.inner_udp);
diff --git a/pipelines/fabric/impl/src/main/resources/include/size.p4 b/pipelines/fabric/impl/src/main/resources/include/size.p4
index caa8c14..3a782f10 100644
--- a/pipelines/fabric/impl/src/main/resources/include/size.p4
+++ b/pipelines/fabric/impl/src/main/resources/include/size.p4
@@ -25,5 +25,11 @@
#define HASHED_ACT_PROFILE_SIZE 32w1024
#define MULTICAST_NEXT_TABLE_SIZE 1024
#define EGRESS_VLAN_TABLE_SIZE 1024
+#define QOS_CLASSIFIER_TABLE_SIZE 512
+#define DSCP_REWRITER_TABLE_SIZE 512
+
+#define SLICE_ID_WIDTH 4
+#define TC_WIDTH 2
+#define SLICE_TC_WIDTH (SLICE_ID_WIDTH + TC_WIDTH)
#endif