blob: 29537bf97284027c50c42ffaa4cb671f12fff2e0 [file] [log] [blame]
Carmelo Cascone4d8785b2019-05-31 17:11:26 -07001/*
2 * Copyright 2019-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 /*
18 * BNG processor implementation. Provides upstream and downstream termination
19 * based on double VLAN tags (s_tag, c_tag) and PPPoE.
20 *
21 * This implementation is based on the P4 Service Edge (p4se) contribution from
22 * Deutsche Telekom:
23 * https://github.com/opencord/p4se
24 */
25
26#ifndef __BNG__
27#define __BNG__
28
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070029#define BNG_SUBSC_IPV6_NET_PREFIX_LEN 64
30
31control bng_ingress_upstream(
32 inout parsed_headers_t hdr,
33 inout fabric_metadata_t fmeta,
34 inout standard_metadata_t smeta) {
35
Daniele Moroce424ca2019-10-03 16:44:33 -070036 counter(BNG_MAX_SUBSC, CounterType.bytes) c_terminated;
37 counter(BNG_MAX_SUBSC, CounterType.bytes) c_dropped;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070038 counter(BNG_MAX_SUBSC, CounterType.packets) c_control;
39
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070040 // TABLE: t_pppoe_cp
41 // Punt to CPU for PPPeE control packets.
42
43 action punt_to_cpu() {
44 smeta.egress_spec = CPU_PORT;
Daniele Moro0cecfe12019-12-13 17:24:33 -080045 // Clean the multicast group, otherwise multicast decision
46 // will override the punting to CPU action
47 smeta.mcast_grp = 0;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070048 c_control.count(fmeta.bng.line_id);
49 }
50
51 table t_pppoe_cp {
52 key = {
53 hdr.pppoe.code : exact @name("pppoe_code");
54 hdr.pppoe.protocol : ternary @name("pppoe_protocol");
55 }
56 actions = {
57 punt_to_cpu;
58 @defaultonly nop;
59 }
60 size = 16;
61 const default_action = nop;
62 }
63
64 // TABLE: PPPoE termination for IPv4
65 // Check subscriber IPv4 source address, line_id, and pppoe_session_id
66 // (antispoofing), if line is enabled, pop PPPoE and double VLANs.
67
68 @hidden
69 action term_enabled(bit<16> eth_type) {
Daniele Moro5a2de712019-09-24 14:34:07 -070070 hdr.eth_type.value = eth_type;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070071 hdr.pppoe.setInvalid();
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070072 c_terminated.count(fmeta.bng.line_id);
73 }
74
75 action term_disabled() {
76 fmeta.bng.type = BNG_TYPE_INVALID;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070077 mark_to_drop(smeta);
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070078 }
79
80 action term_enabled_v4() {
81 term_enabled(ETHERTYPE_IPV4);
82 }
83
Daniele Moro7c3a0022019-07-12 13:38:34 -070084 // TODO: add match on hdr.ethernet.src_addr for antispoofing
85 // Take into account that MAC src address is modified by the Next control block
86 // when doing routing functionality.
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070087 table t_pppoe_term_v4 {
88 key = {
89 fmeta.bng.line_id : exact @name("line_id");
90 hdr.ipv4.src_addr : exact @name("ipv4_src");
91 hdr.pppoe.session_id : exact @name("pppoe_session_id");
92 }
93 actions = {
94 term_enabled_v4;
95 @defaultonly term_disabled;
96 }
97 size = BNG_MAX_SUBSC_NET;
98 const default_action = term_disabled;
99 }
100
101#ifdef WITH_IPV6
102 action term_enabled_v6() {
103 term_enabled(ETHERTYPE_IPV6);
104 }
105
Daniele Moro7c3a0022019-07-12 13:38:34 -0700106 // TODO: add match on hdr.ethernet.src_addr for antispoofing
107 // Match on unmodified metadata field, taking into account that MAC src address
108 // is modified by the Next control block when doing routing functionality.
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700109 table t_pppoe_term_v6 {
110 key = {
111 fmeta.bng.line_id : exact @name("line_id");
112 hdr.ipv6.src_addr[127:64] : exact @name("ipv6_src_net_id");
113 hdr.pppoe.session_id : exact @name("pppoe_session_id");
114 }
115 actions = {
116 term_enabled_v6;
117 @defaultonly term_disabled;
118 }
119 size = BNG_MAX_SUBSC_NET;
120 const default_action = term_disabled;
121 }
122#endif // WITH_IPV6
123
124 apply {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700125 if(t_pppoe_cp.apply().hit) {
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700126 return;
127 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700128 if (hdr.ipv4.isValid()) {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700129 switch(t_pppoe_term_v4.apply().action_run) {
130 term_disabled: {
131 c_dropped.count(fmeta.bng.line_id);
132 }
Daniele Moroe22b5742019-06-28 15:32:37 -0700133 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700134 }
135#ifdef WITH_IPV6
136 else if (hdr.ipv6.isValid()) {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700137 switch(t_pppoe_term_v6.apply().action_run) {
138 term_disabled: {
139 c_dropped.count(fmeta.bng.line_id);
140 }
141 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700142 }
143#endif // WITH_IPV6
144 }
145}
146
147control bng_ingress_downstream(
148 inout parsed_headers_t hdr,
149 inout fabric_metadata_t fmeta,
150 inout standard_metadata_t smeta) {
151
Daniele Moroce424ca2019-10-03 16:44:33 -0700152 counter(BNG_MAX_SUBSC, CounterType.bytes) c_line_rx;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700153
154 meter(BNG_MAX_SUBSC, MeterType.bytes) m_besteff;
155 meter(BNG_MAX_SUBSC, MeterType.bytes) m_prio;
156
Daniele Moro7c3a0022019-07-12 13:38:34 -0700157 action set_session(bit<16> pppoe_session_id) {
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700158 fmeta.bng.type = BNG_TYPE_DOWNSTREAM;
Daniele Moro7c3a0022019-07-12 13:38:34 -0700159 fmeta.bng.pppoe_session_id = pppoe_session_id;
160 c_line_rx.count(fmeta.bng.line_id);
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700161 }
162
Daniele Moro7c3a0022019-07-12 13:38:34 -0700163 action drop() {
164 fmeta.bng.type = BNG_TYPE_DOWNSTREAM;
165 c_line_rx.count(fmeta.bng.line_id);
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700166 mark_to_drop(smeta);
167 }
168
Daniele Moro7c3a0022019-07-12 13:38:34 -0700169 table t_line_session_map {
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700170 key = {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700171 fmeta.bng.line_id : exact @name("line_id");
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700172 }
173 actions = {
174 @defaultonly nop;
Daniele Moro7c3a0022019-07-12 13:38:34 -0700175 set_session;
176 drop;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700177 }
Daniele Moro7c3a0022019-07-12 13:38:34 -0700178 size = BNG_MAX_SUBSC;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700179 const default_action = nop;
180 }
181
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700182 // Downstream QoS tables.
183 // Provide coarse metering before prioritazion in the OLT. By default
184 // everything is tagged and metered as best-effort traffic.
185
186 action qos_prio() {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700187 // no-op
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700188 }
189
190 action qos_besteff() {
Daniele Moroe22b5742019-06-28 15:32:37 -0700191 // no-op
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700192 }
193
194 table t_qos_v4 {
195 key = {
196 fmeta.bng.line_id : ternary @name("line_id");
197 hdr.ipv4.src_addr : lpm @name("ipv4_src");
198 hdr.ipv4.dscp : ternary @name("ipv4_dscp");
199 hdr.ipv4.ecn : ternary @name("ipv4_ecn");
200 }
201 actions = {
202 qos_prio;
203 qos_besteff;
204 }
205 size = 256;
206 const default_action = qos_besteff;
207 }
208
209#ifdef WITH_IPV6
210 table t_qos_v6 {
211 key = {
212 fmeta.bng.line_id : ternary @name("line_id");
213 hdr.ipv6.src_addr : lpm @name("ipv6_src");
214 hdr.ipv6.traffic_class : ternary @name("ipv6_traffic_class");
215 }
216 actions = {
217 qos_prio;
218 qos_besteff;
219 }
220 size = 256;
221 const default_action = qos_besteff;
222 }
223#endif // WITH_IPV6
224
225 apply {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700226 // We are not sure the pkt is a BNG downstream one, first we need to
227 // verify the line_id matches the one of a subscriber...
228
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700229 // IPv4
Daniele Moro7c3a0022019-07-12 13:38:34 -0700230 if (t_line_session_map.apply().hit) {
231 // Apply QoS only to subscriber traffic. This makes sense only
232 // if the downstream ports are used to receive IP traffic NOT
233 // destined to subscribers, e.g. to services in the compute
234 // nodes.
235 if (hdr.ipv4.isValid()) {
236 switch (t_qos_v4.apply().action_run) {
237 qos_prio: {
238 m_prio.execute_meter(fmeta.bng.line_id, fmeta.bng.ds_meter_result);
239 }
240 qos_besteff: {
241 m_besteff.execute_meter(fmeta.bng.line_id, fmeta.bng.ds_meter_result);
242 }
Daniele Moroe22b5742019-06-28 15:32:37 -0700243 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700244 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700245#ifdef WITH_IPV6
Daniele Moro7c3a0022019-07-12 13:38:34 -0700246 // IPv6
247 else if (hdr.ipv6.isValid()) {
248 switch (t_qos_v6.apply().action_run) {
249 qos_prio: {
250 m_prio.execute_meter(fmeta.bng.line_id, fmeta.bng.ds_meter_result);
251 }
252 qos_besteff: {
253 m_besteff.execute_meter(fmeta.bng.line_id, fmeta.bng.ds_meter_result);
254 }
Daniele Moroe22b5742019-06-28 15:32:37 -0700255 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700256 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700257#endif // WITH_IPV6
Daniele Moro7c3a0022019-07-12 13:38:34 -0700258 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700259 }
260}
261
262control bng_egress_downstream(
263 inout parsed_headers_t hdr,
264 inout fabric_metadata_t fmeta,
265 inout standard_metadata_t smeta) {
266
Daniele Moroce424ca2019-10-03 16:44:33 -0700267 counter(BNG_MAX_SUBSC, CounterType.bytes) c_line_tx;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700268
269 @hidden
Daniele Moro7c3a0022019-07-12 13:38:34 -0700270 action encap() {
Daniele Moro5a2de712019-09-24 14:34:07 -0700271 // Here we add PPPoE and modify the Ethernet Type.
272 hdr.eth_type.value = ETHERTYPE_PPPOES;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700273 hdr.pppoe.setValid();
274 hdr.pppoe.version = 4w1;
275 hdr.pppoe.type_id = 4w1;
276 hdr.pppoe.code = 8w0; // 0 means session stage.
Daniele Moro7c3a0022019-07-12 13:38:34 -0700277 hdr.pppoe.session_id = fmeta.bng.pppoe_session_id;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700278 c_line_tx.count(fmeta.bng.line_id);
279 }
280
Daniele Moro7c3a0022019-07-12 13:38:34 -0700281 action encap_v4() {
282 encap();
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700283 hdr.pppoe.length = hdr.ipv4.total_len + 16w2;
284 hdr.pppoe.protocol = PPPOE_PROTOCOL_IP4;
285 }
286
287#ifdef WITH_IPV6
Daniele Moro7c3a0022019-07-12 13:38:34 -0700288 action encap_v6() {
289 encap();
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700290 hdr.pppoe.length = hdr.ipv6.payload_len + 16w42;
291 hdr.pppoe.protocol = PPPOE_PROTOCOL_IP6;
292 }
293#endif // WITH_IPV6
294
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700295 apply {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700296 if (hdr.ipv4.isValid()) {
297 encap_v4();
298 }
299#ifdef WITH_IPV6
300 // IPv6
301 else if (hdr.ipv6.isValid()) {
302 encap_v6();
303 }
304#endif // WITH_IPV6
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700305 }
306}
307
308control bng_ingress(
309 inout parsed_headers_t hdr,
310 inout fabric_metadata_t fmeta,
311 inout standard_metadata_t smeta) {
312
Daniele Moro7c3a0022019-07-12 13:38:34 -0700313 bng_ingress_upstream() upstream;
314 bng_ingress_downstream() downstream;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700315
Daniele Moro7c3a0022019-07-12 13:38:34 -0700316 // TABLE: t_line_map
317 // Map s_tag and c_tag to a line ID to uniquely identify a subscriber
318
319 action set_line(bit<32> line_id) {
320 fmeta.bng.line_id = line_id;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700321 }
Daniele Moro7c3a0022019-07-12 13:38:34 -0700322
323 table t_line_map {
324 key = {
Daniele Morob3d199b2019-11-01 14:01:46 -0700325 fmeta.bng.s_tag : exact @name("s_tag");
326 fmeta.bng.c_tag : exact @name("c_tag");
Daniele Moro7c3a0022019-07-12 13:38:34 -0700327 }
328 actions = {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700329 set_line;
330 }
331 size = BNG_MAX_SUBSC;
Daniele Moro5a2de712019-09-24 14:34:07 -0700332 // By default set the line ID to 0
333 const default_action = set_line(0);
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700334 }
Daniele Moro7c3a0022019-07-12 13:38:34 -0700335
336 apply {
Daniele Morob3d199b2019-11-01 14:01:46 -0700337 // First map the double VLAN tags to a line ID
Daniele Moro7c3a0022019-07-12 13:38:34 -0700338 // If table miss line ID will be 0.
339 t_line_map.apply();
340
341 if (hdr.pppoe.isValid()) {
342 fmeta.bng.type = BNG_TYPE_UPSTREAM;
343 upstream.apply(hdr, fmeta, smeta);
344 } else {
345 downstream.apply(hdr, fmeta, smeta);
346 }
347 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700348}
349
350control bng_egress(
351 inout parsed_headers_t hdr,
352 inout fabric_metadata_t fmeta,
353 inout standard_metadata_t smeta) {
354
355 bng_egress_downstream() downstream;
356
357 apply {
358 if (fmeta.bng.type == BNG_TYPE_DOWNSTREAM) {
359 downstream.apply(hdr, fmeta, smeta);
360 }
361 }
362}
363
364#endif