blob: 2ec4776d064f9f93eb472fec921964c8127bd965 [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 Cascone2102bfb2020-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();
48 }
Carmelo Cascone2102bfb2020-12-04 16:54:24 -080049 @hidden
Robert MacDavidde12b982020-07-15 18:38:59 -070050 action decap_inner_tcp() {
51 decap_inner_common();
52 hdr.udp.setInvalid();
53 hdr.tcp = hdr.inner_tcp;
54 hdr.inner_tcp.setInvalid();
55 }
Carmelo Cascone2102bfb2020-12-04 16:54:24 -080056 @hidden
Robert MacDavidde12b982020-07-15 18:38:59 -070057 action decap_inner_udp() {
58 decap_inner_common();
59 hdr.udp = hdr.inner_udp;
60 hdr.inner_udp.setInvalid();
61 }
Carmelo Cascone2102bfb2020-12-04 16:54:24 -080062 @hidden
Robert MacDavidde12b982020-07-15 18:38:59 -070063 action decap_inner_icmp() {
64 decap_inner_common();
65 hdr.udp.setInvalid();
66 hdr.icmp = hdr.inner_icmp;
67 hdr.inner_icmp.setInvalid();
68 }
Carmelo Cascone2102bfb2020-12-04 16:54:24 -080069 @hidden
Robert MacDavidde12b982020-07-15 18:38:59 -070070 action decap_inner_unknown() {
71 decap_inner_common();
72 hdr.udp.setInvalid();
73 }
74 @hidden
75 table decap_gtpu {
76 key = {
Carmelo Cascone2102bfb2020-12-04 16:54:24 -080077 hdr.inner_tcp.isValid() : exact;
78 hdr.inner_udp.isValid() : exact;
79 hdr.inner_icmp.isValid() : exact;
Robert MacDavidde12b982020-07-15 18:38:59 -070080 }
81 actions = {
82 decap_inner_tcp;
83 decap_inner_udp;
84 decap_inner_icmp;
85 decap_inner_unknown;
86 }
87 const default_action = decap_inner_unknown;
88 const entries = {
89 (true, false, false) : decap_inner_tcp();
90 (false, true, false) : decap_inner_udp();
91 (false, false, true) : decap_inner_icmp();
92 }
Carmelo Cascone2102bfb2020-12-04 16:54:24 -080093 }
94 apply {
95 decap_gtpu.apply();
96 }
97}
98
99
100control SpgwIngress(inout parsed_headers_t hdr,
101 inout fabric_metadata_t fabric_md,
102 inout standard_metadata_t standard_metadata) {
103
104 //=============================//
105 //===== Misc Things ======//
106 //=============================//
Carmelo Cascone2388cc12021-05-26 19:30:30 +0200107
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800108 counter(MAX_PDR_COUNTERS, CounterType.packets_and_bytes) pdr_counter;
109
110 DecapGtpu() decap_gtpu_from_dbuf;
111 DecapGtpu() decap_gtpu;
112
113
114 //=============================//
115 //===== Interface Tables ======//
116 //=============================//
117
118 action load_iface(spgw_interface_t src_iface) {
119 // Interface type can be access, core, from_dbuf (see InterfaceType enum)
120 fabric_md.spgw.src_iface = src_iface;
121 fabric_md.spgw.skip_spgw = _FALSE;
122 }
123 action iface_miss() {
124 fabric_md.spgw.src_iface = SPGW_IFACE_UNKNOWN;
125 fabric_md.spgw.skip_spgw = _TRUE;
126 }
127
128 // TODO: check also that gtpu.msgtype == GTP_GPDU... somewhere
129 table interfaces {
130 key = {
131 hdr.ipv4.dst_addr : lpm @name("ipv4_dst_addr"); // outermost header
132 hdr.gtpu.isValid() : exact @name("gtpu_is_valid");
133 }
134 actions = {
135 load_iface;
136 @defaultonly iface_miss;
137 }
138 const default_action = iface_miss();
139 size = MAX_INTERFACES;
140 }
141
142
143 //=============================//
144 //===== PDR Tables ======//
145 //=============================//
146
ersuneetsinghe326c722021-03-25 21:17:29 -0300147 action load_pdr(pdr_ctr_id_t ctr_id,
148 far_id_t far_id,
149 bit<1> needs_gtpu_decap) {
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800150 fabric_md.spgw.ctr_id = ctr_id;
151 fabric_md.spgw.far_id = far_id;
152 fabric_md.spgw.needs_gtpu_decap = (_BOOL)needs_gtpu_decap;
153 }
154
ersuneetsinghe326c722021-03-25 21:17:29 -0300155 action load_pdr_qos(pdr_ctr_id_t ctr_id,
156 far_id_t far_id,
157 bit<1> needs_gtpu_decap,
158 qid_t qid) {
159 load_pdr(ctr_id, far_id, needs_gtpu_decap);
Carmelo Cascone2388cc12021-05-26 19:30:30 +0200160 // we cannot set the qid, since bmv2 does not support it
ersuneetsinghe326c722021-03-25 21:17:29 -0300161 }
162
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800163 // These two tables scale well and cover the average case PDR
164 table downlink_pdrs {
165 key = {
166 // only available ipv4 header
167 hdr.ipv4.dst_addr : exact @name("ue_addr");
168 }
169 actions = {
170 load_pdr;
ersuneetsinghe326c722021-03-25 21:17:29 -0300171 load_pdr_qos;
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800172 }
173 size = MAX_DOWNLINK_PDRS;
174 }
175
176 table uplink_pdrs {
177 key = {
178 hdr.ipv4.dst_addr : exact @name("tunnel_ipv4_dst");
179 hdr.gtpu.teid : exact @name("teid");
180 }
181 actions = {
182 load_pdr;
ersuneetsinghe326c722021-03-25 21:17:29 -0300183 load_pdr_qos;
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800184 }
185 size = MAX_UPLINK_PDRS;
186 }
187
188 //=============================//
189 //===== FAR Tables ======//
190 //=============================//
191
192 action load_normal_far(bit<1> drop,
193 bit<1> notify_cp) {
194 // general far attributes
195 fabric_md.skip_forwarding = (_BOOL)drop;
196 fabric_md.skip_next = (_BOOL)drop;
197 fabric_md.spgw.notify_spgwc = (_BOOL)notify_cp;
198 }
199 action load_tunnel_far(bit<1> drop,
200 bit<1> notify_cp,
201 bit<16> tunnel_src_port,
202 bit<32> tunnel_src_addr,
203 bit<32> tunnel_dst_addr,
204 teid_t teid) {
205 // general far attributes
206 fabric_md.skip_forwarding = (_BOOL)drop;
207 fabric_md.skip_next = (_BOOL)drop;
208 fabric_md.spgw.notify_spgwc = (_BOOL)notify_cp;
209 // GTP tunnel attributes
210 fabric_md.spgw.needs_gtpu_encap = _TRUE;
211 fabric_md.spgw.teid = teid;
212 fabric_md.spgw.tunnel_src_port = tunnel_src_port;
213 fabric_md.spgw.tunnel_src_addr = tunnel_src_addr;
214 fabric_md.spgw.tunnel_dst_addr = tunnel_dst_addr;
215 // update metadata for correct routing/hashing
216 fabric_md.ipv4_src_addr = tunnel_src_addr;
217 fabric_md.ipv4_dst_addr = tunnel_dst_addr;
218 fabric_md.l4_sport = tunnel_src_port;
219 fabric_md.l4_dport = UDP_PORT_GTPU;
220 }
221
222 action load_dbuf_far(bit<1> drop,
223 bit<1> notify_cp,
224 bit<16> tunnel_src_port,
225 bit<32> tunnel_src_addr,
226 bit<32> tunnel_dst_addr,
227 teid_t teid) {
228 load_tunnel_far(drop, notify_cp, tunnel_src_port,
229 tunnel_src_addr, tunnel_dst_addr, teid);
230 fabric_md.spgw.skip_egress_pdr_ctr = _TRUE;
231 }
232
233 table fars {
234 key = {
235 fabric_md.spgw.far_id : exact @name("far_id");
236 }
237 actions = {
238 load_normal_far;
239 load_tunnel_far;
240 load_dbuf_far;
241 }
242 // default is drop and don't notify CP
243 const default_action = load_normal_far(1, 0);
244 size = MAX_FARS;
Robert MacDavidde12b982020-07-15 18:38:59 -0700245 }
246
247
248 //=============================//
249 //===== Apply Block ======//
250 //=============================//
251 apply {
252
253 // Interfaces
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800254 if (interfaces.apply().hit) {
255 if (fabric_md.spgw.src_iface == SPGW_IFACE_FROM_DBUF) {
256 decap_gtpu_from_dbuf.apply(hdr, fabric_md);
257 }
258 // PDRs
259 if (hdr.gtpu.isValid()) {
260 uplink_pdrs.apply();
261 } else {
262 downlink_pdrs.apply();
263 }
264 if (fabric_md.spgw.src_iface != SPGW_IFACE_FROM_DBUF) {
265 pdr_counter.count(fabric_md.spgw.ctr_id);
266 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700267
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800268 // GTPU Decapsulate
Carmelo Cascone2388cc12021-05-26 19:30:30 +0200269 if (fabric_md.spgw.needs_gtpu_decap == _TRUE) {
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800270 decap_gtpu.apply(hdr, fabric_md);
271 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700272
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800273 // FARs
274 // Load FAR info
275 fars.apply();
276
277 // Nothing to be done immediately for forwarding or encapsulation.
278 // Forwarding is done by other parts of fabric.p4, and
279 // encapsulation is done in the egress
280
281 // Needed for correct GTPU encapsulation in egress
282 fabric_md.spgw.ipv4_len = hdr.ipv4.total_len;
Robert MacDavidde12b982020-07-15 18:38:59 -0700283 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700284 }
285}
286
287
288//====================================//
289//============== Egress ==============//
290//====================================//
291control SpgwEgress(
292 inout parsed_headers_t hdr,
293 inout fabric_metadata_t fabric_md) {
294
295 counter(MAX_PDR_COUNTERS, CounterType.packets_and_bytes) pdr_counter;
296
297
298 @hidden
299 action gtpu_encap() {
300 hdr.gtpu_ipv4.setValid();
301 hdr.gtpu_ipv4.version = IP_VERSION_4;
302 hdr.gtpu_ipv4.ihl = IPV4_MIN_IHL;
303 hdr.gtpu_ipv4.dscp = 0;
304 hdr.gtpu_ipv4.ecn = 0;
305 hdr.gtpu_ipv4.total_len = hdr.ipv4.total_len
306 + (IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE);
307 hdr.gtpu_ipv4.identification = 0x1513; /* From NGIC. TODO: Needs to be dynamic */
308 hdr.gtpu_ipv4.flags = 0;
309 hdr.gtpu_ipv4.frag_offset = 0;
310 hdr.gtpu_ipv4.ttl = DEFAULT_IPV4_TTL;
311 hdr.gtpu_ipv4.protocol = PROTO_UDP;
312 hdr.gtpu_ipv4.src_addr = fabric_md.spgw.tunnel_src_addr;
313 hdr.gtpu_ipv4.dst_addr = fabric_md.spgw.tunnel_dst_addr;
314 hdr.gtpu_ipv4.hdr_checksum = 0; // Updated later
315
316 hdr.gtpu_udp.setValid();
Carmelo Cascone2388cc12021-05-26 19:30:30 +0200317 hdr.gtpu_udp.sport = fabric_md.spgw.tunnel_src_port;
Robert MacDavidde12b982020-07-15 18:38:59 -0700318 hdr.gtpu_udp.dport = UDP_PORT_GTPU;
319 hdr.gtpu_udp.len = fabric_md.spgw.ipv4_len
320 + (UDP_HDR_SIZE + GTP_HDR_SIZE);
321 hdr.gtpu_udp.checksum = 0; // Updated later, if WITH_SPGW_UDP_CSUM_UPDATE
322
323
324 hdr.outer_gtpu.setValid();
325 hdr.outer_gtpu.version = GTPU_VERSION;
326 hdr.outer_gtpu.pt = GTP_PROTOCOL_TYPE_GTP;
327 hdr.outer_gtpu.spare = 0;
328 hdr.outer_gtpu.ex_flag = 0;
329 hdr.outer_gtpu.seq_flag = 0;
330 hdr.outer_gtpu.npdu_flag = 0;
331 hdr.outer_gtpu.msgtype = GTP_GPDU;
332 hdr.outer_gtpu.msglen = fabric_md.spgw.ipv4_len;
333 hdr.outer_gtpu.teid = fabric_md.spgw.teid;
334 }
335
336 apply {
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800337 if (fabric_md.spgw.skip_spgw == _FALSE) {
338 if (fabric_md.spgw.needs_gtpu_encap == _TRUE) {
339 gtpu_encap();
340 }
341 if (fabric_md.spgw.skip_egress_pdr_ctr == _FALSE) {
342 pdr_counter.count(fabric_md.spgw.ctr_id);
343 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700344 }
345 }
346}
347
348
349control update_gtpu_checksum(
350 inout ipv4_t gtpu_ipv4,
351 inout udp_t gtpu_udp,
352 in gtpu_t gtpu,
353 in ipv4_t ipv4,
354 in udp_t udp
355 ) {
356 apply {
357 // Compute outer IPv4 checksum.
358 update_checksum(gtpu_ipv4.isValid(),
359 {
360 gtpu_ipv4.version,
361 gtpu_ipv4.ihl,
362 gtpu_ipv4.dscp,
363 gtpu_ipv4.ecn,
364 gtpu_ipv4.total_len,
365 gtpu_ipv4.identification,
366 gtpu_ipv4.flags,
367 gtpu_ipv4.frag_offset,
368 gtpu_ipv4.ttl,
369 gtpu_ipv4.protocol,
370 gtpu_ipv4.src_addr,
371 gtpu_ipv4.dst_addr
372 },
373 gtpu_ipv4.hdr_checksum,
374 HashAlgorithm.csum16
375 );
376
377#ifdef WITH_SPGW_UDP_CSUM_UPDATE
378 // Compute outer UDP checksum.
379 update_checksum_with_payload(gtpu_udp.isValid(),
380 {
381 gtpu_ipv4.src_addr,
382 gtpu_ipv4.dst_addr,
383 8w0,
384 gtpu_ipv4.protocol,
385 gtpu_udp.len,
386 gtpu_udp.sport,
387 gtpu_udp.dport,
388 gtpu_udp.len,
389 gtpu,
390 ipv4,
391 // FIXME: we are assuming only UDP for downlink packets
392 // How to conditionally switch between UDP/TCP/ICMP?
393 udp
394 },
395 gtpu_udp.checksum,
396 HashAlgorithm.csum16
397 );
398#endif // WITH_SPGW_UDP_CSUM_UPDATE
399 }
400}
401
402#endif