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 OpenSM QoS infrastructure primitives
37 */
38
39 #if HAVE_CONFIG_H
40 # include <config.h>
41 #endif /* HAVE_CONFIG_H */
42
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include <iba/ib_types.h>
47 #include <complib/cl_qmap.h>
48 #include <complib/cl_debug.h>
49 #include <opensm/osm_opensm.h>
50 #include <opensm/osm_subnet.h>
51 #include <opensm/osm_qos_policy.h>
52
53 struct qos_config {
54 uint8_t max_vls;
55 uint8_t vl_high_limit;
56 ib_vl_arb_table_t vlarb_high[2];
57 ib_vl_arb_table_t vlarb_low[2];
58 ib_slvl_table_t sl2vl;
59 };
60
61 static void qos_build_config(struct qos_config *cfg,
62 osm_qos_options_t * opt, osm_qos_options_t * dflt);
63
64 /*
65 * QoS primitives
66 */
vlarb_update_table_block(osm_sm_t * sm,osm_physp_t * p,uint8_t port_num,unsigned force_update,const ib_vl_arb_table_t * table_block,unsigned block_length,unsigned block_num)67 static ib_api_status_t vlarb_update_table_block(osm_sm_t * sm,
68 osm_physp_t * p,
69 uint8_t port_num,
70 unsigned force_update,
71 const ib_vl_arb_table_t *
72 table_block,
73 unsigned block_length,
74 unsigned block_num)
75 {
76 ib_vl_arb_table_t block;
77 osm_madw_context_t context;
78 uint32_t attr_mod;
79 unsigned vl_mask, i;
80
81 vl_mask = (1 << (ib_port_info_get_op_vls(&p->port_info) - 1)) - 1;
82
83 memset(&block, 0, sizeof(block));
84 memcpy(&block, table_block, block_length * sizeof(block.vl_entry[0]));
85 for (i = 0; i < block_length; i++)
86 block.vl_entry[i].vl &= vl_mask;
87
88 if (!force_update &&
89 !memcmp(&p->vl_arb[block_num], &block,
90 block_length * sizeof(block.vl_entry[0])))
91 return IB_SUCCESS;
92
93 context.vla_context.node_guid =
94 osm_node_get_node_guid(osm_physp_get_node_ptr(p));
95 context.vla_context.port_guid = osm_physp_get_port_guid(p);
96 context.vla_context.set_method = TRUE;
97 attr_mod = ((block_num + 1) << 16) | port_num;
98
99 return osm_req_set(sm, osm_physp_get_dr_path_ptr(p),
100 (uint8_t *) & block, sizeof(block),
101 IB_MAD_ATTR_VL_ARBITRATION,
102 cl_hton32(attr_mod), CL_DISP_MSGID_NONE, &context);
103 }
104
vlarb_update(osm_sm_t * sm,osm_physp_t * p,uint8_t port_num,unsigned force_update,const struct qos_config * qcfg)105 static ib_api_status_t vlarb_update(osm_sm_t * sm,
106 osm_physp_t * p, uint8_t port_num,
107 unsigned force_update,
108 const struct qos_config *qcfg)
109 {
110 ib_api_status_t status = IB_SUCCESS;
111 ib_port_info_t *p_pi = &p->port_info;
112 unsigned len;
113
114 if (p_pi->vl_arb_low_cap > 0) {
115 len = p_pi->vl_arb_low_cap < IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK ?
116 p_pi->vl_arb_low_cap : IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK;
117 if ((status = vlarb_update_table_block(sm, p, port_num,
118 force_update,
119 &qcfg->vlarb_low[0],
120 len, 0)) != IB_SUCCESS)
121 return status;
122 }
123 if (p_pi->vl_arb_low_cap > IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK) {
124 len = p_pi->vl_arb_low_cap % IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK;
125 if ((status = vlarb_update_table_block(sm, p, port_num,
126 force_update,
127 &qcfg->vlarb_low[1],
128 len, 1)) != IB_SUCCESS)
129 return status;
130 }
131 if (p_pi->vl_arb_high_cap > 0) {
132 len = p_pi->vl_arb_high_cap < IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK ?
133 p_pi->vl_arb_high_cap : IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK;
134 if ((status = vlarb_update_table_block(sm, p, port_num,
135 force_update,
136 &qcfg->vlarb_high[0],
137 len, 2)) != IB_SUCCESS)
138 return status;
139 }
140 if (p_pi->vl_arb_high_cap > IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK) {
141 len = p_pi->vl_arb_high_cap % IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK;
142 if ((status = vlarb_update_table_block(sm, p, port_num,
143 force_update,
144 &qcfg->vlarb_high[1],
145 len, 3)) != IB_SUCCESS)
146 return status;
147 }
148
149 return status;
150 }
151
sl2vl_update_table(osm_sm_t * sm,osm_physp_t * p,uint8_t in_port,uint8_t out_port,unsigned force_update,const ib_slvl_table_t * sl2vl_table)152 static ib_api_status_t sl2vl_update_table(osm_sm_t * sm,
153 osm_physp_t * p, uint8_t in_port,
154 uint8_t out_port,
155 unsigned force_update,
156 const ib_slvl_table_t * sl2vl_table)
157 {
158 osm_madw_context_t context;
159 ib_slvl_table_t tbl, *p_tbl;
160 osm_node_t *p_node = osm_physp_get_node_ptr(p);
161 uint32_t attr_mod;
162 unsigned vl_mask;
163 uint8_t vl1, vl2;
164 int i;
165
166 vl_mask = (1 << (ib_port_info_get_op_vls(&p->port_info) - 1)) - 1;
167
168 for (i = 0; i < IB_MAX_NUM_VLS / 2; i++) {
169 vl1 = sl2vl_table->raw_vl_by_sl[i] >> 4;
170 vl2 = sl2vl_table->raw_vl_by_sl[i] & 0xf;
171 if (vl1 != 15)
172 vl1 &= vl_mask;
173 if (vl2 != 15)
174 vl2 &= vl_mask;
175 tbl.raw_vl_by_sl[i] = (vl1 << 4) | vl2;
176 }
177
178 if (!force_update && (p_tbl = osm_physp_get_slvl_tbl(p, in_port)) &&
179 !memcmp(p_tbl, &tbl, sizeof(tbl)))
180 return IB_SUCCESS;
181
182 context.slvl_context.node_guid = osm_node_get_node_guid(p_node);
183 context.slvl_context.port_guid = osm_physp_get_port_guid(p);
184 context.slvl_context.set_method = TRUE;
185 attr_mod = in_port << 8 | out_port;
186 return osm_req_set(sm, osm_physp_get_dr_path_ptr(p),
187 (uint8_t *) & tbl, sizeof(tbl),
188 IB_MAD_ATTR_SLVL_TABLE,
189 cl_hton32(attr_mod), CL_DISP_MSGID_NONE, &context);
190 }
191
sl2vl_update(osm_sm_t * sm,osm_port_t * p_port,osm_physp_t * p,uint8_t port_num,unsigned force_update,const struct qos_config * qcfg)192 static ib_api_status_t sl2vl_update(osm_sm_t * sm, osm_port_t * p_port,
193 osm_physp_t * p, uint8_t port_num,
194 unsigned force_update,
195 const struct qos_config *qcfg)
196 {
197 ib_api_status_t status;
198 uint8_t i, num_ports;
199 osm_physp_t *p_physp;
200
201 if (osm_node_get_type(osm_physp_get_node_ptr(p)) == IB_NODE_TYPE_SWITCH) {
202 if (ib_port_info_get_vl_cap(&p->port_info) == 1) {
203 /* Check port 0's capability mask */
204 p_physp = p_port->p_physp;
205 if (!
206 (p_physp->port_info.
207 capability_mask & IB_PORT_CAP_HAS_SL_MAP))
208 return IB_SUCCESS;
209 }
210 num_ports = osm_node_get_num_physp(osm_physp_get_node_ptr(p));
211 } else {
212 if (!(p->port_info.capability_mask & IB_PORT_CAP_HAS_SL_MAP))
213 return IB_SUCCESS;
214 num_ports = 1;
215 }
216
217 for (i = 0; i < num_ports; i++) {
218 status =
219 sl2vl_update_table(sm, p, i, port_num,
220 force_update, &qcfg->sl2vl);
221 if (status != IB_SUCCESS)
222 return status;
223 }
224
225 return IB_SUCCESS;
226 }
227
qos_physp_setup(osm_log_t * p_log,osm_sm_t * sm,osm_port_t * p_port,osm_physp_t * p,uint8_t port_num,unsigned force_update,const struct qos_config * qcfg)228 static ib_api_status_t qos_physp_setup(osm_log_t * p_log, osm_sm_t * sm,
229 osm_port_t * p_port, osm_physp_t * p,
230 uint8_t port_num,
231 unsigned force_update,
232 const struct qos_config *qcfg)
233 {
234 ib_api_status_t status;
235
236 /* OpVLs should be ok at this moment - just use it */
237
238 /* setup VL high limit on the physp later to be updated by link mgr */
239 p->vl_high_limit = qcfg->vl_high_limit;
240
241 /* setup VLArbitration */
242 status = vlarb_update(sm, p, port_num, force_update, qcfg);
243 if (status != IB_SUCCESS) {
244 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6202 : "
245 "failed to update VLArbitration tables "
246 "for port %" PRIx64 " #%d\n",
247 cl_ntoh64(p->port_guid), port_num);
248 return status;
249 }
250
251 /* setup SL2VL tables */
252 status = sl2vl_update(sm, p_port, p, port_num, force_update, qcfg);
253 if (status != IB_SUCCESS) {
254 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 6203 : "
255 "failed to update SL2VLMapping tables "
256 "for port %" PRIx64 " #%d\n",
257 cl_ntoh64(p->port_guid), port_num);
258 return status;
259 }
260
261 return IB_SUCCESS;
262 }
263
osm_qos_setup(osm_opensm_t * p_osm)264 osm_signal_t osm_qos_setup(osm_opensm_t * p_osm)
265 {
266 struct qos_config ca_config, sw0_config, swe_config, rtr_config;
267 struct qos_config *cfg;
268 cl_qmap_t *p_tbl;
269 cl_map_item_t *p_next;
270 osm_port_t *p_port;
271 uint32_t num_physp;
272 osm_physp_t *p_physp;
273 osm_node_t *p_node;
274 ib_api_status_t status;
275 unsigned force_update;
276 uint8_t i;
277
278 if (!p_osm->subn.opt.qos)
279 return OSM_SIGNAL_DONE;
280
281 OSM_LOG_ENTER(&p_osm->log);
282
283 qos_build_config(&ca_config, &p_osm->subn.opt.qos_ca_options,
284 &p_osm->subn.opt.qos_options);
285 qos_build_config(&sw0_config, &p_osm->subn.opt.qos_sw0_options,
286 &p_osm->subn.opt.qos_options);
287 qos_build_config(&swe_config, &p_osm->subn.opt.qos_swe_options,
288 &p_osm->subn.opt.qos_options);
289 qos_build_config(&rtr_config, &p_osm->subn.opt.qos_rtr_options,
290 &p_osm->subn.opt.qos_options);
291
292 cl_plock_excl_acquire(&p_osm->lock);
293
294 /* read QoS policy config file */
295 osm_qos_parse_policy_file(&p_osm->subn);
296
297 p_tbl = &p_osm->subn.port_guid_tbl;
298 p_next = cl_qmap_head(p_tbl);
299 while (p_next != cl_qmap_end(p_tbl)) {
300 p_port = (osm_port_t *) p_next;
301 p_next = cl_qmap_next(p_next);
302
303 p_node = p_port->p_node;
304 if (p_node->sw) {
305 num_physp = osm_node_get_num_physp(p_node);
306 for (i = 1; i < num_physp; i++) {
307 p_physp = osm_node_get_physp_ptr(p_node, i);
308 if (!p_physp)
309 continue;
310 force_update = p_physp->need_update ||
311 p_osm->subn.need_update;
312 status =
313 qos_physp_setup(&p_osm->log, &p_osm->sm,
314 p_port, p_physp, i,
315 force_update, &swe_config);
316 }
317 /* skip base port 0 */
318 if (!ib_switch_info_is_enhanced_port0
319 (&p_node->sw->switch_info))
320 continue;
321
322 cfg = &sw0_config;
323 } else if (osm_node_get_type(p_node) == IB_NODE_TYPE_ROUTER)
324 cfg = &rtr_config;
325 else
326 cfg = &ca_config;
327
328 p_physp = p_port->p_physp;
329 if (!p_physp)
330 continue;
331
332 force_update = p_physp->need_update || p_osm->subn.need_update;
333 status = qos_physp_setup(&p_osm->log, &p_osm->sm,
334 p_port, p_physp, 0, force_update, cfg);
335 }
336
337 cl_plock_release(&p_osm->lock);
338 OSM_LOG_EXIT(&p_osm->log);
339
340 return OSM_SIGNAL_DONE;
341 }
342
343 /*
344 * QoS config stuff
345 */
parse_one_unsigned(char * str,char delim,unsigned * val)346 static int parse_one_unsigned(char *str, char delim, unsigned *val)
347 {
348 char *end;
349 *val = strtoul(str, &end, 0);
350 if (*end)
351 end++;
352 return (int)(end - str);
353 }
354
parse_vlarb_entry(char * str,ib_vl_arb_element_t * e)355 static int parse_vlarb_entry(char *str, ib_vl_arb_element_t * e)
356 {
357 unsigned val;
358 char *p = str;
359 p += parse_one_unsigned(p, ':', &val);
360 e->vl = val % 15;
361 p += parse_one_unsigned(p, ',', &val);
362 e->weight = (uint8_t) val;
363 return (int)(p - str);
364 }
365
parse_sl2vl_entry(char * str,uint8_t * raw)366 static int parse_sl2vl_entry(char *str, uint8_t * raw)
367 {
368 unsigned val1, val2;
369 char *p = str;
370 p += parse_one_unsigned(p, ',', &val1);
371 p += parse_one_unsigned(p, ',', &val2);
372 *raw = (val1 << 4) | (val2 & 0xf);
373 return (int)(p - str);
374 }
375
qos_build_config(struct qos_config * cfg,osm_qos_options_t * opt,osm_qos_options_t * dflt)376 static void qos_build_config(struct qos_config *cfg,
377 osm_qos_options_t * opt, osm_qos_options_t * dflt)
378 {
379 int i;
380 char *p;
381
382 memset(cfg, 0, sizeof(*cfg));
383
384 cfg->max_vls = opt->max_vls > 0 ? opt->max_vls : dflt->max_vls;
385
386 if (opt->high_limit >= 0)
387 cfg->vl_high_limit = (uint8_t) opt->high_limit;
388 else
389 cfg->vl_high_limit = (uint8_t) dflt->high_limit;
390
391 p = opt->vlarb_high ? opt->vlarb_high : dflt->vlarb_high;
392 for (i = 0; i < 2 * IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK; i++) {
393 p += parse_vlarb_entry(p,
394 &cfg->vlarb_high[i /
395 IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK].
396 vl_entry[i %
397 IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK]);
398 }
399
400 p = opt->vlarb_low ? opt->vlarb_low : dflt->vlarb_low;
401 for (i = 0; i < 2 * IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK; i++) {
402 p += parse_vlarb_entry(p,
403 &cfg->vlarb_low[i /
404 IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK].
405 vl_entry[i %
406 IB_NUM_VL_ARB_ELEMENTS_IN_BLOCK]);
407 }
408
409 p = opt->sl2vl ? opt->sl2vl : dflt->sl2vl;
410 for (i = 0; i < IB_MAX_NUM_VLS / 2; i++)
411 p += parse_sl2vl_entry(p, &cfg->sl2vl.raw_vl_by_sl[i]);
412
413 }
414