blob: 27d33af7cb7b29364a9904b14ecd1b78df12941e [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/******************************************************************************
2 *
3 * <:copyright-BRCM:2016:DUAL/GPL:standard
4 *
5 * Copyright (c) 2016 Broadcom
6 * All Rights Reserved
7 *
8 * Unless you and Broadcom execute a separate written software license
9 * agreement governing use of this software, this software is licensed
10 * to you under the terms of the GNU General Public License version 2
11 * (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
12 * with the following added to such license:
13 *
14 * As a special exception, the copyright holders of this software give
15 * you permission to link this software with independent modules, and
16 * to copy and distribute the resulting executable under terms of your
17 * choice, provided that you also meet, for each linked independent
18 * module, the terms and conditions of the license of that module.
19 * An independent module is a module which is not derived from this
20 * software. The special exception does not apply to any modifications
21 * of the software.
22 *
23 * Not withstanding the above, under no circumstances may you combine
24 * this software in any way with any other Broadcom software provided
25 * under a license other than the GPL, without Broadcom's express prior
26 * written consent.
27 *
28 * :>
29 *
30 *****************************************************************************/
31
32/**
33 * @file bal_esw_flow.c
34 * @brief BAL Switch util functions that handle flow requests
35 * @addtogroup sw_util
36 */
37
38 /*@{*/
39#include <bal_common.h>
40#include <bcm_dev_log.h>
41#include <bal_msg.h>
42#include "bal_switch_flow.h"
43#include "flow_fsm.h"
44#include "bcmos_errno.h"
45#include "bal_switch_util.h"
46
47#ifndef TEST_SW_UTIL_LOOPBACK
48#include <bcm/types.h>
49#include <sal/core/libc.h>
50#ifndef sal_memset
51#define sal_memset memset
52#endif
53#include <bcm/port.h>
54#include <bcm/vlan.h>
55#include <bcm/field.h>
56#include <bcm/error.h>
57#include <sal/core/libc.h>
58
59#include "bal_switch_acc_term.h"
60#include "bal_esw_flow.h"
61/**
62 * @brief The acl add function add an Access Control Rule in the switch VCAP/ICAP/ECAP
63 * to perform action based on flow classifier
64 *
65 * @param unit the switch unit this rule is to be added
66 * @param p_flow a pointer to the flow definition the created rule will be based on
67 * @return error code
68 */
69static bcm_field_group_t esw_group_id = 0;
70/* add an ingress ACL rule */
71static bcmos_errno bal_swapp_esw_acl_add(int unit, bcmbal_flow_cfg *p_flow)
72{
73 uint32_t ret, j;
74 uint32_t nni_phy;
75 int vid;
76 bcm_field_qset_t qset;
77 bcm_field_entry_t eid;
78 bcm_mac_t bcast_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
79 bcm_mac_t dst_mask = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
80
81 do
82 {
83 vid = p_flow->data.classifier.o_vid;
84
85 /* VCAP - bcmFieldQualifyStageLookup, ICAP - bcmFieldQualifyStageIngress, ECAP - bcmFieldQualifyStageEgress */
86 /* The KT2 resources allow only limit number of qset - indexed by esw_group_id, create qset when necessary */
87 if (0 == esw_group_id)
88 {
89 BCM_FIELD_QSET_INIT(qset);
90 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyStageLookup);
91 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyOuterVlan);
92 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyInPort);
93 BCM_FIELD_QSET_ADD(qset, bcmFieldQualifyDstMac);
94 ret = bcm_field_group_create(unit, qset, BCM_FIELD_GROUP_PRIO_ANY, &esw_group_id);
95 if (ret != BCM_E_NONE)
96 {
97 BCM_LOG(ERROR, log_id_sw_util,
98 " flow fail to create field - %d\n", ret );
99 break;
100 }
101 }
102
103 /* if action is to drop broadcast, add an ACL in nni VCAP to drop it */
104 if ( p_flow->data.action.cmds_bitmask & BCMBAL_ACTION_CMD_ID_DISCARD_DS_BCAST)
105 {
106 /* loop through all nni ports */
107 for(j=0; -1 != (nni_phy = bal_bcm_net_inf_pbm_get(j)); j++)
108 {
109 if ( bal_bcm_net_inf_dev_get(j) != unit)
110 {
111 continue;
112 }
113
114 ret = bcm_field_entry_create(unit, esw_group_id, &eid);
115 if (ret != BCM_E_NONE)
116 {
117 BCM_LOG(ERROR, log_id_sw_util,
118 " flow fail to create field entry for port %d - ret = %d\n", nni_phy, ret );
119 break;
120 }
121
122 ret = bcm_field_qualify_DstMac(unit, eid, bcast_mac, dst_mask);
123 if (ret != BCM_E_NONE)
124 {
125 BCM_LOG(ERROR, log_id_sw_util,
126 " flow fail to set field dst mac qualifier %d - ret = %d\n", nni_phy, ret );
127 break;
128 }
129
130 ret = bcm_field_qualify_OuterVlanId(unit, eid, vid, 0xffff);
131 if (ret != BCM_E_NONE)
132 {
133 BCM_LOG(ERROR, log_id_sw_util,
134 " flow fail to set field outer vlan qualifier %d - ret = %d\n", nni_phy, ret );
135 break;
136 }
137 ret = bcm_field_action_add(unit, eid, bcmFieldActionDrop, 0, 0);
138 if (ret != BCM_E_NONE)
139 {
140 BCM_LOG(ERROR, log_id_sw_util,
141 " flow fail to add action to the field entry %d - ret = %d\n", nni_phy, ret );
142 break;
143 }
144
145 ret = bcm_field_entry_install(unit, eid);
146 if (ret != BCM_E_NONE)
147 {
148 BCM_LOG(ERROR, log_id_sw_util,
149 " flow fail to install field entry %d - ret = %d\n", nni_phy, ret );
150 break;
151 }
152 } /* for loop */
153 } /* if drop bcast */
154 } while(0);
155
156
157 if (ret != BCM_E_NONE)
158 {
159 return BCM_ERR_INTERNAL;
160 }
161
162 return BCM_ERR_OK;
163}
164
165/**
166 * @brief The ingress vlan translation function program switch to
167 * translate packet vlan attributes before the switch vaidate the
168 * vlan membership of the packets
169 * @param unit the switch unit this translation is perfromed
170 * @param p_flow a pointer to the flow that contains translation action
171 * @return error code
172 */
173static bcmos_errno bal_swapp_esw_ivlanx(int unit, bcmbal_flow_cfg *p_flow)
174{
175 bcmos_errno ret = BCM_ERR_OK;
176 bcm_gport_t pon_gport;
177 uint32_t pon_phy_pbm;
178 int bcm_rc;
179
180 /* find out which PON this action is to be performed */
181 /* map pon logical port to physical port */
182 pon_phy_pbm = bal_bcm_pon_inf_pbm_get(p_flow->data.access_int_id);
183 /* create local gport based on pon physical port number */
184 BCM_GPORT_LOCAL_SET(pon_gport, pon_phy_pbm);
185
186 do
187 {
188 /* For TR-156 1:1 uptream single tagged packets,
189 S-tag add acton is performed in the INGRESS vlan translator.
190 */
191 if (BCMBAL_FLOW_TYPE_UPSTREAM == p_flow->key.flow_type)
192 {
193 if ( p_flow->data.action.cmds_bitmask & BCMBAL_ACTION_CMD_ID_ADD_OUTER_TAG )
194 {
195 uint32_t u_ovid, u_ivid;
196 bcm_vlan_action_set_t u_action;
197 bcm_vlan_action_set_t_init(&u_action);
198
199 /* set gpon ingress translaton to add outer tag on upstream packets */
200 u_action.new_outer_vlan = p_flow->data.action.o_vid;
201 u_action.priority = p_flow->data.action.o_pbits;
202
203 switch(p_flow->data.classifier.pkt_tag_type)
204 {
205 case BCMBAL_PKT_TAG_TYPE_SINGLE_TAG:
206 u_action.ot_outer = bcmVlanActionAdd;
207 u_action.ot_outer_pkt_prio = bcmVlanActionReplace;
208 u_ovid = p_flow->data.classifier.o_vid;
209 u_ivid = BCM_VLAN_NONE;
210 break;
211 default: /* not supported, goto while(0) */
212 u_ovid = BCM_VLAN_NONE;
213 u_ivid = BCM_VLAN_NONE;
214 ret = BCM_ERR_INTERNAL;
215 continue;
216 }
217 /* enable ingress vlan translation on specified port */
218 bcm_rc = bcm_vlan_control_port_set(unit, pon_gport, bcmVlanTranslateIngressEnable, 1);
219 if (bcm_rc != BCM_E_NONE)
220 {
221 BCM_LOG(ERROR, log_id_sw_util,
222 " flow fail to enable ingress vlan translation on port %d - %d\n",
223 pon_phy_pbm, bcm_rc );
224 ret = BCM_ERR_INTERNAL;
225 break;
226 }
227 /* set the outer vlan id as lookup key - i.e. packet filtering key */
228 bcm_rc = bcm_vlan_control_port_set(unit, pon_gport, bcmVlanPortTranslateKeyFirst, bcmVlanTranslateKeyOuter);
229 if (bcm_rc != BCM_E_NONE)
230 {
231 BCM_LOG(ERROR, log_id_sw_util,
232 " flow fail to set upstream lookup key on port %d - %d\n",
233 pon_phy_pbm, bcm_rc );
234 ret = BCM_ERR_INTERNAL;
235 break;
236 }
237 /* install the action into ingress vlan translation table */
238 bcm_rc = bcm_vlan_translate_action_add(unit, pon_gport, bcmVlanTranslateKeyOuter, u_ovid, u_ivid, &u_action);
239 if (bcm_rc != BCM_E_NONE)
240 {
241 BCM_LOG(ERROR, log_id_sw_util,
242 " flow fail to set ingress action on port %d - %d\n",
243 pon_phy_pbm, bcm_rc );
244 ret = BCM_ERR_INTERNAL;
245 break;
246 }
247 }
248 else
249 {
250 BCM_LOG(ERROR, log_id_sw_util,
251 " flow upstream action 0x%x not supported\n", p_flow->data.action.cmds_bitmask);
252
253 ret = BCM_ERR_NOT_SUPPORTED;
254 }
255 }
256
257 } while(0);
258
259 return ret;
260}
261
262/**
263 * @brief The engress vlan translation function program switch to
264 * translate packet vlan attributes before the packets were sent out
265 *
266 * @param unit the switch unit this translation is perfromed
267 * @param p_flow a pointer to the flow that contains translation action
268 * @return error code
269 */
270static bcmos_errno bal_swapp_esw_evlanx(int unit, bcmbal_flow_cfg *p_flow)
271{
272 bcmos_errno ret = BCM_ERR_OK;
273 bcm_gport_t pon_gport;
274 uint32_t pon_phy_pbm;
275 int bcm_rc;
276
277 /* find out which PON this action is to be performed */
278 /* map pon logical port to physical port */
279 pon_phy_pbm = bal_bcm_pon_inf_pbm_get(p_flow->data.access_int_id);
280 /* create local gport based on pon physical port number */
281 BCM_GPORT_LOCAL_SET(pon_gport, pon_phy_pbm);
282
283 do
284 {
285 /* For TR-156 1:1 downstream double tagged packets,
286 S-tag remove acton is performed in the EGRESS vlan translator.
287 */
288 if (BCMBAL_FLOW_TYPE_DOWNSTREAM == p_flow->key.flow_type)
289 {
290
291 if ( p_flow->data.action.cmds_bitmask & BCMBAL_ACTION_CMD_ID_REMOVE_OUTER_TAG )
292 {
293 /* set gpon egress translaton to drop outer tag of double tag downstream packets */
294 uint32_t d_ovid, d_ivid;
295 bcm_vlan_action_set_t d_action;
296 bcm_vlan_action_set_t_init(&d_action);
297 switch(p_flow->data.classifier.pkt_tag_type)
298 {
299 case BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG:
300 d_action.dt_outer = bcmVlanActionDelete;
301 d_ovid = p_flow->data.classifier.o_vid;
302 d_ivid = p_flow->data.classifier.i_vid;
303 break;
304
305 default: /* not supported, goto while(0) */
306 d_ovid = BCM_VLAN_NONE;
307 d_ivid = BCM_VLAN_NONE;
308 ret = BCM_ERR_INTERNAL;
309 continue;
310 }
311 /* enable egress vlan translation on specified port */
312 bcm_rc = bcm_vlan_control_port_set(unit, pon_gport, bcmVlanTranslateEgressEnable, 1);
313 if (bcm_rc != BCM_E_NONE)
314 {
315 BCM_LOG(ERROR, log_id_sw_util,
316 " flow fail to enable egress vlan translation on port %d - %d\n",
317 pon_phy_pbm, bcm_rc );
318 ret = BCM_ERR_INTERNAL;
319 break;
320 }
321
322 /* install the action into egress vlan translation table */
323 bcm_rc = bcm_vlan_translate_egress_action_add(unit, pon_gport, d_ovid, d_ivid, &d_action);
324 if (bcm_rc != BCM_E_NONE)
325 {
326 BCM_LOG(ERROR, log_id_sw_util,
327 " flow fail to set egress action on port %d - %d\n",
328 pon_phy_pbm, bcm_rc );
329 ret = BCM_ERR_INTERNAL;
330 break;
331 }
332 }
333 else
334 {
335 BCM_LOG(ERROR, log_id_sw_util,
336 " flow downstream action 0x%x not supported\n", p_flow->data.action.cmds_bitmask);
337
338 ret = BCM_ERR_NOT_SUPPORTED;
339 }
340
341 }
342
343 } while(0);
344
345 return ret;
346}
347
348
349/**
350 * @brief The flow add function program KT2 to forward packets that have
351 * specified attributes to the designated ports.
352 * The packets is modified before egress
353 * On the downstream, an access id (outer vlan tag) is added to the packets
354 * On the upstream, outer vlan tag (access id) is removed from the packets
355 *
356 * @param iwf_mode The InterWorking Function mode - DIRECT or PER-FLOW
357 * @param p_flow A pointer to the requested add flow info
358 * @return error code
359 */
360bcmos_errno bal_sw_util_esw_flow_add(bcmbal_iwf_mode iwf_mode, bcmbal_flow_cfg *p_flow)
361{
362 bcmos_errno ret = BCM_ERR_OK;
363 bcm_gport_t pon_gport;
364 uint32_t pon_phy_pbm;
365 bcm_vlan_t vlan_id;
366 bcm_gport_t nni_gport;
367 uint32_t nni_phy_pbm;
368 int ii;
369 int bcm_rc;
370 int unit = bal_bcm_pon_inf_dev_get(p_flow->data.access_int_id);
371
372 BCM_LOG(INFO, log_id_sw_util,
373 " Got an ESW flow request - iwf_mode=%d flow_id=%d sub_port=%d svc_id=%d\n",
374 iwf_mode,
375 p_flow->key.flow_id, p_flow->data.access_int_id, p_flow->data.svc_port_id);
376 BCM_LOG(DEBUG, log_id_sw_util,
377 " classifier - mask=0x%llx otpid=%x itpid=%x ovid=%x ivid=%x\n",
378 (unsigned long long)p_flow->data.classifier.presence_mask,
379 p_flow->data.classifier.o_tpid, p_flow->data.classifier.i_tpid,
380 p_flow->data.classifier.o_vid, p_flow->data.classifier.i_vid);
381
382 /*
383 * First, validate that the specified PON has at least one NNI port on the same device.
384 * If not, return an error, as this is not supported.
385 */
386 ii = 0;
387 ret = BCM_ERR_NOT_SUPPORTED;
388 /* walk through the entire mapping table */
389 while(-1 != bal_bcm_net_inf_pbm_get(ii))
390 {
391 if(bal_bcm_net_inf_dev_get(ii) == unit)
392 {
393 ret = BCM_ERR_OK;
394 break;
395 }
396 ii++; /* Next NNI */
397 }
398
399 do
400 {
401 /*
402 * Check return code from device check above. Return if there was an error.
403 */
404 if(BCM_ERR_OK != ret)
405 {
406 BCM_LOG(ERROR, log_id_sw_util,
407 " ERROR: no network port is on the same device as access port %d\n", p_flow->data.access_int_id);
408 break;
409 }
410
411 /* create vlan domain for this flow */
412 vlan_id = (bcm_vlan_t)p_flow->data.classifier.o_vid;
413 bcm_rc = bcm_vlan_create(unit, vlan_id);
414
415 /* if OK or already existed, continue */
416 if (bcm_rc != BCM_E_NONE && bcm_rc != BCM_E_EXISTS)
417 {
418 BCM_LOG(ERROR, log_id_sw_util,
419 " failed to create vlan %d on unit %d - bcm_rc:%d\n", vlan_id, unit, bcm_rc );
420 ret = BCM_ERR_INTERNAL;
421 break;
422 }
423 else
424 {
425 BCM_LOG(INFO, log_id_sw_util,
426 " vlan %d %s on unit %d - bcm_rc:%d\n",
427 vlan_id,
428 (BCM_E_EXISTS == bcm_rc) ? "reused" : "created",
429 unit,
430 bcm_rc );
431 }
432
433 /* map pon logical port to physical port */
434 pon_phy_pbm = bal_bcm_pon_inf_pbm_get(p_flow->data.access_int_id);
435
436 /* create gport based on pon physical port number */
437 BCM_GPORT_LOCAL_SET(pon_gport, pon_phy_pbm);
438
439 /* add the specified pon to vlan */
440 bcm_rc = bcm_vlan_gport_add(unit, vlan_id, pon_gport, BCM_VLAN_GPORT_ADD_VP_VLAN_MEMBERSHIP);
441
442 if (bcm_rc != BCM_E_NONE)
443 {
444 BCM_LOG(ERROR, log_id_sw_util,
445 " flow fail to add pon %d (pbm %d, gport %d) into vlan %d - %d\n",
446 p_flow->data.access_int_id, pon_phy_pbm, pon_gport, vlan_id, bcm_rc );
447
448 ret = BCM_ERR_INTERNAL;
449
450 break;
451 }
452
453 /* Add all the NNI ports that are on the same device to the vlan as well */
454
455 ii = 0; /* Start with the first NNI logical interface */
456
457 /* map nni logical ports to physical ports */
458 while(-1 != (nni_phy_pbm = bal_bcm_net_inf_pbm_get(ii)))
459 {
460 if ( bal_bcm_net_inf_dev_get(ii) != unit)
461 {
462 continue;
463 }
464 /* create gport based on nni physical port number */
465 BCM_GPORT_LOCAL_SET(nni_gport, nni_phy_pbm);
466
467 bcm_rc = bcm_vlan_gport_add(unit, vlan_id, nni_gport, BCM_VLAN_GPORT_ADD_VP_VLAN_MEMBERSHIP);
468
469 if (bcm_rc != BCM_E_NONE)
470 {
471 BCM_LOG(ERROR, log_id_sw_util,
472 " flow fail to add nni %d (pbm %d, gport %d) into vlan %d - %d\n",
473 ii, nni_phy_pbm, nni_gport, vlan_id, bcm_rc );
474
475 ret = BCM_ERR_INTERNAL;
476
477 break;
478 }
479
480 ii++; /* Next NNI */
481 }
482
483 /* perform the ACTION */
484 if (BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, action)
485 /* && BCMOS_TRUE == BCMBAL_ATTRIBUTE_CFG_PROP_IS_SET(&p_flow->data.action, action, action_cmds_bitmask) */
486 )
487 {
488 BCM_LOG(INFO, log_id_sw_util,
489 " Got a flow action - flow type = %d, cmd=%d in_ovid=%d, out_ovid=%d\n",
490 p_flow->key.flow_type, p_flow->data.action.cmds_bitmask,
491 p_flow->data.classifier.i_vid, p_flow->data.classifier.o_vid);
492
493 /* enable vlan translation */
494 bcm_rc = bcm_vlan_control_set(unit, bcmVlanTranslate, 1);
495 if (bcm_rc != BCM_E_NONE)
496 {
497 BCM_LOG(ERROR, log_id_sw_util,
498 " flow fail to enable vlan translation - %d\n",
499 bcm_rc );
500 ret = BCM_ERR_INTERNAL;
501 break;
502 }
503 /* For TR-156 1:1 downstream,
504 ACTIONs are performed on the EGRESS vlan translator.
505 For TR-156 1:1 upstream,
506 ACTIONs are perform on the INGRESS vlan translator.
507 For TR-156 N:1 there is no actions for switch
508 The outer tag adding is per PON base, i.e. upstream packets with same
509 inner vid can add different outer vid based on receiving PON
510 */
511 if (BCMBAL_FLOW_TYPE_UPSTREAM == p_flow->key.flow_type)
512 {
513 if ( p_flow->data.action.cmds_bitmask & BCMBAL_ACTION_CMD_ID_ADD_OUTER_TAG )
514 {
515 ret = bal_swapp_esw_ivlanx(unit, p_flow);
516 }
517 }
518 else if (BCMBAL_FLOW_TYPE_DOWNSTREAM == p_flow->key.flow_type)/* downstream */
519 {
520 if ( p_flow->data.action.cmds_bitmask & BCMBAL_ACTION_CMD_ID_REMOVE_OUTER_TAG )
521 {
522 ret = bal_swapp_esw_evlanx(unit, p_flow);
523 }
524 }
525 else /* broadcast */
526 {
527 if ( p_flow->data.action.cmds_bitmask & BCMBAL_ACTION_CMD_ID_DISCARD_DS_BCAST)
528 {
529 ret = bal_swapp_esw_acl_add(unit, p_flow);
530 }
531
532 }
533 } /* end if ACTION set */
534
535 } while(0);
536
537
538 return ret;
539}
540
541/**
542 * @brief The flow remove function remove switch resource that were allocated during ADD
543 *
544 * @param iwf_mode The InterWorking Function mode - DIRECT or PER-FLOW
545 * @param p_flow A pointer to the requested add flow info
546 * @return error code
547 */
548bcmos_errno bal_sw_util_esw_flow_remove(bcmbal_iwf_mode iwf_mode, bcmbal_flow_cfg *p_flow)
549{
550 return BCM_ERR_OK;
551}
552
553#endif /* #ifndef TEST_SW_UTIL_LOOPBACK */
554
555/*@}*/