blob: 6eb4c40f25b52c439fd70206172f0f86490b9507 [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(
Carmelo Cascone9b607da2019-05-08 14:03:01 -070043 inout ipv4_t gtpu_ipv4,
44 inout udp_t gtpu_udp,
45 inout gtpu_t gtpu,
46 inout ipv4_t ipv4,
47 inout udp_t udp,
48 inout fabric_metadata_t fabric_meta,
49 inout standard_metadata_t standard_metadata
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080050 ) {
51
52 direct_counter(CounterType.packets_and_bytes) ue_counter;
53
Carmelo Casconeb5324e72018-11-25 02:26:32 -080054 @hidden
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080055 action gtpu_decap() {
56 gtpu_ipv4.setInvalid();
57 gtpu_udp.setInvalid();
58 gtpu.setInvalid();
59 }
60
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080061 action set_dl_sess_info(bit<32> teid,
62 bit<32> s1u_enb_addr,
63 bit<32> s1u_sgw_addr) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -080064 fabric_meta.spgw.teid = teid;
65 fabric_meta.spgw.s1u_enb_addr = s1u_enb_addr;
66 fabric_meta.spgw.s1u_sgw_addr = s1u_sgw_addr;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080067 ue_counter.count();
68 }
69
Carmelo Cascone9b0171b2018-08-14 01:43:57 -070070 table dl_sess_lookup {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080071 key = {
Carmelo Cascone9b0171b2018-08-14 01:43:57 -070072 // UE addr for downlink
Carmelo Casconeb5324e72018-11-25 02:26:32 -080073 ipv4.dst_addr : exact @name("ipv4_dst");
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080074 }
75 actions = {
Carmelo Cascone9b0171b2018-08-14 01:43:57 -070076 set_dl_sess_info();
Carmelo Casconeb5324e72018-11-25 02:26:32 -080077 @defaultonly nop();
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080078 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -080079 const default_action = nop();
Carmelo Cascone9b0171b2018-08-14 01:43:57 -070080 counters = ue_counter;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080081 }
82
83 table s1u_filter_table {
84 key = {
Carmelo Cascone9b0171b2018-08-14 01:43:57 -070085 // IP addresses of the S1U interfaces of this SPGW-U instance (when uplink)
Carmelo Casconeb5324e72018-11-25 02:26:32 -080086 gtpu_ipv4.dst_addr : exact @name("gtp_ipv4_dst");
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080087 }
88 actions = {
Carmelo Casconeb5324e72018-11-25 02:26:32 -080089 nop();
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080090 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -080091 const default_action = nop();
Carmelo Casconeb81f4be2018-01-16 23:24:01 -080092 }
93
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080094#ifdef WITH_SPGW_PCC_GATING
95 action set_sdf_rule_id(sdf_rule_id_t id) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -080096 fabric_meta.spgw.sdf_rule_id = id;
Carmelo Casconeb757dbc2018-01-25 17:53:17 -080097 }
98
99 action set_pcc_rule_id(pcc_rule_id_t id) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800100 fabric_meta.spgw.pcc_rule_id = id;
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800101 }
102
103 action set_pcc_info(pcc_gate_status_t gate_status) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800104 fabric_meta.spgw.pcc_gate_status = gate_status;
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800105 }
106
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800107 table sdf_rule_lookup {
108 key = {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800109 fabric_meta.spgw.direction : exact @name("spgw_direction");
110 ipv4.src_addr : ternary @name("ipv4_src");
111 ipv4.dst_addr : ternary @name("ipv4_dst");
112 ipv4.protocol : ternary @name("ip_proto");
113 fabric_meta.l4_sport : ternary @name("l4_sport");
114 fabric_meta.l4_dport : ternary @name("l4_dport");
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800115 }
116 actions = {
117 set_sdf_rule_id();
118 }
119 const default_action = set_sdf_rule_id(DEFAULT_SDF_RULE_ID);
120 }
121
122 table pcc_rule_lookup {
123 key = {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800124 fabric_meta.spgw.sdf_rule_id : exact @name("sdf_rule_id");
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800125 }
126 actions = {
127 set_pcc_rule_id();
128 }
129 const default_action = set_pcc_rule_id(DEFAULT_PCC_RULE_ID);
130 }
131
132 table pcc_info_lookup {
133 key = {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800134 fabric_meta.spgw.pcc_rule_id : exact @name("pcc_rule_id");
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800135 }
136 actions = {
137 set_pcc_info();
138 }
139 const default_action = set_pcc_info(PCC_GATE_OPEN);
140 }
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800141#endif // WITH_SPGW_PCC_GATING
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800142
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800143 apply {
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800144 if (gtpu.isValid()) {
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700145 // If here, pkt has outer IP dst on
146 // S1U_SGW_PREFIX/S1U_SGW_PREFIX_LEN subnet.
147 // TODO: check also that gtpu.msgtype == GTP_GPDU
148 if (!s1u_filter_table.apply().hit) {
Carmelo Cascone9b607da2019-05-08 14:03:01 -0700149 mark_to_drop(standard_metadata);
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800150 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800151 fabric_meta.spgw.direction = SPGW_DIR_UPLINK;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800152 gtpu_decap();
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700153 } else if (dl_sess_lookup.apply().hit) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800154 fabric_meta.spgw.direction = SPGW_DIR_DOWNLINK;
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700155 } else {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800156 fabric_meta.spgw.direction = SPGW_DIR_UNKNOWN;
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700157 // No SPGW processing needed.
158 return;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800159 }
160
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800161#ifdef WITH_SPGW_PCC_GATING
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800162 // Allow all traffic by default.
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800163 fabric_meta.spgw.pcc_gate_status = PCC_GATE_OPEN;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800164
165 sdf_rule_lookup.apply();
166 pcc_rule_lookup.apply();
167 pcc_info_lookup.apply();
168
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800169 if (fabric_meta.spgw.pcc_gate_status == PCC_GATE_CLOSED) {
Carmelo Cascone9b607da2019-05-08 14:03:01 -0700170 mark_to_drop(standard_metadata);
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800171 }
Carmelo Casconeb757dbc2018-01-25 17:53:17 -0800172#endif // WITH_SPGW_PCC_GATING
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800173
Carmelo Cascone274daef2018-02-14 20:32:49 -0800174 // Don't ask why... we'll need this later.
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800175 fabric_meta.spgw.ipv4_len = ipv4.total_len;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800176 }
177}
178
179
180control spgw_egress(
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700181 in ipv4_t ipv4,
182 inout ipv4_t gtpu_ipv4,
183 inout udp_t gtpu_udp,
184 inout gtpu_t gtpu,
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800185 in fabric_metadata_t fabric_meta,
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700186 in standard_metadata_t std_meta
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800187 ) {
188
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800189 @hidden
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800190 action gtpu_encap() {
Carmelo Cascone14cde402018-01-25 01:57:18 -0800191 gtpu_ipv4.setValid();
192 gtpu_ipv4.version = IP_VERSION_4;
193 gtpu_ipv4.ihl = IPV4_MIN_IHL;
Jonghwan Hyuned478dc2018-08-06 15:35:18 +0900194 gtpu_ipv4.dscp = 0;
195 gtpu_ipv4.ecn = 0;
Carmelo Cascone9b0171b2018-08-14 01:43:57 -0700196 gtpu_ipv4.total_len = ipv4.total_len
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800197 + (IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE);
Carmelo Cascone14cde402018-01-25 01:57:18 -0800198 gtpu_ipv4.identification = 0x1513; /* From NGIC */
199 gtpu_ipv4.flags = 0;
200 gtpu_ipv4.frag_offset = 0;
201 gtpu_ipv4.ttl = DEFAULT_IPV4_TTL;
202 gtpu_ipv4.protocol = PROTO_UDP;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800203 gtpu_ipv4.dst_addr = fabric_meta.spgw.s1u_enb_addr;
204 gtpu_ipv4.src_addr = fabric_meta.spgw.s1u_sgw_addr;
Carmelo Cascone14cde402018-01-25 01:57:18 -0800205 gtpu_ipv4.hdr_checksum = 0; // Updated later
206
207 gtpu_udp.setValid();
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800208 gtpu_udp.sport = UDP_PORT_GTPU;
209 gtpu_udp.dport = UDP_PORT_GTPU;
210 gtpu_udp.len = fabric_meta.spgw.ipv4_len
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800211 + (UDP_HDR_SIZE + GTP_HDR_SIZE);
Carmelo Cascone14cde402018-01-25 01:57:18 -0800212 gtpu_udp.checksum = 0; // Updated later
213
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800214 gtpu.setValid();
215 gtpu.version = GTPU_VERSION;
216 gtpu.pt = GTP_PROTOCOL_TYPE_GTP;
217 gtpu.spare = 0;
218 gtpu.ex_flag = 0;
219 gtpu.seq_flag = 0;
220 gtpu.npdu_flag = 0;
221 gtpu.msgtype = GTP_GPDU;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800222 gtpu.msglen = fabric_meta.spgw.ipv4_len;
223 gtpu.teid = fabric_meta.spgw.teid;
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800224 }
225
226 apply {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800227 if (fabric_meta.spgw.direction == SPGW_DIR_DOWNLINK) {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800228 gtpu_encap();
229 }
230 }
231}
232
233
Carmelo Cascone14cde402018-01-25 01:57:18 -0800234control update_gtpu_checksum(
235 inout ipv4_t gtpu_ipv4,
236 inout udp_t gtpu_udp,
237 in gtpu_t gtpu,
238 in ipv4_t ipv4,
239 in udp_t udp
240 ) {
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800241 apply {
242 // Compute outer IPv4 checksum.
243 update_checksum(gtpu_ipv4.isValid(),
244 {
245 gtpu_ipv4.version,
246 gtpu_ipv4.ihl,
Jonghwan Hyuned478dc2018-08-06 15:35:18 +0900247 gtpu_ipv4.dscp,
248 gtpu_ipv4.ecn,
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800249 gtpu_ipv4.total_len,
250 gtpu_ipv4.identification,
251 gtpu_ipv4.flags,
252 gtpu_ipv4.frag_offset,
253 gtpu_ipv4.ttl,
254 gtpu_ipv4.protocol,
255 gtpu_ipv4.src_addr,
256 gtpu_ipv4.dst_addr
257 },
258 gtpu_ipv4.hdr_checksum,
259 HashAlgorithm.csum16
260 );
Carmelo Cascone14cde402018-01-25 01:57:18 -0800261
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800262#ifdef WITH_SPGW_UDP_CSUM_UPDATE
Carmelo Cascone14cde402018-01-25 01:57:18 -0800263 // Compute outer UDP checksum.
264 update_checksum_with_payload(gtpu_udp.isValid(),
265 {
266 gtpu_ipv4.src_addr,
267 gtpu_ipv4.dst_addr,
268 8w0,
269 gtpu_ipv4.protocol,
270 gtpu_udp.len,
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800271 gtpu_udp.sport,
272 gtpu_udp.dport,
Carmelo Cascone14cde402018-01-25 01:57:18 -0800273 gtpu_udp.len,
274 gtpu,
275 ipv4,
276 // FIXME: we are assuming only UDP for downlink packets
277 // How to conditionally switch between UDP/TCP/ICMP?
278 udp
279 },
280 gtpu_udp.checksum,
281 HashAlgorithm.csum16
282 );
Carmelo Cascone33e85c02018-02-01 13:30:18 -0800283#endif // WITH_SPGW_UDP_CSUM_UPDATE
Carmelo Casconeb81f4be2018-01-16 23:24:01 -0800284 }
285}
286
287#endif