796eb9408057b6432f339ad722313ac851ba99b7
[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                         IB_MAD_ATTR_SWITCH_INFO,
851                         0,
852                         CL_DISP_MSGID_NONE,
853                         &context );
854
855   if( status != IB_SUCCESS )
856   {
857     osm_log( p_mgr->p_log, OSM_LOG_ERROR,
858              "__osm_ucast_mgr_set_table: ERR 3A06: "
859              "Sending SwitchInfo attribute failed (%s).\n",
860              ib_get_err_str( status ) );
861   }
862
863   /*
864     Send linear forwarding table blocks to the switch
865     as long as the switch indicates it has blocks needing
866     configuration.
867   */
868
869   context.lft_context.node_guid = osm_node_get_node_guid( p_node );
870   context.lft_context.set_method = TRUE;
871
872   while( osm_switch_get_fwd_tbl_block( p_sw, block_id_ho, block ) )
873   {
874     if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
875     {
876       osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
877                "__osm_ucast_mgr_set_table: "
878                "Writing FT block %u.\n", block_id_ho );
879     }
880
881     status = osm_req_set( p_mgr->p_req,
882                           p_path,
883                           block,
884                           IB_MAD_ATTR_LIN_FWD_TBL,
885                           cl_hton32( block_id_ho ),
886                           CL_DISP_MSGID_NONE,
887                           &context );
888
889     if( status != IB_SUCCESS )
890     {
891       osm_log( p_mgr->p_log, OSM_LOG_ERROR,
892                "__osm_ucast_mgr_set_table: ERR 3A05: "
893                "Sending linear fwd. tbl. block failed (%s).\n",
894                ib_get_err_str( status ) );
895     }
896
897     block_id_ho++;
898   }
899
900   OSM_LOG_EXIT( p_mgr->p_log );
901
902 }
903
904 /**********************************************************************
905  **********************************************************************/
906 static void
907 __osm_ucast_mgr_process_tbl(
908   IN cl_map_item_t* const  p_map_item,
909   IN void* context )
910 {
911   osm_switch_t* const p_sw = (osm_switch_t*)p_map_item;
912   osm_ucast_mgr_t* const p_mgr = (osm_ucast_mgr_t*)context;
913   osm_node_t *p_node;
914   const osm_port_t *p_port;
915   const cl_qmap_t* p_port_tbl;
916
917   OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_tbl );
918
919   p_node = p_sw->p_node;
920
921   CL_ASSERT( p_node );
922   CL_ASSERT( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH );
923
924   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
925   {
926     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
927              "__osm_ucast_mgr_process_tbl: "
928              "Processing switch 0x%" PRIx64 ".\n",
929              cl_ntoh64( osm_node_get_node_guid( p_node ) ));
930   }
931
932   p_port_tbl = &p_mgr->p_subn->port_guid_tbl;
933
934   /*
935     Iterate through every port setting LID routes for each
936     port based on base LID and LMC value.
937   */
938
939   for( p_port = (osm_port_t*)cl_qmap_head( p_port_tbl );
940        p_port != (osm_port_t*)cl_qmap_end( p_port_tbl );
941        p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item ) )
942   {
943     __osm_ucast_mgr_process_port( p_mgr, p_sw, p_port );
944   }
945
946   __osm_ucast_mgr_set_table( p_mgr, p_sw );
947
948   osm_ucast_mgr_dump_path_distribution( p_mgr, p_sw );
949   osm_ucast_mgr_dump_ucast_routes( p_mgr, p_sw );
950   OSM_LOG_EXIT( p_mgr->p_log );
951 }
952
953 /**********************************************************************
954  **********************************************************************/
955 static void
956 __osm_ucast_mgr_process_neighbors(
957   IN cl_map_item_t* const  p_map_item,
958   IN void* context )
959 {
960   osm_switch_t* const p_sw = (osm_switch_t*)p_map_item;
961   osm_ucast_mgr_t* const p_mgr = (osm_ucast_mgr_t*)context;
962   osm_node_t *p_node;
963   osm_node_t *p_remote_node;
964   ib_net64_t remote_node_guid;
965   osm_switch_t *p_remote_sw;
966   uint32_t port_num;
967   uint8_t remote_port_num;
968   uint32_t num_ports;
969   osm_physp_t* p_physp;
970
971   OSM_LOG_ENTER( p_mgr->p_log, __osm_ucast_mgr_process_neighbors );
972
973   p_node = p_sw->p_node;
974
975   CL_ASSERT( p_node );
976   CL_ASSERT( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH );
977
978   if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
979   {
980     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
981              "__osm_ucast_mgr_process_neighbors: "
982              "Processing switch with GUID = 0x%" PRIx64 ".\n",
983              cl_ntoh64( osm_node_get_node_guid( p_node ) ));
984   }
985
986   num_ports = osm_node_get_num_physp( p_node );
987
988   /*
989     Start with port 1 to skip the switch's management port.
990   */
991   for( port_num = 1; port_num < num_ports; port_num++ )
992   {
993     p_remote_node = osm_node_get_remote_node( p_node,
994                                               (uint8_t)port_num, &remote_port_num );
995
996     if( p_remote_node && (p_remote_node != p_node )
997         && (osm_node_get_type( p_remote_node )
998             == IB_NODE_TYPE_SWITCH ))
999     {
1000       /* make sure the link is healthy. If it is not - don't 
1001          propagate through it. */
1002       p_physp = osm_node_get_physp_ptr( p_node, port_num );
1003       if (!osm_link_is_healthy( p_physp ) ) continue;
1004
1005       remote_node_guid = osm_node_get_node_guid( p_remote_node );
1006
1007       p_remote_sw = (osm_switch_t*)cl_qmap_get(
1008         &p_mgr->p_subn->sw_guid_tbl, remote_node_guid );
1009
1010       if( p_remote_sw == (osm_switch_t*)cl_qmap_end(
1011             &p_mgr->p_subn->sw_guid_tbl ) )
1012       {
1013         osm_log( p_mgr->p_log, OSM_LOG_ERROR,
1014                  "__osm_ucast_mgr_process_neighbors: ERR 3A07: "
1015                  "No switch object for Node GUID = 0x%" PRIx64 ".\n",
1016                  cl_ntoh64( remote_node_guid ) );
1017       }
1018       else
1019       {
1020         __osm_ucast_mgr_process_neighbor(
1021           p_mgr,
1022           p_sw,
1023           p_remote_sw,
1024           (uint8_t)port_num,
1025           remote_port_num );
1026       }
1027     }
1028   }
1029
1030
1031   OSM_LOG_EXIT( p_mgr->p_log );
1032 }
1033
1034 /**********************************************************************
1035  **********************************************************************/
1036 osm_signal_t
1037 osm_ucast_mgr_process(
1038   IN osm_ucast_mgr_t* const p_mgr )
1039 {
1040   uint32_t i;
1041   uint32_t iteration_max;
1042   osm_signal_t signal;
1043   cl_qmap_t *p_sw_guid_tbl;
1044
1045   OSM_LOG_ENTER( p_mgr->p_log, osm_ucast_mgr_process );
1046
1047   p_sw_guid_tbl = &p_mgr->p_subn->sw_guid_tbl;
1048
1049   CL_PLOCK_EXCL_ACQUIRE( p_mgr->p_lock );
1050
1051   osm_log(p_mgr->p_log, OSM_LOG_VERBOSE,
1052           "osm_ucast_mgr_process: "
1053           "Starting switches Min Hop Table Assignment.\n");
1054   
1055   /*
1056     Set the switch matrixes for each switch's own port 0 LID,
1057     then set the lid matrixes for the each switch's leaf nodes.
1058   */
1059   cl_qmap_apply_func( p_sw_guid_tbl,
1060                       __osm_ucast_mgr_process_hop_0, p_mgr );
1061
1062   cl_qmap_apply_func( p_sw_guid_tbl,
1063                       __osm_ucast_mgr_process_leaves, p_mgr );
1064
1065   /*
1066     Get the switch matrixes for each switch's neighbors.
1067     This process requires a number of iterations equal to
1068     the number of switches in the subnet minus 1.
1069
1070     In each iteration, a switch learns the lid/port/hop
1071     information (as contained by a switch's lid matrix) from its
1072     immediate neighbors.  After each
1073     iteration, a switch (and it's neighbors) know more
1074     routing information than it did on the previous iteration.
1075     Thus, by repeatedly absorbing the routing information of
1076     neighbor switches, every switch eventually learns how to
1077     route all LIDs on the subnet.
1078
1079     Note that there may not be any switches in the subnet if
1080     we are in simple p2p configuration.
1081   */
1082   iteration_max = cl_qmap_count( &p_mgr->p_subn->sw_guid_tbl );
1083
1084   /*
1085     If there are switches in the subnet, iterate until the lid
1086     matrix has been constructed.  Otherwise, just immediately
1087     indicate we're done if no switches exist.
1088   */
1089   if( iteration_max )
1090   {
1091     iteration_max--;
1092
1093     /*
1094       we need to find out when the propagation of
1095       hop counts has relaxed. So this global variable
1096       is preset to 0 on each iteration and if
1097       if non of the switches was set will exit the
1098       while loop
1099     */
1100     __some_hop_count_set = TRUE;
1101     for( i = 0; (i < iteration_max) && __some_hop_count_set; i++ )
1102     {
1103       __some_hop_count_set = FALSE;
1104       cl_qmap_apply_func( p_sw_guid_tbl,
1105                           __osm_ucast_mgr_process_neighbors, p_mgr );
1106     }
1107     osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1108              "osm_ucast_mgr_process: "
1109              "Min-hop propagated in %d steps\n",
1110              i
1111              );
1112
1113     /*
1114       This is the place where we can load pre-defined routes
1115       into the switches fwd_tbl structures.
1116
1117       Later code will use these values if not configured for
1118       re-assignment.
1119     */
1120     if (p_mgr->p_subn->opt.pfn_ui_ucast_fdb_assign)
1121     {
1122       if( osm_log_is_active( p_mgr->p_log, OSM_LOG_DEBUG ) )
1123       {
1124         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1125                  "osm_ucast_mgr_process: "
1126                  "Invoking UI function pfn_ui_ucast_fdb_assign\n");
1127       }
1128       p_mgr->p_subn->opt.pfn_ui_ucast_fdb_assign(p_mgr->p_subn->opt.ui_ucast_fdb_assign_ctx);
1129     } else {
1130         osm_log( p_mgr->p_log, OSM_LOG_DEBUG,
1131                  "osm_ucast_mgr_process: "
1132                  "UI pfn was not invoked\n");
1133     }
1134
1135     osm_log(p_mgr->p_log, OSM_LOG_INFO,
1136             "osm_ucast_mgr_process: "
1137             "Min Hop Tables configured on all switches.\n");
1138
1139     /*
1140       Now that the lid matrixes have been built, we can
1141       build and download the switch forwarding tables.
1142     */
1143
1144     /* initialize the fdb dump file: */
1145     if( osm_log_is_active( p_mgr->p_log, OSM_LOG_ROUTING ) )
1146       unlink("/tmp/osm.fdbs");
1147
1148     cl_qmap_apply_func( p_sw_guid_tbl,
1149                         __osm_ucast_mgr_process_tbl, p_mgr );
1150
1151     /*
1152       For now dont' bother checking if the switch forwarding tables
1153       actually needed updating.  The current code will always update
1154       them, and thus leave transactions pending on the wire.
1155       Therefore, return OSM_SIGNAL_DONE_PENDING.
1156     */
1157
1158     signal = OSM_SIGNAL_DONE_PENDING;
1159   }
1160   else
1161     signal = OSM_SIGNAL_DONE;
1162
1163   osm_log(p_mgr->p_log, OSM_LOG_VERBOSE,
1164           "osm_ucast_mgr_process: "
1165           "LFT Tables configured on all switches.\n");
1166
1167   CL_PLOCK_RELEASE( p_mgr->p_lock );
1168   OSM_LOG_EXIT( p_mgr->p_log );
1169   return( signal );
1170 }
1171