]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/opensm/opensm/osm_prtn.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / opensm / opensm / osm_prtn.c
1 /*
2  * Copyright (c) 2006-2008 Voltaire, Inc. All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  *
32  */
33
34 /*
35  * Abstract:
36  *    Implementation of osm_prtn_t.
37  * This object represents an IBA partition.
38  * This object is part of the opensm family of objects.
39  */
40
41 #if HAVE_CONFIG_H
42 #  include <config.h>
43 #endif                          /* HAVE_CONFIG_H */
44
45 #include <stdlib.h>
46 #include <string.h>
47 #include <stdio.h>
48 #include <sys/stat.h>
49 #include <complib/cl_debug.h>
50 #include <iba/ib_types.h>
51 #include <opensm/osm_opensm.h>
52 #include <opensm/osm_partition.h>
53 #include <opensm/osm_node.h>
54 #include <opensm/osm_sa.h>
55 #include <opensm/osm_multicast.h>
56
57 extern int osm_prtn_config_parse_file(osm_log_t * const p_log,
58                                       osm_subn_t * const p_subn,
59                                       const char *file_name);
60
61 static uint16_t global_pkey_counter;
62
63 osm_prtn_t *osm_prtn_new(IN const char *name, IN const uint16_t pkey)
64 {
65         osm_prtn_t *p = malloc(sizeof(*p));
66         if (!p)
67                 return NULL;
68
69         memset(p, 0, sizeof(*p));
70         p->pkey = pkey;
71         p->sl = OSM_DEFAULT_SL;
72         cl_map_construct(&p->full_guid_tbl);
73         cl_map_init(&p->full_guid_tbl, 32);
74         cl_map_construct(&p->part_guid_tbl);
75         cl_map_init(&p->part_guid_tbl, 32);
76
77         if (name && *name)
78                 strncpy(p->name, name, sizeof(p->name));
79         else
80                 snprintf(p->name, sizeof(p->name), "%04x", cl_ntoh16(pkey));
81
82         return p;
83 }
84
85 void osm_prtn_delete(IN OUT osm_prtn_t ** const pp_prtn)
86 {
87         osm_prtn_t *p = *pp_prtn;
88
89         cl_map_remove_all(&p->full_guid_tbl);
90         cl_map_destroy(&p->full_guid_tbl);
91         cl_map_remove_all(&p->part_guid_tbl);
92         cl_map_destroy(&p->part_guid_tbl);
93         free(p);
94         *pp_prtn = NULL;
95 }
96
97 ib_api_status_t osm_prtn_add_port(osm_log_t * p_log, osm_subn_t * p_subn,
98                                   osm_prtn_t * p, ib_net64_t guid,
99                                   boolean_t full)
100 {
101         ib_api_status_t status = IB_SUCCESS;
102         cl_map_t *p_tbl;
103         osm_port_t *p_port;
104         osm_physp_t *p_physp;
105
106         p_port = osm_get_port_by_guid(p_subn, guid);
107         if (!p_port) {
108                 OSM_LOG(p_log, OSM_LOG_VERBOSE,
109                         "port 0x%" PRIx64 " not found\n", cl_ntoh64(guid));
110                 return status;
111         }
112
113         p_physp = p_port->p_physp;
114         if (!p_physp) {
115                 OSM_LOG(p_log, OSM_LOG_VERBOSE,
116                         "no physical for port 0x%" PRIx64 "\n",
117                         cl_ntoh64(guid));
118                 return status;
119         }
120
121         if (cl_map_remove(&p->part_guid_tbl, guid) ||
122             cl_map_remove(&p->full_guid_tbl, guid)) {
123                 OSM_LOG(p_log, OSM_LOG_VERBOSE,
124                         "port 0x%" PRIx64 " already in "
125                         "partition \'%s\' (0x%04x). Will overwrite\n",
126                         cl_ntoh64(guid), p->name, cl_ntoh16(p->pkey));
127         }
128
129         p_tbl = (full == TRUE) ? &p->full_guid_tbl : &p->part_guid_tbl;
130
131         if (cl_map_insert(p_tbl, guid, p_physp) == NULL)
132                 return IB_INSUFFICIENT_MEMORY;
133
134         return status;
135 }
136
137 ib_api_status_t osm_prtn_add_all(osm_log_t * p_log, osm_subn_t * p_subn,
138                                  osm_prtn_t * p, boolean_t full)
139 {
140         cl_qmap_t *p_port_tbl = &p_subn->port_guid_tbl;
141         cl_map_item_t *p_item;
142         osm_port_t *p_port;
143         ib_api_status_t status = IB_SUCCESS;
144
145         p_item = cl_qmap_head(p_port_tbl);
146         while (p_item != cl_qmap_end(p_port_tbl)) {
147                 p_port = (osm_port_t *) p_item;
148                 p_item = cl_qmap_next(p_item);
149                 status = osm_prtn_add_port(p_log, p_subn, p,
150                                            osm_port_get_guid(p_port), full);
151                 if (status != IB_SUCCESS)
152                         goto _err;
153         }
154
155 _err:
156         return status;
157 }
158
159 static const ib_gid_t osm_ipoib_mgid = {
160         {
161          0xff,                  /*  multicast field */
162          0x12,                  /*  non-permanent bit, link local scope */
163          0x40, 0x1b,            /*  IPv4 signature */
164          0xff, 0xff,            /*  16 bits of P_Key (to be filled in) */
165          0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    /*  48 bits of zeros */
166          0xff, 0xff, 0xff, 0xff,        /*  32 bit IPv4 broadcast address */
167          },
168 };
169
170 /*
171  * HACK: Until TS resolves their noncompliant join compmask,
172  * we have to pre-define the MGID
173  */
174 static const ib_gid_t osm_ts_ipoib_mgid = {
175         {
176          0xff,                  /*  multicast field */
177          0x12,                  /*  non-permanent bit, link local scope */
178          0x40, 0x1b,            /*  IPv4 signature */
179          0xff, 0xff,            /*  16 bits of P_Key (to be filled in) */
180          0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    /*  48 bits of zeros */
181          0x00, 0x00, 0x00, 0x01,        /*  32 bit IPv4 broadcast address */
182          },
183 };
184
185 ib_api_status_t osm_prtn_add_mcgroup(osm_log_t * p_log,
186                                      osm_subn_t * p_subn, osm_prtn_t * p,
187                                      uint8_t rate,
188                                      uint8_t mtu, uint8_t scope)
189 {
190         ib_member_rec_t mc_rec;
191         ib_net64_t comp_mask;
192         ib_net16_t pkey;
193         osm_mgrp_t *p_mgrp = NULL;
194         osm_sa_t *p_sa = &p_subn->p_osm->sa;
195         ib_api_status_t status = IB_SUCCESS;
196         uint8_t hop_limit;
197
198         pkey = p->pkey | cl_hton16(0x8000);
199         if (!scope)
200                 scope = OSM_DEFAULT_MGRP_SCOPE;
201         hop_limit = (scope == IB_MC_SCOPE_LINK_LOCAL) ? 0 : IB_HOPLIMIT_MAX;
202
203         memset(&mc_rec, 0, sizeof(mc_rec));
204
205         mc_rec.mgid = osm_ipoib_mgid;   /* ipv4 broadcast group */
206         memcpy(&mc_rec.mgid.raw[4], &pkey, sizeof(pkey));
207
208         mc_rec.qkey = CL_HTON32(0x0b1b);
209         mc_rec.mtu = (mtu ? mtu : OSM_DEFAULT_MGRP_MTU) | (2 << 6);     /* 2048 Bytes */
210         mc_rec.tclass = 0;
211         mc_rec.pkey = pkey;
212         mc_rec.rate = (rate ? rate : OSM_DEFAULT_MGRP_RATE) | (2 << 6); /* 10Gb/sec */
213         mc_rec.pkt_life = p_subn->opt.subnet_timeout;
214         mc_rec.sl_flow_hop = ib_member_set_sl_flow_hop(p->sl, 0, hop_limit);
215         /* Scope in MCMemberRecord (if present) needs to be consistent with MGID */
216         mc_rec.scope_state = ib_member_set_scope_state(scope, IB_MC_REC_STATE_FULL_MEMBER);
217         ib_mgid_set_scope(&mc_rec.mgid, scope);
218
219         /* don't update rate, mtu */
220         comp_mask = IB_MCR_COMPMASK_MTU | IB_MCR_COMPMASK_MTU_SEL |
221             IB_MCR_COMPMASK_RATE | IB_MCR_COMPMASK_RATE_SEL;
222         status = osm_mcmr_rcv_find_or_create_new_mgrp(p_sa, comp_mask, &mc_rec,
223                                                       &p_mgrp);
224         if (!p_mgrp || status != IB_SUCCESS)
225                 OSM_LOG(p_log, OSM_LOG_ERROR,
226                         "Failed to create MC group with pkey 0x%04x\n",
227                         cl_ntoh16(pkey));
228         if (p_mgrp) {
229                 p_mgrp->well_known = TRUE;
230                 p->mlid = p_mgrp->mlid;
231         }
232
233         /* workaround for TS */
234         /* FIXME: remove this upon TS fixes */
235         mc_rec.mgid = osm_ts_ipoib_mgid;
236         memcpy(&mc_rec.mgid.raw[4], &pkey, sizeof(pkey));
237         /* Scope in MCMemberRecord (if present) needs to be consistent with MGID */
238         mc_rec.scope_state = ib_member_set_scope_state(scope, IB_MC_REC_STATE_FULL_MEMBER);
239         ib_mgid_set_scope(&mc_rec.mgid, scope);
240
241         status = osm_mcmr_rcv_find_or_create_new_mgrp(p_sa, comp_mask, &mc_rec,
242                                                       &p_mgrp);
243         if (p_mgrp) {
244                 p_mgrp->well_known = TRUE;
245                 if (!p->mlid)
246                         p->mlid = p_mgrp->mlid;
247         }
248
249         return status;
250 }
251
252 static uint16_t __generate_pkey(osm_subn_t * p_subn)
253 {
254         uint16_t pkey;
255
256         cl_qmap_t *m = &p_subn->prtn_pkey_tbl;
257         while (global_pkey_counter < cl_ntoh16(IB_DEFAULT_PARTIAL_PKEY) - 1) {
258                 pkey = ++global_pkey_counter;
259                 pkey = cl_hton16(pkey);
260                 if (cl_qmap_get(m, pkey) == cl_qmap_end(m))
261                         return pkey;
262         }
263         return 0;
264 }
265
266 osm_prtn_t *osm_prtn_find_by_name(osm_subn_t * p_subn, const char *name)
267 {
268         cl_map_item_t *p_next;
269         osm_prtn_t *p;
270
271         p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl);
272         while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) {
273                 p = (osm_prtn_t *) p_next;
274                 p_next = cl_qmap_next(&p->map_item);
275                 if (!strncmp(p->name, name, sizeof(p->name)))
276                         return p;
277         }
278
279         return NULL;
280 }
281
282 osm_prtn_t *osm_prtn_make_new(osm_log_t * p_log, osm_subn_t * p_subn,
283                               const char *name, uint16_t pkey)
284 {
285         osm_prtn_t *p = NULL, *p_check;
286
287         pkey &= cl_hton16((uint16_t) ~ 0x8000);
288
289         if (!pkey) {
290                 if (name && (p = osm_prtn_find_by_name(p_subn, name)))
291                         return p;
292                 if (!(pkey = __generate_pkey(p_subn)))
293                         return NULL;
294         }
295
296         p = osm_prtn_new(name, pkey);
297         if (!p) {
298                 OSM_LOG(p_log, OSM_LOG_ERROR, "Unable to create"
299                         " partition \'%s\' (0x%04x)\n", name, cl_ntoh16(pkey));
300                 return NULL;
301         }
302
303         p_check = (osm_prtn_t *) cl_qmap_insert(&p_subn->prtn_pkey_tbl,
304                                                 p->pkey, &p->map_item);
305         if (p != p_check) {
306                 OSM_LOG(p_log, OSM_LOG_VERBOSE, "Duplicated partition"
307                         " definition: \'%s\' (0x%04x) prev name \'%s\'"
308                         ".  Will use it\n",
309                         name, cl_ntoh16(pkey), p_check->name);
310                 osm_prtn_delete(&p);
311                 p = p_check;
312         }
313
314         return p;
315 }
316
317 static ib_api_status_t osm_prtn_make_default(osm_log_t * const p_log,
318                                              osm_subn_t * const p_subn,
319                                              boolean_t no_config)
320 {
321         ib_api_status_t status = IB_UNKNOWN_ERROR;
322         osm_prtn_t *p;
323
324         p = osm_prtn_make_new(p_log, p_subn, "Default",
325                               IB_DEFAULT_PARTIAL_PKEY);
326         if (!p)
327                 goto _err;
328         status = osm_prtn_add_all(p_log, p_subn, p, no_config);
329         if (status != IB_SUCCESS)
330                 goto _err;
331         cl_map_remove(&p->part_guid_tbl, p_subn->sm_port_guid);
332         status =
333             osm_prtn_add_port(p_log, p_subn, p, p_subn->sm_port_guid, TRUE);
334
335         if (no_config)
336                 osm_prtn_add_mcgroup(p_log, p_subn, p, 0, 0, 0);
337
338 _err:
339         return status;
340 }
341
342 ib_api_status_t osm_prtn_make_partitions(osm_log_t * const p_log,
343                                          osm_subn_t * const p_subn)
344 {
345         struct stat statbuf;
346         const char *file_name;
347         boolean_t is_config = TRUE;
348         ib_api_status_t status = IB_SUCCESS;
349         cl_map_item_t *p_next;
350         osm_prtn_t *p;
351
352         file_name = p_subn->opt.partition_config_file ?
353             p_subn->opt.partition_config_file : OSM_DEFAULT_PARTITION_CONFIG_FILE;
354         if (stat(file_name, &statbuf))
355                 is_config = FALSE;
356
357         /* clean up current port maps */
358         p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl);
359         while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) {
360                 p = (osm_prtn_t *) p_next;
361                 p_next = cl_qmap_next(&p->map_item);
362                 cl_map_remove_all(&p->part_guid_tbl);
363                 cl_map_remove_all(&p->full_guid_tbl);
364         }
365
366         global_pkey_counter = 0;
367
368         status = osm_prtn_make_default(p_log, p_subn, !is_config);
369         if (status != IB_SUCCESS)
370                 goto _err;
371
372         if (is_config && osm_prtn_config_parse_file(p_log, p_subn, file_name)) {
373                 OSM_LOG(p_log, OSM_LOG_VERBOSE, "Partition configuration "
374                         "was not fully processed\n");
375         }
376
377         /* and now clean up empty partitions */
378         p_next = cl_qmap_head(&p_subn->prtn_pkey_tbl);
379         while (p_next != cl_qmap_end(&p_subn->prtn_pkey_tbl)) {
380                 p = (osm_prtn_t *) p_next;
381                 p_next = cl_qmap_next(&p->map_item);
382                 if (cl_map_count(&p->part_guid_tbl) == 0 &&
383                     cl_map_count(&p->full_guid_tbl) == 0) {
384                         cl_qmap_remove_item(&p_subn->prtn_pkey_tbl,
385                                             (cl_map_item_t *) p);
386                         osm_prtn_delete(&p);
387                 }
388         }
389
390 _err:
391         return status;
392 }