isns_object_t * isns_create_storage_node2(const isns_source_t *source, uint32_t type, isns_object_t *parent) { isns_attr_t *name_attr; isns_object_t *obj; if (parent && !ISNS_IS_ENTITY(parent)) { isns_warning("Invalid container type \"%s\" for storage node: " "should be \"%s\"\n", parent->ie_template->iot_name, isns_entity_template.iot_name); return NULL; } if ((name_attr = isns_source_attr(source)) == NULL) { isns_warning("No source attribute\n"); return NULL; } if (name_attr->ia_tag_id == ISNS_TAG_ISCSI_NAME) { obj = isns_create_object(&isns_iscsi_node_template, NULL, parent); isns_attr_list_update_attr(&obj->ie_attrs, name_attr); isns_object_set_uint32(obj, ISNS_TAG_ISCSI_NODE_TYPE, type); } else { /* No iFCP yet, sorry */ isns_warning("%s: source tag type %u not supported\n", __FUNCTION__); return NULL; } return obj; }
/* * Transmit all pending SCN messages * * 2.9.2 * If a Network Entity has multiple Portals with registered SCN UDP Ports, * then SCN messages SHALL be delivered to each Portal registered to * receive such messages. * * FIXME: we should make this timer based just as the ESI code. */ time_t isns_scn_transmit_all(void) { time_t now = time(NULL), next_timeout; isns_scn_t *scn; for (scn = isns_scn_list; scn; scn = scn->scn_next) { isns_simple_t *call; isns_socket_t *sock; /* We do not allow more than one outstanding * notification for now. */ if ((call = scn->scn_pending) != NULL) { if (scn->scn_timeout > now) continue; scn->scn_current_funnel->scn_bad++; if (--(scn->scn_retries)) goto retry; isns_warning("SCN for %s timed out\n", scn->scn_name); isns_simple_free(call); scn->scn_pending = NULL; } if ((call = scn->scn_message) == NULL) continue; isns_debug_scn("SCN: transmit pending message for %s\n", scn->scn_name); scn->scn_retries = isns_config.ic_scn_retries; scn->scn_pending = call; scn->scn_message = NULL; retry: if ((sock = isns_scn_get_socket(scn)) == NULL) { /* Sorry, no can do. */ isns_warning("SCN for %s dropped - no portal\n", scn->scn_name); scn->scn_pending = NULL; isns_simple_free(call); continue; } isns_simple_transmit(sock, call, NULL, isns_config.ic_scn_timeout, isns_process_scn_response); scn->scn_xid = call->is_xid; scn->scn_timeout = now + isns_config.ic_scn_timeout; } next_timeout = now + 3600; for (scn = isns_scn_list; scn; scn = scn->scn_next) { if (scn->scn_pending && scn->scn_timeout < next_timeout) next_timeout = scn->scn_timeout; } return next_timeout; }
/* * Create a registration, and set the source name */ static isns_simple_t * __isns_create_registration(isns_source_t *source, isns_object_t *key_obj) { isns_simple_t *reg; reg = isns_simple_create(ISNS_DEVICE_ATTRIBUTE_REGISTER, source, NULL); if (reg == NULL) return NULL; /* * When sending a registration, you can either specify * the object to be modified in the key attrs, or leave * the key empty. */ if (key_obj == NULL) return reg; /* User gave us a key object. We need to put the key * attributes into the message attrs, and *all* attrs * into the operating attrs. */ if (!isns_object_extract_keys(key_obj, ®->is_message_attrs)) { /* bummer - seems the object is missing some * vital organs. */ isns_warning("%s: object not fully specified, key attrs missing\n", __FUNCTION__); goto failed; } /* * The Message Key identifies the object the DevAttrReg message * acts upon. [...] The key attribute(s) identifying this object * MUST also be included among the Operating Attributes. * * We do not enforce this here, we rely on the caller to get this * right. */ #if 0 if (!isns_object_extract_all(key_obj, ®->is_operating_attrs)) { isns_warning("%s: unable to extract attrs from key objects\n", __FUNCTION__); goto failed; } #endif return reg; failed: isns_simple_free(reg); return NULL; }
int list_objects(isns_client_t *clnt, int argc, char **argv) { isns_attr_list_t query_keys = ISNS_ATTR_LIST_INIT; isns_object_template_t *query_type = NULL; isns_simple_t *simp; int status, count = 0; if (!parse_list(argc, argv, &query_type, &query_keys)) isns_fatal("Unable to parse parameters\n"); simp = isns_create_getnext(clnt, query_type, &query_keys); while (1) { isns_object_t *obj = NULL; isns_simple_t *followup; status = isns_client_call(clnt, &simp); if (status) break; status = isns_getnext_response_get_object(simp, &obj); if (status) break; printf("Object %u:\n", count++); isns_object_print(obj, isns_print_stdout); isns_object_release(obj); followup = isns_create_getnext_followup(clnt, simp, &query_keys); isns_simple_free(simp); simp = followup; } if (status == ISNS_SOURCE_UNAUTHORIZED && query_type == &isns_policy_template && !opt_local) isns_warning("Please use --local trying to list policies\n"); if (status != ISNS_NO_SUCH_ENTRY) { isns_error("GetNext call failed: %s\n", isns_strerror(status)); return status; } return ISNS_SUCCESS; }
isns_object_t * isns_create_storage_node(const char *name, uint32_t type, isns_object_t *parent) { isns_object_t *obj; if (parent && !ISNS_IS_ENTITY(parent)) { isns_warning("Invalid container type \"%s\" for storage node: " "should be \"%s\"\n", parent->ie_template->iot_name, isns_entity_template.iot_name); return NULL; } obj = isns_create_object(&isns_iscsi_node_template, NULL, parent); isns_object_set_string(obj, ISNS_TAG_ISCSI_NAME, name); isns_object_set_uint32(obj, ISNS_TAG_ISCSI_NODE_TYPE, type); return obj; }
/* * This function is invoked whenever someone changes the * database. * * SCNs are another area where the RFC is fabulously wishy washy. * It is not entirely clear when DD/DDS information should be * included in a management SCN - one *reasonable* interpretation * would be that this happens for DDReg/DDDereg/DDSReg/DDSDereg * events only. But some sections make it sound as if DD * information is included for all management SCNs. */ void isns_scn_callback(const isns_db_event_t *ev, void *ptr) { isns_object_t *obj = ev->ie_object; isns_scn_t *scn, **pos; isns_attr_t *timestamp; uint32_t node_type; /* Never send out notifications for policy objects and the like. */ if (obj->ie_flags & ISNS_OBJECT_PRIVATE) return; /* When an entity is nuked, remove all SCNs to nodes * that registered from there */ if (ISNS_IS_ENTITY(obj) && (ev->ie_bits & ISNS_SCN_OBJECT_REMOVED_MASK)) { pos = &isns_scn_list; while ((scn = *pos) != NULL) { if (scn->scn_entity != obj) { pos = &scn->scn_next; continue; } isns_debug_scn("Deleting SCN registration for %s\n", scn->scn_name); *pos = scn->scn_next; isns_scn_free(scn); } return; } /* For now we handle iSCSI nodes only. Maybe later we'll * do iFC nodes as well. */ if (!ISNS_IS_ISCSI_NODE(obj)) return; if (!isns_object_get_uint32(obj, ISNS_TAG_ISCSI_NODE_TYPE, &node_type)) return; if (ev->ie_recipient) { isns_object_t *dst = ev->ie_recipient; isns_debug_scn("SCN unicast <%s %u, %s> -> %s %u\n", obj->ie_template->iot_name, obj->ie_index, isns_event_string(ev->ie_bits), dst->ie_template->iot_name, dst->ie_index); } else { isns_debug_scn("SCN multicast <%s %u, %s>\n", obj->ie_template->iot_name, obj->ie_index, isns_event_string(ev->ie_bits)); } timestamp = isns_create_timestamp_attr(); pos = &isns_scn_list; while ((scn = *pos) != NULL) { unsigned int scn_bits, management; isns_object_t *recipient, *dd = NULL; isns_simple_t *call; recipient = scn->scn_owner; /* Check if the node has gone away completely. */ if (recipient->ie_scn_mask == 0) { *pos = scn->scn_next; isns_scn_free(scn); continue; } if (recipient->ie_container == NULL) { isns_warning("Internal bug - SCN recipient without container\n"); /* Clear the bitmask and loop over - this will remove it */ recipient->ie_scn_mask = 0; continue; } /* See if portals were added/removed. * This does not catch updates that modified *just* * the SCN port */ if (recipient->ie_container->ie_mtime != scn->scn_last_update) { /* Rebuild the list of SCN portals */ isns_scn_release_funnels(scn); scn->scn_last_update = 0; } pos = &scn->scn_next; /* Check for unicast events (triggered for DD addition/removal). * For unicast events, we do not mask the SCN bits, so that * clients who have registered for non-management events * will see the membership events for their DDs nevertheless. */ if (ev->ie_recipient == NULL) { scn_bits = ev->ie_bits & recipient->ie_scn_mask; if (scn_bits == 0) continue; /* Management SCNs should not be delivered to nodes * that have not registered for them. */ if ((ev->ie_bits & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK) && !(recipient->ie_scn_mask & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK)) continue; } else if (recipient == ev->ie_recipient) { scn_bits = ev->ie_bits; } else { /* No match, skip this recipient */ continue; } if (scn->scn_last_update == 0) { scn->scn_last_update = recipient->ie_container->ie_mtime; isns_scn_setup(scn, recipient); } /* We check for SCN capable portals when processing * the SCN registration. But the portals may go away * in the meantime. */ if (scn->scn_funnels == NULL) continue; /* Check SCN bitmask. This will modify the event bits. */ scn_bits = isns_scn_match(scn, scn_bits, obj, node_type); if (scn_bits == 0) continue; management = !!(scn_bits & ISNS_SCN_MANAGEMENT_REGISTRATION_MASK); /* * 2.2.3 * A regular SCN registration indicates that the * Discovery Domain Service SHALL be used to control the * distribution of SCN messages. Receipt of regular * SCNs is limited to the discovery domains in which * the SCN-triggering event takes place. Regular SCNs * do not contain information about discovery domains. * * Implementer's note: We override check for unicast events. * The reason is that DDDereg will sever the * relationship, and we would never send an SCN for that * event. */ if (!management && !ev->ie_recipient) { if (!isns_object_test_visibility(obj, recipient)) continue; } isns_debug_scn("preparing to send SCN to %s\n", scn->scn_name); if ((call = scn->scn_message) == NULL) { call = isns_create_scn(isns_scn_server->is_source, scn->scn_attr, timestamp); if (call == NULL) continue; scn->scn_message = call; } /* * If the SCN is a Management SCN, then the SCN message * SHALL also list the DD_ID and/or DDS_ID of the * Discovery Domains and Discovery Domain Sets (if any) * that caused the change in state for that Storage Node. * These additional attributes (i.e., DD_ID and/or DDS_ID) * shall immediately follow the iSCSI Name or FC Port * Name and precede the next SCN bitmap for the next * notification message (if any). */ if (management && ev->ie_trigger) dd = ev->ie_trigger; isns_scn_add_event(call, scn_bits, obj, dd); } isns_attr_release(timestamp); }