Fixed spgw.p4 decapping GTP packets not meant to be decapped
Also reduces the number of tables used for downlink processing.
Change-Id: I09a67cfac335b805d80e90cf5bb69fbab931e80b
diff --git a/pipelines/fabric/src/main/resources/include/checksum.p4 b/pipelines/fabric/src/main/resources/include/checksum.p4
index 4d1b803..a10a393 100644
--- a/pipelines/fabric/src/main/resources/include/checksum.p4
+++ b/pipelines/fabric/src/main/resources/include/checksum.p4
@@ -72,9 +72,6 @@
hdr.ipv4.hdr_checksum,
HashAlgorithm.csum16
);
-#ifdef WITH_SPGW
- verify_gtpu_checksum.apply(hdr.gtpu_ipv4);
-#endif // WITH_SPGW
}
}
diff --git a/pipelines/fabric/src/main/resources/include/define.p4 b/pipelines/fabric/src/main/resources/include/define.p4
index 74c964e..d717853 100644
--- a/pipelines/fabric/src/main/resources/include/define.p4
+++ b/pipelines/fabric/src/main/resources/include/define.p4
@@ -68,6 +68,21 @@
typedef bit<48> mac_addr_t;
typedef bit<16> group_id_t;
typedef bit<12> vlan_id_t;
+typedef bit<48> timestamp_t;
+typedef bit<32> switch_id_t;
+typedef bit<32> ipv4_addr_t;
+typedef bit<16> l4_port_t;
+
+// SPGW types
+typedef bit<2> direction_t;
+typedef bit pcc_gate_status_t;
+typedef bit<32> sdf_rule_id_t;
+typedef bit<32> pcc_rule_id_t;
+
+// spgw.p4 expects uplink packets with IP dst on this subnet
+// 140.0.0.0/8
+const ipv4_addr_t S1U_SGW_PREFIX = 2348810240;
+#define S1U_SGW_PREFIX_LEN 8
const bit<16> ETHERTYPE_QINQ = 0x88A8;
const bit<16> ETHERTYPE_QINQ_NON_STD = 0x9100;
@@ -95,28 +110,17 @@
const bit<8> DEFAULT_MPLS_TTL = 64;
const bit<8> DEFAULT_IPV4_TTL = 64;
-typedef bit direction_t;
-typedef bit pcc_gate_status_t;
-typedef bit<32> sdf_rule_id_t;
-typedef bit<32> pcc_rule_id_t;
-
const sdf_rule_id_t DEFAULT_SDF_RULE_ID = 0;
const pcc_rule_id_t DEFAULT_PCC_RULE_ID = 0;
-
-const direction_t DIR_UPLINK = 1w0;
-const direction_t DIR_DOWNLINK = 1w1;
-
+const direction_t SPGW_DIR_UNKNOWN = 2w0;
+const direction_t SPGW_DIR_UPLINK = 2w1;
+const direction_t SPGW_DIR_DOWNLINK = 2w2;
const pcc_gate_status_t PCC_GATE_OPEN = 1w0;
const pcc_gate_status_t PCC_GATE_CLOSED = 1w1;
/* indicate INT at LSB of DSCP */
const bit<6> INT_DSCP = 0x1;
-typedef bit<48> timestamp_t;
-typedef bit<32> switch_id_t;
-typedef bit<32> ip_address_t;
-typedef bit<16> l4_port_t;
-
const bit<8> INT_HEADER_LEN_WORD = 4;
const bit<8> CPU_MIRROR_SESSION_ID = 250;
diff --git a/pipelines/fabric/src/main/resources/include/header.p4 b/pipelines/fabric/src/main/resources/include/header.p4
index c1df60e..25ac400 100644
--- a/pipelines/fabric/src/main/resources/include/header.p4
+++ b/pipelines/fabric/src/main/resources/include/header.p4
@@ -132,7 +132,6 @@
}
struct spgw_meta_t {
- _BOOL do_spgw;
direction_t direction;
bit<16> ipv4_len;
bit<32> teid;
@@ -291,6 +290,8 @@
ipv4_t gtpu_ipv4;
udp_t gtpu_udp;
gtpu_t gtpu;
+ ipv4_t inner_ipv4;
+ udp_t inner_udp;
#endif // WITH_SPGW
ipv4_t ipv4;
#ifdef WITH_IPV6
diff --git a/pipelines/fabric/src/main/resources/include/int_report.p4 b/pipelines/fabric/src/main/resources/include/int_report.p4
index da158e2..6d7c29d 100644
--- a/pipelines/fabric/src/main/resources/include/int_report.p4
+++ b/pipelines/fabric/src/main/resources/include/int_report.p4
@@ -44,8 +44,8 @@
(bit<32>) standard_metadata.enq_timestamp;
}
- action do_report_encapsulation(mac_addr_t src_mac, mac_addr_t mon_mac, ip_address_t src_ip,
- ip_address_t mon_ip, l4_port_t mon_port) {
+ action do_report_encapsulation(mac_addr_t src_mac, mac_addr_t mon_mac, ipv4_addr_t src_ip,
+ ipv4_addr_t mon_ip, l4_port_t mon_port) {
//Report Ethernet Header
hdr.report_ethernet.setValid();
hdr.report_ethernet.dst_addr = mon_mac;
diff --git a/pipelines/fabric/src/main/resources/include/parser.p4 b/pipelines/fabric/src/main/resources/include/parser.p4
index b94ca50..20c310c 100644
--- a/pipelines/fabric/src/main/resources/include/parser.p4
+++ b/pipelines/fabric/src/main/resources/include/parser.p4
@@ -179,24 +179,35 @@
#ifdef WITH_SPGW
state parse_gtpu {
- packet.extract(hdr.gtpu);
- transition parse_ipv4_inner;
+ transition select(hdr.ipv4.dst_addr[31:32-S1U_SGW_PREFIX_LEN]) {
+ // Avoid parsing GTP and inner headers if we know this GTP packet
+ // is not to be processed by this switch.
+ // FIXME: use parser value sets when support is ready in ONOS.
+ // To set the S1U_SGW_PREFIX value at runtime.
+ S1U_SGW_PREFIX[31:32-S1U_SGW_PREFIX_LEN]: do_parse_gtpu;
+ default: accept;
+ }
}
- state parse_ipv4_inner {
- packet.extract(hdr.gtpu_ipv4);
- transition select(hdr.gtpu_ipv4.protocol) {
+ state do_parse_gtpu {
+ packet.extract(hdr.gtpu);
+ transition parse_inner_ipv4;
+ }
+
+ state parse_inner_ipv4 {
+ packet.extract(hdr.inner_ipv4);
+ transition select(hdr.inner_ipv4.protocol) {
PROTO_TCP: parse_tcp;
- PROTO_UDP: parse_udp_inner;
+ PROTO_UDP: parse_inner_udp;
PROTO_ICMP: parse_icmp;
default: accept;
}
}
- state parse_udp_inner {
- packet.extract(hdr.gtpu_udp);
- fabric_metadata.l4_src_port = hdr.gtpu_udp.src_port;
- fabric_metadata.l4_dst_port = hdr.gtpu_udp.dst_port;
+ state parse_inner_udp {
+ packet.extract(hdr.inner_udp);
+ fabric_metadata.l4_src_port = hdr.inner_udp.src_port;
+ fabric_metadata.l4_dst_port = hdr.inner_udp.dst_port;
#ifdef WITH_INT
transition select(hdr.ipv4.isValid() && (hdr.ipv4.dscp & INT_DSCP) == INT_DSCP) {
true: parse_intl4_shim;
diff --git a/pipelines/fabric/src/main/resources/include/spgw.p4 b/pipelines/fabric/src/main/resources/include/spgw.p4
index b3ac361..5b2cd29 100644
--- a/pipelines/fabric/src/main/resources/include/spgw.p4
+++ b/pipelines/fabric/src/main/resources/include/spgw.p4
@@ -17,6 +17,27 @@
#ifndef __SPGW__
#define __SPGW__
+control spgw_normalizer(
+ in bool is_gtpu_encapped,
+ out ipv4_t gtpu_ipv4,
+ out udp_t gtpu_udp,
+ inout ipv4_t ipv4,
+ inout udp_t udp,
+ in ipv4_t inner_ipv4,
+ in udp_t inner_udp
+ ) {
+ apply {
+ if (! is_gtpu_encapped) return;
+ gtpu_ipv4 = ipv4;
+ ipv4 = inner_ipv4;
+ gtpu_udp = udp;
+ if (inner_udp.isValid()) {
+ udp = inner_udp;
+ } else {
+ udp.setInvalid();
+ }
+ }
+}
control spgw_ingress(
inout ipv4_t gtpu_ipv4,
@@ -41,26 +62,24 @@
spgw_meta.teid = teid;
spgw_meta.s1u_enb_addr = s1u_enb_addr;
spgw_meta.s1u_sgw_addr = s1u_sgw_addr;
- }
-
- action update_ue_cdr() {
ue_counter.count();
}
- table ue_filter_table {
+ table dl_sess_lookup {
key = {
- // IP prefixes of the UEs managed by this switch (when downlink)
- ipv4.dst_addr : lpm;
+ // UE addr for downlink
+ ipv4.dst_addr : exact;
}
actions = {
- NoAction();
+ set_dl_sess_info();
}
+ counters = ue_counter;
}
table s1u_filter_table {
key = {
- // IP addresses of the S1U interfaces embodied by this switch.
- spgw_meta.s1u_sgw_addr : exact;
+ // IP addresses of the S1U interfaces of this SPGW-U instance (when uplink)
+ gtpu_ipv4.dst_addr : exact;
}
actions = {
NoAction();
@@ -116,56 +135,22 @@
}
#endif // WITH_SPGW_PCC_GATING
- table dl_sess_lookup {
- key = {
- // UE addr for downlink
- ipv4.dst_addr : exact;
- }
- actions = {
- set_dl_sess_info();
- }
- }
-
- table ue_cdr_table {
- key = {
- // UE addr for downlink
- ipv4.dst_addr : exact;
- }
- actions = {
- update_ue_cdr();
- }
- counters = ue_counter;
- }
-
apply {
- spgw_meta.do_spgw = _FALSE;
if (gtpu.isValid()) {
- // If here, the parsed ipv4 header is the outer GTP one, but
- // fabric needs to forward on the inner one, i.e. this.
- // We store the outer values we need in the metadata, then replace
- // the ipv4 header extracted before with this one.
- spgw_meta.s1u_enb_addr = ipv4.src_addr;
- spgw_meta.s1u_sgw_addr = ipv4.dst_addr;
- ipv4 = gtpu_ipv4;
- udp = gtpu_udp;
-
- if (s1u_filter_table.apply().hit) {
- // TODO: check also that gtpu.msgtype == GTP_GPDU
- spgw_meta.do_spgw = _TRUE;
- spgw_meta.direction = DIR_UPLINK;
+ // If here, pkt has outer IP dst on
+ // S1U_SGW_PREFIX/S1U_SGW_PREFIX_LEN subnet.
+ // TODO: check also that gtpu.msgtype == GTP_GPDU
+ if (!s1u_filter_table.apply().hit) {
+ drop_now();
}
- } else if (ue_filter_table.apply().hit) {
- spgw_meta.do_spgw = _TRUE;
- spgw_meta.direction = DIR_DOWNLINK;
- }
-
- if (spgw_meta.do_spgw == _FALSE) {
- // Exit this control block.
- return;
- }
-
- if (spgw_meta.direction == DIR_UPLINK) {
+ spgw_meta.direction = SPGW_DIR_UPLINK;
gtpu_decap();
+ } else if (dl_sess_lookup.apply().hit) {
+ spgw_meta.direction = SPGW_DIR_DOWNLINK;
+ } else {
+ spgw_meta.direction = SPGW_DIR_UNKNOWN;
+ // No SPGW processing needed.
+ return;
}
#ifdef WITH_SPGW_PCC_GATING
@@ -181,15 +166,6 @@
}
#endif // WITH_SPGW_PCC_GATING
- if (spgw_meta.direction == DIR_DOWNLINK) {
- if (!dl_sess_lookup.apply().hit) {
- // We have no other choice than drop, as we miss the session
- // info necessary to properly GTPU encap the packet.
- drop_now();
- }
- ue_cdr_table.apply();
- }
-
// Don't ask why... we'll need this later.
spgw_meta.ipv4_len = ipv4.total_len;
}
@@ -197,12 +173,12 @@
control spgw_egress(
- in ipv4_t ipv4,
- out ipv4_t gtpu_ipv4,
- out udp_t gtpu_udp,
- out gtpu_t gtpu,
- in spgw_meta_t spgw_meta,
- in standard_metadata_t std_meta
+ in ipv4_t ipv4,
+ inout ipv4_t gtpu_ipv4,
+ inout udp_t gtpu_udp,
+ inout gtpu_t gtpu,
+ in spgw_meta_t spgw_meta,
+ in standard_metadata_t std_meta
) {
action gtpu_encap() {
@@ -211,7 +187,7 @@
gtpu_ipv4.ihl = IPV4_MIN_IHL;
gtpu_ipv4.dscp = 0;
gtpu_ipv4.ecn = 0;
- gtpu_ipv4.total_len = spgw_meta.ipv4_len
+ gtpu_ipv4.total_len = ipv4.total_len
+ (IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE);
gtpu_ipv4.identification = 0x1513; /* From NGIC */
gtpu_ipv4.flags = 0;
@@ -242,44 +218,13 @@
}
apply {
- if (spgw_meta.do_spgw == _TRUE && spgw_meta.direction == DIR_DOWNLINK) {
+ if (spgw_meta.direction == SPGW_DIR_DOWNLINK) {
gtpu_encap();
}
}
}
-control verify_gtpu_checksum(
- inout ipv4_t gtpu_ipv4
- ) {
- apply {
- // TODO: re-enable gtpu_ipv4 verification
- // with the current parser logic, gtpu_ip4 contains values of
- // the inner header, which is already verified by include/checksum.p4.
- // We need to modify the parser to copy the outer header somewhere
- // else, and verify that here.
-
- // verify_checksum(gtpu_ipv4.isValid(),
- // {
- // gtpu_ipv4.version,
- // gtpu_ipv4.ihl,
- // gtpu_ipv4.diffserv,
- // gtpu_ipv4.total_len,
- // gtpu_ipv4.identification,
- // gtpu_ipv4.flags,
- // gtpu_ipv4.frag_offset,
- // gtpu_ipv4.ttl,
- // gtpu_ipv4.protocol,
- // gtpu_ipv4.src_addr,
- // gtpu_ipv4.dst_addr
- // },
- // gtpu_ipv4.hdr_checksum,
- // HashAlgorithm.csum16
- // );
- }
-}
-
-
control update_gtpu_checksum(
inout ipv4_t gtpu_ipv4,
inout udp_t gtpu_udp,