Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5259 lines
143 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. nminit.c
  5. Abstract:
  6. Initialization, cluster join, and cluster form routines for the
  7. Node Manager.
  8. Author:
  9. Mike Massa (mikemas)
  10. Revision History:
  11. 6/03/96 Created.
  12. --*/
  13. /*
  14. General Implementation Notes:
  15. The functions DmBeginLocalUpdate, DmCommitLocalUpdate, and
  16. DmAbortLocalUpdate cannot be called while holding the NM lock, or
  17. a deadlock with the NmTimer thread may result during regroup when
  18. disk writes are stalled. These functions attempt to write to the
  19. quorum disk.
  20. */
  21. #include "nmp.h"
  22. //
  23. // External Data
  24. //
  25. extern BOOL CsNoQuorum;
  26. //
  27. // Public Data
  28. //
  29. HANDLE NmClusnetHandle = NULL;
  30. //
  31. // Private Data
  32. //
  33. CRITICAL_SECTION NmpLock;
  34. NM_STATE NmpState = NmStateOffline;
  35. DWORD NmpActiveThreadCount = 0;
  36. HANDLE NmpShutdownEvent = NULL;
  37. CL_NODE_ID NmpJoinerNodeId = ClusterInvalidNodeId;
  38. CL_NODE_ID NmpSponsorNodeId = ClusterInvalidNodeId;
  39. DWORD NmpJoinTimer = 0;
  40. BOOLEAN NmpJoinAbortPending = FALSE;
  41. DWORD NmpJoinSequence = 0;
  42. BOOLEAN NmpJoinerUp = FALSE;
  43. BOOLEAN NmpJoinBeginInProgress = FALSE;
  44. BOOLEAN NmpJoinerOutOfSynch = FALSE;
  45. LPWSTR NmpClusnetEndpoint = NULL;
  46. WCHAR NmpInvalidJoinerIdString[] = L"0";
  47. CL_NODE_ID NmpLeaderNodeId = ClusterInvalidNodeId;
  48. BOOL NmpCleanupIfJoinAborted = FALSE;
  49. BOOL NmpSuccessfulMMJoin = FALSE;
  50. DWORD NmpAddNodeId = ClusterInvalidNodeId;
  51. LPWSTR NmpClusterInstanceId = NULL;
  52. //externs
  53. extern DWORD CsMyHighestVersion;
  54. extern DWORD CsMyLowestVersion;
  55. extern DWORD CsClusterHighestVersion;
  56. extern DWORD CsClusterLowestVersion;
  57. GUM_DISPATCH_ENTRY NmGumDispatchTable[] = {
  58. {1, NmpUpdateCreateNode},
  59. {1, NmpUpdatePauseNode},
  60. {1, NmpUpdateResumeNode},
  61. {1, NmpUpdateEvictNode},
  62. {4, (PGUM_DISPATCH_ROUTINE1) NmpUpdateCreateNetwork},
  63. {2, (PGUM_DISPATCH_ROUTINE1) NmpUpdateSetNetworkName},
  64. {1, NmpUpdateSetNetworkPriorityOrder},
  65. {3, (PGUM_DISPATCH_ROUTINE1) NmpUpdateSetNetworkCommonProperties},
  66. {2, (PGUM_DISPATCH_ROUTINE1) NmpUpdateCreateInterface},
  67. {2, (PGUM_DISPATCH_ROUTINE1) NmpUpdateSetInterfaceInfo},
  68. {3, (PGUM_DISPATCH_ROUTINE1) NmpUpdateSetInterfaceCommonProperties},
  69. {1, NmpUpdateDeleteInterface},
  70. {3, (PGUM_DISPATCH_ROUTINE1) NmpUpdateJoinBegin},
  71. {2, (PGUM_DISPATCH_ROUTINE1) NmpUpdateJoinAbort},
  72. //
  73. // Version 2 (NT 5.0) extensions that are understood by NT4 SP4
  74. //
  75. {5, (PGUM_DISPATCH_ROUTINE1) NmpUpdateJoinBegin2},
  76. {4, (PGUM_DISPATCH_ROUTINE1) NmpUpdateSetNetworkAndInterfaceStates},
  77. {2, (PGUM_DISPATCH_ROUTINE1) NmpUpdatePerformFixups},
  78. {5, (PGUM_DISPATCH_ROUTINE1) NmpUpdatePerformFixups2},
  79. //
  80. // Version 2 (NT 5.0) extensions that are not understood by NT4 SP4
  81. // These may not be called in a mixed NT4/NT5 cluster.
  82. //
  83. {5, (PGUM_DISPATCH_ROUTINE1) NmpUpdateAddNode},
  84. {2, (PGUM_DISPATCH_ROUTINE1) NmpUpdateExtendedNodeState},
  85. //
  86. // NT 5.1 extensions that are not understood by NT5 and
  87. // earlier. NT5 nodes will ignore these updates without
  88. // error.
  89. //
  90. {4, (PGUM_DISPATCH_ROUTINE1) NmpUpdateSetNetworkMulticastConfiguration},
  91. };
  92. //
  93. // Local prototypes
  94. //
  95. DWORD
  96. NmpCreateRpcBindings(
  97. IN PNM_NODE Node
  98. );
  99. DWORD
  100. NmpCreateClusterInstanceId(
  101. VOID
  102. );
  103. //
  104. // Component initialization routines.
  105. //
  106. DWORD
  107. NmInitialize(
  108. VOID
  109. )
  110. /*++
  111. Routine Description:
  112. Initializes the Node Manager component.
  113. Arguments:
  114. None
  115. Return Value:
  116. A Win32 status code.
  117. Notes:
  118. The local node object is created by this routine.
  119. --*/
  120. {
  121. DWORD status;
  122. OM_OBJECT_TYPE_INITIALIZE nodeTypeInitializer;
  123. HDMKEY nodeKey = NULL;
  124. DWORD nameSize = CS_MAX_NODE_NAME_LENGTH + 1;
  125. HKEY serviceKey;
  126. DWORD nodeIdSize = (CS_MAX_NODE_ID_LENGTH + 1) *
  127. sizeof(WCHAR);
  128. LPWSTR nodeIdString = NULL;
  129. WSADATA wsaData;
  130. WORD versionRequested;
  131. int err;
  132. ULONG ndx;
  133. DWORD valueType;
  134. NM_NODE_INFO2 nodeInfo;
  135. WCHAR errorString[12];
  136. DWORD eventCode = 0;
  137. LPWSTR string;
  138. CL_ASSERT(NmpState == NmStateOffline);
  139. ClRtlLogPrint(LOG_NOISE,"[NM] Initializing...\n");
  140. //
  141. // Initialize globals.
  142. //
  143. InitializeCriticalSection(&NmpLock);
  144. InitializeListHead(&NmpNodeList);
  145. InitializeListHead(&NmpNetworkList);
  146. InitializeListHead(&NmpInternalNetworkList);
  147. InitializeListHead(&NmpDeletedNetworkList);
  148. InitializeListHead(&NmpInterfaceList);
  149. InitializeListHead(&NmpDeletedInterfaceList);
  150. NmMaxNodes = ClusterDefaultMaxNodes;
  151. NmMaxNodeId = ClusterMinNodeId + NmMaxNodes - 1;
  152. //
  153. // Initializing the RPC Recording/cancelling mechanism
  154. // NOTE - This should move if NmMaxNodeId Definition above moves.
  155. //
  156. NmpIntraClusterRpcArr = LocalAlloc(LMEM_FIXED,
  157. sizeof(NM_INTRACLUSTER_RPC_THREAD) * (NmMaxNodeId +1));
  158. if(NmpIntraClusterRpcArr == NULL) {
  159. ClRtlLogPrint(LOG_CRITICAL,
  160. "[NM] Failed to allocate memory for RPC monitoring.\n"
  161. );
  162. status = ERROR_NOT_ENOUGH_MEMORY;
  163. eventCode = CS_EVENT_ALLOCATION_FAILURE;
  164. goto error_exit;
  165. }
  166. else {
  167. ZeroMemory(NmpIntraClusterRpcArr,
  168. sizeof(NM_INTRACLUSTER_RPC_THREAD) * (NmMaxNodeId + 1));
  169. for(ndx = 0;ndx <= NmMaxNodeId;ndx++)
  170. InitializeListHead(&NmpIntraClusterRpcArr[ndx]);
  171. InitializeCriticalSection(&NmpRPCLock);
  172. }
  173. //
  174. // Initialize the network configuration package.
  175. //
  176. ClNetInitialize(
  177. ClNetPrint,
  178. ClNetLogEvent,
  179. ClNetLogEvent1,
  180. ClNetLogEvent2,
  181. ClNetLogEvent3
  182. );
  183. //
  184. // Initialize WinSock
  185. //
  186. versionRequested = MAKEWORD(2,0);
  187. err = WSAStartup(versionRequested, &wsaData);
  188. if (err != 0) {
  189. status = WSAGetLastError();
  190. wsprintfW(&(errorString[0]), L"%u", status);
  191. CsLogEvent1(LOG_CRITICAL, NM_EVENT_WSASTARTUP_FAILED, errorString);
  192. ClRtlLogPrint(LOG_NOISE,"[NM] Failed to initialize Winsock, status %1!u!\n", status);
  193. return(status);
  194. }
  195. if ( (LOBYTE(wsaData.wVersion) != 2) || (HIBYTE(wsaData.wVersion) != 0)) {
  196. status = WSAVERNOTSUPPORTED;
  197. wsprintfW(&(errorString[0]), L"%u", status);
  198. CsLogEvent1(LOG_CRITICAL, NM_EVENT_WSASTARTUP_FAILED, errorString);
  199. ClRtlLogPrint(LOG_CRITICAL,
  200. "[NM] Found unexpected Windows Sockets version %1!u!\n",
  201. wsaData.wVersion
  202. );
  203. WSACleanup();
  204. return(status);
  205. }
  206. NmpShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  207. if (NmpShutdownEvent == NULL) {
  208. status = GetLastError();
  209. wsprintfW(&(errorString[0]), L"%u", status);
  210. CsLogEvent1(LOG_CRITICAL, CS_EVENT_ALLOCATION_FAILURE, errorString);
  211. ClRtlLogPrint(LOG_CRITICAL,
  212. "[NM] Failed to create shutdown event, status %1!u!\n",
  213. status
  214. );
  215. WSACleanup();
  216. return(status);
  217. }
  218. NmpState = NmStateOnlinePending;
  219. //
  220. // Get the name of this node.
  221. //
  222. if (!GetComputerName(&(NmLocalNodeName[0]), &nameSize)) {
  223. status = GetLastError();
  224. eventCode = NM_EVENT_GETCOMPUTERNAME_FAILED;
  225. ClRtlLogPrint(LOG_CRITICAL,
  226. "[NM] Unable to get local computername, status %1!u!\n",
  227. status
  228. );
  229. goto error_exit;
  230. }
  231. ClRtlLogPrint(LOG_NOISE,
  232. "[NM] Local node name = %1!ws!.\n",
  233. NmLocalNodeName
  234. );
  235. //
  236. // Open a control channel to the Cluster Network driver
  237. //
  238. NmClusnetHandle = ClusnetOpenControlChannel(0);
  239. if (NmClusnetHandle == NULL) {
  240. status = GetLastError();
  241. eventCode = NM_EVENT_CLUSNET_UNAVAILABLE;
  242. ClRtlLogPrint(LOG_CRITICAL,
  243. "[NM] Unable to open a handle to the Cluster Network driver, status %1!u!\n",
  244. status
  245. );
  246. goto error_exit;
  247. }
  248. //
  249. // Tell the Cluster Network driver to shutdown when our handle is closed
  250. // in case the Cluster Service crashes.
  251. //
  252. status = ClusnetEnableShutdownOnClose(NmClusnetHandle);
  253. if (status != ERROR_SUCCESS) {
  254. eventCode = NM_EVENT_CLUSNET_ENABLE_SHUTDOWN_FAILED;
  255. ClRtlLogPrint(LOG_CRITICAL,
  256. "[NM] Unable to register Cluster Network shutdown trigger, status %1!u!\n",
  257. status
  258. );
  259. goto error_exit;
  260. }
  261. //
  262. // Allocate the node ID array.
  263. //
  264. CL_ASSERT(NmpIdArray == NULL);
  265. NmpIdArray = LocalAlloc(
  266. LMEM_FIXED,
  267. (sizeof(PNM_NODE) * (NmMaxNodeId + 1))
  268. );
  269. if (NmpIdArray == NULL) {
  270. status = ERROR_NOT_ENOUGH_MEMORY;
  271. eventCode = CS_EVENT_ALLOCATION_FAILURE;
  272. goto error_exit;
  273. }
  274. ZeroMemory(NmpIdArray, (sizeof(PNM_NODE) * (NmMaxNodeId + 1)));
  275. //
  276. // Create the node object type
  277. //
  278. ZeroMemory(&nodeTypeInitializer, sizeof(OM_OBJECT_TYPE_INITIALIZE));
  279. nodeTypeInitializer.ObjectSize = sizeof(NM_NODE);
  280. nodeTypeInitializer.Signature = NM_NODE_SIG;
  281. nodeTypeInitializer.Name = L"Node";
  282. nodeTypeInitializer.DeleteObjectMethod = NmpDestroyNodeObject;
  283. status = OmCreateType(ObjectTypeNode, &nodeTypeInitializer);
  284. if (status != ERROR_SUCCESS) {
  285. eventCode = CS_EVENT_ALLOCATION_FAILURE;
  286. ClRtlLogPrint(LOG_CRITICAL,
  287. "[NM] Unable to create node object type, status %1!u!\n",
  288. status
  289. );
  290. goto error_exit;
  291. }
  292. //
  293. // Get the local node ID from the local registry.
  294. //
  295. status = RegCreateKeyW(
  296. HKEY_LOCAL_MACHINE,
  297. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  298. &serviceKey
  299. );
  300. if (status != ERROR_SUCCESS) {
  301. wsprintfW(&(errorString[0]), L"%u", status);
  302. CsLogEvent2(
  303. LOG_CRITICAL,
  304. CS_EVENT_REG_OPEN_FAILED,
  305. CLUSREG_KEYNAME_CLUSSVC_PARAMETERS,
  306. errorString
  307. );
  308. ClRtlLogPrint(LOG_CRITICAL,
  309. "[NM] Failed to open cluster service parameters key, status %1!u!\n",
  310. status
  311. );
  312. goto error_exit;
  313. }
  314. string = L"NodeId";
  315. status = RegQueryValueExW(
  316. serviceKey,
  317. string,
  318. 0,
  319. &valueType,
  320. (LPBYTE) &(NmLocalNodeIdString[0]),
  321. &nodeIdSize
  322. );
  323. RegCloseKey(serviceKey);
  324. if (status != ERROR_SUCCESS) {
  325. wsprintfW(&(errorString[0]), L"%u", status);
  326. CsLogEvent2(
  327. LOG_CRITICAL,
  328. CS_EVENT_REG_QUERY_FAILED,
  329. string,
  330. errorString
  331. );
  332. ClRtlLogPrint(LOG_CRITICAL,
  333. "[NM] Failed to read local node ID from registry, status %1!u!\n",
  334. status
  335. );
  336. goto error_exit;
  337. }
  338. if (valueType != REG_SZ) {
  339. status = ERROR_INVALID_PARAMETER;
  340. wsprintfW(&(errorString[0]), L"%u", status);
  341. CsLogEvent2(
  342. LOG_CRITICAL,
  343. CS_EVENT_REG_QUERY_FAILED,
  344. string,
  345. errorString
  346. );
  347. ClRtlLogPrint(LOG_CRITICAL,
  348. "[NM] Local Node ID registry value is not of type REG_SZ.\n"
  349. );
  350. goto error_exit;
  351. }
  352. ClRtlLogPrint(LOG_NOISE,
  353. "[NM] Local node ID = %1!ws!.\n",
  354. NmLocalNodeIdString
  355. );
  356. NmLocalNodeId = wcstoul(NmLocalNodeIdString, NULL, 10);
  357. //
  358. // Get information about the local node.
  359. //
  360. wcscpy(&(nodeInfo.NodeId[0]), NmLocalNodeIdString);
  361. status = NmpGetNodeDefinition(&nodeInfo);
  362. if (status != ERROR_SUCCESS) {
  363. goto error_exit;
  364. }
  365. //
  366. // Create the local node object. We must do this here because GUM
  367. // requires the local node object to initialize.
  368. //
  369. status = NmpCreateLocalNodeObject(&nodeInfo);
  370. ClNetFreeNodeInfo(&nodeInfo);
  371. if (status != ERROR_SUCCESS) {
  372. goto error_exit;
  373. }
  374. //
  375. // Initialize the network and interface object types
  376. //
  377. status = NmpInitializeNetworks();
  378. if (status != ERROR_SUCCESS) {
  379. goto error_exit;
  380. }
  381. status = NmpInitializeInterfaces();
  382. if (status != ERROR_SUCCESS) {
  383. goto error_exit;
  384. }
  385. //
  386. // Initialize net PnP handling
  387. //
  388. status = NmpInitializePnp();
  389. if (status != ERROR_SUCCESS) {
  390. goto error_exit;
  391. }
  392. //
  393. // init the advise sink that tells when a connection object has been
  394. // renamed
  395. //
  396. status = NmpInitializeConnectoidAdviseSink();
  397. if (status != ERROR_SUCCESS) {
  398. goto error_exit;
  399. }
  400. ClRtlLogPrint(LOG_NOISE,"[NM] Initialization complete.\n");
  401. return(ERROR_SUCCESS);
  402. error_exit:
  403. if (eventCode != 0) {
  404. wsprintfW(&(errorString[0]), L"%u", status);
  405. CsLogEvent1(LOG_CRITICAL, eventCode, errorString);
  406. }
  407. wsprintfW( &(errorString[0]), L"%u", status );
  408. CsLogEvent1(LOG_CRITICAL, NM_INIT_FAILED, errorString);
  409. ClRtlLogPrint(LOG_CRITICAL,"[NM] Initialization failed %1!d!\n",status);
  410. NmShutdown();
  411. return(status);
  412. } // NmInitialize
  413. VOID
  414. NmShutdown(
  415. VOID
  416. )
  417. /*++
  418. Routine Description:
  419. Terminates all processing - shuts down all sources of work for
  420. worker threads.
  421. Arguments:
  422. Return Value:
  423. --*/
  424. {
  425. DWORD status;
  426. if (NmpState == NmStateOffline) {
  427. return;
  428. }
  429. NmCloseConnectoidAdviseSink();
  430. NmpShutdownPnp();
  431. NmpAcquireLock();
  432. ClRtlLogPrint(LOG_NOISE,"[NM] Shutdown starting...\n");
  433. NmpState = NmStateOfflinePending;
  434. if (NmpActiveThreadCount > 0) {
  435. ClRtlLogPrint(LOG_NOISE,
  436. "[NM] Waiting for %1!u! active threads to terminate...\n",
  437. NmpActiveThreadCount
  438. );
  439. NmpReleaseLock();
  440. status = WaitForSingleObject(NmpShutdownEvent, INFINITE);
  441. CL_ASSERT(status == WAIT_OBJECT_0);
  442. ClRtlLogPrint(LOG_NOISE,
  443. "[NM] All active threads have completed. Continuing shutdown...\n"
  444. );
  445. }
  446. else {
  447. NmpReleaseLock();
  448. }
  449. NmLeaveCluster();
  450. NmpCleanupPnp();
  451. if (NmLocalNode != NULL) {
  452. NmpDeleteNodeObject(NmLocalNode, FALSE);
  453. NmLocalNode = NULL;
  454. }
  455. if (NmpIdArray != NULL) {
  456. LocalFree(NmpIdArray); NmpIdArray = NULL;
  457. }
  458. NmpFreeClusterKey();
  459. if (NmpClusterInstanceId != NULL) {
  460. MIDL_user_free(NmpClusterInstanceId);
  461. NmpClusterInstanceId = NULL;
  462. }
  463. if (NmClusnetHandle != NULL) {
  464. ClusnetCloseControlChannel(NmClusnetHandle);
  465. NmClusnetHandle = NULL;
  466. }
  467. CloseHandle(NmpShutdownEvent); NmpShutdownEvent = NULL;
  468. WSACleanup();
  469. //
  470. // As long as the GUM and Clusapi RPC interfaces cannot be
  471. // shutdown, it is not safe to delete this critical section.
  472. //
  473. // DeleteCriticalSection(&NmpLock);
  474. NmpState = NmStateOffline;
  475. ClRtlLogPrint(LOG_NOISE,"[NM] Shutdown complete.\n");
  476. return;
  477. } // NmShutdown
  478. VOID
  479. NmLeaveCluster(
  480. VOID
  481. )
  482. /*++
  483. Routine Description:
  484. Arguments:
  485. Return Value:
  486. --*/
  487. {
  488. DWORD status;
  489. if (NmLocalNode != NULL) {
  490. if ( (NmLocalNode->State == ClusterNodeUp) ||
  491. (NmLocalNode->State == ClusterNodePaused) ||
  492. (NmLocalNode->State == ClusterNodeJoining)
  493. )
  494. {
  495. //
  496. // Leave the cluster.
  497. //
  498. ClRtlLogPrint(LOG_NOISE,"[NM] Leaving cluster.\n");
  499. MMLeave();
  500. #ifdef MM_IN_CLUSNET
  501. status = ClusnetLeaveCluster(NmClusnetHandle);
  502. CL_ASSERT(status == ERROR_SUCCESS);
  503. #endif // MM_IN_CLUSNET
  504. }
  505. }
  506. NmpMembershipShutdown();
  507. NmpCleanupInterfaces();
  508. NmpCleanupNetworks();
  509. NmpCleanupNodes();
  510. //
  511. // Shutdown the Cluster Network driver.
  512. //
  513. if (NmClusnetHandle != NULL) {
  514. DWORD status = ClusnetShutdown(NmClusnetHandle);
  515. if (status != ERROR_SUCCESS) {
  516. ClRtlLogPrint(LOG_UNUSUAL,
  517. "[NM] Shutdown of the Cluster Network driver failed, status %1!u!\n",
  518. status
  519. );
  520. }
  521. }
  522. if (NmpClusnetEndpoint != NULL) {
  523. MIDL_user_free(NmpClusnetEndpoint);
  524. NmpClusnetEndpoint = NULL;
  525. }
  526. return;
  527. } // NmLeaveCluster
  528. DWORD
  529. NmpCreateClusterObjects(
  530. IN RPC_BINDING_HANDLE JoinSponsorBinding
  531. )
  532. /*++
  533. Routine Description:
  534. Creates objects to represent the cluster's nodes, networks, and
  535. interfaces.
  536. Arguments:
  537. JoinSponsorBinding - A pointer to an RPC binding handle for the sponsor
  538. node if this node is joining a cluster. NULL if
  539. this node is forming a cluster.
  540. Return Value:
  541. ERROR_SUCCESS if the routine is successful.
  542. A Win32 error code otherwise.
  543. Notes:
  544. This routine MUST NOT be called with the NM lock held.
  545. --*/
  546. {
  547. DWORD status;
  548. PNM_NODE_ENUM2 nodeEnum = NULL;
  549. PNM_NETWORK_ENUM networkEnum = NULL;
  550. PNM_INTERFACE_ENUM2 interfaceEnum = NULL;
  551. PNM_NODE node = NULL;
  552. DWORD matchedNetworkCount = 0;
  553. DWORD newNetworkCount = 0;
  554. DWORD InitRetry = 2;
  555. WCHAR errorString[12];
  556. DWORD eventCode = 0;
  557. BOOL renameConnectoids;
  558. while ( InitRetry-- ) {
  559. //
  560. // Initialize the Cluster Network driver. This will clean up
  561. // any old state that was left around from the last run of the
  562. // Cluster Service. Note that the local node object is registered in
  563. // this call.
  564. //
  565. status = ClusnetInitialize(
  566. NmClusnetHandle,
  567. NmLocalNodeId,
  568. NmMaxNodes,
  569. NULL,
  570. NULL,
  571. NULL,
  572. NULL,
  573. NULL,
  574. NULL
  575. );
  576. if (status == ERROR_SUCCESS) {
  577. break;
  578. } else {
  579. ClRtlLogPrint(LOG_UNUSUAL,
  580. "[NM] Shutting down Cluster Network driver before retrying Initialization, status %1!u!\n",
  581. status);
  582. ClusnetShutdown( NmClusnetHandle );
  583. }
  584. };
  585. if ( status != ERROR_SUCCESS ) {
  586. eventCode = NM_EVENT_CLUSNET_INITIALIZE_FAILED;
  587. ClRtlLogPrint(LOG_CRITICAL,
  588. "[NM] Initialization of the Cluster Network driver failed, status %1!u!\n",
  589. status
  590. );
  591. goto error_exit;
  592. }
  593. //
  594. // Tell the Cluster Network driver to reserve the Cluster Network
  595. // endpoint on this node.
  596. //
  597. status = ClusnetReserveEndpoint(
  598. NmClusnetHandle,
  599. NmpClusnetEndpoint
  600. );
  601. if (status != ERROR_SUCCESS) {
  602. ClRtlLogPrint(LOG_CRITICAL,
  603. "[NM] Unable to reserve Clusnet Network endpoint %1!ws!, "
  604. "status %2!u!\n", NmpClusnetEndpoint, status
  605. );
  606. wsprintfW(&(errorString[0]), L"%u", status);
  607. CsLogEvent2(
  608. LOG_CRITICAL,
  609. NM_EVENT_CLUSNET_RESERVE_ENDPOINT_FAILED,
  610. NmpClusnetEndpoint,
  611. errorString
  612. );
  613. goto error_exit;
  614. }
  615. //
  616. // Obtain the node portion of the cluster database.
  617. //
  618. ClRtlLogPrint(LOG_NOISE,
  619. "[NM] Synchronizing node information.\n"
  620. );
  621. if (JoinSponsorBinding == NULL) {
  622. status = NmpEnumNodeDefinitions(&nodeEnum);
  623. }
  624. else {
  625. status = NmRpcEnumNodeDefinitions2(
  626. JoinSponsorBinding,
  627. NmpJoinSequence,
  628. NmLocalNodeIdString,
  629. &nodeEnum
  630. );
  631. }
  632. if (status != ERROR_SUCCESS) {
  633. eventCode = NM_EVENT_CONFIG_SYNCH_FAILED;
  634. ClRtlLogPrint(LOG_CRITICAL,
  635. "[NM] Unable to synchronize node information, status %1!u!.\n",
  636. status
  637. );
  638. goto error_exit;
  639. }
  640. //
  641. // Create the node objects.
  642. //
  643. ClRtlLogPrint(LOG_NOISE,
  644. "[NM] Creating node objects.\n"
  645. );
  646. status = NmpCreateNodeObjects(nodeEnum);
  647. if (status != ERROR_SUCCESS) {
  648. goto error_exit;
  649. }
  650. //
  651. // Obtain the networks portion of the cluster database.
  652. //
  653. ClRtlLogPrint(LOG_NOISE,
  654. "[NM] Synchronizing network information.\n"
  655. );
  656. if (JoinSponsorBinding == NULL) {
  657. status = NmpEnumNetworkDefinitions(&networkEnum);
  658. }
  659. else {
  660. status = NmRpcEnumNetworkDefinitions(
  661. JoinSponsorBinding,
  662. NmpJoinSequence,
  663. NmLocalNodeIdString,
  664. &networkEnum
  665. );
  666. }
  667. if (status != ERROR_SUCCESS) {
  668. eventCode = NM_EVENT_CONFIG_SYNCH_FAILED;
  669. ClRtlLogPrint(LOG_CRITICAL,
  670. "[NM] Unable to synchronize network information, status %1!u!.\n",
  671. status
  672. );
  673. goto error_exit;
  674. }
  675. //
  676. // Obtain the interfaces portion of the cluster database.
  677. //
  678. ClRtlLogPrint(LOG_NOISE,
  679. "[NM] Synchronizing interface information.\n"
  680. );
  681. if (JoinSponsorBinding == NULL) {
  682. status = NmpEnumInterfaceDefinitions(&interfaceEnum);
  683. }
  684. else {
  685. status = NmRpcEnumInterfaceDefinitions2(
  686. JoinSponsorBinding,
  687. NmpJoinSequence,
  688. NmLocalNodeIdString,
  689. &interfaceEnum
  690. );
  691. }
  692. if (status != ERROR_SUCCESS) {
  693. eventCode = NM_EVENT_CONFIG_SYNCH_FAILED;
  694. ClRtlLogPrint(LOG_CRITICAL,
  695. "[NM] Unable to synchronize interface information, status %1!u!.\n",
  696. status
  697. );
  698. goto error_exit;
  699. }
  700. if ( CsUpgrade ) {
  701. //
  702. // If this is an upgrade from NT4 to Whistler, then fix up the
  703. // connectoid names so they align with the cluster network
  704. // names.
  705. //
  706. // REMOVE THIS PORTION AFTER WHISTLER HAS SHIPPED.
  707. //
  708. if ( CLUSTER_GET_MAJOR_VERSION( NmLocalNode->HighestVersion ) <= NT4SP4_MAJOR_VERSION ) {
  709. renameConnectoids = TRUE;
  710. } else {
  711. //
  712. // upgrade from W2K to Whistler. Nothing should have changed but
  713. // if it did, connectoids should have precedence
  714. //
  715. renameConnectoids = FALSE;
  716. }
  717. } else {
  718. //
  719. // THIS SECTION MUST ALWAYS BE HERE
  720. //
  721. // if forming, cluster network objects are renamed to its
  722. // corresponding connectoid name. During a join, the opposite is true.
  723. //
  724. if ( JoinSponsorBinding ) {
  725. renameConnectoids = TRUE;
  726. } else {
  727. renameConnectoids = FALSE;
  728. }
  729. }
  730. //
  731. // Post a PnP notification ioctl. If we receive a PnP notification
  732. // before we finish initializing, we must restart the process.
  733. //
  734. NmpWatchForPnpEvents();
  735. if (status != ERROR_SUCCESS) {
  736. goto error_exit;
  737. }
  738. //
  739. // Run the network configuration engine. This will update the
  740. // cluster database.
  741. //
  742. status = NmpConfigureNetworks(
  743. JoinSponsorBinding,
  744. NmLocalNodeIdString,
  745. NmLocalNodeName,
  746. &networkEnum,
  747. &interfaceEnum,
  748. NmpClusnetEndpoint,
  749. &matchedNetworkCount,
  750. &newNetworkCount,
  751. renameConnectoids
  752. );
  753. if (status != ERROR_SUCCESS) {
  754. ClRtlLogPrint(LOG_CRITICAL,
  755. "[NM] Failed to configure networks & interfaces, status %1!u!.\n",
  756. status
  757. );
  758. goto error_exit;
  759. }
  760. ClRtlLogPrint(LOG_NOISE,
  761. "[NM] Matched %1!u! networks, created %2!u! new networks.\n",
  762. matchedNetworkCount,
  763. newNetworkCount
  764. );
  765. //
  766. // Get the updated network information from the database.
  767. //
  768. ClRtlLogPrint(LOG_NOISE,
  769. "[NM] Resynchronizing network information.\n"
  770. );
  771. if (JoinSponsorBinding == NULL) {
  772. status = NmpEnumNetworkDefinitions(&networkEnum);
  773. }
  774. else {
  775. status = NmRpcEnumNetworkDefinitions(
  776. JoinSponsorBinding,
  777. NmpJoinSequence,
  778. NmLocalNodeIdString,
  779. &networkEnum
  780. );
  781. }
  782. if (status != ERROR_SUCCESS) {
  783. eventCode = NM_EVENT_CONFIG_SYNCH_FAILED;
  784. ClRtlLogPrint(LOG_CRITICAL,
  785. "[NM] Unable to resynchronize network information, "
  786. "status %1!u!.\n",
  787. status
  788. );
  789. goto error_exit;
  790. }
  791. //
  792. // Get the updated interface information from the database.
  793. //
  794. ClRtlLogPrint(LOG_NOISE,
  795. "[NM] Resynchronizing interface information.\n"
  796. );
  797. if (JoinSponsorBinding == NULL) {
  798. status = NmpEnumInterfaceDefinitions(&interfaceEnum);
  799. }
  800. else {
  801. status = NmRpcEnumInterfaceDefinitions2(
  802. JoinSponsorBinding,
  803. NmpJoinSequence,
  804. NmLocalNodeIdString,
  805. &interfaceEnum
  806. );
  807. }
  808. if (status != ERROR_SUCCESS) {
  809. eventCode = NM_EVENT_CONFIG_SYNCH_FAILED;
  810. ClRtlLogPrint(LOG_CRITICAL,
  811. "[NM] Unable to resynchronize interface information, status %1!u!.\n",
  812. status
  813. );
  814. goto error_exit;
  815. }
  816. //
  817. // Create the network objects.
  818. //
  819. ClRtlLogPrint(LOG_NOISE,
  820. "[NM] Creating network objects.\n"
  821. );
  822. status = NmpCreateNetworkObjects(networkEnum);
  823. if (status != ERROR_SUCCESS) {
  824. ClRtlLogPrint(LOG_CRITICAL,
  825. "[NM] Failed to create network objects, status %1!u!.\n",
  826. status
  827. );
  828. goto error_exit;
  829. }
  830. //
  831. // Fixup the priorities of the internal networks if we are forming
  832. // a cluster.
  833. //
  834. if (JoinSponsorBinding == NULL) {
  835. DWORD networkCount;
  836. PNM_NETWORK * networkList;
  837. status = NmpEnumInternalNetworks(&networkCount, &networkList);
  838. if ((status == ERROR_SUCCESS) && (networkCount > 0)) {
  839. DWORD i;
  840. HLOCALXSACTION xaction;
  841. //
  842. // Begin a transaction - this must not be done while holding
  843. // the NM lock.
  844. //
  845. xaction = DmBeginLocalUpdate();
  846. if (xaction == NULL) {
  847. status = GetLastError();
  848. ClRtlLogPrint(LOG_CRITICAL,
  849. "[NM] Failed to start a transaction, status %1!u!\n",
  850. status
  851. );
  852. goto error_exit;
  853. }
  854. status = NmpSetNetworkPriorityOrder(
  855. networkCount,
  856. networkList,
  857. xaction
  858. );
  859. if (status == ERROR_SUCCESS) {
  860. DmCommitLocalUpdate(xaction);
  861. }
  862. else {
  863. DmAbortLocalUpdate(xaction);
  864. goto error_exit;
  865. }
  866. for (i=0; i<networkCount; i++) {
  867. if (networkList[i] != NULL) {
  868. OmDereferenceObject(networkList[i]);
  869. }
  870. }
  871. LocalFree(networkList);
  872. }
  873. }
  874. //
  875. // Create the interface objects.
  876. //
  877. ClRtlLogPrint(LOG_NOISE,
  878. "[NM] Creating interface objects.\n"
  879. );
  880. status = NmpCreateInterfaceObjects(interfaceEnum);
  881. if (status != ERROR_SUCCESS) {
  882. ClRtlLogPrint(LOG_CRITICAL,
  883. "[NM] Failed to create interface objects, status %1!u!.\n",
  884. status
  885. );
  886. goto error_exit;
  887. }
  888. if (JoinSponsorBinding != NULL) {
  889. //
  890. // The node must have connectivity to all active cluster nodes
  891. // in order to join a cluster.
  892. //
  893. PNM_NODE unreachableNode;
  894. if (!NmpVerifyJoinerConnectivity(NmLocalNode, &unreachableNode)) {
  895. status = ERROR_CLUSTER_NETWORK_NOT_FOUND;
  896. CsLogEvent1(
  897. LOG_CRITICAL,
  898. NM_EVENT_NODE_UNREACHABLE,
  899. OmObjectName(unreachableNode),
  900. );
  901. ClRtlLogPrint(LOG_CRITICAL,
  902. "[NM] Joining node cannot communicate with all other "
  903. "active nodes.\n"
  904. );
  905. goto error_exit;
  906. }
  907. }
  908. status = NmpMembershipInit();
  909. if (status != ERROR_SUCCESS) {
  910. goto error_exit;
  911. }
  912. error_exit:
  913. if (eventCode != 0) {
  914. wsprintfW(&(errorString[0]), L"%u", status);
  915. CsLogEvent1(LOG_CRITICAL, eventCode, errorString);
  916. }
  917. if (nodeEnum != NULL) {
  918. ClNetFreeNodeEnum(nodeEnum);
  919. }
  920. if (networkEnum != NULL) {
  921. ClNetFreeNetworkEnum(networkEnum);
  922. }
  923. if (interfaceEnum != NULL) {
  924. ClNetFreeInterfaceEnum(interfaceEnum);
  925. }
  926. return(status);
  927. } // NmpCreateClusterObjects
  928. //
  929. // Routines common to joining and forming.
  930. //
  931. DWORD
  932. NmpCreateClusterInstanceId(
  933. VOID
  934. )
  935. /*++
  936. Routine Description:
  937. Checks the cluster database for the cluster instance id. Creates
  938. if not present.
  939. --*/
  940. {
  941. DWORD status;
  942. LPWSTR clusterInstanceId = NULL;
  943. DWORD clusterInstanceIdBufSize = 0;
  944. DWORD clusterInstanceIdSize = 0;
  945. BOOLEAN found = FALSE;
  946. UUID guid;
  947. do {
  948. status = NmpQueryString(
  949. DmClusterParametersKey,
  950. L"ClusterInstanceID",
  951. REG_SZ,
  952. &clusterInstanceId,
  953. &clusterInstanceIdBufSize,
  954. &clusterInstanceIdSize
  955. );
  956. if (status == ERROR_SUCCESS) {
  957. found = TRUE;
  958. } else {
  959. ClRtlLogPrint(LOG_UNUSUAL,
  960. "[NMJOIN] Cluster Instance ID not found in "
  961. "cluster database, status %1!u!.\n",
  962. status
  963. );
  964. status = UuidCreate(&guid);
  965. if (status == RPC_S_OK) {
  966. status = UuidToString(&guid, &clusterInstanceId);
  967. if (status == RPC_S_OK) {
  968. status = DmSetValue(
  969. DmClusterParametersKey,
  970. L"ClusterInstanceID",
  971. REG_SZ,
  972. (PBYTE) clusterInstanceId,
  973. NM_WCSLEN(clusterInstanceId)
  974. );
  975. if (status != ERROR_SUCCESS) {
  976. ClRtlLogPrint(LOG_UNUSUAL,
  977. "[NMJOIN] Failed to store Cluster Instance ID "
  978. "in cluster database, status %1!u!.\n",
  979. status
  980. );
  981. }
  982. if (clusterInstanceId != NULL) {
  983. RpcStringFree(&clusterInstanceId);
  984. clusterInstanceId = NULL;
  985. }
  986. } else {
  987. ClRtlLogPrint(LOG_UNUSUAL,
  988. "[NMJOIN] Failed to convert Cluster Instance ID "
  989. "GUID into string, status %1!u!.\n",
  990. status
  991. );
  992. }
  993. } else {
  994. ClRtlLogPrint(LOG_UNUSUAL,
  995. "[NMJOIN] Failed to create Cluster Instance ID GUID, "
  996. "status %1!u!.\n",
  997. status
  998. );
  999. }
  1000. }
  1001. } while ( !found && (status == ERROR_SUCCESS) );
  1002. if (status == ERROR_SUCCESS) {
  1003. CL_ASSERT(clusterInstanceId != NULL);
  1004. NmpAcquireLock();
  1005. if (NmpClusterInstanceId == NULL) {
  1006. NmpClusterInstanceId = clusterInstanceId;
  1007. clusterInstanceId = NULL;
  1008. }
  1009. NmpReleaseLock();
  1010. }
  1011. if (clusterInstanceId != NULL) {
  1012. midl_user_free(clusterInstanceId);
  1013. clusterInstanceId = NULL;
  1014. }
  1015. return(status);
  1016. } // NmpCreateClusterInstanceId
  1017. //
  1018. // Routines for forming a new cluster.
  1019. //
  1020. DWORD
  1021. NmFormNewCluster(
  1022. VOID
  1023. )
  1024. {
  1025. DWORD status;
  1026. DWORD isPaused = FALSE;
  1027. DWORD pausedDefault = FALSE;
  1028. HDMKEY nodeKey;
  1029. DWORD valueLength, valueSize;
  1030. WCHAR errorString[12], errorString2[12];
  1031. DWORD eventCode = 0;
  1032. PLIST_ENTRY entry;
  1033. PNM_NETWORK network;
  1034. ClRtlLogPrint(LOG_NOISE,
  1035. "[NM] Beginning cluster form process.\n"
  1036. );
  1037. //
  1038. // Since this node is forming the cluster, it is the leader.
  1039. //
  1040. NmpLeaderNodeId = NmLocalNodeId;
  1041. //
  1042. // Read the clusnet endpoint override value from the registry, if it
  1043. // exists.
  1044. //
  1045. if (NmpClusnetEndpoint != NULL) {
  1046. MIDL_user_free(NmpClusnetEndpoint);
  1047. NmpClusnetEndpoint = NULL;
  1048. }
  1049. valueLength = 0;
  1050. status = NmpQueryString(
  1051. DmClusterParametersKey,
  1052. L"ClusnetEndpoint",
  1053. REG_SZ,
  1054. &NmpClusnetEndpoint,
  1055. &valueLength,
  1056. &valueSize
  1057. );
  1058. if (status == ERROR_SUCCESS) {
  1059. USHORT endpoint;
  1060. //
  1061. // Validate the value
  1062. //
  1063. status = ClRtlTcpipStringToEndpoint(
  1064. NmpClusnetEndpoint,
  1065. &endpoint
  1066. );
  1067. if (status != ERROR_SUCCESS) {
  1068. CsLogEvent2(
  1069. LOG_UNUSUAL,
  1070. NM_EVENT_INVALID_CLUSNET_ENDPOINT,
  1071. NmpClusnetEndpoint,
  1072. CLUSNET_DEFAULT_ENDPOINT_STRING
  1073. );
  1074. ClRtlLogPrint(
  1075. LOG_CRITICAL,
  1076. "[NM] '%1!ws!' is not valid endpoint value. Using default value %2!ws!.\n",
  1077. NmpClusnetEndpoint,
  1078. CLUSNET_DEFAULT_ENDPOINT_STRING
  1079. );
  1080. MIDL_user_free(NmpClusnetEndpoint);
  1081. NmpClusnetEndpoint = NULL;
  1082. }
  1083. }
  1084. if (status != ERROR_SUCCESS) {
  1085. NmpClusnetEndpoint = MIDL_user_allocate(
  1086. NM_WCSLEN(CLUSNET_DEFAULT_ENDPOINT_STRING)
  1087. );
  1088. if (NmpClusnetEndpoint == NULL) {
  1089. status = ERROR_NOT_ENOUGH_MEMORY;
  1090. wsprintfW(&(errorString[0]), L"%u", status);
  1091. CsLogEvent1(LOG_CRITICAL, CS_EVENT_ALLOCATION_FAILURE, errorString);
  1092. return(status);
  1093. }
  1094. lstrcpyW(NmpClusnetEndpoint, CLUSNET_DEFAULT_ENDPOINT_STRING);
  1095. }
  1096. //
  1097. // Create the node, network, and interface objects
  1098. //
  1099. status = NmpCreateClusterObjects(NULL);
  1100. if (status != ERROR_SUCCESS) {
  1101. goto error_exit;
  1102. }
  1103. //
  1104. // Perform version checking - check if we are compatible with the rest of the cluster
  1105. //
  1106. status = NmpIsNodeVersionAllowed(NmLocalNodeId, CsMyHighestVersion,
  1107. CsMyLowestVersion, FALSE);
  1108. if (status != ERROR_SUCCESS)
  1109. {
  1110. ClRtlLogPrint(LOG_CRITICAL,
  1111. "[NM] Version of Node %1!ws! is no longer compatible with other members of the cluster.\n",
  1112. NmLocalNodeIdString);
  1113. goto error_exit;
  1114. }
  1115. //If the forming node's version has changed, fix it up
  1116. status = NmpValidateNodeVersion(
  1117. NmLocalNodeIdString,
  1118. CsMyHighestVersion,
  1119. CsMyLowestVersion
  1120. );
  1121. if (status == ERROR_REVISION_MISMATCH)
  1122. {
  1123. //there was a version change, try and fix it up
  1124. status = NmpFormFixupNodeVersion(
  1125. NmLocalNodeIdString,
  1126. CsMyHighestVersion,
  1127. CsMyLowestVersion
  1128. );
  1129. NmLocalNodeVersionChanged = TRUE;
  1130. }
  1131. if (status != ERROR_SUCCESS)
  1132. {
  1133. goto error_exit;
  1134. }
  1135. //
  1136. //at this point we ready to calculate the cluster version
  1137. //all the node versions are in the registry, the fixups have
  1138. //been made if neccessary
  1139. //
  1140. NmpResetClusterVersion(FALSE);
  1141. NmpMulticastInitialize();
  1142. ClRtlLogPrint(LOG_NOISE,
  1143. "[NM] Forming cluster membership.\n"
  1144. );
  1145. status = MMJoin(
  1146. NmLocalNodeId,
  1147. NM_CLOCK_PERIOD,
  1148. NM_SEND_HB_RATE,
  1149. NM_RECV_HB_RATE,
  1150. NM_MM_JOIN_TIMEOUT
  1151. );
  1152. if (status != MM_OK) {
  1153. status = MMMapStatusToDosError(status);
  1154. eventCode = NM_EVENT_MM_FORM_FAILED;
  1155. ClRtlLogPrint(
  1156. LOG_CRITICAL,
  1157. "[NM] Membership form failed, status %1!u!. Unable to form a cluster.\n",
  1158. status
  1159. );
  1160. goto error_exit;
  1161. }
  1162. #ifdef MM_IN_CLUSNET
  1163. status = ClusnetFormCluster(
  1164. NmClusnetHandle,
  1165. NM_CLOCK_PERIOD,
  1166. NM_SEND_HB_RATE,
  1167. NM_RECV_HB_RATE
  1168. );
  1169. if (status != ERROR_SUCCESS) {
  1170. ClRtlLogPrint(
  1171. LOG_CRITICAL,
  1172. "[NM] Failed to form a cluster, status %1!u!.\n",
  1173. status
  1174. );
  1175. goto error_exit;
  1176. }
  1177. #endif // MM_IN_CLUSNET
  1178. //
  1179. // Check to see if we should come up in the paused state.
  1180. //
  1181. nodeKey = DmOpenKey(
  1182. DmNodesKey,
  1183. NmLocalNodeIdString,
  1184. KEY_READ
  1185. );
  1186. if (nodeKey != NULL) {
  1187. status = DmQueryDword(
  1188. nodeKey,
  1189. CLUSREG_NAME_NODE_PAUSED,
  1190. &isPaused,
  1191. &pausedDefault
  1192. );
  1193. if (status != ERROR_SUCCESS) {
  1194. ClRtlLogPrint(
  1195. LOG_UNUSUAL,
  1196. "[NM] Unable to query Paused value for local node, status %1!u!.\n",
  1197. status
  1198. );
  1199. }
  1200. DmCloseKey(nodeKey);
  1201. }
  1202. else {
  1203. ClRtlLogPrint(
  1204. LOG_UNUSUAL,
  1205. "[NM] Unable to open database key to local node, status %1!u!. Unable to determine Pause state.\n",
  1206. status
  1207. );
  1208. }
  1209. NmpAcquireLock();
  1210. if (isPaused) {
  1211. NmLocalNode->State = ClusterNodePaused;
  1212. } else {
  1213. NmLocalNode->State = ClusterNodeUp;
  1214. }
  1215. NmLocalNode->ExtendedState = ClusterNodeJoining;
  1216. NmpState = NmStateOnline;
  1217. NmpReleaseLock();
  1218. //
  1219. // If the cluster instance ID does not exist, create it now. The cluster
  1220. // instance ID should be in the database unless this is the first uplevel
  1221. // node.
  1222. //
  1223. NmpCreateClusterInstanceId();
  1224. //
  1225. // Create the cluster key.
  1226. //
  1227. status = NmpRegenerateClusterKey();
  1228. if (status != ERROR_SUCCESS) {
  1229. ClRtlLogPrint(LOG_UNUSUAL,
  1230. "[NM] Failed to generate cluster key, status %1!u!. "
  1231. "Allowing service to continue ...\n",
  1232. status
  1233. );
  1234. status = ERROR_SUCCESS;
  1235. }
  1236. //
  1237. // Enable communication for the local node.
  1238. //
  1239. status = ClusnetOnlineNodeComm(NmClusnetHandle, NmLocalNodeId);
  1240. if (status != ERROR_SUCCESS) {
  1241. wsprintfW(&(errorString[0]), L"%u", NmLocalNodeId);
  1242. wsprintfW(&(errorString2[0]), L"%u", status);
  1243. CsLogEvent2(
  1244. LOG_CRITICAL,
  1245. NM_EVENT_CLUSNET_ONLINE_COMM_FAILED,
  1246. errorString,
  1247. errorString2
  1248. );
  1249. ClRtlLogPrint(LOG_CRITICAL,
  1250. "[NM] Failed to enable communication for local node, status %1!u!\n",
  1251. status
  1252. );
  1253. goto error_exit;
  1254. }
  1255. GumReceiveUpdates(FALSE,
  1256. GumUpdateMembership,
  1257. NmpGumUpdateHandler,
  1258. NULL,
  1259. sizeof(NmGumDispatchTable)/sizeof(GUM_DISPATCH_ENTRY),
  1260. NmGumDispatchTable,
  1261. NULL
  1262. );
  1263. //
  1264. // Enable network PnP event handling.
  1265. //
  1266. // If a PnP event occured during the form process, an error code will
  1267. // be returned, which will abort startup of the service.
  1268. //
  1269. status = NmpEnablePnpEvents();
  1270. if (status != ERROR_SUCCESS) {
  1271. ClRtlLogPrint(LOG_UNUSUAL,
  1272. "[NM] A network PnP event occurred during form - abort.\n");
  1273. goto error_exit;
  1274. }
  1275. //
  1276. // Check if we formed without any viable networks. The form is still
  1277. // allowed, but we record an entry in the system event log.
  1278. //
  1279. if (!NmpCheckForNetwork()) {
  1280. ClRtlLogPrint(LOG_UNUSUAL,
  1281. "[NM] Formed cluster with no viable networks.\n"
  1282. );
  1283. CsLogEvent(LOG_UNUSUAL, NM_EVENT_FORM_WITH_NO_NETWORKS);
  1284. }
  1285. //
  1286. // Force a reconfiguration of multicast parameters and plumb
  1287. // the results in clusnet.
  1288. //
  1289. NmpAcquireLock();
  1290. if (NmpIsClusterMulticastReady(TRUE)) {
  1291. status = NmpStartMulticast(NULL);
  1292. if (status != ERROR_SUCCESS) {
  1293. ClRtlLogPrint(LOG_UNUSUAL,
  1294. "[NM] Failed to start multicast "
  1295. "on cluster networks, status %1!u!.\n",
  1296. status
  1297. );
  1298. //
  1299. // Not a de facto fatal error.
  1300. //
  1301. status = ERROR_SUCCESS;
  1302. }
  1303. }
  1304. NmpReleaseLock();
  1305. error_exit:
  1306. if (eventCode != 0) {
  1307. wsprintfW(&(errorString[0]), L"%u", status);
  1308. CsLogEvent1(LOG_CRITICAL, eventCode, errorString);
  1309. }
  1310. return(status);
  1311. } // NmFormNewCluster
  1312. //
  1313. //
  1314. // Client-side routines for joining a cluster.
  1315. //
  1316. //
  1317. DWORD
  1318. NmJoinCluster(
  1319. IN RPC_BINDING_HANDLE SponsorBinding
  1320. )
  1321. {
  1322. DWORD status;
  1323. DWORD sponsorNodeId;
  1324. PNM_INTERFACE netInterface;
  1325. PNM_NETWORK network;
  1326. PNM_NODE node;
  1327. PLIST_ENTRY nodeEntry, ifEntry;
  1328. WCHAR errorString[12], errorString2[12];
  1329. DWORD eventCode = 0;
  1330. DWORD versionFlags = 0;
  1331. extern BOOLEAN bFormCluster;
  1332. DWORD retry;
  1333. BOOLEAN joinBegin3 = TRUE;
  1334. LPWSTR clusterInstanceId = NULL;
  1335. ClRtlLogPrint(LOG_NOISE,
  1336. "[NMJOIN] Beginning cluster join process.\n"
  1337. );
  1338. // GN: If a node tries to restart immediately after a clean shutdown,
  1339. // NmRpcJoinBegin2 can fail with ERROR_CLUSTER_NODE_UP. Since the regroup
  1340. // incident caused by this node might not be finished.
  1341. //
  1342. // If we are getting error CLUSTER_NODE_UP, we will keep retrying for
  1343. // 12 seconds, hoping that regroup will finish.
  1344. retry = 120 / 3; // We sleep for 3 seconds. Need to wait 2 minutes //
  1345. for (;;) {
  1346. //
  1347. // Get the join sequence number so we can tell if the cluster
  1348. // configuration changes during the join process. We overload the
  1349. // use of the NmpJoinSequence variable since it isn't used in the
  1350. // sponsor capacity until the node joins.
  1351. //
  1352. //
  1353. // Try NmRpcJoinBegin3. If it fails with an RPC procnum out of
  1354. // range error, the sponsor is a downlevel node. Revert to
  1355. // NmRpcJoinBegin2.
  1356. //
  1357. if (joinBegin3) {
  1358. // Only read the cluster instance ID from the registry on
  1359. // the first try.
  1360. if (clusterInstanceId == NULL) {
  1361. DWORD clusterInstanceIdBufSize = 0;
  1362. DWORD clusterInstanceIdSize = 0;
  1363. status = NmpQueryString(
  1364. DmClusterParametersKey,
  1365. L"ClusterInstanceID",
  1366. REG_SZ,
  1367. &clusterInstanceId,
  1368. &clusterInstanceIdBufSize,
  1369. &clusterInstanceIdSize
  1370. );
  1371. if (status != ERROR_SUCCESS) {
  1372. ClRtlLogPrint(LOG_UNUSUAL,
  1373. "[NMJOIN] Failed to read cluster instance ID from database, status %1!u!.\n",
  1374. status
  1375. );
  1376. // Try to join with the downlevel interface. It is
  1377. // possible that this node was just upgraded and the
  1378. // last time it was in the cluster there was no
  1379. // cluster instance ID.
  1380. joinBegin3 = FALSE;
  1381. continue;
  1382. }
  1383. }
  1384. status = NmRpcJoinBegin3(
  1385. SponsorBinding,
  1386. clusterInstanceId,
  1387. NmLocalNodeIdString,
  1388. NmLocalNodeName,
  1389. CsMyHighestVersion,
  1390. CsMyLowestVersion,
  1391. 0, // joiner's major node version
  1392. 0, // joiner's minor node version
  1393. L"", // joiner's CsdVersion
  1394. 0, // joiner's product suite
  1395. &sponsorNodeId,
  1396. &NmpJoinSequence,
  1397. &NmpClusnetEndpoint
  1398. );
  1399. if (status == RPC_S_PROCNUM_OUT_OF_RANGE) {
  1400. // retry immediately with JoinBegin2
  1401. joinBegin3 = FALSE;
  1402. continue;
  1403. }
  1404. } else {
  1405. status = NmRpcJoinBegin2(
  1406. SponsorBinding,
  1407. NmLocalNodeIdString,
  1408. NmLocalNodeName,
  1409. CsMyHighestVersion,
  1410. CsMyLowestVersion,
  1411. &sponsorNodeId,
  1412. &NmpJoinSequence,
  1413. &NmpClusnetEndpoint
  1414. );
  1415. }
  1416. if ( ((status != ERROR_CLUSTER_NODE_UP
  1417. && status != ERROR_CLUSTER_JOIN_IN_PROGRESS) ) || retry == 0 )
  1418. {
  1419. break;
  1420. }
  1421. ClRtlLogPrint(LOG_UNUSUAL,
  1422. "[NMJOIN] Unable to begin join, status %1!u!. Retrying ...\n",
  1423. status
  1424. );
  1425. CsServiceStatus.dwCheckPoint++;
  1426. CsAnnounceServiceStatus();
  1427. Sleep(3000);
  1428. --retry;
  1429. }
  1430. // Free the cluster instance ID string, if necessary.
  1431. if (clusterInstanceId != NULL) {
  1432. midl_user_free(clusterInstanceId);
  1433. }
  1434. // [GORN Jan/7/2000]
  1435. // If we are here, then we have already successfully talked to the sponsor
  1436. // via JoinVersion interface.
  1437. //
  1438. // We shouldn't try to form the cluster if NmRpcJoinBegin2 fails.
  1439. // Otherwise we may steal the quorum on the move [452108]
  1440. //
  1441. // Past this point we will not try to form a cluster
  1442. //
  1443. bFormCluster = FALSE;
  1444. if (status != ERROR_SUCCESS) {
  1445. eventCode = NM_EVENT_BEGIN_JOIN_FAILED;
  1446. ClRtlLogPrint(LOG_CRITICAL,
  1447. "[NMJOIN] Unable to begin join, status %1!u!.\n",
  1448. status
  1449. );
  1450. goto error_exit;
  1451. }
  1452. ClRtlLogPrint(LOG_NOISE,
  1453. "[NMJOIN] Sponsor node ID = %1!u!. Join sequence number = %2!u!, endpoint = %3!ws!.\n",
  1454. sponsorNodeId,
  1455. NmpJoinSequence,
  1456. NmpClusnetEndpoint
  1457. );
  1458. //
  1459. // Create all of the cluster objects for which we are responsible.
  1460. //
  1461. status = NmpCreateClusterObjects(SponsorBinding);
  1462. if (status != ERROR_SUCCESS) {
  1463. goto error_exit;
  1464. }
  1465. // The local node version might have changed, fix it
  1466. // The sponsorer fixes it in the registry and tells other
  1467. // nodes about it, however the joining node is not a part
  1468. // of the cluster membership as yet.
  1469. // The local node structure is created early on in NmInitialize()
  1470. // hence it must get fixed up
  1471. if ((NmLocalNode->HighestVersion != CsMyHighestVersion) ||
  1472. (NmLocalNode->LowestVersion != CsMyLowestVersion))
  1473. {
  1474. ClRtlLogPrint(LOG_UNUSUAL,
  1475. "[NMJOIN] Local Node version changed probably due to upgrade/deinstall\n");
  1476. NmLocalNode->HighestVersion = CsMyHighestVersion;
  1477. NmLocalNode->LowestVersion = CsMyLowestVersion;
  1478. NmLocalNodeVersionChanged = TRUE;
  1479. }
  1480. //at this point we ready to calculate the cluster version
  1481. //all the node objects contain the correct node versions
  1482. NmpResetClusterVersion(FALSE);
  1483. NmpMulticastInitialize();
  1484. //
  1485. // Enable communication for the local node.
  1486. //
  1487. status = ClusnetOnlineNodeComm(NmClusnetHandle, NmLocalNodeId);
  1488. if (status != ERROR_SUCCESS) {
  1489. wsprintfW(&(errorString[0]), L"%u", NmLocalNodeId);
  1490. wsprintfW(&(errorString2[0]), L"%u", status);
  1491. CsLogEvent2(
  1492. LOG_CRITICAL,
  1493. NM_EVENT_CLUSNET_ONLINE_COMM_FAILED,
  1494. errorString,
  1495. errorString2
  1496. );
  1497. ClRtlLogPrint(LOG_CRITICAL,
  1498. "[NMJOIN] Unable to enable communication for local node, status %1!u!.\n",
  1499. status
  1500. );
  1501. goto error_exit;
  1502. }
  1503. //
  1504. // Fire up the intracluster RPC server so we can perform the membership
  1505. // join.
  1506. //
  1507. status = ClusterRegisterIntraclusterRpcInterface();
  1508. if ( status != ERROR_SUCCESS ) {
  1509. eventCode = CS_EVENT_RPC_INIT_FAILED;
  1510. ClRtlLogPrint(LOG_CRITICAL,
  1511. "ClusSvc: Error starting intracluster RPC server, Status = %1!u!\n",
  1512. status);
  1513. goto error_exit;
  1514. }
  1515. //
  1516. // Cycle through the list of cluster nodes and create mutual RPC bindings
  1517. // for the intracluster interface with each.
  1518. //
  1519. for (nodeEntry = NmpNodeList.Flink;
  1520. nodeEntry != &NmpNodeList;
  1521. nodeEntry = nodeEntry->Flink
  1522. )
  1523. {
  1524. node = CONTAINING_RECORD(nodeEntry, NM_NODE, Linkage);
  1525. if ( (node != NmLocalNode)
  1526. &&
  1527. ( (node->State == ClusterNodeUp)
  1528. ||
  1529. (node->State == ClusterNodePaused)
  1530. )
  1531. )
  1532. {
  1533. ClRtlLogPrint(LOG_NOISE,
  1534. "[NMJOIN] Creating RPC bindings for member node %1!u!\n",
  1535. node->NodeId
  1536. );
  1537. //
  1538. //
  1539. // Cycle through the target node's interfaces
  1540. //
  1541. for (ifEntry = node->InterfaceList.Flink;
  1542. ifEntry != &(node->InterfaceList);
  1543. ifEntry = ifEntry->Flink
  1544. )
  1545. {
  1546. netInterface = CONTAINING_RECORD(
  1547. ifEntry,
  1548. NM_INTERFACE,
  1549. NodeLinkage
  1550. );
  1551. network = netInterface->Network;
  1552. if (NmpIsNetworkForInternalUse(network)) {
  1553. if ( (network->LocalInterface != NULL) &&
  1554. NmpIsInterfaceRegistered(network->LocalInterface) &&
  1555. NmpIsInterfaceRegistered(netInterface)
  1556. )
  1557. {
  1558. PNM_INTERFACE localInterface = network->LocalInterface;
  1559. ClRtlLogPrint(LOG_NOISE,
  1560. "[NMJOIN] Attempting to use network %1!ws! to "
  1561. "create bindings for node %2!u!\n",
  1562. OmObjectName(network),
  1563. node->NodeId
  1564. );
  1565. status = NmpSetNodeInterfacePriority(
  1566. node,
  1567. 0xFFFFFFFF,
  1568. netInterface,
  1569. 1
  1570. );
  1571. if (status == ERROR_SUCCESS) {
  1572. status = NmRpcCreateBinding(
  1573. SponsorBinding,
  1574. NmpJoinSequence,
  1575. NmLocalNodeIdString,
  1576. (LPWSTR) OmObjectId(localInterface),
  1577. (LPWSTR) OmObjectId(node)
  1578. );
  1579. if (status == ERROR_SUCCESS) {
  1580. //
  1581. // Create RPC bindings for the target node.
  1582. //
  1583. status = NmpCreateRpcBindings(node);
  1584. if (status == ERROR_SUCCESS) {
  1585. ClRtlLogPrint(LOG_NOISE,
  1586. "[NMJOIN] Created binding for node "
  1587. "%1!u!\n",
  1588. node->NodeId
  1589. );
  1590. break;
  1591. }
  1592. wsprintfW(&(errorString[0]), L"%u", status);
  1593. CsLogEvent3(
  1594. LOG_UNUSUAL,
  1595. NM_EVENT_JOIN_BIND_OUT_FAILED,
  1596. OmObjectName(node),
  1597. OmObjectName(network),
  1598. errorString
  1599. );
  1600. ClRtlLogPrint(LOG_UNUSUAL,
  1601. "[NMJOIN] Unable to create binding for "
  1602. "node %1!u!, status %2!u!.\n",
  1603. node->NodeId,
  1604. status
  1605. );
  1606. }
  1607. else {
  1608. wsprintfW(&(errorString[0]), L"%u", status);
  1609. CsLogEvent3(
  1610. LOG_UNUSUAL,
  1611. NM_EVENT_JOIN_BIND_IN_FAILED,
  1612. OmObjectName(node),
  1613. OmObjectName(network),
  1614. errorString
  1615. );
  1616. ClRtlLogPrint(LOG_CRITICAL,
  1617. "[NMJOIN] Member node %1!u! failed to "
  1618. "create binding to us, status %2!u!\n",
  1619. node->NodeId,
  1620. status
  1621. );
  1622. }
  1623. }
  1624. else {
  1625. wsprintfW(&(errorString[0]), L"%u", node->NodeId);
  1626. wsprintfW(&(errorString2[0]), L"%u", status);
  1627. CsLogEvent2(
  1628. LOG_UNUSUAL,
  1629. NM_EVENT_CLUSNET_SET_INTERFACE_PRIO_FAILED,
  1630. errorString,
  1631. errorString2
  1632. );
  1633. ClRtlLogPrint(LOG_CRITICAL,
  1634. "[NMJOIN] Failed to set interface priorities "
  1635. "for node %1!u!, status %2!u!\n",
  1636. node->NodeId,
  1637. status
  1638. );
  1639. }
  1640. }
  1641. else {
  1642. status = ERROR_CLUSTER_NODE_UNREACHABLE;
  1643. ClRtlLogPrint(LOG_NOISE,
  1644. "[NMJOIN] No matching local interface for "
  1645. "network %1!ws!\n",
  1646. OmObjectName(netInterface->Network)
  1647. );
  1648. }
  1649. }
  1650. else {
  1651. status = ERROR_CLUSTER_NODE_UNREACHABLE;
  1652. ClRtlLogPrint(LOG_NOISE,
  1653. "[NMJOIN] Network %1!ws! is not used for internal "
  1654. "communication.\n",
  1655. OmObjectName(netInterface->Network)
  1656. );
  1657. }
  1658. }
  1659. if (status != ERROR_SUCCESS) {
  1660. //
  1661. // Cannot make contact with this node. The join fails.
  1662. //
  1663. CsLogEvent1(
  1664. LOG_CRITICAL,
  1665. NM_EVENT_NODE_UNREACHABLE,
  1666. OmObjectName(node)
  1667. );
  1668. ClRtlLogPrint(LOG_NOISE,
  1669. "[NMJOIN] Cluster node %1!u! is not reachable. Join "
  1670. "failed.\n",
  1671. node->NodeId
  1672. );
  1673. goto error_exit;
  1674. }
  1675. }
  1676. }
  1677. CL_ASSERT(status == ERROR_SUCCESS);
  1678. //
  1679. // run through the active nodes again, this time establishing
  1680. // security contexts to use in signing packets
  1681. //
  1682. ClRtlLogPrint(LOG_NOISE,
  1683. "[NMJOIN] Establishing security contexts with all active nodes.\n"
  1684. );
  1685. for (nodeEntry = NmpNodeList.Flink;
  1686. nodeEntry != &NmpNodeList;
  1687. nodeEntry = nodeEntry->Flink
  1688. )
  1689. {
  1690. node = CONTAINING_RECORD(nodeEntry, NM_NODE, Linkage);
  1691. status = ClMsgCreateActiveNodeSecurityContext(NmpJoinSequence, node);
  1692. if ( status != ERROR_SUCCESS ) {
  1693. wsprintfW(&(errorString[0]), L"%u", status);
  1694. CsLogEvent2(
  1695. LOG_UNUSUAL,
  1696. NM_EVENT_CREATE_SECURITY_CONTEXT_FAILED,
  1697. OmObjectName(node),
  1698. errorString
  1699. );
  1700. ClRtlLogPrint(LOG_CRITICAL,
  1701. "[NMJOIN] Unable to establish security context for node %1!u!, status 0x%2!08X!\n",
  1702. node->NodeId,
  1703. status
  1704. );
  1705. goto error_exit;
  1706. }
  1707. }
  1708. //
  1709. // Finally, petition the sponsor for membership
  1710. //
  1711. ClRtlLogPrint(LOG_NOISE,
  1712. "[NMJOIN] Petitioning to join cluster membership.\n"
  1713. );
  1714. #ifdef CLUSTER_TESTPOINT
  1715. TESTPT(TpFailJoinPetitionForMembership) {
  1716. status = 999999;
  1717. goto error_exit;
  1718. }
  1719. #endif
  1720. status = NmRpcPetitionForMembership(
  1721. SponsorBinding,
  1722. NmpJoinSequence,
  1723. NmLocalNodeIdString
  1724. );
  1725. if (status != ERROR_SUCCESS) {
  1726. //
  1727. // Our petition was denied.
  1728. //
  1729. eventCode = NM_EVENT_PETITION_FAILED;
  1730. ClRtlLogPrint(LOG_CRITICAL,
  1731. "[NMJOIN] Petition to join was denied %1!d!\n",
  1732. status
  1733. );
  1734. goto error_exit;
  1735. }
  1736. #ifdef CLUSTER_TESTPOINT
  1737. TESTPT(TpFailNmJoin) {
  1738. status = 999999;
  1739. goto error_exit;
  1740. }
  1741. #endif
  1742. //
  1743. // Reset the interface priorities for all nodes to default to
  1744. // the priorities of the associated networks.
  1745. //
  1746. NmpAcquireLock();
  1747. for (ifEntry = NmpInterfaceList.Flink;
  1748. ifEntry != &NmpInterfaceList;
  1749. ifEntry = ifEntry->Flink
  1750. )
  1751. {
  1752. netInterface = CONTAINING_RECORD(ifEntry, NM_INTERFACE, Linkage);
  1753. network = netInterface->Network;
  1754. if ( NmpIsNetworkForInternalUse(network) &&
  1755. NmpIsInterfaceRegistered(netInterface)
  1756. )
  1757. {
  1758. status = ClusnetSetInterfacePriority(
  1759. NmClusnetHandle,
  1760. netInterface->Node->NodeId,
  1761. netInterface->Network->ShortId,
  1762. 0
  1763. );
  1764. CL_ASSERT(status == ERROR_SUCCESS);
  1765. }
  1766. }
  1767. NmpState = NmStateOnline;
  1768. NmpReleaseLock();
  1769. //
  1770. // Invoke other components to create RPC bindings for each node.
  1771. //
  1772. //
  1773. // Enable our GUM update handler.
  1774. //
  1775. GumReceiveUpdates(
  1776. TRUE,
  1777. GumUpdateMembership,
  1778. NmpGumUpdateHandler,
  1779. NULL,
  1780. sizeof(NmGumDispatchTable)/sizeof(GUM_DISPATCH_ENTRY),
  1781. NmGumDispatchTable,
  1782. NULL
  1783. );
  1784. return(ERROR_SUCCESS);
  1785. error_exit:
  1786. if (eventCode != 0) {
  1787. wsprintfW(&(errorString[0]), L"%u", status);
  1788. CsLogEvent1(LOG_CRITICAL, eventCode, errorString);
  1789. }
  1790. return(status);
  1791. } // NmJoinCluster
  1792. BOOLEAN
  1793. NmpVerifyJoinerConnectivity(
  1794. IN PNM_NODE JoiningNode,
  1795. OUT PNM_NODE * UnreachableNode
  1796. )
  1797. {
  1798. PLIST_ENTRY entry;
  1799. PNM_NODE node;
  1800. ClRtlLogPrint(LOG_NOISE,
  1801. "[NMJOIN] Verifying connectivity to active cluster nodes\n"
  1802. );
  1803. *UnreachableNode = NULL;
  1804. for (entry = NmpNodeList.Flink;
  1805. entry != &NmpNodeList;
  1806. entry = entry->Flink
  1807. )
  1808. {
  1809. node = CONTAINING_RECORD(
  1810. entry,
  1811. NM_NODE,
  1812. Linkage
  1813. );
  1814. if (NM_NODE_UP(node)) {
  1815. if (!NmpVerifyNodeConnectivity(JoiningNode, node, NULL)) {
  1816. *UnreachableNode = node;
  1817. return(FALSE);
  1818. }
  1819. }
  1820. }
  1821. return(TRUE);
  1822. } // NmpVerifyJoinerConnectivity
  1823. DWORD
  1824. NmGetJoinSequence(
  1825. VOID
  1826. )
  1827. {
  1828. DWORD sequence;
  1829. NmpAcquireLock();
  1830. sequence = NmpJoinSequence;
  1831. NmpReleaseLock();
  1832. return(sequence);
  1833. } // NmGetJoinSequence
  1834. DWORD
  1835. NmJoinComplete(
  1836. OUT DWORD *EndSeq
  1837. )
  1838. /*++
  1839. Routine Description:
  1840. This routine is called by the initialization sequence once a
  1841. join has successfully completed and the node can transition
  1842. from ClusterNodeJoining to ClusterNodeOnline.
  1843. Arguments:
  1844. None
  1845. Return Value:
  1846. ERROR_SUCCESS if successful
  1847. Win32 error otherwise.
  1848. --*/
  1849. {
  1850. DWORD Sequence;
  1851. DWORD Status;
  1852. PNM_JOIN_UPDATE JoinUpdate = NULL;
  1853. DWORD UpdateLength;
  1854. HDMKEY NodeKey = NULL;
  1855. DWORD Default = 0;
  1856. DWORD NumRetries=50;
  1857. DWORD eventCode = 0;
  1858. WCHAR errorString[12];
  1859. PNM_NETWORK_STATE_ENUM networkStateEnum = NULL;
  1860. PNM_NETWORK_STATE_INFO networkStateInfo;
  1861. PNM_INTERFACE_STATE_ENUM interfaceStateEnum = NULL;
  1862. PNM_INTERFACE_STATE_INFO interfaceStateInfo;
  1863. DWORD i;
  1864. PNM_NETWORK network;
  1865. PNM_INTERFACE netInterface;
  1866. PLIST_ENTRY entry;
  1867. DWORD moveCount;
  1868. BOOLEAN mcast;
  1869. UpdateLength = sizeof(NM_JOIN_UPDATE) +
  1870. (lstrlenW(OmObjectId(NmLocalNode))+1)*sizeof(WCHAR);
  1871. JoinUpdate = LocalAlloc(LMEM_FIXED, UpdateLength);
  1872. if (JoinUpdate == NULL) {
  1873. Status = ERROR_NOT_ENOUGH_MEMORY;
  1874. eventCode = CS_EVENT_ALLOCATION_FAILURE;
  1875. ClRtlLogPrint(LOG_CRITICAL, "[NMJOIN] Unable to allocate memory.\n");
  1876. goto error_exit;
  1877. }
  1878. JoinUpdate->JoinSequence = NmpJoinSequence;
  1879. lstrcpyW(JoinUpdate->NodeId, OmObjectId(NmLocalNode));
  1880. NodeKey = DmOpenKey(DmNodesKey, OmObjectId(NmLocalNode), KEY_READ);
  1881. if (NodeKey == NULL) {
  1882. Status = GetLastError();
  1883. wsprintfW(&(errorString[0]), L"%u", Status);
  1884. CsLogEvent2(
  1885. LOG_CRITICAL,
  1886. CS_EVENT_REG_OPEN_FAILED,
  1887. OmObjectId(NmLocalNode),
  1888. errorString
  1889. );
  1890. ClRtlLogPrint(
  1891. LOG_CRITICAL,
  1892. "[NMJOIN] Unable to open database key to local node, status %1!u!.\n",
  1893. Status
  1894. );
  1895. goto error_exit;
  1896. }
  1897. retry:
  1898. Status = GumBeginJoinUpdate(GumUpdateMembership, &Sequence);
  1899. if (Status != ERROR_SUCCESS) {
  1900. eventCode = NM_EVENT_GENERAL_JOIN_ERROR;
  1901. goto error_exit;
  1902. }
  1903. //
  1904. // Get the leader node ID from the sponsor.
  1905. //
  1906. Status = NmRpcGetLeaderNodeId(
  1907. CsJoinSponsorBinding,
  1908. NmpJoinSequence,
  1909. NmLocalNodeIdString,
  1910. &NmpLeaderNodeId
  1911. );
  1912. if (Status != ERROR_SUCCESS) {
  1913. if (Status == ERROR_CALL_NOT_IMPLEMENTED) {
  1914. //
  1915. // The sponsor is an NT4 node. Make this node the leader.
  1916. //
  1917. NmpLeaderNodeId = NmLocalNodeId;
  1918. }
  1919. else {
  1920. ClRtlLogPrint(LOG_CRITICAL,
  1921. "[NMJOIN] Failed to get leader node ID from sponsor, status %1!u!.\n",
  1922. Status
  1923. );
  1924. goto error_exit;
  1925. }
  1926. }
  1927. ClRtlLogPrint(LOG_NOISE,
  1928. "[NMJOIN] Node %1!u! is the leader.\n",
  1929. NmpLeaderNodeId
  1930. );
  1931. //
  1932. // Fetch the network and interface states from the sponsor
  1933. //
  1934. Status = NmRpcEnumNetworkAndInterfaceStates(
  1935. CsJoinSponsorBinding,
  1936. NmpJoinSequence,
  1937. NmLocalNodeIdString,
  1938. &networkStateEnum,
  1939. &interfaceStateEnum
  1940. );
  1941. if (Status != ERROR_SUCCESS) {
  1942. ClRtlLogPrint(LOG_CRITICAL,
  1943. "[NMJOIN] Failed to get network and interface state values from sponsor, status %1!u!.\n",
  1944. Status
  1945. );
  1946. goto error_exit;
  1947. }
  1948. NmpAcquireLock();
  1949. for (i=0; i<networkStateEnum->NetworkCount; i++) {
  1950. networkStateInfo = &(networkStateEnum->NetworkList[i]);
  1951. network = OmReferenceObjectById(
  1952. ObjectTypeNetwork,
  1953. networkStateInfo->Id
  1954. );
  1955. if (network == NULL) {
  1956. ClRtlLogPrint(LOG_CRITICAL,
  1957. "[NMJOIN] Cannot find network %1!ws! to update state.\n",
  1958. networkStateInfo->Id
  1959. );
  1960. NmpReleaseLock();
  1961. NmpFreeNetworkStateEnum(networkStateEnum);
  1962. LocalFree(JoinUpdate);
  1963. DmCloseKey(NodeKey);
  1964. return(ERROR_CLUSTER_NETWORK_NOT_FOUND);
  1965. }
  1966. network->State = networkStateInfo->State;
  1967. OmDereferenceObject(network);
  1968. }
  1969. for (i=0; i<interfaceStateEnum->InterfaceCount; i++) {
  1970. interfaceStateInfo = &(interfaceStateEnum->InterfaceList[i]);
  1971. netInterface = OmReferenceObjectById(
  1972. ObjectTypeNetInterface,
  1973. interfaceStateInfo->Id
  1974. );
  1975. if (netInterface == NULL) {
  1976. ClRtlLogPrint(LOG_CRITICAL,
  1977. "[NMJOIN] Cannot find interface %1!ws! to update state.\n",
  1978. interfaceStateInfo->Id
  1979. );
  1980. NmpReleaseLock();
  1981. NmpFreeInterfaceStateEnum(interfaceStateEnum);
  1982. LocalFree(JoinUpdate);
  1983. DmCloseKey(NodeKey);
  1984. return(ERROR_CLUSTER_NETINTERFACE_NOT_FOUND);
  1985. }
  1986. netInterface->State = interfaceStateInfo->State;
  1987. OmDereferenceObject(netInterface);
  1988. }
  1989. NmpReleaseLock();
  1990. NmpFreeInterfaceStateEnum(interfaceStateEnum);
  1991. interfaceStateEnum = NULL;
  1992. //
  1993. // Check the registry to see if we should come up paused.
  1994. //
  1995. JoinUpdate->IsPaused = Default;
  1996. Status = DmQueryDword(NodeKey,
  1997. CLUSREG_NAME_NODE_PAUSED,
  1998. &JoinUpdate->IsPaused,
  1999. &Default);
  2000. if (Status != ERROR_SUCCESS) {
  2001. ClRtlLogPrint(LOG_UNUSUAL,
  2002. "[NMJOIN] Unable to query Paused value for local node, status %1!u!.\n",
  2003. Status
  2004. );
  2005. }
  2006. Status = GumEndJoinUpdate(Sequence,
  2007. GumUpdateMembership,
  2008. NmUpdateJoinComplete,
  2009. UpdateLength,
  2010. JoinUpdate);
  2011. if (Status != ERROR_SUCCESS) {
  2012. if (Status == ERROR_CLUSTER_JOIN_ABORTED) {
  2013. //
  2014. // The join was aborted by the cluster members. Don't retry.
  2015. //
  2016. CsLogEvent(LOG_CRITICAL, NM_EVENT_JOIN_ABORTED);
  2017. goto error_exit;
  2018. }
  2019. ClRtlLogPrint(LOG_UNUSUAL,
  2020. "[NMJOIN] GumEndJoinUpdate with sequence %1!d! failed %2!d!\n",
  2021. Sequence,
  2022. Status
  2023. );
  2024. if (--NumRetries == 0) {
  2025. CsLogEvent(LOG_CRITICAL, NM_EVENT_JOIN_ABANDONED);
  2026. ClRtlLogPrint(LOG_UNUSUAL,
  2027. "[NMJOIN] Tried to complete join too many times. Giving up.\n"
  2028. );
  2029. goto error_exit;
  2030. }
  2031. goto retry;
  2032. }
  2033. NmpAcquireLock();
  2034. if (JoinUpdate->IsPaused != 0) {
  2035. //
  2036. // We should be coming up paused.
  2037. //
  2038. NmLocalNode->State = ClusterNodePaused;
  2039. } else {
  2040. //
  2041. // Set our state to online.
  2042. //
  2043. NmLocalNode->State = ClusterNodeUp;
  2044. }
  2045. //
  2046. // Remember whether this cluster meets multicast criteria.
  2047. //
  2048. mcast = NmpIsClusterMulticastReady(TRUE);
  2049. NmpReleaseLock();
  2050. //
  2051. // If the cluster instance ID does not exist, create it now. The cluster
  2052. // instance ID should be in the database unless this is the first uplevel
  2053. // node.
  2054. //
  2055. NmpCreateClusterInstanceId();
  2056. //
  2057. // Create the cluster key.
  2058. //
  2059. Status = NmpRegenerateClusterKey();
  2060. if (Status != ERROR_SUCCESS) {
  2061. ClRtlLogPrint(LOG_UNUSUAL,
  2062. "[NM] Failed to generate cluster key, status %1!u!. "
  2063. "Allowing service to continue ...\n",
  2064. Status
  2065. );
  2066. Status = ERROR_SUCCESS;
  2067. }
  2068. //
  2069. // Finally, enable network PnP event handling.
  2070. //
  2071. // If a PnP event occured during the join process, an error code will
  2072. // be returned, which will abort startup of the service.
  2073. //
  2074. Status = NmpEnablePnpEvents();
  2075. if (Status != ERROR_SUCCESS) {
  2076. ClRtlLogPrint(LOG_UNUSUAL,
  2077. "[NMJOIN] A network PnP event occurred during join - abort.\n");
  2078. goto error_exit;
  2079. }
  2080. //
  2081. // Mark end sequence
  2082. *EndSeq = Sequence;
  2083. ClRtlLogPrint(LOG_NOISE, "[NMJOIN] Join complete, node now online\n");
  2084. if (mcast) {
  2085. Status = NmpRefreshClusterMulticastConfiguration();
  2086. if (Status != ERROR_SUCCESS) {
  2087. ClRtlLogPrint(LOG_UNUSUAL,
  2088. "[NM] Failed to refresh multicast configuration "
  2089. "for cluster networks, status %1!u!.\n",
  2090. Status
  2091. );
  2092. //
  2093. // Not a de facto fatal error.
  2094. //
  2095. Status = ERROR_SUCCESS;
  2096. }
  2097. }
  2098. error_exit:
  2099. if (JoinUpdate != NULL) {
  2100. LocalFree(JoinUpdate);
  2101. }
  2102. if (NodeKey != NULL) {
  2103. DmCloseKey(NodeKey);
  2104. }
  2105. if (eventCode != 0) {
  2106. wsprintfW(&(errorString[0]), L"%u", Status);
  2107. CsLogEvent1(LOG_CRITICAL, eventCode, errorString);
  2108. }
  2109. return(Status);
  2110. } // NmJoinComplete
  2111. //
  2112. // Server-side routines for sponsoring a joining node.
  2113. //
  2114. /*
  2115. Notes On Joining:
  2116. Only a single node may join the cluster at any time. A join begins with
  2117. a JoinBegin global update. A join completes successfully with a
  2118. JoinComplete global update. A join is aborted with a JoinAbort global
  2119. update.
  2120. A timer runs on the sponsor during a join. The timer is suspended
  2121. while the sponsor is performing work on behalf of the joiner. If the
  2122. timer expires, a worker thread is scheduled to initiate the abort
  2123. process.
  2124. If the sponsor goes down while a join is in progress, the node
  2125. down handling code on each remaining node will abort the join.
  2126. */
  2127. error_status_t
  2128. s_NmRpcJoinBegin(
  2129. IN handle_t IDL_handle,
  2130. IN LPWSTR JoinerNodeId,
  2131. IN LPWSTR JoinerNodeName,
  2132. OUT LPDWORD SponsorNodeId,
  2133. OUT LPDWORD JoinSequenceNumber,
  2134. OUT LPWSTR * ClusnetEndpoint
  2135. )
  2136. /*++
  2137. Routine Description:
  2138. Called by a joining node to begin the join process.
  2139. Issues a JoinBegin global update.
  2140. --*/
  2141. {
  2142. DWORD status=ERROR_CLUSTER_INCOMPATIBLE_VERSIONS;
  2143. ClRtlLogPrint(LOG_NOISE,
  2144. "[NMJOIN] Request by node %1!ws! to begin joining, refused. Using obsolete join interface\n",
  2145. JoinerNodeId
  2146. );
  2147. if ( status != ERROR_SUCCESS ) {
  2148. WCHAR errorCode[16];
  2149. wsprintfW( errorCode, L"%u", status );
  2150. CsLogEvent2(
  2151. LOG_CRITICAL,
  2152. NM_EVENT_JOIN_REFUSED,
  2153. JoinerNodeId,
  2154. errorCode
  2155. );
  2156. }
  2157. return(status);
  2158. } // s_NmRpcJoinBegin
  2159. //
  2160. // Server-side routines for sponsoring a joining node.
  2161. //
  2162. /*
  2163. Notes On Joining:
  2164. */
  2165. //#pragma optimize("", off)
  2166. DWORD
  2167. NmpJoinBegin(
  2168. IN LPWSTR JoinerNodeId,
  2169. IN LPWSTR JoinerNodeName,
  2170. IN DWORD JoinerHighestVersion,
  2171. IN DWORD JoinerLowestVersion,
  2172. OUT LPDWORD SponsorNodeId,
  2173. OUT LPDWORD JoinSequenceNumber,
  2174. OUT LPWSTR * ClusnetEndpoint
  2175. )
  2176. /*++
  2177. Routine Description:
  2178. Called from s_NmRpcJoinBegin2 and s_NmRpcJoinBegin3.
  2179. Contains functionality common to both JoinBegin versions.
  2180. Notes:
  2181. Called with NM lock held and NmpLockedEnterApi already
  2182. called.
  2183. --*/
  2184. {
  2185. DWORD status = ERROR_SUCCESS;
  2186. PNM_NODE joinerNode = NULL;
  2187. LPWSTR endpoint = NULL;
  2188. joinerNode = OmReferenceObjectById(
  2189. ObjectTypeNode,
  2190. JoinerNodeId
  2191. );
  2192. if (joinerNode == NULL) {
  2193. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  2194. ClRtlLogPrint(LOG_UNUSUAL,
  2195. "[NMJOIN] Node %1!ws! is not a member of this cluster. Cannot join.\n",
  2196. JoinerNodeId
  2197. );
  2198. goto FnExit;
  2199. }
  2200. endpoint = MIDL_user_allocate(NM_WCSLEN(NmpClusnetEndpoint));
  2201. if (endpoint == NULL) {
  2202. status = ERROR_NOT_ENOUGH_MEMORY;
  2203. goto FnExit;
  2204. }
  2205. lstrcpyW(endpoint, NmpClusnetEndpoint);
  2206. if (NmpJoinBeginInProgress) {
  2207. status = ERROR_CLUSTER_JOIN_IN_PROGRESS;
  2208. ClRtlLogPrint(LOG_UNUSUAL,
  2209. "[NMJOIN] Node %1!ws! cannot join because a join is already in progress.\n",
  2210. JoinerNodeId
  2211. );
  2212. goto FnExit;
  2213. }
  2214. //
  2215. //validate the nodes version's number
  2216. //ie. check to see what the cluster database
  2217. //claims this node's version is vs what the node
  2218. //itself suggests
  2219. status = NmpValidateNodeVersion(
  2220. JoinerNodeId,
  2221. JoinerHighestVersion,
  2222. JoinerLowestVersion
  2223. );
  2224. //since this node joined, its version has changed
  2225. //this may happen due to upgrades or reinstall
  2226. //if this version cant join due to versioning,fail the join
  2227. if (status == ERROR_REVISION_MISMATCH) {
  2228. DWORD id = NmGetNodeId(joinerNode);
  2229. status = NmpIsNodeVersionAllowed(
  2230. id,
  2231. JoinerHighestVersion,
  2232. JoinerLowestVersion,
  2233. TRUE
  2234. );
  2235. if (status != ERROR_SUCCESS) {
  2236. ClRtlLogPrint(LOG_NOISE,
  2237. "[NMJOIN] The version of the cluster prevents Node %1!ws! from joining the cluster\n",
  2238. JoinerNodeId
  2239. );
  2240. goto FnExit;
  2241. }
  2242. }
  2243. else if (status != ERROR_SUCCESS) {
  2244. ClRtlLogPrint(LOG_NOISE,
  2245. "[NMJOIN] The version of Node %1!ws! cannot be validated.\n",
  2246. JoinerNodeId
  2247. );
  2248. goto FnExit;
  2249. }
  2250. //
  2251. // Lock out other join attempts with this sponsor.
  2252. //
  2253. NmpJoinBeginInProgress = TRUE;
  2254. NmpSuccessfulMMJoin = FALSE;
  2255. NmpReleaseLock();
  2256. status = GumSendUpdateEx(
  2257. GumUpdateMembership,
  2258. NmUpdateJoinBegin2,
  2259. 5,
  2260. NM_WCSLEN(JoinerNodeId),
  2261. JoinerNodeId,
  2262. NM_WCSLEN(JoinerNodeName),
  2263. JoinerNodeName,
  2264. NM_WCSLEN(NmLocalNodeIdString),
  2265. NmLocalNodeIdString,
  2266. sizeof(DWORD),
  2267. &JoinerHighestVersion,
  2268. sizeof(DWORD),
  2269. &JoinerLowestVersion
  2270. );
  2271. NmpAcquireLock();
  2272. CL_ASSERT(NmpJoinBeginInProgress == TRUE);
  2273. NmpJoinBeginInProgress = FALSE;
  2274. if (status != ERROR_SUCCESS)
  2275. {
  2276. ClRtlLogPrint(LOG_UNUSUAL,
  2277. "[NMJOIN] JoinBegin2 update for node %1!ws! failed, status %2!u!\n",
  2278. JoinerNodeId,
  2279. status
  2280. );
  2281. goto FnExit;
  2282. }
  2283. //
  2284. // Verify that the join is still in progress with
  2285. // this node as the sponsor.
  2286. //
  2287. if ( (NmpJoinerNodeId == joinerNode->NodeId) &&
  2288. (NmpSponsorNodeId == NmLocalNodeId)
  2289. )
  2290. {
  2291. //
  2292. // Give the joiner parameters for future
  2293. // join-related calls.
  2294. //
  2295. *SponsorNodeId = NmLocalNodeId;
  2296. *JoinSequenceNumber = NmpJoinSequence;
  2297. //
  2298. // Start the join timer
  2299. //
  2300. NmpJoinTimer = NM_JOIN_TIMEOUT;
  2301. ClRtlLogPrint(LOG_NOISE,
  2302. "[NMJOIN] Node %1!ws! has begun the join process.\n",
  2303. JoinerNodeId
  2304. );
  2305. }
  2306. else
  2307. {
  2308. status = ERROR_CLUSTER_JOIN_ABORTED;
  2309. ClRtlLogPrint(LOG_UNUSUAL,
  2310. "[NMJOIN] Begin join of node %1!ws! was aborted\n",
  2311. JoinerNodeId
  2312. );
  2313. }
  2314. FnExit:
  2315. if (joinerNode) {
  2316. OmDereferenceObject(joinerNode);
  2317. }
  2318. if (status == ERROR_SUCCESS) {
  2319. *ClusnetEndpoint = endpoint;
  2320. }
  2321. else {
  2322. WCHAR errorCode[16];
  2323. if (endpoint) MIDL_user_free(endpoint);
  2324. wsprintfW( errorCode, L"%u", status );
  2325. CsLogEvent2(
  2326. LOG_CRITICAL,
  2327. NM_EVENT_JOIN_REFUSED,
  2328. JoinerNodeId,
  2329. errorCode
  2330. );
  2331. }
  2332. return(status);
  2333. } // NmpJoinBegin
  2334. error_status_t
  2335. s_NmRpcJoinBegin2(
  2336. IN handle_t IDL_handle,
  2337. IN LPWSTR JoinerNodeId,
  2338. IN LPWSTR JoinerNodeName,
  2339. IN DWORD JoinerHighestVersion,
  2340. IN DWORD JoinerLowestVersion,
  2341. OUT LPDWORD SponsorNodeId,
  2342. OUT LPDWORD JoinSequenceNumber,
  2343. OUT LPWSTR * ClusnetEndpoint
  2344. )
  2345. /*++
  2346. Routine Description:
  2347. Called by a joining node to begin the join process.
  2348. Issues a JoinBegin global update.
  2349. --*/
  2350. {
  2351. DWORD status = ERROR_SUCCESS;
  2352. status = FmDoesQuorumAllowJoin();
  2353. if (status != ERROR_SUCCESS)
  2354. {
  2355. ClRtlLogPrint(LOG_NOISE,
  2356. "[NMJOIN] Quorum Characteristics prevent the node %1!ws! to from joining, Status=%2!u!.\n",
  2357. JoinerNodeId,
  2358. status
  2359. );
  2360. return(status);
  2361. }
  2362. NmpAcquireLock();
  2363. ClRtlLogPrint(LOG_NOISE,
  2364. "[NMJOIN] Processing request by node %1!ws! to begin joining (2).\n",
  2365. JoinerNodeId
  2366. );
  2367. if (!NmpLockedEnterApi(NmStateOnline)) {
  2368. status = ERROR_NODE_NOT_AVAILABLE;
  2369. ClRtlLogPrint(LOG_UNUSUAL,
  2370. "[NMJOIN] Cannot sponsor a joining node at this time.\n"
  2371. );
  2372. NmpReleaseLock();
  2373. return(status);
  2374. }
  2375. status = NmpJoinBegin(
  2376. JoinerNodeId,
  2377. JoinerNodeName,
  2378. JoinerHighestVersion,
  2379. JoinerLowestVersion,
  2380. SponsorNodeId,
  2381. JoinSequenceNumber,
  2382. ClusnetEndpoint
  2383. );
  2384. NmpLockedLeaveApi();
  2385. NmpReleaseLock();
  2386. return(status);
  2387. } // s_NmRpcJoinBegin2
  2388. error_status_t
  2389. s_NmRpcJoinBegin3(
  2390. IN handle_t IDL_handle,
  2391. IN LPWSTR JoinerClusterInstanceId,
  2392. IN LPWSTR JoinerNodeId,
  2393. IN LPWSTR JoinerNodeName,
  2394. IN DWORD JoinerHighestVersion,
  2395. IN DWORD JoinerLowestVersion,
  2396. IN DWORD JoinerMajorVersion,
  2397. IN DWORD JoinerMinorVersion,
  2398. IN LPWSTR JoinerCsdVersion,
  2399. IN DWORD JoinerProductSuite,
  2400. OUT LPDWORD SponsorNodeId,
  2401. OUT LPDWORD JoinSequenceNumber,
  2402. OUT LPWSTR * ClusnetEndpoint
  2403. )
  2404. {
  2405. DWORD status = ERROR_SUCCESS;
  2406. LPWSTR clusterInstanceId = NULL;
  2407. DWORD clusterInstanceIdBufSize = 0;
  2408. DWORD clusterInstanceIdSize = 0;
  2409. ClRtlLogPrint(LOG_NOISE,
  2410. "[NMJOIN] Processing request by node %1!ws! to begin joining (3).\n",
  2411. JoinerNodeId
  2412. );
  2413. status = FmDoesQuorumAllowJoin();
  2414. if (status != ERROR_SUCCESS)
  2415. {
  2416. ClRtlLogPrint(LOG_NOISE,
  2417. "[NMJOIN] Quorum Characteristics prevent node %1!ws! from joining, Status=%2!u!.\n",
  2418. JoinerNodeId,
  2419. status
  2420. );
  2421. return(status);
  2422. }
  2423. //
  2424. // Check our cluster instance ID against the joiner's.
  2425. //
  2426. if (NmpClusterInstanceId == NULL ||
  2427. lstrcmpiW(NmpClusterInstanceId, JoinerClusterInstanceId) != 0) {
  2428. WCHAR errorCode[16];
  2429. status = ERROR_CLUSTER_INSTANCE_ID_MISMATCH;
  2430. ClRtlLogPrint(LOG_CRITICAL,
  2431. "[NMJOIN] Sponsor cluster instance ID %1!ws! does not match joiner cluster instance id %2!ws!.\n",
  2432. ((NmpClusterInstanceId == NULL) ? L"<NULL>" : NmpClusterInstanceId),
  2433. JoinerClusterInstanceId
  2434. );
  2435. wsprintfW( errorCode, L"%u", status );
  2436. CsLogEvent2(
  2437. LOG_CRITICAL,
  2438. NM_EVENT_JOIN_REFUSED,
  2439. JoinerNodeId,
  2440. errorCode
  2441. );
  2442. return(status);
  2443. } else {
  2444. ClRtlLogPrint(LOG_NOISE,
  2445. "[NMJOIN] Sponsor cluster instance ID matches joiner cluster instance id (%1!ws!).\n",
  2446. JoinerClusterInstanceId
  2447. );
  2448. }
  2449. NmpAcquireLock();
  2450. if (!NmpLockedEnterApi(NmStateOnline)) {
  2451. status = ERROR_NODE_NOT_AVAILABLE;
  2452. ClRtlLogPrint(LOG_UNUSUAL,
  2453. "[NMJOIN] Cannot sponsor a joining node at this time.\n"
  2454. );
  2455. } else {
  2456. status = NmpJoinBegin(
  2457. JoinerNodeId,
  2458. JoinerNodeName,
  2459. JoinerHighestVersion,
  2460. JoinerLowestVersion,
  2461. SponsorNodeId,
  2462. JoinSequenceNumber,
  2463. ClusnetEndpoint
  2464. );
  2465. NmpLockedLeaveApi();
  2466. }
  2467. NmpReleaseLock();
  2468. return(status);
  2469. } // s_NmRpcJoinBegin3
  2470. DWORD
  2471. NmpUpdateJoinBegin(
  2472. IN BOOL SourceNode,
  2473. IN LPWSTR JoinerNodeId,
  2474. IN LPWSTR JoinerNodeName,
  2475. IN LPWSTR SponsorNodeId
  2476. )
  2477. {
  2478. DWORD status=ERROR_CLUSTER_INCOMPATIBLE_VERSIONS;
  2479. ClRtlLogPrint(LOG_NOISE,
  2480. "[NMJOIN] Failing update to begin join of node %1!ws! with "
  2481. "sponsor %2!ws!. Using obsolete join interface.\n",
  2482. JoinerNodeId,
  2483. SponsorNodeId
  2484. );
  2485. return(status);
  2486. } // NmpUpdateJoinBegin
  2487. DWORD
  2488. NmpUpdateJoinBegin2(
  2489. IN BOOL SourceNode,
  2490. IN LPWSTR JoinerNodeId,
  2491. IN LPWSTR JoinerNodeName,
  2492. IN LPWSTR SponsorNodeId,
  2493. IN LPDWORD JoinerHighestVersion,
  2494. IN LPDWORD JoinerLowestVersion
  2495. )
  2496. {
  2497. DWORD status = ERROR_SUCCESS;
  2498. PNM_NODE sponsorNode=NULL;
  2499. PNM_NODE joinerNode=NULL;
  2500. HLOCALXSACTION hXsaction=NULL;
  2501. BOOLEAN lockAcquired = FALSE;
  2502. BOOLEAN fakeSuccess = FALSE;
  2503. ClRtlLogPrint(LOG_NOISE,
  2504. "[NMJOIN] Received update to begin join (2) of node %1!ws! with "
  2505. "sponsor %2!ws!.\n",
  2506. JoinerNodeId,
  2507. SponsorNodeId
  2508. );
  2509. //
  2510. // If running with -noquorum flag or if not online, don't sponsor
  2511. // any node.
  2512. //
  2513. if (CsNoQuorum || !NmpEnterApi(NmStateOnline)) {
  2514. ClRtlLogPrint(LOG_NOISE,
  2515. "[NM] Not in valid state to begin a join operation.\n"
  2516. );
  2517. return(ERROR_NODE_NOT_AVAILABLE);
  2518. }
  2519. //
  2520. // Find the sponsor node
  2521. //
  2522. sponsorNode = OmReferenceObjectById(
  2523. ObjectTypeNode,
  2524. SponsorNodeId
  2525. );
  2526. if (sponsorNode == NULL) {
  2527. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  2528. ClRtlLogPrint(LOG_UNUSUAL,
  2529. "[NMJOIN] JoinBegin update for node %1!ws! failed because "
  2530. "sponsor node %2!ws! is not a member of this cluster.\n",
  2531. JoinerNodeId,
  2532. SponsorNodeId
  2533. );
  2534. goto FnExit;
  2535. }
  2536. //
  2537. // Find the joiner node
  2538. //
  2539. joinerNode = OmReferenceObjectById(
  2540. ObjectTypeNode,
  2541. JoinerNodeId
  2542. );
  2543. if (joinerNode == NULL) {
  2544. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  2545. ClRtlLogPrint(LOG_UNUSUAL,
  2546. "[NMJOIN] Node %1!ws! is not a member of this cluster. "
  2547. "Cannot join.\n",
  2548. JoinerNodeId
  2549. );
  2550. goto FnExit;
  2551. }
  2552. hXsaction = DmBeginLocalUpdate();
  2553. if (hXsaction == NULL) {
  2554. status = GetLastError();
  2555. ClRtlLogPrint(LOG_CRITICAL,
  2556. "[NM] Failed to start a transaction, status %1!u!\n",
  2557. status
  2558. );
  2559. goto FnExit;
  2560. }
  2561. NmpAcquireLock(); lockAcquired = TRUE;
  2562. if (!NM_NODE_UP(sponsorNode)) {
  2563. //
  2564. // [GorN 4/3/2000] See bug#98287
  2565. // This hack is a kludgy solution to a problem that
  2566. // a replay of this Gum update after the sponsor death
  2567. // will fail on all the nodes that didn't see the update.
  2568. //
  2569. fakeSuccess = TRUE;
  2570. status = ERROR_NODE_NOT_AVAILABLE;
  2571. ClRtlLogPrint(LOG_UNUSUAL,
  2572. "[NMJOIN] Sponsor node %1!ws! is not up. Join of node %2!ws! "
  2573. "failed.\n",
  2574. SponsorNodeId,
  2575. JoinerNodeId
  2576. );
  2577. goto FnExit;
  2578. }
  2579. //
  2580. // Check that the joiner is really who we think it is.
  2581. //
  2582. if (lstrcmpiW( OmObjectName(joinerNode), JoinerNodeName)) {
  2583. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  2584. ClRtlLogPrint(LOG_UNUSUAL,
  2585. "[NMJOIN] Node %1!ws! is not a member of this cluster. "
  2586. "Cannot join.\n",
  2587. JoinerNodeName
  2588. );
  2589. goto FnExit;
  2590. }
  2591. //
  2592. // Make sure the joiner is currently down.
  2593. //
  2594. if (joinerNode->State != ClusterNodeDown) {
  2595. status = ERROR_CLUSTER_NODE_UP;
  2596. ClRtlLogPrint(LOG_UNUSUAL,
  2597. "[NMJOIN] Node %1!ws! is not down. Cannot begin join.\n",
  2598. JoinerNodeId
  2599. );
  2600. goto FnExit;
  2601. }
  2602. //
  2603. // Make sure we aren't already in a join.
  2604. //
  2605. if (NmpJoinerNodeId != ClusterInvalidNodeId) {
  2606. status = ERROR_CLUSTER_JOIN_IN_PROGRESS;
  2607. ClRtlLogPrint(LOG_UNUSUAL,
  2608. "[NMJOIN] Node %1!ws! cannot begin join because a join is "
  2609. "already in progress for node %2!u!.\n",
  2610. JoinerNodeId,
  2611. NmpJoinerNodeId
  2612. );
  2613. goto FnExit;
  2614. }
  2615. //
  2616. // Perform the version compatibility check.
  2617. //
  2618. status = NmpIsNodeVersionAllowed(
  2619. NmGetNodeId(joinerNode),
  2620. *JoinerHighestVersion,
  2621. *JoinerLowestVersion,
  2622. TRUE
  2623. );
  2624. if (status != ERROR_SUCCESS) {
  2625. ClRtlLogPrint(LOG_UNUSUAL,
  2626. "[NMJOIN] The version of the cluster prevents Node %1!ws! "
  2627. "from joining the cluster\n",
  2628. JoinerNodeId
  2629. );
  2630. goto FnExit;
  2631. }
  2632. // Fix up the joiner's version number if needed.
  2633. //
  2634. status = NmpValidateNodeVersion(
  2635. JoinerNodeId,
  2636. *JoinerHighestVersion,
  2637. *JoinerLowestVersion
  2638. );
  2639. if (status == ERROR_REVISION_MISMATCH) {
  2640. //
  2641. // At this point, the registry contains the new
  2642. // versions for the joining code.
  2643. // The new node information should be reread
  2644. // from the registry before resetting the cluster
  2645. // version
  2646. // make sure the joiner gets the database from the
  2647. // sponsor after the fixups have occured
  2648. //
  2649. status = NmpJoinFixupNodeVersion(
  2650. hXsaction,
  2651. JoinerNodeId,
  2652. *JoinerHighestVersion,
  2653. *JoinerLowestVersion
  2654. );
  2655. if (status != ERROR_SUCCESS) {
  2656. ClRtlLogPrint(LOG_UNUSUAL,
  2657. "[NMJOIN] Node %1!ws! failed to fixup its node version\r\n",
  2658. JoinerNodeId);
  2659. goto FnExit;
  2660. }
  2661. }
  2662. else if (status != ERROR_SUCCESS) {
  2663. ClRtlLogPrint(LOG_UNUSUAL,
  2664. "[NMJOIN] The verison of Node %1!ws! could not be validated\n",
  2665. JoinerNodeId);
  2666. goto FnExit;
  2667. }
  2668. //
  2669. //at this point we ready to calculate the cluster version
  2670. //all the node versions are in the registry, the fixups have
  2671. //been made if neccessary
  2672. //
  2673. NmpResetClusterVersion(TRUE);
  2674. //
  2675. // Enable communication to the joiner.
  2676. //
  2677. // This must be the last test that can fail before the join is allowed
  2678. // to proceed.
  2679. //
  2680. status = ClusnetOnlineNodeComm(NmClusnetHandle, joinerNode->NodeId);
  2681. if (status != ERROR_SUCCESS) {
  2682. if (status != ERROR_CLUSTER_NODE_ALREADY_UP) {
  2683. ClRtlLogPrint(LOG_CRITICAL,
  2684. "[NMJOIN] Failed to enable communication for node %1!u!, "
  2685. "status %2!u!\n",
  2686. JoinerNodeId,
  2687. status
  2688. );
  2689. goto FnExit;
  2690. }
  2691. else {
  2692. status = ERROR_SUCCESS;
  2693. }
  2694. }
  2695. //
  2696. // Officially begin the join process
  2697. //
  2698. CL_ASSERT(NmpJoinTimer == 0);
  2699. CL_ASSERT(NmpJoinAbortPending == FALSE);
  2700. CL_ASSERT(NmpJoinerUp == FALSE);
  2701. CL_ASSERT(NmpSponsorNodeId == ClusterInvalidNodeId);
  2702. NmpJoinerNodeId = joinerNode->NodeId;
  2703. NmpSponsorNodeId = sponsorNode->NodeId;
  2704. NmpJoinerOutOfSynch = FALSE;
  2705. NmpJoinSequence = GumGetCurrentSequence(GumUpdateMembership);
  2706. joinerNode->State = ClusterNodeJoining;
  2707. ClusterEvent(
  2708. CLUSTER_EVENT_NODE_JOIN,
  2709. joinerNode
  2710. );
  2711. NmpCleanupIfJoinAborted = TRUE;
  2712. ClRtlLogPrint(LOG_NOISE,
  2713. "[NMJOIN] Node %1!ws! join sequence = %2!u!\n",
  2714. JoinerNodeId,
  2715. NmpJoinSequence
  2716. );
  2717. CL_ASSERT(status == ERROR_SUCCESS);
  2718. FnExit:
  2719. if (lockAcquired) {
  2720. NmpLockedLeaveApi();
  2721. NmpReleaseLock();
  2722. }
  2723. else {
  2724. NmpLeaveApi();
  2725. }
  2726. if (hXsaction != NULL) {
  2727. if (status == ERROR_SUCCESS) {
  2728. DmCommitLocalUpdate(hXsaction);
  2729. }
  2730. else {
  2731. DmAbortLocalUpdate(hXsaction);
  2732. }
  2733. }
  2734. if (joinerNode != NULL) {
  2735. OmDereferenceObject(joinerNode);
  2736. }
  2737. if (sponsorNode != NULL) {
  2738. OmDereferenceObject(sponsorNode);
  2739. }
  2740. if (fakeSuccess) {
  2741. status = ERROR_SUCCESS;
  2742. }
  2743. return(status);
  2744. } // NmpUpdateJoinBegin2
  2745. DWORD
  2746. NmpCreateRpcBindings(
  2747. IN PNM_NODE Node
  2748. )
  2749. {
  2750. DWORD status;
  2751. //
  2752. // Create the default binding for the whole cluster service
  2753. //
  2754. status = ClMsgCreateDefaultRpcBinding(
  2755. Node, &Node->DefaultRpcBindingGeneration);
  2756. if (status != ERROR_SUCCESS) {
  2757. return(status);
  2758. }
  2759. //
  2760. // Create private bindings for the NM's use.
  2761. // We create one for reporting network connectivity and one for
  2762. // performing network failure isolation. The NM uses the
  2763. // default binding for operations on behalf of joining nodes.
  2764. //
  2765. if (Node->ReportRpcBinding != NULL) {
  2766. //
  2767. // Reuse the old binding.
  2768. //
  2769. status = ClMsgVerifyRpcBinding(Node->ReportRpcBinding);
  2770. if (status != ERROR_SUCCESS) {
  2771. ClRtlLogPrint(LOG_CRITICAL,
  2772. "[NM] Failed to verify RPC binding for node %1!u!, "
  2773. "status %2!u!.\n",
  2774. Node->NodeId,
  2775. status
  2776. );
  2777. return(status);
  2778. }
  2779. }
  2780. else {
  2781. //
  2782. // Create a new binding
  2783. //
  2784. status = ClMsgCreateRpcBinding(
  2785. Node,
  2786. &(Node->ReportRpcBinding),
  2787. 0 );
  2788. if (status != ERROR_SUCCESS) {
  2789. ClRtlLogPrint(LOG_CRITICAL,
  2790. "[NM] Failed to create RPC binding for node %1!u!, "
  2791. "status %2!u!.\n",
  2792. Node->NodeId,
  2793. status
  2794. );
  2795. return(status);
  2796. }
  2797. }
  2798. if (Node->IsolateRpcBinding != NULL) {
  2799. //
  2800. // Reuse the old binding.
  2801. //
  2802. status = ClMsgVerifyRpcBinding(Node->IsolateRpcBinding);
  2803. if (status != ERROR_SUCCESS) {
  2804. ClRtlLogPrint(LOG_CRITICAL,
  2805. "[NM] Failed to verify RPC binding for node %1!u!, "
  2806. "status %2!u!.\n",
  2807. Node->NodeId,
  2808. status
  2809. );
  2810. return(status);
  2811. }
  2812. }
  2813. else {
  2814. //
  2815. // Create a new binding
  2816. //
  2817. status = ClMsgCreateRpcBinding(
  2818. Node,
  2819. &(Node->IsolateRpcBinding),
  2820. 0 );
  2821. if (status != ERROR_SUCCESS) {
  2822. ClRtlLogPrint(LOG_CRITICAL,
  2823. "[NM] Failed to create RPC binding for node %1!u!, "
  2824. "status %2!u!.\n",
  2825. Node->NodeId,
  2826. status
  2827. );
  2828. return(status);
  2829. }
  2830. }
  2831. //
  2832. // Call other components to create their private bindings
  2833. //
  2834. status = GumCreateRpcBindings(Node);
  2835. if (status != ERROR_SUCCESS) {
  2836. return(status);
  2837. }
  2838. status = EvCreateRpcBindings(Node);
  2839. if (status != ERROR_SUCCESS) {
  2840. return(status);
  2841. }
  2842. status = FmCreateRpcBindings(Node);
  2843. if (status != ERROR_SUCCESS) {
  2844. return(status);
  2845. }
  2846. return(ERROR_SUCCESS);
  2847. } // NmpCreateRpcBindings
  2848. error_status_t
  2849. s_NmRpcCreateBinding(
  2850. IN handle_t IDL_handle,
  2851. IN DWORD JoinSequence,
  2852. IN LPWSTR JoinerNodeId,
  2853. IN LPWSTR JoinerInterfaceId,
  2854. IN LPWSTR MemberNodeId
  2855. )
  2856. {
  2857. DWORD status;
  2858. NmpAcquireLock();
  2859. ClRtlLogPrint(LOG_NOISE,
  2860. "[NMJOIN] Processing CreateBinding request from joining node %1!ws! for member node %2!ws!\n",
  2861. JoinerNodeId,
  2862. MemberNodeId
  2863. );
  2864. if (NmpLockedEnterApi(NmStateOnlinePending)) {
  2865. PNM_NODE joinerNode = OmReferenceObjectById(
  2866. ObjectTypeNode,
  2867. JoinerNodeId
  2868. );
  2869. if (joinerNode != NULL) {
  2870. if ( (JoinSequence == NmpJoinSequence) &&
  2871. (NmpJoinerNodeId == joinerNode->NodeId) &&
  2872. (NmpSponsorNodeId == NmLocalNodeId) &&
  2873. !NmpJoinAbortPending
  2874. )
  2875. {
  2876. PNM_NODE memberNode;
  2877. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  2878. CL_ASSERT(NmpJoinerUp == FALSE);
  2879. CL_ASSERT(NmpJoinTimer != 0);
  2880. //
  2881. // Suspend the join timer while we are working on
  2882. // behalf of the joiner. This precludes an abort
  2883. // from occuring as well.
  2884. //
  2885. NmpJoinTimer = 0;
  2886. memberNode = OmReferenceObjectById(
  2887. ObjectTypeNode,
  2888. MemberNodeId
  2889. );
  2890. if (memberNode != NULL) {
  2891. PNM_INTERFACE netInterface = OmReferenceObjectById(
  2892. ObjectTypeNetInterface,
  2893. JoinerInterfaceId
  2894. );
  2895. if (netInterface != NULL) {
  2896. if (memberNode == NmLocalNode) {
  2897. status = NmpCreateJoinerRpcBindings(
  2898. joinerNode,
  2899. netInterface
  2900. );
  2901. }
  2902. else {
  2903. if (NM_NODE_UP(memberNode)) {
  2904. DWORD joinSequence = NmpJoinSequence;
  2905. RPC_BINDING_HANDLE binding =
  2906. Session[memberNode->NodeId];
  2907. CL_ASSERT(binding != NULL);
  2908. NmpReleaseLock();
  2909. NmStartRpc(memberNode->NodeId);
  2910. status = NmRpcCreateJoinerBinding(
  2911. binding,
  2912. joinSequence,
  2913. JoinerNodeId,
  2914. JoinerInterfaceId
  2915. );
  2916. NmEndRpc(memberNode->NodeId);
  2917. if(status != RPC_S_OK) {
  2918. NmDumpRpcExtErrorInfo(status);
  2919. }
  2920. NmpAcquireLock();
  2921. }
  2922. else {
  2923. status = ERROR_CLUSTER_NODE_DOWN;
  2924. ClRtlLogPrint(LOG_UNUSUAL,
  2925. "[NMJOIN] CreateBinding call for joining node %1!ws! failed because member node %2!ws! is down.\n",
  2926. JoinerNodeId,
  2927. MemberNodeId
  2928. );
  2929. }
  2930. }
  2931. OmDereferenceObject(netInterface);
  2932. }
  2933. else {
  2934. status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
  2935. ClRtlLogPrint(LOG_CRITICAL,
  2936. "[NMJOIN] Can't create binding for joining node %1!ws! - interface %2!ws! doesn't exist.\n",
  2937. JoinerNodeId,
  2938. JoinerInterfaceId
  2939. );
  2940. }
  2941. OmDereferenceObject(memberNode);
  2942. }
  2943. else {
  2944. status = ERROR_CLUSTER_NODE_NOT_FOUND;
  2945. ClRtlLogPrint(LOG_UNUSUAL,
  2946. "[NMJOIN] CreateBinding call for joining node %1!ws! failed because member node %2!ws! does not exist\n",
  2947. JoinerNodeId,
  2948. MemberNodeId
  2949. );
  2950. }
  2951. //
  2952. // Verify that the join is still in progress
  2953. //
  2954. if ( (JoinSequence == NmpJoinSequence) &&
  2955. (NmpJoinerNodeId == joinerNode->NodeId)
  2956. )
  2957. {
  2958. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  2959. CL_ASSERT(NmpJoinerUp == FALSE);
  2960. CL_ASSERT(NmpSponsorNodeId == NmLocalNodeId);
  2961. CL_ASSERT(NmpJoinTimer == 0);
  2962. CL_ASSERT(NmpJoinAbortPending == FALSE);
  2963. //
  2964. // Restart the join timer.
  2965. //
  2966. NmpJoinTimer = NM_JOIN_TIMEOUT;
  2967. }
  2968. else {
  2969. status = ERROR_CLUSTER_JOIN_ABORTED;
  2970. ClRtlLogPrint(LOG_UNUSUAL,
  2971. "[NMJOIN] CreateBinding call for joining node %1!ws! failed because the join was aborted.\n",
  2972. JoinerNodeId
  2973. );
  2974. }
  2975. }
  2976. else {
  2977. status = ERROR_CLUSTER_JOIN_ABORTED;
  2978. ClRtlLogPrint(LOG_UNUSUAL,
  2979. "[NMJOIN] CreateBinding call for joining node %1!ws! failed because the join was aborted.\n",
  2980. JoinerNodeId
  2981. );
  2982. }
  2983. OmDereferenceObject(joinerNode);
  2984. }
  2985. else {
  2986. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  2987. ClRtlLogPrint(LOG_UNUSUAL,
  2988. "[NMJOIN] CreateBinding call for joining node %1!ws! failed because the node is not a member of the cluster.\n",
  2989. JoinerNodeId
  2990. );
  2991. }
  2992. NmpLockedLeaveApi();
  2993. }
  2994. NmpReleaseLock();
  2995. return(status);
  2996. } // s_NmRpcCreateBinding
  2997. error_status_t
  2998. s_NmRpcCreateJoinerBinding(
  2999. IN handle_t IDL_handle,
  3000. IN DWORD JoinSequence,
  3001. IN LPWSTR JoinerNodeId,
  3002. IN LPWSTR JoinerInterfaceId
  3003. )
  3004. /*++
  3005. Notes:
  3006. The sponsor is responsible for aborting the join on failure.
  3007. --*/
  3008. {
  3009. DWORD status;
  3010. NmpAcquireLock();
  3011. ClRtlLogPrint(LOG_NOISE,
  3012. "[NMJOIN] Processing CreateBinding request for joining node %1!ws!.\n",
  3013. JoinerNodeId
  3014. );
  3015. if (NmpLockedEnterApi(NmStateOnline)) {
  3016. PNM_NODE joinerNode = OmReferenceObjectById(
  3017. ObjectTypeNode,
  3018. JoinerNodeId
  3019. );
  3020. if (joinerNode != NULL) {
  3021. PNM_INTERFACE netInterface = OmReferenceObjectById(
  3022. ObjectTypeNetInterface,
  3023. JoinerInterfaceId
  3024. );
  3025. if (netInterface != NULL) {
  3026. //
  3027. // Verify that a join is still in progress.
  3028. //
  3029. if ( (JoinSequence == NmpJoinSequence) &&
  3030. (NmpJoinerNodeId == joinerNode->NodeId)
  3031. )
  3032. {
  3033. status = NmpCreateJoinerRpcBindings(
  3034. joinerNode,
  3035. netInterface
  3036. );
  3037. if (status != ERROR_SUCCESS) {
  3038. WCHAR errorString[12];
  3039. wsprintfW(&(errorString[0]), L"%u", status);
  3040. CsLogEvent3(
  3041. LOG_UNUSUAL,
  3042. NM_EVENT_JOINER_BIND_FAILED,
  3043. OmObjectName(joinerNode),
  3044. OmObjectName(netInterface->Network),
  3045. errorString
  3046. );
  3047. }
  3048. }
  3049. else {
  3050. status = ERROR_CLUSTER_JOIN_ABORTED;
  3051. ClRtlLogPrint(LOG_UNUSUAL,
  3052. "[NMJOIN] Failing create bindings for joining node %1!ws! because the join was aborted\n",
  3053. JoinerNodeId
  3054. );
  3055. }
  3056. OmDereferenceObject(netInterface);
  3057. }
  3058. else {
  3059. status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
  3060. ClRtlLogPrint(LOG_CRITICAL,
  3061. "[NMJOIN] Can't create binding for joining node %1!ws! - no corresponding interface for joiner interface %2!ws!.\n",
  3062. JoinerNodeId,
  3063. JoinerInterfaceId
  3064. );
  3065. }
  3066. OmDereferenceObject(joinerNode);
  3067. }
  3068. else {
  3069. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  3070. ClRtlLogPrint(LOG_UNUSUAL,
  3071. "[NMJOIN] CreateBinding call for joining node %1!ws! failed because the node is not a member of the cluster.\n",
  3072. JoinerNodeId
  3073. );
  3074. }
  3075. NmpLockedLeaveApi();
  3076. }
  3077. else {
  3078. status = ERROR_NODE_NOT_AVAILABLE;
  3079. ClRtlLogPrint(LOG_NOISE,
  3080. "[NMJOIN] Not in valid state to process the request.\n"
  3081. );
  3082. }
  3083. NmpReleaseLock();
  3084. return(status);
  3085. } // s_NmRpcCreateJoinerBinding
  3086. DWORD
  3087. NmpCreateJoinerRpcBindings(
  3088. IN PNM_NODE JoinerNode,
  3089. IN PNM_INTERFACE JoinerInterface
  3090. )
  3091. /*++
  3092. Notes:
  3093. Called with the NmpLock held.
  3094. --*/
  3095. {
  3096. DWORD status;
  3097. PNM_NETWORK network = JoinerInterface->Network;
  3098. CL_NODE_ID joinerNodeId = JoinerNode->NodeId;
  3099. CL_ASSERT(JoinerNode->NodeId == NmpJoinerNodeId);
  3100. CL_ASSERT(JoinerNode->State == ClusterNodeJoining);
  3101. ClRtlLogPrint(LOG_NOISE,
  3102. "[NMJOIN] Creating bindings for joining node %1!u! using network %2!ws!\n",
  3103. joinerNodeId,
  3104. OmObjectName(JoinerInterface->Network)
  3105. );
  3106. //
  3107. // Make sure that this node has an interface on the target network.
  3108. //
  3109. if (NmpIsNetworkForInternalUse(network)) {
  3110. if (network->LocalInterface != NULL) {
  3111. if ( NmpIsInterfaceRegistered(JoinerInterface) &&
  3112. NmpIsInterfaceRegistered(network->LocalInterface)
  3113. )
  3114. {
  3115. status = NmpSetNodeInterfacePriority(
  3116. JoinerNode,
  3117. 0xFFFFFFFF,
  3118. JoinerInterface,
  3119. 1
  3120. );
  3121. if (status == ERROR_SUCCESS) {
  3122. PNM_INTERFACE localInterface = network->LocalInterface;
  3123. //
  3124. // Create intracluster RPC bindings for the petitioner.
  3125. // The MM relies on these to perform the join.
  3126. //
  3127. OmReferenceObject(localInterface);
  3128. OmReferenceObject(JoinerNode);
  3129. NmpReleaseLock();
  3130. status = NmpCreateRpcBindings(JoinerNode);
  3131. NmpAcquireLock();
  3132. if (status != ERROR_SUCCESS) {
  3133. ClRtlLogPrint(LOG_UNUSUAL,
  3134. "[NMJOIN] Unable to create RPC binding for "
  3135. "joining node %1!u!, status %2!u!.\n",
  3136. joinerNodeId,
  3137. status
  3138. );
  3139. }
  3140. OmDereferenceObject(JoinerNode);
  3141. OmDereferenceObject(localInterface);
  3142. }
  3143. else {
  3144. ClRtlLogPrint(LOG_CRITICAL,
  3145. "[NMJOIN] Failed to set interface priority for "
  3146. "network %1!ws! (%2!ws!), status %3!u!\n",
  3147. OmObjectId(network),
  3148. OmObjectName(network),
  3149. status
  3150. );
  3151. }
  3152. }
  3153. else {
  3154. status = ERROR_CLUSTER_NODE_UNREACHABLE;
  3155. }
  3156. }
  3157. else {
  3158. status = ERROR_CLUSTER_NETINTERFACE_NOT_FOUND;
  3159. }
  3160. }
  3161. else {
  3162. status = ERROR_CLUSTER_NODE_UNREACHABLE;
  3163. }
  3164. if (status !=ERROR_SUCCESS) {
  3165. ClRtlLogPrint(LOG_CRITICAL,
  3166. "[NMJOIN] Failed to create binding for joining node %1!u! "
  3167. "on network %2!ws! (%3!ws!), status %4!u!\n",
  3168. joinerNodeId,
  3169. OmObjectId(network),
  3170. OmObjectName(network),
  3171. status
  3172. );
  3173. }
  3174. return(status);
  3175. } // NmpCreateJoinerRpcBinding
  3176. error_status_t
  3177. s_NmRpcPetitionForMembership(
  3178. IN handle_t IDL_handle,
  3179. IN DWORD JoinSequence,
  3180. IN LPCWSTR JoinerNodeId
  3181. )
  3182. /*++
  3183. Routine Description:
  3184. Server side of a join petition.
  3185. Arguments:
  3186. IDL_handle - RPC binding handle, not used.
  3187. JoinSequence - Supplies the sequence returned from NmRpcJoinBegin
  3188. JoinerNodeId - Supplies the ID of the node attempting to join.
  3189. Return Value:
  3190. ERROR_SUCCESS if successful
  3191. Win32 error otherwise.
  3192. --*/
  3193. {
  3194. DWORD status;
  3195. PNM_NODE joinerNode;
  3196. #ifdef CLUSTER_TESTPOINT
  3197. TESTPT(TestpointJoinFailPetition) {
  3198. return(999999);
  3199. }
  3200. #endif
  3201. NmpAcquireLock();
  3202. ClRtlLogPrint(LOG_UNUSUAL,
  3203. "[NMJOIN] Processing petition to join from node %1!ws!.\n",
  3204. JoinerNodeId
  3205. );
  3206. if (NmpLockedEnterApi(NmStateOnline)) {
  3207. joinerNode = OmReferenceObjectById(ObjectTypeNode, JoinerNodeId);
  3208. if (joinerNode != NULL) {
  3209. //
  3210. // Verify that the join is still in progress
  3211. //
  3212. //
  3213. // DavidDio 6/13/2000
  3214. // There is a small window where a begin join update can
  3215. // succeed during a regroup, but the regroup ends before
  3216. // the joining node petitions to join. In this case, the
  3217. // node will be marked out of sync. Aborting the join
  3218. // after MMJoin() is much more heavyweight than before,
  3219. // so check for this condition now. (Bug 125778).
  3220. //
  3221. if ( (JoinSequence == NmpJoinSequence) &&
  3222. (NmpJoinerNodeId == joinerNode->NodeId) &&
  3223. (NmpSponsorNodeId == NmLocalNodeId) &&
  3224. (!NmpJoinAbortPending) &&
  3225. (!NmpJoinerOutOfSynch)
  3226. )
  3227. {
  3228. ClRtlLogPrint(LOG_UNUSUAL, "[NMJOIN] Performing join.\n");
  3229. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  3230. CL_ASSERT(NmpJoinerUp == FALSE);
  3231. CL_ASSERT(NmpJoinTimer != 0);
  3232. //
  3233. // Call the MM to join this node to the cluster membership.
  3234. // Disable the join timer. Once the node becomes an active
  3235. // member, we won't need it anymore.
  3236. //
  3237. NmpJoinTimer = 0;
  3238. NmpReleaseLock();
  3239. status = MMJoin(
  3240. joinerNode->NodeId,
  3241. NM_CLOCK_PERIOD,
  3242. NM_SEND_HB_RATE,
  3243. NM_RECV_HB_RATE,
  3244. NM_MM_JOIN_TIMEOUT
  3245. );
  3246. NmpAcquireLock();
  3247. //
  3248. // Verify that the join is still in progress
  3249. //
  3250. if ( (JoinSequence == NmpJoinSequence) &&
  3251. (NmpJoinerNodeId == joinerNode->NodeId)
  3252. )
  3253. {
  3254. CL_ASSERT(NmpSponsorNodeId == NmLocalNodeId);
  3255. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  3256. CL_ASSERT(NmpJoinTimer == 0);
  3257. CL_ASSERT(NmpJoinAbortPending == FALSE);
  3258. // GorN 3/22/2000
  3259. // We hit a case when MMJoin has succeeded after a regroup
  3260. // that killed one of the nodes (not joiner and not sponsor)
  3261. // thus leaving the joiner out of sync
  3262. // We need to abourt the join in this case too
  3263. if (status != MM_OK || NmpJoinerOutOfSynch) {
  3264. status = MMMapStatusToDosError(status);
  3265. if (NmpJoinerOutOfSynch) {
  3266. status = ERROR_CLUSTER_JOIN_ABORTED;
  3267. }
  3268. //
  3269. // Abort the join
  3270. //
  3271. ClRtlLogPrint(LOG_UNUSUAL,
  3272. "[NMJOIN] Petition to join by node %1!ws! failed, status %2!u!.\n",
  3273. JoinerNodeId,
  3274. status
  3275. );
  3276. //
  3277. // If MMJoin was unsuccessful it initiates a banishing
  3278. // regroup. This regroup will deliver node down events
  3279. // on all nodes that saw hb's from the joiner.
  3280. //
  3281. // Calling MMBlockIfRegroupIsInProgress here will guarantee that
  3282. // Phase2 cleanup is complete on all nodes, before we
  3283. // call NmpJoinAbort.
  3284. //
  3285. NmpReleaseLock();
  3286. MMBlockIfRegroupIsInProgress();
  3287. NmpAcquireLock();
  3288. NmpJoinAbort(status, joinerNode);
  3289. }
  3290. else {
  3291. NmpSuccessfulMMJoin = TRUE;
  3292. ClRtlLogPrint(LOG_UNUSUAL,
  3293. "[NMJOIN] Petition to join by node %1!ws! succeeded.\n",
  3294. JoinerNodeId
  3295. );
  3296. }
  3297. #ifdef MM_IN_CLUSNET
  3298. if (status == MM_OK) {
  3299. status = NmJoinNodeToCluster(joinerNodeId);
  3300. if (status != ERROR_SUCCESS) {
  3301. DWORD clusnetStatus;
  3302. ClRtlLogPrint(LOG_UNUSUAL,
  3303. "[NMJOIN] Join of node %1!ws! failed, status %2!u!.\n",
  3304. JoinerNodeId,
  3305. status
  3306. );
  3307. CL_LOGFAILURE( status );
  3308. NmpReleaseLock();
  3309. MMEject(joinerNodeId);
  3310. NmpAcquireLock();
  3311. clusnetStatus = ClusnetOfflineNodeComm(
  3312. NmClusnetHandle,
  3313. joinerNodeId
  3314. );
  3315. CL_ASSERT(
  3316. (status == ERROR_SUCCESS) ||
  3317. (status == ERROR_CLUSTER_NODE_ALREADY_DOWN
  3318. );
  3319. }
  3320. else {
  3321. ClRtlLogPrint(LOG_UNUSUAL,
  3322. "[NMJOIN] Join completed successfully.\n"
  3323. );
  3324. }
  3325. }
  3326. #endif // MM_IN_CLUSNET
  3327. }
  3328. else {
  3329. status = ERROR_CLUSTER_JOIN_ABORTED;
  3330. ClRtlLogPrint(LOG_UNUSUAL,
  3331. "[NMJOIN] Petition to join by node %1!ws! failed because the join was aborted.\n",
  3332. JoinerNodeId
  3333. );
  3334. }
  3335. }
  3336. else {
  3337. status = ERROR_CLUSTER_JOIN_ABORTED;
  3338. ClRtlLogPrint(LOG_UNUSUAL,
  3339. "[NMJOIN] Petition by node %1!ws! failed because the join was aborted\n",
  3340. JoinerNodeId
  3341. );
  3342. }
  3343. OmDereferenceObject(joinerNode);
  3344. }
  3345. else {
  3346. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  3347. ClRtlLogPrint(LOG_UNUSUAL,
  3348. "[NMJOIN] Petition to join by %1!ws! failed because the node is not a cluster member\n",
  3349. JoinerNodeId
  3350. );
  3351. }
  3352. NmpLockedLeaveApi();
  3353. }
  3354. else {
  3355. status = ERROR_NODE_NOT_AVAILABLE;
  3356. ClRtlLogPrint(LOG_NOISE,
  3357. "[NMJOIN] Not in valid state to process the request.\n"
  3358. );
  3359. }
  3360. NmpReleaseLock();
  3361. return(status);
  3362. } // s_NmRpcPetitionForMembership
  3363. error_status_t
  3364. s_NmRpcGetLeaderNodeId(
  3365. IN handle_t IDL_handle,
  3366. IN DWORD JoinSequence, OPTIONAL
  3367. IN LPWSTR JoinerNodeId, OPTIONAL
  3368. OUT LPDWORD LeaderNodeId
  3369. )
  3370. {
  3371. DWORD status = ERROR_SUCCESS;
  3372. PNM_NODE joinerNode = NULL;
  3373. NmpAcquireLock();
  3374. if (NmpLockedEnterApi(NmStateOnline)){
  3375. joinerNode = OmReferenceObjectById(
  3376. ObjectTypeNode,
  3377. JoinerNodeId
  3378. );
  3379. if (joinerNode != NULL) {
  3380. if ( (JoinSequence == NmpJoinSequence) &&
  3381. (NmpJoinerNodeId == joinerNode->NodeId) &&
  3382. (NmpSponsorNodeId == NmLocalNodeId) &&
  3383. !NmpJoinAbortPending
  3384. )
  3385. {
  3386. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  3387. *LeaderNodeId = NmpLeaderNodeId;
  3388. }
  3389. else {
  3390. status = ERROR_CLUSTER_JOIN_ABORTED;
  3391. ClRtlLogPrint(LOG_UNUSUAL,
  3392. "[NMJOIN] GetLeaderNodeId call for joining node %1!ws! failed because the join was aborted.\n",
  3393. JoinerNodeId
  3394. );
  3395. }
  3396. OmDereferenceObject(joinerNode);
  3397. }
  3398. else {
  3399. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  3400. ClRtlLogPrint(LOG_UNUSUAL,
  3401. "[NMJOIN] GetLeaderNodeId call for joining node %1!ws! failed because the node is not a member of the cluster.\n",
  3402. JoinerNodeId
  3403. );
  3404. }
  3405. NmpLockedLeaveApi();
  3406. }
  3407. else {
  3408. status = ERROR_NODE_NOT_AVAILABLE;
  3409. ClRtlLogPrint(LOG_NOISE,
  3410. "[NMJOIN] Not in valid state to process GetLeaderNodeId request.\n"
  3411. );
  3412. }
  3413. NmpReleaseLock();
  3414. return(status);
  3415. } // s_NmRpcGetLeaderNodeId
  3416. DWORD
  3417. NmpUpdateJoinComplete(
  3418. IN PNM_JOIN_UPDATE JoinUpdate
  3419. )
  3420. {
  3421. DWORD status;
  3422. NmpAcquireLock();
  3423. ClRtlLogPrint(LOG_NOISE,
  3424. "[NMJOIN] Processing JoinComplete update from node %1!ws!\n",
  3425. JoinUpdate->NodeId
  3426. );
  3427. if (NmpLockedEnterApi(NmStateOnline)) {
  3428. PNM_NODE joinerNode;
  3429. LPWSTR joinerIdString = JoinUpdate->NodeId;
  3430. joinerNode = OmReferenceObjectById(ObjectTypeNode, joinerIdString);
  3431. if (joinerNode != NULL) {
  3432. CL_ASSERT(joinerNode != NmLocalNode);
  3433. //
  3434. // Verify that the join is still in progress and nothing has
  3435. // changed.
  3436. //
  3437. if ( (JoinUpdate->JoinSequence == NmpJoinSequence) &&
  3438. (NmpJoinerNodeId == joinerNode->NodeId) &&
  3439. (joinerNode->State == ClusterNodeJoining) &&
  3440. NmpJoinerUp &&
  3441. !NmpJoinerOutOfSynch
  3442. )
  3443. {
  3444. PNM_INTERFACE netInterface;
  3445. PNM_NETWORK network;
  3446. PLIST_ENTRY ifEntry;
  3447. NmpJoinerNodeId = ClusterInvalidNodeId;
  3448. NmpSponsorNodeId = ClusterInvalidNodeId;
  3449. NmpJoinTimer = 0;
  3450. NmpJoinAbortPending = FALSE;
  3451. NmpJoinSequence = 0;
  3452. NmpJoinerUp = FALSE;
  3453. if (JoinUpdate->IsPaused != 0) {
  3454. //
  3455. // This node is coming up in the paused state.
  3456. //
  3457. joinerNode->State = ClusterNodePaused;
  3458. } else {
  3459. joinerNode->State = ClusterNodeUp;
  3460. }
  3461. joinerNode->ExtendedState = ClusterNodeJoining;
  3462. ClusterEvent(CLUSTER_EVENT_NODE_UP, (PVOID)joinerNode);
  3463. //
  3464. // Reset the interface priorities for this node.
  3465. //
  3466. for (ifEntry = joinerNode->InterfaceList.Flink;
  3467. ifEntry != &joinerNode->InterfaceList;
  3468. ifEntry = ifEntry->Flink
  3469. )
  3470. {
  3471. netInterface = CONTAINING_RECORD(
  3472. ifEntry,
  3473. NM_INTERFACE,
  3474. NodeLinkage
  3475. );
  3476. network = netInterface->Network;
  3477. if ( NmpIsNetworkForInternalUse(network) &&
  3478. NmpIsInterfaceRegistered(netInterface)
  3479. )
  3480. {
  3481. status = ClusnetSetInterfacePriority(
  3482. NmClusnetHandle,
  3483. joinerNode->NodeId,
  3484. network->ShortId,
  3485. 0
  3486. );
  3487. CL_ASSERT(status == ERROR_SUCCESS);
  3488. }
  3489. }
  3490. status = ERROR_SUCCESS;
  3491. }
  3492. else {
  3493. status = ERROR_CLUSTER_JOIN_ABORTED;
  3494. ClRtlLogPrint(LOG_UNUSUAL,
  3495. "[NMJOIN] Join of node %1!ws! cannot complete because the join was aborted\n",
  3496. joinerIdString
  3497. );
  3498. }
  3499. OmDereferenceObject(joinerNode);
  3500. }
  3501. else {
  3502. status =ERROR_CLUSTER_NODE_NOT_MEMBER;
  3503. ClRtlLogPrint(LOG_UNUSUAL,
  3504. "[NMJOIN] Join of node %1!ws! cannot complete because the node is not a cluster member.\n",
  3505. joinerIdString
  3506. );
  3507. }
  3508. NmpLockedLeaveApi();
  3509. }
  3510. else {
  3511. status = ERROR_NODE_NOT_AVAILABLE;
  3512. ClRtlLogPrint(LOG_UNUSUAL,
  3513. "[NMJOIN] Not in valid state to process JoinComplete update.\n"
  3514. );
  3515. }
  3516. //
  3517. // If the multicast shared key is based on the cluster service account
  3518. // password, we may need to refresh, since the password might have
  3519. // changed and the joiner will be running under the new password.
  3520. //
  3521. if (status == ERROR_SUCCESS) {
  3522. status = NmpMulticastRegenerateKey(NULL);
  3523. if (status != ERROR_SUCCESS) {
  3524. ClRtlLogPrint(LOG_UNUSUAL,
  3525. "[NM] Failed to regenerate cluster network multicast "
  3526. "keys, status %1!u!.\n",
  3527. status
  3528. );
  3529. //
  3530. // Not a de facto fatal error.
  3531. //
  3532. status = ERROR_SUCCESS;
  3533. }
  3534. }
  3535. NmpReleaseLock();
  3536. // DavidDio 10/27/2000
  3537. // Bug 213781: NmpUpdateJoinComplete must always return ERROR_SUCCESS.
  3538. // Otherwise, there is a small window whereby GUM sequence numbers on
  3539. // remaining cluster nodes can fall out of sync. If the join should
  3540. // be aborted, return ERROR_SUCCESS but poison the joiner out-of-band.
  3541. if (status != ERROR_SUCCESS) {
  3542. DWORD dwJoinerId;
  3543. if (JoinUpdate->NodeId != NULL) {
  3544. dwJoinerId = wcstoul(JoinUpdate->NodeId, NULL, 10);
  3545. ClRtlLogPrint(LOG_UNUSUAL,
  3546. "[NMJOIN] Join of node %1!u! failed with status %2!u!. Initiating banishment.\n",
  3547. dwJoinerId,
  3548. status
  3549. );
  3550. NmAdviseNodeFailure(dwJoinerId, status);
  3551. } else {
  3552. dwJoinerId = ClusterInvalidNodeId;
  3553. ClRtlLogPrint(LOG_UNUSUAL,
  3554. "[NMJOIN] Join of node %1!ws! failed with status %2!u!. Cannot initiate banishment as node id is unknown.\n",
  3555. dwJoinerId,
  3556. status
  3557. );
  3558. }
  3559. }
  3560. return(ERROR_SUCCESS);
  3561. } // NmpUpdateJoinComplete
  3562. DWORD
  3563. NmpUpdateJoinAbort(
  3564. IN BOOL SourceNode,
  3565. IN LPDWORD JoinSequence,
  3566. IN LPWSTR JoinerNodeId
  3567. )
  3568. /*++
  3569. Notes:
  3570. --*/
  3571. {
  3572. DWORD status = ERROR_SUCCESS;
  3573. NmpAcquireLock();
  3574. ClRtlLogPrint(LOG_NOISE,
  3575. "[NMJOIN] Received update to abort join sequence %1!u! (joiner id %2!ws!).\n",
  3576. *JoinSequence,
  3577. JoinerNodeId
  3578. );
  3579. if (NmpLockedEnterApi(NmStateOnline)) {
  3580. PNM_NODE joinerNode = OmReferenceObjectById(
  3581. ObjectTypeNode,
  3582. JoinerNodeId
  3583. );
  3584. if (joinerNode != NULL) {
  3585. //
  3586. // Check if the specified join is still in progress.
  3587. //
  3588. if ( (*JoinSequence == NmpJoinSequence) &&
  3589. (NmpJoinerNodeId == joinerNode->NodeId)
  3590. )
  3591. {
  3592. CL_ASSERT(NmpSponsorNodeId != ClusterInvalidNodeId);
  3593. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  3594. //
  3595. // Assumption:
  3596. //
  3597. // An abort cannot occur during the MM join process.
  3598. // If the joiner is not already up, it cannot come up
  3599. // during the abort processing.
  3600. //
  3601. // Assert condition may not be true with the current MM join code.
  3602. // Some nodes might have got monitor node and set
  3603. // NmpJoinerUp state to TRUE by the time the sponsor issued
  3604. // an abort update
  3605. //
  3606. //CL_ASSERT(NmpJoinerUp == FALSE);
  3607. if (NmpCleanupIfJoinAborted) {
  3608. NmpCleanupIfJoinAborted = FALSE;
  3609. ClRtlLogPrint(LOG_UNUSUAL,
  3610. "[NMJOIN] Issuing a node down event for %1!u!.\n",
  3611. joinerNode->NodeId
  3612. );
  3613. //
  3614. // This node is not yet active in the membership.
  3615. // Call the node down event handler to finish the abort.
  3616. //
  3617. //
  3618. // We will not call NmpMsgCleanup1 and NmpMsgCleanup2,
  3619. // because we cannot guarantee that they will get executed
  3620. // in a barrier style fashion
  3621. //
  3622. // !!! Lock will be acquired by NmpNodeDownEventHandler
  3623. // second time. Is it OK?
  3624. //
  3625. NmpNodeDownEventHandler(joinerNode);
  3626. } else {
  3627. ClRtlLogPrint(LOG_UNUSUAL,
  3628. "[NMJOIN] Node down was already issued for %1!u!.\n",
  3629. joinerNode->NodeId
  3630. );
  3631. }
  3632. }
  3633. else {
  3634. ClRtlLogPrint(LOG_UNUSUAL,
  3635. "[NMJOIN] Ignoring old join abort update with sequence %1!u!.\n",
  3636. *JoinSequence
  3637. );
  3638. }
  3639. OmDereferenceObject(joinerNode);
  3640. status = ERROR_SUCCESS;
  3641. }
  3642. else {
  3643. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  3644. ClRtlLogPrint(LOG_UNUSUAL,
  3645. "[NMJOIN] Join of node %1!ws! cannot be aborted because the node is not a cluster member.\n",
  3646. JoinerNodeId
  3647. );
  3648. }
  3649. NmpLockedLeaveApi();
  3650. }
  3651. else {
  3652. status = ERROR_NODE_NOT_AVAILABLE;
  3653. ClRtlLogPrint(LOG_UNUSUAL,
  3654. "[NMJOIN] Not in valid state to process JoinAbort update.\n"
  3655. );
  3656. }
  3657. NmpReleaseLock();
  3658. return(status);
  3659. } // NmpUpdateJoinAbort
  3660. VOID
  3661. NmpJoinAbort(
  3662. DWORD AbortStatus,
  3663. PNM_NODE JoinerNode
  3664. )
  3665. /*++
  3666. Routine Description:
  3667. Issues a JoinAbort update.
  3668. Notes:
  3669. Called with the NmpLock held.
  3670. --*/
  3671. {
  3672. DWORD status;
  3673. DWORD joinSequence = NmpJoinSequence;
  3674. WCHAR errorString[12];
  3675. CL_ASSERT(NmpJoinerNodeId != ClusterInvalidNodeId);
  3676. CL_ASSERT(NmpSponsorNodeId == NmLocalNodeId);
  3677. CL_ASSERT(JoinerNode->State == ClusterNodeJoining);
  3678. if (AbortStatus == ERROR_TIMEOUT) {
  3679. wsprintfW(&(errorString[0]), L"%u", AbortStatus);
  3680. CsLogEvent1(
  3681. LOG_CRITICAL,
  3682. NM_EVENT_JOIN_TIMED_OUT,
  3683. OmObjectName(JoinerNode)
  3684. );
  3685. }
  3686. else {
  3687. wsprintfW(&(errorString[0]), L"%u", AbortStatus);
  3688. CsLogEvent2(
  3689. LOG_CRITICAL,
  3690. NM_EVENT_SPONSOR_JOIN_ABORTED,
  3691. OmObjectName(JoinerNode),
  3692. errorString
  3693. );
  3694. }
  3695. //
  3696. // Assumption:
  3697. //
  3698. // An abort cannot occur during the MM join process. If the joiner
  3699. // is not already up, it cannot come up during the abort processing.
  3700. //
  3701. if (NmpSuccessfulMMJoin == FALSE) {
  3702. //
  3703. // The joining node has not become active yet. Issue
  3704. // an abort update.
  3705. //
  3706. DWORD joinSequence = NmpJoinSequence;
  3707. ClRtlLogPrint(LOG_NOISE,
  3708. "[NMJOIN] Issuing update to abort join of node %1!u!.\n",
  3709. NmpJoinerNodeId
  3710. );
  3711. NmpReleaseLock();
  3712. status = GumSendUpdateEx(
  3713. GumUpdateMembership,
  3714. NmUpdateJoinAbort,
  3715. 2,
  3716. sizeof(DWORD),
  3717. &joinSequence,
  3718. NM_WCSLEN(OmObjectId(JoinerNode)),
  3719. OmObjectId(JoinerNode)
  3720. );
  3721. NmpAcquireLock();
  3722. }
  3723. else {
  3724. //
  3725. // The joining node is already active in the membership.
  3726. // Ask the MM to kick it out. The node down event will
  3727. // finish the abort process.
  3728. //
  3729. CL_NODE_ID joinerNodeId = NmpJoinerNodeId;
  3730. ClRtlLogPrint(LOG_NOISE,
  3731. "[NMJOIN] Ejecting joining node %1!u! from the cluster membership.\n",
  3732. NmpJoinerNodeId
  3733. );
  3734. NmpReleaseLock();
  3735. status = MMEject(joinerNodeId);
  3736. NmpAcquireLock();
  3737. }
  3738. if (status != MM_OK) {
  3739. status = MMMapStatusToDosError(status);
  3740. ClRtlLogPrint(LOG_UNUSUAL,
  3741. "[NMJOIN] Update to abort join of node %1!u! failed, status %2!u!\n",
  3742. JoinerNode->NodeId,
  3743. status
  3744. );
  3745. //
  3746. // If the join is still pending, and this is the sponsor node,
  3747. // force a timeout to retry the abort. If we aren't the sponsor,
  3748. // there isn't much we can do.
  3749. //
  3750. if ( (joinSequence == NmpJoinSequence) &&
  3751. (NmpJoinerNodeId == JoinerNode->NodeId) &&
  3752. (NmpSponsorNodeId == NmLocalNodeId)
  3753. )
  3754. {
  3755. NmpJoinTimer = 1;
  3756. NmpJoinAbortPending = FALSE;
  3757. }
  3758. }
  3759. return;
  3760. } // NmpJoinAbort
  3761. VOID
  3762. NmpJoinAbortWorker(
  3763. IN PCLRTL_WORK_ITEM WorkItem,
  3764. IN DWORD Status,
  3765. IN DWORD BytesTransferred,
  3766. IN ULONG_PTR IoContext
  3767. )
  3768. /*++
  3769. Routine Description:
  3770. Worker thread for aborting a join.
  3771. --*/
  3772. {
  3773. DWORD joinSequence = PtrToUlong(WorkItem->Context);
  3774. NmpAcquireLock();
  3775. //
  3776. // The active thread count was bumped up when this item was scheduled.
  3777. // No need to call NmpEnterApi().
  3778. //
  3779. //
  3780. // If the join is still pending, begin the abort process.
  3781. //
  3782. if ( (joinSequence == NmpJoinSequence) &&
  3783. (NmpJoinerNodeId != ClusterInvalidNodeId) &&
  3784. NmpJoinAbortPending
  3785. )
  3786. {
  3787. PNM_NODE joinerNode = NmpIdArray[NmpJoinerNodeId];
  3788. if (joinerNode != NULL) {
  3789. ClRtlLogPrint(LOG_NOISE,
  3790. "[NMJOIN] Worker thread initiating abort of joining node %1!u!\n",
  3791. NmpJoinerNodeId
  3792. );
  3793. NmpJoinAbort(ERROR_TIMEOUT, joinerNode);
  3794. }
  3795. else {
  3796. CL_ASSERT(joinerNode != NULL);
  3797. }
  3798. }
  3799. else {
  3800. ClRtlLogPrint(LOG_NOISE,
  3801. "[NMJOIN] Skipping join abort, sequence to abort %1!u!, current join sequence %2!u!, "
  3802. "joiner node: %3!u! sponsor node: %4!u!\n",
  3803. joinSequence,
  3804. NmpJoinSequence,
  3805. NmpJoinerNodeId,
  3806. NmpSponsorNodeId
  3807. );
  3808. }
  3809. NmpLockedLeaveApi();
  3810. NmpReleaseLock();
  3811. LocalFree(WorkItem);
  3812. return;
  3813. } // NmpJoinAbortWorker
  3814. VOID
  3815. NmpJoinTimerTick(
  3816. IN DWORD MsTickInterval
  3817. )
  3818. /*++
  3819. Notes:
  3820. Called with NmpLock held.
  3821. --*/
  3822. {
  3823. if (NmpLockedEnterApi(NmStateOnline)) {
  3824. //
  3825. // If we are sponsoring a join, update the timer.
  3826. //
  3827. if ( (NmpJoinerNodeId != ClusterInvalidNodeId) &&
  3828. (NmpSponsorNodeId == NmLocalNodeId) &&
  3829. !NmpJoinAbortPending &&
  3830. (NmpJoinTimer != 0)
  3831. )
  3832. {
  3833. //ClRtlLogPrint(LOG_NOISE,
  3834. // "[NMJOIN] Timer tick (%1!u! ms)\n",
  3835. // Interval
  3836. // );
  3837. if (NmpJoinTimer > MsTickInterval) {
  3838. NmpJoinTimer -= MsTickInterval;
  3839. }
  3840. else {
  3841. //
  3842. // The join has timed out. Schedule a worker thread to
  3843. // carry out the abort process.
  3844. //
  3845. PCLRTL_WORK_ITEM workItem;
  3846. ClRtlLogPrint(LOG_UNUSUAL,
  3847. "[NMJOIN] Join of node %1!u! has timed out.\n",
  3848. NmpJoinerNodeId
  3849. );
  3850. workItem = LocalAlloc(LMEM_FIXED, sizeof(CLRTL_WORK_ITEM));
  3851. if (workItem != NULL) {
  3852. DWORD status;
  3853. ClRtlInitializeWorkItem(
  3854. workItem,
  3855. NmpJoinAbortWorker,
  3856. ULongToPtr(NmpJoinSequence)
  3857. );
  3858. status = ClRtlPostItemWorkQueue(
  3859. CsDelayedWorkQueue,
  3860. workItem,
  3861. 0,
  3862. 0
  3863. );
  3864. if (status == ERROR_SUCCESS) {
  3865. //
  3866. // Stop the timer, flag that an abort is in progress,
  3867. // and account for the thread we just scheduled.
  3868. //
  3869. NmpJoinTimer = 0;
  3870. NmpJoinAbortPending = TRUE;
  3871. NmpActiveThreadCount++;
  3872. }
  3873. else {
  3874. ClRtlLogPrint(LOG_UNUSUAL,
  3875. "[NMJOIN] Failed to schedule abort of join, status %1!u!.\n",
  3876. status
  3877. );
  3878. LocalFree(workItem);
  3879. }
  3880. }
  3881. else {
  3882. ClRtlLogPrint(LOG_UNUSUAL,
  3883. "[NMJOIN] Failed to allocate memory for join abort.\n"
  3884. );
  3885. }
  3886. }
  3887. }
  3888. NmpLockedLeaveApi();
  3889. }
  3890. return;
  3891. } // NmpJoinTimerTick
  3892. VOID
  3893. NmTimerTick(
  3894. IN DWORD MsTickInterval
  3895. )
  3896. /*++
  3897. Routine Description:
  3898. Implements all of the NM timers. Called on every tick of
  3899. the common NM/MM timer - currently every 300ms.
  3900. Arguments:
  3901. MsTickInterval - The number of milliseconds that have passed
  3902. since the last tick.
  3903. ReturnValue:
  3904. None.
  3905. --*/
  3906. {
  3907. NmpAcquireLock();
  3908. NmpNetworkTimerTick(MsTickInterval);
  3909. NmpJoinTimerTick(MsTickInterval);
  3910. #if DBG
  3911. // Addition for checking for hung RPC threads.
  3912. NmpRpcTimerTick(MsTickInterval);
  3913. #endif // DBG
  3914. NmpReleaseLock();
  3915. return;
  3916. } // NmTimerTick
  3917. error_status_t
  3918. s_JoinAddNode3(
  3919. IN handle_t IDL_handle,
  3920. IN LPCWSTR lpszNodeName,
  3921. IN DWORD dwNodeHighestVersion,
  3922. IN DWORD dwNodeLowestVersion,
  3923. IN DWORD dwNodeProductSuite
  3924. )
  3925. /*++
  3926. Routine Description:
  3927. Adds a new node to the cluster.
  3928. Arguments:
  3929. IDL_handle - RPC binding handle, not used.
  3930. lpszNodeName - Supplies the name of the new node.
  3931. dwNodeHighestVersion - The highest cluster version number that the
  3932. new node can support.
  3933. dwNodeLowestVersion - The lowest cluster version number that the
  3934. new node can support.
  3935. dwNodeProductSuite - The product suite type identifier for the new node.
  3936. Return Value:
  3937. ERROR_SUCCESS if successful
  3938. Win32 error code otherwise.
  3939. Notes:
  3940. This is a new routine in NT5. It performs the AddNode operation
  3941. correctly. It will never be invoked by an NT4 system. It cannot
  3942. be invoked if an NT4 node is in the cluster without violating
  3943. the license agreement.
  3944. The cluster registry APIs cannot be called while holding the NmpLock,
  3945. or a deadlock may occur.
  3946. --*/
  3947. {
  3948. DWORD status;
  3949. DWORD registryNodeLimit;
  3950. ClRtlLogPrint(LOG_NOISE,
  3951. "[NMJOIN] Received request to add node '%1!ws!' to the cluster.\n",
  3952. lpszNodeName
  3953. );
  3954. //
  3955. // Read the necessary registry parameters before acquiring
  3956. // the NM lock.
  3957. //
  3958. status = DmQueryDword(
  3959. DmClusterParametersKey,
  3960. CLUSREG_NAME_MAX_NODES,
  3961. &registryNodeLimit,
  3962. NULL
  3963. );
  3964. if (status != ERROR_SUCCESS) {
  3965. registryNodeLimit = 0;
  3966. }
  3967. NmpAcquireLock();
  3968. if (NmpLockedEnterApi(NmStateOnline)) {
  3969. DWORD retryCount = 0;
  3970. //if this is the last node and it has been evicted
  3971. //but the cleanup hasnt completed and hence the
  3972. //service is up, then it should not entertain
  3973. //any new join requests
  3974. if (NmpLastNodeEvicted)
  3975. {
  3976. ClRtlLogPrint(LOG_UNUSUAL,
  3977. "[NMJOIN] This node was evicted and hence is not in a valid state to process a "
  3978. "request to add a node to the cluster.\n"
  3979. );
  3980. status = ERROR_NODE_NOT_AVAILABLE;
  3981. NmpLockedLeaveApi();
  3982. goto FnExit;
  3983. }
  3984. while (TRUE) {
  3985. if (NmpLeaderNodeId == NmLocalNodeId) {
  3986. //
  3987. // This node is the leader, call the internal
  3988. // handler directly.
  3989. //
  3990. status = NmpAddNode(
  3991. lpszNodeName,
  3992. dwNodeHighestVersion,
  3993. dwNodeLowestVersion,
  3994. dwNodeProductSuite,
  3995. registryNodeLimit
  3996. );
  3997. }
  3998. else {
  3999. //
  4000. // Forward the request to the leader.
  4001. //
  4002. RPC_BINDING_HANDLE binding = Session[NmpLeaderNodeId];
  4003. ClRtlLogPrint(LOG_NOISE,
  4004. "[NMJOIN] Forwarding request to add node '%1!ws!' "
  4005. "to the cluster to the leader (node %!u!).\n",
  4006. lpszNodeName,
  4007. NmpLeaderNodeId
  4008. );
  4009. CL_ASSERT(binding != NULL);
  4010. NmpReleaseLock();
  4011. status = NmRpcAddNode(
  4012. binding,
  4013. lpszNodeName,
  4014. dwNodeHighestVersion,
  4015. dwNodeLowestVersion,
  4016. dwNodeProductSuite
  4017. );
  4018. NmpAcquireLock();
  4019. }
  4020. //
  4021. // Check for the error codes that indicate either that
  4022. // another AddNode operation is in progress or that the
  4023. // leadership is changing. We will retry in these cases.
  4024. //
  4025. if ( (status != ERROR_CLUSTER_JOIN_IN_PROGRESS) &&
  4026. (status != ERROR_NODE_NOT_AVAILABLE)
  4027. ) {
  4028. break;
  4029. }
  4030. //
  4031. // Sleep for 3 seconds and try again. We will give up and
  4032. // return the error after retrying for 2 minutes.
  4033. //
  4034. if (++retryCount > 40) {
  4035. break;
  4036. }
  4037. ClRtlLogPrint(LOG_NOISE,
  4038. "[NMJOIN] AddNode operation for node '%1!ws! delayed "
  4039. "waiting for competing AddNode operation to complete.\n",
  4040. lpszNodeName
  4041. );
  4042. NmpReleaseLock();
  4043. Sleep(3000);
  4044. NmpAcquireLock();
  4045. } // end while(TRUE)
  4046. NmpLockedLeaveApi();
  4047. }
  4048. else {
  4049. ClRtlLogPrint(LOG_UNUSUAL,
  4050. "[NMJOIN] This system is not in a valid state to process a "
  4051. "request to add a node to the cluster.\n"
  4052. );
  4053. status = ERROR_NODE_NOT_AVAILABLE;
  4054. }
  4055. FnExit:
  4056. NmpReleaseLock();
  4057. return(status);
  4058. } // s_NmJoinAddNode3
  4059. // This is used by setup of all highest major versions post 1.0
  4060. error_status_t
  4061. s_JoinAddNode2(
  4062. IN handle_t IDL_handle,
  4063. IN LPCWSTR lpszNodeName,
  4064. IN DWORD dwNodeHighestVersion,
  4065. IN DWORD dwNodeLowestVersion
  4066. )
  4067. /*++
  4068. Routine Description:
  4069. Adds a new node to the cluster database.
  4070. Arguments:
  4071. IDL_handle - RPC binding handle, not used.
  4072. lpszNodeName - Supplies the name of the new node.
  4073. Return Value:
  4074. ERROR_SUCCESS if successful
  4075. Win32 error code otherwise.
  4076. Notes:
  4077. This routine was defined in NT4-SP4. JoinAddNode3 is used by NT5. Since
  4078. it is impossible to install clustering using the NT4-SP4 software,
  4079. this routine should never be invoked.
  4080. --*/
  4081. {
  4082. CL_ASSERT(FALSE);
  4083. return(ERROR_CLUSTER_INCOMPATIBLE_VERSIONS);
  4084. }
  4085. error_status_t
  4086. s_JoinAddNode(
  4087. IN handle_t IDL_handle,
  4088. IN LPCWSTR lpszNodeName
  4089. )
  4090. /*++
  4091. Routine Description:
  4092. Adds a new node to the cluster database.
  4093. Arguments:
  4094. IDL_handle - RPC binding handle, not used.
  4095. lpszNodeName - Supplies the name of the new node.
  4096. Return Value:
  4097. ERROR_SUCCESS if successful
  4098. Win32 error code otherwise.
  4099. Notes:
  4100. This is the routine that NT4-SP3 setup invokes to add a new node to
  4101. a cluster. The combination of NT4-SP3 and NT5 is not supported.
  4102. --*/
  4103. {
  4104. return(ERROR_CLUSTER_INCOMPATIBLE_VERSIONS);
  4105. }
  4106. //
  4107. // The rest of the code is currently unused.
  4108. //
  4109. error_status_t
  4110. s_NmRpcDeliverJoinMessage(
  4111. IN handle_t IDL_handle,
  4112. IN UCHAR * Message,
  4113. IN DWORD MessageLength
  4114. )
  4115. /*++
  4116. Routine Description:
  4117. Server side of the RPC interface for delivering membership
  4118. join messages.
  4119. Arguments:
  4120. IDL_handle - RPC binding handle, not used.
  4121. buffer - Supplies a pointer to the message data.
  4122. length - Supplies the length of the message data.
  4123. Return Value:
  4124. ERROR_SUCCESS
  4125. --*/
  4126. {
  4127. DWORD status = ERROR_SUCCESS;
  4128. #ifdef MM_IN_CLUSNET
  4129. ClRtlLogPrint(LOG_NOISE,
  4130. "[NMJOIN] Delivering join message to Clusnet.\n"
  4131. );
  4132. status = ClusnetDeliverJoinMessage(
  4133. NmClusnetHandle,
  4134. Message,
  4135. MessageLength
  4136. );
  4137. #endif
  4138. return(status);
  4139. }
  4140. #ifdef MM_IN_CLUSNET
  4141. DWORD
  4142. NmpSendJoinMessage(
  4143. IN ULONG DestNodeMask,
  4144. IN PVOID Message,
  4145. IN ULONG MessageLength
  4146. )
  4147. {
  4148. DWORD status = ERROR_SUCCESS;
  4149. CL_NODE_ID node;
  4150. CL_ASSERT(NmMaxNodeId != ClusterInvalidNodeId);
  4151. for ( node = ClusterMinNodeId;
  4152. node <= NmMaxNodeId;
  4153. node++, (DestNodeMask >>= 1)
  4154. )
  4155. {
  4156. if (DestNodeMask & 0x1) {
  4157. if (node != NmLocalNodeId) {
  4158. ClRtlLogPrint(LOG_NOISE,
  4159. "[NMJOIN] Sending join message to node %1!u!.\n",
  4160. node
  4161. );
  4162. status = NmRpcDeliverJoinMessage(
  4163. Session[node->NodeId],
  4164. Message,
  4165. MessageLength
  4166. );
  4167. if (status == RPC_S_CALL_FAILED_DNE) {
  4168. //
  4169. // Try again since the first call to a restarted
  4170. // RPC server will fail.
  4171. //
  4172. status = NmRpcDeliverJoinMessage(
  4173. Session[node->NodeId],
  4174. Message,
  4175. MessageLength
  4176. );
  4177. }
  4178. }
  4179. else {
  4180. ClRtlLogPrint(LOG_NOISE,
  4181. "[NMJOIN] Delivering join message to local node.\n"
  4182. );
  4183. status = ClusnetDeliverJoinMessage(
  4184. NmClusnetHandle,
  4185. Message,
  4186. MessageLength
  4187. );
  4188. }
  4189. if (status != ERROR_SUCCESS) {
  4190. ClRtlLogPrint(LOG_NOISE,
  4191. "[NMJOIN] send of join message to node %1!u! failed, status %2!u!\n",
  4192. node,
  4193. status
  4194. );
  4195. break;
  4196. }
  4197. }
  4198. }
  4199. return(status);
  4200. } // NmpSendJoinMessage
  4201. DWORD
  4202. NmJoinNodeToCluster(
  4203. CL_NODE_ID joinerNodeId
  4204. )
  4205. {
  4206. DWORD status;
  4207. PVOID message = NULL;
  4208. ULONG messageLength;
  4209. ULONG destMask;
  4210. CLUSNET_JOIN_PHASE phase;
  4211. ClRtlLogPrint(LOG_NOISE,
  4212. "[NMJOIN] Joining node %1!u! to the cluster.\n",
  4213. joinerNodeId
  4214. );
  4215. for (phase = ClusnetJoinPhase1; phase <= ClusnetJoinPhase4; phase++) {
  4216. ClRtlLogPrint(LOG_NOISE,
  4217. "[NMJOIN] JoinNode phase %1!u!\n",
  4218. phase
  4219. );
  4220. status = ClusnetJoinCluster(
  4221. NmClusnetHandle,
  4222. joinerNodeId,
  4223. phase,
  4224. NM_MM_JOIN_TIMEOUT,
  4225. &message,
  4226. &messageLength,
  4227. &destMask
  4228. );
  4229. if (status != ERROR_SUCCESS) {
  4230. ClRtlLogPrint(LOG_NOISE,
  4231. "[NMJOIN] JoinNode phase %1!u! failed, status %2!u!\n",
  4232. phase,
  4233. status
  4234. );
  4235. break;
  4236. }
  4237. status = NmpSendJoinMessage(
  4238. destMask,
  4239. message,
  4240. messageLength
  4241. );
  4242. if (status != ERROR_SUCCESS) {
  4243. DWORD abortStatus;
  4244. ClRtlLogPrint(LOG_NOISE,
  4245. "[NMJOIN] send join message failed %1!u!, aborting join of node %2!u!.\n",
  4246. status,
  4247. joinerNodeId
  4248. );
  4249. abortStatus = ClusnetJoinCluster(
  4250. NmClusnetHandle,
  4251. joinerNodeId,
  4252. ClusnetJoinPhaseAbort,
  4253. NM_MM_JOIN_TIMEOUT,
  4254. &message,
  4255. &messageLength,
  4256. &destMask
  4257. );
  4258. if (abortStatus == ERROR_SUCCESS) {
  4259. (VOID) NmpSendJoinMessage(
  4260. destMask,
  4261. message,
  4262. messageLength
  4263. );
  4264. }
  4265. break;
  4266. }
  4267. }
  4268. if (message != NULL) {
  4269. ClusnetEndJoinCluster(NmClusnetHandle, message);
  4270. }
  4271. return(status);
  4272. } // NmJoinNodeToCluster
  4273. #endif // MM_IN_CLUSNET