In osm_ucast_mgr, where osm_req_set is called for SwitchInfo,
[mirror/winof/.git] / ulp / opensm / user / opensm / osm_ucast_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_ucast_mgr_t.
38  * This file implements the LID Manager object.
39  *
40  * Environment:
41  *    Linux User Mode
42  *
43  * $Revision: 1.14 $
44  */
45
46 /*
47   Next available error code: 0x403
48 */
49
50 #if HAVE_CONFIG_H
51 #  include <config.h>
52 #endif /* HAVE_CONFIG_H */
53
54 #include <iba/ib_types.h>
55 #include <complib/cl_memory.h>
56 #include <complib/cl_qmap.h>
57 #include <complib/cl_debug.h>
58 #include <opensm/osm_ucast_mgr.h>
59 #include <opensm/osm_log.h>
60 #include <opensm/osm_node.h>
61 #include <opensm/osm_switch.h>
62 #include <opensm/osm_helper.h>
63 #include <opensm/osm_msgdef.h>
64
65 #define LINE_LENGTH 256
66
67 /**********************************************************************
68  **********************************************************************/
69 /*
70  * This flag is used for stopping the relaxation algorithm if no
71  * change detected during the fabric scan
72  */
73 static boolean_t __some_hop_count_set;
74
75 /**********************************************************************
76  **********************************************************************/
77 void
78 osm_ucast_mgr_construct(
79   IN osm_ucast_mgr_t* const p_mgr )
80 {
81   cl_memclr( p_mgr, sizeof(*p_mgr) );
82 }
83
84 /**********************************************************************
85  **********************************************************************/
86 void
87 osm_ucast_mgr_destroy(
88   IN osm_ucast_mgr_t* const p_mgr )
89 {
90   OSM_LOG_ENTER( p_mgr->p_log, osm_ucast_mgr_destroy );
91
92   CL_ASSERT( p_mgr );
93   OSM_LOG_EXIT( p_mgr->p_log );
94 }
95
96
97 /**********************************************************************
98  **********************************************************************/
99 ib_api_status_t
100 osm_ucast_mgr_init(
101   IN osm_ucast_mgr_t* const p_mgr,
102   IN osm_req_t* const p_req,
103   IN osm_subn_t* const p_subn,
104   IN char* const p_report_buf,
105   IN osm_log_t* const p_log,
106   IN cl_plock_t* const p_lock )
107 {
108   ib_api_status_t status = IB_SUCCESS;
109
110   OSM_LOG_ENTER( p_log, osm_ucast_mgr_init );
111
112   CL_ASSERT( p_req );
113   CL_ASSERT( p_subn );
114   CL_ASSERT( p_lock );
115
116   osm_ucast_mgr_construct( p_mgr );
117
118   p_mgr->p_log = p_log;
119   p_mgr->p_subn = p_subn;
120   p_mgr->p_lock = p_lock;
121   p_mgr->p_req = p_req;
122   p_mgr->p_report_buf = p_report_buf;
123
124   OSM_LOG_EXIT( p_mgr->p_log );
125   return( status );
126 }
127
128 /**********************************************************************
129  **********************************************************************/
130 void
131 osm_ucast_mgr_dump_path_distribution(
132   IN const osm_ucast_mgr_t* const p_mgr,
133   IN const osm_switch_t* const p_sw )
134 {
135   osm_node_t *p_node;
136   osm_node_t *p_remote_node;
137   uint8_t i;
138   uint8_t num_ports;
139   uint32_t num_paths;
140   ib_net64_t remote_guid_ho;
141   char line[OSM_REPORT_LINE_SIZE];
142
143   OSM_LOG_ENTER( p_mgr->p_log, osm_ucast_mgr_dump_path_distribution );
144
145   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
146   {
147     p_node = osm_switch_get_node_ptr( p_sw );
148
149     num_ports = osm_switch_get_num_ports( p_sw );
150     sprintf( p_mgr->p_report_buf, "osm_ucast_mgr_dump_path_distribution: "
151              "Switch 0x%" PRIx64 "\n"
152              "Port : Path Count Through Port",
153              cl_ntoh64( osm_node_get_node_guid( p_node ) ) );
154
155     for( i = 0; i < num_ports; i++ )
156     {
157       num_paths = osm_switch_path_count_get( p_sw , i );
158       sprintf( line, "\n %03u : %u", i, num_paths );
159       strcat( p_mgr->p_report_buf, line );
160       if( i == 0 )
161       {
162         strcat( p_mgr->p_report_buf, " (switch management port)" );
163         continue;
164       }
165
166       p_remote_node = osm_node_get_remote_node(
167         p_node, i, NULL );
168
169       if( p_remote_node == NULL )
170         continue;
171
172       remote_guid_ho = cl_ntoh64(
173         osm_node_get_node_guid( p_remote_node ) );
174
175       switch(  osm_node_get_remote_type( p_node, i ) )
176       {
177       case IB_NODE_TYPE_SWITCH:
178         strcat( p_mgr->p_report_buf, " (link to switch" );
179         break;
180       case IB_NODE_TYPE_ROUTER:
181         strcat( p_mgr->p_report_buf, " (link to router" );
182         break;
183       case IB_NODE_TYPE_CA:
184         strcat( p_mgr->p_report_buf, " (link to CA" );
185         break;
186       default:
187         strcat( p_mgr->p_report_buf, " (link to unknown type, node" );
188         break;
189       }
190
191       sprintf( line, " 0x%" PRIx64 ")", remote_guid_ho );
192       strcat( p_mgr->p_report_buf, line );
193     }
194
195     strcat( p_mgr->p_report_buf, "\n" );
196
197     osm_log_raw( p_mgr->p_log, OSM_LOG_ROUTING, p_mgr->p_report_buf );
198   }
199
200   OSM_LOG_EXIT( p_mgr->p_log );
201 }
202
203 /**********************************************************************
204  **********************************************************************/
205 void
206 osm_ucast_mgr_dump_ucast_routes(
207   IN const osm_ucast_mgr_t*   const p_mgr,
208   IN const osm_switch_t*      const p_sw )
209 {
210   const osm_node_t*        p_node;
211   uint8_t                  port_num;
212   uint8_t                  num_hops;
213   uint8_t                  best_hops;
214   uint8_t                  best_port;
215   uint16_t              max_lid_ho;
216   uint16_t              lid_ho;
217   char                  line[OSM_REPORT_LINE_SIZE];
218   uint32_t              line_num = 0;
219   FILE  *              p_fdbFile;
220   boolean_t            ui_ucast_fdb_assign_func_defined;
221   char                *file_name = NULL;
222   
223   OSM_LOG_ENTER( p_mgr->p_log, osm_ucast_mgr_dump_ucast_routes );
224
225   if( !osm_log_is_active( p_mgr->p_log, OSM_LOG_ROUTING ) )
226     goto Exit;
227
228   file_name = 
229     (char*)cl_malloc(strlen(p_mgr->p_subn->opt.dump_files_dir) + 10);
230   
231   CL_ASSERT(file_name);
232   
233   strcpy(file_name, p_mgr->p_subn->opt.dump_files_dir);
234   strcat(file_name,"/osm.fdbs");
235   
236   /* Open the file or error */
237   p_fdbFile = fopen(file_name, "a");
238   if (! p_fdbFile)
239   {
240     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
241              "osm_ucast_mgr_dump_ucast_routes: ERR 3A12: "
242              "Fail to open fdb file (%s).\n",
243              file_name );
244     goto Exit;
245   }
246
247   p_node = osm_switch_get_node_ptr( p_sw );
248
249   max_lid_ho = osm_switch_get_max_lid_ho( p_sw );
250
251   for( lid_ho = 1; lid_ho <= max_lid_ho; lid_ho++ )
252   {
253     if( line_num == 0 )
254     {
255       sprintf( p_mgr->p_report_buf, "osm_ucast_mgr_dump_ucast_routes: "
256                "Switch 0x%016" PRIx64 "\n"
257                "LID    : Port : Hops : Optimal\n",
258                cl_ntoh64( osm_node_get_node_guid( p_node ) ) );
259       line_num++;
260     }
261
262     port_num = osm_switch_get_port_by_lid( p_sw, lid_ho );
263     if( port_num == OSM_NO_PATH )
264     {
265       /*
266         This may occur if there are 'holes' in the existing
267         LID assignemnts.  Running SM with --reassign_lids
268         will reassign and compress the LID range.  The
269         subnet should work fine either way.
270       */
271       sprintf( line, "0x%04X : UNREACHABLE\n", lid_ho );
272       strcat( p_mgr->p_report_buf, line );
273       line_num++;
274       continue;
275     }
276     /*
277       Switches can lie about which port routes a given
278       lid due to a recent reconfiguration of the subnet.
279       Therefore, ensure that the hop count is better than
280       OSM_NO_PATH.
281     */
282     num_hops = osm_switch_get_hop_count( p_sw, lid_ho, port_num );
283     if( num_hops == OSM_NO_PATH )
284     {
285       sprintf( line, "0x%04X : UNREACHABLE\n", lid_ho );
286       strcat( p_mgr->p_report_buf, line );
287       line_num++;
288       continue;
289     }
290
291     best_hops = osm_switch_get_least_hops( p_sw, lid_ho );
292     sprintf( line, "0x%04X : %03u  : %02u   : ",
293              lid_ho, port_num, num_hops );
294     strcat( p_mgr->p_report_buf, line );
295
296     if( best_hops == num_hops )
297       strcat( p_mgr->p_report_buf, "yes" );
298     else
299     {
300       if (p_mgr->p_subn->opt.pfn_ui_ucast_fdb_assign) {
301         ui_ucast_fdb_assign_func_defined = TRUE;
302       } else {
303         ui_ucast_fdb_assign_func_defined = FALSE;
304       }
305       best_port = osm_switch_recommend_path(
306         p_sw, lid_ho, TRUE,
307         NULL, NULL, NULL, NULL, /* No LMC Optimization */
308         0xffffffff, ui_ucast_fdb_assign_func_defined );
309       sprintf( line, "No %u hop path possible via port %u!",
310                best_hops, best_port );
311       strcat( p_mgr->p_report_buf, line );
312     }
313
314     strcat( p_mgr->p_report_buf, "\n" );
315
316     if( ++line_num >= OSM_REPORT_BUF_THRESHOLD )
317     {
318       fprintf(p_fdbFile,"%s",p_mgr->p_report_buf );
319       line_num = 0;
320     }
321   }
322
323   if( line_num != 0 )
324     fprintf(p_fdbFile,"%s\n",p_mgr->p_report_buf );
325
326   fclose(p_fdbFile);
327
328  Exit:
329   if (file_name)
330     cl_free(file_name);
331   OSM_LOG_EXIT( p_mgr->p_log );
332 }
333
334 /**********************************************************************
335    Add each switch's own LID to its LID matrix.
336 **********************************************************************/
337 static void
338 __osm_ucast_mgr_process_hop_0(
339   IN cl_map_item_t* const  p_map_item,
340   IN void* context )
341 {
342   osm_switch_t* const p_sw = (osm_switch_t*)p_map_item;
343   osm_ucast_mgr_t* const p_mgr = (osm_ucast_mgr_t*)context;
344   osm_node_t *p_node;
345   uint16_t lid_ho;
346   cl_status_t status;
347
348   OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_hop_0 );
349
350   p_node = p_sw->p_node;
351
352   CL_ASSERT( p_node );
353   CL_ASSERT( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH );
354
355   /*
356     Starting a rebuild, so notify the switch so it can
357     clear tables, etc...
358   */
359   osm_switch_prepare_path_rebuild( p_sw );
360
361   lid_ho = cl_ntoh16( osm_node_get_base_lid( p_node, 0 ) );
362
363   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
364   {
365     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
366              "__osm_ucast_mgr_process_hop_0: "
367              "Processing switch GUID 0x%" PRIx64 ", LID 0x%X.\n",
368              cl_ntoh64( osm_node_get_node_guid( p_node ) ),
369              lid_ho );
370   }
371
372   status = osm_switch_set_hops( p_sw, lid_ho, 0, 0 );
373   if( status != CL_SUCCESS )
374   {
375     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
376              "__osm_ucast_mgr_process_hop_0: ERR 3A02: "
377              "Setting hop count failed (%s).\n",
378              CL_STATUS_MSG( status ) );
379   }
380
381   OSM_LOG_EXIT( p_mgr->p_log );
382 }
383
384 /**********************************************************************
385  **********************************************************************/
386 static void
387 __osm_ucast_mgr_process_neighbor(
388   IN osm_ucast_mgr_t* const p_mgr,
389   IN osm_switch_t* const p_sw,
390   IN osm_switch_t* const p_remote_sw,
391   IN const uint8_t port_num,
392   IN const uint8_t remote_port_num )
393 {
394   uint16_t lid_ho;
395   uint16_t max_lid_ho;
396   osm_node_t* p_node;
397   const osm_node_t* p_remote_node;
398   uint8_t hops;
399   cl_status_t status;
400
401   OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_neighbor );
402
403   CL_ASSERT( p_sw );
404   CL_ASSERT( p_remote_sw );
405   CL_ASSERT( port_num );
406   CL_ASSERT( remote_port_num );
407
408   p_node = osm_switch_get_node_ptr( p_sw );
409   p_remote_node = osm_switch_get_node_ptr( p_remote_sw );
410
411   CL_ASSERT( p_node );
412   CL_ASSERT( p_remote_node );
413
414   CL_ASSERT( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH );
415   CL_ASSERT( osm_node_get_type( p_remote_node ) == IB_NODE_TYPE_SWITCH );
416
417   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
418   {
419     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
420              "__osm_ucast_mgr_process_neighbor: "
421              "Node 0x%" PRIx64 ", remote node 0x%" PRIx64 "\n"
422              "\t\t\t\tport 0x%X, remote port 0x%X.\n",
423              cl_ntoh64( osm_node_get_node_guid( p_node ) ),
424              cl_ntoh64( osm_node_get_node_guid( p_remote_node ) ),
425              port_num, remote_port_num );
426   }
427
428   /*
429     Iterate through all the LIDs in the neighbor switch.
430   */
431   max_lid_ho = osm_switch_get_max_lid_ho( p_remote_sw );
432
433   /*
434     Make sure the local lid matrix has enough room to hold
435     all the LID info coming from the remote LID matrix.
436   */
437   osm_switch_set_min_lid_size( p_sw, max_lid_ho );
438
439   hops = OSM_NO_PATH;
440   for( lid_ho = 1; lid_ho <= max_lid_ho; lid_ho++ )
441   {
442     /*
443       Find the lowest hop count value to this LID.
444     */
445       hops = osm_switch_get_least_hops( p_remote_sw, lid_ho );
446
447       if( hops != OSM_NO_PATH )
448       {
449         /*
450           Increment hop count of the neighbor by 1, since it
451           takes 1 hop to get to the neighbor.
452         */
453         hops++;
454
455         CL_ASSERT( hops <= osm_switch_get_hop_count( p_sw, lid_ho,
456                                                      port_num ) );
457         if( osm_switch_get_hop_count( p_sw, lid_ho,
458                                       port_num ) > hops )
459         {
460           if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
461           {
462             osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
463                      "__osm_ucast_mgr_process_neighbor: "
464                      "New best path is %u hops for LID 0x%X.\n",
465                      hops, lid_ho );
466           }
467
468           /* mark the fact we have got to change anything */
469           __some_hop_count_set = TRUE;
470
471           status = osm_switch_set_hops( p_sw, lid_ho,
472                                         port_num, hops );
473           if( status != CL_SUCCESS )
474           {
475             osm_log( p_mgr->p_log, OSM_LOG_ERROR,
476                      "__osm_ucast_mgr_process_neighbor: ERR 3A03: "
477                      "Setting hop count failed (%s).\n",
478                      CL_STATUS_MSG( status ) );
479           }
480         }
481       }
482   }
483
484   OSM_LOG_EXIT( p_mgr->p_log );
485
486 }
487
488 /**********************************************************************
489  **********************************************************************/
490 static void
491 __osm_ucast_mgr_process_leaf(
492   IN osm_ucast_mgr_t* const p_mgr,
493   IN osm_switch_t* const p_sw,
494   IN osm_node_t* const p_node,
495   IN const uint8_t port_num,
496   IN osm_node_t* const p_remote_node,
497   IN const uint8_t remote_port_num )
498 {
499   uint16_t i;
500   uint16_t base_lid_ho;
501   uint16_t max_lid_ho;
502   uint8_t lmc;
503
504   OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_leaf );
505
506   CL_ASSERT( p_node );
507   CL_ASSERT( p_remote_node );
508   CL_ASSERT( port_num );
509   CL_ASSERT( remote_port_num );
510
511   switch( osm_node_get_type( p_remote_node ) )
512   {
513   case IB_NODE_TYPE_CA:
514   case IB_NODE_TYPE_ROUTER:
515     base_lid_ho = cl_ntoh16( osm_node_get_base_lid(
516                                p_remote_node, remote_port_num ) );
517     lmc = osm_node_get_lmc( p_remote_node, remote_port_num );
518     break;
519 /*   case IB_NODE_TYPE_SWITCH: */
520 /*     base_lid_ho = cl_ntoh16( osm_node_get_base_lid( */
521 /*                                p_remote_node, 0 ) ); */
522 /*     lmc = 0; */
523 /*     break; */
524
525   default:
526     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
527              "__osm_ucast_mgr_process_leaf: ERR 3A01: "
528              "Bad node type %u, GUID = 0x%" PRIx64 ".\n",
529              osm_node_get_type( p_remote_node ),
530              cl_ntoh64( osm_node_get_node_guid( p_node ) ));
531     goto Exit;
532   }
533
534   max_lid_ho = (uint16_t)(base_lid_ho + (1 << lmc) - 1 );
535
536   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
537   {
538     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
539              "__osm_ucast_mgr_process_leaf: "
540              "Discovered LIDs [0x%X,0x%X]\n"
541              "\t\t\t\tport number 0x%X, node 0x%" PRIx64 ".\n",
542              base_lid_ho, max_lid_ho,
543              port_num, cl_ntoh64( osm_node_get_node_guid( p_node ) ));
544   }
545
546   for( i = base_lid_ho; i <= max_lid_ho; i++ )
547     osm_switch_set_hops( p_sw, i, port_num, 1 );
548
549  Exit:
550   OSM_LOG_EXIT( p_mgr->p_log );
551
552 }
553
554 /**********************************************************************
555  **********************************************************************/
556 static void
557 __osm_ucast_mgr_process_leaves(
558   IN cl_map_item_t* const  p_map_item,
559   IN void* context )
560 {
561   osm_switch_t* const p_sw = (osm_switch_t*)p_map_item;
562   osm_ucast_mgr_t* const p_mgr = (osm_ucast_mgr_t*)context;
563   osm_node_t *p_node;
564   osm_node_t *p_remote_node;
565   uint32_t port_num;
566   uint8_t remote_port_num;
567   uint32_t num_ports;
568
569   OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_leaves );
570
571   p_node = p_sw->p_node;
572
573   CL_ASSERT( p_node );
574   CL_ASSERT( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH );
575
576   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
577   {
578     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
579              "__osm_ucast_mgr_process_leaves: "
580              "Processing switch 0x%" PRIx64 ".\n",
581              cl_ntoh64( osm_node_get_node_guid( p_node ) ));
582   }
583
584   /*
585     Add the LIDs of all leaves of this switch to the LID matrix.
586     Don't bother processing loopback paths from one port of
587     this switch to the another port.
588     Don't process neighbor switches yet.
589     Start with port 1 to skip the switch's management port.
590   */
591   num_ports = osm_node_get_num_physp( p_node );
592
593   for( port_num = 1; port_num < num_ports; port_num++ )
594   {
595     p_remote_node = osm_node_get_remote_node( p_node,
596                                               (uint8_t)port_num, &remote_port_num );
597
598     if( p_remote_node && (p_remote_node != p_node )
599         && (osm_node_get_type( p_remote_node )
600             != IB_NODE_TYPE_SWITCH ))
601     {
602       __osm_ucast_mgr_process_leaf(
603         p_mgr,
604         p_sw,
605         p_node,
606         (uint8_t)port_num,
607         p_remote_node,
608         remote_port_num );
609     }
610   }
611
612
613   OSM_LOG_EXIT( p_mgr->p_log );
614 }
615
616 /**********************************************************************
617  **********************************************************************/
618 static void
619 __osm_ucast_mgr_process_port(
620   IN osm_ucast_mgr_t* const p_mgr,
621   IN osm_switch_t* const p_sw,
622   IN const osm_port_t* const p_port )
623 {
624   uint16_t min_lid_ho;
625   uint16_t max_lid_ho;
626   uint16_t lid_ho;
627   uint8_t port;
628   boolean_t ignore_existing, is_ignored_by_port_pro;
629   ib_net64_t node_guid;
630   boolean_t  ui_ucast_fdb_assign_func_defined;
631   /*
632     The following are temporary structures that will aid
633     in providing better routing in LMC > 0 situations
634   */
635   uint16_t lids_per_port = 1 << p_mgr->p_subn->opt.lmc;
636   uint64_t* remote_sys_guids = NULL;
637   uint64_t* remote_node_guids = NULL;
638   uint16_t num_used_sys = 0;
639   uint16_t num_used_nodes = 0;
640
641   OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_port );
642
643   remote_sys_guids = cl_zalloc( sizeof(uint64_t) * lids_per_port );
644   if( remote_sys_guids == NULL )
645   {
646     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
647              "__osm_ucast_mgr_process_port: ERR 3A09: "
648              "Cannot allocate array. Memory insufficient.\n");
649     goto Exit;
650   }
651
652   remote_node_guids = cl_zalloc( sizeof(uint64_t) * lids_per_port );
653   if( remote_node_guids == NULL )
654   {
655     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
656              "__osm_ucast_mgr_process_port: ERR 3A0A: "
657              "Cannot allocate array. Memory insufficient.\n");
658     goto Exit;
659   }
660
661   osm_port_get_lid_range_ho( p_port, &min_lid_ho, &max_lid_ho );
662
663   /* If the lids are zero - then there was some problem with the initialization.
664      Don't handle this port. */
665   if (min_lid_ho == 0 || max_lid_ho == 0)
666   {
667     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
668              "__osm_ucast_mgr_process_port: ERR 3A04: "
669              "Port 0x%" PRIx64 " has LID 0. An initialization "
670              "error occurred. Ignoring port\n",
671              cl_ntoh64( osm_port_get_guid( p_port ) ) );
672     goto Exit;
673   }
674
675   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
676   {
677     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
678              "__osm_ucast_mgr_process_port: "
679              "Processing port 0x%" PRIx64
680              ", LIDs [0x%X,0x%X].\n",
681              cl_ntoh64( osm_port_get_guid( p_port ) ),
682              min_lid_ho, max_lid_ho );
683   }
684
685   /*
686     TO DO -
687     This should be runtime error, not an CL_ASSERT()
688   */
689   CL_ASSERT( max_lid_ho < osm_switch_get_fwd_tbl_size( p_sw ) );
690
691   node_guid = osm_node_get_node_guid(osm_switch_get_node_ptr( p_sw ) );
692
693   /* Flag to mark whether or not a ui ucast fdb assign function was given */
694   if (p_mgr->p_subn->opt.pfn_ui_ucast_fdb_assign)
695     ui_ucast_fdb_assign_func_defined = TRUE;
696   else
697     ui_ucast_fdb_assign_func_defined = FALSE;
698
699   /*
700     If the user request a complete subnet reconfiguration,
701     then ignore existing paths when choosing paths now.
702     Note that if there is a ui ucast fdb assign function - then the 
703     ignore_existing should be false.
704   */
705   ignore_existing = p_mgr->p_subn->ignore_existing_lfts &&
706     (!ui_ucast_fdb_assign_func_defined) ;
707
708   /*
709     The lid matrix contains the number of hops to each
710     lid from each port.  From this information we determine
711     how best to distribute the LID range across the ports
712     that can reach those LIDs.
713   */
714   for( lid_ho = min_lid_ho; lid_ho <= max_lid_ho; lid_ho++ )
715   {
716     /* Use the enhanced algorithm only for LMC > 0 */
717     if (lids_per_port > 1)
718       port = osm_switch_recommend_path( p_sw, lid_ho, ignore_existing,
719                                         remote_sys_guids, &num_used_sys,
720                                         remote_node_guids, &num_used_nodes,
721                                         p_mgr->p_subn->opt.max_port_profile,
722                                         ui_ucast_fdb_assign_func_defined );
723     else
724       port = osm_switch_recommend_path( p_sw, lid_ho, ignore_existing,
725                                         NULL, NULL, NULL, NULL,
726                                         p_mgr->p_subn->opt.max_port_profile,
727                                         ui_ucast_fdb_assign_func_defined );
728
729     /*
730       There might be no path to the target:
731     */
732     if (port == OSM_NO_PATH)
733     {
734       /* do not try to overwrite the ppro of non existing port ... */ 
735       is_ignored_by_port_pro = TRUE;
736
737       /* Up/Down routing can cause unreachable routes between some 
738          switches so we do not report that as an error in that case */
739       if (!p_mgr->p_subn->opt.updn_activate)
740       {
741         osm_log( p_mgr->p_log, OSM_LOG_ERROR,
742                  "__osm_ucast_mgr_process_port: ERR 3A08: "
743                  "No path to get to LID 0x%X from switch 0x%" PRIx64 ".\n",
744                  lid_ho, cl_ntoh64( node_guid ) );
745         /* trigger a new sweep - try again ... */
746         p_mgr->p_subn->subnet_initialization_error = TRUE;
747       }
748       else 
749         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
750                  "__osm_ucast_mgr_process_port: "
751                  "No path to get to LID 0x%X from switch 0x%" PRIx64 ".\n",
752                  lid_ho, cl_ntoh64( node_guid ) );
753     }
754     else
755     {
756       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
757                "__osm_ucast_mgr_process_port: "
758                "Routing LID 0x%X to port 0x%X"
759                "\n\t\t\t\tFor switch 0x%" PRIx64 ".\n",
760                lid_ho, port, cl_ntoh64( node_guid ) );
761
762       /*
763         we would like to optionally ignore this port in equalization
764         like in the case of the Mellanox Anafa Internal PCI TCA port
765       */
766       is_ignored_by_port_pro =
767         osm_port_pro_is_ignored_port(p_mgr->p_subn, cl_ntoh64(node_guid), port);
768
769       /*
770         We also would ignore this route if the target lid if of a switch
771         and the port_profile_switch_node is not TRUE
772       */
773       if (! p_mgr->p_subn->opt.port_profile_switch_nodes)
774       {
775         is_ignored_by_port_pro |=
776           (osm_node_get_type(osm_port_get_parent_node(p_port)) ==
777            IB_NODE_TYPE_SWITCH);
778       }
779     }
780
781     /*
782       We have selected the port for this LID.
783       Write it to the forwarding tables.
784     */
785     osm_switch_set_path( p_sw, lid_ho, port, is_ignored_by_port_pro);
786   }
787  Exit:
788   if (remote_sys_guids) cl_free(remote_sys_guids);
789   if (remote_node_guids) cl_free(remote_node_guids);
790   OSM_LOG_EXIT( p_mgr->p_log );
791 }
792
793 /**********************************************************************
794  **********************************************************************/
795 static void
796 __osm_ucast_mgr_set_table(
797   IN osm_ucast_mgr_t* const p_mgr,
798   IN osm_switch_t* const p_sw )
799 {
800   osm_node_t *p_node;
801   osm_dr_path_t *p_path;
802   osm_madw_context_t context;
803   ib_api_status_t status;
804   ib_switch_info_t si;
805   uint32_t block_id_ho = 0;
806   uint8_t block[IB_SMP_DATA_SIZE];
807
808   OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_set_table );
809
810   CL_ASSERT( p_mgr );
811   CL_ASSERT( p_sw );
812
813   p_node = osm_switch_get_node_ptr( p_sw );
814
815   CL_ASSERT( p_node );
816
817   p_path = osm_node_get_any_dr_path_ptr( p_node );
818
819   CL_ASSERT( p_path );
820
821   /*
822     Set the top of the unicast forwarding table.
823   */
824   si = *osm_switch_get_si_ptr( p_sw );
825   si.lin_top = cl_hton16( osm_switch_get_max_lid_ho( p_sw ) );
826
827   /* check to see if the change state bit is on. If it is - then we
828      need to clear it. */
829    if( ib_switch_info_get_state_change( &si ) )
830     si.life_state = ( (p_mgr->p_subn->opt.packet_life_time <<3 )
831                       | ( si.life_state & IB_SWITCH_PSC ) )  & 0xfc;
832   else
833     si.life_state = (p_mgr->p_subn->opt.packet_life_time <<3 ) & 0xf8;
834
835   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
836   {
837     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
838              "__osm_ucast_mgr_set_table: "
839              "Setting switch FT top to LID 0x%X.\n",
840              osm_switch_get_max_lid_ho( p_sw ) );
841   }
842
843   context.si_context.light_sweep = FALSE;
844   context.si_context.node_guid = osm_node_get_node_guid( p_node );
845   context.si_context.set_method = TRUE;
846
847   status = osm_req_set( p_mgr->p_req,
848                         p_path,
849                         (uint8_t*)&si,
850                         sizeof(si),
851                         IB_MAD_ATTR_SWITCH_INFO,
852                         0,
853                         CL_DISP_MSGID_NONE,
854                         &context );
855
856   if( status != IB_SUCCESS )
857   {
858     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
859              "__osm_ucast_mgr_set_table: ERR 3A06: "
860              "Sending SwitchInfo attribute failed (%s).\n",
861              ib_get_err_str( status ) );
862   }
863
864   /*
865     Send linear forwarding table blocks to the switch
866     as long as the switch indicates it has blocks needing
867     configuration.
868   */
869
870   context.lft_context.node_guid = osm_node_get_node_guid( p_node );
871   context.lft_context.set_method = TRUE;
872
873   while( osm_switch_get_fwd_tbl_block( p_sw, block_id_ho, block ) )
874   {
875     if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
876     {
877       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
878                "__osm_ucast_mgr_set_table: "
879                "Writing FT block %u.\n", block_id_ho );
880     }
881
882     status = osm_req_set( p_mgr->p_req,
883                           p_path,
884                           block,
885                           sizeof(block),
886                           IB_MAD_ATTR_LIN_FWD_TBL,
887                           cl_hton32( block_id_ho ),
888                           CL_DISP_MSGID_NONE,
889                           &context );
890
891     if( status != IB_SUCCESS )
892     {
893       osm_log( p_mgr->p_log, OSM_LOG_ERROR,
894                "__osm_ucast_mgr_set_table: ERR 3A05: "
895                "Sending linear fwd. tbl. block failed (%s).\n",
896                ib_get_err_str( status ) );
897     }
898
899     block_id_ho++;
900   }
901
902   OSM_LOG_EXIT( p_mgr->p_log );
903
904 }
905
906 /**********************************************************************
907  **********************************************************************/
908 static void
909 __osm_ucast_mgr_process_tbl(
910   IN cl_map_item_t* const  p_map_item,
911   IN void* context )
912 {
913   osm_switch_t* const p_sw = (osm_switch_t*)p_map_item;
914   osm_ucast_mgr_t* const p_mgr = (osm_ucast_mgr_t*)context;
915   osm_node_t *p_node;
916   const osm_port_t *p_port;
917   const cl_qmap_t* p_port_tbl;
918
919   OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_tbl );
920
921   p_node = p_sw->p_node;
922
923   CL_ASSERT( p_node );
924   CL_ASSERT( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH );
925
926   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
927   {
928     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
929              "__osm_ucast_mgr_process_tbl: "
930              "Processing switch 0x%" PRIx64 ".\n",
931              cl_ntoh64( osm_node_get_node_guid( p_node ) ));
932   }
933
934   p_port_tbl = &p_mgr->p_subn->port_guid_tbl;
935
936   /*
937     Iterate through every port setting LID routes for each
938     port based on base LID and LMC value.
939   */
940
941   for( p_port = (osm_port_t*)cl_qmap_head( p_port_tbl );
942        p_port != (osm_port_t*)cl_qmap_end( p_port_tbl );
943        p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item ) )
944   {
945     __osm_ucast_mgr_process_port( p_mgr, p_sw, p_port );
946   }
947
948   __osm_ucast_mgr_set_table( p_mgr, p_sw );
949
950   osm_ucast_mgr_dump_path_distribution( p_mgr, p_sw );
951   osm_ucast_mgr_dump_ucast_routes( p_mgr, p_sw );
952   OSM_LOG_EXIT( p_mgr->p_log );
953 }
954
955 /**********************************************************************
956  **********************************************************************/
957 static void
958 __osm_ucast_mgr_process_neighbors(
959   IN cl_map_item_t* const  p_map_item,
960   IN void* context )
961 {
962   osm_switch_t* const p_sw = (osm_switch_t*)p_map_item;
963   osm_ucast_mgr_t* const p_mgr = (osm_ucast_mgr_t*)context;
964   osm_node_t *p_node;
965   osm_node_t *p_remote_node;
966   ib_net64_t remote_node_guid;
967   osm_switch_t *p_remote_sw;
968   uint32_t port_num;
969   uint8_t remote_port_num;
970   uint32_t num_ports;
971   osm_physp_t* p_physp;
972
973   OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_neighbors );
974
975   p_node = p_sw->p_node;
976
977   CL_ASSERT( p_node );
978   CL_ASSERT( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH );
979
980   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
981   {
982     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
983              "__osm_ucast_mgr_process_neighbors: "
984              "Processing switch with GUID = 0x%" PRIx64 ".\n",
985              cl_ntoh64( osm_node_get_node_guid( p_node ) ));
986   }
987
988   num_ports = osm_node_get_num_physp( p_node );
989
990   /*
991     Start with port 1 to skip the switch's management port.
992   */
993   for( port_num = 1; port_num < num_ports; port_num++ )
994   {
995     p_remote_node = osm_node_get_remote_node( p_node,
996                                               (uint8_t)port_num, &remote_port_num );
997
998     if( p_remote_node && (p_remote_node != p_node )
999         && (osm_node_get_type( p_remote_node )
1000             == IB_NODE_TYPE_SWITCH ))
1001     {
1002       /* make sure the link is healthy. If it is not - don't 
1003          propagate through it. */
1004       p_physp = osm_node_get_physp_ptr( p_node, port_num );
1005       if (!osm_link_is_healthy( p_physp ) ) continue;
1006
1007       remote_node_guid = osm_node_get_node_guid( p_remote_node );
1008
1009       p_remote_sw = (osm_switch_t*)cl_qmap_get(
1010         &p_mgr->p_subn->sw_guid_tbl, remote_node_guid );
1011
1012       if( p_remote_sw == (osm_switch_t*)cl_qmap_end(
1013             &p_mgr->p_subn->sw_guid_tbl ) )
1014       {
1015         osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1016                  "__osm_ucast_mgr_process_neighbors: ERR 3A07: "
1017                  "No switch object for Node GUID = 0x%" PRIx64 ".\n",
1018                  cl_ntoh64( remote_node_guid ) );
1019       }
1020       else
1021       {
1022         __osm_ucast_mgr_process_neighbor(
1023           p_mgr,
1024           p_sw,
1025           p_remote_sw,
1026           (uint8_t)port_num,
1027           remote_port_num );
1028       }
1029     }
1030   }
1031
1032
1033   OSM_LOG_EXIT( p_mgr->p_log );
1034 }
1035
1036 /**********************************************************************
1037  **********************************************************************/
1038 osm_signal_t
1039 osm_ucast_mgr_process(
1040   IN osm_ucast_mgr_t* const p_mgr )
1041 {
1042   uint32_t i;
1043   uint32_t iteration_max;
1044   osm_signal_t signal;
1045   cl_qmap_t *p_sw_guid_tbl;
1046
1047   OSM_LOG_ENTER( p_mgr->p_log, osm_ucast_mgr_process );
1048
1049   p_sw_guid_tbl = &p_mgr->p_subn->sw_guid_tbl;
1050
1051   CL_PLOCK_EXCL_ACQUIRE( p_mgr->p_lock );
1052
1053   osm_log(p_mgr->p_log, OSM_LOG_VERBOSE,
1054           "osm_ucast_mgr_process: "
1055           "Starting switches Min Hop Table Assignment.\n");
1056   
1057   /*
1058     Set the switch matrixes for each switch's own port 0 LID,
1059     then set the lid matrixes for the each switch's leaf nodes.
1060   */
1061   cl_qmap_apply_func( p_sw_guid_tbl,
1062                       __osm_ucast_mgr_process_hop_0, p_mgr );
1063
1064   cl_qmap_apply_func( p_sw_guid_tbl,
1065                       __osm_ucast_mgr_process_leaves, p_mgr );
1066
1067   /*
1068     Get the switch matrixes for each switch's neighbors.
1069     This process requires a number of iterations equal to
1070     the number of switches in the subnet minus 1.
1071
1072     In each iteration, a switch learns the lid/port/hop
1073     information (as contained by a switch's lid matrix) from its
1074     immediate neighbors.  After each
1075     iteration, a switch (and it's neighbors) know more
1076     routing information than it did on the previous iteration.
1077     Thus, by repeatedly absorbing the routing information of
1078     neighbor switches, every switch eventually learns how to
1079     route all LIDs on the subnet.
1080
1081     Note that there may not be any switches in the subnet if
1082     we are in simple p2p configuration.
1083   */
1084   iteration_max = cl_qmap_count( &p_mgr->p_subn->sw_guid_tbl );
1085
1086   /*
1087     If there are switches in the subnet, iterate until the lid
1088     matrix has been constructed.  Otherwise, just immediately
1089     indicate we're done if no switches exist.
1090   */
1091   if( iteration_max )
1092   {
1093     iteration_max--;
1094
1095     /*
1096       we need to find out when the propagation of
1097       hop counts has relaxed. So this global variable
1098       is preset to 0 on each iteration and if
1099       if non of the switches was set will exit the
1100       while loop
1101     */
1102     __some_hop_count_set = TRUE;
1103     for( i = 0; (i < iteration_max) && __some_hop_count_set; i++ )
1104     {
1105       __some_hop_count_set = FALSE;
1106       cl_qmap_apply_func( p_sw_guid_tbl,
1107                           __osm_ucast_mgr_process_neighbors, p_mgr );
1108     }
1109     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1110              "osm_ucast_mgr_process: "
1111              "Min-hop propagated in %d steps\n",
1112              i
1113              );
1114
1115     /*
1116       This is the place where we can load pre-defined routes
1117       into the switches fwd_tbl structures.
1118
1119       Later code will use these values if not configured for
1120       re-assignment.
1121     */
1122     if (p_mgr->p_subn->opt.pfn_ui_ucast_fdb_assign)
1123     {
1124       if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
1125       {
1126         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1127                  "osm_ucast_mgr_process: "
1128                  "Invoking UI function pfn_ui_ucast_fdb_assign\n");
1129       }
1130       p_mgr->p_subn->opt.pfn_ui_ucast_fdb_assign(p_mgr->p_subn->opt.ui_ucast_fdb_assign_ctx);
1131     } else {
1132         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1133                  "osm_ucast_mgr_process: "
1134                  "UI pfn was not invoked\n");
1135     }
1136
1137     osm_log(p_mgr->p_log, OSM_LOG_INFO,
1138             "osm_ucast_mgr_process: "
1139             "Min Hop Tables configured on all switches.\n");
1140
1141     /*
1142       Now that the lid matrixes have been built, we can
1143       build and download the switch forwarding tables.
1144     */
1145
1146     /* initialize the fdb dump file: */
1147     if( osm_log_is_active( p_mgr->p_log, OSM_LOG_ROUTING ) )
1148       unlink("/tmp/osm.fdbs");
1149
1150     cl_qmap_apply_func( p_sw_guid_tbl,
1151                         __osm_ucast_mgr_process_tbl, p_mgr );
1152
1153     /*
1154       For now dont' bother checking if the switch forwarding tables
1155       actually needed updating.  The current code will always update
1156       them, and thus leave transactions pending on the wire.
1157       Therefore, return OSM_SIGNAL_DONE_PENDING.
1158     */
1159
1160     signal = OSM_SIGNAL_DONE_PENDING;
1161   }
1162   else
1163     signal = OSM_SIGNAL_DONE;
1164
1165   osm_log(p_mgr->p_log, OSM_LOG_VERBOSE,
1166           "osm_ucast_mgr_process: "
1167           "LFT Tables configured on all switches.\n");
1168
1169   CL_PLOCK_RELEASE( p_mgr->p_lock );
1170   OSM_LOG_EXIT( p_mgr->p_log );
1171   return( signal );
1172 }
1173