blob: cafa502b818afe02f75a65e58fef38e0c77bec8e [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
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080032 action drop_now() {
33 mark_to_drop();
34 exit;
35 }
36
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080037 action gtpu_decap() {
38 gtpu_ipv4.setInvalid();
39 gtpu_udp.setInvalid();
40 gtpu.setInvalid();
41 }
42
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080043 action set_dl_sess_info(bit<32> teid,
44 bit<32> s1u_enb_addr,
45 bit<32> s1u_sgw_addr) {
46 spgw_meta.teid = teid;
47 spgw_meta.s1u_enb_addr = s1u_enb_addr;
48 spgw_meta.s1u_sgw_addr = s1u_sgw_addr;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080049 }
50
51 action update_ue_cdr() {
52 ue_counter.count();
53 }
54
55 table ue_filter_table {
56 key = {
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080057 // IP prefixes of the UEs managed by this switch (when downlink)
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080058 ipv4.dst_addr : lpm;
59 }
60 actions = {
61 NoAction();
62 }
63 }
64
65 table s1u_filter_table {
66 key = {
67 // IP addresses of the S1U interfaces embodied by this switch.
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080068 spgw_meta.s1u_sgw_addr : exact;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080069 }
70 actions = {
71 NoAction();
72 }
73 }
74
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080075#ifdef WITH_SPGW_PCC_GATING
76 action set_sdf_rule_id(sdf_rule_id_t id) {
77 spgw_meta.sdf_rule_id = id;
78 }
79
80 action set_pcc_rule_id(pcc_rule_id_t id) {
81 spgw_meta.pcc_rule_id = id;
82 }
83
84 action set_pcc_info(pcc_gate_status_t gate_status) {
85 spgw_meta.pcc_gate_status = gate_status;
86 }
87
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080088 table sdf_rule_lookup {
89 key = {
90 spgw_meta.direction : exact;
91 ipv4.src_addr : ternary;
92 ipv4.dst_addr : ternary;
93 ipv4.protocol : ternary;
94 spgw_meta.l4_src_port : ternary;
95 spgw_meta.l4_dst_port : ternary;
96 }
97 actions = {
98 set_sdf_rule_id();
99 }
100 const default_action = set_sdf_rule_id(DEFAULT_SDF_RULE_ID);
101 }
102
103 table pcc_rule_lookup {
104 key = {
105 spgw_meta.sdf_rule_id : exact;
106 }
107 actions = {
108 set_pcc_rule_id();
109 }
110 const default_action = set_pcc_rule_id(DEFAULT_PCC_RULE_ID);
111 }
112
113 table pcc_info_lookup {
114 key = {
115 spgw_meta.pcc_rule_id : exact;
116 }
117 actions = {
118 set_pcc_info();
119 }
120 const default_action = set_pcc_info(PCC_GATE_OPEN);
121 }
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800122#endif // WITH_SPGW_PCC_GATING
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800123
124 table dl_sess_lookup {
125 key = {
126 // UE addr for downlink
127 ipv4.dst_addr : exact;
128 }
129 actions = {
130 set_dl_sess_info();
131 }
132 }
133
134 table ue_cdr_table {
135 key = {
136 // UE addr for downlink
137 ipv4.dst_addr : exact;
138 }
139 actions = {
140 update_ue_cdr();
141 }
142 counters = ue_counter;
143 }
144
145 apply {
Carmelo Cascone04888222018-03-19 22:18:12 -0700146 spgw_meta.do_spgw = 1w0;
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800147 if (gtpu.isValid()) {
148 // If here, the parsed ipv4 header is the outer GTP one, but
149 // fabric needs to forward on the inner one, i.e. this.
150 // We store the outer values we need in the metadata, then replace
151 // the ipv4 header extracted before with this one.
152 spgw_meta.s1u_enb_addr = ipv4.src_addr;
153 spgw_meta.s1u_sgw_addr = ipv4.dst_addr;
154 ipv4 = gtpu_ipv4;
155 udp = gtpu_udp;
156
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800157 if (s1u_filter_table.apply().hit) {
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800158 // TODO: check also that gtpu.msgtype == GTP_GPDU
Carmelo Cascone04888222018-03-19 22:18:12 -0700159 spgw_meta.do_spgw = 1w1;
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800160 spgw_meta.direction = DIR_UPLINK;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800161 }
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800162 } else if (ue_filter_table.apply().hit) {
Carmelo Cascone04888222018-03-19 22:18:12 -0700163 spgw_meta.do_spgw = 1w1;
Carmelo Cascone14cde402018-01-25 01:57:18 -0800164 spgw_meta.direction = DIR_DOWNLINK;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800165 }
166
Carmelo Cascone04888222018-03-19 22:18:12 -0700167 if (spgw_meta.do_spgw == 1w0) {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800168 // Exit this control block.
169 return;
170 }
171
172 if (spgw_meta.direction == DIR_UPLINK) {
173 gtpu_decap();
174 }
175
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800176#ifdef WITH_SPGW_PCC_GATING
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800177 // Allow all traffic by default.
178 spgw_meta.pcc_gate_status = PCC_GATE_OPEN;
179
180 sdf_rule_lookup.apply();
181 pcc_rule_lookup.apply();
182 pcc_info_lookup.apply();
183
184 if (spgw_meta.pcc_gate_status == PCC_GATE_CLOSED) {
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800185 drop_now();
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800186 }
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800187#endif // WITH_SPGW_PCC_GATING
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800188
189 if (spgw_meta.direction == DIR_DOWNLINK) {
190 if (!dl_sess_lookup.apply().hit) {
191 // We have no other choice than drop, as we miss the session
192 // info necessary to properly GTPU encap the packet.
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800193 drop_now();
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800194 }
195 ue_cdr_table.apply();
196 }
197 }
198}
199
200
201control spgw_egress(
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800202 in ipv4_t ipv4,
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800203 out ipv4_t gtpu_ipv4,
204 out udp_t gtpu_udp,
205 out gtpu_t gtpu,
206 in spgw_meta_t spgw_meta,
207 in standard_metadata_t std_meta
208 ) {
209
210 action gtpu_encap() {
Carmelo Cascone14cde402018-01-25 01:57:18 -0800211 gtpu_ipv4.setValid();
212 gtpu_ipv4.version = IP_VERSION_4;
213 gtpu_ipv4.ihl = IPV4_MIN_IHL;
Carmelo Cascone04888222018-03-19 22:18:12 -0700214 gtpu_ipv4.dscp = 0;
215 gtpu_ipv4.ecn = 0;
Carmelo Cascone103c0a02018-03-24 00:36:06 -0700216 gtpu_ipv4.total_len = ipv4.total_len
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800217 + (IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE);
Carmelo Cascone14cde402018-01-25 01:57:18 -0800218 gtpu_ipv4.identification = 0x1513; /* From NGIC */
219 gtpu_ipv4.flags = 0;
220 gtpu_ipv4.frag_offset = 0;
221 gtpu_ipv4.ttl = DEFAULT_IPV4_TTL;
222 gtpu_ipv4.protocol = PROTO_UDP;
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800223 gtpu_ipv4.dst_addr = spgw_meta.s1u_enb_addr;
224 gtpu_ipv4.src_addr = spgw_meta.s1u_sgw_addr;
Carmelo Cascone14cde402018-01-25 01:57:18 -0800225 gtpu_ipv4.hdr_checksum = 0; // Updated later
226
227 gtpu_udp.setValid();
228 gtpu_udp.src_port = UDP_PORT_GTPU;
229 gtpu_udp.dst_port = UDP_PORT_GTPU;
Carmelo Cascone103c0a02018-03-24 00:36:06 -0700230 gtpu_udp.len = ipv4.total_len
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800231 + (UDP_HDR_SIZE + GTP_HDR_SIZE);
Carmelo Cascone14cde402018-01-25 01:57:18 -0800232 gtpu_udp.checksum = 0; // Updated later
233
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800234 gtpu.setValid();
235 gtpu.version = GTPU_VERSION;
236 gtpu.pt = GTP_PROTOCOL_TYPE_GTP;
237 gtpu.spare = 0;
238 gtpu.ex_flag = 0;
239 gtpu.seq_flag = 0;
240 gtpu.npdu_flag = 0;
241 gtpu.msgtype = GTP_GPDU;
Carmelo Cascone103c0a02018-03-24 00:36:06 -0700242 gtpu.msglen = ipv4.total_len;
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800243 gtpu.teid = spgw_meta.teid;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800244 }
245
246 apply {
Carmelo Cascone04888222018-03-19 22:18:12 -0700247 if (spgw_meta.do_spgw == 1w1 && spgw_meta.direction == DIR_DOWNLINK) {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800248 gtpu_encap();
249 }
250 }
251}
252
253
Carmelo Cascone14cde402018-01-25 01:57:18 -0800254control verify_gtpu_checksum(
255 inout ipv4_t gtpu_ipv4
256 ) {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800257 apply {
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800258 // TODO: re-enable gtpu_ipv4 verification
259 // with the current parser logic, gtpu_ip4 contains values of
260 // the inner header, which is already verified by include/checksum.p4.
261 // We need to modify the parser to copy the outer header somewhere
262 // else, and verify that here.
263
264 // verify_checksum(gtpu_ipv4.isValid(),
265 // {
266 // gtpu_ipv4.version,
267 // gtpu_ipv4.ihl,
268 // gtpu_ipv4.diffserv,
269 // gtpu_ipv4.total_len,
270 // gtpu_ipv4.identification,
271 // gtpu_ipv4.flags,
272 // gtpu_ipv4.frag_offset,
273 // gtpu_ipv4.ttl,
274 // gtpu_ipv4.protocol,
275 // gtpu_ipv4.src_addr,
276 // gtpu_ipv4.dst_addr
277 // },
278 // gtpu_ipv4.hdr_checksum,
279 // HashAlgorithm.csum16
280 // );
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800281 }
282}
283
284
Carmelo Cascone14cde402018-01-25 01:57:18 -0800285control update_gtpu_checksum(
286 inout ipv4_t gtpu_ipv4,
287 inout udp_t gtpu_udp,
288 in gtpu_t gtpu,
289 in ipv4_t ipv4,
290 in udp_t udp
291 ) {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800292 apply {
293 // Compute outer IPv4 checksum.
294 update_checksum(gtpu_ipv4.isValid(),
295 {
296 gtpu_ipv4.version,
297 gtpu_ipv4.ihl,
Carmelo Cascone04888222018-03-19 22:18:12 -0700298 gtpu_ipv4.dscp,
299 gtpu_ipv4.ecn,
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800300 gtpu_ipv4.total_len,
301 gtpu_ipv4.identification,
302 gtpu_ipv4.flags,
303 gtpu_ipv4.frag_offset,
304 gtpu_ipv4.ttl,
305 gtpu_ipv4.protocol,
306 gtpu_ipv4.src_addr,
307 gtpu_ipv4.dst_addr
308 },
309 gtpu_ipv4.hdr_checksum,
310 HashAlgorithm.csum16
311 );
Carmelo Cascone14cde402018-01-25 01:57:18 -0800312
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800313#ifdef WITH_SPGW_UDP_CSUM_UPDATE
Carmelo Cascone14cde402018-01-25 01:57:18 -0800314 // Compute outer UDP checksum.
315 update_checksum_with_payload(gtpu_udp.isValid(),
316 {
317 gtpu_ipv4.src_addr,
318 gtpu_ipv4.dst_addr,
319 8w0,
320 gtpu_ipv4.protocol,
321 gtpu_udp.len,
322 gtpu_udp.src_port,
323 gtpu_udp.dst_port,
324 gtpu_udp.len,
325 gtpu,
326 ipv4,
327 // FIXME: we are assuming only UDP for downlink packets
328 // How to conditionally switch between UDP/TCP/ICMP?
329 udp
330 },
331 gtpu_udp.checksum,
332 HashAlgorithm.csum16
333 );
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800334#endif // WITH_SPGW_UDP_CSUM_UPDATE
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800335 }
336}
337
338#endif