blob: 05894fdf6646f2897e590ef4b14dc23b396047b2 [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_group.c
34 * @brief BAL Switch util helper functions that handle group 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/multicast.h>
55
56#include "bal_dpp_group.h"
57#include "bal_switch_acc_term.h"
58#include "bal_dpp_vswitch.h"
59
60
61
62/* A local link list to keep track of group list */
63TAILQ_HEAD(bal_sw_group_list_head, bal_sw_group_list) g_swutil_group_list;
64
65/**
66 * @brief The group list init function prepare a link list to keep track of
67 * multicast group in the switch util
68 *
69 * @return error code
70 */
71bcmos_errno bal_sw_util_dpp_group_list_init(void)
72{
73 TAILQ_INIT(&g_swutil_group_list);
74 return BCM_ERR_OK;
75}
76
77/**
78 * @brief The group list finish function release all resources allocated in the list
79 *
80 * @return error code
81 */
82bcmos_errno bal_sw_util_dpp_group_list_finish(void)
83{
84 bal_sw_group_list *current_entry, *p_temp_entry;
85
86 /* Free all the entries in the list */
87 TAILQ_FOREACH_SAFE(current_entry,
88 &g_swutil_group_list,
89 next_grp,
90 p_temp_entry)
91 {
92 /* Remove it from the list */
93 TAILQ_REMOVE(&g_swutil_group_list, current_entry, next_grp);
94
95 bcmos_free(current_entry);
96 }
97
98 return BCM_ERR_OK;
99}
100
101/**
102 * @brief The group list search function by BAL group id
103 *
104 * @param grp_id the group id that need to match the entry in the list
105 * @return pointer to an element in the list, NULL if search failed
106 */
107bal_sw_group_list *bal_sw_util_dpp_group_list_get_by_id(uint32_t grp_id)
108{
109 bal_sw_group_list *p_entry, *p_temp;
110
111 TAILQ_FOREACH_SAFE(p_entry, &g_swutil_group_list, next_grp, p_temp)
112 {
113 if( p_entry->bal_grp_id == grp_id)
114 {
115 break;
116 }
117 }
118 /* if reach the end of the list, TAILQ_FOREACH_SAFE set the p_entry to NULL */
119 return p_entry;
120
121}
122
123/*
124 * @brief The group list insert function
125 *
126 * @param entry the group element to be added in the link list
127 * @return pointer to the newly inserted group in the list, NULL if operation failed
128*/
129static bal_sw_group_list *bal_sw_util_group_list_insert(bal_sw_group_list entry)
130{
131 bal_sw_group_list *p_new_entry;
132
133 p_new_entry = bcmos_calloc(sizeof(bal_sw_group_list));
134 if(NULL == p_new_entry)
135 {
136 BCM_LOG(ERROR, log_id_sw_util, "GROUP list insert out of memory\n");
137 return NULL;
138 }
139 *p_new_entry = entry;
140 TAILQ_INSERT_TAIL(&g_swutil_group_list, p_new_entry, next_grp);
141 return p_new_entry;
142}
143
144/*
145 * @brief The group list remove function
146 *
147 * @param p_entry Pointer to the group element in the link list result from the search functions
148 * @return error code
149*/
150static bcmos_errno bal_sw_util_group_list_remove(bal_sw_group_list *p_entry)
151{
152 TAILQ_REMOVE(&g_swutil_group_list, p_entry, next_grp);
153 bcmos_free(p_entry);
154 return BCM_ERR_OK;
155}
156
157/**
158 * @brief The group list membership check function by port
159 * Validate if interface/svervice_port is already a member
160 *
161 * @param p_grp_port the interface that need to be matched in the list
162 * @param p_entry pointer to an entry in the group list
163 * @return index to the port member, -1 if not found
164 */
165static int bal_sw_util_dpp_group_list_membership_check(bal_sw_group_list *p_entry, bal_sw_group_port *p_grp_port)
166{
167 int i;
168
169 if(p_entry == NULL)
170 {
171 BCM_LOG(ERROR, log_id_sw_util, "group membership check with NULL parameter\n");
172 return BCMOS_FALSE;
173 }
174
175 for(i=0; i<p_entry->num_port; i++)
176 {
177 if(p_entry->port[i].port == p_grp_port->port &&
178 p_entry->port[i].svc_port == p_grp_port->svc_port)
179 {
180 p_grp_port->gport = p_entry->port[i].gport;
181 return i;
182 }
183 }
184 return -1;
185}
186
187/**
188 * @brief The group list membership remove function by port
189 * remove interface/svervice_port from the group membership
190 *
191 * @param grp_port the interface that need to be matched in the list
192 * @param p_entry pointer to an entry in the group list
193 * @return boolen TRUE or FALSE
194 */
195static bcmos_bool bal_sw_util_dpp_group_list_membership_rem(bal_sw_group_list *p_entry, bal_sw_group_port grp_port)
196{
197 int i, rv;
198
199 if(p_entry == NULL)
200 {
201 BCM_LOG(ERROR, log_id_sw_util, "group membership remove with NULL parameter\n");
202 return BCMOS_FALSE;
203 }
204
205 for(i=0; i<p_entry->num_port; i++)
206 {
207 if(p_entry->port[i].port == grp_port.port &&
208 p_entry->port[i].svc_port == grp_port.svc_port)
209 {
210 /* destroy the vlan port (i.e., PON LIF) */
211 if(p_entry->port[i].gport)
212 {
213 rv = bcm_vlan_port_destroy(p_entry->device, p_entry->port[i].gport);
214 if (rv != BCM_E_NONE)
215 {
216 BCM_LOG(WARNING, log_id_sw_util, "Warning, GROUP:bcm_vlan_port_destroy pon %d failed %d\n", p_entry->port[i].gport, rv);
217 /* Likely a bug in the 6.5.4 release, ignore for now
218 return BCMOS_FALSE;
219 */
220 }
221 p_entry->port[i].gport = 0;
222 }
223 break;
224 }
225 }
226
227 /* if can't find the port, just return OK */
228 if(i != p_entry->num_port)
229 {
230 /* pack the list */
231 bal_sw_group_port null_port={0};
232 for(; i<p_entry->num_port-1; i++)
233 {
234 p_entry->port[i] = p_entry->port[i+1];
235 }
236 p_entry->port[i] = null_port;
237 p_entry->num_port--;
238 }
239
240 return BCMOS_TRUE;
241}
242
243
244/**
245 * @brief The group create function create a multicast group that contains egress LIF.
246 * This group can later connects to virtual switch in multiple FLOWs.
247 *
248 * The pointer of the created group will be returned
249 *
250 * @param unit switch device id
251 * @param p_grp a pointer to the multicast group definition
252 *
253 * @return pointer to the group list entry, NULL if operation failed
254 */
255
256bal_sw_group_list *bal_sw_util_dpp_group_create(int unit, bcmbal_group_cfg *p_grp)
257{
258 bal_sw_group_list *p_grp_list, grp_list_elm;
259 int32_t multicast_id;
260 uint32_t svc_indx;
261 int rv, flags;
262 bal_sw_vsi_service *p_vsi_service;
263
264 if(p_grp == NULL)
265 {
266 BCM_LOG(ERROR, log_id_sw_util, "group create with NULL parameter\n");
267 return NULL;
268 }
269 /* check group list */
270 p_grp_list = bal_sw_util_dpp_group_list_get_by_id(p_grp->key.group_id);
271 if(p_grp_list)
272 {
273 BCM_LOG(ERROR, log_id_sw_util, "group create with group id %d already existed\n", p_grp->key.group_id);
274 return NULL;
275 }
276 /* alloc an entry in the group list*/
277 memset(&grp_list_elm, 0, sizeof(bal_sw_group_list));
278 grp_list_elm.device = unit;
279 grp_list_elm.bal_grp_id = p_grp->key.group_id;
280 p_grp_list = bal_sw_util_group_list_insert(grp_list_elm);
281 if(p_grp_list == NULL)
282 {
283 BCM_LOG(ERROR, log_id_sw_util, "group create failed insert to group list\n");
284 return NULL;
285 }
286
287 /* create a vswitch with empty service, we need vsi to create the MC flooding group for egress */
288 p_vsi_service = bal_sw_util_dpp_vsi_service_create(unit, NULL, &svc_indx);
289 if(NULL == p_vsi_service)
290 {
291 BCM_LOG(ERROR, log_id_sw_util, "create vsi service for group failed \n");
292 bal_sw_util_group_list_remove(p_grp_list);
293 return NULL;
294 }
295
296 p_grp_list->p_vsi = p_vsi_service;
297
298 multicast_id = p_vsi_service->vswitch + BAL_DPP_MC_OFFSET;
299
300 rv = bcm_multicast_group_is_free(unit, multicast_id);
301 if (rv == BCM_E_EXISTS)
302 {
303 rv = bcm_multicast_destroy(unit, multicast_id);
304 if (rv != BCM_E_NONE)
305 {
306 BCM_LOG(ERROR, log_id_sw_util, "MC: bcm_multicast_destroy 0x%x failed %d \n", multicast_id, rv);
307 bal_sw_util_group_list_remove(p_grp_list);
308 return NULL;
309 }
310 }
311 flags = BCM_MULTICAST_INGRESS_GROUP | BCM_MULTICAST_WITH_ID | BCM_MULTICAST_TYPE_L2;
312 rv = bcm_multicast_create(unit, flags, &multicast_id);
313 if (rv != BCM_E_NONE)
314 {
315 BCM_LOG(ERROR, log_id_sw_util, "MC: in bcm_multicast_create 0x%x w ingress failed %d \n", multicast_id, rv);
316 bal_sw_util_group_list_remove(p_grp_list);
317
318 return NULL;
319 }
320 else
321 {
322 BCM_LOG(INFO, log_id_sw_util, "MC: vswitch flood group 0x%x created\n", multicast_id);
323 }
324
325 /* update the group list info */
326 p_grp_list->l2_grp_id = multicast_id;
327 return p_grp_list;
328}
329
330/**
331 * @brief The group add function add members to the multicast group.
332 * In this function, gourp members are PON interfaces
333 *
334 * @param unit switch device id
335 * @param p_grp a pointer to the multicast group definition
336 *
337 * @return error code
338 */
339
340bcmos_errno bal_sw_util_dpp_group_add(int unit, bcmbal_group_cfg *p_grp)
341{
342 bal_sw_group_list *p_grp_list;
343 int i, pon, rv, indx;
344 bcm_gport_t pon_gport;
345 bcmos_errno ret;
346 int pon_encap_id;
347 bcm_vlan_port_t vp;
348 uint32_t flood_grp;
349
350 if(p_grp == NULL)
351 {
352 BCM_LOG(ERROR, log_id_sw_util, "group add with NULL parameter\n");
353 return BCM_ERR_PARM;
354 }
355 /* check if L2 group has been created */
356 p_grp_list = bal_sw_util_dpp_group_list_get_by_id(p_grp->key.group_id);
357 if(!p_grp_list)
358 {
359 BCM_LOG(INFO, log_id_sw_util, "group add will alloc a L2 MC group, group id %d \n", p_grp->key.group_id);
360 p_grp_list = bal_sw_util_dpp_group_create(unit, p_grp);
361 if(p_grp_list == NULL)
362 {
363 BCM_LOG(ERROR, log_id_sw_util, "group add failed create L2 Mc group\n");
364 return BCM_ERR_NORES;
365 }
366 }
367
368
369 ret = BCM_ERR_OK;
370
371 for(i=0; i<p_grp->data.members.len; i++)
372 {
373 bcmbal_group_member_info *p_member = &p_grp->data.members.val[i];
374 bal_sw_group_port port_member;
375
376 /* find the L2 logical interface number */
377 pon = bal_bcm_pon_inf_pbm_get(p_member->intf_id);
378
379 /* check if interface is already a member in the group list */
380 port_member.port = pon;
381 port_member.svc_port = p_member->svc_port_id;
382 if( -1 != bal_sw_util_dpp_group_list_membership_check(p_grp_list, &port_member))
383 {
384 BCM_LOG(INFO, log_id_sw_util, "pon interface %d with service port %d already a member\n",p_member->intf_id, p_member->svc_port_id);
385 continue;
386 }
387
388 /* check if interface already has an entry in the group list */
389 port_member.port = pon;
390 port_member.svc_port = 0;
391 indx = bal_sw_util_dpp_group_list_membership_check(p_grp_list, &port_member);
392 if( -1 == indx)
393 {
394 /* make sure there is still room in the group list for new member */
395 if(p_grp_list->num_port >= MAX_PON_PORT)
396 {
397 BCM_LOG(ERROR, log_id_sw_util,
398 "Error, GROUP: Reach maximum number of membership in the group list\n");
399 ret = BCM_ERR_NORES;
400 break;
401 }
402 }
403 /* if group has a owner, create a LIF for each member */
404 if(p_grp->data.owner != BCMBAL_GROUP_OWNER_NONE)
405 {
406 /* Map the tunnel ID to a PON channel OTM port */
407 rv = bcm_port_pon_tunnel_map_set(unit,
408 pon,
409 p_member->svc_port_id,
410 pon);
411 if (rv != BCM_E_NONE)
412 {
413 BCM_LOG(ERROR, log_id_sw_util,
414 "Error, GROUP:bcm_port_pon_tunnel_map_set on pon %d failed %d"
415 " (have you chosen the correct intf_maptable?)\n", pon, rv);
416 ret = BCM_ERR_INTERNAL;
417 break;
418 }
419
420 /* Create the pon LIF to be DS only */
421 bcm_vlan_port_t_init(&vp);
422
423 /* preserve any incoming packet vlan tags, if vlan actions are required, do it using egress translation */
424 vp.flags = BCM_VLAN_PORT_OUTER_VLAN_PRESERVE | BCM_VLAN_PORT_INNER_VLAN_PRESERVE;
425 /* It is required to set the FEC flag so that the egress redirection action from the DS classification can
426 select the correct PON LIF to forward the packet */
427 vp.flags |= BCM_VLAN_PORT_FORWARD_GROUP;
428
429 vp.criteria = BCM_VLAN_PORT_MATCH_PORT_TUNNEL;
430
431 vp.port = pon;
432 vp.match_tunnel_value = p_member->svc_port_id;
433 vp.egress_tunnel_value = p_member->svc_port_id;
434
435 vp.vsi = 0; /* will be populated when the gport is added to service, using vswitch_port_add */
436
437 /* Create the vlan port (i.e., PON LIF) */
438 rv = bcm_vlan_port_create(unit, &vp);
439 if (rv != BCM_E_NONE)
440 {
441 BCM_LOG(ERROR, log_id_sw_util, "Error, GROUP:bcm_vlan_port_create pon %d failed %d\n", pon, rv);
442 ret = BCM_ERR_INTERNAL;
443 break;
444 }
445 else
446 {
447 BCM_LOG(INFO, log_id_sw_util, "Info, GROUP:bcm_vlan_port_create pon %d with tunnel %d success\n", pon, p_member->svc_port_id);
448 }
449
450 pon_gport = vp.vlan_port_id;
451 rv = bcm_port_discard_set(unit, pon_gport, BCM_PORT_DISCARD_INGRESS);
452 if (rv != BCM_E_NONE)
453 {
454 BCM_LOG(ERROR, log_id_sw_util, "Error, GROUP:bcm_port_discard_set on pon %d failed %d\n", pon, rv);
455 ret = BCM_ERR_INTERNAL;
456 break;
457 }
458 /* select the flooding group */
459 if(p_grp->data.owner == BCMBAL_GROUP_OWNER_MULTICAST)
460 {
461 flood_grp = p_grp_list->l2_grp_id;
462 }
463 else
464 {
465 flood_grp = (p_grp_list->p_vsi)->ds_flood_grp_id;
466 }
467 /* join the L2 multicast group */
468 rv = bcm_multicast_vlan_encap_get(unit, flood_grp, pon, pon_gport, &pon_encap_id);
469 if (rv != BCM_E_NONE)
470 {
471 BCM_LOG(ERROR, log_id_sw_util, "Error, GROUP:bcm_vlan_encap_get on pon %d failed %d\n", pon, rv);
472 ret = BCM_ERR_INTERNAL;
473 break;
474 }
475 rv = bcm_multicast_ingress_add(unit, flood_grp, pon, pon_encap_id);
476 if (rv != BCM_E_NONE)
477 {
478 BCM_LOG(ERROR, log_id_sw_util, "Error, GROUP:bcm_multicast_ingress_add on pon %d failed %d\n", pon, rv);
479 ret = BCM_ERR_INTERNAL;
480 break;
481 }
482
483 BCM_LOG(INFO, log_id_sw_util, "Info, GROUP:pon %d join l2 mc group 0x%x success\n", pon, flood_grp);
484 /* update the group list membership */
485 port_member.gport = pon_gport;
486 }
487 else
488 {
489 port_member.gport = 0;
490 }
491 p_grp_list->port[p_grp_list->num_port] = port_member;
492 p_grp_list->num_port++;
493
494 }
495
496
497 return ret;
498}
499
500
501/**
502 * @brief The group remove function remove members from the multicast group.
503 * In this function, group members are PON interfaces
504 *
505 * @param unit switch device id
506 * @param p_grp a pointer to the multicast group definition
507 *
508 * @return error code
509 */
510
511bcmos_errno bal_sw_util_dpp_group_rem(int unit, bcmbal_group_cfg *p_grp)
512{
513 bal_sw_group_list *p_grp_list;
514 int i, pon, rv;
515 bcmos_errno ret;
516 int pon_encap_id;
517
518 if(p_grp == NULL)
519 {
520 BCM_LOG(ERROR, log_id_sw_util, "group remove with NULL parameter\n");
521 return BCM_ERR_PARM;
522 }
523 /* check if L2 group has been created */
524 p_grp_list = bal_sw_util_dpp_group_list_get_by_id(p_grp->key.group_id);
525 if(!p_grp_list)
526 {
527 BCM_LOG(ERROR, log_id_sw_util, "group remove can not find L2 Mc group %d\n", p_grp->key.group_id);
528 return BCM_ERR_INTERNAL;
529 }
530
531 /* remove LIF for each member */
532 ret = BCM_ERR_OK;
533 for(i=0; i<p_grp->data.members.len; i++)
534 {
535 bcmbal_group_member_info *p_member = &p_grp->data.members.val[i];
536 bal_sw_group_port port_member;
537
538 /* find the L2 logical interface number */
539 pon = bal_bcm_pon_inf_pbm_get(p_member->intf_id);
540
541 /* check if interface is already removed from the group list */
542 port_member.port = pon;
543 port_member.svc_port = p_member->svc_port_id;
544 if( -1 == bal_sw_util_dpp_group_list_membership_check(p_grp_list, &port_member))
545 {
546 BCM_LOG(INFO, log_id_sw_util, "pon interface %d with service port %d is not a member\n",p_member->intf_id, p_member->svc_port_id);
547 continue;
548 }
549
550 /* if the member has a LIF assigned, remove it from the switch multicast group */
551 if(port_member.gport)
552 {
553 /* leave the L2 multicast group */
554 rv = bcm_multicast_vlan_encap_get(unit, p_grp_list->l2_grp_id, pon, port_member.gport, &pon_encap_id);
555 if (rv != BCM_E_NONE)
556 {
557 BCM_LOG(ERROR, log_id_sw_util, "Error, GROUP:bcm_vlan_encap_get on pon %d failed %d\n", pon, rv);
558 ret = BCM_ERR_INTERNAL;
559 break;
560 }
561 rv = bcm_multicast_ingress_delete(unit, p_grp_list->l2_grp_id, pon, pon_encap_id);
562 if (rv != BCM_E_NONE)
563 {
564 BCM_LOG(ERROR, log_id_sw_util, "Error, GROUP:bcm_multicast_ingress_delete on pon %d failed %d\n", pon, rv);
565 ret = BCM_ERR_INTERNAL;
566 break;
567 }
568 }
569 if( BCMOS_FALSE == bal_sw_util_dpp_group_list_membership_rem(p_grp_list, port_member))
570 {
571 BCM_LOG(INFO, log_id_sw_util, "pon interface %d with service port %d membership remove failed\n",p_member->intf_id, p_member->svc_port_id);
572 ret = BCM_ERR_INTERNAL;
573 break;
574 }
575 }
576
577 return ret;
578}
579
580/**
581 * @brief The group set function replace members from the multicast group.
582 * In this function, group members are PON interfaces
583 *
584 * @param unit switch device id
585 * @param p_grp a pointer to the multicast group definition
586 *
587 * @return error code
588 */
589
590bcmos_errno bal_sw_util_dpp_group_set(int unit, bcmbal_group_cfg *p_grp)
591{
592 bal_sw_group_list *p_grp_list;
593 bcmos_errno ret = BCM_ERR_OK;
594 int pon_encap_id;
595
596 if(p_grp == NULL)
597 {
598 BCM_LOG(ERROR, log_id_sw_util, "group replace with NULL parameter\n");
599 return BCM_ERR_PARM;
600 }
601 /* check if L2 group has been created */
602 p_grp_list = bal_sw_util_dpp_group_list_get_by_id(p_grp->key.group_id);
603 if(!p_grp_list)
604 {
605 /* mark it OK to create group at the end */
606 ret = BCM_ERR_OK;
607 }
608 else if(p_grp_list->num_port)
609 {
610 /* remove all members from the group */
611 do
612 {
613 if( p_grp_list->port[0].gport)
614 {
615 /* leave the L2 multicast group */
616 if (BCM_E_NONE != bcm_multicast_vlan_encap_get(unit, p_grp_list->l2_grp_id, p_grp_list->port[0].port, p_grp_list->port[0].gport, &pon_encap_id))
617 {
618 BCM_LOG(ERROR, log_id_sw_util, "Error, GROUP:bcm_vlan_encap_get on pon %d failed\n", p_grp_list->port[0].port);
619 ret = BCM_ERR_INTERNAL;
620 break;
621 }
622 if (BCM_E_NONE != bcm_multicast_ingress_delete(unit, p_grp_list->l2_grp_id, p_grp_list->port[0].port, pon_encap_id))
623 {
624 BCM_LOG(ERROR, log_id_sw_util, "Error, GROUP:bcm_multicast_ingress_delete on pon %d failed\n", p_grp_list->port[0].port);
625 ret = BCM_ERR_INTERNAL;
626 break;
627 }
628 }
629 if( BCMOS_FALSE == bal_sw_util_dpp_group_list_membership_rem(p_grp_list, p_grp_list->port[0]))
630 {
631 BCM_LOG(ERROR, log_id_sw_util, "group set fail to remove existing member interface %d\n",p_grp_list->port[0].port );
632 ret = BCM_ERR_INTERNAL;
633 break;
634 }
635 }while(p_grp_list->num_port);
636 }
637
638 if(ret == BCM_ERR_OK)
639 {
640 /* create/add the group */
641 return bal_sw_util_dpp_group_add(unit, p_grp);
642 }
643 return ret;
644}
645
646/**
647 * @brief The group destroy function free up a multicast group.
648 * The group will be removed from the group list.
649 * All L2 resources accociated with the group will be free.
650 *
651 * @param unit switch device id
652 * @param p_grp a pointer to the multicast group definition
653 *
654 * @return error code
655 */
656
657bcmos_errno bal_sw_util_dpp_group_destroy(int unit, bcmbal_group_cfg *p_grp)
658{
659 bal_sw_group_list *p_grp_list;
660 int rv;
661 bcmos_errno ret;
662
663 if(p_grp == NULL)
664 {
665 BCM_LOG(ERROR, log_id_sw_util, "group destroy with NULL parameter\n");
666 return BCM_ERR_PARM;
667 }
668 /* check group list */
669 p_grp_list = bal_sw_util_dpp_group_list_get_by_id(p_grp->key.group_id);
670 if(!p_grp_list)
671 {
672 BCM_LOG(INFO, log_id_sw_util, "group destroy with group id %d does not existed\n", p_grp->key.group_id);
673 return BCM_ERR_OK;
674 }
675 /* can't destroy if any flow is still reference it */
676 if(p_grp_list->use_count)
677 {
678 BCM_LOG(WARNING, log_id_sw_util, "group destroy with group id %d is busy\n", p_grp->key.group_id);
679 return BCM_ERR_INVALID_OP;
680 }
681
682 /* Do our best to clean up */
683 /* free resources used by all members */
684 ret = bal_sw_util_dpp_group_rem(unit, p_grp);
685 if (ret != BCM_ERR_OK)
686 {
687 BCM_LOG(ERROR, log_id_sw_util, "MC: destroy group 0x%x failed to free members \n", p_grp_list->l2_grp_id);
688 }
689
690 /* free the L2 multicast group */
691 rv = bcm_multicast_destroy(unit, p_grp_list->l2_grp_id);
692 if (rv != BCM_E_NONE)
693 {
694 BCM_LOG(ERROR, log_id_sw_util, "MC: in bcm_multicast_destroy 0x%x failed %d \n", p_grp_list->l2_grp_id, rv);
695 }
696
697 /* clean up the vsi */
698 bal_sw_util_dpp_vsi_service_destroy(unit, p_grp_list->p_vsi);
699 /* remove from the list */
700 bal_sw_util_group_list_remove(p_grp_list);
701
702 return BCM_ERR_OK;
703}
704
705#endif /* LOOPBACK */
706/*@}*/