blob: 10c446746805184729bc77496f47e747fef12f58 [file] [log] [blame]
Robert MacDavidc9fce632020-07-28 22:17:07 -04001/*
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
Robert MacDavid4d1d67f2020-09-30 13:57:58 -040033control DecapGtpu(inout parsed_headers_t hdr,
34 inout fabric_metadata_t fabric_md) {
35 @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 }
49 @hidden
50 action decap_inner_tcp() {
51 decap_inner_common();
52 hdr.udp.setInvalid();
53 hdr.tcp = hdr.inner_tcp;
54 hdr.inner_tcp.setInvalid();
55 }
56 @hidden
57 action decap_inner_udp() {
58 decap_inner_common();
59 hdr.udp = hdr.inner_udp;
60 hdr.inner_udp.setInvalid();
61 }
62 @hidden
63 action decap_inner_icmp() {
64 decap_inner_common();
65 hdr.udp.setInvalid();
66 hdr.icmp = hdr.inner_icmp;
67 hdr.inner_icmp.setInvalid();
68 }
69 @hidden
70 action decap_inner_unknown() {
71 decap_inner_common();
72 hdr.udp.setInvalid();
73 }
74 @hidden
75 table decap_gtpu {
76 key = {
77 hdr.inner_tcp.isValid() : exact;
78 hdr.inner_udp.isValid() : exact;
79 hdr.inner_icmp.isValid() : exact;
80 }
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 }
93 size = 4;
94 }
95 apply {
96 decap_gtpu.apply();
97 }
98}
Robert MacDavidc9fce632020-07-28 22:17:07 -040099
100
101control SpgwIngress(inout parsed_headers_t hdr,
102 inout fabric_metadata_t fabric_md,
103 inout standard_metadata_t standard_metadata) {
104
Robert MacDavid4d1d67f2020-09-30 13:57:58 -0400105 //=============================//
106 //===== Misc Things ======//
107 //=============================//
108
109 counter(MAX_PDR_COUNTERS, CounterType.packets_and_bytes) pdr_counter;
Robert MacDavidc9fce632020-07-28 22:17:07 -0400110
Robert MacDavid4d1d67f2020-09-30 13:57:58 -0400111 DecapGtpu() decap_gtpu_from_dbuf;
112 DecapGtpu() decap_gtpu;
Robert MacDavidc9fce632020-07-28 22:17:07 -0400113
114
115 //=============================//
116 //===== Interface Tables ======//
117 //=============================//
118
119 action set_source_iface(spgw_interface_t src_iface, direction_t direction,
120 bit<1> skip_spgw) {
121 // Interface type can be access, core, n6_lan, etc (see InterfaceType enum)
122 // If interface is from the control plane, direction can be either up or down
123 fabric_md.spgw.src_iface = src_iface;
124 fabric_md.spgw.direction = direction;
125 fabric_md.spgw.skip_spgw = (_BOOL)skip_spgw;
126 }
127 // TODO: check also that gtpu.msgtype == GTP_GPDU... somewhere
128 table interface_lookup {
129 key = {
130 hdr.ipv4.dst_addr : lpm @name("ipv4_dst_addr"); // outermost header
131 hdr.gtpu.isValid() : exact @name("gtpu_is_valid");
132 }
133 actions = {
134 set_source_iface;
135 }
136 const default_action = set_source_iface(SPGW_IFACE_UNKNOWN, SPGW_DIR_UNKNOWN, 1);
137 size = MAX_INTERFACES;
138 }
139
140
141 //=============================//
142 //===== PDR Tables ======//
143 //=============================//
144
145 action set_pdr_attributes(pdr_ctr_id_t ctr_id,
146 far_id_t far_id,
147 bit<1> needs_gtpu_decap) {
148 fabric_md.spgw.pdr_hit = _TRUE;
149 fabric_md.spgw.ctr_id = ctr_id;
150 fabric_md.spgw.far_id = far_id;
151 fabric_md.spgw.needs_gtpu_decap = (_BOOL)needs_gtpu_decap;
152 }
153
154 // These two tables scale well and cover the average case PDR
155 table downlink_pdr_lookup {
156 key = {
157 // only available ipv4 header
158 hdr.ipv4.dst_addr : exact @name("ue_addr");
159 }
160 actions = {
161 set_pdr_attributes;
162 }
163 const default_action = set_pdr_attributes(DEFAULT_PDR_CTR_ID, DEFAULT_FAR_ID, 0);
164 size = MAX_DOWNLINK_PDRS;
165 }
166 table uplink_pdr_lookup {
167 key = {
Robert MacDavidc9fce632020-07-28 22:17:07 -0400168 hdr.ipv4.dst_addr : exact @name("tunnel_ipv4_dst");
169 hdr.gtpu.teid : exact @name("teid");
Robert MacDavidc9fce632020-07-28 22:17:07 -0400170 }
171 actions = {
172 set_pdr_attributes;
173 }
174 const default_action = set_pdr_attributes(DEFAULT_PDR_CTR_ID, DEFAULT_FAR_ID, 0);
175 size = MAX_UPLINK_PDRS;
176 }
177 // This table scales poorly and covers uncommon PDRs
178 table flexible_pdr_lookup {
179 key = {
180 fabric_md.spgw.src_iface : ternary @name("src_iface");
181 // GTPU
182 hdr.gtpu.isValid() : ternary @name("gtpu_is_valid");
183 hdr.gtpu.teid : ternary @name("teid");
184 // SDF
185 // outer 5-tuple
186 hdr.ipv4.src_addr : ternary @name("ipv4_src");
187 hdr.ipv4.dst_addr : ternary @name("ipv4_dst");
188 hdr.ipv4.protocol : ternary @name("ip_proto");
189 fabric_md.l4_sport : ternary @name("l4_sport");
190 fabric_md.l4_dport : ternary @name("l4_dport");
191 // inner 5-tuple
192 hdr.inner_ipv4.src_addr : ternary @name("inner_ipv4_src");
193 hdr.inner_ipv4.dst_addr : ternary @name("inner_ipv4_dst");
194 hdr.inner_ipv4.protocol : ternary @name("inner_ip_proto");
195 fabric_md.inner_l4_sport : ternary @name("inner_l4_sport");
196 fabric_md.inner_l4_dport : ternary @name("inner_l4_dport");
197 }
198 actions = {
199 set_pdr_attributes;
200 }
201 const default_action = set_pdr_attributes(DEFAULT_PDR_CTR_ID, DEFAULT_FAR_ID, 0);
202 }
203
204 //=============================//
205 //===== FAR Tables ======//
206 //=============================//
207
208 action load_normal_far_attributes(bit<1> drop,
209 bit<1> notify_cp) {
210 // general far attributes
Robert MacDavid4d1d67f2020-09-30 13:57:58 -0400211 fabric_md.skip_forwarding = (_BOOL)drop;
212 fabric_md.skip_next = (_BOOL)drop;
Robert MacDavidc9fce632020-07-28 22:17:07 -0400213 fabric_md.spgw.notify_spgwc = (_BOOL)notify_cp;
214 }
215 action load_tunnel_far_attributes(bit<1> drop,
216 bit<1> notify_cp,
217 bit<16> tunnel_src_port,
218 bit<32> tunnel_src_addr,
219 bit<32> tunnel_dst_addr,
220 teid_t teid) {
221 // general far attributes
Robert MacDavid4d1d67f2020-09-30 13:57:58 -0400222 fabric_md.skip_forwarding = (_BOOL)drop;
223 fabric_md.skip_next = (_BOOL)drop;
Robert MacDavidc9fce632020-07-28 22:17:07 -0400224 fabric_md.spgw.notify_spgwc = (_BOOL)notify_cp;
225 // GTP tunnel attributes
226 fabric_md.spgw.needs_gtpu_encap = _TRUE;
227 fabric_md.spgw.teid = teid;
228 fabric_md.spgw.tunnel_src_port = tunnel_src_port;
229 fabric_md.spgw.tunnel_src_addr = tunnel_src_addr;
230 fabric_md.spgw.tunnel_dst_addr = tunnel_dst_addr;
231 // update metadata for correct routing/hashing
232 fabric_md.ipv4_src_addr = tunnel_src_addr;
233 fabric_md.ipv4_dst_addr = tunnel_dst_addr;
234 fabric_md.l4_sport = tunnel_src_port;
235 fabric_md.l4_dport = UDP_PORT_GTPU;
236 }
237
Robert MacDavid4d1d67f2020-09-30 13:57:58 -0400238 action load_dbuf_far_attributes(bit<1> drop,
239 bit<1> notify_cp,
240 bit<16> tunnel_src_port,
241 bit<32> tunnel_src_addr,
242 bit<32> tunnel_dst_addr,
243 teid_t teid) {
244 load_tunnel_far_attributes(drop, notify_cp, tunnel_src_port,
245 tunnel_src_addr, tunnel_dst_addr, teid);
246 fabric_md.spgw.skip_egress_pdr_ctr = _TRUE;
247 }
248
Robert MacDavidc9fce632020-07-28 22:17:07 -0400249 table far_lookup {
250 key = {
251 fabric_md.spgw.far_id : exact @name("far_id");
252 }
253 actions = {
254 load_normal_far_attributes;
255 load_tunnel_far_attributes;
Robert MacDavid4d1d67f2020-09-30 13:57:58 -0400256 load_dbuf_far_attributes;
Robert MacDavidc9fce632020-07-28 22:17:07 -0400257 }
258 // default is drop and don't notify CP
Robert MacDavid4d1d67f2020-09-30 13:57:58 -0400259 const default_action = load_normal_far_attributes(1, 0);
Robert MacDavidc9fce632020-07-28 22:17:07 -0400260 size = MAX_FARS;
261 }
262
Robert MacDavidc9fce632020-07-28 22:17:07 -0400263
264
265 //=============================//
266 //===== Apply Block ======//
267 //=============================//
268 apply {
269
270 // Interfaces
Robert MacDavid4d1d67f2020-09-30 13:57:58 -0400271 if (interface_lookup.apply().hit) {
272 if (fabric_md.spgw.src_iface == SPGW_IFACE_FROM_DBUF) {
273 decap_gtpu_from_dbuf.apply(hdr, fabric_md);
274 }
275 // PDRs
276 if (hdr.gtpu.isValid()) {
277 uplink_pdr_lookup.apply();
278 } else {
279 downlink_pdr_lookup.apply();
280 }
281 if (fabric_md.spgw.src_iface != SPGW_IFACE_FROM_DBUF) {
282 pdr_counter.count(fabric_md.spgw.ctr_id);
283 }
Robert MacDavidc9fce632020-07-28 22:17:07 -0400284
Robert MacDavid4d1d67f2020-09-30 13:57:58 -0400285 // GTPU Decapsulate
286 if (fabric_md.spgw.needs_gtpu_decap == _TRUE) {
287 decap_gtpu.apply(hdr, fabric_md);
288 }
Robert MacDavidc9fce632020-07-28 22:17:07 -0400289
Robert MacDavid4d1d67f2020-09-30 13:57:58 -0400290 // FARs
291 // Load FAR info
292 far_lookup.apply();
293
294 // Nothing to be done immediately for forwarding or encapsulation.
295 // Forwarding is done by other parts of fabric.p4, and
296 // encapsulation is done in the egress
297
298 // Needed for correct GTPU encapsulation in egress
299 fabric_md.spgw.ipv4_len = hdr.ipv4.total_len;
Robert MacDavidc9fce632020-07-28 22:17:07 -0400300 }
Robert MacDavidc9fce632020-07-28 22:17:07 -0400301 }
302}
303
304
305//====================================//
306//============== Egress ==============//
307//====================================//
308control SpgwEgress(
309 inout parsed_headers_t hdr,
310 inout fabric_metadata_t fabric_md) {
311
312 counter(MAX_PDR_COUNTERS, CounterType.packets_and_bytes) pdr_counter;
313
314
315 @hidden
316 action gtpu_encap() {
317 hdr.gtpu_ipv4.setValid();
318 hdr.gtpu_ipv4.version = IP_VERSION_4;
319 hdr.gtpu_ipv4.ihl = IPV4_MIN_IHL;
320 hdr.gtpu_ipv4.dscp = 0;
321 hdr.gtpu_ipv4.ecn = 0;
322 hdr.gtpu_ipv4.total_len = hdr.ipv4.total_len
323 + (IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE);
324 hdr.gtpu_ipv4.identification = 0x1513; /* From NGIC. TODO: Needs to be dynamic */
325 hdr.gtpu_ipv4.flags = 0;
326 hdr.gtpu_ipv4.frag_offset = 0;
327 hdr.gtpu_ipv4.ttl = DEFAULT_IPV4_TTL;
328 hdr.gtpu_ipv4.protocol = PROTO_UDP;
329 hdr.gtpu_ipv4.src_addr = fabric_md.spgw.tunnel_src_addr;
330 hdr.gtpu_ipv4.dst_addr = fabric_md.spgw.tunnel_dst_addr;
331 hdr.gtpu_ipv4.hdr_checksum = 0; // Updated later
332
333 hdr.gtpu_udp.setValid();
334 hdr.gtpu_udp.sport = fabric_md.spgw.tunnel_src_port;
335 hdr.gtpu_udp.dport = UDP_PORT_GTPU;
336 hdr.gtpu_udp.len = fabric_md.spgw.ipv4_len
337 + (UDP_HDR_SIZE + GTP_HDR_SIZE);
338 hdr.gtpu_udp.checksum = 0; // Updated later, if WITH_SPGW_UDP_CSUM_UPDATE
339
340
341 hdr.outer_gtpu.setValid();
342 hdr.outer_gtpu.version = GTPU_VERSION;
343 hdr.outer_gtpu.pt = GTP_PROTOCOL_TYPE_GTP;
344 hdr.outer_gtpu.spare = 0;
345 hdr.outer_gtpu.ex_flag = 0;
346 hdr.outer_gtpu.seq_flag = 0;
347 hdr.outer_gtpu.npdu_flag = 0;
348 hdr.outer_gtpu.msgtype = GTP_GPDU;
349 hdr.outer_gtpu.msglen = fabric_md.spgw.ipv4_len;
350 hdr.outer_gtpu.teid = fabric_md.spgw.teid;
351 }
352
353 apply {
Robert MacDavid4d1d67f2020-09-30 13:57:58 -0400354 if (fabric_md.spgw.skip_spgw == _FALSE) {
355 if (fabric_md.spgw.needs_gtpu_encap == _TRUE) {
356 gtpu_encap();
357 }
358 if (fabric_md.spgw.skip_egress_pdr_ctr == _FALSE) {
359 pdr_counter.count(fabric_md.spgw.ctr_id);
360 }
Robert MacDavidc9fce632020-07-28 22:17:07 -0400361 }
362 }
363}
364
365
366control update_gtpu_checksum(
367 inout ipv4_t gtpu_ipv4,
368 inout udp_t gtpu_udp,
369 in gtpu_t gtpu,
370 in ipv4_t ipv4,
371 in udp_t udp
372 ) {
373 apply {
374 // Compute outer IPv4 checksum.
375 update_checksum(gtpu_ipv4.isValid(),
376 {
377 gtpu_ipv4.version,
378 gtpu_ipv4.ihl,
379 gtpu_ipv4.dscp,
380 gtpu_ipv4.ecn,
381 gtpu_ipv4.total_len,
382 gtpu_ipv4.identification,
383 gtpu_ipv4.flags,
384 gtpu_ipv4.frag_offset,
385 gtpu_ipv4.ttl,
386 gtpu_ipv4.protocol,
387 gtpu_ipv4.src_addr,
388 gtpu_ipv4.dst_addr
389 },
390 gtpu_ipv4.hdr_checksum,
391 HashAlgorithm.csum16
392 );
393
394#ifdef WITH_SPGW_UDP_CSUM_UPDATE
395 // Compute outer UDP checksum.
396 update_checksum_with_payload(gtpu_udp.isValid(),
397 {
398 gtpu_ipv4.src_addr,
399 gtpu_ipv4.dst_addr,
400 8w0,
401 gtpu_ipv4.protocol,
402 gtpu_udp.len,
403 gtpu_udp.sport,
404 gtpu_udp.dport,
405 gtpu_udp.len,
406 gtpu,
407 ipv4,
408 // FIXME: we are assuming only UDP for downlink packets
409 // How to conditionally switch between UDP/TCP/ICMP?
410 udp
411 },
412 gtpu_udp.checksum,
413 HashAlgorithm.csum16
414 );
415#endif // WITH_SPGW_UDP_CSUM_UPDATE
416 }
417}
418
419#endif