blob: 6750dbd81b7576ab95416cf64aee0c4a816ed01a [file] [log] [blame]
Robert MacDavidde12b982020-07-15 18:38:59 -07001/*
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
20#define DEFAULT_PDR_CTR_ID 0
21#define DEFAULT_FAR_ID 0
22
23#ifndef MAX_UES
24#define MAX_UES 1024
25#endif // MAX_UES
26#define MAX_INTERFACES 128
27
28#define MAX_UPLINK_PDRS MAX_UES
29#define MAX_DOWNLINK_PDRS MAX_UES
30#define MAX_PDR_COUNTERS 2 * MAX_UES
31#define MAX_FARS 2 * MAX_UES
32
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -080033control DecapGtpu(inout parsed_headers_t hdr,
34 inout fabric_metadata_t fabric_md) {
Robert MacDavidde12b982020-07-15 18:38:59 -070035 @hidden
36 action decap_inner_common() {
37 // Correct parser-set metadata to use the inner header values
38 fabric_md.ip_eth_type = ETHERTYPE_IPV4;
39 fabric_md.ip_proto = hdr.inner_ipv4.protocol;
40 fabric_md.ipv4_src_addr = hdr.inner_ipv4.src_addr;
41 fabric_md.ipv4_dst_addr = hdr.inner_ipv4.dst_addr;
42 fabric_md.l4_sport = fabric_md.inner_l4_sport;
43 fabric_md.l4_dport = fabric_md.inner_l4_dport;
44 // Move GTPU and inner L3 headers out
45 hdr.ipv4 = hdr.inner_ipv4;
46 hdr.inner_ipv4.setInvalid();
47 hdr.gtpu.setInvalid();
Daniele Moro411f6f72021-07-28 18:53:34 +020048 hdr.gtpu_options.setInvalid();
49 hdr.gtpu_ext_psc.setInvalid();
Robert MacDavidde12b982020-07-15 18:38:59 -070050 }
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -080051 @hidden
Robert MacDavidde12b982020-07-15 18:38:59 -070052 action decap_inner_tcp() {
53 decap_inner_common();
54 hdr.udp.setInvalid();
55 hdr.tcp = hdr.inner_tcp;
56 hdr.inner_tcp.setInvalid();
57 }
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -080058 @hidden
Robert MacDavidde12b982020-07-15 18:38:59 -070059 action decap_inner_udp() {
60 decap_inner_common();
61 hdr.udp = hdr.inner_udp;
62 hdr.inner_udp.setInvalid();
63 }
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -080064 @hidden
Robert MacDavidde12b982020-07-15 18:38:59 -070065 action decap_inner_icmp() {
66 decap_inner_common();
67 hdr.udp.setInvalid();
68 hdr.icmp = hdr.inner_icmp;
69 hdr.inner_icmp.setInvalid();
70 }
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -080071 @hidden
Robert MacDavidde12b982020-07-15 18:38:59 -070072 action decap_inner_unknown() {
73 decap_inner_common();
74 hdr.udp.setInvalid();
75 }
76 @hidden
77 table decap_gtpu {
78 key = {
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -080079 hdr.inner_tcp.isValid() : exact;
80 hdr.inner_udp.isValid() : exact;
81 hdr.inner_icmp.isValid() : exact;
Robert MacDavidde12b982020-07-15 18:38:59 -070082 }
83 actions = {
84 decap_inner_tcp;
85 decap_inner_udp;
86 decap_inner_icmp;
87 decap_inner_unknown;
88 }
89 const default_action = decap_inner_unknown;
90 const entries = {
91 (true, false, false) : decap_inner_tcp();
92 (false, true, false) : decap_inner_udp();
93 (false, false, true) : decap_inner_icmp();
94 }
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -080095 }
96 apply {
97 decap_gtpu.apply();
98 }
99}
100
101
102control SpgwIngress(inout parsed_headers_t hdr,
103 inout fabric_metadata_t fabric_md,
104 inout standard_metadata_t standard_metadata) {
105
106 //=============================//
107 //===== Misc Things ======//
108 //=============================//
Carmelo Casconedb347372021-05-26 19:30:30 +0200109
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800110 counter(MAX_PDR_COUNTERS, CounterType.packets_and_bytes) pdr_counter;
111
112 DecapGtpu() decap_gtpu_from_dbuf;
113 DecapGtpu() decap_gtpu;
114
115
116 //=============================//
117 //===== Interface Tables ======//
118 //=============================//
119
Daniele Moro411f6f72021-07-28 18:53:34 +0200120 action load_iface(spgw_interface_t src_iface, slice_id_t slice_id) {
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800121 // Interface type can be access, core, from_dbuf (see InterfaceType enum)
122 fabric_md.spgw.src_iface = src_iface;
123 fabric_md.spgw.skip_spgw = _FALSE;
Daniele Moro411f6f72021-07-28 18:53:34 +0200124 fabric_md.slice_id = slice_id;
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800125 }
126 action iface_miss() {
127 fabric_md.spgw.src_iface = SPGW_IFACE_UNKNOWN;
128 fabric_md.spgw.skip_spgw = _TRUE;
129 }
130
131 // TODO: check also that gtpu.msgtype == GTP_GPDU... somewhere
132 table interfaces {
133 key = {
134 hdr.ipv4.dst_addr : lpm @name("ipv4_dst_addr"); // outermost header
135 hdr.gtpu.isValid() : exact @name("gtpu_is_valid");
136 }
137 actions = {
138 load_iface;
139 @defaultonly iface_miss;
140 }
141 const default_action = iface_miss();
142 size = MAX_INTERFACES;
143 }
144
145
146 //=============================//
147 //===== PDR Tables ======//
148 //=============================//
ersuneetsinghc78a2512021-03-25 21:17:29 -0300149 action load_pdr(pdr_ctr_id_t ctr_id,
150 far_id_t far_id,
Daniele Moro411f6f72021-07-28 18:53:34 +0200151 bit<1> needs_gtpu_decap,
152 tc_t tc) {
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800153 fabric_md.spgw.ctr_id = ctr_id;
154 fabric_md.spgw.far_id = far_id;
155 fabric_md.spgw.needs_gtpu_decap = (_BOOL)needs_gtpu_decap;
Daniele Moro411f6f72021-07-28 18:53:34 +0200156 fabric_md.tc = tc;
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800157 }
158
Daniele Moro411f6f72021-07-28 18:53:34 +0200159 action load_pdr_qos(pdr_ctr_id_t ctr_id,
160 far_id_t far_id,
161 bit<1> needs_gtpu_decap,
162 // Used to push QFI, valid for 5G traffic only
163 bit<1> needs_qfi_push,
164 qfi_t qfi,
165 tc_t tc) {
166 load_pdr(ctr_id, far_id, needs_gtpu_decap, tc);
167 fabric_md.spgw.qfi = qfi;
168 fabric_md.spgw.needs_qfi_push = (_BOOL)needs_qfi_push;
ersuneetsinghc78a2512021-03-25 21:17:29 -0300169 }
170
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800171 // These two tables scale well and cover the average case PDR
172 table downlink_pdrs {
173 key = {
174 // only available ipv4 header
175 hdr.ipv4.dst_addr : exact @name("ue_addr");
176 }
177 actions = {
178 load_pdr;
ersuneetsinghc78a2512021-03-25 21:17:29 -0300179 load_pdr_qos;
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800180 }
181 size = MAX_DOWNLINK_PDRS;
182 }
183
184 table uplink_pdrs {
185 key = {
186 hdr.ipv4.dst_addr : exact @name("tunnel_ipv4_dst");
187 hdr.gtpu.teid : exact @name("teid");
Daniele Moro411f6f72021-07-28 18:53:34 +0200188 // Match valid only for 5G traffic
189 hdr.gtpu_ext_psc.isValid() : exact @name("has_qfi");
190 // QFI metadata is 0 when gptu_ext_psc is invalid.
191 fabric_md.spgw.qfi : exact @name("qfi");
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800192 }
193 actions = {
194 load_pdr;
ersuneetsinghc78a2512021-03-25 21:17:29 -0300195 load_pdr_qos;
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800196 }
197 size = MAX_UPLINK_PDRS;
198 }
199
200 //=============================//
201 //===== FAR Tables ======//
202 //=============================//
203
204 action load_normal_far(bit<1> drop,
205 bit<1> notify_cp) {
206 // general far attributes
207 fabric_md.skip_forwarding = (_BOOL)drop;
208 fabric_md.skip_next = (_BOOL)drop;
209 fabric_md.spgw.notify_spgwc = (_BOOL)notify_cp;
210 }
211 action load_tunnel_far(bit<1> drop,
212 bit<1> notify_cp,
213 bit<16> tunnel_src_port,
214 bit<32> tunnel_src_addr,
215 bit<32> tunnel_dst_addr,
216 teid_t teid) {
217 // general far attributes
218 fabric_md.skip_forwarding = (_BOOL)drop;
219 fabric_md.skip_next = (_BOOL)drop;
220 fabric_md.spgw.notify_spgwc = (_BOOL)notify_cp;
221 // GTP tunnel attributes
222 fabric_md.spgw.needs_gtpu_encap = _TRUE;
223 fabric_md.spgw.teid = teid;
224 fabric_md.spgw.tunnel_src_port = tunnel_src_port;
225 fabric_md.spgw.tunnel_src_addr = tunnel_src_addr;
226 fabric_md.spgw.tunnel_dst_addr = tunnel_dst_addr;
227 // update metadata for correct routing/hashing
228 fabric_md.ipv4_src_addr = tunnel_src_addr;
229 fabric_md.ipv4_dst_addr = tunnel_dst_addr;
230 fabric_md.l4_sport = tunnel_src_port;
231 fabric_md.l4_dport = UDP_PORT_GTPU;
232 }
233
234 action load_dbuf_far(bit<1> drop,
235 bit<1> notify_cp,
236 bit<16> tunnel_src_port,
237 bit<32> tunnel_src_addr,
238 bit<32> tunnel_dst_addr,
239 teid_t teid) {
240 load_tunnel_far(drop, notify_cp, tunnel_src_port,
241 tunnel_src_addr, tunnel_dst_addr, teid);
242 fabric_md.spgw.skip_egress_pdr_ctr = _TRUE;
243 }
244
245 table fars {
246 key = {
247 fabric_md.spgw.far_id : exact @name("far_id");
248 }
249 actions = {
250 load_normal_far;
251 load_tunnel_far;
252 load_dbuf_far;
253 }
254 // default is drop and don't notify CP
255 const default_action = load_normal_far(1, 0);
256 size = MAX_FARS;
Robert MacDavidde12b982020-07-15 18:38:59 -0700257 }
258
259
260 //=============================//
261 //===== Apply Block ======//
262 //=============================//
263 apply {
264
265 // Interfaces
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800266 if (interfaces.apply().hit) {
267 if (fabric_md.spgw.src_iface == SPGW_IFACE_FROM_DBUF) {
268 decap_gtpu_from_dbuf.apply(hdr, fabric_md);
269 }
270 // PDRs
271 if (hdr.gtpu.isValid()) {
272 uplink_pdrs.apply();
273 } else {
274 downlink_pdrs.apply();
275 }
276 if (fabric_md.spgw.src_iface != SPGW_IFACE_FROM_DBUF) {
277 pdr_counter.count(fabric_md.spgw.ctr_id);
278 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700279
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800280 // GTPU Decapsulate
Carmelo Casconedb347372021-05-26 19:30:30 +0200281 if (fabric_md.spgw.needs_gtpu_decap == _TRUE) {
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800282 decap_gtpu.apply(hdr, fabric_md);
283 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700284
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800285 // FARs
286 // Load FAR info
287 fars.apply();
288
289 // Nothing to be done immediately for forwarding or encapsulation.
290 // Forwarding is done by other parts of fabric.p4, and
291 // encapsulation is done in the egress
292
293 // Needed for correct GTPU encapsulation in egress
294 fabric_md.spgw.ipv4_len = hdr.ipv4.total_len;
Robert MacDavidde12b982020-07-15 18:38:59 -0700295 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700296 }
297}
298
299
300//====================================//
301//============== Egress ==============//
302//====================================//
303control SpgwEgress(
304 inout parsed_headers_t hdr,
305 inout fabric_metadata_t fabric_md) {
306
307 counter(MAX_PDR_COUNTERS, CounterType.packets_and_bytes) pdr_counter;
308
Robert MacDavidde12b982020-07-15 18:38:59 -0700309 @hidden
310 action gtpu_encap() {
311 hdr.gtpu_ipv4.setValid();
312 hdr.gtpu_ipv4.version = IP_VERSION_4;
313 hdr.gtpu_ipv4.ihl = IPV4_MIN_IHL;
314 hdr.gtpu_ipv4.dscp = 0;
315 hdr.gtpu_ipv4.ecn = 0;
316 hdr.gtpu_ipv4.total_len = hdr.ipv4.total_len
317 + (IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE);
318 hdr.gtpu_ipv4.identification = 0x1513; /* From NGIC. TODO: Needs to be dynamic */
319 hdr.gtpu_ipv4.flags = 0;
320 hdr.gtpu_ipv4.frag_offset = 0;
321 hdr.gtpu_ipv4.ttl = DEFAULT_IPV4_TTL;
322 hdr.gtpu_ipv4.protocol = PROTO_UDP;
323 hdr.gtpu_ipv4.src_addr = fabric_md.spgw.tunnel_src_addr;
324 hdr.gtpu_ipv4.dst_addr = fabric_md.spgw.tunnel_dst_addr;
325 hdr.gtpu_ipv4.hdr_checksum = 0; // Updated later
326
327 hdr.gtpu_udp.setValid();
Carmelo Casconedb347372021-05-26 19:30:30 +0200328 hdr.gtpu_udp.sport = fabric_md.spgw.tunnel_src_port;
Robert MacDavidde12b982020-07-15 18:38:59 -0700329 hdr.gtpu_udp.dport = UDP_PORT_GTPU;
330 hdr.gtpu_udp.len = fabric_md.spgw.ipv4_len
331 + (UDP_HDR_SIZE + GTP_HDR_SIZE);
332 hdr.gtpu_udp.checksum = 0; // Updated later, if WITH_SPGW_UDP_CSUM_UPDATE
333
Robert MacDavidde12b982020-07-15 18:38:59 -0700334 hdr.outer_gtpu.setValid();
Carmelo Casconeffa7fed2021-06-01 18:31:57 -0700335 hdr.outer_gtpu.version = GTP_V1;
Robert MacDavidde12b982020-07-15 18:38:59 -0700336 hdr.outer_gtpu.pt = GTP_PROTOCOL_TYPE_GTP;
337 hdr.outer_gtpu.spare = 0;
338 hdr.outer_gtpu.ex_flag = 0;
339 hdr.outer_gtpu.seq_flag = 0;
340 hdr.outer_gtpu.npdu_flag = 0;
341 hdr.outer_gtpu.msgtype = GTP_GPDU;
342 hdr.outer_gtpu.msglen = fabric_md.spgw.ipv4_len;
343 hdr.outer_gtpu.teid = fabric_md.spgw.teid;
344 }
345
Daniele Moro411f6f72021-07-28 18:53:34 +0200346 @hidden
347 action gtpu_encap_qfi() {
348 gtpu_encap();
349 hdr.gtpu_ipv4.total_len = hdr.ipv4.total_len
350 + IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE
351 + GTPU_OPTIONS_HDR_BYTES + GTPU_EXT_PSC_HDR_BYTES;
352 hdr.gtpu_udp.len = fabric_md.spgw.ipv4_len
353 + UDP_HDR_SIZE + GTP_HDR_SIZE
354 + GTPU_OPTIONS_HDR_BYTES + GTPU_EXT_PSC_HDR_BYTES;
355 hdr.outer_gtpu.msglen = fabric_md.spgw.ipv4_len
356 + GTPU_OPTIONS_HDR_BYTES + GTPU_EXT_PSC_HDR_BYTES;
357 hdr.outer_gtpu.ex_flag = 1;
358 hdr.outer_gtpu_options.setValid();
359 hdr.outer_gtpu_options.next_ext = GTPU_NEXT_EXT_PSC;
360 hdr.outer_gtpu_ext_psc.setValid();
361 hdr.outer_gtpu_ext_psc.type = GTPU_EXT_PSC_TYPE_DL;
362 hdr.outer_gtpu_ext_psc.len = GTPU_EXT_PSC_LEN;
363 hdr.outer_gtpu_ext_psc.qfi = fabric_md.spgw.qfi;
364 hdr.outer_gtpu_ext_psc.next_ext = GTPU_NEXT_EXT_NONE;
365 }
366
Robert MacDavidde12b982020-07-15 18:38:59 -0700367 apply {
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800368 if (fabric_md.spgw.skip_spgw == _FALSE) {
369 if (fabric_md.spgw.needs_gtpu_encap == _TRUE) {
Daniele Moro411f6f72021-07-28 18:53:34 +0200370 if (fabric_md.spgw.needs_qfi_push == _TRUE) {
371 gtpu_encap_qfi();
372 } else {
373 gtpu_encap();
374 }
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -0800375 }
376 if (fabric_md.spgw.skip_egress_pdr_ctr == _FALSE) {
377 pdr_counter.count(fabric_md.spgw.ctr_id);
378 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700379 }
380 }
381}
382
383
384control update_gtpu_checksum(
385 inout ipv4_t gtpu_ipv4,
386 inout udp_t gtpu_udp,
387 in gtpu_t gtpu,
388 in ipv4_t ipv4,
389 in udp_t udp
390 ) {
391 apply {
392 // Compute outer IPv4 checksum.
393 update_checksum(gtpu_ipv4.isValid(),
394 {
395 gtpu_ipv4.version,
396 gtpu_ipv4.ihl,
397 gtpu_ipv4.dscp,
398 gtpu_ipv4.ecn,
399 gtpu_ipv4.total_len,
400 gtpu_ipv4.identification,
401 gtpu_ipv4.flags,
402 gtpu_ipv4.frag_offset,
403 gtpu_ipv4.ttl,
404 gtpu_ipv4.protocol,
405 gtpu_ipv4.src_addr,
406 gtpu_ipv4.dst_addr
407 },
408 gtpu_ipv4.hdr_checksum,
409 HashAlgorithm.csum16
410 );
411
412#ifdef WITH_SPGW_UDP_CSUM_UPDATE
413 // Compute outer UDP checksum.
414 update_checksum_with_payload(gtpu_udp.isValid(),
415 {
416 gtpu_ipv4.src_addr,
417 gtpu_ipv4.dst_addr,
418 8w0,
419 gtpu_ipv4.protocol,
420 gtpu_udp.len,
421 gtpu_udp.sport,
422 gtpu_udp.dport,
423 gtpu_udp.len,
424 gtpu,
425 ipv4,
426 // FIXME: we are assuming only UDP for downlink packets
427 // How to conditionally switch between UDP/TCP/ICMP?
428 udp
429 },
430 gtpu_udp.checksum,
431 HashAlgorithm.csum16
432 );
433#endif // WITH_SPGW_UDP_CSUM_UPDATE
434 }
435}
436
437#endif