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