b152fc3e821f87c9cb428fb2028186b9f086f7e4
[mirror/winof/.git] / ulp / opensm / user / opensm / osm_mcast_mgr.c
1 /*
2  * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  *
6  * This software is available to you under the OpenIB.org BSD license
7  * below:
8  *
9  *     Redistribution and use in source and binary forms, with or
10  *     without modification, are permitted provided that the following
11  *     conditions are met:
12  *
13  *      - Redistributions of source code must retain the above
14  *        copyright notice, this list of conditions and the following
15  *        disclaimer.
16  *
17  *      - Redistributions in binary form must reproduce the above
18  *        copyright notice, this list of conditions and the following
19  *        disclaimer in the documentation and/or other materials
20  *        provided with the distribution.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29  * SOFTWARE.
30  *
31  * $Id$
32  */
33
34
35 /*
36  * Abstract:
37  *    Implementation of osm_mcast_mgr_t.
38  * This file implements the Multicast Manager object.
39  *
40  * Environment:
41  *    Linux User Mode
42  *
43  * $Revision: 1.9 $
44  */
45
46 #if HAVE_CONFIG_H
47 #  include <config.h>
48 #endif /* HAVE_CONFIG_H */
49
50 #include <iba/ib_types.h>
51 #include <complib/cl_memory.h>
52 #include <complib/cl_debug.h>
53 #include <opensm/osm_mcast_mgr.h>
54 #include <opensm/osm_multicast.h>
55 #include <opensm/osm_node.h>
56 #include <opensm/osm_switch.h>
57 #include <opensm/osm_helper.h>
58 #include <opensm/osm_msgdef.h>
59
60 #define LINE_LENGTH 256
61
62 /**********************************************************************
63  **********************************************************************/
64 typedef struct _osm_mcast_work_obj
65 {
66   cl_list_item_t     list_item;
67   osm_port_t*        p_port;
68
69 } osm_mcast_work_obj_t;
70
71 /**********************************************************************
72  **********************************************************************/
73 static osm_mcast_work_obj_t*
74 __osm_mcast_work_obj_new(
75   IN const osm_port_t*     const p_port )
76 {
77   /*
78     TO DO - get these objects from a lockpool.
79   */
80   osm_mcast_work_obj_t*    p_obj;
81
82   /*
83     clean allocated memory to avoid assertion when trying to insert to
84     qlist.
85     see cl_qlist_insert_tail(): CL_ASSERT(p_list_item->p_list != p_list)
86   */
87   p_obj = cl_zalloc( sizeof( *p_obj ) );
88   if( p_obj )
89     p_obj->p_port = (osm_port_t*)p_port;
90
91   return( p_obj );
92 }
93
94 /**********************************************************************
95  **********************************************************************/
96 static void
97 __osm_mcast_work_obj_delete(
98   IN osm_mcast_work_obj_t* p_wobj )
99 {
100   cl_free( p_wobj );
101 }
102
103 /**********************************************************************
104    Recursively remove nodes from the tree
105 **********************************************************************/
106 void
107 __osm_mcast_mgr_purge_tree_node(
108   IN osm_mtree_node_t*     p_mtn )
109 {
110   uint8_t                  i;
111
112   for( i = 0; i < p_mtn->max_children; i++ )
113   {
114     if( p_mtn->child_array[i] &&
115         (p_mtn->child_array[i] != OSM_MTREE_LEAF) )
116       __osm_mcast_mgr_purge_tree_node( p_mtn->child_array[i] );
117
118     p_mtn->child_array[i] = NULL;
119
120   }
121
122   cl_free( p_mtn );
123 }
124
125 /**********************************************************************
126  **********************************************************************/
127 static void
128 __osm_mcast_mgr_purge_tree(
129   IN osm_mcast_mgr_t*         const p_mgr,
130   IN osm_mgrp_t*           const p_mgrp )
131 {
132   OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_purge_tree );
133
134   if( p_mgrp->p_root )
135     __osm_mcast_mgr_purge_tree_node( p_mgrp->p_root );
136
137   p_mgrp->p_root = NULL;
138
139   OSM_LOG_EXIT( p_mgr->p_log );
140 }
141
142 /**********************************************************************
143  **********************************************************************/
144 uint32_t
145 osm_mcast_mgr_compute_avg_hops(
146   osm_mcast_mgr_t*         const p_mgr,
147   const osm_mgrp_t*        const p_mgrp,
148   const osm_switch_t*         const p_sw )
149 {
150   uint32_t avg_hops = 0;
151   uint32_t hops = 0;
152   uint32_t num_ports = 0;
153   uint16_t base_lid_ho;
154   const osm_port_t* p_port;
155   const osm_mcm_port_t* p_mcm_port;
156   const cl_qmap_t* p_mcm_tbl;
157   const cl_qmap_t* p_port_tbl;
158
159   OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_compute_avg_hops );
160
161   p_mcm_tbl = &p_mgrp->mcm_port_tbl;
162   p_port_tbl = &p_mgr->p_subn->port_guid_tbl;
163
164   /*
165     For each member of the multicast group, compute the
166     number of hops to its base LID.
167   */
168   for( p_mcm_port = (osm_mcm_port_t*)cl_qmap_head( p_mcm_tbl );
169        p_mcm_port != (osm_mcm_port_t*)cl_qmap_end( p_mcm_tbl );
170        p_mcm_port = (osm_mcm_port_t*)cl_qmap_next(&p_mcm_port->map_item))
171   {
172     /*
173       Acquire the port object for this port guid, then create
174       the new worker object to build the list.
175     */
176     p_port = (osm_port_t*)cl_qmap_get( p_port_tbl,
177                                        ib_gid_get_guid( &p_mcm_port->port_gid ) );
178
179     if( p_port == (osm_port_t*)cl_qmap_end( p_port_tbl ) )
180     {
181       osm_log( p_mgr->p_log, OSM_LOG_ERROR,
182                "osm_mcast_mgr_compute_avg_hops: ERR 0A18: "
183                "No port object for port 0x%016" PRIx64 ".\n",
184                cl_ntoh64( ib_gid_get_guid( &p_mcm_port->port_gid ) ) );
185       continue;
186     }
187
188     base_lid_ho = cl_ntoh16( osm_port_get_base_lid( p_port ) );
189     hops += osm_switch_get_least_hops( p_sw, base_lid_ho );
190     num_ports++;
191   }
192
193   /*
194     We should be here if there aren't any ports in the group.
195   */
196   CL_ASSERT( num_ports );
197
198   if( num_ports != 0 )
199   {
200     avg_hops = hops / num_ports;
201   }
202
203   OSM_LOG_EXIT( p_mgr->p_log );
204   return( avg_hops );
205 }
206
207 /**********************************************************************
208  Calculate the maximal "min hops" from the given switch to any
209  of the group HCAs
210  **********************************************************************/
211 uint32_t
212 osm_mcast_mgr_compute_max_hops(
213   osm_mcast_mgr_t*         const p_mgr,
214   const osm_mgrp_t*        const p_mgrp,
215   const osm_switch_t*      const p_sw )
216 {
217   uint32_t max_hops = 0;
218   uint32_t hops = 0;
219   uint16_t base_lid_ho;
220   const osm_port_t* p_port;
221   const osm_mcm_port_t* p_mcm_port;
222   const cl_qmap_t* p_mcm_tbl;
223   const cl_qmap_t* p_port_tbl;
224
225   OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_compute_max_hops );
226
227   p_mcm_tbl = &p_mgrp->mcm_port_tbl;
228   p_port_tbl = &p_mgr->p_subn->port_guid_tbl;
229
230   /*
231     For each member of the multicast group, compute the
232     number of hops to its base LID.
233   */
234   for( p_mcm_port = (osm_mcm_port_t*)cl_qmap_head( p_mcm_tbl );
235        p_mcm_port != (osm_mcm_port_t*)cl_qmap_end( p_mcm_tbl );
236        p_mcm_port = (osm_mcm_port_t*)cl_qmap_next(&p_mcm_port->map_item))
237   {
238     /*
239       Acquire the port object for this port guid, then create
240       the new worker object to build the list.
241     */
242     p_port = (osm_port_t*)cl_qmap_get(
243       p_port_tbl,
244       ib_gid_get_guid( &p_mcm_port->port_gid ) );
245
246     if( p_port == (osm_port_t*)cl_qmap_end( p_port_tbl ) )
247     {
248       osm_log( p_mgr->p_log, OSM_LOG_ERROR,
249                "osm_mcast_mgr_compute_max_hops: ERR 0A18: "
250                "No port object for port 0x%016" PRIx64 ".\n",
251                cl_ntoh64( ib_gid_get_guid( &p_mcm_port->port_gid ) ) );
252       continue;
253     }
254
255     base_lid_ho = cl_ntoh16( osm_port_get_base_lid( p_port ) );
256     hops = osm_switch_get_least_hops( p_sw, base_lid_ho );
257     if (hops > max_hops) max_hops = hops;
258   }
259
260   if( max_hops == 0 )
261   {
262     /*
263       We should be here if there aren't any ports in the group.
264     */
265     max_hops = 10001; /* see later - we use it to realize no hops */
266   }
267
268   OSM_LOG_EXIT( p_mgr->p_log );
269   return( max_hops );
270 }
271
272 /**********************************************************************
273    This function attempts to locate the optimal switch for the
274    center of the spanning tree.  The current algorithm chooses
275    a switch with the lowest average hop count to the members
276    of the multicast group.
277 **********************************************************************/
278 static osm_switch_t*
279 __osm_mcast_mgr_find_optimal_switch(
280   osm_mcast_mgr_t*         const p_mgr,
281   const osm_mgrp_t*        const p_mgrp )
282 {
283   cl_qmap_t*               p_sw_tbl;
284   const osm_switch_t*         p_sw;
285   const osm_switch_t*         p_best_sw = NULL;
286   uint32_t                 hops = 0;
287   uint32_t                 best_hops = 10000;   /* any big # will do */
288   uint64_t              sw_guid_ho;
289 #ifdef OSM_VENDOR_INTF_ANAFA  
290         boolean_t             use_avg_hops = TRUE; /* anafa2 - bug hca on switch */ /* use max hops for root */
291 #else
292         boolean_t             use_avg_hops = FALSE;  /* use max hops for root */
293 #endif
294
295   OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_find_optimal_switch );
296
297   p_sw_tbl = &p_mgr->p_subn->sw_guid_tbl;
298
299   CL_ASSERT( !osm_mgrp_is_empty( p_mgrp ) );
300
301   for( p_sw = (osm_switch_t*)cl_qmap_head( p_sw_tbl );
302        p_sw != (osm_switch_t*)cl_qmap_end( p_sw_tbl );
303        p_sw = (osm_switch_t*)cl_qmap_next( &p_sw->map_item ) )
304   {
305     if( !osm_switch_supports_mcast( p_sw ) )
306       continue;
307
308     if (use_avg_hops) 
309       hops = osm_mcast_mgr_compute_avg_hops( p_mgr, p_mgrp, p_sw );
310     else
311       hops = osm_mcast_mgr_compute_max_hops( p_mgr, p_mgrp, p_sw );
312
313     if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
314     {
315       sw_guid_ho = cl_ntoh64( osm_node_get_node_guid(
316                                 osm_switch_get_node_ptr( p_sw ) ) );
317
318       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
319                "__osm_mcast_mgr_find_optimal_switch: "
320                "Switch 0x%016" PRIx64 ", hops = %f.\n",
321                sw_guid_ho, hops );
322     }
323
324     if( hops < best_hops )
325     {
326       p_best_sw = p_sw;
327       best_hops = hops;
328     }
329   }
330
331   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
332   {
333     if( p_best_sw )
334     {
335       sw_guid_ho = cl_ntoh64( osm_node_get_node_guid(
336                                 osm_switch_get_node_ptr( p_best_sw ) ) );
337
338       osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
339                "__osm_mcast_mgr_find_optimal_switch: "
340                "Best switch is 0x%" PRIx64 ", hops = %f.\n",
341                sw_guid_ho, best_hops );
342     }
343     else
344     {
345       osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
346                "__osm_mcast_mgr_find_optimal_switch: "
347                "No multicast capable switches detected.\n" );
348     }
349   }
350
351   OSM_LOG_EXIT( p_mgr->p_log );
352   return( (osm_switch_t*)p_best_sw );
353 }
354
355 /**********************************************************************
356    This function returns the existing or optimal root swtich for the tree.
357 **********************************************************************/
358 static osm_switch_t*
359 __osm_mcast_mgr_find_root_switch(
360   osm_mcast_mgr_t* const p_mgr,
361   const osm_mgrp_t* const p_mgrp )
362 {
363   const osm_switch_t* p_sw = NULL;
364
365   OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_find_root_switch );
366
367   /*
368     We always look for the best multicast tree root switch.
369     Otherwise since we always start with a a single join
370     the root will be always on the first switch attached to it.
371     - Very bad ...
372   */
373   p_sw = __osm_mcast_mgr_find_optimal_switch( p_mgr, p_mgrp );
374
375   OSM_LOG_EXIT( p_mgr->p_log );
376   return( (osm_switch_t*)p_sw );
377 }
378
379 /**********************************************************************
380  **********************************************************************/
381 void
382 osm_mcast_mgr_construct(
383   IN osm_mcast_mgr_t* const p_mgr )
384 {
385   cl_memclr( p_mgr, sizeof(*p_mgr) );
386 }
387
388 /**********************************************************************
389  **********************************************************************/
390 void
391 osm_mcast_mgr_destroy(
392   IN osm_mcast_mgr_t* const p_mgr )
393 {
394   OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_destroy );
395
396   CL_ASSERT( p_mgr );
397   OSM_LOG_EXIT( p_mgr->p_log );
398 }
399
400 /**********************************************************************
401  **********************************************************************/
402 ib_api_status_t
403 osm_mcast_mgr_init(
404   IN osm_mcast_mgr_t*         const p_mgr,
405   IN osm_req_t*            const p_req,
406   IN osm_subn_t*           const p_subn,
407   IN osm_log_t*            const p_log,
408   IN cl_plock_t*           const p_lock )
409 {
410   ib_api_status_t          status = IB_SUCCESS;
411
412   OSM_LOG_ENTER( p_log, osm_mcast_mgr_init );
413
414   CL_ASSERT( p_req );
415   CL_ASSERT( p_subn );
416   CL_ASSERT( p_lock );
417
418   osm_mcast_mgr_construct( p_mgr );
419
420   p_mgr->p_log = p_log;
421   p_mgr->p_subn = p_subn;
422   p_mgr->p_lock = p_lock;
423   p_mgr->p_req = p_req;
424
425   OSM_LOG_EXIT( p_mgr->p_log );
426   return( status );
427 }
428
429 /**********************************************************************
430  **********************************************************************/
431 static osm_signal_t
432 __osm_mcast_mgr_set_tbl(
433   IN osm_mcast_mgr_t*         const p_mgr,
434   IN osm_switch_t*         const p_sw )
435 {
436   osm_node_t*              p_node;
437   osm_dr_path_t*           p_path;
438   osm_madw_context_t       mad_context;
439   ib_api_status_t          status;
440   uint32_t              block_id_ho = 0;
441   int16_t                  block_num = 0;
442   uint32_t              position = 0;
443   uint32_t              max_position;
444   osm_mcast_tbl_t*         p_tbl;
445   ib_net16_t               block[IB_MCAST_BLOCK_SIZE];
446   osm_signal_t          signal = OSM_SIGNAL_DONE;
447
448   OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_set_tbl );
449
450   CL_ASSERT( p_mgr );
451   CL_ASSERT( p_sw );
452
453   p_node = osm_switch_get_node_ptr( p_sw );
454
455   CL_ASSERT( p_node );
456
457   p_path = osm_node_get_any_dr_path_ptr( p_node );
458
459   CL_ASSERT( p_path );
460
461   /*
462     Send multicast forwarding table blocks to the switch
463     as long as the switch indicates it has blocks needing
464     configuration.
465   */
466
467   mad_context.mft_context.node_guid = osm_node_get_node_guid( p_node );
468   mad_context.mft_context.set_method = TRUE;
469
470   p_tbl = osm_switch_get_mcast_tbl_ptr( p_sw );
471   max_position = p_tbl->max_position;
472
473   while( osm_mcast_tbl_get_block( p_tbl, block_num,
474                                   (uint8_t)position, block ) )
475   {
476     if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
477     {
478       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
479                "__osm_mcast_mgr_set_tbl: "
480                "Writing MFT block 0x%X.\n", block_id_ho );
481     }
482
483     block_id_ho = block_num + (position << 28);
484
485     status = osm_req_set( p_mgr->p_req,
486                           p_path,
487                           (void*)block,
488                           IB_MAD_ATTR_MCAST_FWD_TBL,
489                           cl_hton32( block_id_ho ),
490                           CL_DISP_MSGID_NONE,
491                           &mad_context );
492
493     if( status != IB_SUCCESS )
494     {
495       osm_log( p_mgr->p_log, OSM_LOG_ERROR,
496                "__osm_mcast_mgr_set_tbl: ERR 0A02: "
497                "Sending linear fwd. tbl. block failed (%s).\n",
498                ib_get_err_str( status ) );
499     }
500
501     signal = OSM_SIGNAL_DONE_PENDING;
502
503     if( ++position > max_position )
504     {
505       position = 0;
506       block_num++;
507     }
508   }
509
510   OSM_LOG_EXIT( p_mgr->p_log );
511   return( signal );
512 }
513
514 /**********************************************************************
515   This is part of the recursive function to compute the paths in the
516   spanning tree that eminate from this switch.  On input, the p_list
517   contains the group members that must be routed from this switch.
518 **********************************************************************/
519 static void
520 __osm_mcast_mgr_subdivide(
521   osm_mcast_mgr_t*         const p_mgr,
522   osm_mgrp_t*              const p_mgrp,
523   osm_switch_t*            const p_sw,
524   cl_qlist_t*              const p_list,
525   cl_qlist_t*              const list_array,
526   uint8_t                  const array_size )
527 {
528   uint8_t                  port_num;
529   uint16_t              mlid_ho;
530   uint16_t              lid_ho;
531   boolean_t             ignore_existing;
532   osm_mcast_work_obj_t*    p_wobj;
533
534   OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_subdivide );
535
536   mlid_ho = cl_ntoh16( osm_mgrp_get_mlid( p_mgrp ) );
537
538   /* 
539      For Multicast Groups we want to not count on previous 
540      configurations - since we can easily generate a storm 
541      by loops.
542   */
543   ignore_existing = TRUE;
544
545   /*
546     Subdivide the set of ports into non-overlapping subsets
547     that will be routed to other switches.
548   */
549   while( (p_wobj = (osm_mcast_work_obj_t*)cl_qlist_remove_head( p_list )) !=
550          (osm_mcast_work_obj_t*)cl_qlist_end( p_list ) )
551   {
552     lid_ho = cl_ntoh16( osm_port_get_base_lid( p_wobj->p_port ) );
553
554     port_num = osm_switch_recommend_mcast_path(
555       p_sw, lid_ho, mlid_ho, ignore_existing );
556
557     if( port_num == OSM_NO_PATH )
558     {
559       /*
560         This typically occurs if the switch does not support
561         multicast and the multicast tree must branch at this
562         switch.
563       */
564       uint64_t node_guid_ho = cl_ntoh64( osm_node_get_node_guid(
565                                            osm_switch_get_node_ptr( p_sw ) ) );
566
567       osm_log( p_mgr->p_log, OSM_LOG_ERROR,
568                "__osm_mcast_mgr_subdivide: ERR 0A03: "
569                "Error routing MLID 0x%X through switch 0x%" PRIx64 ".\n"
570                "\t\t\t\tNo multicast paths from this switch for port "
571                "with LID 0x%X.\n",
572                mlid_ho, node_guid_ho, lid_ho );
573
574       __osm_mcast_work_obj_delete( p_wobj );
575       continue;
576     }
577
578     if( port_num > array_size )
579     {
580       uint64_t node_guid_ho = cl_ntoh64( osm_node_get_node_guid(
581                                            osm_switch_get_node_ptr( p_sw ) ) );
582
583       osm_log( p_mgr->p_log, OSM_LOG_ERROR,
584                "__osm_mcast_mgr_subdivide: ERR 0A04: "
585                "Error routing MLID 0x%X through switch "
586                "0x%" PRIx64 ".\n"
587                "\t\t\t\tNo multicast paths from this switch "
588                "to port with LID 0x%X.\n",
589                mlid_ho, node_guid_ho, lid_ho );
590
591       __osm_mcast_work_obj_delete( p_wobj );
592
593       /* This is means OpenSM has a bug. */
594       CL_ASSERT( FALSE );
595       continue;
596     }
597
598     cl_qlist_insert_tail( &list_array[port_num], &p_wobj->list_item );
599   }
600
601   OSM_LOG_EXIT( p_mgr->p_log );
602 }
603
604 /**********************************************************************
605  **********************************************************************/
606 static void
607 __osm_mcast_mgr_purge_list(
608   osm_mcast_mgr_t*         const p_mgr,
609   cl_qlist_t*              const p_list )
610 {
611   osm_mcast_work_obj_t*    p_wobj;
612
613   OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_purge_list );
614
615   while( (p_wobj = (osm_mcast_work_obj_t*)cl_qlist_remove_head( p_list ) )
616          != (osm_mcast_work_obj_t*)cl_qlist_end( p_list ) )
617   {
618     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
619              "__osm_mcast_mgr_purge_list: ERR 0A06: "
620              "Unable to route for port 0x%" PRIx64 ".\n",
621              osm_port_get_guid( p_wobj->p_port ) );
622     __osm_mcast_work_obj_delete( p_wobj );
623   }
624
625   OSM_LOG_EXIT( p_mgr->p_log );
626 }
627
628 /**********************************************************************
629   This is the recursive function to compute the paths in the spanning
630   tree that eminate from this switch.  On input, the p_list contains
631   the group members that must be routed from this switch.
632
633   The function returns the newly created mtree node element.
634 **********************************************************************/
635 static osm_mtree_node_t*
636 __osm_mcast_mgr_branch(
637   osm_mcast_mgr_t*         const p_mgr,
638   osm_mgrp_t*              const p_mgrp,
639   osm_switch_t*            const p_sw,
640   cl_qlist_t*              const p_list,
641   uint8_t                  depth,
642   uint8_t                  const upstream_port,
643   uint8_t*              const p_max_depth )
644 {
645   uint8_t                  max_children;
646   osm_mtree_node_t*        p_mtn = NULL;
647   cl_qlist_t*              list_array = NULL;
648   uint8_t                  i;
649   cl_qmap_t*               p_sw_guid_tbl;
650   ib_net64_t               node_guid;
651   uint64_t              node_guid_ho;
652   osm_mcast_work_obj_t*    p_wobj;
653   cl_qlist_t*              p_port_list;
654   size_t                count;
655   uint16_t              mlid_ho;
656   osm_mcast_tbl_t*         p_tbl;
657
658   OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_branch );
659
660   CL_ASSERT( p_sw );
661   CL_ASSERT( p_list );
662   CL_ASSERT( p_max_depth );
663
664   node_guid = osm_node_get_node_guid(  osm_switch_get_node_ptr( p_sw ) );
665   node_guid_ho = cl_ntoh64( node_guid );
666   mlid_ho = cl_ntoh16( osm_mgrp_get_mlid( p_mgrp ) );
667
668   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
669   {
670     osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
671              "__osm_mcast_mgr_branch: "
672              "Routing MLID 0x%X through switch 0x%" PRIx64 ".\n"
673              "\t\t\t\t%u nodes at depth %u.\n",
674              mlid_ho,
675              node_guid_ho,
676              cl_qlist_count( p_list ), depth );
677   }
678
679   CL_ASSERT( cl_qlist_count( p_list ) > 0 );
680
681   depth++;
682
683   if( depth > *p_max_depth )
684   {
685     CL_ASSERT( depth == *p_max_depth + 1 );
686     *p_max_depth = depth;
687   }
688
689   if( osm_switch_supports_mcast( p_sw ) == FALSE )
690   {
691     /*
692       This switch doesn't do multicast.  Clean-up.
693     */
694     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
695              "__osm_mcast_mgr_branch: ERR 0A14: "
696              "Switch 0x%" PRIx64 " does not support multicast.\n",
697              node_guid_ho );
698
699     /*
700       Deallocate all the work objects on this branch of the tree.
701     */
702     __osm_mcast_mgr_purge_list( p_mgr, p_list );
703     goto Exit;
704   }
705
706   p_mtn = osm_mtree_node_new( p_sw );
707   if( p_mtn == NULL )
708   {
709     /*
710       We are unable to continue routing down this
711       leg of the tree.  Clean-up.
712     */
713     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
714              "__osm_mcast_mgr_branch: ERR 0A15: "
715              "Insufficient memory to build multicast tree.\n" );
716
717     /*
718       Deallocate all the work objects on this branch of the tree.
719     */
720     __osm_mcast_mgr_purge_list( p_mgr, p_list );
721     goto Exit;
722   }
723
724   p_sw_guid_tbl = &p_mgr->p_subn->sw_guid_tbl;
725
726   max_children = osm_mtree_node_get_max_children( p_mtn );
727
728   CL_ASSERT( max_children > 1 );
729
730   /*
731     Prepare an empty list for each port in the switch.
732     TO DO - this list array could probably be moved
733     inside the switch element to save on malloc thrashing.
734   */
735   list_array = cl_zalloc( sizeof(cl_qlist_t) * max_children );
736   if( list_array == NULL )
737   {
738     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
739              "__osm_mcast_mgr_branch: ERR 0A16: "
740              "Unable to allocate list array.\n" );
741     __osm_mcast_mgr_purge_list( p_mgr, p_list );
742     goto Exit;
743   }
744
745   for( i = 0; i < max_children; i++ )
746     cl_qlist_init( &list_array[i] );
747
748   __osm_mcast_mgr_subdivide( p_mgr, p_mgrp, p_sw, p_list, list_array,
749                              max_children );
750
751   p_tbl = osm_switch_get_mcast_tbl_ptr( p_sw );
752
753   /*
754     Add the upstream port to the forwarding table unless
755     we're at the root of the spanning tree.
756   */
757   if( depth > 1 )
758   {
759     if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
760     {
761       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
762                "__osm_mcast_mgr_branch: "
763                "Adding upstream port 0x%X.\n", upstream_port );
764     }
765
766     CL_ASSERT( upstream_port );
767     osm_mcast_tbl_set( p_tbl, mlid_ho, upstream_port );
768   }
769
770   /*
771     For each port that was allocated some routes,
772     recurse into this function to continue building the tree
773     if the node on the other end of that port is another switch.
774     Otherwise, the node is an endpoint, and we've found a leaf
775     of the tree.  Mark leaves with our special pointer value.
776   */
777
778   for( i = 0; i < max_children; i++ )
779   {
780     const osm_physp_t      *p_physp;
781     const osm_physp_t      *p_remote_physp;
782     const osm_node_t    *p_node;
783     const osm_node_t    *p_remote_node;
784     osm_switch_t        *p_remote_sw;
785
786     p_port_list = &list_array[i];
787
788     count = cl_qlist_count( p_port_list );
789
790     /*
791       There should be no children routed through the upstream port!
792     */
793     CL_ASSERT( ( upstream_port == 0 ) || ( i != upstream_port) ||
794                ( (i == upstream_port) && (count == 0)) );
795
796     if( count == 0)
797       continue;      /* No routes down this port. */
798
799     if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
800     {
801       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
802                "__osm_mcast_mgr_branch: "
803                "Routing %u destination(s) via switch port 0x%X.\n",
804                count, i );
805     }
806
807     /*
808       This port routes frames for this mcast group.  Therefore,
809       set the appropriate bit in the multicast forwarding
810       table for this switch.
811     */
812     osm_mcast_tbl_set( p_tbl, mlid_ho, i );
813     if (i == 0) 
814       /* This means we are adding the switch to the mc group.
815          We do not need to continue looking at the remote port, just 
816          needed to add the port to the table */
817       continue;
818
819     p_node = osm_switch_get_node_ptr( p_sw );
820     p_remote_node = osm_node_get_remote_node( p_node, i, NULL );
821
822     if( osm_node_get_type( p_remote_node ) == IB_NODE_TYPE_SWITCH )
823     {
824       /*
825         Acquire a pointer to the remote switch then recurse.
826       */
827       p_remote_sw = (osm_switch_t*)cl_qmap_get(
828         p_sw_guid_tbl, osm_node_get_node_guid( p_remote_node ) );
829       CL_ASSERT( p_remote_sw );
830
831       p_physp = osm_node_get_physp_ptr( p_node, i );
832       CL_ASSERT( p_physp );
833       CL_ASSERT( osm_physp_is_valid( p_physp ) );
834
835       p_remote_physp = osm_physp_get_remote( p_physp );
836       CL_ASSERT( p_remote_physp );
837       CL_ASSERT( osm_physp_is_valid( p_remote_physp ) );
838
839       p_mtn->child_array[i] = __osm_mcast_mgr_branch(
840         p_mgr, p_mgrp, p_remote_sw,
841         p_port_list, depth,
842         osm_physp_get_port_num( p_remote_physp),
843         p_max_depth );
844     }
845     else
846     {
847       /*
848         The neighbor node is not a switch, so this
849         must be a leaf.
850       */
851       CL_ASSERT( count == 1 );
852
853       p_mtn->child_array[i] = OSM_MTREE_LEAF;
854       p_wobj = (osm_mcast_work_obj_t*)cl_qlist_remove_head(
855         p_port_list );
856
857       CL_ASSERT( cl_is_qlist_empty( p_port_list ) );
858
859       if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
860       {
861         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
862                  "__osm_mcast_mgr_branch: "
863                  "Found leaf for port 0x%016" PRIx64 ",\n"
864                  "\t\t\t\ton switch port 0x%X.\n",
865                  cl_ntoh64( osm_port_get_guid( p_wobj->p_port ) ), i );
866       }
867
868       __osm_mcast_work_obj_delete( p_wobj );
869     }
870   }
871
872   cl_free( list_array );
873  Exit:
874   OSM_LOG_EXIT( p_mgr->p_log );
875   return( p_mtn );
876 }
877
878 /**********************************************************************
879  **********************************************************************/
880 static ib_api_status_t
881 __osm_mcast_mgr_build_spanning_tree(
882   osm_mcast_mgr_t*         const p_mgr,
883   osm_mgrp_t*              const p_mgrp )
884 {
885   const cl_qmap_t*         p_mcm_tbl;
886   const cl_qmap_t*         p_port_tbl;
887   const osm_port_t*        p_port;
888   const osm_mcm_port_t*    p_mcm_port;
889   uint32_t              num_ports;
890   cl_qlist_t               port_list;
891   osm_switch_t*            p_sw;
892   osm_mcast_work_obj_t*    p_wobj;
893   ib_api_status_t          status = IB_SUCCESS;
894   uint8_t                  max_depth = 0;
895   uint32_t              count;
896
897   OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_build_spanning_tree );
898
899   cl_qlist_init( &port_list );
900
901   /*
902     TO DO - for now, just blow away the old tree.
903     In the future we'll need to construct the tree based
904     on multicast forwarding table information if the user wants to
905     preserve existing multicast routes.
906   */
907   __osm_mcast_mgr_purge_tree( p_mgr, p_mgrp );
908
909   p_mcm_tbl = &p_mgrp->mcm_port_tbl;
910   p_port_tbl = &p_mgr->p_subn->port_guid_tbl;
911   num_ports = cl_qmap_count( p_mcm_tbl );
912   if( num_ports == 0 )
913   {
914     if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
915     {
916       osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
917                "__osm_mcast_mgr_build_spanning_tree: "
918                "MLID 0x%X has no members--nothing to do.\n",
919                cl_ntoh16( osm_mgrp_get_mlid( p_mgrp ) ) );
920     }
921     goto Exit;
922   }
923
924   /*
925     This function builds the single spanning tree recursively.
926     At each stage, the ports to be reached are divided into
927     non-overlapping subsets of member ports that can be reached through
928     a given switch port.  Construction then moves down each
929     branch, and the process starts again with each branch computing
930     for its own subset of the member ports.
931
932     The maximum recursion depth is at worst the maximum hop count in the
933     subnet, which is spec limited to 64.
934   */
935
936   /*
937     Locate the switch around which to create the spanning
938     tree for this multicast group.
939   */
940   p_sw = __osm_mcast_mgr_find_root_switch( p_mgr, p_mgrp );
941   if( p_sw == NULL )
942   {
943     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
944              "__osm_mcast_mgr_build_spanning_tree: ERR 0A08: "
945              "Unable to locate a suitable switch for group 0x%X.\n",
946              cl_ntoh16( osm_mgrp_get_mlid( p_mgrp ) ));
947     status = IB_ERROR;
948     goto Exit;
949   }
950
951   /*
952     Build the first "subset" containing all member ports.
953   */
954   for( p_mcm_port = (osm_mcm_port_t*)cl_qmap_head( p_mcm_tbl );
955        p_mcm_port != (osm_mcm_port_t*)cl_qmap_end( p_mcm_tbl );
956        p_mcm_port = (osm_mcm_port_t*)cl_qmap_next(&p_mcm_port->map_item))
957   {
958     /*
959       Acquire the port object for this port guid, then create
960       the new worker object to build the list.
961     */
962     p_port = (osm_port_t*)cl_qmap_get( p_port_tbl,
963                                        ib_gid_get_guid( &p_mcm_port->port_gid ) );
964
965     if( p_port == (osm_port_t*)cl_qmap_end( p_port_tbl ) )
966     {
967       osm_log( p_mgr->p_log, OSM_LOG_ERROR,
968                "__osm_mcast_mgr_build_spanning_tree: ERR 0A09: "
969                "No port object for port 0x%016" PRIx64 ".\n",
970                cl_ntoh64( ib_gid_get_guid( &p_mcm_port->port_gid ) ) );
971       continue;
972     }
973
974     p_wobj = __osm_mcast_work_obj_new( p_port );
975     if( p_wobj == NULL )
976     {
977       osm_log( p_mgr->p_log, OSM_LOG_ERROR,
978                "__osm_mcast_mgr_build_spanning_tree: ERR 0A10: "
979                "Insufficient memory to route port 0x%016" PRIx64 ".\n",
980                cl_ntoh64( osm_port_get_guid( p_port ) ) );
981       continue;
982     }
983
984     cl_qlist_insert_tail( &port_list, &p_wobj->list_item );
985   }
986
987   count = cl_qlist_count( &port_list );
988   p_mgrp->p_root = __osm_mcast_mgr_branch( p_mgr, p_mgrp, p_sw,
989                                            &port_list, 0, 0, &max_depth );
990
991   osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
992            "__osm_mcast_mgr_build_spanning_tree: "
993            "Configured MLID 0x%X for %u ports, max tree depth = %u.\n",
994            cl_ntoh16( osm_mgrp_get_mlid( p_mgrp ) ),
995            count, max_depth );
996
997  Exit:
998   OSM_LOG_EXIT( p_mgr->p_log );
999   return( status );
1000 }
1001 #if 0
1002 /* unused */
1003 /**********************************************************************
1004  **********************************************************************/
1005 void
1006 osm_mcast_mgr_set_table(
1007   IN osm_mcast_mgr_t*         const p_mgr,
1008   IN const osm_mgrp_t*     const p_mgrp,
1009   IN const osm_mtree_node_t*  const p_mtn )
1010 {
1011   uint8_t i;
1012   uint8_t max_children;
1013   osm_mtree_node_t* p_child_mtn;
1014   uint16_t mlid_ho;
1015   osm_mcast_tbl_t* p_tbl;
1016   osm_switch_t* p_sw;
1017
1018   OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_set_table );
1019
1020   mlid_ho = cl_ntoh16( osm_mgrp_get_mlid( p_mgrp ) );
1021   p_sw = osm_mtree_node_get_switch_ptr( p_mtn );
1022
1023   CL_ASSERT( p_sw );
1024
1025   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
1026   {
1027     osm_log( p_mgr->p_log, OSM_LOG_VERBOSE,
1028              "osm_mcast_mgr_set_table: "
1029              "Configuring MLID 0x%X on switch 0x%" PRIx64 ".\n",
1030              mlid_ho, osm_node_get_node_guid(
1031                osm_switch_get_node_ptr( p_sw ) ) );
1032   }
1033
1034   /*
1035     For every child of this tree node, set the corresponding
1036     bit in the switch's mcast table.
1037   */
1038   p_tbl = osm_switch_get_mcast_tbl_ptr( p_sw );
1039   max_children = osm_mtree_node_get_max_children( p_mtn );
1040
1041   CL_ASSERT( max_children <= osm_switch_get_num_ports( p_sw ) );
1042
1043   osm_mcast_tbl_clear_mlid( p_tbl, mlid_ho );
1044
1045   for( i = 0; i < max_children; i++ )
1046   {
1047     p_child_mtn = osm_mtree_node_get_child( p_mtn, i );
1048     if( p_child_mtn == NULL )
1049       continue;
1050
1051     osm_mcast_tbl_set( p_tbl, mlid_ho, i );
1052   }
1053
1054   OSM_LOG_EXIT( p_mgr->p_log );
1055 }
1056 #endif
1057
1058 /**********************************************************************
1059  **********************************************************************/
1060 static void
1061 __osm_mcast_mgr_clear(
1062   IN osm_mcast_mgr_t*         const p_mgr,
1063   IN osm_mgrp_t*           const p_mgrp )
1064 {
1065   osm_switch_t*            p_sw;
1066   cl_qmap_t*               p_tbl;
1067   osm_mcast_tbl_t*         p_mcast_tbl;
1068
1069
1070   OSM_LOG_ENTER( p_mgr->p_log, __osm_mcast_mgr_clear );
1071
1072   /*
1073     Walk the switches and clear the routing entries for
1074     this MLID.
1075   */
1076   p_tbl = &p_mgr->p_subn->sw_guid_tbl;
1077   p_sw = (osm_switch_t*)cl_qmap_head( p_tbl );
1078   while( p_sw != (osm_switch_t*)cl_qmap_end( p_tbl ) )
1079   {
1080     p_mcast_tbl = osm_switch_get_mcast_tbl_ptr( p_sw );
1081     osm_mcast_tbl_clear_mlid( p_mcast_tbl, cl_ntoh16(p_mgrp->mlid) );
1082     p_sw = (osm_switch_t*)cl_qmap_next( &p_sw->map_item );
1083   }
1084
1085   OSM_LOG_EXIT( p_mgr->p_log );
1086 }
1087
1088 #if 0
1089 /* TO DO - make this real -- at least update spanning tree */
1090 /**********************************************************************
1091    Lock must be held on entry.
1092 **********************************************************************/
1093 ib_api_status_t
1094 osm_mcast_mgr_process_single(
1095   IN osm_mcast_mgr_t*         const p_mgr,
1096   IN ib_net16_t            const mlid,
1097   IN ib_net64_t            const port_guid,
1098   IN uint8_t               const join_state )
1099 {
1100   uint8_t                  port_num;
1101   uint16_t              mlid_ho;
1102   osm_switch_t*            p_sw;
1103   ib_net64_t               sw_guid;
1104   osm_port_t*              p_port;
1105   osm_physp_t*          p_physp;
1106   osm_physp_t*          p_remote_physp;
1107   osm_node_t*              p_remote_node;
1108   cl_qmap_t*               p_port_tbl;
1109   cl_qmap_t*               p_sw_tbl;
1110   osm_mcast_tbl_t*         p_mcast_tbl;
1111   ib_api_status_t          status = IB_SUCCESS;
1112
1113   OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_process_single );
1114
1115   CL_ASSERT( mlid );
1116   CL_ASSERT( port_guid );
1117
1118   p_port_tbl = &p_mgr->p_subn->port_guid_tbl;
1119   p_sw_tbl = &p_mgr->p_subn->sw_guid_tbl;
1120   mlid_ho = cl_ntoh16( mlid );
1121
1122   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
1123   {
1124     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1125              "osm_mcast_mgr_process_single: "
1126              "Attempting to add port 0x%" PRIx64 " to MLID 0x%X, "
1127              "\n\t\t\t\tjoin state = 0x%X.\n",
1128              cl_ntoh64( port_guid ), mlid_ho, join_state );
1129   }
1130
1131   /*
1132     Acquire the Port object.
1133   */
1134   p_port = (osm_port_t*)cl_qmap_get( p_port_tbl, port_guid );
1135   if( p_port == (osm_port_t*)cl_qmap_end( p_port_tbl ) )
1136   {
1137     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1138              "osm_mcast_mgr_process_single: ERR 0A01: "
1139              "Unable to acquire port object for 0x%" PRIx64 ".\n",
1140              cl_ntoh64( port_guid ) );
1141     status = IB_ERROR;
1142     goto Exit;
1143   }
1144
1145   p_physp = osm_port_get_default_phys_ptr( p_port );
1146   if( p_physp == NULL )
1147   {
1148     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1149              "osm_mcast_mgr_process_single: ERR 0A05: "
1150              "Unable to acquire phsyical port object for 0x%" PRIx64 ".\n",
1151              cl_ntoh64( port_guid ) );
1152     status = IB_ERROR;
1153     goto Exit;
1154   }
1155
1156   if( !osm_physp_is_valid( p_physp ) )
1157   {
1158     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1159              "osm_mcast_mgr_process_single: ERR 0A07: "
1160              "Unable to acquire valid physical port object "
1161              "for 0x%" PRIx64 ".\n",
1162              cl_ntoh64( port_guid ) );
1163     status = IB_ERROR;
1164     goto Exit;
1165   }
1166
1167   p_remote_physp = osm_physp_get_remote( p_physp );
1168   if( p_remote_physp == NULL )
1169   {
1170     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1171              "osm_mcast_mgr_process_single: ERR 0A11: "
1172              "Unable to acquire remote phsyical port object "
1173              "for 0x%" PRIx64 ".\n",
1174              cl_ntoh64( port_guid ) );
1175     status = IB_ERROR;
1176     goto Exit;
1177   }
1178
1179   if( !osm_physp_is_valid( p_remote_physp ) )
1180   {
1181     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1182              "osm_mcast_mgr_process_single: ERR 0A21: "
1183              "Unable to acquire valid remote physical port object "
1184              "for 0x%" PRIx64 ".\n",
1185              cl_ntoh64( port_guid ) );
1186     status = IB_ERROR;
1187     goto Exit;
1188   }
1189
1190   p_remote_node = osm_physp_get_node_ptr( p_remote_physp );
1191
1192   CL_ASSERT( p_remote_node );
1193
1194   sw_guid = osm_node_get_node_guid( p_remote_node );
1195
1196   if( osm_node_get_type( p_remote_node ) != IB_NODE_TYPE_SWITCH )
1197   {
1198     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1199              "osm_mcast_mgr_process_single: ERR 0A22: "
1200              "Remote node not a switch node 0x%" PRIx64 ".\n",
1201              cl_ntoh64( sw_guid ) );
1202     status = IB_ERROR;
1203     goto Exit;
1204   }
1205
1206   p_sw = (osm_switch_t*)cl_qmap_get( p_sw_tbl, sw_guid );
1207   if( p_sw == (osm_switch_t*)cl_qmap_end( p_sw_tbl ) )
1208   {
1209     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1210              "osm_mcast_mgr_process_single: ERR 0A12: "
1211              "No switch object 0x%" PRIx64 ".\n",
1212              cl_ntoh64( sw_guid ) );
1213     status = IB_ERROR;
1214     goto Exit;
1215   }
1216
1217   if( osm_switch_is_in_mcast_tree( p_sw, mlid_ho ) )
1218   {
1219     /*
1220       We're in luck.  The switch attached to this port
1221       is already in the multicast group, so we can just
1222       add the specified port as a new leaf of the tree.
1223     */
1224     if( join_state & (IB_JOIN_STATE_FULL | IB_JOIN_STATE_NON ) )
1225     {
1226       /*
1227         This node wants to receive multicast frames.
1228         Get the switch port number to which the new member port
1229         is attached, then configure this single mcast table.
1230       */
1231       port_num = osm_physp_get_port_num( p_remote_physp );
1232       CL_ASSERT( port_num );
1233
1234       p_mcast_tbl = osm_switch_get_mcast_tbl_ptr( p_sw );
1235       osm_mcast_tbl_set( p_mcast_tbl, mlid_ho, port_num );
1236     }
1237     else
1238     {
1239       if( join_state & IB_JOIN_STATE_SEND_ONLY )
1240       {
1241         if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
1242         {
1243           osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1244                    "osm_mcast_mgr_process_single: "
1245                    "Success.  Nothing to do for send"
1246                    "only member.\n" );
1247         }
1248       }
1249       else
1250       {
1251         osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1252                  "osm_mcast_mgr_process_single: ERR 0A13: "
1253                  "Unknown join state 0x%X.\n", join_state );
1254         status = IB_ERROR;
1255         goto Exit;
1256       }
1257     }
1258   }
1259   else
1260   {
1261     if( osm_log_is_active( p_mgr->p_log, OSM_LOG_VERBOSE ) )
1262     {
1263       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1264                "osm_mcast_mgr_process_single: "
1265                "Unable to add port.\n" );
1266     }
1267   }
1268
1269  Exit:
1270   OSM_LOG_EXIT( p_mgr->p_log );
1271   return( status );
1272 }
1273 #endif
1274
1275 /**********************************************************************
1276    lock must already be held on entry
1277 **********************************************************************/
1278 ib_api_status_t
1279 osm_mcast_mgr_process_tree(
1280   IN osm_mcast_mgr_t*      const p_mgr,
1281   IN osm_mgrp_t*           const p_mgrp,
1282   IN osm_mcast_req_type_t        req_type,
1283   ib_net64_t                     port_guid )
1284 {
1285   ib_api_status_t          status = IB_SUCCESS;
1286   cl_qmap_t*               p_tbl;
1287   ib_net16_t               mlid;
1288   boolean_t                ui_mcast_fdb_assign_func_defined;
1289
1290   OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_process_tree );
1291
1292   mlid = osm_mgrp_get_mlid( p_mgrp );
1293   p_tbl = &p_mgr->p_subn->sw_guid_tbl;
1294
1295   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
1296   {
1297     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1298              "osm_mcast_mgr_process_tree: "
1299              "Processing multicast group 0x%X.\n", cl_ntoh16( mlid ));
1300   }
1301
1302   /*
1303     If there are no switches in the subnet, then we have nothing to do.
1304   */
1305   if( cl_qmap_count( &p_mgr->p_subn->sw_guid_tbl ) == 0 )
1306   {
1307     if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
1308     {
1309       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1310                "osm_mcast_mgr_process_tree: "
1311                "No switches in subnet.  Nothing to do.\n" );
1312     }
1313     goto Exit;
1314   }
1315
1316   if (p_mgr->p_subn->opt.pfn_ui_mcast_fdb_assign)
1317     ui_mcast_fdb_assign_func_defined = TRUE;
1318   else
1319     ui_mcast_fdb_assign_func_defined = FALSE;
1320
1321   /*
1322     Clear the multicast tables to start clean, then build
1323     the spanning tree which sets the mcast table bits for each
1324     port in the group.
1325     We will clean the multicast tables if a ui_mcast function isn't
1326     defined, or if such function is defined, but we got here
1327     through a MC_CREATE request - this means we are creating a new
1328     multicast group - clean all old data.
1329   */
1330   if ( ui_mcast_fdb_assign_func_defined == FALSE ||
1331        req_type == OSM_MCAST_REQ_TYPE_CREATE ) 
1332     __osm_mcast_mgr_clear( p_mgr, p_mgrp );
1333
1334   /* If a UI function is defined, then we will call it here. 
1335      If not - the use the regular build spanning tree function */
1336   if ( ui_mcast_fdb_assign_func_defined == FALSE )
1337   {
1338     status = __osm_mcast_mgr_build_spanning_tree( p_mgr, p_mgrp );
1339     if( status != IB_SUCCESS )
1340     {
1341       osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1342                "osm_mcast_mgr_process_tree: ERR 0A17: "
1343                "Unable to create spanning tree (%s).\n",
1344                ib_get_err_str( status ) );
1345       goto Exit;
1346     }
1347   }
1348   else
1349   {
1350     if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
1351     {
1352       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1353                "osm_mcast_mgr_process_tree: "
1354                "Invoking UI function pfn_ui_mcast_fdb_assign\n");
1355     }
1356     
1357     p_mgr->p_subn->opt.pfn_ui_mcast_fdb_assign(
1358       p_mgr->p_subn->opt.ui_mcast_fdb_assign_ctx,
1359       mlid, req_type, port_guid );
1360   }    
1361   
1362  Exit:
1363   OSM_LOG_EXIT( p_mgr->p_log );
1364   return( status );
1365 }
1366
1367 /**********************************************************************
1368  **********************************************************************/
1369 void
1370 osm_mcast_mgr_dump_mcast_routes(
1371   IN const osm_mcast_mgr_t*   const p_mgr,
1372   IN const osm_switch_t*      const p_sw )
1373 {
1374   osm_mcast_tbl_t*      p_tbl;
1375   int16_t               mlid_ho = 0;
1376   int16_t               mlid_start_ho;
1377   uint8_t               position = 0;
1378   int16_t               block_num = 0;
1379   char                  line[OSM_REPORT_LINE_SIZE];
1380   boolean_t             print_lid;
1381   const osm_node_t*     p_node;
1382   FILE  *               p_mcfdbFile;
1383   uint16_t              i, j;
1384   uint16_t              mask_entry;
1385   char                 *file_name = NULL;
1386
1387   OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_dump_mcast_routes );
1388   
1389   if( !osm_log_is_active( p_mgr->p_log, OSM_LOG_ROUTING ) )
1390     goto Exit;
1391
1392   file_name = 
1393     (char*)cl_malloc(strlen(p_mgr->p_subn->opt.dump_files_dir) + 12);
1394   
1395   CL_ASSERT(file_name);
1396   
1397   strcpy(file_name, p_mgr->p_subn->opt.dump_files_dir);
1398   strcat(file_name,"/osm.mcfdbs");
1399   
1400   /* Open the file or error */
1401   p_mcfdbFile = fopen(file_name, "a");
1402   if (! p_mcfdbFile)
1403   {
1404     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1405              "osm_mcast_mgr_dump_mcast_routes: ERR 0A23: "
1406              "Fail to open mcfdb file (%s).\n",
1407              file_name );
1408     goto Exit;
1409   }
1410
1411   p_node = osm_switch_get_node_ptr( p_sw );
1412
1413   p_tbl = osm_switch_get_mcast_tbl_ptr( p_sw );
1414
1415   fprintf( p_mcfdbFile, "\nSwitch 0x%016" PRIx64 "\n"
1416            "LID    : Out Port(s) \n",
1417            cl_ntoh64( osm_node_get_node_guid( p_node ) ) );  
1418   while ( block_num <= p_tbl->max_block_in_use )
1419   {
1420     mlid_start_ho = (uint16_t)(block_num * IB_MCAST_BLOCK_SIZE);
1421     for (i = 0 ; i < IB_MCAST_BLOCK_SIZE ; i++)
1422     {
1423       mlid_ho = mlid_start_ho + i;
1424       position = 0;
1425       print_lid = FALSE;
1426       sprintf( line, "0x%04X :", mlid_ho + IB_LID_MCAST_START_HO );
1427       while ( position <= p_tbl->max_position )
1428       {
1429         mask_entry = cl_ntoh16((*p_tbl->p_mask_tbl)[mlid_ho][position]);
1430         if (mask_entry == 0)
1431         {
1432           position++;
1433           continue;
1434         }
1435         print_lid = TRUE;
1436         for (j = 0 ; j < 16 ; j++)
1437         {
1438           if ( (1 << j) & mask_entry )
1439             sprintf( line, "%s 0x%03X ", line, j+(position*16) );
1440         }
1441         position++;
1442       }
1443       if (print_lid)
1444       {
1445         fprintf( p_mcfdbFile, "%s\n", line );
1446       }
1447     }
1448     block_num++;
1449   }
1450
1451   fclose(p_mcfdbFile);
1452
1453  Exit:
1454   if (file_name)
1455     cl_free(file_name);
1456   OSM_LOG_EXIT( p_mgr->p_log );
1457 }
1458
1459 /**********************************************************************
1460  Process the entire group.
1461
1462  NOTE : The lock should be held externally!
1463  **********************************************************************/
1464 osm_signal_t
1465 osm_mcast_mgr_process_mgrp(
1466   IN osm_mcast_mgr_t*      const p_mgr,
1467   IN osm_mgrp_t*           const p_mgrp,
1468   IN osm_mcast_req_type_t        req_type,
1469   IN ib_net64_t                  port_guid )
1470 {
1471   osm_signal_t          signal = OSM_SIGNAL_DONE;
1472   ib_api_status_t          status;
1473   osm_switch_t*            p_sw;
1474   cl_qmap_t*               p_tbl;
1475   boolean_t             pending_transactions = FALSE;
1476
1477   OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_process_mgrp );
1478
1479   p_tbl = &p_mgr->p_subn->sw_guid_tbl;
1480
1481   status = osm_mcast_mgr_process_tree( p_mgr, p_mgrp, req_type, port_guid );
1482   if( status != IB_SUCCESS )
1483   {
1484     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1485              "osm_mcast_mgr_process_mgrp: ERR 0A19: "
1486              "Unable to create spanning tree (%s).\n",
1487              ib_get_err_str( status ) );
1488
1489     goto Exit;
1490   }
1491
1492   /* initialize the mc fdb dump file: */
1493   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_ROUTING ) )
1494     unlink("/tmp/osm.mcfdbs");
1495
1496   /*
1497     Walk the switches and download the tables for each.
1498   */
1499   p_sw = (osm_switch_t*)cl_qmap_head( p_tbl );
1500   while( p_sw != (osm_switch_t*)cl_qmap_end( p_tbl ) )
1501   {
1502     signal = __osm_mcast_mgr_set_tbl( p_mgr, p_sw );
1503     if( signal == OSM_SIGNAL_DONE_PENDING )
1504       pending_transactions = TRUE;
1505
1506     osm_mcast_mgr_dump_mcast_routes( p_mgr, p_sw );
1507
1508     p_sw = (osm_switch_t*)cl_qmap_next( &p_sw->map_item );
1509   }
1510
1511  Exit:
1512   OSM_LOG_EXIT( p_mgr->p_log );
1513
1514   if( pending_transactions == TRUE )
1515     return( OSM_SIGNAL_DONE_PENDING );
1516   else
1517     return( OSM_SIGNAL_DONE );
1518 }
1519
1520 /**********************************************************************
1521  **********************************************************************/
1522 osm_signal_t
1523 osm_mcast_mgr_process(
1524   IN osm_mcast_mgr_t*         const p_mgr )
1525 {
1526   osm_signal_t          signal;
1527   osm_switch_t*            p_sw;
1528   cl_qmap_t*               p_tbl;
1529   cl_qmap_t*               p_mcast_tbl;
1530   osm_mgrp_t*              p_mgrp;
1531   ib_api_status_t          status;
1532   boolean_t             pending_transactions = FALSE;
1533
1534   OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_process );
1535
1536   p_tbl = &p_mgr->p_subn->sw_guid_tbl;
1537
1538   p_mcast_tbl = &p_mgr->p_subn->mgrp_mlid_tbl;
1539   /*
1540     While holding the lock, iterate over all the established
1541     multicast groups, servicing each in turn.
1542
1543     Then, download the multicast tables to the switches.
1544   */
1545   CL_PLOCK_EXCL_ACQUIRE( p_mgr->p_lock );
1546
1547   p_mgrp = (osm_mgrp_t*)cl_qmap_head( p_mcast_tbl );
1548   while( p_mgrp != (osm_mgrp_t*)cl_qmap_end( p_mcast_tbl ) )
1549   {
1550     /* We reached here due to some change that caused a heavy sweep
1551        of the subnet. Not due to a specific multicast request.
1552        So the request type is subnet_change and the port guid is 0. */
1553     status = osm_mcast_mgr_process_tree( p_mgr, p_mgrp,
1554                                          OSM_MCAST_REQ_TYPE_SUBNET_CHANGE, 0);
1555     if( status != IB_SUCCESS )
1556     {
1557       osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1558                "osm_mcast_mgr_process: ERR 0A20: "
1559                "Unable to create spanning tree (%s).\n",
1560                ib_get_err_str( status ) );
1561     }
1562
1563     p_mgrp = (osm_mgrp_t*)cl_qmap_next( &p_mgrp->map_item );
1564   }
1565
1566   /* initialize the mc fdb dump file: */
1567   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_ROUTING ) )
1568     unlink("/tmp/osm.mcfdbs");
1569
1570   /*
1571     Walk the switches and download the tables for each.
1572   */
1573   p_sw = (osm_switch_t*)cl_qmap_head( p_tbl );
1574   while( p_sw != (osm_switch_t*)cl_qmap_end( p_tbl ) )
1575   {
1576     signal = __osm_mcast_mgr_set_tbl( p_mgr, p_sw );
1577     if( signal == OSM_SIGNAL_DONE_PENDING )
1578       pending_transactions = TRUE;
1579
1580     osm_mcast_mgr_dump_mcast_routes( p_mgr, p_sw );
1581
1582     p_sw = (osm_switch_t*)cl_qmap_next( &p_sw->map_item );
1583   }
1584
1585   CL_PLOCK_RELEASE( p_mgr->p_lock );
1586
1587   OSM_LOG_EXIT( p_mgr->p_log );
1588
1589   if( pending_transactions == TRUE )
1590     return( OSM_SIGNAL_DONE_PENDING );
1591   else
1592     return( OSM_SIGNAL_DONE );
1593 }
1594
1595 /**********************************************************************
1596  **********************************************************************/
1597
1598 static
1599 osm_mgrp_t *
1600 __get_mgrp_by_mlid(
1601   IN osm_mcast_mgr_t* const p_mgr,
1602   IN ib_net16_t const mlid)
1603 {
1604   cl_map_item_t *map_item;
1605
1606   map_item = cl_qmap_get(&p_mgr->p_subn->mgrp_mlid_tbl, mlid);
1607   if(map_item == cl_qmap_end(&p_mgr->p_subn->mgrp_mlid_tbl))
1608   {
1609     return NULL;
1610   }
1611   return (osm_mgrp_t *)map_item;
1612 }
1613
1614 /**********************************************************************
1615   This is the function that is invoked during idle time to handle the 
1616   process request. Context1 is simply the osm_mcast_mgr_t*, Context2
1617   hold the mlid, port guid and action (join/leave/delete) required.
1618  **********************************************************************/
1619 osm_signal_t
1620 osm_mcast_mgr_process_mgrp_cb(
1621   IN void*              const Context1,
1622   IN void*              const Context2 )
1623 {
1624   osm_mcast_mgr_t* p_mgr = (osm_mcast_mgr_t*)Context1;
1625   osm_mgrp_t* p_mgrp;
1626   ib_net16_t  mlid;
1627   osm_signal_t signal;
1628   osm_mcast_mgr_ctxt_t* p_ctxt = (osm_mcast_mgr_ctxt_t*)Context2;
1629   osm_mcast_req_type_t req_type = p_ctxt->req_type;
1630   ib_net64_t port_guid = p_ctxt->port_guid;
1631
1632   OSM_LOG_ENTER( p_mgr->p_log, osm_mcast_mgr_process_mgrp_cb );
1633  
1634   /* nice copy no warning on size diff */
1635   cl_memcpy(&mlid, &p_ctxt->mlid, sizeof(mlid));
1636
1637   /* we can destroy the context now */
1638   cl_free(p_ctxt);
1639
1640   /* we need a lock to make sure the p_mgrp is not change other ways */
1641   CL_PLOCK_EXCL_ACQUIRE( p_mgr->p_lock );
1642   p_mgrp = __get_mgrp_by_mlid( p_mgr, mlid);
1643
1644   /* since we delayed the execution we prefer to pass the
1645      mlid as the mgrp identifier and then find it or abort */
1646
1647   if (p_mgrp)
1648   {
1649
1650     /* if there was no change from the last time we processed the group
1651        we can skip doing anything
1652     */
1653     if ( p_mgrp->last_change_id == p_mgrp->last_tree_id)
1654     {
1655       signal = OSM_SIGNAL_DONE;
1656       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1657                "osm_mcast_mgr_process_mgrp_cb: "
1658                "Skip processing mgrp with lid:0x%X change id:%u \n",
1659                cl_ntoh16(mlid), p_mgrp->last_change_id );
1660     }
1661     else
1662     {
1663       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1664                "osm_mcast_mgr_process_mgrp_cb: "
1665                "Processing mgrp with lid:0x%X change id:%u \n",
1666                cl_ntoh16(mlid), p_mgrp->last_change_id );
1667
1668       signal =
1669         osm_mcast_mgr_process_mgrp( p_mgr, p_mgrp, req_type, port_guid );
1670       p_mgrp->last_tree_id = p_mgrp->last_change_id;
1671     }
1672     CL_PLOCK_RELEASE( p_mgr->p_lock );
1673
1674     /* Remove MGRP only if osm_mcm_port_t count is 0 and
1675      * Not a well known group
1676      */
1677     if((0x0 == cl_qmap_count(&p_mgrp->mcm_port_tbl)) &&
1678        (p_mgrp->well_known == FALSE))
1679     {
1680       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1681                "osm_mcast_mgr_process_mgrp_cb: "
1682                "Destroying mgrp with lid:0x%X \n",
1683                cl_ntoh16(mlid) );
1684
1685      /* Send a Report to any InformInfo registerd for
1686          Trap 67 : MCGroup delete */
1687       osm_mgrp_send_delete_notice( p_mgr->p_subn, p_mgr->p_log, p_mgrp );
1688
1689       CL_PLOCK_EXCL_ACQUIRE( p_mgr->p_lock );
1690       cl_qmap_remove_item(&p_mgr->p_subn->mgrp_mlid_tbl,
1691                           (cl_map_item_t *)p_mgrp );
1692
1693       osm_mgrp_destroy(p_mgrp);
1694       CL_PLOCK_RELEASE( p_mgr->p_lock );
1695     }
1696     /* no need for CL_PLOCK_RELEASE( p_mgr->p_lock ) - internally done */
1697     OSM_LOG_EXIT( p_mgr->p_log );
1698     return signal;
1699   }
1700   else
1701   {
1702     CL_PLOCK_RELEASE( p_mgr->p_lock );
1703     OSM_LOG_EXIT( p_mgr->p_log );
1704     return OSM_SIGNAL_DONE;
1705   }
1706
1707 }