blob: 9ef9e17e75ce83367dcaee3d7fbccbdc405d2710 [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 Morof4d1bc62019-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;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070045 c_control.count(fmeta.bng.line_id);
46 }
47
48 table t_pppoe_cp {
49 key = {
50 hdr.pppoe.code : exact @name("pppoe_code");
51 hdr.pppoe.protocol : ternary @name("pppoe_protocol");
52 }
53 actions = {
54 punt_to_cpu;
55 @defaultonly nop;
56 }
57 size = 16;
58 const default_action = nop;
59 }
60
61 // TABLE: PPPoE termination for IPv4
62 // Check subscriber IPv4 source address, line_id, and pppoe_session_id
63 // (antispoofing), if line is enabled, pop PPPoE and double VLANs.
64
65 @hidden
66 action term_enabled(bit<16> eth_type) {
Daniele Moro693d76f2019-09-24 14:34:07 -070067 hdr.eth_type.value = eth_type;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070068 hdr.pppoe.setInvalid();
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070069 c_terminated.count(fmeta.bng.line_id);
70 }
71
72 action term_disabled() {
73 fmeta.bng.type = BNG_TYPE_INVALID;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070074 mark_to_drop(smeta);
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070075 }
76
77 action term_enabled_v4() {
78 term_enabled(ETHERTYPE_IPV4);
79 }
80
Daniele Moro7c3a0022019-07-12 13:38:34 -070081 // TODO: add match on hdr.ethernet.src_addr for antispoofing
82 // Take into account that MAC src address is modified by the Next control block
83 // when doing routing functionality.
Carmelo Cascone4d8785b2019-05-31 17:11:26 -070084 table t_pppoe_term_v4 {
85 key = {
86 fmeta.bng.line_id : exact @name("line_id");
87 hdr.ipv4.src_addr : exact @name("ipv4_src");
88 hdr.pppoe.session_id : exact @name("pppoe_session_id");
89 }
90 actions = {
91 term_enabled_v4;
92 @defaultonly term_disabled;
93 }
94 size = BNG_MAX_SUBSC_NET;
95 const default_action = term_disabled;
96 }
97
98#ifdef WITH_IPV6
99 action term_enabled_v6() {
100 term_enabled(ETHERTYPE_IPV6);
101 }
102
Daniele Moro7c3a0022019-07-12 13:38:34 -0700103 // TODO: add match on hdr.ethernet.src_addr for antispoofing
104 // Match on unmodified metadata field, taking into account that MAC src address
105 // is modified by the Next control block when doing routing functionality.
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700106 table t_pppoe_term_v6 {
107 key = {
108 fmeta.bng.line_id : exact @name("line_id");
109 hdr.ipv6.src_addr[127:64] : exact @name("ipv6_src_net_id");
110 hdr.pppoe.session_id : exact @name("pppoe_session_id");
111 }
112 actions = {
113 term_enabled_v6;
114 @defaultonly term_disabled;
115 }
116 size = BNG_MAX_SUBSC_NET;
117 const default_action = term_disabled;
118 }
119#endif // WITH_IPV6
120
121 apply {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700122 if(t_pppoe_cp.apply().hit) {
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700123 return;
124 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700125 if (hdr.ipv4.isValid()) {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700126 switch(t_pppoe_term_v4.apply().action_run) {
127 term_disabled: {
128 c_dropped.count(fmeta.bng.line_id);
129 }
Daniele Moroe22b5742019-06-28 15:32:37 -0700130 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700131 }
132#ifdef WITH_IPV6
133 else if (hdr.ipv6.isValid()) {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700134 switch(t_pppoe_term_v6.apply().action_run) {
135 term_disabled: {
136 c_dropped.count(fmeta.bng.line_id);
137 }
138 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700139 }
140#endif // WITH_IPV6
141 }
142}
143
144control bng_ingress_downstream(
145 inout parsed_headers_t hdr,
146 inout fabric_metadata_t fmeta,
147 inout standard_metadata_t smeta) {
148
Daniele Morof4d1bc62019-10-03 16:44:33 -0700149 counter(BNG_MAX_SUBSC, CounterType.bytes) c_line_rx;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700150
151 meter(BNG_MAX_SUBSC, MeterType.bytes) m_besteff;
152 meter(BNG_MAX_SUBSC, MeterType.bytes) m_prio;
153
Daniele Moro7c3a0022019-07-12 13:38:34 -0700154 action set_session(bit<16> pppoe_session_id) {
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700155 fmeta.bng.type = BNG_TYPE_DOWNSTREAM;
Daniele Moro7c3a0022019-07-12 13:38:34 -0700156 fmeta.bng.pppoe_session_id = pppoe_session_id;
157 c_line_rx.count(fmeta.bng.line_id);
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700158 }
159
Daniele Moro7c3a0022019-07-12 13:38:34 -0700160 action drop() {
161 fmeta.bng.type = BNG_TYPE_DOWNSTREAM;
162 c_line_rx.count(fmeta.bng.line_id);
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700163 mark_to_drop(smeta);
164 }
165
Daniele Moro7c3a0022019-07-12 13:38:34 -0700166 table t_line_session_map {
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700167 key = {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700168 fmeta.bng.line_id : exact @name("line_id");
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700169 }
170 actions = {
171 @defaultonly nop;
Daniele Moro7c3a0022019-07-12 13:38:34 -0700172 set_session;
173 drop;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700174 }
Daniele Moro7c3a0022019-07-12 13:38:34 -0700175 size = BNG_MAX_SUBSC;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700176 const default_action = nop;
177 }
178
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700179 // Downstream QoS tables.
180 // Provide coarse metering before prioritazion in the OLT. By default
181 // everything is tagged and metered as best-effort traffic.
182
183 action qos_prio() {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700184 // no-op
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700185 }
186
187 action qos_besteff() {
Daniele Moroe22b5742019-06-28 15:32:37 -0700188 // no-op
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700189 }
190
191 table t_qos_v4 {
192 key = {
193 fmeta.bng.line_id : ternary @name("line_id");
194 hdr.ipv4.src_addr : lpm @name("ipv4_src");
195 hdr.ipv4.dscp : ternary @name("ipv4_dscp");
196 hdr.ipv4.ecn : ternary @name("ipv4_ecn");
197 }
198 actions = {
199 qos_prio;
200 qos_besteff;
201 }
202 size = 256;
203 const default_action = qos_besteff;
204 }
205
206#ifdef WITH_IPV6
207 table t_qos_v6 {
208 key = {
209 fmeta.bng.line_id : ternary @name("line_id");
210 hdr.ipv6.src_addr : lpm @name("ipv6_src");
211 hdr.ipv6.traffic_class : ternary @name("ipv6_traffic_class");
212 }
213 actions = {
214 qos_prio;
215 qos_besteff;
216 }
217 size = 256;
218 const default_action = qos_besteff;
219 }
220#endif // WITH_IPV6
221
222 apply {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700223 // We are not sure the pkt is a BNG downstream one, first we need to
224 // verify the line_id matches the one of a subscriber...
225
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700226 // IPv4
Daniele Moro7c3a0022019-07-12 13:38:34 -0700227 if (t_line_session_map.apply().hit) {
228 // Apply QoS only to subscriber traffic. This makes sense only
229 // if the downstream ports are used to receive IP traffic NOT
230 // destined to subscribers, e.g. to services in the compute
231 // nodes.
232 if (hdr.ipv4.isValid()) {
233 switch (t_qos_v4.apply().action_run) {
234 qos_prio: {
235 m_prio.execute_meter(fmeta.bng.line_id, fmeta.bng.ds_meter_result);
236 }
237 qos_besteff: {
238 m_besteff.execute_meter(fmeta.bng.line_id, fmeta.bng.ds_meter_result);
239 }
Daniele Moroe22b5742019-06-28 15:32:37 -0700240 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700241 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700242#ifdef WITH_IPV6
Daniele Moro7c3a0022019-07-12 13:38:34 -0700243 // IPv6
244 else if (hdr.ipv6.isValid()) {
245 switch (t_qos_v6.apply().action_run) {
246 qos_prio: {
247 m_prio.execute_meter(fmeta.bng.line_id, fmeta.bng.ds_meter_result);
248 }
249 qos_besteff: {
250 m_besteff.execute_meter(fmeta.bng.line_id, fmeta.bng.ds_meter_result);
251 }
Daniele Moroe22b5742019-06-28 15:32:37 -0700252 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700253 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700254#endif // WITH_IPV6
Daniele Moro7c3a0022019-07-12 13:38:34 -0700255 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700256 }
257}
258
259control bng_egress_downstream(
260 inout parsed_headers_t hdr,
261 inout fabric_metadata_t fmeta,
262 inout standard_metadata_t smeta) {
263
Daniele Morof4d1bc62019-10-03 16:44:33 -0700264 counter(BNG_MAX_SUBSC, CounterType.bytes) c_line_tx;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700265
266 @hidden
Daniele Moro7c3a0022019-07-12 13:38:34 -0700267 action encap() {
Daniele Moro693d76f2019-09-24 14:34:07 -0700268 // Here we add PPPoE and modify the Ethernet Type.
269 hdr.eth_type.value = ETHERTYPE_PPPOES;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700270 hdr.pppoe.setValid();
271 hdr.pppoe.version = 4w1;
272 hdr.pppoe.type_id = 4w1;
273 hdr.pppoe.code = 8w0; // 0 means session stage.
Daniele Moro7c3a0022019-07-12 13:38:34 -0700274 hdr.pppoe.session_id = fmeta.bng.pppoe_session_id;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700275 c_line_tx.count(fmeta.bng.line_id);
276 }
277
Daniele Moro7c3a0022019-07-12 13:38:34 -0700278 action encap_v4() {
279 encap();
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700280 hdr.pppoe.length = hdr.ipv4.total_len + 16w2;
281 hdr.pppoe.protocol = PPPOE_PROTOCOL_IP4;
282 }
283
284#ifdef WITH_IPV6
Daniele Moro7c3a0022019-07-12 13:38:34 -0700285 action encap_v6() {
286 encap();
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700287 hdr.pppoe.length = hdr.ipv6.payload_len + 16w42;
288 hdr.pppoe.protocol = PPPOE_PROTOCOL_IP6;
289 }
290#endif // WITH_IPV6
291
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700292 apply {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700293 if (hdr.ipv4.isValid()) {
294 encap_v4();
295 }
296#ifdef WITH_IPV6
297 // IPv6
298 else if (hdr.ipv6.isValid()) {
299 encap_v6();
300 }
301#endif // WITH_IPV6
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700302 }
303}
304
305control bng_ingress(
306 inout parsed_headers_t hdr,
307 inout fabric_metadata_t fmeta,
308 inout standard_metadata_t smeta) {
309
Daniele Moro7c3a0022019-07-12 13:38:34 -0700310 bng_ingress_upstream() upstream;
311 bng_ingress_downstream() downstream;
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700312
Daniele Moro7c3a0022019-07-12 13:38:34 -0700313 vlan_id_t s_tag = 0;
314 vlan_id_t c_tag = 0;
315
316 // 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 = {
325 s_tag : exact @name("s_tag");
326 c_tag : exact @name("c_tag");
327 }
328 actions = {
Daniele Moro7c3a0022019-07-12 13:38:34 -0700329 set_line;
330 }
331 size = BNG_MAX_SUBSC;
Daniele Moro693d76f2019-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 {
337 if(hdr.pppoe.isValid()) {
338 s_tag = hdr.vlan_tag.vlan_id;
339 c_tag = hdr.inner_vlan_tag.vlan_id;
340 } else {
341 // We expect the packet to be downstream,
342 // the tags are set by the next stage in the metadata.
343 s_tag = fmeta.vlan_id;
344 c_tag = fmeta.inner_vlan_id;
345 }
346
347 // First map the double VLAN tags to a line ID
348 // If table miss line ID will be 0.
349 t_line_map.apply();
350
351 if (hdr.pppoe.isValid()) {
352 fmeta.bng.type = BNG_TYPE_UPSTREAM;
353 upstream.apply(hdr, fmeta, smeta);
354 } else {
355 downstream.apply(hdr, fmeta, smeta);
356 }
357 }
Carmelo Cascone4d8785b2019-05-31 17:11:26 -0700358}
359
360control bng_egress(
361 inout parsed_headers_t hdr,
362 inout fabric_metadata_t fmeta,
363 inout standard_metadata_t smeta) {
364
365 bng_egress_downstream() downstream;
366
367 apply {
368 if (fmeta.bng.type == BNG_TYPE_DOWNSTREAM) {
369 downstream.apply(hdr, fmeta, smeta);
370 }
371 }
372}
373
374#endif