blob: 0dfd8f14e23bc318a0bb09ac2f006d257f096241 [file] [log] [blame]
Carmelo Casconeb81f4be2018-01-16 23:24:01 -08001/*
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
21control spgw_ingress(
22 inout ipv4_t gtpu_ipv4,
23 inout udp_t gtpu_udp,
24 inout gtpu_t gtpu,
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080025 inout ipv4_t ipv4,
26 inout udp_t udp,
27 inout spgw_meta_t spgw_meta
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080028 ) {
29
30 direct_counter(CounterType.packets_and_bytes) ue_counter;
31
32 action gtpu_decap() {
33 gtpu_ipv4.setInvalid();
34 gtpu_udp.setInvalid();
35 gtpu.setInvalid();
36 }
37
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080038 action set_dl_sess_info(bit<32> teid,
39 bit<32> s1u_enb_addr,
40 bit<32> s1u_sgw_addr) {
41 spgw_meta.teid = teid;
42 spgw_meta.s1u_enb_addr = s1u_enb_addr;
43 spgw_meta.s1u_sgw_addr = s1u_sgw_addr;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080044 }
45
46 action update_ue_cdr() {
47 ue_counter.count();
48 }
49
50 table ue_filter_table {
51 key = {
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080052 // IP prefixes of the UEs managed by this switch (when downlink)
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080053 ipv4.dst_addr : lpm;
54 }
55 actions = {
56 NoAction();
57 }
58 }
59
60 table s1u_filter_table {
61 key = {
62 // IP addresses of the S1U interfaces embodied by this switch.
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080063 spgw_meta.s1u_sgw_addr : exact;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080064 }
65 actions = {
66 NoAction();
67 }
68 }
69
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080070#ifdef WITH_SPGW_PCC_GATING
71 action set_sdf_rule_id(sdf_rule_id_t id) {
72 spgw_meta.sdf_rule_id = id;
73 }
74
75 action set_pcc_rule_id(pcc_rule_id_t id) {
76 spgw_meta.pcc_rule_id = id;
77 }
78
79 action set_pcc_info(pcc_gate_status_t gate_status) {
80 spgw_meta.pcc_gate_status = gate_status;
81 }
82
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080083 table sdf_rule_lookup {
84 key = {
85 spgw_meta.direction : exact;
86 ipv4.src_addr : ternary;
87 ipv4.dst_addr : ternary;
88 ipv4.protocol : ternary;
89 spgw_meta.l4_src_port : ternary;
90 spgw_meta.l4_dst_port : ternary;
91 }
92 actions = {
93 set_sdf_rule_id();
94 }
95 const default_action = set_sdf_rule_id(DEFAULT_SDF_RULE_ID);
96 }
97
98 table pcc_rule_lookup {
99 key = {
100 spgw_meta.sdf_rule_id : exact;
101 }
102 actions = {
103 set_pcc_rule_id();
104 }
105 const default_action = set_pcc_rule_id(DEFAULT_PCC_RULE_ID);
106 }
107
108 table pcc_info_lookup {
109 key = {
110 spgw_meta.pcc_rule_id : exact;
111 }
112 actions = {
113 set_pcc_info();
114 }
115 const default_action = set_pcc_info(PCC_GATE_OPEN);
116 }
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800117#endif // WITH_SPGW_PCC_GATING
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800118
119 table dl_sess_lookup {
120 key = {
121 // UE addr for downlink
122 ipv4.dst_addr : exact;
123 }
124 actions = {
125 set_dl_sess_info();
126 }
127 }
128
129 table ue_cdr_table {
130 key = {
131 // UE addr for downlink
132 ipv4.dst_addr : exact;
133 }
134 actions = {
135 update_ue_cdr();
136 }
137 counters = ue_counter;
138 }
139
140 apply {
Carmelo Cascone35d9b332018-06-15 16:27:22 +0200141 spgw_meta.do_spgw = _FALSE;
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800142 if (gtpu.isValid()) {
143 // If here, the parsed ipv4 header is the outer GTP one, but
144 // fabric needs to forward on the inner one, i.e. this.
145 // We store the outer values we need in the metadata, then replace
146 // the ipv4 header extracted before with this one.
147 spgw_meta.s1u_enb_addr = ipv4.src_addr;
148 spgw_meta.s1u_sgw_addr = ipv4.dst_addr;
149 ipv4 = gtpu_ipv4;
150 udp = gtpu_udp;
151
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800152 if (s1u_filter_table.apply().hit) {
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800153 // TODO: check also that gtpu.msgtype == GTP_GPDU
Carmelo Cascone35d9b332018-06-15 16:27:22 +0200154 spgw_meta.do_spgw = _TRUE;
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800155 spgw_meta.direction = DIR_UPLINK;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800156 }
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800157 } else if (ue_filter_table.apply().hit) {
Carmelo Cascone35d9b332018-06-15 16:27:22 +0200158 spgw_meta.do_spgw = _TRUE;
Carmelo Cascone14cde402018-01-25 01:57:18 -0800159 spgw_meta.direction = DIR_DOWNLINK;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800160 }
161
Carmelo Cascone35d9b332018-06-15 16:27:22 +0200162 if (spgw_meta.do_spgw == _FALSE) {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800163 // Exit this control block.
164 return;
165 }
166
167 if (spgw_meta.direction == DIR_UPLINK) {
168 gtpu_decap();
169 }
170
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800171#ifdef WITH_SPGW_PCC_GATING
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800172 // Allow all traffic by default.
173 spgw_meta.pcc_gate_status = PCC_GATE_OPEN;
174
175 sdf_rule_lookup.apply();
176 pcc_rule_lookup.apply();
177 pcc_info_lookup.apply();
178
179 if (spgw_meta.pcc_gate_status == PCC_GATE_CLOSED) {
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800180 drop_now();
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800181 }
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800182#endif // WITH_SPGW_PCC_GATING
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800183
184 if (spgw_meta.direction == DIR_DOWNLINK) {
185 if (!dl_sess_lookup.apply().hit) {
186 // We have no other choice than drop, as we miss the session
187 // info necessary to properly GTPU encap the packet.
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800188 drop_now();
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800189 }
190 ue_cdr_table.apply();
191 }
Carmelo Cascone274daef2018-02-14 20:32:49 -0800192
193 // Don't ask why... we'll need this later.
194 spgw_meta.ipv4_len = ipv4.total_len;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800195 }
196}
197
198
199control spgw_egress(
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800200 in ipv4_t ipv4,
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800201 out ipv4_t gtpu_ipv4,
202 out udp_t gtpu_udp,
203 out gtpu_t gtpu,
204 in spgw_meta_t spgw_meta,
205 in standard_metadata_t std_meta
206 ) {
207
208 action gtpu_encap() {
Carmelo Cascone14cde402018-01-25 01:57:18 -0800209 gtpu_ipv4.setValid();
210 gtpu_ipv4.version = IP_VERSION_4;
211 gtpu_ipv4.ihl = IPV4_MIN_IHL;
212 gtpu_ipv4.diffserv = 0;
Carmelo Cascone274daef2018-02-14 20:32:49 -0800213 gtpu_ipv4.total_len = spgw_meta.ipv4_len
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800214 + (IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE);
Carmelo Cascone14cde402018-01-25 01:57:18 -0800215 gtpu_ipv4.identification = 0x1513; /* From NGIC */
216 gtpu_ipv4.flags = 0;
217 gtpu_ipv4.frag_offset = 0;
218 gtpu_ipv4.ttl = DEFAULT_IPV4_TTL;
219 gtpu_ipv4.protocol = PROTO_UDP;
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800220 gtpu_ipv4.dst_addr = spgw_meta.s1u_enb_addr;
221 gtpu_ipv4.src_addr = spgw_meta.s1u_sgw_addr;
Carmelo Cascone14cde402018-01-25 01:57:18 -0800222 gtpu_ipv4.hdr_checksum = 0; // Updated later
223
224 gtpu_udp.setValid();
225 gtpu_udp.src_port = UDP_PORT_GTPU;
226 gtpu_udp.dst_port = UDP_PORT_GTPU;
Carmelo Cascone274daef2018-02-14 20:32:49 -0800227 gtpu_udp.len = spgw_meta.ipv4_len
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800228 + (UDP_HDR_SIZE + GTP_HDR_SIZE);
Carmelo Cascone14cde402018-01-25 01:57:18 -0800229 gtpu_udp.checksum = 0; // Updated later
230
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800231 gtpu.setValid();
232 gtpu.version = GTPU_VERSION;
233 gtpu.pt = GTP_PROTOCOL_TYPE_GTP;
234 gtpu.spare = 0;
235 gtpu.ex_flag = 0;
236 gtpu.seq_flag = 0;
237 gtpu.npdu_flag = 0;
238 gtpu.msgtype = GTP_GPDU;
Carmelo Cascone274daef2018-02-14 20:32:49 -0800239 gtpu.msglen = spgw_meta.ipv4_len;
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800240 gtpu.teid = spgw_meta.teid;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800241 }
242
243 apply {
Carmelo Cascone35d9b332018-06-15 16:27:22 +0200244 if (spgw_meta.do_spgw == _TRUE && spgw_meta.direction == DIR_DOWNLINK) {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800245 gtpu_encap();
246 }
247 }
248}
249
250
Carmelo Cascone14cde402018-01-25 01:57:18 -0800251control verify_gtpu_checksum(
252 inout ipv4_t gtpu_ipv4
253 ) {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800254 apply {
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800255 // TODO: re-enable gtpu_ipv4 verification
256 // with the current parser logic, gtpu_ip4 contains values of
257 // the inner header, which is already verified by include/checksum.p4.
258 // We need to modify the parser to copy the outer header somewhere
259 // else, and verify that here.
260
261 // verify_checksum(gtpu_ipv4.isValid(),
262 // {
263 // gtpu_ipv4.version,
264 // gtpu_ipv4.ihl,
265 // gtpu_ipv4.diffserv,
266 // gtpu_ipv4.total_len,
267 // gtpu_ipv4.identification,
268 // gtpu_ipv4.flags,
269 // gtpu_ipv4.frag_offset,
270 // gtpu_ipv4.ttl,
271 // gtpu_ipv4.protocol,
272 // gtpu_ipv4.src_addr,
273 // gtpu_ipv4.dst_addr
274 // },
275 // gtpu_ipv4.hdr_checksum,
276 // HashAlgorithm.csum16
277 // );
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800278 }
279}
280
281
Carmelo Cascone14cde402018-01-25 01:57:18 -0800282control update_gtpu_checksum(
283 inout ipv4_t gtpu_ipv4,
284 inout udp_t gtpu_udp,
285 in gtpu_t gtpu,
286 in ipv4_t ipv4,
287 in udp_t udp
288 ) {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800289 apply {
290 // Compute outer IPv4 checksum.
291 update_checksum(gtpu_ipv4.isValid(),
292 {
293 gtpu_ipv4.version,
294 gtpu_ipv4.ihl,
295 gtpu_ipv4.diffserv,
296 gtpu_ipv4.total_len,
297 gtpu_ipv4.identification,
298 gtpu_ipv4.flags,
299 gtpu_ipv4.frag_offset,
300 gtpu_ipv4.ttl,
301 gtpu_ipv4.protocol,
302 gtpu_ipv4.src_addr,
303 gtpu_ipv4.dst_addr
304 },
305 gtpu_ipv4.hdr_checksum,
306 HashAlgorithm.csum16
307 );
Carmelo Cascone14cde402018-01-25 01:57:18 -0800308
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800309#ifdef WITH_SPGW_UDP_CSUM_UPDATE
Carmelo Cascone14cde402018-01-25 01:57:18 -0800310 // Compute outer UDP checksum.
311 update_checksum_with_payload(gtpu_udp.isValid(),
312 {
313 gtpu_ipv4.src_addr,
314 gtpu_ipv4.dst_addr,
315 8w0,
316 gtpu_ipv4.protocol,
317 gtpu_udp.len,
318 gtpu_udp.src_port,
319 gtpu_udp.dst_port,
320 gtpu_udp.len,
321 gtpu,
322 ipv4,
323 // FIXME: we are assuming only UDP for downlink packets
324 // How to conditionally switch between UDP/TCP/ICMP?
325 udp
326 },
327 gtpu_udp.checksum,
328 HashAlgorithm.csum16
329 );
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800330#endif // WITH_SPGW_UDP_CSUM_UPDATE
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800331 }
332}
333
334#endif