blob: d281e1f222daa9a09a0958dd303cba824ed69639 [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_dpp_vswitch.c
34 * @brief BAL Switch util helper functions that handle vswitch service 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_utils_msg.h>
43#include "bcmos_errno.h"
44
45#ifndef TEST_SW_UTIL_LOOPBACK
46#include <bcm/types.h>
47#include <sal/core/libc.h>
48#ifndef sal_memset
49#define sal_memset memset
50#endif
51#include <bcm/port.h>
52#include <bcm/vlan.h>
53#include <bcm/error.h>
54#include <bcm/vswitch.h>
55
56#include "bal_switch_flow.h"
57#include "bal_dpp_vswitch.h"
58#include "bal_switch_util.h"
59
60/* A local link list to keep trak of virtual switch service */
61TAILQ_HEAD(bal_sw_vsi_list_head, bal_sw_vsi_service) g_swutil_vsi_list;
62
63/**
64 * @brief The vsi list init function prepare a link list to keep track of
65 * vsi service in the switch util
66 *
67 * @return error code
68 */
69bcmos_errno bal_sw_util_vsi_list_init(void)
70{
71 static uint32_t g_vsi_inited = 0;
72 if(g_vsi_inited == 0)
73 {
74 TAILQ_INIT(&g_swutil_vsi_list);
75 g_vsi_inited = 1;
76 }
77 return BCM_ERR_OK;
78}
79
80/**
81 * @brief The vsi list search function by LIF tag
82 *
83 * @param p_lif_tag a pointer to the packet tag that need to match the entry in the list
84 * @param p_svc_indx a pointer to store the created service tag index within the vsi
85
86 * @return pointer to an element in the list, NULL if failed
87 */
88static bal_sw_vsi_service *bal_sw_util_dpp_vsi_service_get_by_tag(bal_sw_lif_pkt_tag *p_lif_tag, uint32_t *p_svc_indx)
89{
90 bal_sw_vsi_service *p_entry, *p_temp;
91 int lif_match = 0, svc_idx;
92
93 if(p_svc_indx == NULL)
94 {
95 BCM_LOG(ERROR, log_id_sw_util, "call VSI service get tag with invalid parameter\n");
96 return NULL;
97 }
98
99 /* clear the storage area */
100 *p_svc_indx = 0;
101
102 TAILQ_FOREACH_SAFE(p_entry, &g_swutil_vsi_list, next_service, p_temp)
103 {
104 for(svc_idx = 0; svc_idx < p_entry->num_tag; svc_idx++)
105 {
106 if( p_entry->pkt_tag[svc_idx].type == p_lif_tag->type)
107 {
108 switch (p_lif_tag->type)
109 {
110 case BCMBAL_PKT_TAG_TYPE_SINGLE_TAG:
111 if( p_lif_tag->o_vid == p_entry->pkt_tag[svc_idx].o_vid)
112 {
113 lif_match = 1;
114 }
115 break;
116 case BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG:
117 if( p_lif_tag->o_vid == p_entry->pkt_tag[svc_idx].o_vid && p_lif_tag->i_vid == p_entry->pkt_tag[svc_idx].i_vid)
118 {
119 lif_match = 1;
120 }
121 break;
122 case BCMBAL_PKT_TAG_TYPE_UNTAGGED:
123 lif_match = 1;
124 break;
125 default:
126 BCM_LOG(ERROR, log_id_sw_util, "Unsupported packet type %d in LIF info\n", p_lif_tag->type);
127 return NULL;
128 }
129 if(lif_match)
130 {
131 if(p_svc_indx)
132 {
133 *p_svc_indx = svc_idx;
134 }
135 return p_entry;
136 }
137 }
138 }
139 }
140
141 /* if reach the end of the list, TAILQ_FOREACH_SAFE set the p_entry to NULL */
142 return NULL;
143
144}
145
146/*
147 * @brief The vsi list insert function
148 *
149 * @param entry the vsi element to be added in the link list
150 * @return error code
151*/
152static bal_sw_vsi_service *bal_sw_util_vsi_list_insert(bal_sw_vsi_service *p_entry)
153{
154 bal_sw_vsi_service *p_new_entry;
155
156 p_new_entry = bcmos_calloc(sizeof(bal_sw_vsi_service));
157 if(NULL == p_new_entry)
158 {
159 BCM_LOG(ERROR, log_id_sw_util, "VSI list insert out of memory\n");
160 return NULL;
161 }
162 *p_new_entry = *p_entry;
163 TAILQ_INSERT_TAIL(&g_swutil_vsi_list, p_new_entry, next_service);
164 return p_new_entry;
165}
166
167/*
168 * @brief The vsi list remove function
169 *
170 * @param p_entry Pointer to the vsi element in the link list result from the search functions
171 * @return error code
172*/
173static bcmos_errno bal_sw_util_vsi_list_remove(bal_sw_vsi_service *p_entry)
174{
175 TAILQ_REMOVE(&g_swutil_vsi_list, p_entry, next_service);
176 bcmos_free(p_entry);
177 return BCM_ERR_OK;
178}
179
180/**
181 * @brief The vsi create function create a virtual switch service that contains ingress LIF
182 * and virtual switch. This service can later be connected to multiple egress LIF of multiple FLOWs.
183 * The function use the source port and vid information in the bcmbal_flow_cfg as input
184 * The pointer of the created vsi will be returned
185 * Since a vsi can provide multiple srevices, the index to the created service tag is return here
186 *
187 * @param unit switch device id
188 * @param p_flow a pointer to the flow definition which the created service will be based on
189 * @param p_svc_indx a pointer to store the created service tag index within the vsi
190 *
191 * @return pointer to the vsi service list entry, NULL if operation failed
192 */
193
194bal_sw_vsi_service *bal_sw_util_dpp_vsi_service_create(int unit, bcmbal_flow_cfg *p_flow, uint32_t *p_svc_indx)
195{
196 int rv;
197 bal_sw_lif_pkt_tag svc_pkt_tag = {0};
198 bal_sw_vsi_service *p_vsi_service, vsi_svc_elm;
199 bcm_vlan_t vsi;
200 int multicast_id, flags;
201
202 /* p_flow can be NULL when create vswitch for multicast group, service tag will be added when multicast flow is created */
203 if (p_flow == NULL)
204 {
205 BCM_LOG(INFO, log_id_sw_util, "create vsi service with no service tag \n");
206 p_vsi_service = NULL;
207 }
208 else
209 {
210 /* find out if the vsi service already exist */
211 svc_pkt_tag.type = p_flow->data.classifier.pkt_tag_type;
212 svc_pkt_tag.o_vid = p_flow->data.classifier.o_vid;
213 svc_pkt_tag.i_vid = p_flow->data.classifier.i_vid;
214 p_vsi_service = bal_sw_util_dpp_vsi_service_get_by_tag(&svc_pkt_tag, p_svc_indx);
215 }
216
217 /* if no service, create one */
218 if(p_vsi_service == NULL)
219 {
220 /* initialize link list vsi element */
221 memset(&vsi_svc_elm, 0, sizeof (bal_sw_vsi_service));
222 /* if flow (service tag) is specified, fill in the basic info, since it is new, add it to the first tag */
223 if(p_flow)
224 {
225 vsi_svc_elm.pkt_tag[0] = svc_pkt_tag;
226 vsi_svc_elm.num_tag = 1;
227 }
228
229 rv = bcm_vswitch_create(unit, &vsi);
230 if (rv != BCM_E_NONE)
231 {
232 BCM_LOG(ERROR, log_id_sw_util, "bcm_vswitch_create failed %d \n", rv);
233 return NULL;
234 }
235 else
236 {
237 BCM_LOG(INFO, log_id_sw_util, " vswitch 0x%x created\n", vsi);
238 }
239 vsi_svc_elm.vswitch = vsi;
240 /* create two multicast groups (a.k.a. flooding group), one for upstream and one for downstream
241 clean up first, it is OK there is nothing to destroy */
242
243 /* Create the multicast group used for upstream flooding
244 * (PON-->NNI). For the upstream mcast group, the QAX hardware
245 * requires the ID to be set to a value equal to the VSI ID
246 * created above.
247 */
248 multicast_id = vsi + BAL_DPP_US_FLOOD_OFFSET;
249 rv = bcm_multicast_group_is_free(unit, multicast_id);
250 if (rv == BCM_E_EXISTS)
251 {
252 rv = bcm_multicast_destroy(unit, multicast_id);
253 if (rv != BCM_E_NONE)
254 {
255 BCM_LOG(ERROR, log_id_sw_util, "US: bcm_multicast_destroy 0x%x failed %d \n", multicast_id, rv);
256 bcm_vswitch_destroy(unit, vsi);
257 return NULL;
258 }
259 }
260 /* flags = ingress replication + fixed id + L2 multicast */
261 flags = BCM_MULTICAST_INGRESS_GROUP | BCM_MULTICAST_WITH_ID | BCM_MULTICAST_TYPE_L2;
262 rv = bcm_multicast_create(unit, flags, &multicast_id);
263 if (rv != BCM_E_NONE)
264 {
265 BCM_LOG(ERROR, log_id_sw_util, "US: in bcm_multicast_create 0x%x w ingress failed %d \n", multicast_id, rv);
266 bcm_vswitch_destroy(unit, vsi);
267 return NULL;
268 }
269 else
270 {
271 BCM_LOG(INFO, log_id_sw_util, "US: vswitch flood group 0x%x created\n", multicast_id);
272 }
273 vsi_svc_elm.us_flood_grp_id = multicast_id;
274
275 /* downstream flooding group */
276 multicast_id = vsi + BAL_DPP_DS_FLOOD_OFFSET;
277 rv = bcm_multicast_group_is_free(unit, multicast_id);
278 if (rv == BCM_E_EXISTS)
279 {
280 rv = bcm_multicast_destroy(unit, multicast_id);
281 if (rv != BCM_E_NONE)
282 {
283 BCM_LOG(ERROR, log_id_sw_util, "DS: bcm_multicast_destroy 0x%x failed %d \n", multicast_id, rv);
284 bcm_multicast_destroy(unit, vsi_svc_elm.us_flood_grp_id);
285 bcm_vswitch_destroy(unit, vsi);
286 return NULL;
287 }
288 }
289 flags = BCM_MULTICAST_INGRESS_GROUP | BCM_MULTICAST_WITH_ID | BCM_MULTICAST_TYPE_L2;
290 rv = bcm_multicast_create(unit, flags, &multicast_id);
291 if (rv != BCM_E_NONE)
292 {
293 BCM_LOG(ERROR, log_id_sw_util, "DS: in bcm_multicast_create 0x%x w ingress 2 failed %d \n", multicast_id, rv);
294 bcm_multicast_destroy(unit, vsi_svc_elm.us_flood_grp_id);
295 bcm_vswitch_destroy(unit, vsi);
296 return NULL;
297 }
298 else
299 {
300 BCM_LOG(INFO, log_id_sw_util, "DS: vswitch flood group 0x%x created\n", multicast_id);
301 }
302 vsi_svc_elm.ds_flood_grp_id = multicast_id;
303
304 /* add vsi service to the vsi list */
305 p_vsi_service = bal_sw_util_vsi_list_insert(&vsi_svc_elm);
306 if (p_vsi_service == NULL)
307 {
308 BCM_LOG(ERROR, log_id_sw_util, "VSI: fail to insert new vsi to the service list\n");
309 bcm_multicast_destroy(unit, vsi_svc_elm.us_flood_grp_id);
310 bcm_multicast_destroy(unit, vsi_svc_elm.ds_flood_grp_id);
311 bcm_vswitch_destroy(unit, vsi_svc_elm.vswitch);
312 return NULL;
313 }
314 p_vsi_service->use_count = 1;
315 }
316 else
317 {
318 p_vsi_service->use_count++;
319 }
320
321 return p_vsi_service;
322}
323
324/**
325 * @brief The vsi destroy function free up Hardare resource of a virtual switch.
326 * It also remove the vsi fromt the service list
327 *
328 * @param unit switch device id
329 * @param p_vsi_svc a pointer to the vsi service
330 *
331 * @return error code
332 */
333
334bcmos_errno bal_sw_util_dpp_vsi_service_destroy(int unit, bal_sw_vsi_service *p_vsi_svc)
335{
336 int rv;
337
338 /* input validation */
339 if (p_vsi_svc == NULL)
340 {
341 BCM_LOG(ERROR, log_id_sw_util, "destroy vsi service with invalid parameters \n");
342 return BCM_ERR_PARM;
343 }
344
345 /* only clean up when no more users */
346 if(p_vsi_svc->use_count > 1)
347 {
348 p_vsi_svc->use_count--;
349 return BCM_ERR_OK;
350 }
351
352 /* free up HW resource, continue even if any failed */
353 rv = bcm_multicast_destroy(unit, p_vsi_svc->us_flood_grp_id);
354 if (rv != BCM_E_NONE)
355 {
356 BCM_LOG(WARNING, log_id_sw_util, "bcm_multicast_destroy US 0x%x failed %d \n", p_vsi_svc->us_flood_grp_id, rv);
357 }
358 rv = bcm_multicast_destroy(unit, p_vsi_svc->ds_flood_grp_id);
359 if (rv != BCM_E_NONE)
360 {
361 BCM_LOG(WARNING, log_id_sw_util, "bcm_multicast_destroy DS 0x%x failed %d \n", p_vsi_svc->ds_flood_grp_id, rv);
362 }
363 rv = bcm_vswitch_destroy(unit, p_vsi_svc->vswitch);
364 if (rv != BCM_E_NONE)
365 {
366 BCM_LOG(WARNING, log_id_sw_util, "bcm_multicast_destroy vswitch 0x%x failed %d \n", p_vsi_svc->vswitch, rv);
367 }
368
369 /* remove from the service list */
370 rv = bal_sw_util_vsi_list_remove(p_vsi_svc);
371 if (rv != BCM_E_NONE)
372 {
373 BCM_LOG(WARNING, log_id_sw_util, "bcm_multicast_destroy VSI entry failed %d \n", rv);
374 }
375
376 return BCM_ERR_OK;
377}
378
379
380/**
381 * @brief The vsi port_find function search a port from the port list of a vsi service entry.
382 *
383 * @param p_vsi_svc a pointer to the vsi service
384 * @param svc_tag_indx an index to the service within the vsi that a port need to be searched
385 * @param port the ingress port that needs to be located
386 * @param idx pointer to a storage where the array index of the found port will be return
387 *
388 * @return error code
389 */
390
391static bcmos_errno bal_sw_util_dpp_vsi_service_port_find(bal_sw_vsi_service *p_vsi_svc, uint32_t svc_tag_indx, uint32_t port, uint32_t *idx)
392{
393 int i;
394
395 /* input validation */
396 if (p_vsi_svc == NULL)
397 {
398 BCM_LOG(ERROR, log_id_sw_util, "vsi service port find function with invalid parameters \n");
399 return BCM_ERR_PARM;
400 }
401 /* loop through the list */
402 for( i=0; i<p_vsi_svc->pkt_tag[svc_tag_indx].num_port; i++)
403 {
404 if(p_vsi_svc->pkt_tag[svc_tag_indx].port[i].port == port)
405 {
406 break;
407 }
408 }
409 if (i == p_vsi_svc->pkt_tag[svc_tag_indx].num_port)
410 {
411 return BCM_ERR_NOENT;
412 }
413 *idx = i;
414 return BCM_ERR_OK;
415}
416
417/**
418 * @brief The vsi port_find function search a gport from the port list of a vsi service entry.
419 *
420 * @param p_vsi_svc a pointer to the vsi service
421 * @param svc_tag_indx an index to the service within the vsi that a gport need to be searched
422 * @param gport the ingress gport that needs to be located
423 * @param idx pointer to a storage where the array index of the found port will be return
424 *
425 * @return error code
426 */
427
428static bcmos_errno bal_sw_util_dpp_vsi_service_gport_find(bal_sw_vsi_service *p_vsi_svc, uint32_t svc_tag_indx, uint32_t gport, uint32_t *idx)
429{
430 int i;
431
432 /* input validation */
433 if (p_vsi_svc == NULL)
434 {
435 BCM_LOG(ERROR, log_id_sw_util, "vsi service port find function with invalid parameters \n");
436 return BCM_ERR_PARM;
437 }
438 /* loop through the list */
439 for( i=0; i<p_vsi_svc->pkt_tag[svc_tag_indx].num_port; i++)
440 {
441 if(p_vsi_svc->pkt_tag[svc_tag_indx].port[i].gport == gport)
442 {
443 break;
444 }
445 }
446 if (i == p_vsi_svc->pkt_tag[svc_tag_indx].num_port)
447 {
448 return BCM_ERR_NOENT;
449 }
450 *idx = i;
451 return BCM_ERR_OK;
452}
453
454/**
455 * @brief The vsi port_add function add an ingress port to the vsi service.
456 If the port is already in the vsi, just increase the counter
457 If the port is not in the vsi, create a gport and add it to the US flooding group.
458 This allows the US SPEAK_FIRST packets to be forwarded to the network.
459 *
460 * @param unit switch device id
461 * @param p_vsi_svc a pointer to the vsi service
462 * @param svc_tag_indx an index to the service within the vsi that a port need to be added
463 * @param port the ingress port that needs to be added to the vsi service
464 * @param p_gport a valid pointer where the created/existing gport will be returned.
465 * NULL, if caller don't care the gport
466 *
467 * @return error code
468 */
469
470bcmos_errno bal_sw_util_dpp_vsi_service_port_add(int unit, bal_sw_vsi_service *p_vsi_svc, uint32_t svc_tag_indx, uint32_t port, int32_t *p_gport)
471{
472 bcm_vlan_port_t vp;
473 uint32_t idx;
474 int ind, rv;
475 int32_t gport;
476 bcmos_errno ret;
477 int port_encap_id;
478
479 /* input validation */
480 if (p_vsi_svc == NULL)
481 {
482 BCM_LOG(ERROR, log_id_sw_util, "vsi service port add function with invalid parameters \n");
483 return BCM_ERR_PARM;
484 }
485 /* check if the port already in the vsi */
486 ret = bal_sw_util_dpp_vsi_service_port_find(p_vsi_svc, svc_tag_indx, port, &idx);
487 /* if port already in the vsi, just increase the counter */
488 if(ret == BCM_ERR_OK)
489 {
490 if(p_gport)
491 {
492 *p_gport = p_vsi_svc->pkt_tag[svc_tag_indx].port[idx].gport;
493 }
494 (p_vsi_svc->pkt_tag[svc_tag_indx].port[idx].use_count)++;
495 return BCM_ERR_OK;
496 }
497
498 /* create the LIF */
499 bcm_vlan_port_t_init(&vp);
500 vp.port = port;
501 /* configure frame match according to the service packet tags */
502 switch(p_vsi_svc->pkt_tag[svc_tag_indx].type)
503 {
504 case BCMBAL_PKT_TAG_TYPE_UNTAGGED:
505 vp.criteria = BCM_VLAN_PORT_MATCH_PORT;
506 break;
507 case BCMBAL_PKT_TAG_TYPE_SINGLE_TAG:
508 vp.criteria = BCM_VLAN_PORT_MATCH_PORT_VLAN;
509 vp.match_vlan = p_vsi_svc->pkt_tag[svc_tag_indx].o_vid;
510 break;
511 case BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG:
512 vp.criteria = BCM_VLAN_PORT_MATCH_PORT_VLAN_STACKED;
513 vp.match_vlan = p_vsi_svc->pkt_tag[svc_tag_indx].o_vid;
514 vp.match_inner_vlan = p_vsi_svc->pkt_tag[svc_tag_indx].i_vid;
515 break;
516 default:
517 /* should not reach here */
518 BCM_LOG(ERROR, log_id_sw_util, "VSI: Unsupported packet type %d \n",p_vsi_svc->pkt_tag[svc_tag_indx].type );
519 return BCM_ERR_INTERNAL;
520 break;
521 }
522
523 vp.vsi = 0; /* will be populated when the gport is added to service, using vswitch_port_add */
524 vp.flags = BCM_VLAN_PORT_OUTER_VLAN_PRESERVE | BCM_VLAN_PORT_INNER_VLAN_PRESERVE;
525
526 rv = bcm_vlan_port_create(unit, &vp);
527 if (rv != BCM_E_NONE)
528 {
529 BCM_LOG(ERROR, log_id_sw_util, "VSI: bcm_vlan_port_create port %d, failed %d\n", port, rv);
530 return BCM_ERR_INTERNAL;
531 }
532
533 gport = vp.vlan_port_id;
534
535 // add gport to vswitch
536 rv = bcm_vswitch_port_add(unit, p_vsi_svc->vswitch, gport);
537 if (rv != BCM_E_NONE)
538 {
539 BCM_LOG(ERROR, log_id_sw_util, "VSI, bcm_vswitch_port_add for port %d failed %d\n", port, rv);
540 bcm_vlan_port_destroy(unit, gport);
541 return BCM_ERR_INTERNAL;
542 }
543 else
544 {
545 BCM_LOG(INFO, log_id_sw_util, "VSI: bcm_vswitch_port_add for port %d, gport 0x%x\n", port, gport);
546 }
547 /* if caller requre for the gport info, return the gport */
548 if(p_gport)
549 {
550 *p_gport = gport;
551 }
552 /* record the gport into the vsi */
553 ind = p_vsi_svc->pkt_tag[svc_tag_indx].num_port;
554 if (ind == MAX_NET_PORT)
555 {
556 BCM_LOG(ERROR, log_id_sw_util, "VSI, reach max port allow\n");
557 bcm_vswitch_port_delete(unit, p_vsi_svc->vswitch, gport);
558 bcm_vlan_port_destroy(unit, gport);
559 return BCM_ERR_NORES;
560 }
561 p_vsi_svc->pkt_tag[svc_tag_indx].port[ind].port = port;
562 p_vsi_svc->pkt_tag[svc_tag_indx].port[ind].gport = gport;
563 p_vsi_svc->pkt_tag[svc_tag_indx].port[ind].use_count = 1;
564 p_vsi_svc->pkt_tag[svc_tag_indx].num_port = ++ind;
565
566 ret = BCM_ERR_OK;
567 do
568 {
569 // update flooding group with phy_port/gport as ingress port
570 rv = bcm_multicast_vlan_encap_get(unit, p_vsi_svc->us_flood_grp_id, port, gport, &port_encap_id);
571 if (rv != BCM_E_NONE)
572 {
573 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_multicast_vlan_encap_get for port failed %d\n", rv);
574 ret = BCM_ERR_NOENT;
575 break;
576 }
577 /* be a member of the upstream flooding group */
578 rv = bcm_multicast_ingress_add(unit, p_vsi_svc->us_flood_grp_id, port, port_encap_id);
579 if (rv != BCM_E_NONE)
580 {
581 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_multicast_ingress_add for port failed %d\n", rv);
582 ret = BCM_ERR_NOENT;
583 break;
584 }
585
586 /* now set the type of packets that goes to the downstream flooding group */
587 /* forward unknown unicast */
588 rv = bcm_port_control_set(unit, gport, bcmPortControlFloodUnknownUcastGroup, BAL_DPP_DS_FLOOD_OFFSET);
589 if (rv != BCM_E_NONE)
590 {
591 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_port_control_set ucast for nni failed %d\n", rv);
592 ret = BCM_ERR_INTERNAL;
593 break;
594 }
595 /* drop unknown multicast */
596 rv = bcm_port_control_set(unit, gport, bcmPortControlFloodUnknownMcastGroup, BCM_GPORT_BLACK_HOLE);
597 if (rv != BCM_E_NONE)
598 {
599 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_port_control_set mcast for nni failed %d\n", rv);
600 ret = BCM_ERR_INTERNAL;
601 break;
602 }
603
604 /* forward broadcast */
605 rv = bcm_port_control_set(unit, gport, bcmPortControlFloodBroadcastGroup, BAL_DPP_DS_FLOOD_OFFSET);
606 if (rv != BCM_E_NONE)
607 {
608 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_port_control_set bcast for nni failed %d\n", rv);
609 ret = BCM_ERR_INTERNAL;
610 break;
611 }
612 }while(0);
613
614 return ret;
615}
616
617/**
618 * @brief The vsi port_rem function remove an ingress port to the vsi service.
619 *
620 * @param unit switch device id
621 * @param p_vsi_svc a pointer to the vsi service
622 * @param svc_tag_indx an index to the service within the vsi that a port need to be removed
623 * @param gport the ingress gport that needs to be removed from the vsi service
624 *
625 * @return error code
626 */
627
628bcmos_errno bal_sw_util_dpp_vsi_service_port_rem(int unit, bal_sw_vsi_service *p_vsi_svc, uint32_t svc_tag_indx, uint32_t gport)
629{
630 uint32_t idx;;
631 int port_encap_id, rv, i;
632 bcmos_errno ret = BCM_ERR_OK;
633 int port;
634 /* input validation */
635 if (p_vsi_svc == NULL)
636 {
637 BCM_LOG(ERROR, log_id_sw_util, "vsi service port rem function with invalid parameters \n");
638 return BCM_ERR_PARM;
639 }
640 /* check if the port in the vsi */
641 ret = bal_sw_util_dpp_vsi_service_gport_find(p_vsi_svc, svc_tag_indx, gport, &idx);
642 if(ret != BCM_ERR_OK)
643 {
644 BCM_LOG(ERROR, log_id_sw_util, "Error, vsi service port find for gport %d failed\n", gport);
645 return ret;
646 }
647 /* only remove from the array when no flow reference it */
648 if(p_vsi_svc->pkt_tag[svc_tag_indx].port[idx].use_count > 1)
649 {
650 (p_vsi_svc->pkt_tag[svc_tag_indx].port[idx].use_count)--;
651 return BCM_ERR_OK;
652 }
653
654 port = p_vsi_svc->pkt_tag[svc_tag_indx].port[idx].port;
655
656 /* compact the port list */
657 for(i=idx; i<p_vsi_svc->pkt_tag[svc_tag_indx].num_port-1; i++)
658 {
659 p_vsi_svc->pkt_tag[svc_tag_indx].port[i] = p_vsi_svc->pkt_tag[svc_tag_indx].port[i+1];
660 }
661 memset(&p_vsi_svc->pkt_tag[svc_tag_indx].port[i], 0, sizeof (bal_sw_lif_port));
662
663 (p_vsi_svc->pkt_tag[svc_tag_indx].num_port)--;
664
665 ret = BCM_ERR_OK;
666 do
667 {
668 /* find the encap_id */
669 rv = bcm_multicast_vlan_encap_get(unit, p_vsi_svc->us_flood_grp_id, port, gport, &port_encap_id);
670 if (rv != BCM_E_NONE)
671 {
672 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_multicast_vlan_encap_get for port %d failed %d\n", port, rv);
673 ret = BCM_ERR_NOENT;
674 break;
675 }
676 /* remove from the upstream flooding group */
677 rv = bcm_multicast_ingress_delete(unit, p_vsi_svc->us_flood_grp_id, port, port_encap_id);
678 if (rv != BCM_E_NONE)
679 {
680 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_multicast_ingress_delete for port %d failed %d\n", port, rv);
681 ret = BCM_ERR_NOENT;
682 break;
683 }
684 rv = bcm_vswitch_port_delete(unit, p_vsi_svc->vswitch, gport);
685 if (rv != BCM_E_NONE)
686 {
687 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_vswitch_port_delete for port %d failed %d\n", port, rv);
688 ret = BCM_ERR_NOENT;
689 break;
690 }
691 rv = bcm_vlan_port_destroy(unit, gport);
692 if (rv != BCM_E_NONE)
693 {
694 BCM_LOG(WARNING, log_id_sw_util, "Error, bcm_vlan_port_destroy for port %d failed %d\n", port, rv);
695 /* Likely a bug in the 6.5.4 release, igore for now
696 ret = BCM_ERR_NOENT;
697 break;
698 */
699 }
700 }while(0);
701 return ret;
702}
703
704/**
705 * @brief The vsi_service_tag_add function add the service tag of a flow to a vsi target service.
706 *
707 * @param unit switch device id
708 * @param p_vsi_target a pointer to the vsi service
709 * @param p_flow a pointer to a flow that define the service tag need to be added
710 * @param p_svc_tag_indx a pointer to store the return service tag index that just added
711 *
712 * @return error code
713 */
714bcmos_errno bal_sw_util_dpp_vsi_service_tag_add(int unit, bal_sw_vsi_service *p_vsi_target, bcmbal_flow_cfg *p_flow, uint32_t *p_svc_tag_indx)
715{
716 bal_sw_lif_pkt_tag svc_pkt_tag = {0};
717 bal_sw_vsi_service *p_vsi_service;
718
719 /* input parameters checking */
720 if (p_flow == NULL || p_vsi_target == NULL || p_svc_tag_indx == NULL)
721 {
722 BCM_LOG(ERROR, log_id_sw_util, "invalid parameters when adding vsi service tag \n");
723 return BCM_ERR_PARM;
724 }
725
726 /* find out if the service tag already exist */
727 svc_pkt_tag.type = p_flow->data.classifier.pkt_tag_type;
728 svc_pkt_tag.o_vid = p_flow->data.classifier.o_vid;
729 svc_pkt_tag.i_vid = p_flow->data.classifier.i_vid;
730 p_vsi_service = bal_sw_util_dpp_vsi_service_get_by_tag(&svc_pkt_tag, p_svc_tag_indx);
731 if (p_vsi_service)
732 {
733 /* if the service tag already exist in the system, it has to be within the same vsi.
734 We don't allow same service tag to be serviced by more than one vsi
735 */
736 if(p_vsi_service != p_vsi_target)
737 {
738 return BCM_ERR_INTERNAL;
739 }
740 else
741 {
742 return BCM_ERR_OK;
743 }
744 }
745
746 /* now add the tag to the list */
747 p_vsi_target->pkt_tag[p_vsi_target->num_tag] = svc_pkt_tag;
748 *p_svc_tag_indx = p_vsi_target->num_tag;
749 p_vsi_target->num_tag ++;
750 return BCM_ERR_OK;
751}
752
753/**
754 * @brief The vsi_service_tag_rem function remove the service tag index by svc_tag_indx from a vsi service.
755 *
756 * @param unit switch device id
757 * @param p_vsi_svc a pointer to the vsi service
758 * @param svc_tag_indx a service tag index point to the service tag list that need to be removed
759 *
760 * @return error code
761 */
762bcmos_errno bal_sw_util_dpp_vsi_service_tag_rem(int unit, bal_sw_vsi_service *p_vsi_svc, uint32_t svc_tag_indx)
763{
764 int i;
765 /* input parameters checking */
766 if (p_vsi_svc == NULL || p_vsi_svc->num_tag <= svc_tag_indx)
767 {
768 BCM_LOG(ERROR, log_id_sw_util, "invalid parameters when removing vsi service tag \n");
769 return BCM_ERR_PARM;
770 }
771 /* compact the tag list */
772 for(i=svc_tag_indx; i<p_vsi_svc->num_tag-1; i++)
773 {
774 p_vsi_svc->pkt_tag[i] = p_vsi_svc->pkt_tag[i+1];
775 }
776 memset(&p_vsi_svc->pkt_tag[i], 0, sizeof (bal_sw_lif_pkt_tag));
777
778 (p_vsi_svc->num_tag)--;
779 return BCM_ERR_OK;
780}
781
782#endif /* #ifndef TEST_SW_UTIL_LOOPBACK */
783/*@}*/
784
785