2 * Efficient Multicast Forwarding Layer: This module does the efficient
3 * layer 2 forwarding of multicast streams, i.e., forward the streams
4 * only on to the ports that have corresponding group members there by
5 * reducing the bandwidth utilization and latency. It uses the information
6 * updated by IGMP Snooping layer to do the optimal forwarding. This file
7 * contains the common code routines of EMFL.
9 * Copyright (C) 2009, Broadcom Corporation
10 * All Rights Reserved.
12 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
13 * the contents of this file may not be disclosed to third parties, copied
14 * or duplicated in any form, in whole or in part, without the prior
15 * written permission of Broadcom Corporation.
17 * $Id: emfc.c,v 1.4 2010/02/17 23:36:15 Exp $
21 #include <bcmendian.h>
22 #include <proto/ethernet.h>
23 #include <proto/bcmip.h>
26 #include <osl_linux.h>
27 #else /* defined(osl_xx) */
28 #error "Unsupported osl"
29 #endif /* defined(osl_xx) */
33 #include "emfc_export.h"
35 #include "emf_export.h"
37 static CLIST_DECL_INIT(emfc_list_head
);
38 static osl_lock_t emfc_list_lock
;
41 emfc_instance_find(char *inst_id
)
48 EMF_ERROR("Invalid instance id string\n");
52 OSL_LOCK(emfc_list_lock
);
54 for (ptr
= emfc_list_head
.next
; ptr
!= &emfc_list_head
;
57 emfc
= clist_entry(ptr
, emfc_info_t
, emfc_list
);
59 if (strcmp(inst_id
, emfc
->inst_id
) == 0)
61 OSL_UNLOCK(emfc_list_lock
);
66 OSL_UNLOCK(emfc_list_lock
);
72 * Description: This function is called by the IGMP snooper layer to
73 * register snooper instance with EMFL.
75 * Input: inst_id - Instance identier used to associate EMF
76 * and IGMP snooper instances.
77 * emfc - EMFL Common code global instance handle
78 * snooper - Contains snooper specific parameters and
79 * event callback functions. These functions
80 * are called by EMFL on events like IGMP
81 * packet receive, EMF enable and disable.
82 * The snooper parameter needs to global or
85 * Return: SUCCESS or FAILURE
88 emfc_igmp_snooper_register(int8
*inst_id
, emfc_info_t
**emfc
, emfc_snooper_t
*snooper
)
93 EMF_ERROR("Snooper parameter should be non NULL\n");
99 EMF_ERROR("EMF handle should be non NULL\n");
103 /* Validate the instance id */
104 if ((*emfc
= emfc_instance_find(inst_id
)) == NULL
)
106 EMF_ERROR("EMF Instance doesn't exist\n");
110 if (snooper
->input_fn
== NULL
)
112 EMF_ERROR("Snooper input function should be non NULL\n");
116 (*emfc
)->snooper
= snooper
;
122 * Description: This function is called by the IGMP snooper layer
123 * to unregister snooper instance.
125 * Input: handle - Handle returned during registration.
126 * snooper - Contains snooper specific parameters and
129 emfc_igmp_snooper_unregister(emfc_info_t
*emfc
)
133 EMF_ERROR("Unregistering using invalid handle\n");
137 emfc
->snooper
= NULL
;
143 * Description: This function handles the unregistered frame forwarding.
144 * IGMP frames are forwarded on router ports. Data frames
145 * are flooded on to user configured UFFP.
147 * Input: emfc - EMFC Global instance data
148 * sdu - Pointer to packet buffer.
149 * ifp - Interface on which the packet arrived.
150 * dest_ip - Multicast destination IP address
151 * rt_port - TRUE when the packet is received from IP
152 * Stack otherwise FALSE.
154 * Return: EMF_TAKEN - EMF has taken the ownership of the packet.
155 * EMF_NOP - No processing needed by EMF, just return
157 * EMF_DROP - Drop and free the packet.
160 emfc_unreg_frame_handle(emfc_info_t
*emfc
, void *sdu
, void *ifp
, uint8 proto
,
161 uint32 dest_ip
, bool rt_port
)
165 uint32 mcast_flooded
= 0;
167 /* Forward the frame on to router port */
170 EMF_DEBUG("Sending frame on to router port\n");
172 if ((sdu_clone
= PKTDUP(emfc
->osh
, sdu
)) == NULL
)
174 EMFC_PROT_STATS_INCR(emfc
, proto
, igmp_frames_dropped
,
179 emfc
->wrapper
.sendup_fn(emfc
->emfi
, sdu_clone
);
181 EMFC_PROT_STATS_INCR(emfc
, proto
, igmp_frames_sentup
,
185 OSL_LOCK(emfc
->iflist_lock
);
187 /* Flood the frame on to user specified ports */
188 for (ptr
= emfc
->iflist_head
; ptr
!= NULL
; ptr
= ptr
->next
)
190 /* Dont forward the frame on to the port on which it
196 if (proto
== IP_PROT_IGMP
)
198 /* Dont forward IGMP frame if the port is not router port */
199 if (ptr
->rtport_ref
== 0)
204 /* Dont forward data frame if the port is neither router
207 if ((ptr
->rtport_ref
+ ptr
->uffp_ref
) == 0)
211 if ((sdu_clone
= PKTDUP(emfc
->osh
, sdu
)) == NULL
)
213 EMFC_PROT_STATS_INCR(emfc
, proto
, igmp_frames_dropped
,
215 OSL_UNLOCK(emfc
->iflist_lock
);
219 if (emfc
->wrapper
.forward_fn(emfc
->emfi
, sdu_clone
, dest_ip
,
220 ptr
->ifp
, rt_port
) != SUCCESS
)
222 EMF_INFO("Unable to flood the unreg frame on to %s\n",
223 DEV_IFNAME(ptr
->ifp
));
224 EMFC_PROT_STATS_INCR(emfc
, proto
, igmp_frames_dropped
,
231 OSL_UNLOCK(emfc
->iflist_lock
);
233 if (mcast_flooded
> 0)
235 EMFC_PROT_STATS_INCR(emfc
, proto
, igmp_frames_fwd
,
242 EMFC_PROT_STATS_INCR(emfc
, proto
, igmp_frames_dropped
,
247 PKTFREE(emfc
->osh
, sdu
, FALSE
);
253 * Description: This function is called from the registered OS hook
254 * points once for every frame. This function does the
255 * MFDB lookup, packet cloning and frame forwarding.
257 * Input: emfc - EMFC Global instance data
258 * sdu - Pointer to packet buffer.
259 * ifp - Interface on which the packet arrived.
260 * iph - Pointer to start of IP header.
261 * rt_port - TRUE when the packet is received from IP
262 * Stack otherwise FALSE.
264 * Return: EMF_NOP - No processing needed by EMF, just return
266 * EMF_TAKEN - EMF has taken the ownership of the packet.
267 * EMF_DROP - Drop and free the packet.
270 emfc_input(emfc_info_t
*emfc
, void *sdu
, void *ifp
, uint8
*iph
, bool rt_port
)
274 EMF_DEBUG("Received frame with dest ip %d.%d.%d.%d\n",
275 iph
[IPV4_DEST_IP_OFFSET
], iph
[IPV4_DEST_IP_OFFSET
+ 1],
276 iph
[IPV4_DEST_IP_OFFSET
+ 2], iph
[IPV4_DEST_IP_OFFSET
+ 3]);
278 dest_ip
= ntoh32(*((uint32
*)(iph
+ IPV4_DEST_IP_OFFSET
)));
280 /* No processing is required if the received frame is unicast or
281 * broadcast, when EMF is disabled. Send the frame back to bridge.
283 if ((!IP_ISMULTI(dest_ip
)) || (!emfc
->emf_enable
))
285 EMF_DEBUG("Unicast frame recevied/EMF disabled\n");
289 /* Non-IPv4 multicast packets are not handled */
290 if (IP_VER(iph
) != IP_VER_4
)
292 EMF_INFO("Non-IPv4 multicast packets will be flooded\n");
296 /* Check the protocol type of multicast frame */
297 if ((IPV4_PROT(iph
) == IP_PROT_IGMP
) && (emfc
->snooper
!= NULL
))
301 EMF_DEBUG("Received IGMP frame type %d\n", *(iph
+ IPV4_HLEN(iph
)));
303 EMFC_STATS_INCR(emfc
, igmp_frames
);
305 /* IGMP packet received from LAN or IP Stack. Call the IGMP
306 * Snooping function. Based on the IGMP packet type it may
307 * add/delete MFDB entry. Also the function return value
308 * tells whether to drop, forward, or flood the frame.
310 ASSERT(emfc
->snooper
->input_fn
);
311 action
= emfc
->snooper
->input_fn(emfc
->snooper
, ifp
, iph
,
312 iph
+ IPV4_HLEN(iph
), rt_port
);
317 EMF_INFO("Dropping the IGMP frame\n");
321 emfc
->wrapper
.sendup_fn(emfc
->emfi
, sdu
);
322 EMFC_STATS_INCR(emfc
, igmp_frames_sentup
);
326 return (emfc_unreg_frame_handle(emfc
, sdu
, ifp
,
331 EMF_DEBUG("Returning the IGMP frame to bridge\n");
332 EMFC_STATS_INCR(emfc
, igmp_frames_fwd
);
336 EMF_ERROR("Unknown return value from IGMP Snooper\n");
337 EMFC_STATS_INCR(emfc
, igmp_frames_fwd
);
350 EMF_DEBUG("Received frame with proto %d\n", IPV4_PROT(iph
));
352 EMFC_STATS_INCR(emfc
, mcast_data_frames
);
354 /* Packets with destination IP address in the range 224.0.0.x
355 * must be forwarded on all ports. Similarly UPnP specific
356 * protocol traffic such as SSDP must be forwarded on to all
359 if (MCAST_ADDR_LINKLOCAL(dest_ip
) || MCAST_ADDR_UPNP_SSDP(dest_ip
))
361 EMF_DEBUG("Flooding the frames with link-local/ssdp address\n");
365 OSL_LOCK(emfc
->fdb_lock
);
367 /* Do the MFDB lookup to determine the destination port(s)
368 * to forward the frame.
370 mgrp
= emfc_mfdb_group_find(emfc
, dest_ip
);
372 /* If no matching MFDB entry is found send the frame back to
373 * bridge module so that it floods on to all the ports.
377 OSL_UNLOCK(emfc
->fdb_lock
);
378 EMF_DEBUG("MFDB Group entry not found\n");
379 return (emfc_unreg_frame_handle(emfc
, sdu
, ifp
,
384 ASSERT(!clist_empty(&mgrp
->mi_head
));
386 /* If the data frame is received from one of the bridge
387 * ports then a copy has to be sent up to the router port.
391 EMF_DEBUG("Sending to router port\n");
393 if ((sdu_clone
= PKTDUP(emfc
->osh
, sdu
)) == NULL
)
395 OSL_UNLOCK(emfc
->fdb_lock
);
396 EMFC_STATS_INCR(emfc
, mcast_data_dropped
);
400 emfc
->wrapper
.sendup_fn(emfc
->emfi
, sdu_clone
);
401 EMFC_STATS_INCR(emfc
, mcast_data_sentup
);
404 /* Data frame received from LAN or IP Stack (WAN). Clone
405 * the buffer and send on all but the last interface.
407 for (ptr
= mgrp
->mi_head
.next
;
408 ptr
!= mgrp
->mi_head
.prev
; ptr
= ptr
->next
)
410 mi
= clist_entry(ptr
, emfc_mi_t
, mi_list
);
412 /* Dont forward the frame on to the port on which it
415 if (ifp
== mi
->mi_mhif
->mhif_ifp
)
418 EMF_DEBUG("Cloning the buffer for forwarding\n");
420 if ((sdu_clone
= PKTDUP(emfc
->osh
, sdu
)) == NULL
)
422 OSL_UNLOCK(emfc
->fdb_lock
);
423 EMFC_STATS_INCR(emfc
, mcast_data_dropped
);
427 emfc
->wrapper
.forward_fn(emfc
->emfi
, sdu_clone
,
428 dest_ip
, mi
->mi_mhif
->mhif_ifp
, rt_port
) ?
429 EMFC_STATS_INCR(emfc
, mcast_data_dropped
) :
430 mi
->mi_mhif
->mhif_data_fwd
++,
434 /* Send the last frame without cloning */
435 mi
= clist_entry(ptr
, emfc_mi_t
, mi_list
);
437 /* Dont forward the frame on to the port on which it was received */
438 if (ifp
!= mi
->mi_mhif
->mhif_ifp
)
440 EMF_DEBUG("Sending the original packet buffer\n");
442 emfc
->wrapper
.forward_fn(emfc
->emfi
, sdu
, dest_ip
,
443 mi
->mi_mhif
->mhif_ifp
, rt_port
) ?
444 EMFC_STATS_INCR(emfc
, mcast_data_dropped
) :
445 mi
->mi_mhif
->mhif_data_fwd
++,
450 EMF_DEBUG("Freeing the original packet buffer\n");
451 PKTFREE(emfc
->osh
, sdu
, FALSE
);
454 EMFC_STATS_INCR(emfc
, mcast_data_fwd
);
456 OSL_UNLOCK(emfc
->fdb_lock
);
463 * Description: This function initializes the MFDB. MFDB group
464 * entries are organized as a hash table with chaining
465 * for collision resolution. Each MFDB group entry
466 * points to the chain of MFDB interface entries that are
467 * members of the group.
469 * Input: emfc - EMFL Common code global data handle
472 emfc_mfdb_init(emfc_info_t
*emfc
)
476 /* Initialize the multicast forwarding database */
477 for (i
= 0; i
< MFDB_HASHT_SIZE
; i
++)
479 clist_init_head(&emfc
->mgrp_fdb
[i
]);
482 /* Initialize the multicast interface list. This list contains
483 * all the interfaces that have multicast group members. Entries in
484 * this list are never expired/deleted. Each entry maintains stats
485 * specific to the interface.
487 emfc
->mhif_head
= NULL
;
493 * Description: This function does the MFDB lookup to locate interface
494 * entry of the specified group.
496 * Input: emfc - EMFL Common code global data handle
497 * mgrp - Pointer to multicast group entry of MFDB
498 * ifp - Interface pointer to locate.
500 * Return: Returns pointer to the MFDB interface entry, NULL
504 emfc_mfdb_mi_entry_find(emfc_info_t
*emfc
, emfc_mgrp_t
*mgrp
, void *ifp
)
511 for (ptr
= mgrp
->mi_head
.next
;
512 ptr
!= &mgrp
->mi_head
; ptr
= ptr
->next
)
514 mi
= clist_entry(ptr
, emfc_mi_t
, mi_list
);
515 if (ifp
== mi
->mi_mhif
->mhif_ifp
)
525 * Description: This function does the MFDB lookup to locate a multicast
528 * Input: emfc - EMFL Common code global data handle
529 * mgrp_ip - Multicast group address of the entry.
531 * Return: Returns NULL is no group entry is found. Otherwise
532 * returns pointer to the MFDB group entry.
535 emfc_mfdb_group_find(emfc_info_t
*emfc
, uint32 mgrp_ip
)
541 ASSERT(IP_ISMULTI(mgrp_ip
));
543 /* Do the cache lookup first. Since the multicast video traffic
544 * is bursty in nature there is a good chance that the cache
545 * hit ratio will be good. If during the testing we find that
546 * the hit ratio is not as good then this single entry cache
547 * mechanism will be removed.
549 if (mgrp_ip
== emfc
->mgrp_cache_ip
)
551 EMFC_STATS_INCR(emfc
, mfdb_cache_hits
);
552 return (emfc
->mgrp_cache
);
555 EMFC_STATS_INCR(emfc
, mfdb_cache_misses
);
557 hash
= MFDB_MGRP_HASH(mgrp_ip
);
559 for (ptr
= emfc
->mgrp_fdb
[hash
].next
;
560 ptr
!= &emfc
->mgrp_fdb
[hash
];
563 mgrp
= clist_entry(ptr
, emfc_mgrp_t
, mgrp_hlist
);
565 /* Compare group address */
566 if (mgrp_ip
== mgrp
->mgrp_ip
)
568 EMF_MFDB("Multicast Group entry %d.%d.%d.%d found\n",
569 (mgrp_ip
>> 24), ((mgrp_ip
>> 16) & 0xff),
570 ((mgrp_ip
>> 8) & 0xff), (mgrp_ip
& 0xff));
571 emfc
->mgrp_cache
= mgrp
;
572 emfc
->mgrp_cache_ip
= mgrp_ip
;
581 * Add the entry if not present otherwise return the pointer to
585 emfc_mfdb_mhif_add(emfc_info_t
*emfc
, void *ifp
)
587 emfc_mhif_t
*ptr
, *mhif
;
589 OSL_LOCK(emfc
->fdb_lock
);
591 for (ptr
= emfc
->mhif_head
; ptr
!= NULL
; ptr
= ptr
->next
)
593 if (ptr
->mhif_ifp
== ifp
)
595 OSL_UNLOCK(emfc
->fdb_lock
);
601 mhif
= MALLOC(emfc
->osh
, sizeof(emfc_mgrp_t
));
604 OSL_UNLOCK(emfc
->fdb_lock
);
605 EMF_ERROR("Failed to alloc mem size %d for mhif entry\n",
606 sizeof(emfc_mhif_t
));
610 mhif
->mhif_ifp
= ifp
;
611 mhif
->mhif_data_fwd
= 0;
612 mhif
->next
= emfc
->mhif_head
;
613 emfc
->mhif_head
= mhif
;
615 OSL_UNLOCK(emfc
->fdb_lock
);
621 * Description: This function does the MFDB lookup to locate a interface
622 * entry of the specified multicast group.
624 * Input: emfc - EMFL Common code global data handle
625 * mgrp_ip - Multicast group IP address of the entry.
626 * ifp - Pointer to the interface on which the member
629 * Return: Returns NULL is no interface entry is found. Otherwise
630 * returns pointer to the MFDB interface entry.
633 emfc_mfdb_membership_find(emfc_info_t
*emfc
, uint32 mgrp_ip
, void *ifp
)
638 ASSERT(IP_ISMULTI(mgrp_ip
));
640 OSL_LOCK(emfc
->fdb_lock
);
642 /* Find group entry */
643 mgrp
= emfc_mfdb_group_find(emfc
, mgrp_ip
);
647 /* Find interface entry */
648 mi
= emfc_mfdb_mi_entry_find(emfc
, mgrp
, ifp
);
651 EMF_MFDB("Interface entry %d.%d.%d.%d:%p found\n",
652 (mgrp_ip
>> 24), ((mgrp_ip
>> 16) & 0xff),
653 ((mgrp_ip
>> 8) & 0xff), (mgrp_ip
& 0xff), ifp
);
658 OSL_UNLOCK(emfc
->fdb_lock
);
660 EMF_MFDB("Interface entry %x %p not found\n", mgrp_ip
, ifp
);
666 * Description: This function is called by IGMP Snooper when it wants
667 * to add MFDB entry or refresh the entry. This function
668 * is also called by the management application to add a
671 * If the MFDB entry is not present, it allocates group
672 * entry, interface entry and links them together.
674 * Input: Same as above function.
676 * Return: SUCCESS or FAILURE
679 emfc_mfdb_membership_add(emfc_info_t
*emfc
, uint32 mgrp_ip
, void *ifp
)
685 ASSERT(IP_ISMULTI(mgrp_ip
));
687 OSL_LOCK(emfc
->fdb_lock
);
689 /* If the group entry doesn't exist, add a new entry and update
690 * the member/interface information.
692 mgrp
= emfc_mfdb_group_find(emfc
, mgrp_ip
);
696 /* Allocate and initialize multicast group entry */
697 mgrp
= MALLOC(emfc
->osh
, sizeof(emfc_mgrp_t
));
700 EMF_ERROR("Failed to alloc mem size %d for group entry\n",
701 sizeof(emfc_mgrp_t
));
702 OSL_UNLOCK(emfc
->fdb_lock
);
706 mgrp
->mgrp_ip
= mgrp_ip
;
707 clist_init_head(&mgrp
->mi_head
);
709 EMF_MFDB("Adding group entry %d.%d.%d.%d\n",
710 (mgrp_ip
>> 24), ((mgrp_ip
>> 16) & 0xff),
711 ((mgrp_ip
>> 8) & 0xff), (mgrp_ip
& 0xff));
713 /* Add the group entry to hash table */
714 hash
= MFDB_MGRP_HASH(mgrp_ip
);
715 clist_add_head(&emfc
->mgrp_fdb
[hash
], &mgrp
->mgrp_hlist
);
719 mi
= emfc_mfdb_mi_entry_find(emfc
, mgrp
, ifp
);
721 /* Update the ref count */
725 OSL_UNLOCK(emfc
->fdb_lock
);
730 EMF_MFDB("Adding interface entry for interface %p\n", ifp
);
732 /* Allocate and initialize multicast interface entry */
733 mi
= MALLOC(emfc
->osh
, sizeof(emfc_mi_t
));
736 EMF_ERROR("Failed to allocated memory %d for interface entry\n",
738 if (clist_empty(&mgrp
->mi_head
))
740 clist_delete(&mgrp
->mgrp_hlist
);
741 emfc
->mgrp_cache_ip
= ((emfc
->mgrp_cache
== mgrp
) ?
742 0 : emfc
->mgrp_cache_ip
);
743 MFREE(emfc
->osh
, mgrp
, sizeof(emfc_mgrp_t
));
745 OSL_UNLOCK(emfc
->fdb_lock
);
749 /* Initialize the multicast interface list entry */
751 mi
->mi_mhif
= emfc_mfdb_mhif_add(emfc
, ifp
);
754 /* Add the multicast interface entry */
755 clist_add_head(&mgrp
->mi_head
, &mi
->mi_list
);
757 OSL_UNLOCK(emfc
->fdb_lock
);
763 * Description: This function is called by the IGMP snooper layer
764 * to delete the MFDB entry. It deletes the group
765 * entry also if the interface entry is last in the
768 * Input: Same as above function.
770 * Return: SUCCESS or FAILURE
773 emfc_mfdb_membership_del(emfc_info_t
*emfc
, uint32 mgrp_ip
, void *ifp
)
778 OSL_LOCK(emfc
->fdb_lock
);
780 /* Find group entry */
781 mgrp
= emfc_mfdb_group_find(emfc
, mgrp_ip
);
785 OSL_UNLOCK(emfc
->fdb_lock
);
789 /* Find interface entry */
790 mi
= emfc_mfdb_mi_entry_find(emfc
, mgrp
, ifp
);
794 OSL_UNLOCK(emfc
->fdb_lock
);
798 EMF_MFDB("Deleting MFDB interface entry for interface %p\n", ifp
);
800 /* Delete the interface entry when ref count reaches zero */
804 OSL_UNLOCK(emfc
->fdb_lock
);
809 EMF_MFDB("Deleting interface entry %p\n", mi
->mi_mhif
->mhif_ifp
);
810 clist_delete(&mi
->mi_list
);
813 /* If the member being deleted is last node in the interface list,
814 * delete the group entry also.
816 if (clist_empty(&mgrp
->mi_head
))
818 EMF_MFDB("Deleting group entry of %d.%d.%d.%d too\n",
819 (mgrp_ip
>> 24), ((mgrp_ip
>> 16) & 0xff),
820 ((mgrp_ip
>> 8) & 0xff), (mgrp_ip
& 0xff));
822 clist_delete(&mgrp
->mgrp_hlist
);
823 emfc
->mgrp_cache_ip
= ((emfc
->mgrp_cache
== mgrp
) ?
824 0 : emfc
->mgrp_cache_ip
);
825 MFREE(emfc
->osh
, mgrp
, sizeof(emfc_mgrp_t
));
828 MFREE(emfc
->osh
, mi
, sizeof(emfc_mi_t
));
830 OSL_UNLOCK(emfc
->fdb_lock
);
836 * Description: This function clears the group interval timers and
837 * deletes the group and interface entries of the MFDB.
839 * Input: emfc - EMFL Common code global data handle
842 emfc_mfdb_clear(emfc_info_t
*emfc
)
847 clist_head_t
*ptr1
, *ptr2
, *tmp1
, *tmp2
;
849 OSL_LOCK(emfc
->fdb_lock
);
851 /* Delete all the group entries */
852 for (i
= 0; i
< MFDB_HASHT_SIZE
; i
++)
854 for (ptr1
= emfc
->mgrp_fdb
[i
].next
;
855 ptr1
!= &emfc
->mgrp_fdb
[i
]; ptr1
= tmp1
)
857 mgrp
= clist_entry(ptr1
, emfc_mgrp_t
, mgrp_hlist
);
859 /* Delete all interface entries */
860 for (ptr2
= mgrp
->mi_head
.next
;
861 ptr2
!= &mgrp
->mi_head
; ptr2
= tmp2
)
863 mi
= clist_entry(ptr2
, emfc_mi_t
, mi_list
);
866 EMF_MFDB("Deleting interface entry %p\n", mi
);
868 MFREE(emfc
->osh
, mi
, sizeof(emfc_mi_t
));
873 /* Delete the group entry when there are no more interface
874 * entries for this group.
877 MFREE(emfc
->osh
, mgrp
, sizeof(emfc_mgrp_t
));
881 emfc
->mgrp_cache_ip
= 0;
883 OSL_UNLOCK(emfc
->fdb_lock
);
889 * EMFC Interface List cleanup
892 emfc_iflist_clear(emfc_info_t
*emfc
)
894 emfc_iflist_t
*ptr
, *temp
;
896 OSL_LOCK(emfc
->iflist_lock
);
898 ptr
= emfc
->iflist_head
;
902 MFREE(emfc
->osh
, ptr
, sizeof(emfc_iflist_t
));
906 emfc
->iflist_head
= NULL
;
908 OSL_UNLOCK(emfc
->iflist_lock
);
914 * Description: This function is called to enable/disable the efficient
915 * multicast forwarding feature. When the config operation
916 * cannot be completed respective status is returned.
918 * Input: emfc - EMFL Common code global data handle
920 * Input/Output: cfg - Pointer to configuration request data. It contains
921 * the command id, operation type, corresponding
922 * arguments and output status.
925 emfc_cfg_emf_enable(emfc_info_t
*emfc
, emf_cfg_request_t
*cfg
)
929 EMF_DEBUG("Operation type: %d\n", cfg
->oper_type
);
931 switch (cfg
->oper_type
)
933 case EMFCFG_OPER_TYPE_GET
:
934 *(bool *)cfg
->arg
= emfc
->emf_enable
;
935 cfg
->size
= sizeof(bool);
936 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
939 case EMFCFG_OPER_TYPE_SET
:
940 /* Enable or disable EMF */
941 emf_enable
= (*(bool *)cfg
->arg
? TRUE
: FALSE
);
942 if (emfc
->emf_enable
== emf_enable
)
944 cfg
->status
= EMFCFG_STATUS_FAILURE
;
945 cfg
->size
= sprintf(cfg
->arg
,
946 "Duplicate configuration request\n");
950 emfc
->emf_enable
= emf_enable
;
952 if (emfc
->emf_enable
)
954 /* Register the hooks to start receiving multicast frames */
955 if (emfc
->wrapper
.hooks_register_fn(emfc
->emfi
) != SUCCESS
)
957 cfg
->status
= EMFCFG_STATUS_FAILURE
;
958 cfg
->size
= sprintf(cfg
->arg
,
959 "Duplicate hooks registration\n");
963 /* Call the registered EMF enable entry point function */
964 if (emfc
->snooper
&& emfc
->snooper
->emf_enable_fn
!= NULL
)
966 EMF_DEBUG("Calling the EMF enable function\n");
967 emfc
->snooper
->emf_enable_fn(emfc
->snooper
);
972 /* Call the registered EMF disable entry point function */
973 if (emfc
->snooper
&& emfc
->snooper
->emf_disable_fn
!= NULL
)
975 EMF_DEBUG("Calling the EMF disable function\n");
976 emfc
->snooper
->emf_disable_fn(emfc
->snooper
);
979 /* Unregister the packet hooks first */
980 emfc
->wrapper
.hooks_unregister_fn(emfc
->emfi
);
982 /* Cleanup the MFDB entries */
983 emfc_mfdb_clear(emfc
);
985 /* Cleanup the UFFP entries */
986 emfc_iflist_clear(emfc
);
989 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
993 cfg
->status
= EMFCFG_STATUS_OPER_UNKNOWN
;
994 cfg
->size
= sprintf(cfg
->arg
, "Unknown operation\n");
1002 * EMFL Packet Counters/Statistics
1005 emfc_stats_get(emfc_info_t
*emfc
, emf_stats_t
*emfs
, uint32 size
)
1009 EMF_ERROR("Invalid EMFC handle passed\n");
1015 EMF_ERROR("Invalid buffer input\n");
1019 if (size
< sizeof(emf_stats_t
))
1021 EMF_ERROR("Insufficient buffer size %d\n", size
);
1025 *emfs
= emfc
->stats
;
1031 * MFDB Listing Function
1034 emfc_mfdb_list(emfc_info_t
*emfc
, emf_cfg_mfdb_list_t
*list
, uint32 size
)
1036 clist_head_t
*ptr1
, *ptr2
;
1043 EMF_ERROR("Invalid EMFC handle passed\n");
1049 EMF_ERROR("Invalid buffer input\n");
1053 for (i
= 0; i
< MFDB_HASHT_SIZE
; i
++)
1055 for (ptr1
= emfc
->mgrp_fdb
[i
].next
;
1056 ptr1
!= &emfc
->mgrp_fdb
[i
]; ptr1
= ptr1
->next
)
1058 mgrp
= clist_entry(ptr1
, emfc_mgrp_t
, mgrp_hlist
);
1059 for (ptr2
= mgrp
->mi_head
.next
;
1060 ptr2
!= &mgrp
->mi_head
; ptr2
= ptr2
->next
)
1062 mi
= clist_entry(ptr2
, emfc_mi_t
, mi_list
);
1064 list
->mfdb_entry
[index
].mgrp_ip
= mgrp
->mgrp_ip
;
1065 strncpy(list
->mfdb_entry
[index
].if_name
,
1066 DEV_IFNAME(mi
->mi_mhif
->mhif_ifp
), 16);
1067 list
->mfdb_entry
[index
].pkts_fwd
= mi
->mi_data_fwd
;
1073 /* Update the total number of entries */
1074 list
->num_entries
= index
;
1080 * EMFC Interface List find
1082 static emfc_iflist_t
*
1083 emfc_iflist_find(emfc_info_t
*emfc
, void *ifp
, emfc_iflist_t
**prev
)
1087 OSL_LOCK(emfc
->iflist_lock
);
1090 for (ptr
= emfc
->iflist_head
; ptr
!= NULL
;
1091 *prev
= ptr
, ptr
= ptr
->next
)
1093 if (ptr
->ifp
== ifp
)
1095 OSL_UNLOCK(emfc
->iflist_lock
);
1100 OSL_UNLOCK(emfc
->iflist_lock
);
1106 * EMFC Interface List add entry
1109 emfc_iflist_add(emfc_info_t
*emfc
, void *ifp
)
1111 emfc_iflist_t
*iflist
, *prev
;
1115 EMF_ERROR("Invalid interface identifier\n");
1119 if (emfc_iflist_find(emfc
, ifp
, &prev
) != NULL
)
1121 EMF_DEBUG("Adding duplicate interface entry\n");
1125 /* Allocate and initialize UFFP entry */
1126 iflist
= MALLOC(emfc
->osh
, sizeof(emfc_iflist_t
));
1129 EMF_ERROR("Failed to alloc mem size %d for interface entry\n",
1130 sizeof(emfc_iflist_t
));
1135 iflist
->uffp_ref
= 0;
1136 iflist
->rtport_ref
= 0;
1138 /* Add the UFFP entry to the list */
1139 OSL_LOCK(emfc
->iflist_lock
);
1140 iflist
->next
= emfc
->iflist_head
;
1141 emfc
->iflist_head
= iflist
;
1142 OSL_UNLOCK(emfc
->iflist_lock
);
1148 * EMFC Interface List delete entry
1151 emfc_iflist_del(emfc_info_t
*emfc
, void *ifp
)
1153 emfc_iflist_t
*ptr
, *prev
;
1157 EMF_ERROR("Invalid interface identifier\n");
1161 if ((ptr
= emfc_iflist_find(emfc
, ifp
, &prev
)) == NULL
)
1163 EMF_ERROR("UFFP entry not found\n");
1167 OSL_LOCK(emfc
->iflist_lock
);
1169 /* Delete the UFFP entry from the list */
1171 prev
->next
= ptr
->next
;
1173 emfc
->iflist_head
= ptr
->next
;
1175 OSL_UNLOCK(emfc
->iflist_lock
);
1177 MFREE(emfc
->osh
, ptr
, sizeof(emfc_iflist_t
));
1186 emfc_uffp_add(emfc_info_t
*emfc
, void *ifp
)
1188 emfc_iflist_t
*iflist
, *prev
;
1190 /* Add the interface entry if not present already */
1191 emfc_iflist_add(emfc
, ifp
);
1193 OSL_LOCK(emfc
->iflist_lock
);
1194 if ((iflist
= emfc_iflist_find(emfc
, ifp
, &prev
)) != NULL
)
1196 OSL_UNLOCK(emfc
->iflist_lock
);
1205 emfc_uffp_del(emfc_info_t
*emfc
, void *ifp
)
1207 emfc_iflist_t
*iflist
, *prev
;
1209 if ((iflist
= emfc_iflist_find(emfc
, ifp
, &prev
)) == NULL
)
1212 /* Delete the interface entry when flags is zero */
1213 OSL_LOCK(emfc
->iflist_lock
);
1215 if ((iflist
->uffp_ref
== 0) && (iflist
->rtport_ref
== 0))
1216 emfc_iflist_del(emfc
, ifp
);
1217 OSL_UNLOCK(emfc
->iflist_lock
);
1223 * UFFP Interface Listing
1226 emfc_uffp_list(emfc_info_t
*emfc
, emf_cfg_uffp_list_t
*list
, uint32 size
)
1228 int32 index
= 0, bytes
= 0;
1231 for (ptr
= emfc
->iflist_head
; ptr
!= NULL
; ptr
= ptr
->next
)
1233 if (ptr
->uffp_ref
== 0)
1236 bytes
+= sizeof(emf_cfg_uffp_t
);
1240 strncpy(list
->uffp_entry
[index
].if_name
, DEV_IFNAME(ptr
->ifp
), 16);
1241 list
->uffp_entry
[index
].if_name
[15] = 0;
1245 /* Update the total number of entries */
1246 list
->num_entries
= index
;
1252 * Description: This function is called by the IGMP Snooper to add a Router
1253 * Port. Router Port is the interface on which the IGMP Snooper
1254 * determines that a multicast router is present. We set a bit
1255 * in the flag field of the interface list entry to mark it as
1258 * Input: emfc - EMFC Global Instance handle
1259 * ifp - Interface pointer
1261 * Return: SUCCESS/FAILURE
1264 emfc_rtport_add(emfc_info_t
*emfc
, void *ifp
)
1266 emfc_iflist_t
*iflist
, *prev
;
1268 /* Add interface list entry */
1269 emfc_iflist_add(emfc
, ifp
);
1271 OSL_LOCK(emfc
->iflist_lock
);
1272 if ((iflist
= emfc_iflist_find(emfc
, ifp
, &prev
)) != NULL
)
1273 iflist
->rtport_ref
++;
1274 OSL_UNLOCK(emfc
->iflist_lock
);
1276 EMF_INFO("RTPORT %s added refcount %d\n", DEV_IFNAME(ifp
), iflist
->rtport_ref
);
1282 * Description: This function is called by the IGMP Snooper to delete a
1283 * Router Port. We clear the corresponding bit in the flags
1284 * field to mark the port as non-router port.
1286 * Input: emfc - EMFC Global Instance handle
1287 * ifp - Interface pointer
1289 * Return: SUCCESS/FAILURE
1292 emfc_rtport_del(emfc_info_t
*emfc
, void *ifp
)
1294 emfc_iflist_t
*iflist
, *prev
;
1296 if ((iflist
= emfc_iflist_find(emfc
, ifp
, &prev
)) == NULL
)
1298 EMF_ERROR("Invalid interface specified to rtport delete\n");
1302 /* Delete the interface entry when flags is zero */
1303 OSL_LOCK(emfc
->iflist_lock
);
1304 iflist
->rtport_ref
--;
1305 if ((iflist
->rtport_ref
== 0) && (iflist
->uffp_ref
== 0))
1306 emfc_iflist_del(emfc
, ifp
);
1307 OSL_UNLOCK(emfc
->iflist_lock
);
1313 * RTPORT listing function
1316 emfc_rtport_list(emfc_info_t
*emfc
, emf_cfg_rtport_list_t
*list
, uint32 size
)
1318 int32 index
= 0, bytes
= 0;
1321 for (ptr
= emfc
->iflist_head
; ptr
!= NULL
; ptr
= ptr
->next
)
1323 if (ptr
->rtport_ref
== 0)
1326 bytes
+= sizeof(emf_cfg_rtport_t
);
1330 strncpy(list
->rtport_entry
[index
].if_name
, DEV_IFNAME(ptr
->ifp
), 16);
1331 list
->rtport_entry
[index
].if_name
[15] = 0;
1335 /* Update the total number of entries */
1336 list
->num_entries
= index
;
1342 * Description: This function is called from the OS Specific layer when the
1343 * user issues a configuration command.
1345 * Input/Output: Same as emfc_cfg_emf_enable.
1348 emfc_cfg_request_process(emfc_info_t
*emfc
, emf_cfg_request_t
*cfg
)
1350 emf_cfg_mfdb_t
*mfdb
;
1351 emf_cfg_uffp_t
*uffp
;
1352 emf_cfg_rtport_t
*rtport
;
1354 EMF_DEBUG("Command identifier: %d\n", cfg
->command_id
);
1356 switch (cfg
->command_id
)
1358 case EMFCFG_CMD_EMF_ENABLE
:
1359 emfc_cfg_emf_enable(emfc
, cfg
);
1362 case EMFCFG_CMD_MFDB_ADD
:
1363 mfdb
= (emf_cfg_mfdb_t
*)cfg
->arg
;
1366 /* Add MFDB entry for this group and interface */
1367 if (emfc_mfdb_membership_add(emfc
, mfdb
->mgrp_ip
,
1368 mfdb
->if_ptr
) != SUCCESS
)
1370 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1371 cfg
->size
+= sprintf(cfg
->arg
, "Unable to add entry\n");
1375 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1377 EMF_MFDB("MFDB entry %x %p added by user\n",
1378 mfdb
->mgrp_ip
, mfdb
->if_ptr
);
1381 case EMFCFG_CMD_MFDB_DEL
:
1382 mfdb
= (emf_cfg_mfdb_t
*)cfg
->arg
;
1385 /* Delete MFDB entry */
1386 if (emfc_mfdb_membership_del(emfc
, mfdb
->mgrp_ip
,
1387 mfdb
->if_ptr
) != SUCCESS
)
1389 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1390 cfg
->size
+= sprintf(cfg
->arg
, "MFDB entry not found\n");
1394 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1396 EMF_MFDB("MFDB entry %x %p deleted by user\n",
1397 mfdb
->mgrp_ip
, mfdb
->if_ptr
);
1400 case EMFCFG_CMD_MFDB_LIST
:
1401 if (emfc_mfdb_list(emfc
, (emf_cfg_mfdb_list_t
*)cfg
->arg
,
1402 cfg
->size
) != SUCCESS
)
1404 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1405 cfg
->size
+= sprintf(cfg
->arg
, "MFDB list get failed\n");
1409 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1412 case EMFCFG_CMD_MFDB_CLEAR
:
1413 emfc_mfdb_clear(emfc
);
1414 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1417 case EMFCFG_CMD_RTPORT_ADD
:
1418 rtport
= (emf_cfg_rtport_t
*)cfg
->arg
;
1421 if (emfc_rtport_add(emfc
, rtport
->if_ptr
) != SUCCESS
)
1423 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1424 cfg
->size
+= sprintf(cfg
->arg
,
1425 "Unknown interface, rtport add failed\n");
1429 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1432 case EMFCFG_CMD_RTPORT_DEL
:
1433 rtport
= (emf_cfg_rtport_t
*)cfg
->arg
;
1436 if (emfc_rtport_del(emfc
, rtport
->if_ptr
) != SUCCESS
)
1438 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1439 cfg
->size
+= sprintf(cfg
->arg
,
1440 "Unknown interface, rtport del failed\n");
1444 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1447 case EMFCFG_CMD_RTPORT_LIST
:
1448 if (emfc_rtport_list(emfc
, (emf_cfg_rtport_list_t
*)cfg
->arg
,
1449 cfg
->size
) != SUCCESS
)
1451 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1452 cfg
->size
= sprintf(cfg
->arg
, "rtport list get failed\n");
1456 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1459 case EMFCFG_CMD_UFFP_ADD
:
1460 uffp
= (emf_cfg_uffp_t
*)cfg
->arg
;
1463 if (emfc_uffp_add(emfc
, uffp
->if_ptr
) != SUCCESS
)
1465 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1466 cfg
->size
+= sprintf(cfg
->arg
,
1467 "Unknown interface, UFFP add failed\n");
1471 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1474 case EMFCFG_CMD_UFFP_DEL
:
1475 uffp
= (emf_cfg_uffp_t
*)cfg
->arg
;
1478 if (emfc_uffp_del(emfc
, uffp
->if_ptr
) != SUCCESS
)
1480 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1481 cfg
->size
+= sprintf(cfg
->arg
,
1482 "Unknown interface, UFFP del failed\n");
1486 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1489 case EMFCFG_CMD_UFFP_LIST
:
1490 if (emfc_uffp_list(emfc
, (emf_cfg_uffp_list_t
*)cfg
->arg
,
1491 cfg
->size
) != SUCCESS
)
1493 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1494 cfg
->size
= sprintf(cfg
->arg
, "UFFP list get failed\n");
1498 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1501 case EMFCFG_CMD_EMF_STATS
:
1502 if (emfc_stats_get(emfc
, (emf_stats_t
*)cfg
->arg
,
1503 cfg
->size
) != SUCCESS
)
1505 cfg
->status
= EMFCFG_STATUS_FAILURE
;
1506 cfg
->size
= sprintf(cfg
->arg
, "EMF stats get failed\n");
1510 cfg
->status
= EMFCFG_STATUS_SUCCESS
;
1514 EMF_DEBUG("Unknown command %d\n", cfg
->command_id
);
1515 cfg
->status
= EMFCFG_STATUS_CMD_UNKNOWN
;
1516 cfg
->size
= sprintf(cfg
->arg
, "Unknown command\n");
1524 * Description: This function is called from the OS specific module init
1525 * routine to create and initialize EMFC instance. This function
1526 * primarily initializes the EMFL global data and MFDB.
1528 * Input: inst_id - Instance identier used to associate EMF
1529 * and IGMP snooper instances.
1530 * emfi - EMFL OS Specific global data handle
1531 * osh - OS abstraction layer handle
1532 * wrapper - EMFC wrapper info
1534 * Return: emfc - EMFL Common code global data handle
1537 emfc_init(int8
*inst_id
, void *emfi
, osl_t
*osh
, emfc_wrapper_t
*wrapper
)
1541 EMF_DEBUG("Initializing EMFL\n");
1543 /* Check for the wrapper parameter */
1544 if (wrapper
== NULL
)
1546 EMF_ERROR("emfc_init: wrapper parameter NULL\n");
1550 /* Allocate memory */
1551 emfc
= MALLOC(osh
, sizeof(emfc_info_t
));
1554 EMF_ERROR("Failed to allocated memory size %d for MFL\n",
1555 sizeof(emfc_info_t
));
1559 EMF_DEBUG("Allocated memory for EMFC info\n");
1561 /* Initialize the EMF global data */
1562 bzero(emfc
, sizeof(emfc_info_t
));
1565 emfc
->mgrp_cache_ip
= 0;
1566 emfc
->mgrp_cache
= NULL
;
1567 emfc
->iflist_head
= NULL
;
1569 /* Set EMF status as disabled */
1570 emfc
->emf_enable
= FALSE
;
1572 /* Initialize Multicast FDB */
1573 emfc_mfdb_init(emfc
);
1575 /* Create lock for MFDB access */
1576 emfc
->fdb_lock
= OSL_LOCK_CREATE("FDB Lock");
1577 if (emfc
->fdb_lock
== NULL
)
1579 MFREE(emfc
->osh
, emfc
, sizeof(emfc_info_t
));
1583 /* Create lock for router port list access */
1584 emfc
->iflist_lock
= OSL_LOCK_CREATE("Router Port List Lock");
1585 if (emfc
->iflist_lock
== NULL
)
1587 OSL_LOCK_DESTROY(emfc
->fdb_lock
);
1588 MFREE(emfc
->osh
, emfc
, sizeof(emfc_info_t
));
1592 /* Save the instance id */
1593 strncpy(emfc
->inst_id
, inst_id
, IFNAMSIZ
);
1594 emfc
->inst_id
[IFNAMSIZ
- 1] = 0;
1596 /* Fill up the wrapper specific functions */
1597 emfc
->wrapper
.forward_fn
= wrapper
->forward_fn
;
1598 emfc
->wrapper
.sendup_fn
= wrapper
->sendup_fn
;
1599 emfc
->wrapper
.hooks_register_fn
= wrapper
->hooks_register_fn
;
1600 emfc
->wrapper
.hooks_unregister_fn
= wrapper
->hooks_unregister_fn
;
1602 /* Add to the EMFC instance list */
1603 OSL_LOCK(emfc_list_lock
);
1604 clist_add_head(&emfc_list_head
, &emfc
->emfc_list
);
1605 OSL_UNLOCK(emfc_list_lock
);
1607 EMF_DEBUG("Initialized MFDB\n");
1613 * Description: This function is called from OS specific module cleanup
1614 * routine. This routine primarily clears the MFDB entries
1615 * and frees the global instance data.
1617 * Input: emfc - EMFL global instance handle
1620 emfc_exit(emfc_info_t
*emfc
)
1622 emfc_mhif_t
*ptr
, *temp
;
1624 /* Unregister the packet hooks if not already */
1625 emfc
->wrapper
.hooks_unregister_fn(emfc
->emfi
);
1627 /* Cleanup MFDB entries */
1628 emfc_mfdb_clear(emfc
);
1630 /* Cleanup the interface list entries */
1631 emfc_iflist_clear(emfc
);
1632 OSL_LOCK_DESTROY(emfc
->iflist_lock
);
1634 OSL_LOCK(emfc
->fdb_lock
);
1636 /* Delete interface list */
1637 ptr
= emfc
->mhif_head
;
1641 MFREE(emfc
->osh
, ptr
, sizeof(emfc_mhif_t
));
1645 OSL_UNLOCK(emfc
->fdb_lock
);
1647 OSL_LOCK_DESTROY(emfc
->fdb_lock
);
1649 /* Delete the EMFC instance */
1650 OSL_LOCK(emfc_list_lock
);
1651 clist_delete(&emfc
->emfc_list
);
1652 OSL_UNLOCK(emfc_list_lock
);
1654 MFREE(emfc
->osh
, emfc
, sizeof(emfc_info_t
));
1656 EMF_DEBUG("Cleaned up EMFL, exiting common code\n");
1662 * Description: This function is called from OS specific module init
1663 * routine. This allocates global resources required by the
1667 emfc_module_init(void)
1669 /* Create lock for EMFC instance list access */
1670 emfc_list_lock
= OSL_LOCK_CREATE("EMFC List Lock");
1672 if (emfc_list_lock
== NULL
)
1674 EMF_ERROR("EMFC List lock create failed\n");
1682 * Description: This function is called from OS specific module cleanup
1683 * routine. This frees all the global resources.
1686 emfc_module_exit(void)
1688 OSL_LOCK_DESTROY(emfc_list_lock
);