blob: 5b2cd29b3198e1794d6b0e6c072af6160d5e7878 [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
Carmelo Cascone9b0171b2018-08-14 01:43:57 -070020control spgw_normalizer(
21 in bool is_gtpu_encapped,
22 out ipv4_t gtpu_ipv4,
23 out udp_t gtpu_udp,
24 inout ipv4_t ipv4,
25 inout udp_t udp,
26 in ipv4_t inner_ipv4,
27 in udp_t inner_udp
28 ) {
29 apply {
30 if (! is_gtpu_encapped) return;
31 gtpu_ipv4 = ipv4;
32 ipv4 = inner_ipv4;
33 gtpu_udp = udp;
34 if (inner_udp.isValid()) {
35 udp = inner_udp;
36 } else {
37 udp.setInvalid();
38 }
39 }
40}
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080041
42control spgw_ingress(
43 inout ipv4_t gtpu_ipv4,
44 inout udp_t gtpu_udp,
45 inout gtpu_t gtpu,
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080046 inout ipv4_t ipv4,
47 inout udp_t udp,
48 inout spgw_meta_t spgw_meta
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080049 ) {
50
51 direct_counter(CounterType.packets_and_bytes) ue_counter;
52
53 action gtpu_decap() {
54 gtpu_ipv4.setInvalid();
55 gtpu_udp.setInvalid();
56 gtpu.setInvalid();
57 }
58
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080059 action set_dl_sess_info(bit<32> teid,
60 bit<32> s1u_enb_addr,
61 bit<32> s1u_sgw_addr) {
62 spgw_meta.teid = teid;
63 spgw_meta.s1u_enb_addr = s1u_enb_addr;
64 spgw_meta.s1u_sgw_addr = s1u_sgw_addr;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080065 ue_counter.count();
66 }
67
Carmelo Cascone9b0171b2018-08-14 01:43:57 -070068 table dl_sess_lookup {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080069 key = {
Carmelo Cascone9b0171b2018-08-14 01:43:57 -070070 // UE addr for downlink
71 ipv4.dst_addr : exact;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080072 }
73 actions = {
Carmelo Cascone9b0171b2018-08-14 01:43:57 -070074 set_dl_sess_info();
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080075 }
Carmelo Cascone9b0171b2018-08-14 01:43:57 -070076 counters = ue_counter;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080077 }
78
79 table s1u_filter_table {
80 key = {
Carmelo Cascone9b0171b2018-08-14 01:43:57 -070081 // IP addresses of the S1U interfaces of this SPGW-U instance (when uplink)
82 gtpu_ipv4.dst_addr : exact;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080083 }
84 actions = {
85 NoAction();
86 }
87 }
88
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080089#ifdef WITH_SPGW_PCC_GATING
90 action set_sdf_rule_id(sdf_rule_id_t id) {
91 spgw_meta.sdf_rule_id = id;
92 }
93
94 action set_pcc_rule_id(pcc_rule_id_t id) {
95 spgw_meta.pcc_rule_id = id;
96 }
97
98 action set_pcc_info(pcc_gate_status_t gate_status) {
99 spgw_meta.pcc_gate_status = gate_status;
100 }
101
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800102 table sdf_rule_lookup {
103 key = {
104 spgw_meta.direction : exact;
105 ipv4.src_addr : ternary;
106 ipv4.dst_addr : ternary;
107 ipv4.protocol : ternary;
108 spgw_meta.l4_src_port : ternary;
109 spgw_meta.l4_dst_port : ternary;
110 }
111 actions = {
112 set_sdf_rule_id();
113 }
114 const default_action = set_sdf_rule_id(DEFAULT_SDF_RULE_ID);
115 }
116
117 table pcc_rule_lookup {
118 key = {
119 spgw_meta.sdf_rule_id : exact;
120 }
121 actions = {
122 set_pcc_rule_id();
123 }
124 const default_action = set_pcc_rule_id(DEFAULT_PCC_RULE_ID);
125 }
126
127 table pcc_info_lookup {
128 key = {
129 spgw_meta.pcc_rule_id : exact;
130 }
131 actions = {
132 set_pcc_info();
133 }
134 const default_action = set_pcc_info(PCC_GATE_OPEN);
135 }
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800136#endif // WITH_SPGW_PCC_GATING
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800137
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800138 apply {
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800139 if (gtpu.isValid()) {
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700140 // If here, pkt has outer IP dst on
141 // S1U_SGW_PREFIX/S1U_SGW_PREFIX_LEN subnet.
142 // TODO: check also that gtpu.msgtype == GTP_GPDU
143 if (!s1u_filter_table.apply().hit) {
144 drop_now();
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800145 }
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700146 spgw_meta.direction = SPGW_DIR_UPLINK;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800147 gtpu_decap();
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700148 } else if (dl_sess_lookup.apply().hit) {
149 spgw_meta.direction = SPGW_DIR_DOWNLINK;
150 } else {
151 spgw_meta.direction = SPGW_DIR_UNKNOWN;
152 // No SPGW processing needed.
153 return;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800154 }
155
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800156#ifdef WITH_SPGW_PCC_GATING
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800157 // Allow all traffic by default.
158 spgw_meta.pcc_gate_status = PCC_GATE_OPEN;
159
160 sdf_rule_lookup.apply();
161 pcc_rule_lookup.apply();
162 pcc_info_lookup.apply();
163
164 if (spgw_meta.pcc_gate_status == PCC_GATE_CLOSED) {
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800165 drop_now();
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800166 }
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800167#endif // WITH_SPGW_PCC_GATING
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800168
Carmelo Cascone274daef2018-02-14 20:32:49 -0800169 // Don't ask why... we'll need this later.
170 spgw_meta.ipv4_len = ipv4.total_len;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800171 }
172}
173
174
175control spgw_egress(
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700176 in ipv4_t ipv4,
177 inout ipv4_t gtpu_ipv4,
178 inout udp_t gtpu_udp,
179 inout gtpu_t gtpu,
180 in spgw_meta_t spgw_meta,
181 in standard_metadata_t std_meta
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800182 ) {
183
184 action gtpu_encap() {
Carmelo Cascone14cde402018-01-25 01:57:18 -0800185 gtpu_ipv4.setValid();
186 gtpu_ipv4.version = IP_VERSION_4;
187 gtpu_ipv4.ihl = IPV4_MIN_IHL;
Jonghwan Hyuned478dc2018-08-06 15:35:18 +0900188 gtpu_ipv4.dscp = 0;
189 gtpu_ipv4.ecn = 0;
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700190 gtpu_ipv4.total_len = ipv4.total_len
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800191 + (IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE);
Carmelo Cascone14cde402018-01-25 01:57:18 -0800192 gtpu_ipv4.identification = 0x1513; /* From NGIC */
193 gtpu_ipv4.flags = 0;
194 gtpu_ipv4.frag_offset = 0;
195 gtpu_ipv4.ttl = DEFAULT_IPV4_TTL;
196 gtpu_ipv4.protocol = PROTO_UDP;
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800197 gtpu_ipv4.dst_addr = spgw_meta.s1u_enb_addr;
198 gtpu_ipv4.src_addr = spgw_meta.s1u_sgw_addr;
Carmelo Cascone14cde402018-01-25 01:57:18 -0800199 gtpu_ipv4.hdr_checksum = 0; // Updated later
200
201 gtpu_udp.setValid();
202 gtpu_udp.src_port = UDP_PORT_GTPU;
203 gtpu_udp.dst_port = UDP_PORT_GTPU;
Carmelo Cascone274daef2018-02-14 20:32:49 -0800204 gtpu_udp.len = spgw_meta.ipv4_len
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800205 + (UDP_HDR_SIZE + GTP_HDR_SIZE);
Carmelo Cascone14cde402018-01-25 01:57:18 -0800206 gtpu_udp.checksum = 0; // Updated later
207
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800208 gtpu.setValid();
209 gtpu.version = GTPU_VERSION;
210 gtpu.pt = GTP_PROTOCOL_TYPE_GTP;
211 gtpu.spare = 0;
212 gtpu.ex_flag = 0;
213 gtpu.seq_flag = 0;
214 gtpu.npdu_flag = 0;
215 gtpu.msgtype = GTP_GPDU;
Carmelo Cascone274daef2018-02-14 20:32:49 -0800216 gtpu.msglen = spgw_meta.ipv4_len;
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800217 gtpu.teid = spgw_meta.teid;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800218 }
219
220 apply {
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700221 if (spgw_meta.direction == SPGW_DIR_DOWNLINK) {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800222 gtpu_encap();
223 }
224 }
225}
226
227
Carmelo Cascone14cde402018-01-25 01:57:18 -0800228control update_gtpu_checksum(
229 inout ipv4_t gtpu_ipv4,
230 inout udp_t gtpu_udp,
231 in gtpu_t gtpu,
232 in ipv4_t ipv4,
233 in udp_t udp
234 ) {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800235 apply {
236 // Compute outer IPv4 checksum.
237 update_checksum(gtpu_ipv4.isValid(),
238 {
239 gtpu_ipv4.version,
240 gtpu_ipv4.ihl,
Jonghwan Hyuned478dc2018-08-06 15:35:18 +0900241 gtpu_ipv4.dscp,
242 gtpu_ipv4.ecn,
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800243 gtpu_ipv4.total_len,
244 gtpu_ipv4.identification,
245 gtpu_ipv4.flags,
246 gtpu_ipv4.frag_offset,
247 gtpu_ipv4.ttl,
248 gtpu_ipv4.protocol,
249 gtpu_ipv4.src_addr,
250 gtpu_ipv4.dst_addr
251 },
252 gtpu_ipv4.hdr_checksum,
253 HashAlgorithm.csum16
254 );
Carmelo Cascone14cde402018-01-25 01:57:18 -0800255
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800256#ifdef WITH_SPGW_UDP_CSUM_UPDATE
Carmelo Cascone14cde402018-01-25 01:57:18 -0800257 // Compute outer UDP checksum.
258 update_checksum_with_payload(gtpu_udp.isValid(),
259 {
260 gtpu_ipv4.src_addr,
261 gtpu_ipv4.dst_addr,
262 8w0,
263 gtpu_ipv4.protocol,
264 gtpu_udp.len,
265 gtpu_udp.src_port,
266 gtpu_udp.dst_port,
267 gtpu_udp.len,
268 gtpu,
269 ipv4,
270 // FIXME: we are assuming only UDP for downlink packets
271 // How to conditionally switch between UDP/TCP/ICMP?
272 udp
273 },
274 gtpu_udp.checksum,
275 HashAlgorithm.csum16
276 );
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800277#endif // WITH_SPGW_UDP_CSUM_UPDATE
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800278 }
279}
280
281#endif