blob: a27f9a010a6c9cd37080e32b4ea7bafff125d464 [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 size = 4;
94 }
95 apply {
96 decap_gtpu.apply();
97 }
98}
99
100
101control SpgwIngress(inout parsed_headers_t hdr,
102 inout fabric_metadata_t fabric_md,
103 inout standard_metadata_t standard_metadata) {
104
105 //=============================//
106 //===== Misc Things ======//
107 //=============================//
108
109 counter(MAX_PDR_COUNTERS, CounterType.packets_and_bytes) pdr_counter;
110
111 DecapGtpu() decap_gtpu_from_dbuf;
112 DecapGtpu() decap_gtpu;
113
114
115 //=============================//
116 //===== Interface Tables ======//
117 //=============================//
118
119 action load_iface(spgw_interface_t src_iface) {
120 // Interface type can be access, core, from_dbuf (see InterfaceType enum)
121 fabric_md.spgw.src_iface = src_iface;
122 fabric_md.spgw.skip_spgw = _FALSE;
123 }
124 action iface_miss() {
125 fabric_md.spgw.src_iface = SPGW_IFACE_UNKNOWN;
126 fabric_md.spgw.skip_spgw = _TRUE;
127 }
128
129 // TODO: check also that gtpu.msgtype == GTP_GPDU... somewhere
130 table interfaces {
131 key = {
132 hdr.ipv4.dst_addr : lpm @name("ipv4_dst_addr"); // outermost header
133 hdr.gtpu.isValid() : exact @name("gtpu_is_valid");
134 }
135 actions = {
136 load_iface;
137 @defaultonly iface_miss;
138 }
139 const default_action = iface_miss();
140 size = MAX_INTERFACES;
141 }
142
143
144 //=============================//
145 //===== PDR Tables ======//
146 //=============================//
147
ersuneetsinghe326c722021-03-25 21:17:29 -0300148 action load_pdr(pdr_ctr_id_t ctr_id,
149 far_id_t far_id,
150 bit<1> needs_gtpu_decap) {
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800151 fabric_md.spgw.ctr_id = ctr_id;
152 fabric_md.spgw.far_id = far_id;
153 fabric_md.spgw.needs_gtpu_decap = (_BOOL)needs_gtpu_decap;
154 }
155
ersuneetsinghe326c722021-03-25 21:17:29 -0300156 action load_pdr_qos(pdr_ctr_id_t ctr_id,
157 far_id_t far_id,
158 bit<1> needs_gtpu_decap,
159 qid_t qid) {
160 load_pdr(ctr_id, far_id, needs_gtpu_decap);
161 // we cannot set the qid, since bmv2 does not support it
162 }
163
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800164 // These two tables scale well and cover the average case PDR
165 table downlink_pdrs {
166 key = {
167 // only available ipv4 header
168 hdr.ipv4.dst_addr : exact @name("ue_addr");
169 }
170 actions = {
171 load_pdr;
ersuneetsinghe326c722021-03-25 21:17:29 -0300172 load_pdr_qos;
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800173 }
174 size = MAX_DOWNLINK_PDRS;
175 }
176
177 table uplink_pdrs {
178 key = {
179 hdr.ipv4.dst_addr : exact @name("tunnel_ipv4_dst");
180 hdr.gtpu.teid : exact @name("teid");
181 }
182 actions = {
183 load_pdr;
ersuneetsinghe326c722021-03-25 21:17:29 -0300184 load_pdr_qos;
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800185 }
186 size = MAX_UPLINK_PDRS;
187 }
188
189 //=============================//
190 //===== FAR Tables ======//
191 //=============================//
192
193 action load_normal_far(bit<1> drop,
194 bit<1> notify_cp) {
195 // general far attributes
196 fabric_md.skip_forwarding = (_BOOL)drop;
197 fabric_md.skip_next = (_BOOL)drop;
198 fabric_md.spgw.notify_spgwc = (_BOOL)notify_cp;
199 }
200 action load_tunnel_far(bit<1> drop,
201 bit<1> notify_cp,
202 bit<16> tunnel_src_port,
203 bit<32> tunnel_src_addr,
204 bit<32> tunnel_dst_addr,
205 teid_t teid) {
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 // GTP tunnel attributes
211 fabric_md.spgw.needs_gtpu_encap = _TRUE;
212 fabric_md.spgw.teid = teid;
213 fabric_md.spgw.tunnel_src_port = tunnel_src_port;
214 fabric_md.spgw.tunnel_src_addr = tunnel_src_addr;
215 fabric_md.spgw.tunnel_dst_addr = tunnel_dst_addr;
216 // update metadata for correct routing/hashing
217 fabric_md.ipv4_src_addr = tunnel_src_addr;
218 fabric_md.ipv4_dst_addr = tunnel_dst_addr;
219 fabric_md.l4_sport = tunnel_src_port;
220 fabric_md.l4_dport = UDP_PORT_GTPU;
221 }
222
223 action load_dbuf_far(bit<1> drop,
224 bit<1> notify_cp,
225 bit<16> tunnel_src_port,
226 bit<32> tunnel_src_addr,
227 bit<32> tunnel_dst_addr,
228 teid_t teid) {
229 load_tunnel_far(drop, notify_cp, tunnel_src_port,
230 tunnel_src_addr, tunnel_dst_addr, teid);
231 fabric_md.spgw.skip_egress_pdr_ctr = _TRUE;
232 }
233
234 table fars {
235 key = {
236 fabric_md.spgw.far_id : exact @name("far_id");
237 }
238 actions = {
239 load_normal_far;
240 load_tunnel_far;
241 load_dbuf_far;
242 }
243 // default is drop and don't notify CP
244 const default_action = load_normal_far(1, 0);
245 size = MAX_FARS;
Robert MacDavidde12b982020-07-15 18:38:59 -0700246 }
247
248
249 //=============================//
250 //===== Apply Block ======//
251 //=============================//
252 apply {
253
254 // Interfaces
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800255 if (interfaces.apply().hit) {
256 if (fabric_md.spgw.src_iface == SPGW_IFACE_FROM_DBUF) {
257 decap_gtpu_from_dbuf.apply(hdr, fabric_md);
258 }
259 // PDRs
260 if (hdr.gtpu.isValid()) {
261 uplink_pdrs.apply();
262 } else {
263 downlink_pdrs.apply();
264 }
265 if (fabric_md.spgw.src_iface != SPGW_IFACE_FROM_DBUF) {
266 pdr_counter.count(fabric_md.spgw.ctr_id);
267 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700268
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800269 // GTPU Decapsulate
270 if (fabric_md.spgw.needs_gtpu_decap == _TRUE) {
271 decap_gtpu.apply(hdr, fabric_md);
272 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700273
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800274 // FARs
275 // Load FAR info
276 fars.apply();
277
278 // Nothing to be done immediately for forwarding or encapsulation.
279 // Forwarding is done by other parts of fabric.p4, and
280 // encapsulation is done in the egress
281
282 // Needed for correct GTPU encapsulation in egress
283 fabric_md.spgw.ipv4_len = hdr.ipv4.total_len;
Robert MacDavidde12b982020-07-15 18:38:59 -0700284 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700285 }
286}
287
288
289//====================================//
290//============== Egress ==============//
291//====================================//
292control SpgwEgress(
293 inout parsed_headers_t hdr,
294 inout fabric_metadata_t fabric_md) {
295
296 counter(MAX_PDR_COUNTERS, CounterType.packets_and_bytes) pdr_counter;
297
298
299 @hidden
300 action gtpu_encap() {
301 hdr.gtpu_ipv4.setValid();
302 hdr.gtpu_ipv4.version = IP_VERSION_4;
303 hdr.gtpu_ipv4.ihl = IPV4_MIN_IHL;
304 hdr.gtpu_ipv4.dscp = 0;
305 hdr.gtpu_ipv4.ecn = 0;
306 hdr.gtpu_ipv4.total_len = hdr.ipv4.total_len
307 + (IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE);
308 hdr.gtpu_ipv4.identification = 0x1513; /* From NGIC. TODO: Needs to be dynamic */
309 hdr.gtpu_ipv4.flags = 0;
310 hdr.gtpu_ipv4.frag_offset = 0;
311 hdr.gtpu_ipv4.ttl = DEFAULT_IPV4_TTL;
312 hdr.gtpu_ipv4.protocol = PROTO_UDP;
313 hdr.gtpu_ipv4.src_addr = fabric_md.spgw.tunnel_src_addr;
314 hdr.gtpu_ipv4.dst_addr = fabric_md.spgw.tunnel_dst_addr;
315 hdr.gtpu_ipv4.hdr_checksum = 0; // Updated later
316
317 hdr.gtpu_udp.setValid();
318 hdr.gtpu_udp.sport = fabric_md.spgw.tunnel_src_port;
319 hdr.gtpu_udp.dport = UDP_PORT_GTPU;
320 hdr.gtpu_udp.len = fabric_md.spgw.ipv4_len
321 + (UDP_HDR_SIZE + GTP_HDR_SIZE);
322 hdr.gtpu_udp.checksum = 0; // Updated later, if WITH_SPGW_UDP_CSUM_UPDATE
323
324
325 hdr.outer_gtpu.setValid();
326 hdr.outer_gtpu.version = GTPU_VERSION;
327 hdr.outer_gtpu.pt = GTP_PROTOCOL_TYPE_GTP;
328 hdr.outer_gtpu.spare = 0;
329 hdr.outer_gtpu.ex_flag = 0;
330 hdr.outer_gtpu.seq_flag = 0;
331 hdr.outer_gtpu.npdu_flag = 0;
332 hdr.outer_gtpu.msgtype = GTP_GPDU;
333 hdr.outer_gtpu.msglen = fabric_md.spgw.ipv4_len;
334 hdr.outer_gtpu.teid = fabric_md.spgw.teid;
335 }
336
337 apply {
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800338 if (fabric_md.spgw.skip_spgw == _FALSE) {
339 if (fabric_md.spgw.needs_gtpu_encap == _TRUE) {
340 gtpu_encap();
341 }
342 if (fabric_md.spgw.skip_egress_pdr_ctr == _FALSE) {
343 pdr_counter.count(fabric_md.spgw.ctr_id);
344 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700345 }
346 }
347}
348
349
350control update_gtpu_checksum(
351 inout ipv4_t gtpu_ipv4,
352 inout udp_t gtpu_udp,
353 in gtpu_t gtpu,
354 in ipv4_t ipv4,
355 in udp_t udp
356 ) {
357 apply {
358 // Compute outer IPv4 checksum.
359 update_checksum(gtpu_ipv4.isValid(),
360 {
361 gtpu_ipv4.version,
362 gtpu_ipv4.ihl,
363 gtpu_ipv4.dscp,
364 gtpu_ipv4.ecn,
365 gtpu_ipv4.total_len,
366 gtpu_ipv4.identification,
367 gtpu_ipv4.flags,
368 gtpu_ipv4.frag_offset,
369 gtpu_ipv4.ttl,
370 gtpu_ipv4.protocol,
371 gtpu_ipv4.src_addr,
372 gtpu_ipv4.dst_addr
373 },
374 gtpu_ipv4.hdr_checksum,
375 HashAlgorithm.csum16
376 );
377
378#ifdef WITH_SPGW_UDP_CSUM_UPDATE
379 // Compute outer UDP checksum.
380 update_checksum_with_payload(gtpu_udp.isValid(),
381 {
382 gtpu_ipv4.src_addr,
383 gtpu_ipv4.dst_addr,
384 8w0,
385 gtpu_ipv4.protocol,
386 gtpu_udp.len,
387 gtpu_udp.sport,
388 gtpu_udp.dport,
389 gtpu_udp.len,
390 gtpu,
391 ipv4,
392 // FIXME: we are assuming only UDP for downlink packets
393 // How to conditionally switch between UDP/TCP/ICMP?
394 udp
395 },
396 gtpu_udp.checksum,
397 HashAlgorithm.csum16
398 );
399#endif // WITH_SPGW_UDP_CSUM_UPDATE
400 }
401}
402
403#endif