blob: 00bfd948800a02f19d424bf7f6a48e72d580b66c [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
148 action load_pdr(pdr_ctr_id_t ctr_id,
149 far_id_t far_id,
150 bit<1> needs_gtpu_decap) {
151 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
156 // These two tables scale well and cover the average case PDR
157 table downlink_pdrs {
158 key = {
159 // only available ipv4 header
160 hdr.ipv4.dst_addr : exact @name("ue_addr");
161 }
162 actions = {
163 load_pdr;
164 }
165 size = MAX_DOWNLINK_PDRS;
166 }
167
168 table uplink_pdrs {
169 key = {
170 hdr.ipv4.dst_addr : exact @name("tunnel_ipv4_dst");
171 hdr.gtpu.teid : exact @name("teid");
172 }
173 actions = {
174 load_pdr;
175 }
176 size = MAX_UPLINK_PDRS;
177 }
178
179 //=============================//
180 //===== FAR Tables ======//
181 //=============================//
182
183 action load_normal_far(bit<1> drop,
184 bit<1> notify_cp) {
185 // general far attributes
186 fabric_md.skip_forwarding = (_BOOL)drop;
187 fabric_md.skip_next = (_BOOL)drop;
188 fabric_md.spgw.notify_spgwc = (_BOOL)notify_cp;
189 }
190 action load_tunnel_far(bit<1> drop,
191 bit<1> notify_cp,
192 bit<16> tunnel_src_port,
193 bit<32> tunnel_src_addr,
194 bit<32> tunnel_dst_addr,
195 teid_t teid) {
196 // general far attributes
197 fabric_md.skip_forwarding = (_BOOL)drop;
198 fabric_md.skip_next = (_BOOL)drop;
199 fabric_md.spgw.notify_spgwc = (_BOOL)notify_cp;
200 // GTP tunnel attributes
201 fabric_md.spgw.needs_gtpu_encap = _TRUE;
202 fabric_md.spgw.teid = teid;
203 fabric_md.spgw.tunnel_src_port = tunnel_src_port;
204 fabric_md.spgw.tunnel_src_addr = tunnel_src_addr;
205 fabric_md.spgw.tunnel_dst_addr = tunnel_dst_addr;
206 // update metadata for correct routing/hashing
207 fabric_md.ipv4_src_addr = tunnel_src_addr;
208 fabric_md.ipv4_dst_addr = tunnel_dst_addr;
209 fabric_md.l4_sport = tunnel_src_port;
210 fabric_md.l4_dport = UDP_PORT_GTPU;
211 }
212
213 action load_dbuf_far(bit<1> drop,
214 bit<1> notify_cp,
215 bit<16> tunnel_src_port,
216 bit<32> tunnel_src_addr,
217 bit<32> tunnel_dst_addr,
218 teid_t teid) {
219 load_tunnel_far(drop, notify_cp, tunnel_src_port,
220 tunnel_src_addr, tunnel_dst_addr, teid);
221 fabric_md.spgw.skip_egress_pdr_ctr = _TRUE;
222 }
223
224 table fars {
225 key = {
226 fabric_md.spgw.far_id : exact @name("far_id");
227 }
228 actions = {
229 load_normal_far;
230 load_tunnel_far;
231 load_dbuf_far;
232 }
233 // default is drop and don't notify CP
234 const default_action = load_normal_far(1, 0);
235 size = MAX_FARS;
Robert MacDavidde12b982020-07-15 18:38:59 -0700236 }
237
238
239 //=============================//
240 //===== Apply Block ======//
241 //=============================//
242 apply {
243
244 // Interfaces
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800245 if (interfaces.apply().hit) {
246 if (fabric_md.spgw.src_iface == SPGW_IFACE_FROM_DBUF) {
247 decap_gtpu_from_dbuf.apply(hdr, fabric_md);
248 }
249 // PDRs
250 if (hdr.gtpu.isValid()) {
251 uplink_pdrs.apply();
252 } else {
253 downlink_pdrs.apply();
254 }
255 if (fabric_md.spgw.src_iface != SPGW_IFACE_FROM_DBUF) {
256 pdr_counter.count(fabric_md.spgw.ctr_id);
257 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700258
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800259 // GTPU Decapsulate
260 if (fabric_md.spgw.needs_gtpu_decap == _TRUE) {
261 decap_gtpu.apply(hdr, fabric_md);
262 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700263
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800264 // FARs
265 // Load FAR info
266 fars.apply();
267
268 // Nothing to be done immediately for forwarding or encapsulation.
269 // Forwarding is done by other parts of fabric.p4, and
270 // encapsulation is done in the egress
271
272 // Needed for correct GTPU encapsulation in egress
273 fabric_md.spgw.ipv4_len = hdr.ipv4.total_len;
Robert MacDavidde12b982020-07-15 18:38:59 -0700274 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700275 }
276}
277
278
279//====================================//
280//============== Egress ==============//
281//====================================//
282control SpgwEgress(
283 inout parsed_headers_t hdr,
284 inout fabric_metadata_t fabric_md) {
285
286 counter(MAX_PDR_COUNTERS, CounterType.packets_and_bytes) pdr_counter;
287
288
289 @hidden
290 action gtpu_encap() {
291 hdr.gtpu_ipv4.setValid();
292 hdr.gtpu_ipv4.version = IP_VERSION_4;
293 hdr.gtpu_ipv4.ihl = IPV4_MIN_IHL;
294 hdr.gtpu_ipv4.dscp = 0;
295 hdr.gtpu_ipv4.ecn = 0;
296 hdr.gtpu_ipv4.total_len = hdr.ipv4.total_len
297 + (IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE);
298 hdr.gtpu_ipv4.identification = 0x1513; /* From NGIC. TODO: Needs to be dynamic */
299 hdr.gtpu_ipv4.flags = 0;
300 hdr.gtpu_ipv4.frag_offset = 0;
301 hdr.gtpu_ipv4.ttl = DEFAULT_IPV4_TTL;
302 hdr.gtpu_ipv4.protocol = PROTO_UDP;
303 hdr.gtpu_ipv4.src_addr = fabric_md.spgw.tunnel_src_addr;
304 hdr.gtpu_ipv4.dst_addr = fabric_md.spgw.tunnel_dst_addr;
305 hdr.gtpu_ipv4.hdr_checksum = 0; // Updated later
306
307 hdr.gtpu_udp.setValid();
308 hdr.gtpu_udp.sport = fabric_md.spgw.tunnel_src_port;
309 hdr.gtpu_udp.dport = UDP_PORT_GTPU;
310 hdr.gtpu_udp.len = fabric_md.spgw.ipv4_len
311 + (UDP_HDR_SIZE + GTP_HDR_SIZE);
312 hdr.gtpu_udp.checksum = 0; // Updated later, if WITH_SPGW_UDP_CSUM_UPDATE
313
314
315 hdr.outer_gtpu.setValid();
316 hdr.outer_gtpu.version = GTPU_VERSION;
317 hdr.outer_gtpu.pt = GTP_PROTOCOL_TYPE_GTP;
318 hdr.outer_gtpu.spare = 0;
319 hdr.outer_gtpu.ex_flag = 0;
320 hdr.outer_gtpu.seq_flag = 0;
321 hdr.outer_gtpu.npdu_flag = 0;
322 hdr.outer_gtpu.msgtype = GTP_GPDU;
323 hdr.outer_gtpu.msglen = fabric_md.spgw.ipv4_len;
324 hdr.outer_gtpu.teid = fabric_md.spgw.teid;
325 }
326
327 apply {
Carmelo Cascone2102bfb2020-12-04 16:54:24 -0800328 if (fabric_md.spgw.skip_spgw == _FALSE) {
329 if (fabric_md.spgw.needs_gtpu_encap == _TRUE) {
330 gtpu_encap();
331 }
332 if (fabric_md.spgw.skip_egress_pdr_ctr == _FALSE) {
333 pdr_counter.count(fabric_md.spgw.ctr_id);
334 }
Robert MacDavidde12b982020-07-15 18:38:59 -0700335 }
336 }
337}
338
339
340control update_gtpu_checksum(
341 inout ipv4_t gtpu_ipv4,
342 inout udp_t gtpu_udp,
343 in gtpu_t gtpu,
344 in ipv4_t ipv4,
345 in udp_t udp
346 ) {
347 apply {
348 // Compute outer IPv4 checksum.
349 update_checksum(gtpu_ipv4.isValid(),
350 {
351 gtpu_ipv4.version,
352 gtpu_ipv4.ihl,
353 gtpu_ipv4.dscp,
354 gtpu_ipv4.ecn,
355 gtpu_ipv4.total_len,
356 gtpu_ipv4.identification,
357 gtpu_ipv4.flags,
358 gtpu_ipv4.frag_offset,
359 gtpu_ipv4.ttl,
360 gtpu_ipv4.protocol,
361 gtpu_ipv4.src_addr,
362 gtpu_ipv4.dst_addr
363 },
364 gtpu_ipv4.hdr_checksum,
365 HashAlgorithm.csum16
366 );
367
368#ifdef WITH_SPGW_UDP_CSUM_UPDATE
369 // Compute outer UDP checksum.
370 update_checksum_with_payload(gtpu_udp.isValid(),
371 {
372 gtpu_ipv4.src_addr,
373 gtpu_ipv4.dst_addr,
374 8w0,
375 gtpu_ipv4.protocol,
376 gtpu_udp.len,
377 gtpu_udp.sport,
378 gtpu_udp.dport,
379 gtpu_udp.len,
380 gtpu,
381 ipv4,
382 // FIXME: we are assuming only UDP for downlink packets
383 // How to conditionally switch between UDP/TCP/ICMP?
384 udp
385 },
386 gtpu_udp.checksum,
387 HashAlgorithm.csum16
388 );
389#endif // WITH_SPGW_UDP_CSUM_UPDATE
390 }
391}
392
393#endif