blob: ce39acb0a600fbe2dd278dfce01cb71a80de16f7 [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,
25 inout spgw_meta_t spgw_meta,
26 in ipv4_t ipv4
27 ) {
28
29 direct_counter(CounterType.packets_and_bytes) ue_counter;
30
31 action gtpu_decap() {
32 gtpu_ipv4.setInvalid();
33 gtpu_udp.setInvalid();
34 gtpu.setInvalid();
35 }
36
37 action set_sdf_rule_id(sdf_rule_id_t id) {
38 spgw_meta.sdf_rule_id = id;
39 }
40
41 action set_pcc_rule_id(pcc_rule_id_t id) {
42 spgw_meta.pcc_rule_id = id;
43 }
44
45 action set_pcc_info(pcc_gate_status_t gate_status) {
46 spgw_meta.pcc_gate_status = gate_status;
47 }
48
49 action set_dl_sess_info(bit<32> dl_sess_teid,
50 bit<32> dl_sess_enb_addr,
51 bit<32> dl_sess_s1u_addr) {
52 spgw_meta.dl_sess_teid = dl_sess_teid;
53 spgw_meta.dl_sess_enb_addr = dl_sess_enb_addr;
54 spgw_meta.dl_sess_s1u_addr = dl_sess_s1u_addr;
55 }
56
57 action update_ue_cdr() {
58 ue_counter.count();
59 }
60
61 table ue_filter_table {
62 key = {
63 // IP prefixes of the UEs managed by this switch.
64 ipv4.dst_addr : lpm;
65 }
66 actions = {
67 NoAction();
68 }
69 }
70
71 table s1u_filter_table {
72 key = {
73 // IP addresses of the S1U interfaces embodied by this switch.
74 gtpu_ipv4.dst_addr : exact;
75 }
76 actions = {
77 NoAction();
78 }
79 }
80
81 table sdf_rule_lookup {
82 key = {
83 spgw_meta.direction : exact;
84 ipv4.src_addr : ternary;
85 ipv4.dst_addr : ternary;
86 ipv4.protocol : ternary;
87 spgw_meta.l4_src_port : ternary;
88 spgw_meta.l4_dst_port : ternary;
89 }
90 actions = {
91 set_sdf_rule_id();
92 }
93 const default_action = set_sdf_rule_id(DEFAULT_SDF_RULE_ID);
94 }
95
96 table pcc_rule_lookup {
97 key = {
98 spgw_meta.sdf_rule_id : exact;
99 }
100 actions = {
101 set_pcc_rule_id();
102 }
103 const default_action = set_pcc_rule_id(DEFAULT_PCC_RULE_ID);
104 }
105
106 table pcc_info_lookup {
107 key = {
108 spgw_meta.pcc_rule_id : exact;
109 }
110 actions = {
111 set_pcc_info();
112 }
113 const default_action = set_pcc_info(PCC_GATE_OPEN);
114 }
115
116 table dl_sess_lookup {
117 key = {
118 // UE addr for downlink
119 ipv4.dst_addr : exact;
120 }
121 actions = {
122 set_dl_sess_info();
123 }
124 }
125
126 table ue_cdr_table {
127 key = {
128 // UE addr for downlink
129 ipv4.dst_addr : exact;
130 }
131 actions = {
132 update_ue_cdr();
133 }
134 counters = ue_counter;
135 }
136
137 apply {
138 // Admit only packets to known UE/S1U addresses, if so sets direction,
139 // otherwise skip SPGW processing.
140 spgw_meta.do_spgw = false;
141 if (gtpu.isValid() && gtpu.msgtype == GTP_GPDU) {
142 spgw_meta.direction = DIR_UPLINK;
143 if (s1u_filter_table.apply().hit) {
144 spgw_meta.do_spgw = true;
145 }
146 } else {
147 if (ue_filter_table.apply().hit) {
148 spgw_meta.do_spgw = true;
149 }
150 }
151
152 if (!spgw_meta.do_spgw) {
153 // Exit this control block.
154 return;
155 }
156
157 if (spgw_meta.direction == DIR_UPLINK) {
158 gtpu_decap();
159 }
160
161 // Allow all traffic by default.
162 spgw_meta.pcc_gate_status = PCC_GATE_OPEN;
163
164 sdf_rule_lookup.apply();
165 pcc_rule_lookup.apply();
166 pcc_info_lookup.apply();
167
168 if (spgw_meta.pcc_gate_status == PCC_GATE_CLOSED) {
169 mark_to_drop();
170 exit;
171 }
172
173 if (spgw_meta.direction == DIR_DOWNLINK) {
174 if (!dl_sess_lookup.apply().hit) {
175 // We have no other choice than drop, as we miss the session
176 // info necessary to properly GTPU encap the packet.
177 mark_to_drop();
178 exit;
179 }
180 ue_cdr_table.apply();
181 }
182 }
183}
184
185
186control spgw_egress(
187 out ipv4_t gtpu_ipv4,
188 out udp_t gtpu_udp,
189 out gtpu_t gtpu,
190 in spgw_meta_t spgw_meta,
191 in standard_metadata_t std_meta
192 ) {
193
194 action gtpu_encap() {
195 // GTPU
196 gtpu.setValid();
197 gtpu.version = GTPU_VERSION;
198 gtpu.pt = GTP_PROTOCOL_TYPE_GTP;
199 gtpu.spare = 0;
200 gtpu.ex_flag = 0;
201 gtpu.seq_flag = 0;
202 gtpu.npdu_flag = 0;
203 gtpu.msgtype = GTP_GPDU;
204 gtpu.msglen = (bit<16>) (std_meta.packet_length - ETH_HDR_SIZE);
205 gtpu.teid = spgw_meta.dl_sess_teid;
206 // Outer IPv4
207 gtpu_ipv4.setValid();
208 gtpu_ipv4.version = IP_VERSION_4;
209 gtpu_ipv4.ihl = IPV4_MIN_IHL;
210 gtpu_ipv4.diffserv = 0;
211 gtpu_ipv4.total_len = (bit<16>) (std_meta.packet_length
212 - ETH_HDR_SIZE + IPV4_HDR_SIZE + UDP_HDR_SIZE);
213 gtpu_ipv4.identification = 0x1513; /* From NGIC */
214 gtpu_ipv4.flags = 0;
215 gtpu_ipv4.frag_offset = 0;
216 gtpu_ipv4.ttl = DEFAULT_IPV4_TTL;
217 gtpu_ipv4.protocol = PROTO_UDP;
218 gtpu_ipv4.dst_addr = spgw_meta.dl_sess_enb_addr;
219 gtpu_ipv4.src_addr = spgw_meta.dl_sess_s1u_addr;
220 gtpu_ipv4.hdr_checksum = 0; /* Updated later */
221 // Outer UDP
222 gtpu_udp.setValid();
223 gtpu_udp.src_port = UDP_PORT_GTPU;
224 gtpu_udp.dst_port = UDP_PORT_GTPU;
225 gtpu_udp.len = (bit<16>) (std_meta.packet_length
226 - ETH_HDR_SIZE + UDP_HDR_SIZE);
227 gtpu_udp.checksum = 0; /* Ignore, won't be updated */
228 }
229
230 apply {
231 if (spgw_meta.do_spgw && spgw_meta.direction == DIR_DOWNLINK) {
232 gtpu_encap();
233 }
234 }
235}
236
237
238control verify_gtpu_checksum(inout ipv4_t gtpu_ipv4) {
239 apply {
240 verify_checksum(gtpu_ipv4.isValid(),
241 {
242 gtpu_ipv4.version,
243 gtpu_ipv4.ihl,
244 gtpu_ipv4.diffserv,
245 gtpu_ipv4.total_len,
246 gtpu_ipv4.identification,
247 gtpu_ipv4.flags,
248 gtpu_ipv4.frag_offset,
249 gtpu_ipv4.ttl,
250 gtpu_ipv4.protocol,
251 gtpu_ipv4.src_addr,
252 gtpu_ipv4.dst_addr
253 },
254 gtpu_ipv4.hdr_checksum,
255 HashAlgorithm.csum16
256 );
257 }
258}
259
260
261control update_gtpu_checksum(inout ipv4_t gtpu_ipv4) {
262 apply {
263 // Compute outer IPv4 checksum.
264 update_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 );
281 }
282}
283
284#endif