2 * Copyright (c) 2004-2008 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 * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved.
7 * This software is available to you under a choice of one of two
8 * licenses. You may choose to be licensed under the terms of the GNU
9 * General Public License (GPL) Version 2, available from the file
10 * COPYING in the main directory of this source tree, or the
11 * OpenIB.org BSD license below:
13 * Redistribution and use in source and binary forms, with or
14 * without modification, are permitted provided that the following
17 * - Redistributions of source code must retain the above
18 * copyright notice, this list of conditions and the following
21 * - Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials
24 * provided with the distribution.
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 * Implementation of osm_mcmr_recv_t.
40 * This object represents the MCMemberRecord Receiver object.
41 * This object is part of the opensm family of objects.
46 #endif /* HAVE_CONFIG_H */
50 #include <arpa/inet.h>
51 #include <iba/ib_types.h>
52 #include <complib/cl_qmap.h>
53 #include <complib/cl_passivelock.h>
54 #include <complib/cl_debug.h>
55 #include <complib/cl_qlist.h>
56 #include <vendor/osm_vendor_api.h>
57 #include <opensm/osm_madw.h>
58 #include <opensm/osm_log.h>
59 #include <opensm/osm_subnet.h>
60 #include <opensm/osm_mad_pool.h>
61 #include <opensm/osm_helper.h>
62 #include <opensm/osm_msgdef.h>
63 #include <opensm/osm_pkey.h>
64 #include <opensm/osm_inform.h>
65 #include <opensm/osm_sa.h>
67 #include <sys/socket.h>
69 #define JOIN_MC_COMP_MASK (IB_MCR_COMPMASK_MGID | \
70 IB_MCR_COMPMASK_PORT_GID | \
71 IB_MCR_COMPMASK_JOIN_STATE)
73 #define REQUIRED_MC_CREATE_COMP_MASK (IB_MCR_COMPMASK_MGID | \
74 IB_MCR_COMPMASK_PORT_GID | \
75 IB_MCR_COMPMASK_JOIN_STATE | \
76 IB_MCR_COMPMASK_QKEY | \
77 IB_MCR_COMPMASK_TCLASS | \
78 IB_MCR_COMPMASK_PKEY | \
79 IB_MCR_COMPMASK_FLOW | \
82 typedef struct osm_mcmr_item {
83 cl_list_item_t list_item;
87 /*********************************************************************
88 Copy certain fields between two mcmember records
89 used during the process of join request to copy data from the mgrp
91 **********************************************************************/
93 __copy_from_create_mc_rec(IN ib_member_rec_t * const dest,
94 IN const ib_member_rec_t * const src)
96 dest->qkey = src->qkey;
97 dest->mlid = src->mlid;
98 dest->tclass = src->tclass;
99 dest->pkey = src->pkey;
100 dest->sl_flow_hop = src->sl_flow_hop;
101 dest->mtu = src->mtu;
102 dest->rate = src->rate;
103 dest->pkt_life = src->pkt_life;
106 /*********************************************************************
107 Return mlid to the pool of free mlids.
108 But this implementation is not a pool - it simply scans through
109 the MGRP database for unused mlids...
110 *********************************************************************/
111 static void __free_mlid(IN osm_sa_t * sa, IN uint16_t mlid)
117 /*********************************************************************
118 Get a new unused mlid by scanning all the used ones in the subnet.
119 **********************************************************************/
120 static ib_net16_t __get_new_mlid(osm_sa_t *sa, ib_net16_t requested_mlid)
122 osm_subn_t *p_subn = sa->p_subn;
125 if (requested_mlid && cl_ntoh16(requested_mlid) >= IB_LID_MCAST_START_HO
126 && cl_ntoh16(requested_mlid) <= p_subn->max_mcast_lid_ho
127 && !osm_get_mgrp_by_mlid(p_subn, requested_mlid))
128 return requested_mlid;
130 max = p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO + 1;
131 for (i = 0; i < max; i++) {
132 osm_mgrp_t *p_mgrp = sa->p_subn->mgroups[i];
133 if (!p_mgrp || p_mgrp->to_be_deleted)
134 return cl_hton16(i + IB_LID_MCAST_START_HO);
140 /*********************************************************************
141 This procedure is only invoked to cleanup an INTERMEDIATE mgrp.
142 If there is only one port on the mgrp it means that the current
143 request was the only member and the group is not really needed. So
144 we silently drop it. Since it was an intermediate group no need to
146 **********************************************************************/
147 static void __cleanup_mgrp(IN osm_sa_t * sa, osm_mgrp_t *mgrp)
149 /* Remove MGRP only if osm_mcm_port_t count is 0 and
150 not a well known group */
151 if (cl_is_qmap_empty(&mgrp->mcm_port_tbl) && !mgrp->well_known) {
152 sa->p_subn->mgroups[cl_ntoh16(mgrp->mlid) - IB_LID_MCAST_START_HO] = NULL;
153 osm_mgrp_delete(mgrp);
157 /*********************************************************************
158 Add a port to the group. Calculating its PROXY_JOIN by the Port and
160 **********************************************************************/
161 static ib_api_status_t
162 __add_new_mgrp_port(IN osm_sa_t * sa,
163 IN osm_mgrp_t * p_mgrp,
164 IN ib_member_rec_t * p_recvd_mcmember_rec,
165 IN osm_mad_addr_t * p_mad_addr,
166 OUT osm_mcm_port_t ** pp_mcmr_port)
168 boolean_t proxy_join;
169 ib_gid_t requester_gid;
172 /* set the proxy_join if the requester gid is not identical to the
174 res = osm_get_gid_by_mad_addr(sa->p_log, sa->p_subn,
175 p_mad_addr, &requester_gid);
176 if (res != IB_SUCCESS) {
177 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B29: "
178 "Could not find GID for requester\n");
180 return IB_INVALID_PARAMETER;
183 if (!memcmp(&p_recvd_mcmember_rec->port_gid, &requester_gid,
186 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
187 "Create new port with proxy_join FALSE\n");
189 /* The port is not the one specified in PortGID.
190 The check that the requester is in the same partition as
191 the PortGID is done before - just need to update
194 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
195 "Create new port with proxy_join TRUE\n");
198 *pp_mcmr_port = osm_mgrp_add_port(sa->p_subn, sa->p_log, p_mgrp,
199 &p_recvd_mcmember_rec->port_gid,
200 p_recvd_mcmember_rec->scope_state,
202 if (*pp_mcmr_port == NULL) {
203 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B06: "
204 "osm_mgrp_add_port failed\n");
206 return IB_INSUFFICIENT_MEMORY;
212 /**********************************************************************
213 **********************************************************************/
214 static inline boolean_t __check_join_comp_mask(ib_net64_t comp_mask)
216 return ((comp_mask & JOIN_MC_COMP_MASK) == JOIN_MC_COMP_MASK);
219 /**********************************************************************
220 **********************************************************************/
221 static inline boolean_t
222 __check_create_comp_mask(ib_net64_t comp_mask,
223 ib_member_rec_t * p_recvd_mcmember_rec)
225 return ((comp_mask & REQUIRED_MC_CREATE_COMP_MASK) ==
226 REQUIRED_MC_CREATE_COMP_MASK);
229 /**********************************************************************
230 Generate the response MAD
231 **********************************************************************/
233 __osm_mcmr_rcv_respond(IN osm_sa_t * sa,
234 IN osm_madw_t * const p_madw,
235 IN ib_member_rec_t * p_mcmember_rec)
238 osm_mcmr_item_t *item;
240 OSM_LOG_ENTER(sa->p_log);
242 item = malloc(sizeof(*item));
244 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B16: "
245 "rec_item alloc failed\n");
249 item->rec = *p_mcmember_rec;
251 /* Fill in the mtu, rate, and packet lifetime selectors */
252 item->rec.mtu &= 0x3f;
253 item->rec.mtu |= 2 << 6; /* exactly */
254 item->rec.rate &= 0x3f;
255 item->rec.rate |= 2 << 6; /* exactly */
256 item->rec.pkt_life &= 0x3f;
257 item->rec.pkt_life |= 2 << 6; /* exactly */
259 cl_qlist_init(&rec_list);
260 cl_qlist_insert_tail(&rec_list, &item->list_item);
262 osm_sa_respond(sa, p_madw, sizeof(ib_member_rec_t), &rec_list);
265 OSM_LOG_EXIT(sa->p_log);
268 /*********************************************************************
269 In joining an existing group, or when querying the mc groups,
270 we make sure the following components provided match: MTU and RATE
271 HACK: Currently we ignore the PKT_LIFETIME field.
272 **********************************************************************/
274 __validate_more_comp_fields(osm_log_t * p_log,
275 const osm_mgrp_t * p_mgrp,
276 const ib_member_rec_t * p_recvd_mcmember_rec,
277 ib_net64_t comp_mask)
280 uint8_t mtu_required;
283 uint8_t rate_required;
286 if (comp_mask & IB_MCR_COMPMASK_MTU_SEL) {
287 mtu_sel = (uint8_t) (p_recvd_mcmember_rec->mtu >> 6);
288 /* Clearing last 2 bits */
289 mtu_required = (uint8_t) (p_recvd_mcmember_rec->mtu & 0x3F);
290 mtu_mgrp = (uint8_t) (p_mgrp->mcmember_rec.mtu & 0x3F);
292 case 0: /* Greater than MTU specified */
293 if (mtu_mgrp <= mtu_required) {
294 OSM_LOG(p_log, OSM_LOG_DEBUG,
295 "Requested mcast group has MTU %x, "
296 "which is not greater than %x\n",
297 mtu_mgrp, mtu_required);
301 case 1: /* Less than MTU specified */
302 if (mtu_mgrp >= mtu_required) {
303 OSM_LOG(p_log, OSM_LOG_DEBUG,
304 "Requested mcast group has MTU %x, "
305 "which is not less than %x\n",
306 mtu_mgrp, mtu_required);
310 case 2: /* Exactly MTU specified */
311 if (mtu_mgrp != mtu_required) {
312 OSM_LOG(p_log, OSM_LOG_DEBUG,
313 "Requested mcast group has MTU %x, "
314 "which is not equal to %x\n",
315 mtu_mgrp, mtu_required);
324 /* what about rate ? */
325 if (comp_mask & IB_MCR_COMPMASK_RATE_SEL) {
326 rate_sel = (uint8_t) (p_recvd_mcmember_rec->rate >> 6);
327 /* Clearing last 2 bits */
328 rate_required = (uint8_t) (p_recvd_mcmember_rec->rate & 0x3F);
329 rate_mgrp = (uint8_t) (p_mgrp->mcmember_rec.rate & 0x3F);
331 case 0: /* Greater than RATE specified */
332 if (rate_mgrp <= rate_required) {
333 OSM_LOG(p_log, OSM_LOG_DEBUG,
334 "Requested mcast group has RATE %x, "
335 "which is not greater than %x\n",
336 rate_mgrp, rate_required);
340 case 1: /* Less than RATE specified */
341 if (rate_mgrp >= rate_required) {
342 OSM_LOG(p_log, OSM_LOG_DEBUG,
343 "Requested mcast group has RATE %x, "
344 "which is not less than %x\n",
345 rate_mgrp, rate_required);
349 case 2: /* Exactly RATE specified */
350 if (rate_mgrp != rate_required) {
351 OSM_LOG(p_log, OSM_LOG_DEBUG,
352 "Requested mcast group has RATE %x, "
353 "which is not equal to %x\n",
354 rate_mgrp, rate_required);
366 /*********************************************************************
367 In joining an existing group, we make sure the following components
368 are physically realizable: MTU and RATE
369 **********************************************************************/
371 __validate_port_caps(osm_log_t * const p_log,
372 const osm_mgrp_t * p_mgrp, const osm_physp_t * p_physp)
374 uint8_t mtu_required;
376 uint8_t rate_required;
379 mtu_required = ib_port_info_get_mtu_cap(&p_physp->port_info);
380 mtu_mgrp = (uint8_t) (p_mgrp->mcmember_rec.mtu & 0x3F);
381 if (mtu_required < mtu_mgrp) {
382 OSM_LOG(p_log, OSM_LOG_DEBUG,
383 "Port's MTU %x is less than %x\n",
384 mtu_required, mtu_mgrp);
388 rate_required = ib_port_info_compute_rate(&p_physp->port_info);
389 rate_mgrp = (uint8_t) (p_mgrp->mcmember_rec.rate & 0x3F);
390 if (rate_required < rate_mgrp) {
391 OSM_LOG(p_log, OSM_LOG_DEBUG,
392 "Port's RATE %x is less than %x\n",
393 rate_required, rate_mgrp);
400 /**********************************************************************
401 * o15-0.2.1: If SA supports UD multicast, then if SA receives a SubnAdmSet()
402 * or SubnAdmDelete() method that would modify an existing
403 * MCMemberRecord, SA shall not modify that MCMemberRecord and shall
404 * return an error status of ERR_REQ_INVALID in response in the
406 * 1. Saved MCMemberRecord.ProxyJoin is not set and the request is
407 * issued by a requester with a GID other than the Port-GID.
408 * 2. Saved MCMemberRecord.ProxyJoin is set and the requester is not
409 * part of the partition for that MCMemberRecord.
410 **********************************************************************/
412 __validate_modify(IN osm_sa_t * sa,
413 IN osm_mgrp_t * p_mgrp,
414 IN osm_mad_addr_t * p_mad_addr,
415 IN ib_member_rec_t * p_recvd_mcmember_rec,
416 OUT osm_mcm_port_t ** pp_mcm_port)
419 ib_gid_t request_gid;
420 osm_physp_t *p_request_physp;
423 portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id;
427 /* o15-0.2.1: If this is a new port being added - nothing to check */
428 if (!osm_mgrp_is_port_present(p_mgrp, portguid, pp_mcm_port)) {
429 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
430 "This is a new port in the MC group\n");
434 /* We validate the request according the the proxy_join.
435 Check if the proxy_join is set or not */
436 if ((*pp_mcm_port)->proxy_join == FALSE) {
437 /* The proxy_join is not set. Modifying can by done only
438 if the requester GID == PortGID */
439 res = osm_get_gid_by_mad_addr(sa->p_log,
441 p_mad_addr, &request_gid);
443 if (res != IB_SUCCESS) {
444 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
445 "Could not find port for requested address\n");
449 if (memcmp(&((*pp_mcm_port)->port_gid), &request_gid,
451 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
452 "No ProxyJoin but different ports: stored:"
453 "0x%016" PRIx64 " request:0x%016" PRIx64 "\n",
454 cl_ntoh64((*pp_mcm_port)->port_gid.unicast.
456 cl_ntoh64(p_mad_addr->addr_type.gsi.grh_info.
457 src_gid.unicast.interface_id));
461 /* The proxy_join is set. Modification allowed only if the
462 requester is part of the partition for this MCMemberRecord */
463 p_request_physp = osm_get_physp_by_mad_addr(sa->p_log,
466 if (p_request_physp == NULL)
469 if (!osm_physp_has_pkey(sa->p_log, p_mgrp->mcmember_rec.pkey,
471 /* the request port is not part of the partition for this mgrp */
472 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
473 "ProxyJoin but port not in partition. stored:"
474 "0x%016" PRIx64 " request:0x%016" PRIx64 "\n",
475 cl_ntoh64((*pp_mcm_port)->port_gid.unicast.
477 cl_ntoh64(p_mad_addr->addr_type.gsi.grh_info.
478 src_gid.unicast.interface_id));
485 /**********************************************************************
486 **********************************************************************/
488 * Check legality of the requested MGID DELETE
489 * o15-0.1.14 = VALID DELETE:
490 * To be a valid delete MAD needs to:
491 * 1 the MADs PortGID and MGID components match the PortGID and
492 * MGID of a stored MCMemberRecord;
493 * 2 the MADs JoinState component contains at least one bit set to 1
494 * in the same position as that stored MCMemberRecords JoinState
495 * has a bit set to 1,
496 * i.e., the logical AND of the two JoinState components
498 * 3 the MADs JoinState component does not have some bits set
499 * which are not set in the stored MCMemberRecords JoinState component;
500 * 4 either the stored MCMemberRecord:ProxyJoin is reset (0), and the
501 * MADs source is the stored PortGID;
503 * the stored MCMemberRecord:ProxyJoin is set (1), (see o15-
504 * 0.1.2:); and the MADs source is a member of the partition indicated
505 * by the stored MCMemberRecord:P_Key.
508 __validate_delete(IN osm_sa_t * sa,
509 IN osm_mgrp_t * p_mgrp,
510 IN osm_mad_addr_t * p_mad_addr,
511 IN ib_member_rec_t * p_recvd_mcmember_rec,
512 OUT osm_mcm_port_t ** pp_mcm_port)
516 portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id;
521 if (!osm_mgrp_is_port_present(p_mgrp, portguid, pp_mcm_port)) {
522 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
523 "Failed to find the port in the MC group\n");
528 if (!(p_recvd_mcmember_rec->scope_state & 0x0F &
529 (*pp_mcm_port)->scope_state)) {
530 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
531 "Could not find any matching bits in the stored "
532 "and requested JoinStates\n");
537 if (((p_recvd_mcmember_rec->scope_state & 0x0F) |
538 (0x0F & (*pp_mcm_port)->scope_state)) !=
539 (0x0F & (*pp_mcm_port)->scope_state)) {
540 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
541 "Some bits in the request JoinState (0x%X) are not "
542 "set in the stored port (0x%X)\n",
543 (p_recvd_mcmember_rec->scope_state & 0x0F),
544 (0x0F & (*pp_mcm_port)->scope_state));
549 /* Validate according the the proxy_join (o15-0.1.2) */
550 if (__validate_modify(sa, p_mgrp, p_mad_addr, p_recvd_mcmember_rec,
551 pp_mcm_port) == FALSE) {
552 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
553 "proxy_join validation failure\n");
559 /**********************************************************************
560 **********************************************************************/
562 * Check legality of the requested MGID (note this does not hold for SA
565 * Implementing o15-0.1.5:
566 * A multicast GID is considered to be invalid if:
567 * 1. It does not comply with the rules as specified in 4.1.1 "GID Usage and
568 * Properties" on page 145:
570 * 14) The multicast GID format is (bytes are comma sep):
571 * 0xff,<Fl><Sc>,<Si>,<Si>,<P>,<P>,<P>,<P>,<P>,<P>,<P>,<P>,<Id>,<Id>,<Id>,<Id>
572 * Fl 4bit = Flags (b)
573 * Sc 4bit = Scope (c)
574 * Si 16bit = Signature (2)
575 * P 64bit = GID Prefix (should be a subnet unique ID - normally Subnet Prefix)
576 * Id 32bit = Unique ID in the Subnet (might be MLID or Pkey ?)
578 * a) 8-bits of 11111111 at the start of the GID identifies this as being a
580 * b) Flags is a set of four 1-bit flags: 000T with three flags reserved
581 * and defined as zero (0). The T flag is defined as follows:
582 * i) T = 0 indicates this is a permanently assigned (i.e. wellknown)
583 * multicast GID. See RFC 2373 and RFC 2375 as reference
584 * for these permanently assigned GIDs.
585 * ii) T = 1 indicates this is a non-permanently assigned (i.e. transient)
587 * c) Scope is a 4-bit multicast scope value used to limit the scope of
588 * the multicast group. The following table defines scope value and
591 * Multicast Address Scope Values:
594 * 0x8 Organization-local
597 * 2. It contains the SA-specific signature of 0xA01B and has the link-local
598 * scope bits set. (EZ: the idea here is that SA created MGIDs are the
599 * only source for this signature with link-local scope)
601 static ib_api_status_t
602 __validate_requested_mgid(IN osm_sa_t * sa,
603 IN const ib_member_rec_t * p_mcm_rec)
606 boolean_t valid = TRUE;
608 OSM_LOG_ENTER(sa->p_log);
610 /* 14-a: mcast GID must start with 0xFF */
611 if (p_mcm_rec->mgid.multicast.header[0] != 0xFF) {
612 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B01: "
613 "Wrong MGID Prefix 0x%02X must be 0xFF\n",
614 cl_ntoh16(p_mcm_rec->mgid.multicast.header[0]));
619 /* the MGID signature can mark IPoIB or SA assigned MGIDs */
620 memcpy(&signature, &(p_mcm_rec->mgid.multicast.raw_group_id),
622 signature = cl_ntoh16(signature);
623 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
624 "MGID Signed as 0x%04X\n", signature);
627 * We skip any checks for MGIDs that follow IPoIB
628 * GID structure as defined by the IETF ipoib-link-multicast.
630 * For IPv4 over IB, the signature will be "0x401B".
632 * | 8 | 4 | 4 | 16 bits | 16 bits | 48 bits | 32 bits |
633 * +--------+----+----+-----------------+---------+----------+---------+
634 * |11111111|0001|scop|<IPoIB signature>|< P_Key >|00.......0|<all 1's>|
635 * +--------+----+----+-----------------+---------+----------+---------+
637 * For IPv6 over IB, the signature will be "0x601B".
639 * | 8 | 4 | 4 | 16 bits | 16 bits | 80 bits |
640 * +--------+----+----+-----------------+---------+--------------------+
641 * |11111111|0001|scop|<IPoIB signature>|< P_Key >|000.............0001|
642 * +--------+----+----+-----------------+---------+--------------------+
645 if (signature == 0x401B || signature == 0x601B) {
646 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
647 "Skipping MGID Validation for IPoIB Signed (0x%04X) MGIDs\n",
652 /* 14-b: the 3 upper bits in the "flags" should be zero: */
653 if (p_mcm_rec->mgid.multicast.header[1] & 0xE0) {
654 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B28: "
655 "MGID uses Reserved Flags: flags=0x%X\n",
656 (p_mcm_rec->mgid.multicast.header[1] & 0xE0) >> 4);
661 /* 2 - now what if the link local format 0xA01B is used -
662 the scope should not be link local */
663 if (signature == 0xA01B &&
664 (p_mcm_rec->mgid.multicast.header[1] & 0x0F) ==
665 IB_MC_SCOPE_LINK_LOCAL) {
666 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B24: "
667 "MGID uses 0xA01B signature but with link-local scope\n");
673 * For SA assigned MGIDs (signature 0xA01B):
674 * There is no real way to make sure the Unique MGID Prefix is really unique.
675 * If we could enforce using the Subnet Prefix for that purpose it would
676 * have been nice. But the spec does not require it.
680 OSM_LOG_EXIT(sa->p_log);
684 /**********************************************************************
685 Check if the requested new MC group parameters are realizable.
686 Also set the default MTU and Rate if not provided by the user.
687 **********************************************************************/
689 __mgrp_request_is_realizable(IN osm_sa_t * sa,
690 IN ib_net64_t comp_mask,
691 IN ib_member_rec_t * p_mcm_rec,
692 IN const osm_physp_t * const p_physp)
694 uint8_t mtu_sel = 2; /* exactly */
695 uint8_t mtu_required, mtu, port_mtu;
696 uint8_t rate_sel = 2; /* exactly */
697 uint8_t rate_required, rate, port_rate;
698 osm_log_t *p_log = sa->p_log;
700 OSM_LOG_ENTER(sa->p_log);
703 * End of o15-0.2.3 specifies:
705 * The entity may also supply the other components such as HopLimit,
706 * MTU, etc. during group creation time. If these components are not
707 * provided during group creation time, SA will provide them for the
708 * group. The values chosen are vendor-dependent and beyond the scope
709 * of the specification.
711 * so we might also need to assign RATE/MTU if they are not comp
715 port_mtu = p_physp ? ib_port_info_get_mtu_cap(&p_physp->port_info) : 0;
716 if (!(comp_mask & IB_MCR_COMPMASK_MTU) ||
717 !(comp_mask & IB_MCR_COMPMASK_MTU_SEL) ||
718 (mtu_sel = (p_mcm_rec->mtu >> 6)) == 3)
719 mtu = port_mtu ? port_mtu : sa->p_subn->min_ca_mtu;
721 mtu_required = (uint8_t) (p_mcm_rec->mtu & 0x3F);
724 case 0: /* Greater than MTU specified */
725 if (port_mtu && mtu_required >= port_mtu) {
726 OSM_LOG(p_log, OSM_LOG_DEBUG,
727 "Requested MTU %x >= the port\'s mtu:%x\n",
728 mtu_required, port_mtu);
731 /* we provide the largest MTU possible if we can */
734 else if (mtu_required < sa->p_subn->min_ca_mtu)
735 mtu = sa->p_subn->min_ca_mtu;
739 case 1: /* Less than MTU specified */
740 /* use the smaller of the two:
741 a. one lower then the required
742 b. the mtu of the requesting port (if exists) */
743 if (port_mtu && mtu_required > port_mtu)
748 case 2: /* Exactly MTU specified */
752 /* make sure it still be in the range */
753 if (mtu < IB_MIN_MTU || mtu > IB_MAX_MTU) {
754 OSM_LOG(p_log, OSM_LOG_DEBUG,
755 "Calculated MTU %x is out of range\n", mtu);
759 p_mcm_rec->mtu = (mtu_sel << 6) | mtu;
762 p_physp ? ib_port_info_compute_rate(&p_physp->port_info) : 0;
763 if (!(comp_mask & IB_MCR_COMPMASK_RATE)
764 || !(comp_mask & IB_MCR_COMPMASK_RATE_SEL)
765 || (rate_sel = (p_mcm_rec->rate >> 6)) == 3)
766 rate = port_rate ? port_rate : sa->p_subn->min_ca_rate;
768 rate_required = (uint8_t) (p_mcm_rec->rate & 0x3F);
769 rate = rate_required;
771 case 0: /* Greater than RATE specified */
772 if (port_rate && rate_required >= port_rate) {
773 OSM_LOG(p_log, OSM_LOG_DEBUG,
774 "Requested RATE %x >= the port\'s rate:%x\n",
775 rate_required, port_rate);
778 /* we provide the largest RATE possible if we can */
781 else if (rate_required < sa->p_subn->min_ca_rate)
782 rate = sa->p_subn->min_ca_rate;
786 case 1: /* Less than RATE specified */
787 /* use the smaller of the two:
788 a. one lower then the required
789 b. the rate of the requesting port (if exists) */
790 if (port_rate && rate_required > port_rate)
795 case 2: /* Exactly RATE specified */
799 /* make sure it still is in the range */
800 if (rate < IB_MIN_RATE || rate > IB_MAX_RATE) {
801 OSM_LOG(p_log, OSM_LOG_DEBUG,
802 "Calculated RATE %x is out of range\n", rate);
806 p_mcm_rec->rate = (rate_sel << 6) | rate;
808 OSM_LOG_EXIT(sa->p_log);
812 /**********************************************************************
813 Call this function to create a new mgrp.
814 **********************************************************************/
816 osm_mcmr_rcv_create_new_mgrp(IN osm_sa_t * sa,
817 IN ib_net64_t comp_mask,
818 IN const ib_member_rec_t *
819 const p_recvd_mcmember_rec,
820 IN const osm_physp_t * const p_physp,
821 OUT osm_mgrp_t ** pp_mgrp)
824 unsigned zero_mgid, i;
827 osm_mgrp_t *p_prev_mgrp;
828 ib_api_status_t status = IB_SUCCESS;
829 ib_member_rec_t mcm_rec = *p_recvd_mcmember_rec; /* copy for modifications */
831 OSM_LOG_ENTER(sa->p_log);
833 /* but what if the given MGID was not 0 ? */
835 for (i = 0; i < sizeof(p_recvd_mcmember_rec->mgid); i++)
836 if (p_recvd_mcmember_rec->mgid.raw[i] != 0) {
842 we allocate a new mlid number before we might use it
845 mlid = __get_new_mlid(sa, mcm_rec.mlid);
847 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B19: "
848 "__get_new_mlid failed request mlid 0x%04x\n", cl_ntoh16(mcm_rec.mlid));
849 status = IB_SA_MAD_STATUS_NO_RESOURCES;
853 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
854 "Obtained new mlid 0x%X\n", cl_ntoh16(mlid));
856 /* we need to create the new MGID if it was not defined */
858 /* create a new MGID */
859 char gid_str[INET6_ADDRSTRLEN];
861 /* use the given scope state only if requested! */
862 if (comp_mask & IB_MCR_COMPMASK_SCOPE)
863 ib_member_get_scope_state(p_recvd_mcmember_rec->
864 scope_state, &scope, NULL);
866 /* to guarantee no collision with other subnets use local scope! */
867 scope = IB_MC_SCOPE_LINK_LOCAL;
869 p_mgid = &(mcm_rec.mgid);
870 p_mgid->raw[0] = 0xFF;
871 p_mgid->raw[1] = 0x10 | scope;
872 p_mgid->raw[2] = 0xA0;
873 p_mgid->raw[3] = 0x1B;
875 /* HACK: use the SA port gid to make it globally unique */
876 memcpy((&p_mgid->raw[4]),
877 &sa->p_subn->opt.subnet_prefix, sizeof(uint64_t));
879 /* HACK: how do we get a unique number - use the mlid twice */
880 memcpy(&p_mgid->raw[10], &mlid, sizeof(uint16_t));
881 memcpy(&p_mgid->raw[12], &mlid, sizeof(uint16_t));
882 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Allocated new MGID:%s\n",
883 inet_ntop(AF_INET6, p_mgid->raw, gid_str,
885 } else if (!__validate_requested_mgid(sa, &mcm_rec)) {
886 /* a specific MGID was requested so validate the resulting MGID */
887 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B22: "
888 "Invalid requested MGID\n");
889 __free_mlid(sa, mlid);
890 status = IB_SA_MAD_STATUS_REQ_INVALID;
894 /* check the requested parameters are realizable */
895 if (__mgrp_request_is_realizable(sa, comp_mask, &mcm_rec, p_physp) ==
897 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B26: "
898 "Requested MGRP parameters are not realizable\n");
899 __free_mlid(sa, mlid);
900 status = IB_SA_MAD_STATUS_REQ_INVALID;
904 /* create a new MC Group */
905 *pp_mgrp = osm_mgrp_new(mlid);
906 if (*pp_mgrp == NULL) {
907 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B08: "
908 "osm_mgrp_new failed\n");
909 __free_mlid(sa, mlid);
910 status = IB_SA_MAD_STATUS_NO_RESOURCES;
914 /* Initialize the mgrp */
915 (*pp_mgrp)->mcmember_rec = mcm_rec;
916 (*pp_mgrp)->mcmember_rec.mlid = mlid;
918 /* the mcmember_record should have mtu_sel, rate_sel, and pkt_lifetime_sel = 2 */
919 (*pp_mgrp)->mcmember_rec.mtu &= 0x3f;
920 (*pp_mgrp)->mcmember_rec.mtu |= 2 << 6; /* exactly */
921 (*pp_mgrp)->mcmember_rec.rate &= 0x3f;
922 (*pp_mgrp)->mcmember_rec.rate |= 2 << 6; /* exactly */
923 (*pp_mgrp)->mcmember_rec.pkt_life &= 0x3f;
924 (*pp_mgrp)->mcmember_rec.pkt_life |= 2 << 6; /* exactly */
926 /* Insert the new group in the data base */
928 /* since we might have an old group by that mlid
929 one whose deletion was delayed for an idle time
930 we need to deallocate it first */
931 p_prev_mgrp = osm_get_mgrp_by_mlid(sa->p_subn, mlid);
933 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
934 "Found previous group for mlid:0x%04x - "
935 "Destroying it first\n",
937 sa->p_subn->mgroups[cl_ntoh16(mlid) - IB_LID_MCAST_START_HO] = NULL;
938 osm_mgrp_delete(p_prev_mgrp);
941 sa->p_subn->mgroups[cl_ntoh16(mlid) - IB_LID_MCAST_START_HO] = *pp_mgrp;
944 OSM_LOG_EXIT(sa->p_log);
948 /**********************************************************************
949 *********************************************************************/
950 static unsigned match_mgrp_by_mgid(IN osm_mgrp_t * const p_mgrp, ib_gid_t *mgid)
952 /* ignore groups marked for deletion */
953 if (p_mgrp->to_be_deleted ||
954 memcmp(&p_mgrp->mcmember_rec.mgid, mgid, sizeof(ib_gid_t)))
960 /**********************************************************************
961 **********************************************************************/
962 #define PREFIX_MASK CL_HTON64(0xff10ffff0000ffffULL)
963 #define PREFIX_SIGNATURE CL_HTON64(0xff10601b00000000ULL)
964 #define INT_ID_MASK CL_HTON64(0xfffffff1ff000000ULL)
965 #define INT_ID_SIGNATURE CL_HTON64(0x00000001ff000000ULL)
967 /* Special Case IPv6 Solicited Node Multicast (SNM) addresses */
968 /* 0xff1Z601bXXXX0000 : 0x00000001ffYYYYYY */
969 /* Where Z is the scope, XXXX is the P_Key, and
970 * YYYYYY is the last 24 bits of the port guid */
971 static unsigned match_and_update_ipv6_snm_mgid(ib_gid_t *mgid)
973 if ((mgid->unicast.prefix & PREFIX_MASK) == PREFIX_SIGNATURE &&
974 (mgid->unicast.interface_id & INT_ID_MASK) == INT_ID_SIGNATURE) {
975 mgid->unicast.prefix &= PREFIX_MASK;
976 mgid->unicast.interface_id &= INT_ID_MASK;
982 osm_mgrp_t *osm_get_mgrp_by_mgid(IN osm_sa_t *sa, IN ib_gid_t *p_mgid)
986 if (sa->p_subn->opt.consolidate_ipv6_snm_req &&
987 match_and_update_ipv6_snm_mgid(p_mgid)) {
988 char gid_str[INET6_ADDRSTRLEN];
989 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
990 "Special Case Solicited Node Mcast Join for MGID %s\n",
991 inet_ntop(AF_INET6, p_mgid->raw, gid_str,
995 for (i = 0; i <= sa->p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO;
997 if (sa->p_subn->mgroups[i] &&
998 match_mgrp_by_mgid(sa->p_subn->mgroups[i], p_mgid))
999 return sa->p_subn->mgroups[i];
1004 /**********************************************************************
1005 Call this function to find or create a new mgrp.
1006 **********************************************************************/
1008 osm_mcmr_rcv_find_or_create_new_mgrp(IN osm_sa_t * sa,
1009 IN ib_net64_t comp_mask,
1010 IN ib_member_rec_t *
1011 const p_recvd_mcmember_rec,
1012 OUT osm_mgrp_t ** pp_mgrp)
1016 if ((mgrp = osm_get_mgrp_by_mgid(sa, &p_recvd_mcmember_rec->mgid))) {
1020 return osm_mcmr_rcv_create_new_mgrp(sa, comp_mask,
1021 p_recvd_mcmember_rec, NULL,
1025 /*********************************************************************
1026 Process a request for leaving the group
1027 **********************************************************************/
1029 __osm_mcmr_rcv_leave_mgrp(IN osm_sa_t * sa,
1030 IN osm_madw_t * const p_madw)
1033 ib_sa_mad_t *p_sa_mad;
1034 ib_member_rec_t *p_recvd_mcmember_rec;
1035 ib_member_rec_t mcmember_rec;
1037 ib_net64_t portguid;
1038 osm_mcm_port_t *p_mcm_port;
1041 OSM_LOG_ENTER(sa->p_log);
1043 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1044 p_recvd_mcmember_rec =
1045 (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
1047 mcmember_rec = *p_recvd_mcmember_rec;
1049 if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) {
1050 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Dump of record\n");
1051 osm_dump_mc_record(sa->p_log, &mcmember_rec, OSM_LOG_DEBUG);
1054 CL_PLOCK_EXCL_ACQUIRE(sa->p_lock);
1055 p_mgrp = osm_get_mgrp_by_mgid(sa, &p_recvd_mcmember_rec->mgid);
1057 char gid_str[INET6_ADDRSTRLEN];
1058 CL_PLOCK_RELEASE(sa->p_lock);
1059 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1060 "Failed since multicast group %s not present\n",
1061 inet_ntop(AF_INET6, p_recvd_mcmember_rec->mgid.raw,
1062 gid_str, sizeof gid_str));
1063 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1067 mlid = p_mgrp->mlid;
1068 portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id;
1070 /* check validity of the delete request o15-0.1.14 */
1071 if (!__validate_delete(sa, p_mgrp, osm_madw_get_mad_addr_ptr(p_madw),
1072 p_recvd_mcmember_rec, &p_mcm_port)) {
1073 char gid_str[INET6_ADDRSTRLEN];
1074 char gid_str2[INET6_ADDRSTRLEN];
1075 CL_PLOCK_RELEASE(sa->p_lock);
1076 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B25: "
1077 "Received an invalid delete request for "
1078 "MGID: %s for PortGID: %s\n",
1079 inet_ntop(AF_INET6, p_recvd_mcmember_rec->mgid.raw,
1080 gid_str, sizeof gid_str),
1081 inet_ntop(AF_INET6, p_recvd_mcmember_rec->port_gid.raw,
1082 gid_str2, sizeof gid_str2));
1083 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1087 /* store state - we'll need it if the port is removed */
1088 mcmember_rec.scope_state = p_mcm_port->scope_state;
1090 /* remove port or update join state */
1091 removed = osm_mgrp_remove_port(sa->p_subn, sa->p_log, p_mgrp, p_mcm_port,
1092 p_recvd_mcmember_rec->scope_state&0x0F);
1094 mcmember_rec.scope_state = p_mcm_port->scope_state;
1096 CL_PLOCK_RELEASE(sa->p_lock);
1098 /* we can leave if port was deleted from MCG */
1099 if (removed && osm_sm_mcgrp_leave(sa->sm, mlid, portguid))
1100 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B09: "
1101 "osm_sm_mcgrp_leave failed\n");
1103 /* Send an SA response */
1104 __osm_mcmr_rcv_respond(sa, p_madw, &mcmember_rec);
1107 OSM_LOG_EXIT(sa->p_log);
1110 /**********************************************************************
1111 Handle a join (or create) request
1112 **********************************************************************/
1114 __osm_mcmr_rcv_join_mgrp(IN osm_sa_t * sa, IN osm_madw_t * const p_madw)
1116 osm_mgrp_t *p_mgrp = NULL;
1117 ib_api_status_t status;
1118 ib_sa_mad_t *p_sa_mad;
1119 ib_member_rec_t *p_recvd_mcmember_rec;
1120 ib_member_rec_t mcmember_rec;
1122 osm_mcm_port_t *p_mcmr_port;
1123 ib_net64_t portguid;
1125 osm_physp_t *p_physp;
1126 osm_physp_t *p_request_physp;
1127 uint8_t is_new_group; /* TRUE = there is a need to create a group */
1128 osm_mcast_req_type_t req_type;
1131 OSM_LOG_ENTER(sa->p_log);
1133 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1134 p_recvd_mcmember_rec = ib_sa_mad_get_payload_ptr(p_sa_mad);
1136 portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id;
1138 mcmember_rec = *p_recvd_mcmember_rec;
1140 if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG)) {
1141 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Dump of incoming record\n");
1142 osm_dump_mc_record(sa->p_log, &mcmember_rec, OSM_LOG_DEBUG);
1145 CL_PLOCK_EXCL_ACQUIRE(sa->p_lock);
1147 /* make sure the requested port guid is known to the SM */
1148 p_port = osm_get_port_by_guid(sa->p_subn, portguid);
1150 CL_PLOCK_RELEASE(sa->p_lock);
1152 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1153 "Unknown port GUID 0x%016" PRIx64 "\n",
1154 cl_ntoh64(portguid));
1155 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1159 p_physp = p_port->p_physp;
1160 /* Check that the p_physp and the requester physp are in the same
1163 osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
1164 osm_madw_get_mad_addr_ptr(p_madw));
1165 if (p_request_physp == NULL) {
1166 CL_PLOCK_RELEASE(sa->p_lock);
1170 if (!osm_physp_share_pkey(sa->p_log, p_physp, p_request_physp)) {
1171 CL_PLOCK_RELEASE(sa->p_lock);
1173 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1174 "Port and requester don't share pkey\n");
1175 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1179 ib_member_get_scope_state(p_recvd_mcmember_rec->scope_state, NULL,
1182 /* do we need to create a new group? */
1183 p_mgrp = osm_get_mgrp_by_mgid(sa, &p_recvd_mcmember_rec->mgid);
1184 if (!p_mgrp || p_mgrp->to_be_deleted) {
1185 /* check for JoinState.FullMember = 1 o15.0.1.9 */
1186 if ((join_state & 0x01) != 0x01) {
1187 char gid_str[INET6_ADDRSTRLEN];
1188 CL_PLOCK_RELEASE(sa->p_lock);
1189 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B10: "
1190 "Provided Join State != FullMember - "
1191 "required for create, "
1192 "MGID: %s from port 0x%016" PRIx64 " (%s)\n",
1194 p_recvd_mcmember_rec->mgid.raw,
1195 gid_str, sizeof gid_str),
1196 cl_ntoh64(portguid),
1197 p_port->p_node->print_desc);
1198 osm_sa_send_error(sa, p_madw,
1199 IB_SA_MAD_STATUS_REQ_INVALID);
1203 /* check the comp_mask */
1204 if (!__check_create_comp_mask(p_sa_mad->comp_mask,
1205 p_recvd_mcmember_rec)) {
1206 char gid_str[INET6_ADDRSTRLEN];
1207 CL_PLOCK_RELEASE(sa->p_lock);
1209 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B11: "
1210 "method = %s, scope_state = 0x%x, "
1211 "component mask = 0x%016" PRIx64 ", "
1212 "expected comp mask = 0x%016" PRIx64 ", "
1213 "MGID: %s from port 0x%016" PRIx64 " (%s)\n",
1214 ib_get_sa_method_str(p_sa_mad->method),
1215 p_recvd_mcmember_rec->scope_state,
1216 cl_ntoh64(p_sa_mad->comp_mask),
1217 CL_NTOH64(REQUIRED_MC_CREATE_COMP_MASK),
1219 p_recvd_mcmember_rec->mgid.raw,
1220 gid_str, sizeof gid_str),
1221 cl_ntoh64(portguid),
1222 p_port->p_node->print_desc);
1224 osm_sa_send_error(sa, p_madw,
1225 IB_SA_MAD_STATUS_INSUF_COMPS);
1229 status = osm_mcmr_rcv_create_new_mgrp(sa, p_sa_mad->comp_mask,
1230 p_recvd_mcmember_rec,
1232 if (status != IB_SUCCESS) {
1233 CL_PLOCK_RELEASE(sa->p_lock);
1234 osm_sa_send_error(sa, p_madw, status);
1237 /* copy the MGID to the result */
1238 mcmember_rec.mgid = p_mgrp->mcmember_rec.mgid;
1240 req_type = OSM_MCAST_REQ_TYPE_CREATE;
1242 /* no need for a new group */
1244 req_type = OSM_MCAST_REQ_TYPE_JOIN;
1248 mlid = p_mgrp->mlid;
1251 * o15-0.2.4: If SA supports UD multicast, then SA shall cause an
1252 * endport to join an existing multicast group if:
1253 * 1. It receives a SubnAdmSet() method for a MCMemberRecord, and
1254 * - WE KNOW THAT ALREADY
1255 * 2. The MGID is specified and matches an existing multicast
1257 * - WE KNOW THAT ALREADY
1258 * 3. The MCMemberRecord:JoinState is not all 0s, and
1259 * 4. PortGID is specified and
1260 * - WE KNOW THAT ALREADY (as it matched a real one)
1261 * 5. All other components match that existing group, either by
1262 * being wildcarded or by having values identical to those specified
1263 * by the component mask and in use by the group with the exception
1264 * of components such as ProxyJoin and Reserved, which are ignored
1267 * We need to check #3 and #5 here:
1269 if (!__validate_more_comp_fields(sa->p_log, p_mgrp,
1270 p_recvd_mcmember_rec,
1271 p_sa_mad->comp_mask)
1272 || !__validate_port_caps(sa->p_log, p_mgrp, p_physp)
1273 || !(join_state != 0)) {
1274 /* since we might have created the new group we need to cleanup */
1275 __cleanup_mgrp(sa, p_mgrp);
1277 CL_PLOCK_RELEASE(sa->p_lock);
1279 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B12: "
1280 "__validate_more_comp_fields, __validate_port_caps, "
1281 "or JoinState = 0 failed from port 0x%016" PRIx64
1282 " (%s), " "sending IB_SA_MAD_STATUS_REQ_INVALID\n",
1283 cl_ntoh64(portguid), p_port->p_node->print_desc);
1285 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1290 * o15-0.2.1 requires validation of the requesting port
1291 * in the case of modification:
1293 if (!is_new_group &&
1294 !__validate_modify(sa, p_mgrp, osm_madw_get_mad_addr_ptr(p_madw),
1295 p_recvd_mcmember_rec, &p_mcmr_port)) {
1296 CL_PLOCK_RELEASE(sa->p_lock);
1298 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B13: "
1299 "__validate_modify failed from port 0x%016" PRIx64
1300 " (%s), sending IB_SA_MAD_STATUS_REQ_INVALID\n",
1301 cl_ntoh64(portguid), p_port->p_node->print_desc);
1303 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1307 /* create or update existing port (join-state will be updated) */
1308 status = __add_new_mgrp_port(sa, p_mgrp, p_recvd_mcmember_rec,
1309 osm_madw_get_mad_addr_ptr(p_madw),
1312 if (status != IB_SUCCESS) {
1313 /* we fail to add the port so we might need to delete the group */
1314 __cleanup_mgrp(sa, p_mgrp);
1316 CL_PLOCK_RELEASE(sa->p_lock);
1318 osm_sa_send_error(sa, p_madw, status == IB_INVALID_PARAMETER ?
1319 IB_SA_MAD_STATUS_REQ_INVALID :
1320 IB_SA_MAD_STATUS_NO_RESOURCES);
1324 /* o15.0.1.11: copy the join state */
1325 mcmember_rec.scope_state = p_mcmr_port->scope_state;
1327 /* copy qkey mlid tclass pkey sl_flow_hop mtu rate pkt_life sl_flow_hop */
1328 __copy_from_create_mc_rec(&mcmember_rec, &p_mgrp->mcmember_rec);
1330 /* Release the lock as we don't need it. */
1331 CL_PLOCK_RELEASE(sa->p_lock);
1333 /* do the actual routing (actually schedule the update) */
1334 status = osm_sm_mcgrp_join(sa->sm, mlid,
1335 p_recvd_mcmember_rec->port_gid.unicast.
1336 interface_id, req_type);
1338 if (status != IB_SUCCESS) {
1339 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B14: "
1340 "osm_sm_mcgrp_join failed from port 0x%016" PRIx64
1341 " (%s), " "sending IB_SA_MAD_STATUS_NO_RESOURCES\n",
1342 cl_ntoh64(portguid), p_port->p_node->print_desc);
1344 CL_PLOCK_EXCL_ACQUIRE(sa->p_lock);
1346 /* the request for routing failed so we need to remove the port */
1347 osm_mgrp_delete_port(sa->p_subn, sa->p_log, p_mgrp,
1348 p_recvd_mcmember_rec->port_gid.
1349 unicast.interface_id);
1350 __cleanup_mgrp(sa, p_mgrp);
1351 CL_PLOCK_RELEASE(sa->p_lock);
1352 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES);
1356 /* failed to route */
1357 if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG))
1358 osm_dump_mc_record(sa->p_log, &mcmember_rec, OSM_LOG_DEBUG);
1360 __osm_mcmr_rcv_respond(sa, p_madw, &mcmember_rec);
1363 OSM_LOG_EXIT(sa->p_log);
1366 /**********************************************************************
1367 Add a patched multicast group to the results list
1368 **********************************************************************/
1369 static ib_api_status_t
1370 __osm_mcmr_rcv_new_mcmr(IN osm_sa_t * sa,
1371 IN const ib_member_rec_t * p_rcvd_rec,
1372 IN cl_qlist_t * const p_list)
1374 osm_mcmr_item_t *p_rec_item;
1375 ib_api_status_t status = IB_SUCCESS;
1377 OSM_LOG_ENTER(sa->p_log);
1379 p_rec_item = malloc(sizeof(*p_rec_item));
1380 if (p_rec_item == NULL) {
1381 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B15: "
1382 "rec_item alloc failed\n");
1383 status = IB_INSUFFICIENT_RESOURCES;
1387 memset(p_rec_item, 0, sizeof(*p_rec_item));
1389 /* HACK: Untrusted requesters should result with 0 Join
1390 State, Port Guid, and Proxy */
1391 p_rec_item->rec = *p_rcvd_rec;
1392 cl_qlist_insert_tail(p_list, &p_rec_item->list_item);
1395 OSM_LOG_EXIT(sa->p_log);
1399 /**********************************************************************
1400 Match the given mgrp to the requested mcmr
1401 **********************************************************************/
1402 static void mcmr_by_comp_mask(osm_sa_t *sa, const ib_member_rec_t *p_rcvd_rec,
1403 ib_net64_t comp_mask, osm_mgrp_t *p_mgrp,
1404 const osm_physp_t *p_req_physp,
1405 boolean_t trusted_req, cl_qlist_t *list)
1407 /* since we might change scope_state */
1408 ib_member_rec_t match_rec;
1409 osm_mcm_port_t *p_mcm_port;
1410 ib_net64_t portguid = p_rcvd_rec->port_gid.unicast.interface_id;
1411 /* will be used for group or port info */
1412 uint8_t scope_state;
1413 uint8_t scope_state_mask = 0;
1414 cl_map_item_t *p_item;
1416 boolean_t proxy_join = FALSE;
1418 OSM_LOG_ENTER(sa->p_log);
1420 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1421 "Checking mlid:0x%X\n", cl_ntoh16(p_mgrp->mlid));
1423 /* the group might be marked for deletion */
1424 if (p_mgrp->to_be_deleted) {
1425 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1426 "Group mlid:0x%X is marked to be deleted\n",
1427 cl_ntoh16(p_mgrp->mlid));
1431 /* first try to eliminate the group by MGID, MLID, or P_Key */
1432 if ((IB_MCR_COMPMASK_MGID & comp_mask) &&
1433 memcmp(&p_rcvd_rec->mgid, &p_mgrp->mcmember_rec.mgid,
1437 if ((IB_MCR_COMPMASK_MLID & comp_mask) &&
1438 memcmp(&p_rcvd_rec->mlid, &p_mgrp->mcmember_rec.mlid,
1442 /* if the requester physical port doesn't have the pkey that is defined
1443 for the group - exit. */
1444 if (!osm_physp_has_pkey(sa->p_log, p_mgrp->mcmember_rec.pkey,
1448 /* now do the rest of the match */
1449 if ((IB_MCR_COMPMASK_QKEY & comp_mask) &&
1450 p_rcvd_rec->qkey != p_mgrp->mcmember_rec.qkey)
1453 if ((IB_MCR_COMPMASK_PKEY & comp_mask) &&
1454 p_rcvd_rec->pkey != p_mgrp->mcmember_rec.pkey)
1457 if ((IB_MCR_COMPMASK_TCLASS & comp_mask) &&
1458 p_rcvd_rec->tclass != p_mgrp->mcmember_rec.tclass)
1461 /* check SL, Flow, and Hop limit */
1463 uint8_t mgrp_sl, query_sl;
1464 uint32_t mgrp_flow, query_flow;
1465 uint8_t mgrp_hop, query_hop;
1467 ib_member_get_sl_flow_hop(p_rcvd_rec->sl_flow_hop,
1468 &query_sl, &query_flow, &query_hop);
1470 ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop,
1471 &mgrp_sl, &mgrp_flow, &mgrp_hop);
1473 if ((IB_MCR_COMPMASK_SL & comp_mask) && query_sl != mgrp_sl)
1476 if ((IB_MCR_COMPMASK_FLOW & comp_mask) &&
1477 query_flow != mgrp_flow)
1480 if ((IB_MCR_COMPMASK_HOP & comp_mask) && query_hop != mgrp_hop)
1484 if ((IB_MCR_COMPMASK_PROXY & comp_mask) &&
1485 p_rcvd_rec->proxy_join != p_mgrp->mcmember_rec.proxy_join)
1488 /* need to validate mtu, rate, and pkt_lifetime fields */
1489 if (__validate_more_comp_fields(sa->p_log, p_mgrp, p_rcvd_rec,
1490 comp_mask) == FALSE)
1493 /* Port specific fields */
1494 /* so did we get the PortGUID mask */
1495 if (IB_MCR_COMPMASK_PORT_GID & comp_mask) {
1496 /* try to find this port */
1497 if (osm_mgrp_is_port_present(p_mgrp, portguid, &p_mcm_port)) {
1498 scope_state = p_mcm_port->scope_state;
1499 memcpy(&port_gid, &(p_mcm_port->port_gid),
1501 proxy_join = p_mcm_port->proxy_join;
1503 /* port not in group */
1507 /* point to the group information */
1508 scope_state = p_mgrp->mcmember_rec.scope_state;
1511 if (IB_MCR_COMPMASK_SCOPE & comp_mask)
1512 scope_state_mask = 0xF0;
1514 if (IB_MCR_COMPMASK_JOIN_STATE & comp_mask)
1515 scope_state_mask = scope_state_mask | 0x0F;
1517 /* Many MC records returned */
1518 if (trusted_req == TRUE
1519 && !(IB_MCR_COMPMASK_PORT_GID & comp_mask)) {
1520 char gid_str[INET6_ADDRSTRLEN];
1521 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1522 "Trusted req is TRUE and no specific port defined\n");
1524 /* return all the ports that match in this MC group */
1525 p_item = cl_qmap_head(&(p_mgrp->mcm_port_tbl));
1526 while (p_item != cl_qmap_end(&(p_mgrp->mcm_port_tbl))) {
1527 p_mcm_port = (osm_mcm_port_t *) p_item;
1529 if ((scope_state_mask & p_rcvd_rec->scope_state) ==
1530 (scope_state_mask & p_mcm_port->scope_state)) {
1531 /* add to the list */
1532 match_rec = p_mgrp->mcmember_rec;
1533 match_rec.scope_state = p_mcm_port->scope_state;
1534 memcpy(&(match_rec.port_gid),
1535 &(p_mcm_port->port_gid),
1537 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1538 "Record of port_gid: %s"
1539 " in multicast_lid: 0x%X is returned\n",
1540 inet_ntop(AF_INET6, match_rec.port_gid.raw,
1541 gid_str, sizeof gid_str),
1542 cl_ntoh16(p_mgrp->mlid));
1544 match_rec.proxy_join =
1545 (uint8_t) (p_mcm_port->proxy_join);
1547 __osm_mcmr_rcv_new_mcmr(sa, &match_rec, list);
1549 p_item = cl_qmap_next(p_item);
1552 /* One MC record returned */
1554 if ((scope_state_mask & p_rcvd_rec->scope_state) !=
1555 (scope_state_mask & scope_state))
1558 /* add to the list */
1559 match_rec = p_mgrp->mcmember_rec;
1560 match_rec.scope_state = scope_state;
1561 memcpy(&(match_rec.port_gid), &port_gid, sizeof(ib_gid_t));
1562 match_rec.proxy_join = (uint8_t) proxy_join;
1564 __osm_mcmr_rcv_new_mcmr(sa, &match_rec, list);
1568 OSM_LOG_EXIT(sa->p_log);
1571 /**********************************************************************
1572 Handle a query request
1573 **********************************************************************/
1575 __osm_mcmr_query_mgrp(IN osm_sa_t * sa,
1576 IN osm_madw_t * const p_madw)
1578 const ib_sa_mad_t *p_rcvd_mad;
1579 const ib_member_rec_t *p_rcvd_rec;
1580 cl_qlist_t rec_list;
1581 ib_net64_t comp_mask;
1582 osm_physp_t *p_req_physp;
1583 boolean_t trusted_req;
1587 OSM_LOG_ENTER(sa->p_log);
1589 p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw);
1590 p_rcvd_rec = (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad);
1591 comp_mask = p_rcvd_mad->comp_mask;
1594 if sm_key is not zero and does not match we never get here
1595 see main SA receiver
1597 trusted_req = (p_rcvd_mad->sm_key != 0);
1599 /* update the requester physical port. */
1600 p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
1601 osm_madw_get_mad_addr_ptr
1603 if (p_req_physp == NULL) {
1604 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B04: "
1605 "Cannot find requester physical port\n");
1609 cl_qlist_init(&rec_list);
1611 CL_PLOCK_ACQUIRE(sa->p_lock);
1613 /* simply go over all MCGs and match */
1614 for (i = 0; i <= sa->p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO;
1616 p_mgrp = sa->p_subn->mgroups[i];
1618 mcmr_by_comp_mask(sa, p_rcvd_rec, comp_mask, p_mgrp,
1619 p_req_physp, trusted_req, &rec_list);
1622 CL_PLOCK_RELEASE(sa->p_lock);
1625 p923 - The PortGID, JoinState and ProxyJoin shall be zero,
1626 except in the case of a trusted request.
1627 Note: In the mad controller we check that the SM_Key received on
1628 the mad is valid. Meaning - is either zero or equal to the local
1632 if (!p_rcvd_mad->sm_key) {
1633 osm_mcmr_item_t *item;
1634 for (item = (osm_mcmr_item_t *) cl_qlist_head(&rec_list);
1635 item != (osm_mcmr_item_t *) cl_qlist_end(&rec_list);
1636 item = (osm_mcmr_item_t *)cl_qlist_next(&item->list_item)) {
1637 memset(&item->rec.port_gid, 0, sizeof(ib_gid_t));
1638 ib_member_set_join_state(&item->rec, 0);
1639 item->rec.proxy_join = 0;
1643 osm_sa_respond(sa, p_madw, sizeof(ib_member_rec_t), &rec_list);
1646 OSM_LOG_EXIT(sa->p_log);
1649 /**********************************************************************
1650 **********************************************************************/
1651 void osm_mcmr_rcv_process(IN void *context, IN void *data)
1653 osm_sa_t *sa = context;
1654 osm_madw_t *p_madw = data;
1655 ib_sa_mad_t *p_sa_mad;
1656 ib_member_rec_t *p_recvd_mcmember_rec;
1660 OSM_LOG_ENTER(sa->p_log);
1664 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1665 p_recvd_mcmember_rec =
1666 (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
1668 CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_MCMEMBER_RECORD);
1670 switch (p_sa_mad->method) {
1671 case IB_MAD_METHOD_SET:
1672 if (!__check_join_comp_mask(p_sa_mad->comp_mask)) {
1673 char gid_str[INET6_ADDRSTRLEN];
1674 char gid_str2[INET6_ADDRSTRLEN];
1675 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B18: "
1676 "component mask = 0x%016" PRIx64 ", "
1677 "expected comp mask = 0x%016" PRIx64 ", "
1678 "MGID: %s for PortGID: %s\n",
1679 cl_ntoh64(p_sa_mad->comp_mask),
1680 CL_NTOH64(JOIN_MC_COMP_MASK),
1682 p_recvd_mcmember_rec->mgid.raw,
1683 gid_str, sizeof gid_str),
1685 p_recvd_mcmember_rec->port_gid.raw,
1686 gid_str2, sizeof gid_str2));
1688 osm_sa_send_error(sa, p_madw,
1689 IB_SA_MAD_STATUS_REQ_INVALID);
1694 * Join or Create Multicast Group
1696 __osm_mcmr_rcv_join_mgrp(sa, p_madw);
1698 case IB_MAD_METHOD_DELETE:
1699 if (!__check_join_comp_mask(p_sa_mad->comp_mask)) {
1700 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B20: "
1701 "component mask = 0x%016" PRIx64 ", "
1702 "expected comp mask = 0x%016" PRIx64 "\n",
1703 cl_ntoh64(p_sa_mad->comp_mask),
1704 CL_NTOH64(JOIN_MC_COMP_MASK));
1706 osm_sa_send_error(sa, p_madw,
1707 IB_SA_MAD_STATUS_REQ_INVALID);
1712 * Leave Multicast Group
1714 __osm_mcmr_rcv_leave_mgrp(sa, p_madw);
1716 case IB_MAD_METHOD_GET:
1717 case IB_MAD_METHOD_GETTABLE:
1719 * Querying a Multicast Group
1721 __osm_mcmr_query_mgrp(sa, p_madw);
1724 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B21: "
1725 "Unsupported Method (%s)\n",
1726 ib_get_sa_method_str(p_sa_mad->method));
1727 osm_sa_send_error(sa, p_madw,
1728 IB_MAD_STATUS_UNSUP_METHOD_ATTR);
1733 OSM_LOG_EXIT(sa->p_log);