blob: 0aa78c057dbfcdc776f0dc75ebefddbbb6fb3c50 [file] [log] [blame]
Carmelo Casconeb81f4be2018-01-16 23:24:01 -08001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef __SPGW__
18#define __SPGW__
19
Robert MacDavid1d475692020-05-21 21:32:38 -040020#define MAX_PDR_COUNTERS 1024
21#define DEFAULT_PDR_CTR_ID 0
22#define DEFAULT_FAR_ID 0
23
Carmelo Cascone9b0171b2018-08-14 01:43:57 -070024control spgw_normalizer(
25 in bool is_gtpu_encapped,
26 out ipv4_t gtpu_ipv4,
27 out udp_t gtpu_udp,
28 inout ipv4_t ipv4,
29 inout udp_t udp,
30 in ipv4_t inner_ipv4,
31 in udp_t inner_udp
32 ) {
33 apply {
34 if (! is_gtpu_encapped) return;
35 gtpu_ipv4 = ipv4;
36 ipv4 = inner_ipv4;
37 gtpu_udp = udp;
38 if (inner_udp.isValid()) {
39 udp = inner_udp;
40 } else {
41 udp.setInvalid();
42 }
43 }
44}
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080045
46control spgw_ingress(
Carmelo Cascone9b607da2019-05-08 14:03:01 -070047 inout ipv4_t gtpu_ipv4,
48 inout udp_t gtpu_udp,
49 inout gtpu_t gtpu,
50 inout ipv4_t ipv4,
51 inout udp_t udp,
52 inout fabric_metadata_t fabric_meta,
53 inout standard_metadata_t standard_metadata
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080054 ) {
55
Robert MacDavid1d475692020-05-21 21:32:38 -040056 counter(MAX_PDR_COUNTERS, CounterType.packets_and_bytes) pdr_counter;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080057
Carmelo Casconeb5324e72018-11-25 02:26:32 -080058 @hidden
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080059 action gtpu_decap() {
Robert MacDavid1d475692020-05-21 21:32:38 -040060 // grab information from the tunnel that we'll need later
61 fabric_meta.spgw.teid = gtpu.teid;
62 fabric_meta.spgw.tunnel_dst_addr = gtpu_ipv4.dst_addr;
63 // update metadata src and dst addresses with the inner packet
64 fabric_meta.ipv4_src_addr = ipv4.src_addr;
65 fabric_meta.ipv4_dst_addr = ipv4.dst_addr;
66 // decap
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080067 gtpu_ipv4.setInvalid();
68 gtpu_udp.setInvalid();
69 gtpu.setInvalid();
Robert MacDavid1d475692020-05-21 21:32:38 -040070
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080071 }
72
Robert MacDavid1d475692020-05-21 21:32:38 -040073 table downlink_filter_table {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080074 key = {
Robert MacDavid1d475692020-05-21 21:32:38 -040075 // UE addr pool for downlink
76 ipv4.dst_addr : lpm @name("ipv4_prefix");
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080077 }
78 actions = {
Robert MacDavid1d475692020-05-21 21:32:38 -040079 nop();
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080080 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -080081 const default_action = nop();
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080082 }
83
Robert MacDavid1d475692020-05-21 21:32:38 -040084 table uplink_filter_table {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080085 key = {
Carmelo Cascone9b0171b2018-08-14 01:43:57 -070086 // IP addresses of the S1U interfaces of this SPGW-U instance (when uplink)
Carmelo Casconeb5324e72018-11-25 02:26:32 -080087 gtpu_ipv4.dst_addr : exact @name("gtp_ipv4_dst");
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080088 }
89 actions = {
Carmelo Casconeb5324e72018-11-25 02:26:32 -080090 nop();
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080091 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -080092 const default_action = nop();
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080093 }
94
Robert MacDavid1d475692020-05-21 21:32:38 -040095 action set_pdr_attributes(ctr_id_t ctr_id,
96 far_id_t far_id) {
97 fabric_meta.spgw.pdr_hit = _TRUE;
98 fabric_meta.spgw.ctr_id = ctr_id;
99 fabric_meta.spgw.far_id = far_id;
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800100 }
101
Robert MacDavid1d475692020-05-21 21:32:38 -0400102 // These two tables scale well and cover the average case PDR
103 table downlink_pdr_lookup {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800104 key = {
Robert MacDavid1d475692020-05-21 21:32:38 -0400105 ipv4.dst_addr : exact @name("ue_addr");
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800106 }
107 actions = {
Robert MacDavid1d475692020-05-21 21:32:38 -0400108 set_pdr_attributes;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800109 }
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800110 }
Robert MacDavid1d475692020-05-21 21:32:38 -0400111 table uplink_pdr_lookup {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800112 key = {
Robert MacDavid1d475692020-05-21 21:32:38 -0400113 // tunnel_dst_addr will be static for Q2 target. Can remove if need more scaling
114 fabric_meta.spgw.tunnel_dst_addr : exact @name("tunnel_ipv4_dst");
115 fabric_meta.spgw.teid : exact @name("teid");
116 ipv4.src_addr : exact @name("ue_addr");
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800117 }
118 actions = {
Robert MacDavid1d475692020-05-21 21:32:38 -0400119 set_pdr_attributes;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800120 }
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800121 }
Robert MacDavid1d475692020-05-21 21:32:38 -0400122 // This table scales poorly and covers uncommon PDRs
123 table flexible_pdr_lookup {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800124 key = {
Robert MacDavid1d475692020-05-21 21:32:38 -0400125 // Direction. Eventually change to interface
126 fabric_meta.spgw.direction : ternary @name("spgw_direction");
127 // F-TEID
128 fabric_meta.spgw.tunnel_dst_addr : ternary @name("tunnel_ipv4_dst");
129 fabric_meta.spgw.teid : ternary @name("teid");
130 // SDF (5-tuple)
131 ipv4.src_addr : ternary @name("ipv4_src");
132 ipv4.dst_addr : ternary @name("ipv4_dst");
133 ipv4.protocol : ternary @name("ip_proto");
134 fabric_meta.l4_sport : ternary @name("l4_sport");
135 fabric_meta.l4_dport : ternary @name("l4_dport");
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800136 }
137 actions = {
Robert MacDavid1d475692020-05-21 21:32:38 -0400138 set_pdr_attributes;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800139 }
Robert MacDavid1d475692020-05-21 21:32:38 -0400140 const default_action = set_pdr_attributes(DEFAULT_PDR_CTR_ID, DEFAULT_FAR_ID);
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800141 }
Robert MacDavid1d475692020-05-21 21:32:38 -0400142
143 action load_normal_far_attributes(bit<1> drop,
144 bit<1> notify_cp) {
145 // general far attributes
146 fabric_meta.spgw.far_dropped = (_BOOL)drop;
147 fabric_meta.spgw.notify_cp = (_BOOL)notify_cp;
148 }
149 action load_tunnel_far_attributes(bit<1> drop,
150 bit<1> notify_cp,
151 ipv4_addr_t tunnel_src_addr,
152 ipv4_addr_t tunnel_dst_addr,
153 teid_t teid) {
154 // general far attributes
155 fabric_meta.spgw.far_dropped = (_BOOL)drop;
156 fabric_meta.spgw.notify_cp = (_BOOL)notify_cp;
157 // GTP tunnel attributes
158 fabric_meta.spgw.outer_header_creation = _TRUE;
159 fabric_meta.spgw.teid = teid;
160 fabric_meta.spgw.tunnel_src_addr = tunnel_src_addr;
161 fabric_meta.spgw.tunnel_dst_addr = tunnel_dst_addr;
162 // update metadata IP addresses for correct routing/hashing
163 fabric_meta.ipv4_src_addr = tunnel_src_addr;
164 fabric_meta.ipv4_dst_addr = tunnel_dst_addr;
165 }
166
167
168 table far_lookup {
169 key = {
170 fabric_meta.spgw.far_id : exact @name("far_id");
171 }
172 actions = {
173 load_normal_far_attributes;
174 load_tunnel_far_attributes;
175 }
176 // default is drop and don't notify CP
177 const default_action = load_normal_far_attributes(1w1, 1w0);
178 }
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800179
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800180 apply {
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800181 if (gtpu.isValid()) {
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700182 // If here, pkt has outer IP dst on
183 // S1U_SGW_PREFIX/S1U_SGW_PREFIX_LEN subnet.
184 // TODO: check also that gtpu.msgtype == GTP_GPDU
Robert MacDavid1d475692020-05-21 21:32:38 -0400185 if (!uplink_filter_table.apply().hit) {
186 // Should this be changed to a forwarding/next skip instead of a drop?
Carmelo Cascone9b607da2019-05-08 14:03:01 -0700187 mark_to_drop(standard_metadata);
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800188 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800189 fabric_meta.spgw.direction = SPGW_DIR_UPLINK;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800190 gtpu_decap();
Robert MacDavid1d475692020-05-21 21:32:38 -0400191 } else if (downlink_filter_table.apply().hit) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800192 fabric_meta.spgw.direction = SPGW_DIR_DOWNLINK;
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700193 } else {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800194 fabric_meta.spgw.direction = SPGW_DIR_UNKNOWN;
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700195 // No SPGW processing needed.
196 return;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800197 }
198
Robert MacDavid1d475692020-05-21 21:32:38 -0400199 // Try the efficient PDR tables first (This PDR partitioning only works
200 // if the PDRs do not overlap. Will need fixing later.)
201 if (fabric_meta.spgw.direction == SPGW_DIR_UPLINK) {
202 uplink_pdr_lookup.apply();
203 } else if (fabric_meta.spgw.direction == SPGW_DIR_DOWNLINK) {
204 downlink_pdr_lookup.apply();
205 } else { // SPGW_DIR_UNKNOWN
206 return;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800207 }
Robert MacDavid1d475692020-05-21 21:32:38 -0400208 // If those fail to find a match, use the wildcard tables
209 if (fabric_meta.spgw.pdr_hit == _FALSE) {
210 flexible_pdr_lookup.apply();
211 }
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800212
Robert MacDavid1d475692020-05-21 21:32:38 -0400213 pdr_counter.count(fabric_meta.spgw.ctr_id);
214 // Load FAR info
215 far_lookup.apply();
216
217 if (fabric_meta.spgw.notify_cp == _TRUE) {
218 // TODO: cpu clone session here
219 }
220 if (fabric_meta.spgw.far_dropped == _TRUE) {
221 // Do dropping in the same way as fabric's filtering.p4, so we can traverse
222 // the ACL table, which is good for cases like DHCP.
223 fabric_meta.skip_forwarding = _TRUE;
224 fabric_meta.skip_next = _TRUE;
225 }
226
227 // Nothing to be done immediately for forwarding or encapsulation.
228 // Forwarding is done by other parts of fabric.p4, and
229 // encapsulation is done in the egress
230
231 // Needed for correct GTPU encapsulation in egress
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800232 fabric_meta.spgw.ipv4_len = ipv4.total_len;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800233 }
234}
235
236
237control spgw_egress(
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700238 in ipv4_t ipv4,
239 inout ipv4_t gtpu_ipv4,
240 inout udp_t gtpu_udp,
241 inout gtpu_t gtpu,
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800242 in fabric_metadata_t fabric_meta,
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700243 in standard_metadata_t std_meta
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800244 ) {
245
Robert MacDavid1d475692020-05-21 21:32:38 -0400246 counter(MAX_PDR_COUNTERS, CounterType.packets_and_bytes) pdr_counter;
247
248
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800249 @hidden
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800250 action gtpu_encap() {
Carmelo Cascone14cde402018-01-25 01:57:18 -0800251 gtpu_ipv4.setValid();
252 gtpu_ipv4.version = IP_VERSION_4;
253 gtpu_ipv4.ihl = IPV4_MIN_IHL;
Jonghwan Hyuned478dc2018-08-06 15:35:18 +0900254 gtpu_ipv4.dscp = 0;
255 gtpu_ipv4.ecn = 0;
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700256 gtpu_ipv4.total_len = ipv4.total_len
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800257 + (IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE);
Robert MacDavid1d475692020-05-21 21:32:38 -0400258 gtpu_ipv4.identification = 0x1513; /* From NGIC. TODO: Needs to be dynamic */
Carmelo Cascone14cde402018-01-25 01:57:18 -0800259 gtpu_ipv4.flags = 0;
260 gtpu_ipv4.frag_offset = 0;
261 gtpu_ipv4.ttl = DEFAULT_IPV4_TTL;
262 gtpu_ipv4.protocol = PROTO_UDP;
Robert MacDavid1d475692020-05-21 21:32:38 -0400263 gtpu_ipv4.src_addr = fabric_meta.spgw.tunnel_src_addr;
264 gtpu_ipv4.dst_addr = fabric_meta.spgw.tunnel_dst_addr;
Carmelo Cascone14cde402018-01-25 01:57:18 -0800265 gtpu_ipv4.hdr_checksum = 0; // Updated later
266
267 gtpu_udp.setValid();
Robert MacDavid1d475692020-05-21 21:32:38 -0400268 gtpu_udp.sport = UDP_PORT_GTPU; // TODO: make this dynamic per 3GPP specs
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800269 gtpu_udp.dport = UDP_PORT_GTPU;
270 gtpu_udp.len = fabric_meta.spgw.ipv4_len
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800271 + (UDP_HDR_SIZE + GTP_HDR_SIZE);
Robert MacDavid1d475692020-05-21 21:32:38 -0400272 gtpu_udp.checksum = 0; // Updated later, if WITH_SPGW_UDP_CSUM_UPDATE
273
Carmelo Cascone14cde402018-01-25 01:57:18 -0800274
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800275 gtpu.setValid();
276 gtpu.version = GTPU_VERSION;
277 gtpu.pt = GTP_PROTOCOL_TYPE_GTP;
278 gtpu.spare = 0;
279 gtpu.ex_flag = 0;
280 gtpu.seq_flag = 0;
281 gtpu.npdu_flag = 0;
282 gtpu.msgtype = GTP_GPDU;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800283 gtpu.msglen = fabric_meta.spgw.ipv4_len;
284 gtpu.teid = fabric_meta.spgw.teid;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800285 }
286
287 apply {
Robert MacDavid1d475692020-05-21 21:32:38 -0400288 pdr_counter.count(fabric_meta.spgw.ctr_id);
289
290 if (fabric_meta.spgw.outer_header_creation == _TRUE) {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800291 gtpu_encap();
292 }
293 }
294}
295
296
Carmelo Cascone14cde402018-01-25 01:57:18 -0800297control update_gtpu_checksum(
298 inout ipv4_t gtpu_ipv4,
299 inout udp_t gtpu_udp,
300 in gtpu_t gtpu,
301 in ipv4_t ipv4,
302 in udp_t udp
303 ) {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800304 apply {
305 // Compute outer IPv4 checksum.
306 update_checksum(gtpu_ipv4.isValid(),
307 {
308 gtpu_ipv4.version,
309 gtpu_ipv4.ihl,
Jonghwan Hyuned478dc2018-08-06 15:35:18 +0900310 gtpu_ipv4.dscp,
311 gtpu_ipv4.ecn,
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800312 gtpu_ipv4.total_len,
313 gtpu_ipv4.identification,
314 gtpu_ipv4.flags,
315 gtpu_ipv4.frag_offset,
316 gtpu_ipv4.ttl,
317 gtpu_ipv4.protocol,
318 gtpu_ipv4.src_addr,
319 gtpu_ipv4.dst_addr
320 },
321 gtpu_ipv4.hdr_checksum,
322 HashAlgorithm.csum16
323 );
Carmelo Cascone14cde402018-01-25 01:57:18 -0800324
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800325#ifdef WITH_SPGW_UDP_CSUM_UPDATE
Carmelo Cascone14cde402018-01-25 01:57:18 -0800326 // Compute outer UDP checksum.
327 update_checksum_with_payload(gtpu_udp.isValid(),
328 {
329 gtpu_ipv4.src_addr,
330 gtpu_ipv4.dst_addr,
331 8w0,
332 gtpu_ipv4.protocol,
333 gtpu_udp.len,
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800334 gtpu_udp.sport,
335 gtpu_udp.dport,
Carmelo Cascone14cde402018-01-25 01:57:18 -0800336 gtpu_udp.len,
337 gtpu,
338 ipv4,
339 // FIXME: we are assuming only UDP for downlink packets
340 // How to conditionally switch between UDP/TCP/ICMP?
341 udp
342 },
343 gtpu_udp.checksum,
344 HashAlgorithm.csum16
345 );
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800346#endif // WITH_SPGW_UDP_CSUM_UPDATE
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800347 }
348}
349
350#endif