2 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2015 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.
6 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
8 * This software is available to you under a choice of one of two
9 * licenses. You may choose to be licensed under the terms of the GNU
10 * General Public License (GPL) Version 2, available from the file
11 * COPYING in the main directory of this source tree, or the
12 * OpenIB.org BSD license below:
14 * Redistribution and use in source and binary forms, with or
15 * without modification, are permitted provided that the following
18 * - Redistributions of source code must retain the above
19 * copyright notice, this list of conditions and the following
22 * - Redistributions in binary form must reproduce the above
23 * copyright notice, this list of conditions and the following
24 * disclaimer in the documentation and/or other materials
25 * provided with the distribution.
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40 * Implementation of osm_mcmr_recv_t.
41 * This object represents the MCMemberRecord Receiver object.
42 * This object is part of the opensm family of objects.
47 #endif /* HAVE_CONFIG_H */
51 #include <arpa/inet.h>
52 #include <sys/socket.h>
53 #include <iba/ib_types.h>
54 #include <complib/cl_qmap.h>
55 #include <complib/cl_passivelock.h>
56 #include <complib/cl_debug.h>
57 #include <complib/cl_qlist.h>
58 #include <opensm/osm_file_ids.h>
59 #define FILE_ID OSM_FILE_SA_MCMEMBER_RECORD_C
60 #include <vendor/osm_vendor_api.h>
61 #include <opensm/osm_madw.h>
62 #include <opensm/osm_log.h>
63 #include <opensm/osm_subnet.h>
64 #include <opensm/osm_mad_pool.h>
65 #include <opensm/osm_helper.h>
66 #include <opensm/osm_msgdef.h>
67 #include <opensm/osm_pkey.h>
68 #include <opensm/osm_inform.h>
69 #include <opensm/osm_sa.h>
71 #define SA_MCM_RESP_SIZE SA_ITEM_RESP_SIZE(mc_rec)
73 #define JOIN_MC_COMP_MASK (IB_MCR_COMPMASK_MGID | \
74 IB_MCR_COMPMASK_PORT_GID | \
75 IB_MCR_COMPMASK_JOIN_STATE)
77 #define REQUIRED_MC_CREATE_COMP_MASK (IB_MCR_COMPMASK_MGID | \
78 IB_MCR_COMPMASK_PORT_GID | \
79 IB_MCR_COMPMASK_JOIN_STATE | \
80 IB_MCR_COMPMASK_QKEY | \
81 IB_MCR_COMPMASK_TCLASS | \
82 IB_MCR_COMPMASK_PKEY | \
83 IB_MCR_COMPMASK_FLOW | \
86 #define IPV4_BCAST_MGID_PREFIX CL_HTON64(0xff10401b00000000ULL)
87 #define IPV4_BCAST_MGID_INT_ID CL_HTON64(0x00000000ffffffffULL)
89 static int validate_other_comp_fields(osm_log_t * p_log, ib_net64_t comp_mask,
90 const ib_member_rec_t * p_mcmr,
92 osm_log_level_t log_level);
94 /*********************************************************************
95 Copy certain fields between two mcmember records
96 used during the process of join request to copy data from the mgrp
98 **********************************************************************/
99 static void copy_from_create_mc_rec(IN ib_member_rec_t * dest,
100 IN const ib_member_rec_t * src)
102 dest->qkey = src->qkey;
103 dest->mlid = src->mlid;
104 dest->tclass = src->tclass;
105 dest->pkey = src->pkey;
106 dest->sl_flow_hop = src->sl_flow_hop;
107 dest->scope_state = ib_member_set_scope_state(src->scope_state >> 4,
108 dest->scope_state & 0x0F);
109 dest->mtu = src->mtu;
110 dest->rate = src->rate;
111 dest->pkt_life = src->pkt_life;
114 /*********************************************************************
115 Return mlid to the pool of free mlids.
116 But this implementation is not a pool - it simply scans through
117 the MGRP database for unused mlids...
118 *********************************************************************/
119 static void free_mlid(IN osm_sa_t * sa, IN uint16_t mlid)
125 /*********************************************************************
126 Get a new unused mlid by scanning all the used ones in the subnet.
127 **********************************************************************/
128 /* Special Case IPv6 Solicited Node Multicast (SNM) addresses */
129 /* 0xff1Z601bXXXX0000 : 0x00000001ffYYYYYY */
130 /* Where Z is the scope, XXXX is the P_Key, and
131 * YYYYYY is the last 24 bits of the port guid */
132 #define PREFIX_MASK CL_HTON64(0xff10ffff0000ffffULL)
133 #define PREFIX_SIGNATURE CL_HTON64(0xff10601b00000000ULL)
134 #define INT_ID_MASK CL_HTON64(0xfffffff1ff000000ULL)
135 #define INT_ID_SIGNATURE CL_HTON64(0x00000001ff000000ULL)
137 static int compare_ipv6_snm_mgids(const void *m1, const void *m2)
139 return memcmp(m1, m2, sizeof(ib_gid_t) - 3);
142 static ib_net16_t find_ipv6_snm_mlid(osm_subn_t *subn, ib_gid_t *mgid)
144 osm_mgrp_t *m = (osm_mgrp_t *)cl_fmap_match(&subn->mgrp_mgid_tbl, mgid,
145 compare_ipv6_snm_mgids);
146 if (m != (osm_mgrp_t *)cl_fmap_end(&subn->mgrp_mgid_tbl))
151 static unsigned match_ipv6_snm_mgid(ib_gid_t * mgid)
153 return ((mgid->unicast.prefix & PREFIX_MASK) == PREFIX_SIGNATURE &&
154 (mgid->unicast.interface_id & INT_ID_MASK) == INT_ID_SIGNATURE);
157 static ib_net16_t get_new_mlid(osm_sa_t * sa, ib_member_rec_t * mcmr)
159 osm_subn_t *p_subn = sa->p_subn;
160 ib_net16_t requested_mlid = mcmr->mlid;
163 if (requested_mlid && cl_ntoh16(requested_mlid) >= IB_LID_MCAST_START_HO
164 && cl_ntoh16(requested_mlid) <= p_subn->max_mcast_lid_ho
165 && !osm_get_mbox_by_mlid(p_subn, requested_mlid))
166 return requested_mlid;
168 if (sa->p_subn->opt.consolidate_ipv6_snm_req
169 && match_ipv6_snm_mgid(&mcmr->mgid)
170 && (requested_mlid = find_ipv6_snm_mlid(sa->p_subn, &mcmr->mgid))) {
171 char str[INET6_ADDRSTRLEN];
172 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
173 "Special Case Solicited Node Mcast Join for MGID %s\n",
174 inet_ntop(AF_INET6, mcmr->mgid.raw, str, sizeof(str)));
175 return requested_mlid;
178 max = p_subn->max_mcast_lid_ho - IB_LID_MCAST_START_HO + 1;
179 for (i = 0; i < max; i++)
180 if (!sa->p_subn->mboxes[i])
181 return cl_hton16(i + IB_LID_MCAST_START_HO);
186 static inline boolean_t check_join_comp_mask(ib_net64_t comp_mask)
188 return ((comp_mask & JOIN_MC_COMP_MASK) == JOIN_MC_COMP_MASK);
191 static boolean_t check_create_comp_mask(ib_net64_t comp_mask,
192 ib_member_rec_t * p_recvd_mcmember_rec)
194 return ((comp_mask & REQUIRED_MC_CREATE_COMP_MASK) ==
195 REQUIRED_MC_CREATE_COMP_MASK);
198 /**********************************************************************
199 Generate the response MAD
200 **********************************************************************/
201 static void mcmr_rcv_respond(IN osm_sa_t * sa, IN osm_madw_t * p_madw,
202 IN ib_member_rec_t * p_mcmember_rec)
207 OSM_LOG_ENTER(sa->p_log);
209 item = malloc(SA_MCM_RESP_SIZE);
211 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B16: "
212 "rec_item alloc failed\n");
216 item->resp.mc_rec = *p_mcmember_rec;
218 /* Fill in the mtu, rate, and packet lifetime selectors */
219 item->resp.mc_rec.mtu &= 0x3f;
220 item->resp.mc_rec.mtu |= IB_PATH_SELECTOR_EXACTLY << 6;
221 item->resp.mc_rec.rate &= 0x3f;
222 item->resp.mc_rec.rate |= IB_PATH_SELECTOR_EXACTLY << 6;
223 item->resp.mc_rec.pkt_life &= 0x3f;
224 item->resp.mc_rec.pkt_life |= IB_PATH_SELECTOR_EXACTLY << 6;
226 cl_qlist_init(&rec_list);
227 cl_qlist_insert_tail(&rec_list, &item->list_item);
229 osm_sa_respond(sa, p_madw, sizeof(ib_member_rec_t), &rec_list);
232 OSM_LOG_EXIT(sa->p_log);
235 /*********************************************************************
236 In joining an existing group, or when querying the mc groups,
237 we make sure the following components provided match: MTU and RATE
238 HACK: Currently we ignore the PKT_LIFETIME field.
239 **********************************************************************/
240 static boolean_t validate_more_comp_fields(osm_log_t * p_log,
241 const osm_mgrp_t * p_mgrp,
242 const ib_member_rec_t *
243 p_recvd_mcmember_rec,
244 ib_net64_t comp_mask)
247 uint8_t mtu_required;
250 uint8_t rate_required;
253 if (comp_mask & IB_MCR_COMPMASK_MTU_SEL) {
254 mtu_sel = (uint8_t) (p_recvd_mcmember_rec->mtu >> 6);
255 /* Clearing last 2 bits */
256 mtu_required = (uint8_t) (p_recvd_mcmember_rec->mtu & 0x3F);
257 mtu_mgrp = (uint8_t) (p_mgrp->mcmember_rec.mtu & 0x3F);
259 case 0: /* Greater than MTU specified */
260 if (mtu_mgrp <= mtu_required) {
261 OSM_LOG(p_log, OSM_LOG_VERBOSE,
262 "Requested mcast group has MTU %x, "
263 "which is not greater than %x\n",
264 mtu_mgrp, mtu_required);
268 case 1: /* Less than MTU specified */
269 if (mtu_mgrp >= mtu_required) {
270 OSM_LOG(p_log, OSM_LOG_VERBOSE,
271 "Requested mcast group has MTU %x, "
272 "which is not less than %x\n",
273 mtu_mgrp, mtu_required);
277 case 2: /* Exactly MTU specified */
278 if (mtu_mgrp != mtu_required) {
279 OSM_LOG(p_log, OSM_LOG_VERBOSE,
280 "Requested mcast group has MTU %x, "
281 "which is not equal to %x\n",
282 mtu_mgrp, mtu_required);
291 /* what about rate ? */
292 if (comp_mask & IB_MCR_COMPMASK_RATE_SEL) {
293 rate_sel = (uint8_t) (p_recvd_mcmember_rec->rate >> 6);
294 /* Clearing last 2 bits */
295 rate_required = (uint8_t) (p_recvd_mcmember_rec->rate & 0x3F);
296 rate_mgrp = (uint8_t) (p_mgrp->mcmember_rec.rate & 0x3F);
298 case 0: /* Greater than RATE specified */
299 if (ib_path_compare_rates(rate_mgrp, rate_required) <= 0) {
300 OSM_LOG(p_log, OSM_LOG_VERBOSE,
301 "Requested mcast group has RATE %x, "
302 "which is not greater than %x\n",
303 rate_mgrp, rate_required);
307 case 1: /* Less than RATE specified */
308 if (ib_path_compare_rates(rate_mgrp, rate_required) >= 0) {
309 OSM_LOG(p_log, OSM_LOG_VERBOSE,
310 "Requested mcast group has RATE %x, "
311 "which is not less than %x\n",
312 rate_mgrp, rate_required);
316 case 2: /* Exactly RATE specified */
317 if (ib_path_compare_rates(rate_mgrp, rate_required)) {
318 OSM_LOG(p_log, OSM_LOG_VERBOSE,
319 "Requested mcast group has RATE %x, "
320 "which is not equal to %x\n",
321 rate_mgrp, rate_required);
333 /*********************************************************************
334 In joining an existing group, we make sure the following components
335 are physically realizable: MTU and RATE
336 **********************************************************************/
337 static boolean_t validate_port_caps(osm_log_t * p_log,
338 const osm_mgrp_t * p_mgrp,
339 const osm_physp_t * p_physp)
341 const ib_port_info_t *p_pi;
342 uint8_t mtu_required;
344 uint8_t rate_required;
348 mtu_required = ib_port_info_get_neighbor_mtu(&p_physp->port_info);
349 mtu_mgrp = (uint8_t) (p_mgrp->mcmember_rec.mtu & 0x3F);
350 if (mtu_required < mtu_mgrp) {
351 OSM_LOG(p_log, OSM_LOG_VERBOSE,
352 "Port's MTU %x is less than %x\n",
353 mtu_required, mtu_mgrp);
357 p_pi = &p_physp->port_info;
358 extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
359 rate_required = ib_port_info_compute_rate(p_pi, extended);
360 rate_mgrp = (uint8_t) (p_mgrp->mcmember_rec.rate & 0x3F);
361 if (ib_path_compare_rates(rate_required, rate_mgrp) < 0) {
362 OSM_LOG(p_log, OSM_LOG_VERBOSE,
363 "Port's RATE %x is less than %x\n",
364 rate_required, rate_mgrp);
371 /**********************************************************************
372 * o15-0.2.1: If SA supports UD multicast, then if SA receives a SubnAdmSet()
373 * or SubnAdmDelete() method that would modify an existing
374 * MCMemberRecord, SA shall not modify that MCMemberRecord and shall
375 * return an error status of ERR_REQ_INVALID in response in the
377 * 1. Saved MCMemberRecord.ProxyJoin is not set and the request is
378 * issued by a requester with a GID other than the Port-GID.
379 * 2. Saved MCMemberRecord.ProxyJoin is set and the requester is not
380 * part of the partition for that MCMemberRecord.
381 **********************************************************************/
382 static boolean_t validate_modify(IN osm_sa_t * sa, IN osm_mgrp_t * p_mgrp,
383 IN osm_mad_addr_t * p_mad_addr,
384 IN ib_member_rec_t * p_recvd_mcmember_rec,
385 OUT osm_mcm_alias_guid_t ** pp_mcm_alias_guid)
388 ib_gid_t request_gid;
389 osm_physp_t *p_request_physp;
392 portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id;
394 *pp_mcm_alias_guid = osm_mgrp_get_mcm_alias_guid(p_mgrp, portguid);
396 /* o15-0.2.1: If this is a new port being added - nothing to check */
397 if (!*pp_mcm_alias_guid) {
398 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
399 "This is a new port in the MC group\n");
403 /* We validate the request according the the proxy_join.
404 Check if the proxy_join is set or not */
405 if ((*pp_mcm_alias_guid)->proxy_join == FALSE) {
406 /* The proxy_join is not set. Modifying can by done only
407 if the requester GID == PortGID */
408 res = osm_get_gid_by_mad_addr(sa->p_log, sa->p_subn, p_mad_addr,
410 if (res != IB_SUCCESS) {
411 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
412 "Could not find port for requested address\n");
416 if ((*pp_mcm_alias_guid)->p_base_mcm_port->port->guid !=
417 request_gid.unicast.interface_id ||
418 (*pp_mcm_alias_guid)->port_gid.unicast.prefix !=
419 request_gid.unicast.prefix) {
420 ib_gid_t base_port_gid;
421 char gid_str[INET6_ADDRSTRLEN];
422 char gid_str2[INET6_ADDRSTRLEN];
424 base_port_gid.unicast.prefix = (*pp_mcm_alias_guid)->port_gid.unicast.prefix;
425 base_port_gid.unicast.interface_id = (*pp_mcm_alias_guid)->p_base_mcm_port->port->guid;
426 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
427 "No ProxyJoin but different ports: stored:"
429 inet_ntop(AF_INET6, base_port_gid.raw, gid_str,
431 inet_ntop(AF_INET6, request_gid.raw, gid_str2,
436 /* The proxy_join is set. Modification allowed only if the
437 requester is part of the partition for this MCMemberRecord */
438 p_request_physp = osm_get_physp_by_mad_addr(sa->p_log,
441 if (p_request_physp == NULL)
444 if (!osm_physp_has_pkey(sa->p_log, p_mgrp->mcmember_rec.pkey,
446 /* the request port is not part of the partition for this mgrp */
447 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
448 "Requesting port 0x%016" PRIx64 " has no PKey 0x%04x\n",
449 cl_ntoh64(p_request_physp->port_guid),
450 cl_ntoh16(p_mgrp->mcmember_rec.pkey));
458 * Check legality of the requested MGID DELETE
459 * o15-0.1.14 = VALID DELETE:
460 * To be a valid delete MAD needs to:
461 * 1 the MADs PortGID and MGID components match the PortGID and
462 * MGID of a stored MCMemberRecord;
463 * 2 the MADs JoinState component contains at least one bit set to 1
464 * in the same position as that stored MCMemberRecords JoinState
465 * has a bit set to 1,
466 * i.e., the logical AND of the two JoinState components
468 * 3 the MADs JoinState component does not have some bits set
469 * which are not set in the stored MCMemberRecords JoinState component;
470 * 4 either the stored MCMemberRecord:ProxyJoin is reset (0), and the
471 * MADs source is the stored PortGID;
473 * the stored MCMemberRecord:ProxyJoin is set (1), (see o15-
474 * 0.1.2:); and the MADs source is a member of the partition indicated
475 * by the stored MCMemberRecord:P_Key.
477 static boolean_t validate_delete(IN osm_sa_t * sa, IN osm_mgrp_t * p_mgrp,
478 IN osm_mad_addr_t * p_mad_addr,
479 IN ib_member_rec_t * p_recvd_mcmember_rec,
480 OUT osm_mcm_alias_guid_t ** pp_mcm_alias_guid)
484 portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id;
486 *pp_mcm_alias_guid = osm_mgrp_get_mcm_alias_guid(p_mgrp, portguid);
489 if (!*pp_mcm_alias_guid) {
490 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
491 "Failed to find the port in the MC group\n");
496 if (!(p_recvd_mcmember_rec->scope_state & 0x0F &
497 (*pp_mcm_alias_guid)->scope_state)) {
498 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
499 "Could not find any matching bits in the stored "
500 "and requested JoinStates\n");
505 if (((p_recvd_mcmember_rec->scope_state & 0x0F) |
506 (0x0F & (*pp_mcm_alias_guid)->scope_state)) !=
507 (0x0F & (*pp_mcm_alias_guid)->scope_state)) {
508 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
509 "Some bits in the request JoinState (0x%X) are not "
510 "set in the stored port (0x%X)\n",
511 (p_recvd_mcmember_rec->scope_state & 0x0F),
512 (0x0F & (*pp_mcm_alias_guid)->scope_state));
517 /* Validate according the the proxy_join (o15-0.1.2) */
518 if (validate_modify(sa, p_mgrp, p_mad_addr, p_recvd_mcmember_rec,
519 pp_mcm_alias_guid) == FALSE) {
520 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
521 "proxy_join validation failure\n");
528 * Check legality of the requested MGID (note this does not hold for SA
531 * Implementing o15-0.1.5:
532 * A multicast GID is considered to be invalid if:
533 * 1. It does not comply with the rules as specified in 4.1.1 "GID Usage and
534 * Properties" on page 145:
536 * 14) The multicast GID format is (bytes are comma sep):
537 * 0xff,<Fl><Sc>,<Si>,<Si>,<P>,<P>,<P>,<P>,<P>,<P>,<P>,<P>,<Id>,<Id>,<Id>,<Id>
538 * Fl 4bit = Flags (b)
539 * Sc 4bit = Scope (c)
540 * Si 16bit = Signature (2)
541 * P 64bit = GID Prefix (should be a subnet unique ID - normally Subnet Prefix)
542 * Id 32bit = Unique ID in the Subnet (might be MLID or P_Key ?)
544 * a) 8-bits of 11111111 at the start of the GID identifies this as being a
546 * b) Flags is a set of four 1-bit flags: 000T with three flags reserved
547 * and defined as zero (0). The T flag is defined as follows:
548 * i) T = 0 indicates this is a permanently assigned (i.e. wellknown)
549 * multicast GID. See RFC 2373 and RFC 2375 as reference
550 * for these permanently assigned GIDs.
551 * ii) T = 1 indicates this is a non-permanently assigned (i.e. transient)
553 * c) Scope is a 4-bit multicast scope value used to limit the scope of
554 * the multicast group. The following table defines scope value and
557 * Multicast Address Scope Values:
560 * 0x8 Organization-local
563 * 2. It contains the SA-specific signature of 0xA01B and has the link-local
564 * scope bits set. (EZ: the idea here is that SA created MGIDs are the
565 * only source for this signature with link-local scope)
567 static boolean_t validate_requested_mgid(IN osm_sa_t * sa,
568 IN const ib_member_rec_t * p_mcm_rec)
571 boolean_t valid = TRUE;
573 OSM_LOG_ENTER(sa->p_log);
575 /* 14-a: mcast GID must start with 0xFF */
576 if (p_mcm_rec->mgid.multicast.header[0] != 0xFF) {
577 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B01: "
578 "Invalid prefix 0x%02X in requested MGID, "
580 cl_ntoh16(p_mcm_rec->mgid.multicast.header[0]));
585 /* the MGID signature can mark IPoIB or SA assigned MGIDs */
586 memcpy(&signature, &(p_mcm_rec->mgid.multicast.raw_group_id),
588 signature = cl_ntoh16(signature);
589 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "MGID Signed as 0x%04X\n", signature);
592 * We skip any checks for MGIDs that follow IPoIB
593 * GID structure as defined by the IETF ipoib-link-multicast.
595 * For IPv4 over IB, the signature will be "0x401B".
597 * | 8 | 4 | 4 | 16 bits | 16 bits | 48 bits | 32 bits |
598 * +--------+----+----+-----------------+---------+----------+---------+
599 * |11111111|0001|scop|<IPoIB signature>|< P_Key >|00.......0|<all 1's>|
600 * +--------+----+----+-----------------+---------+----------+---------+
602 * For IPv6 over IB, the signature will be "0x601B".
604 * | 8 | 4 | 4 | 16 bits | 16 bits | 80 bits |
605 * +--------+----+----+-----------------+---------+--------------------+
606 * |11111111|0001|scop|<IPoIB signature>|< P_Key >|000.............0001|
607 * +--------+----+----+-----------------+---------+--------------------+
610 if (signature == 0x401B || signature == 0x601B) {
611 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
612 "Skipping MGID Validation for IPoIB Signed (0x%04X) MGIDs\n",
617 /* 14-b: the 3 upper bits in the "flags" should be zero: */
618 if (p_mcm_rec->mgid.multicast.header[1] & 0xE0) {
619 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B28: "
620 "Requested MGID invalid, uses Reserved Flags: flags=0x%X\n",
621 (p_mcm_rec->mgid.multicast.header[1] & 0xE0) >> 4);
626 /* 2 - now what if the link local format 0xA01B is used -
627 the scope should not be link local */
628 if (signature == 0xA01B &&
629 (p_mcm_rec->mgid.multicast.header[1] & 0x0F) ==
630 IB_MC_SCOPE_LINK_LOCAL) {
631 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B24: "
632 "Requested MGID invalid, "
633 "uses 0xA01B signature but with link-local scope\n");
639 * For SA assigned MGIDs (signature 0xA01B):
640 * There is no real way to make sure the GID Prefix is really unique.
641 * If we could enforce using the Subnet Prefix for that purpose it would
642 * have been nice. But the spec does not require it.
646 OSM_LOG_EXIT(sa->p_log);
650 /**********************************************************************
651 Check if the requested new MC group parameters are realizable.
652 Also set the default MTU and Rate if not provided by the user.
653 **********************************************************************/
654 static boolean_t mgrp_request_is_realizable(IN osm_sa_t * sa,
655 IN ib_net64_t comp_mask,
656 IN ib_member_rec_t * p_mcm_rec,
657 IN const osm_physp_t * p_physp)
659 uint8_t mtu_sel = 2; /* exactly */
660 uint8_t mtu_required, mtu, port_mtu;
661 uint8_t rate_sel = 2; /* exactly */
662 uint8_t rate_required, rate, port_rate;
663 const ib_port_info_t *p_pi;
664 osm_log_t *p_log = sa->p_log;
667 OSM_LOG_ENTER(sa->p_log);
670 * End of o15-0.2.3 specifies:
672 * The entity may also supply the other components such as HopLimit,
673 * MTU, etc. during group creation time. If these components are not
674 * provided during group creation time, SA will provide them for the
675 * group. The values chosen are vendor-dependent and beyond the scope
676 * of the specification.
678 * so we might also need to assign RATE/MTU if they are not comp
682 p_pi = &p_physp->port_info;
683 port_mtu = p_physp ? ib_port_info_get_mtu_cap(p_pi) : 0;
684 if (!(comp_mask & IB_MCR_COMPMASK_MTU) ||
685 !(comp_mask & IB_MCR_COMPMASK_MTU_SEL) ||
686 (mtu_sel = (p_mcm_rec->mtu >> 6)) == 3)
687 mtu = port_mtu ? port_mtu : sa->p_subn->min_ca_mtu;
689 mtu_required = (uint8_t) (p_mcm_rec->mtu & 0x3F);
692 case 0: /* Greater than MTU specified */
693 if (port_mtu && mtu_required >= port_mtu) {
694 OSM_LOG(p_log, OSM_LOG_VERBOSE,
695 "Requested MTU %x >= the port\'s mtu:%x\n",
696 mtu_required, port_mtu);
699 /* we provide the largest MTU possible if we can */
702 else if (mtu_required < sa->p_subn->min_ca_mtu)
703 mtu = sa->p_subn->min_ca_mtu;
707 case 1: /* Less than MTU specified */
708 /* use the smaller of the two:
709 a. one lower then the required
710 b. the mtu of the requesting port (if exists) */
711 if (port_mtu && mtu_required > port_mtu)
716 case 2: /* Exactly MTU specified */
720 /* make sure it still is in the range */
721 if (mtu < IB_MIN_MTU || mtu > IB_MAX_MTU) {
722 OSM_LOG(p_log, OSM_LOG_VERBOSE,
723 "Calculated MTU %x is out of range\n", mtu);
727 p_mcm_rec->mtu = (mtu_sel << 6) | mtu;
730 extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
731 port_rate = ib_port_info_compute_rate(p_pi, extended);
735 if (!(comp_mask & IB_MCR_COMPMASK_RATE)
736 || !(comp_mask & IB_MCR_COMPMASK_RATE_SEL)
737 || (rate_sel = (p_mcm_rec->rate >> 6)) == 3)
738 rate = port_rate ? port_rate : sa->p_subn->min_ca_rate;
740 rate_required = (uint8_t) (p_mcm_rec->rate & 0x3F);
741 rate = rate_required;
743 case 0: /* Greater than RATE specified */
744 if (ib_path_compare_rates(rate_required, port_rate) >= 0) {
745 OSM_LOG(p_log, OSM_LOG_VERBOSE,
746 "Requested RATE %x >= the port\'s rate:%x\n",
747 rate_required, port_rate);
750 /* we provide the largest RATE possible if we can */
753 else if (ib_path_compare_rates(rate_required,
754 sa->p_subn->min_ca_rate) < 0)
755 rate = sa->p_subn->min_ca_rate;
757 rate = ib_path_rate_get_next(rate);
759 case 1: /* Less than RATE specified */
760 /* use the smaller of the two:
761 a. one lower then the required
762 b. the rate of the requesting port (if exists) */
763 if (ib_path_compare_rates(rate_required, port_rate) > 0)
766 rate = ib_path_rate_get_prev(rate);
768 case 2: /* Exactly RATE specified */
772 /* make sure it still is in the range */
773 if (rate < IB_MIN_RATE || rate > IB_MAX_RATE) {
774 OSM_LOG(p_log, OSM_LOG_VERBOSE,
775 "Calculated RATE %x is out of range\n", rate);
779 p_mcm_rec->rate = (rate_sel << 6) | rate;
781 OSM_LOG_EXIT(sa->p_log);
785 static unsigned build_new_mgid(osm_sa_t * sa, ib_net64_t comp_mask,
786 ib_member_rec_t * mcmr)
788 static uint32_t uniq_count;
789 ib_gid_t *mgid = &mcmr->mgid;
793 /* use the given scope state only if requested! */
794 if (comp_mask & IB_MCR_COMPMASK_SCOPE)
795 ib_member_get_scope_state(mcmr->scope_state, &scope, NULL);
797 /* to guarantee no collision with other subnets use local scope! */
798 scope = IB_MC_SCOPE_LINK_LOCAL;
801 mgid->raw[1] = 0x10 | scope;
805 memcpy(&mgid->raw[4], &sa->p_subn->opt.subnet_prefix, sizeof(uint64_t));
807 for (i = 0; i < 1000; i++) {
808 memcpy(&mgid->raw[10], &uniq_count, 4);
810 if (!osm_get_mgrp_by_mgid(sa->p_subn, mgid))
817 /**********************************************************************
818 Call this function to create a new mgrp.
819 **********************************************************************/
820 static ib_api_status_t mcmr_rcv_create_new_mgrp(IN osm_sa_t * sa,
821 IN ib_net64_t comp_mask,
822 IN const ib_member_rec_t * p_recvd_mcmember_rec,
823 IN const osm_physp_t * p_physp,
824 OUT osm_mgrp_t ** pp_mgrp)
828 ib_api_status_t status = IB_SUCCESS;
829 osm_mgrp_t *bcast_mgrp;
831 ib_member_rec_t mcm_rec = *p_recvd_mcmember_rec; /* copy for modifications */
832 char gid_str[INET6_ADDRSTRLEN];
834 OSM_LOG_ENTER(sa->p_log);
836 /* we need to create the new MGID if it was not defined */
837 if (!ib_gid_is_notzero(&p_recvd_mcmember_rec->mgid)) {
838 /* create a new MGID */
839 if (!build_new_mgid(sa, comp_mask, &mcm_rec)) {
840 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B23: "
841 "cannot allocate unique MGID value\n");
842 status = IB_SA_MAD_STATUS_NO_RESOURCES;
845 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Allocated new MGID:%s\n",
846 inet_ntop(AF_INET6, mcm_rec.mgid.raw, gid_str,
848 } else if (sa->p_subn->opt.ipoib_mcgroup_creation_validation) {
849 /* a specific MGID was requested so validate the resulting MGID */
850 if (validate_requested_mgid(sa, &mcm_rec)) {
851 memcpy(&signature, &(mcm_rec.mgid.multicast.raw_group_id),
853 signature = cl_ntoh16(signature);
854 /* Check for IPoIB signature in MGID */
855 if (signature == 0x401B || signature == 0x601B) {
856 /* Derive IPoIB broadcast MGID */
857 bcast_mgid.unicast.prefix = IPV4_BCAST_MGID_PREFIX;
858 bcast_mgid.unicast.interface_id = IPV4_BCAST_MGID_INT_ID;
859 /* Set scope in IPoIB broadcast MGID */
860 bcast_mgid.multicast.header[1] =
861 (bcast_mgid.multicast.header[1] & 0xF0) |
862 (mcm_rec.mgid.multicast.header[1] & 0x0F);
863 /* Set P_Key in IPoIB broadcast MGID */
864 bcast_mgid.multicast.raw_group_id[2] =
865 mcm_rec.mgid.multicast.raw_group_id[2];
866 bcast_mgid.multicast.raw_group_id[3] =
867 mcm_rec.mgid.multicast.raw_group_id[3];
868 /* Check MC group for the IPoIB broadcast group */
869 if (signature != 0x401B ||
870 memcmp(&bcast_mgid, &(mcm_rec.mgid), sizeof(ib_gid_t))) {
871 bcast_mgrp = osm_get_mgrp_by_mgid(sa->p_subn,
874 OSM_LOG(sa->p_log, OSM_LOG_ERROR,
875 "ERR 1B1B: Broadcast group %s not found, sending IB_SA_MAD_STATUS_REQ_INVALID\n",
876 inet_ntop(AF_INET6, bcast_mgid.raw, gid_str, sizeof gid_str));
877 status = IB_SA_MAD_STATUS_REQ_INVALID;
880 if (!validate_other_comp_fields(sa->p_log, comp_mask, p_recvd_mcmember_rec, bcast_mgrp, OSM_LOG_ERROR)) {
881 OSM_LOG(sa->p_log, OSM_LOG_ERROR,
882 "ERR 1B1C: validate_other_comp_fields failed for MGID: %s, sending IB_SA_MAD_STATUS_REQ_INVALID\n",
883 inet_ntop(AF_INET6, &p_recvd_mcmember_rec->mgid, gid_str, sizeof gid_str));
884 status = IB_SA_MAD_STATUS_REQ_INVALID;
890 status = IB_SA_MAD_STATUS_REQ_INVALID;
895 /* check the requested parameters are realizable */
896 if (mgrp_request_is_realizable(sa, comp_mask, &mcm_rec, p_physp) ==
898 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B26: "
899 "Requested MGRP parameters are not realizable\n");
900 status = IB_SA_MAD_STATUS_REQ_INVALID;
904 mlid = get_new_mlid(sa, &mcm_rec);
906 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B19: "
907 "get_new_mlid failed request mlid 0x%04x\n",
908 cl_ntoh16(mcm_rec.mlid));
909 status = IB_SA_MAD_STATUS_NO_RESOURCES;
913 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Obtained new mlid 0x%X\n",
917 /* create a new MC Group */
918 *pp_mgrp = osm_mgrp_new(sa->p_subn, mlid, &mcm_rec);
919 if (*pp_mgrp == NULL) {
920 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B08: "
921 "osm_mgrp_new failed\n");
923 status = IB_SA_MAD_STATUS_NO_RESOURCES;
927 /* the mcmember_record should have mtu_sel, rate_sel, and pkt_lifetime_sel = 2 */
928 (*pp_mgrp)->mcmember_rec.mtu &= 0x3f;
929 (*pp_mgrp)->mcmember_rec.mtu |= IB_PATH_SELECTOR_EXACTLY << 6;
930 (*pp_mgrp)->mcmember_rec.rate &= 0x3f;
931 (*pp_mgrp)->mcmember_rec.rate |= IB_PATH_SELECTOR_EXACTLY << 6;
932 (*pp_mgrp)->mcmember_rec.pkt_life &= 0x3f;
933 (*pp_mgrp)->mcmember_rec.pkt_life |= IB_PATH_SELECTOR_EXACTLY << 6;
936 OSM_LOG_EXIT(sa->p_log);
940 /**********************************************************************
941 Call this function to find or create a new mgrp.
942 **********************************************************************/
943 osm_mgrp_t *osm_mcmr_rcv_find_or_create_new_mgrp(IN osm_sa_t * sa,
944 IN ib_net64_t comp_mask,
946 p_recvd_mcmember_rec)
950 if ((mgrp = osm_get_mgrp_by_mgid(sa->p_subn,
951 &p_recvd_mcmember_rec->mgid)))
953 if (mcmr_rcv_create_new_mgrp(sa, comp_mask, p_recvd_mcmember_rec, NULL,
954 &mgrp) == IB_SUCCESS)
959 /*********************************************************************
960 Process a request for leaving the group
961 **********************************************************************/
962 static void mcmr_rcv_leave_mgrp(IN osm_sa_t * sa, IN osm_madw_t * p_madw)
965 ib_sa_mad_t *p_sa_mad;
966 ib_member_rec_t *p_recvd_mcmember_rec;
967 ib_member_rec_t mcmember_rec;
968 osm_mcm_alias_guid_t *p_mcm_alias_guid;
970 OSM_LOG_ENTER(sa->p_log);
972 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
973 p_recvd_mcmember_rec =
974 (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
976 mcmember_rec = *p_recvd_mcmember_rec;
978 /* Validate the subnet prefix in the PortGID */
979 if (p_recvd_mcmember_rec->port_gid.unicast.prefix !=
980 sa->p_subn->opt.subnet_prefix) {
981 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
982 "PortGID subnet prefix 0x%" PRIx64
983 " does not match configured prefix 0x%" PRIx64 "\n",
984 cl_ntoh64(p_recvd_mcmember_rec->port_gid.unicast.prefix),
985 cl_ntoh64(sa->p_subn->opt.subnet_prefix));
986 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INVALID_GID);
990 CL_PLOCK_EXCL_ACQUIRE(sa->p_lock);
992 if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
993 osm_physp_t *p_req_physp;
995 p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
996 osm_madw_get_mad_addr_ptr(p_madw));
997 if (p_req_physp == NULL) {
998 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B02: "
999 "Cannot find requester physical port\n");
1001 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1002 "Requester port GUID 0x%" PRIx64 "\n",
1003 cl_ntoh64(osm_physp_get_port_guid(p_req_physp)));
1005 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Dump of record\n");
1006 osm_dump_mc_record_v2(sa->p_log, &mcmember_rec, FILE_ID, OSM_LOG_DEBUG);
1009 p_mgrp = osm_get_mgrp_by_mgid(sa->p_subn, &p_recvd_mcmember_rec->mgid);
1011 char gid_str[INET6_ADDRSTRLEN];
1012 CL_PLOCK_RELEASE(sa->p_lock);
1013 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1014 "Failed since multicast group %s not present\n",
1015 inet_ntop(AF_INET6, p_recvd_mcmember_rec->mgid.raw,
1016 gid_str, sizeof gid_str));
1017 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1021 /* check validity of the delete request o15-0.1.14 */
1022 if (!validate_delete(sa, p_mgrp, osm_madw_get_mad_addr_ptr(p_madw),
1023 p_recvd_mcmember_rec, &p_mcm_alias_guid)) {
1024 char gid_str[INET6_ADDRSTRLEN];
1025 char gid_str2[INET6_ADDRSTRLEN];
1026 CL_PLOCK_RELEASE(sa->p_lock);
1027 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B25: "
1028 "Received an invalid delete request for "
1029 "MGID: %s for PortGID: %s\n",
1030 inet_ntop(AF_INET6, p_recvd_mcmember_rec->mgid.raw,
1031 gid_str, sizeof gid_str),
1032 inet_ntop(AF_INET6, p_recvd_mcmember_rec->port_gid.raw,
1033 gid_str2, sizeof gid_str2));
1034 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1038 /* remove port and/or update join state */
1039 osm_mgrp_remove_port(sa->p_subn, sa->p_log, p_mgrp, p_mcm_alias_guid,
1041 CL_PLOCK_RELEASE(sa->p_lock);
1043 mcmr_rcv_respond(sa, p_madw, &mcmember_rec);
1046 OSM_LOG_EXIT(sa->p_log);
1049 static int validate_other_comp_fields(osm_log_t * p_log, ib_net64_t comp_mask,
1050 const ib_member_rec_t * p_mcmr,
1051 osm_mgrp_t * p_mgrp,
1052 osm_log_level_t log_level)
1056 if ((IB_MCR_COMPMASK_QKEY & comp_mask) &&
1057 p_mcmr->qkey != p_mgrp->mcmember_rec.qkey) {
1058 OSM_LOG(p_log, log_level, "ERR 1B30: "
1059 "Q_Key mismatch: query 0x%x group 0x%x\n",
1060 cl_ntoh32(p_mcmr->qkey),
1061 cl_ntoh32(p_mgrp->mcmember_rec.qkey));
1065 if (IB_MCR_COMPMASK_PKEY & comp_mask) {
1066 if (!(ib_pkey_is_full_member(p_mcmr->pkey) ||
1067 ib_pkey_is_full_member(p_mgrp->mcmember_rec.pkey))) {
1068 OSM_LOG(p_log, log_level, "ERR 1B31: "
1069 "Both limited P_Keys: query 0x%x group 0x%x\n",
1070 cl_ntoh16(p_mcmr->pkey),
1071 cl_ntoh16(p_mgrp->mcmember_rec.pkey));
1074 if (ib_pkey_get_base(p_mcmr->pkey) !=
1075 ib_pkey_get_base(p_mgrp->mcmember_rec.pkey)) {
1076 OSM_LOG(p_log, log_level, "ERR 1B32: "
1077 "P_Key base mismatch: query 0x%x group 0x%x\n",
1078 cl_ntoh16(p_mcmr->pkey),
1079 cl_ntoh16(p_mgrp->mcmember_rec.pkey));
1084 if ((IB_MCR_COMPMASK_TCLASS & comp_mask) &&
1085 p_mcmr->tclass != p_mgrp->mcmember_rec.tclass) {
1086 OSM_LOG(p_log, log_level, "ERR 1B33: "
1087 "TClass mismatch: query %d group %d\n",
1088 p_mcmr->tclass, p_mgrp->mcmember_rec.tclass);
1092 /* check SL, Flow, and Hop limit */
1094 uint32_t mgrp_flow, query_flow;
1095 uint8_t mgrp_sl, query_sl;
1096 uint8_t mgrp_hop, query_hop;
1098 ib_member_get_sl_flow_hop(p_mcmr->sl_flow_hop,
1099 &query_sl, &query_flow, &query_hop);
1101 ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop,
1102 &mgrp_sl, &mgrp_flow, &mgrp_hop);
1104 if ((IB_MCR_COMPMASK_SL & comp_mask) && query_sl != mgrp_sl) {
1105 OSM_LOG(p_log, log_level, "ERR 1B34: "
1106 "SL mismatch: query %d group %d\n",
1111 if ((IB_MCR_COMPMASK_FLOW & comp_mask) &&
1112 query_flow != mgrp_flow) {
1113 OSM_LOG(p_log, log_level, "ERR 1B35: "
1114 "FlowLabel mismatch: query 0x%x group 0x%x\n",
1115 query_flow, mgrp_flow);
1119 if ((IB_MCR_COMPMASK_HOP & comp_mask) && query_hop != mgrp_hop) {
1120 OSM_LOG(p_log, log_level, "ERR 1B36: "
1121 "Hop mismatch: query %d group %d\n",
1122 query_hop, mgrp_hop);
1132 /**********************************************************************
1133 Handle a join (or create) request
1134 **********************************************************************/
1135 static void mcmr_rcv_join_mgrp(IN osm_sa_t * sa, IN osm_madw_t * p_madw)
1137 osm_mgrp_t *p_mgrp = NULL;
1138 ib_api_status_t status;
1139 ib_sa_mad_t *p_sa_mad;
1140 ib_member_rec_t *p_recvd_mcmember_rec;
1141 ib_member_rec_t mcmember_rec;
1142 osm_mcm_port_t *p_mcmr_port;
1143 osm_mcm_alias_guid_t *p_mcm_alias_guid;
1144 ib_net64_t portguid;
1146 osm_physp_t *p_physp;
1147 osm_physp_t *p_request_physp;
1148 uint8_t is_new_group; /* TRUE = there is a need to create a group */
1152 OSM_LOG_ENTER(sa->p_log);
1154 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1155 p_recvd_mcmember_rec = ib_sa_mad_get_payload_ptr(p_sa_mad);
1157 portguid = p_recvd_mcmember_rec->port_gid.unicast.interface_id;
1159 mcmember_rec = *p_recvd_mcmember_rec;
1161 /* Validate the subnet prefix in the PortGID */
1162 if (p_recvd_mcmember_rec->port_gid.unicast.prefix !=
1163 sa->p_subn->opt.subnet_prefix) {
1164 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1165 "PortGID subnet prefix 0x%" PRIx64
1166 " does not match configured prefix 0x%" PRIx64 "\n",
1167 cl_ntoh64(p_recvd_mcmember_rec->port_gid.unicast.prefix),
1168 cl_ntoh64(sa->p_subn->opt.subnet_prefix));
1169 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INVALID_GID);
1173 CL_PLOCK_EXCL_ACQUIRE(sa->p_lock);
1175 if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
1176 osm_physp_t *p_req_physp;
1178 p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
1179 osm_madw_get_mad_addr_ptr(p_madw));
1180 if (p_req_physp == NULL) {
1181 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B03: "
1182 "Cannot find requester physical port\n");
1184 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1185 "Requester port GUID 0x%" PRIx64 "\n",
1186 cl_ntoh64(osm_physp_get_port_guid(p_req_physp)));
1188 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Dump of incoming record\n");
1189 osm_dump_mc_record_v2(sa->p_log, &mcmember_rec, FILE_ID, OSM_LOG_DEBUG);
1192 /* make sure the requested port guid is known to the SM */
1193 p_port = osm_get_port_by_alias_guid(sa->p_subn, portguid);
1195 CL_PLOCK_RELEASE(sa->p_lock);
1196 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1197 "Unknown port GUID 0x%016" PRIx64 "\n",
1198 cl_ntoh64(portguid));
1199 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1203 p_physp = p_port->p_physp;
1204 /* Check that the p_physp and the requester physp are in the same
1207 osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
1208 osm_madw_get_mad_addr_ptr(p_madw));
1209 if (p_request_physp == NULL) {
1210 CL_PLOCK_RELEASE(sa->p_lock);
1214 proxy = (p_physp != p_request_physp);
1216 if (proxy && !osm_physp_share_pkey(sa->p_log, p_physp, p_request_physp,
1217 sa->p_subn->opt.allow_both_pkeys)) {
1218 CL_PLOCK_RELEASE(sa->p_lock);
1219 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1220 "Port and requester don't share PKey\n");
1221 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1225 if ((p_sa_mad->comp_mask & IB_MCR_COMPMASK_PKEY) &&
1226 ib_pkey_is_invalid(p_recvd_mcmember_rec->pkey)) {
1227 CL_PLOCK_RELEASE(sa->p_lock);
1228 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1229 "Invalid PKey supplied in request\n");
1230 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1234 ib_member_get_scope_state(p_recvd_mcmember_rec->scope_state, NULL,
1237 /* do we need to create a new group? */
1238 p_mgrp = osm_get_mgrp_by_mgid(sa->p_subn, &p_recvd_mcmember_rec->mgid);
1240 /* check for JoinState.FullMember = 1 o15.0.1.9 */
1241 if ((join_state & 0x01) != 0x01) {
1242 char gid_str[INET6_ADDRSTRLEN];
1243 CL_PLOCK_RELEASE(sa->p_lock);
1244 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B10: "
1245 "Failed to create multicast group "
1246 "because Join State != FullMember, "
1247 "MGID: %s from port 0x%016" PRIx64 " (%s)\n",
1249 p_recvd_mcmember_rec->mgid.raw,
1250 gid_str, sizeof gid_str),
1251 cl_ntoh64(portguid),
1252 p_port->p_node->print_desc);
1253 osm_sa_send_error(sa, p_madw,
1254 IB_SA_MAD_STATUS_REQ_INVALID);
1258 /* check the comp_mask */
1259 if (!check_create_comp_mask(p_sa_mad->comp_mask,
1260 p_recvd_mcmember_rec)) {
1261 char gid_str[INET6_ADDRSTRLEN];
1262 CL_PLOCK_RELEASE(sa->p_lock);
1263 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B11: "
1264 "Port 0x%016" PRIx64 " (%s) failed to join "
1265 "non-existing multicast group with MGID %s, "
1266 "insufficient components specified for "
1267 "implicit create (comp_mask 0x%" PRIx64 ")\n",
1268 cl_ntoh64(portguid), p_port->p_node->print_desc,
1270 p_recvd_mcmember_rec->mgid.raw,
1271 gid_str, sizeof gid_str),
1272 cl_ntoh64(p_sa_mad->comp_mask));
1273 osm_sa_send_error(sa, p_madw,
1274 IB_SA_MAD_STATUS_INSUF_COMPS);
1278 status = mcmr_rcv_create_new_mgrp(sa, p_sa_mad->comp_mask,
1279 p_recvd_mcmember_rec,
1281 if (status != IB_SUCCESS) {
1282 CL_PLOCK_RELEASE(sa->p_lock);
1283 osm_sa_send_error(sa, p_madw, status);
1286 /* copy the MGID to the result */
1287 mcmember_rec.mgid = p_mgrp->mcmember_rec.mgid;
1290 /* no need for a new group */
1292 if (sa->p_subn->opt.mcgroup_join_validation &&
1293 !validate_other_comp_fields(sa->p_log, p_sa_mad->comp_mask,
1294 p_recvd_mcmember_rec, p_mgrp,
1296 char gid_str[INET6_ADDRSTRLEN];
1297 CL_PLOCK_RELEASE(sa->p_lock);
1298 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B1A: "
1299 "validate_other_comp_fields failed for "
1300 "MGID: %s port 0x%016" PRIx64
1301 " (%s), sending IB_SA_MAD_STATUS_REQ_INVALID\n",
1303 p_mgrp->mcmember_rec.mgid.raw,
1304 gid_str, sizeof gid_str),
1305 cl_ntoh64(portguid),
1306 p_port->p_node->print_desc);
1307 osm_sa_send_error(sa, p_madw,
1308 IB_SA_MAD_STATUS_REQ_INVALID);
1316 * o15-0.2.4: If SA supports UD multicast, then SA shall cause an
1317 * endport to join an existing multicast group if:
1318 * 1. It receives a SubnAdmSet() method for a MCMemberRecord, and
1319 * - WE KNOW THAT ALREADY
1320 * 2. The MGID is specified and matches an existing multicast
1322 * - WE KNOW THAT ALREADY
1323 * 3. The MCMemberRecord:JoinState is not all 0s, and
1324 * 4. PortGID is specified and
1325 * - WE KNOW THAT ALREADY (as it matched a real one)
1326 * 5. All other components match that existing group, either by
1327 * being wildcarded or by having values identical to those specified
1328 * by the component mask and in use by the group with the exception
1329 * of components such as ProxyJoin and Reserved, which are ignored
1332 * We need to check #3 and #5 here:
1334 if (!validate_more_comp_fields(sa->p_log, p_mgrp, p_recvd_mcmember_rec,
1335 p_sa_mad->comp_mask)
1336 || !validate_port_caps(sa->p_log, p_mgrp, p_physp)
1337 || !(join_state != 0)) {
1338 char gid_str[INET6_ADDRSTRLEN];
1339 /* since we might have created the new group we need to cleanup */
1341 osm_mgrp_cleanup(sa->p_subn, p_mgrp);
1342 CL_PLOCK_RELEASE(sa->p_lock);
1343 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B12: "
1344 "validate_more_comp_fields, validate_port_caps, "
1345 "or JoinState = 0 failed for MGID: %s port 0x%016" PRIx64
1346 " (%s), sending IB_SA_MAD_STATUS_REQ_INVALID\n",
1347 inet_ntop(AF_INET6, p_mgrp->mcmember_rec.mgid.raw,
1348 gid_str, sizeof gid_str),
1349 cl_ntoh64(portguid), p_port->p_node->print_desc);
1350 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1354 /* verify that the joining port is in the partition of the group */
1355 if (!osm_physp_has_pkey(sa->p_log, p_mgrp->mcmember_rec.pkey, p_physp)) {
1356 char gid_str[INET6_ADDRSTRLEN];
1358 osm_mgrp_cleanup(sa->p_subn, p_mgrp);
1359 CL_PLOCK_RELEASE(sa->p_lock);
1360 memset(gid_str, 0, sizeof(gid_str));
1361 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B14: "
1362 "Cannot join port 0x%016" PRIx64 " to MGID %s - "
1363 "Port is not in partition of this MC group\n",
1364 cl_ntoh64(portguid),
1366 p_mgrp->mcmember_rec.mgid.raw,
1367 gid_str, sizeof(gid_str)));
1368 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1373 * o15-0.2.1 requires validation of the requesting port
1374 * in the case of modification:
1376 if (!is_new_group &&
1377 !validate_modify(sa, p_mgrp, osm_madw_get_mad_addr_ptr(p_madw),
1378 p_recvd_mcmember_rec, &p_mcm_alias_guid)) {
1379 char gid_str[INET6_ADDRSTRLEN];
1380 CL_PLOCK_RELEASE(sa->p_lock);
1381 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B13: "
1382 "validate_modify failed from port 0x%016" PRIx64
1383 " (%s) for MGID: %s, sending IB_SA_MAD_STATUS_REQ_INVALID\n",
1384 cl_ntoh64(portguid), p_port->p_node->print_desc,
1386 p_mgrp->mcmember_rec.mgid.raw,
1387 gid_str, sizeof(gid_str)));
1388 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1392 /* copy qkey mlid tclass pkey sl_flow_hop mtu rate pkt_life */
1393 copy_from_create_mc_rec(&mcmember_rec, &p_mgrp->mcmember_rec);
1395 /* create or update existing port (join-state will be updated) */
1396 p_mcmr_port = osm_mgrp_add_port(sa->p_subn, sa->p_log, p_mgrp, p_port,
1397 &mcmember_rec, proxy);
1399 /* we fail to add the port so we might need to delete the group */
1401 osm_mgrp_cleanup(sa->p_subn, p_mgrp);
1402 CL_PLOCK_RELEASE(sa->p_lock);
1403 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B06: "
1404 "osm_mgrp_add_port failed\n");
1405 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES);
1409 /* Release the lock as we don't need it. */
1410 CL_PLOCK_RELEASE(sa->p_lock);
1412 if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG))
1413 osm_dump_mc_record_v2(sa->p_log, &mcmember_rec, FILE_ID, OSM_LOG_DEBUG);
1415 mcmr_rcv_respond(sa, p_madw, &mcmember_rec);
1418 OSM_LOG_EXIT(sa->p_log);
1421 /**********************************************************************
1422 Add a patched multicast group to the results list
1423 **********************************************************************/
1424 static ib_api_status_t mcmr_rcv_new_mcmr(IN osm_sa_t * sa,
1425 IN const ib_member_rec_t * p_rcvd_rec,
1426 IN cl_qlist_t * p_list)
1428 osm_sa_item_t *p_rec_item;
1429 ib_api_status_t status = IB_SUCCESS;
1431 OSM_LOG_ENTER(sa->p_log);
1433 p_rec_item = malloc(SA_MCM_RESP_SIZE);
1434 if (p_rec_item == NULL) {
1435 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B15: "
1436 "rec_item alloc failed\n");
1437 status = IB_INSUFFICIENT_RESOURCES;
1441 memset(p_rec_item, 0, sizeof(cl_list_item_t));
1443 /* HACK: Untrusted requesters should result with 0 Join
1444 State, Port Guid, and Proxy */
1445 p_rec_item->resp.mc_rec = *p_rcvd_rec;
1446 cl_qlist_insert_tail(p_list, &p_rec_item->list_item);
1449 OSM_LOG_EXIT(sa->p_log);
1453 /**********************************************************************
1454 Match the given mgrp to the requested mcmr
1455 **********************************************************************/
1456 static void mcmr_by_comp_mask(osm_sa_t * sa, const ib_member_rec_t * p_rcvd_rec,
1457 ib_net64_t comp_mask, osm_mgrp_t * p_mgrp,
1458 const osm_physp_t * p_req_physp,
1459 boolean_t trusted_req, cl_qlist_t * list)
1461 /* since we might change scope_state */
1462 ib_member_rec_t match_rec;
1463 osm_mcm_alias_guid_t *p_mcm_alias_guid;
1464 ib_net64_t portguid = p_rcvd_rec->port_gid.unicast.interface_id;
1465 /* will be used for group or port info */
1466 uint8_t scope_state;
1467 uint8_t scope_state_mask = 0;
1468 cl_map_item_t *p_item;
1470 boolean_t proxy_join = FALSE;
1472 OSM_LOG_ENTER(sa->p_log);
1474 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1475 "Checking mlid:0x%X\n", cl_ntoh16(p_mgrp->mlid));
1477 /* first try to eliminate the group by MGID, MLID, or P_Key */
1478 if ((IB_MCR_COMPMASK_MGID & comp_mask) &&
1479 memcmp(&p_rcvd_rec->mgid, &p_mgrp->mcmember_rec.mgid,
1483 if ((IB_MCR_COMPMASK_MLID & comp_mask) &&
1484 memcmp(&p_rcvd_rec->mlid, &p_mgrp->mcmember_rec.mlid,
1488 /* if the requester physical port doesn't have the pkey that is defined
1489 for the group - exit. */
1490 if (!osm_physp_has_pkey(sa->p_log, p_mgrp->mcmember_rec.pkey,
1494 /* now do the rest of the match */
1495 if (!validate_other_comp_fields(sa->p_log, comp_mask, p_rcvd_rec, p_mgrp,
1499 if ((IB_MCR_COMPMASK_PROXY & comp_mask) &&
1500 p_rcvd_rec->proxy_join != p_mgrp->mcmember_rec.proxy_join)
1503 /* need to validate mtu, rate, and pkt_lifetime fields */
1504 if (validate_more_comp_fields(sa->p_log, p_mgrp, p_rcvd_rec,
1505 comp_mask) == FALSE)
1508 /* Port specific fields */
1509 /* so did we get the PortGUID mask */
1510 if (IB_MCR_COMPMASK_PORT_GID & comp_mask) {
1511 /* try to find this port */
1512 p_mcm_alias_guid = osm_mgrp_get_mcm_alias_guid(p_mgrp, portguid);
1513 if (!p_mcm_alias_guid) /* port not in group */
1515 scope_state = p_mcm_alias_guid->scope_state;
1516 memcpy(&port_gid, &(p_mcm_alias_guid->port_gid),
1518 proxy_join = p_mcm_alias_guid->proxy_join;
1519 } else /* point to the group information */
1520 scope_state = p_mgrp->mcmember_rec.scope_state;
1522 if (IB_MCR_COMPMASK_SCOPE & comp_mask)
1523 scope_state_mask = 0xF0;
1525 if (IB_MCR_COMPMASK_JOIN_STATE & comp_mask)
1526 scope_state_mask = scope_state_mask | 0x0F;
1528 /* Many MC records returned */
1529 if (trusted_req == TRUE && !(IB_MCR_COMPMASK_PORT_GID & comp_mask)) {
1530 char gid_str[INET6_ADDRSTRLEN];
1531 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1532 "Trusted req is TRUE and no specific port defined\n");
1534 /* return all the ports that match in this MC group */
1535 p_item = cl_qmap_head(&(p_mgrp->mcm_alias_port_tbl));
1536 while (p_item != cl_qmap_end(&(p_mgrp->mcm_alias_port_tbl))) {
1537 p_mcm_alias_guid = (osm_mcm_alias_guid_t *) p_item;
1539 if ((scope_state_mask & p_rcvd_rec->scope_state) ==
1540 (scope_state_mask & p_mcm_alias_guid->scope_state)) {
1541 /* add to the list */
1542 match_rec = p_mgrp->mcmember_rec;
1543 match_rec.scope_state = p_mcm_alias_guid->scope_state;
1544 memcpy(&match_rec.port_gid,
1545 &p_mcm_alias_guid->port_gid,
1547 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1548 "Record of port_gid: %s"
1549 " in multicast_lid: 0x%X is returned\n",
1551 match_rec.port_gid.raw,
1552 gid_str, sizeof gid_str),
1553 cl_ntoh16(p_mgrp->mlid));
1555 match_rec.proxy_join =
1556 (uint8_t) (p_mcm_alias_guid->proxy_join);
1558 mcmr_rcv_new_mcmr(sa, &match_rec, list);
1560 p_item = cl_qmap_next(p_item);
1562 } else { /* One MC record returned */
1563 if ((scope_state_mask & p_rcvd_rec->scope_state) !=
1564 (scope_state_mask & scope_state))
1567 /* add to the list */
1568 match_rec = p_mgrp->mcmember_rec;
1569 match_rec.scope_state = scope_state;
1570 memcpy(&(match_rec.port_gid), &port_gid, sizeof(ib_gid_t));
1571 match_rec.proxy_join = (uint8_t) proxy_join;
1573 mcmr_rcv_new_mcmr(sa, &match_rec, list);
1577 OSM_LOG_EXIT(sa->p_log);
1580 /**********************************************************************
1581 Handle a query request
1582 **********************************************************************/
1583 static void mcmr_query_mgrp(IN osm_sa_t * sa, IN osm_madw_t * p_madw)
1585 const ib_sa_mad_t *p_rcvd_mad;
1586 const ib_member_rec_t *p_rcvd_rec;
1587 cl_qlist_t rec_list;
1588 ib_net64_t comp_mask;
1589 osm_physp_t *p_req_physp;
1590 boolean_t trusted_req;
1593 OSM_LOG_ENTER(sa->p_log);
1595 p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw);
1596 p_rcvd_rec = (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad);
1597 comp_mask = p_rcvd_mad->comp_mask;
1600 if sm_key is not zero and does not match we never get here
1601 see main SA receiver
1603 trusted_req = (p_rcvd_mad->sm_key != 0);
1605 CL_PLOCK_ACQUIRE(sa->p_lock);
1607 /* update the requester physical port */
1608 p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
1609 osm_madw_get_mad_addr_ptr
1611 if (p_req_physp == NULL) {
1612 CL_PLOCK_RELEASE(sa->p_lock);
1613 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B04: "
1614 "Cannot find requester physical port\n");
1618 if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
1619 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1620 "Requester port GUID 0x%" PRIx64 "\n",
1621 cl_ntoh64(osm_physp_get_port_guid(p_req_physp)));
1622 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Dump of record\n");
1623 osm_dump_mc_record(sa->p_log, p_rcvd_rec, OSM_LOG_DEBUG);
1626 cl_qlist_init(&rec_list);
1628 /* simply go over all MCGs and match */
1629 for (p_mgrp = (osm_mgrp_t *) cl_fmap_head(&sa->p_subn->mgrp_mgid_tbl);
1630 p_mgrp != (osm_mgrp_t *) cl_fmap_end(&sa->p_subn->mgrp_mgid_tbl);
1631 p_mgrp = (osm_mgrp_t *) cl_fmap_next(&p_mgrp->map_item))
1632 mcmr_by_comp_mask(sa, p_rcvd_rec, comp_mask, p_mgrp,
1633 p_req_physp, trusted_req, &rec_list);
1635 CL_PLOCK_RELEASE(sa->p_lock);
1638 p923 - The PortGID, JoinState and ProxyJoin shall be zero,
1639 except in the case of a trusted request.
1640 Note: In the mad controller we check that the SM_Key received on
1641 the mad is valid. Meaning - is either zero or equal to the local
1645 if (!p_rcvd_mad->sm_key) {
1646 osm_sa_item_t *item;
1647 for (item = (osm_sa_item_t *) cl_qlist_head(&rec_list);
1648 item != (osm_sa_item_t *) cl_qlist_end(&rec_list);
1650 (osm_sa_item_t *) cl_qlist_next(&item->list_item)) {
1651 memset(&item->resp.mc_rec.port_gid, 0, sizeof(ib_gid_t));
1652 ib_member_set_join_state(&item->resp.mc_rec, 0);
1653 item->resp.mc_rec.proxy_join = 0;
1657 osm_sa_respond(sa, p_madw, sizeof(ib_member_rec_t), &rec_list);
1660 OSM_LOG_EXIT(sa->p_log);
1663 static uint8_t rate_is_valid(IN const ib_sa_mad_t *p_sa_mad,
1664 IN const ib_member_rec_t *p_recvd_mcmember_rec)
1668 /* Validate rate if supplied */
1669 if ((p_sa_mad->comp_mask & IB_MCR_COMPMASK_RATE_SEL) &&
1670 (p_sa_mad->comp_mask & IB_MCR_COMPMASK_RATE)) {
1671 rate = (uint8_t) (p_recvd_mcmember_rec->rate & 0x3F);
1672 return ib_rate_is_valid(rate);
1677 static int mtu_is_valid(IN const ib_sa_mad_t *p_sa_mad,
1678 IN const ib_member_rec_t *p_recvd_mcmember_rec)
1682 /* Validate MTU if supplied */
1683 if ((p_sa_mad->comp_mask & IB_MCR_COMPMASK_MTU_SEL) &&
1684 (p_sa_mad->comp_mask & IB_MCR_COMPMASK_MTU)) {
1685 mtu = (uint8_t) (p_recvd_mcmember_rec->mtu & 0x3F);
1686 return ib_mtu_is_valid(mtu);
1691 void osm_mcmr_rcv_process(IN void *context, IN void *data)
1693 osm_sa_t *sa = context;
1694 osm_madw_t *p_madw = data;
1695 ib_sa_mad_t *p_sa_mad;
1696 ib_member_rec_t *p_recvd_mcmember_rec;
1700 OSM_LOG_ENTER(sa->p_log);
1704 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1705 p_recvd_mcmember_rec =
1706 (ib_member_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
1708 CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_MCMEMBER_RECORD);
1710 switch (p_sa_mad->method) {
1711 case IB_MAD_METHOD_SET:
1712 if (!check_join_comp_mask(p_sa_mad->comp_mask)) {
1713 char gid_str[INET6_ADDRSTRLEN];
1714 char gid_str2[INET6_ADDRSTRLEN];
1715 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B18: "
1716 "component mask = 0x%016" PRIx64 ", "
1717 "expected comp mask = 0x%016" PRIx64 ", "
1718 "MGID: %s for PortGID: %s\n",
1719 cl_ntoh64(p_sa_mad->comp_mask),
1720 CL_NTOH64(JOIN_MC_COMP_MASK),
1722 p_recvd_mcmember_rec->mgid.raw,
1723 gid_str, sizeof gid_str),
1725 p_recvd_mcmember_rec->port_gid.raw,
1726 gid_str2, sizeof gid_str2));
1727 osm_sa_send_error(sa, p_madw,
1728 IB_SA_MAD_STATUS_INSUF_COMPS);
1731 if (!rate_is_valid(p_sa_mad, p_recvd_mcmember_rec) ||
1732 !mtu_is_valid(p_sa_mad, p_recvd_mcmember_rec)) {
1733 osm_sa_send_error(sa, p_madw,
1734 IB_SA_MAD_STATUS_REQ_INVALID);
1739 * Join or Create Multicast Group
1741 mcmr_rcv_join_mgrp(sa, p_madw);
1743 case IB_MAD_METHOD_DELETE:
1744 if (!check_join_comp_mask(p_sa_mad->comp_mask)) {
1745 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B20: "
1746 "component mask = 0x%016" PRIx64 ", "
1747 "expected comp mask = 0x%016" PRIx64 "\n",
1748 cl_ntoh64(p_sa_mad->comp_mask),
1749 CL_NTOH64(JOIN_MC_COMP_MASK));
1750 osm_sa_send_error(sa, p_madw,
1751 IB_SA_MAD_STATUS_INSUF_COMPS);
1754 if (!rate_is_valid(p_sa_mad, p_recvd_mcmember_rec) ||
1755 !mtu_is_valid(p_sa_mad, p_recvd_mcmember_rec)) {
1756 osm_sa_send_error(sa, p_madw,
1757 IB_SA_MAD_STATUS_REQ_INVALID);
1762 * Leave Multicast Group
1764 mcmr_rcv_leave_mgrp(sa, p_madw);
1766 case IB_MAD_METHOD_GET:
1767 case IB_MAD_METHOD_GETTABLE:
1768 if (!rate_is_valid(p_sa_mad, p_recvd_mcmember_rec) ||
1769 !mtu_is_valid(p_sa_mad, p_recvd_mcmember_rec)) {
1770 osm_sa_send_error(sa, p_madw,
1771 IB_SA_MAD_STATUS_REQ_INVALID);
1776 * Querying a Multicast Group
1778 mcmr_query_mgrp(sa, p_madw);
1781 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1B21: "
1782 "Unsupported Method (%s) for MCMemberRecord request\n",
1783 ib_get_sa_method_str(p_sa_mad->method));
1784 osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
1789 OSM_LOG_EXIT(sa->p_log);