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.

8441 lines
233 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. network.c
  5. Abstract:
  6. Implements the Node Manager's network management routines.
  7. Author:
  8. Mike Massa (mikemas) 7-Nov-1996
  9. Revision History:
  10. --*/
  11. #include "nmp.h"
  12. /////////////////////////////////////////////////////////////////////////////
  13. //
  14. // Data
  15. //
  16. /////////////////////////////////////////////////////////////////////////////
  17. ULONG NmpNextNetworkShortId = 0;
  18. LIST_ENTRY NmpNetworkList = {NULL, NULL};
  19. LIST_ENTRY NmpInternalNetworkList = {NULL, NULL};
  20. LIST_ENTRY NmpDeletedNetworkList = {NULL, NULL};
  21. DWORD NmpNetworkCount = 0;
  22. DWORD NmpInternalNetworkCount = 0;
  23. DWORD NmpClientNetworkCount = 0;
  24. BOOLEAN NmpIsConnectivityReportWorkerRunning = FALSE;
  25. BOOLEAN NmpNeedConnectivityReport = FALSE;
  26. CLRTL_WORK_ITEM NmpConnectivityReportWorkItem;
  27. RESUTIL_PROPERTY_ITEM
  28. NmpNetworkProperties[] =
  29. {
  30. {
  31. L"Id", NULL, CLUSPROP_FORMAT_SZ,
  32. 0, 0, 0,
  33. 0,
  34. FIELD_OFFSET(NM_NETWORK_INFO, Id)
  35. },
  36. {
  37. CLUSREG_NAME_NET_NAME, NULL, CLUSPROP_FORMAT_SZ,
  38. 0, 0, 0,
  39. 0,
  40. FIELD_OFFSET(NM_NETWORK_INFO, Name)
  41. },
  42. {
  43. CLUSREG_NAME_NET_DESC, NULL, CLUSPROP_FORMAT_SZ,
  44. (DWORD_PTR) NmpNullString, 0, 0,
  45. 0,
  46. FIELD_OFFSET(NM_NETWORK_INFO, Description)
  47. },
  48. {
  49. CLUSREG_NAME_NET_ROLE, NULL, CLUSPROP_FORMAT_DWORD,
  50. ClusterNetworkRoleClientAccess,
  51. ClusterNetworkRoleNone,
  52. ClusterNetworkRoleInternalAndClient,
  53. 0,
  54. FIELD_OFFSET(NM_NETWORK_INFO, Role)
  55. },
  56. {
  57. CLUSREG_NAME_NET_PRIORITY, NULL, CLUSPROP_FORMAT_DWORD,
  58. 0, 0, 0xFFFFFFFF,
  59. 0,
  60. FIELD_OFFSET(NM_NETWORK_INFO, Priority)
  61. },
  62. {
  63. CLUSREG_NAME_NET_TRANSPORT, NULL, CLUSPROP_FORMAT_SZ,
  64. 0, 0, 0,
  65. 0,
  66. FIELD_OFFSET(NM_NETWORK_INFO, Transport)
  67. },
  68. {
  69. CLUSREG_NAME_NET_ADDRESS, NULL, CLUSPROP_FORMAT_SZ,
  70. 0, 0, 0,
  71. 0,
  72. FIELD_OFFSET(NM_NETWORK_INFO, Address)
  73. },
  74. {
  75. CLUSREG_NAME_NET_ADDRESS_MASK, NULL, CLUSPROP_FORMAT_SZ,
  76. 0, 0, 0,
  77. 0,
  78. FIELD_OFFSET(NM_NETWORK_INFO, AddressMask)
  79. },
  80. {
  81. 0
  82. }
  83. };
  84. /////////////////////////////////////////////////////////////////////////////
  85. //
  86. // Initialization & cleanup routines
  87. //
  88. /////////////////////////////////////////////////////////////////////////////
  89. DWORD
  90. NmpInitializeNetworks(
  91. VOID
  92. )
  93. /*++
  94. Routine Description:
  95. Initializes network resources.
  96. Arguments:
  97. None.
  98. Return Value:
  99. A Win32 status value.
  100. --*/
  101. {
  102. DWORD status;
  103. OM_OBJECT_TYPE_INITIALIZE networkTypeInitializer;
  104. ClRtlLogPrint(LOG_NOISE,"[NM] Initializing networks.\n");
  105. //
  106. // Create the network object type
  107. //
  108. ZeroMemory(&networkTypeInitializer, sizeof(OM_OBJECT_TYPE_INITIALIZE));
  109. networkTypeInitializer.ObjectSize = sizeof(NM_NETWORK);
  110. networkTypeInitializer.Signature = NM_NETWORK_SIG;
  111. networkTypeInitializer.Name = L"Network";
  112. networkTypeInitializer.DeleteObjectMethod = &NmpDestroyNetworkObject;
  113. status = OmCreateType(ObjectTypeNetwork, &networkTypeInitializer);
  114. if (status != ERROR_SUCCESS) {
  115. WCHAR errorString[12];
  116. wsprintfW(&(errorString[0]), L"%u", status);
  117. CsLogEvent1(LOG_CRITICAL, CS_EVENT_ALLOCATION_FAILURE, errorString);
  118. ClRtlLogPrint(LOG_CRITICAL,
  119. "[NM] Unable to create network object type, status %1!u!\n",
  120. status
  121. );
  122. return(status);
  123. }
  124. return(status);
  125. } // NmpInitializeNetworks
  126. VOID
  127. NmpCleanupNetworks(
  128. VOID
  129. )
  130. /*++
  131. Routine Description:
  132. Destroys all existing network resources.
  133. Arguments:
  134. None.
  135. Return Value:
  136. None.
  137. --*/
  138. {
  139. PNM_NETWORK network;
  140. PLIST_ENTRY entry;
  141. DWORD status;
  142. ClRtlLogPrint(LOG_NOISE,"[NM] Network cleanup starting...\n");
  143. //
  144. // Now clean up all the network objects.
  145. //
  146. NmpAcquireLock();
  147. while (!IsListEmpty(&NmpNetworkList)) {
  148. entry = NmpNetworkList.Flink;
  149. network = CONTAINING_RECORD(entry, NM_NETWORK, Linkage);
  150. CL_ASSERT(NM_OM_INSERTED(network));
  151. NmpDeleteNetworkObject(network, FALSE);
  152. }
  153. NmpCleanupMulticast();
  154. NmpReleaseLock();
  155. ClRtlLogPrint(LOG_NOISE,"[NM] Network cleanup complete\n");
  156. return;
  157. } // NmpCleanupNetworks
  158. /////////////////////////////////////////////////////////////////////////////
  159. //
  160. // Top-level routines called during network configuration
  161. //
  162. /////////////////////////////////////////////////////////////////////////////
  163. DWORD
  164. NmpCreateNetwork(
  165. IN RPC_BINDING_HANDLE JoinSponsorBinding,
  166. IN PNM_NETWORK_INFO NetworkInfo,
  167. IN PNM_INTERFACE_INFO2 InterfaceInfo
  168. )
  169. /*++
  170. Notes:
  171. Must not be called with NM lock held.
  172. --*/
  173. {
  174. DWORD status;
  175. if (JoinSponsorBinding != NULL) {
  176. //
  177. // We are joining a cluster. Ask the sponsor to add the definition
  178. // to the cluster database. The sponsor will also prompt all active
  179. // nodes to instantiate a corresponding object. The object will be
  180. // instantiated locally later in the join process.
  181. //
  182. status = NmRpcCreateNetwork2(
  183. JoinSponsorBinding,
  184. NmpJoinSequence,
  185. NmLocalNodeIdString,
  186. NetworkInfo,
  187. InterfaceInfo
  188. );
  189. }
  190. else if (NmpState == NmStateOnlinePending) {
  191. HLOCALXSACTION xaction;
  192. //
  193. // We are forming a cluster. Add the definitions to the database.
  194. // The corresponding object will be created later in
  195. // the form process.
  196. //
  197. //
  198. // Start a transaction - this must be done before acquiring the
  199. // NM lock.
  200. //
  201. xaction = DmBeginLocalUpdate();
  202. if (xaction == NULL) {
  203. status = GetLastError();
  204. ClRtlLogPrint(LOG_CRITICAL,
  205. "[NM] Failed to start a transaction, status %1!u!\n",
  206. status
  207. );
  208. return(status);
  209. }
  210. status = NmpCreateNetworkDefinition(NetworkInfo, xaction);
  211. if (status == ERROR_SUCCESS) {
  212. status = NmpCreateInterfaceDefinition(InterfaceInfo, xaction);
  213. }
  214. //
  215. // Complete the transaction - this must be done after releasing
  216. // the NM lock.
  217. //
  218. if (status == ERROR_SUCCESS) {
  219. DmCommitLocalUpdate(xaction);
  220. }
  221. else {
  222. DmAbortLocalUpdate(xaction);
  223. }
  224. }
  225. else {
  226. //
  227. // We are online. This is a PnP update.
  228. //
  229. NmpAcquireLock();
  230. status = NmpGlobalCreateNetwork(NetworkInfo, InterfaceInfo);
  231. NmpReleaseLock();
  232. }
  233. return(status);
  234. } // NmpCreateNetwork
  235. DWORD
  236. NmpSetNetworkName(
  237. IN PNM_NETWORK_INFO NetworkInfo
  238. )
  239. /*++
  240. Notes:
  241. Must not be called with NM lock held.
  242. --*/
  243. {
  244. DWORD status;
  245. if (NmpState == NmStateOnlinePending) {
  246. HLOCALXSACTION xaction;
  247. //
  248. // We are forming a cluster. The local connectoid name has
  249. // precedence. Fix the cluster network name stored in the
  250. // cluster database.
  251. //
  252. //
  253. // Start a transaction - this must be done before acquiring the
  254. // NM lock.
  255. //
  256. xaction = DmBeginLocalUpdate();
  257. if (xaction == NULL) {
  258. status = GetLastError();
  259. ClRtlLogPrint(LOG_CRITICAL,
  260. "[NM] Failed to start a transaction, status %1!u!\n",
  261. status
  262. );
  263. return(status);
  264. }
  265. status = NmpSetNetworkNameDefinition(NetworkInfo, xaction);
  266. //
  267. // Complete the transaction - this must be done after releasing
  268. // the NM lock.
  269. //
  270. if (status == ERROR_SUCCESS) {
  271. DmCommitLocalUpdate(xaction);
  272. }
  273. else {
  274. DmAbortLocalUpdate(xaction);
  275. }
  276. }
  277. else {
  278. //
  279. // We are online. This is either a PnP update or we were called
  280. // back to indicate that a local connectoid name changed.
  281. // Issue a global update to set the cluster network name accordingly.
  282. //
  283. status = NmpGlobalSetNetworkName( NetworkInfo );
  284. }
  285. return(status);
  286. } // NmpSetNetworkName
  287. /////////////////////////////////////////////////////////////////////////////
  288. //
  289. // Remote procedures called by joining nodes.
  290. //
  291. /////////////////////////////////////////////////////////////////////////////
  292. error_status_t
  293. s_NmRpcCreateNetwork(
  294. IN handle_t IDL_handle,
  295. IN DWORD JoinSequence, OPTIONAL
  296. IN LPWSTR JoinerNodeId, OPTIONAL
  297. IN PNM_NETWORK_INFO NetworkInfo,
  298. IN PNM_INTERFACE_INFO InterfaceInfo1
  299. )
  300. {
  301. DWORD status;
  302. NM_INTERFACE_INFO2 interfaceInfo2;
  303. //
  304. // Translate and call the V2.0 procedure. The NetIndex isn't used in this call.
  305. //
  306. CopyMemory(&interfaceInfo2, InterfaceInfo1, sizeof(NM_INTERFACE_INFO));
  307. interfaceInfo2.AdapterId = NmpUnknownString;
  308. interfaceInfo2.NetIndex = NmInvalidInterfaceNetIndex;
  309. status = s_NmRpcCreateNetwork2(
  310. IDL_handle,
  311. JoinSequence,
  312. JoinerNodeId,
  313. NetworkInfo,
  314. &interfaceInfo2
  315. );
  316. return(status);
  317. } // s_NmRpcCreateNetwork
  318. error_status_t
  319. s_NmRpcCreateNetwork2(
  320. IN handle_t IDL_handle,
  321. IN DWORD JoinSequence, OPTIONAL
  322. IN LPWSTR JoinerNodeId, OPTIONAL
  323. IN PNM_NETWORK_INFO NetworkInfo,
  324. IN PNM_INTERFACE_INFO2 InterfaceInfo
  325. )
  326. {
  327. DWORD status = ERROR_SUCCESS;
  328. ClRtlLogPrint(LOG_NOISE,
  329. "[NMJOIN] Received request to create new network %1!ws! for "
  330. "joining node.\n",
  331. NetworkInfo->Id
  332. );
  333. NmpAcquireLock();
  334. if (NmpLockedEnterApi(NmStateOnline)) {
  335. PNM_NODE joinerNode = NULL;
  336. if (lstrcmpW(JoinerNodeId, NmpInvalidJoinerIdString) != 0) {
  337. joinerNode = OmReferenceObjectById(
  338. ObjectTypeNode,
  339. JoinerNodeId
  340. );
  341. if (joinerNode != NULL) {
  342. if ( (JoinSequence == NmpJoinSequence) &&
  343. (NmpJoinerNodeId == joinerNode->NodeId) &&
  344. (NmpSponsorNodeId == NmLocalNodeId) &&
  345. !NmpJoinAbortPending
  346. )
  347. {
  348. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  349. CL_ASSERT(NmpJoinerUp == FALSE);
  350. CL_ASSERT(NmpJoinTimer != 0);
  351. //
  352. // Suspend the join timer while we are working on
  353. // behalf of the joiner. This precludes an abort
  354. // from occuring as well.
  355. //
  356. NmpJoinTimer = 0;
  357. }
  358. else {
  359. status = ERROR_CLUSTER_JOIN_ABORTED;
  360. ClRtlLogPrint(LOG_UNUSUAL,
  361. "[NMJOIN] CreateNetwork call for joining node %1!ws! "
  362. "failed because the join was aborted.\n",
  363. JoinerNodeId
  364. );
  365. }
  366. }
  367. else {
  368. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  369. ClRtlLogPrint(LOG_UNUSUAL,
  370. "[NMJOIN] CreateNetwork call for joining node %1!ws! "
  371. "failed because the node is not a member of the "
  372. "cluster.\n",
  373. JoinerNodeId
  374. );
  375. }
  376. }
  377. if (status == ERROR_SUCCESS) {
  378. status = NmpGlobalCreateNetwork(NetworkInfo, InterfaceInfo);
  379. if (joinerNode != NULL) {
  380. //
  381. // Verify that the join is still in progress
  382. //
  383. if ( (JoinSequence == NmpJoinSequence) &&
  384. (NmpJoinerNodeId == joinerNode->NodeId)
  385. )
  386. {
  387. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  388. CL_ASSERT(NmpJoinerUp == FALSE);
  389. CL_ASSERT(NmpSponsorNodeId == NmLocalNodeId);
  390. CL_ASSERT(NmpJoinTimer == 0);
  391. CL_ASSERT(NmpJoinAbortPending == FALSE);
  392. if (status == ERROR_SUCCESS) {
  393. //
  394. // Restart the join timer.
  395. //
  396. NmpJoinTimer = NM_JOIN_TIMEOUT;
  397. }
  398. else {
  399. //
  400. // Abort the join
  401. //
  402. NmpJoinAbort(status, joinerNode);
  403. }
  404. }
  405. else {
  406. status = ERROR_CLUSTER_JOIN_ABORTED;
  407. ClRtlLogPrint(LOG_UNUSUAL,
  408. "[NMJOIN] CreateNetwork call for joining node %1!ws! "
  409. "failed because the join was aborted.\n",
  410. JoinerNodeId
  411. );
  412. }
  413. }
  414. }
  415. if (joinerNode != NULL) {
  416. OmDereferenceObject(joinerNode);
  417. }
  418. NmpLockedLeaveApi();
  419. }
  420. else {
  421. status = ERROR_NODE_NOT_AVAILABLE;
  422. ClRtlLogPrint(LOG_NOISE,
  423. "[NMJOIN] Not in valid state to process CreateNetwork request.\n"
  424. );
  425. }
  426. NmpReleaseLock();
  427. return(status);
  428. } // s_NmRpcCreateNetwork2
  429. error_status_t
  430. s_NmRpcSetNetworkName(
  431. IN handle_t IDL_handle,
  432. IN DWORD JoinSequence, OPTIONAL
  433. IN LPWSTR JoinerNodeId, OPTIONAL
  434. IN PNM_NETWORK_INFO NetworkInfo
  435. )
  436. {
  437. DWORD status = ERROR_SUCCESS;
  438. ClRtlLogPrint(LOG_NOISE,
  439. "[NMJOIN] Received request to set name of network %1!ws! from "
  440. "joining node %2!ws!.\n",
  441. NetworkInfo->Id,
  442. JoinerNodeId
  443. );
  444. NmpAcquireLock();
  445. if (NmpLockedEnterApi(NmStateOnline)) {
  446. PNM_NODE joinerNode = NULL;
  447. if (lstrcmpW(JoinerNodeId, NmpInvalidJoinerIdString) != 0) {
  448. joinerNode = OmReferenceObjectById(
  449. ObjectTypeNode,
  450. JoinerNodeId
  451. );
  452. if (joinerNode != NULL) {
  453. if ( (JoinSequence == NmpJoinSequence) &&
  454. (NmpJoinerNodeId == joinerNode->NodeId) &&
  455. (NmpSponsorNodeId == NmLocalNodeId) &&
  456. !NmpJoinAbortPending
  457. )
  458. {
  459. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  460. CL_ASSERT(NmpJoinerUp == FALSE);
  461. CL_ASSERT(NmpJoinTimer != 0);
  462. //
  463. // Suspend the join timer while we are working on
  464. // behalf of the joiner. This precludes an abort
  465. // from occuring as well.
  466. //
  467. NmpJoinTimer = 0;
  468. }
  469. else {
  470. status = ERROR_CLUSTER_JOIN_ABORTED;
  471. ClRtlLogPrint(LOG_UNUSUAL,
  472. "[NMJOIN] SetNetworkName call for joining node "
  473. "%1!ws! failed because the join was aborted.\n",
  474. JoinerNodeId
  475. );
  476. }
  477. }
  478. else {
  479. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  480. ClRtlLogPrint(LOG_UNUSUAL,
  481. "[NMJOIN] SetNetworkName call for joining node %1!ws! "
  482. "failed because the node is not a member of the cluster.\n",
  483. JoinerNodeId
  484. );
  485. }
  486. }
  487. if (status == ERROR_SUCCESS) {
  488. status = NmpGlobalSetNetworkName( NetworkInfo );
  489. if (joinerNode != NULL) {
  490. //
  491. // Verify that the join is still in progress
  492. //
  493. if ( (JoinSequence == NmpJoinSequence) &&
  494. (NmpJoinerNodeId == joinerNode->NodeId)
  495. )
  496. {
  497. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  498. CL_ASSERT(NmpJoinerUp == FALSE);
  499. CL_ASSERT(NmpSponsorNodeId == NmLocalNodeId);
  500. CL_ASSERT(NmpJoinTimer == 0);
  501. CL_ASSERT(NmpJoinAbortPending == FALSE);
  502. if (status == ERROR_SUCCESS) {
  503. //
  504. // Restart the join timer.
  505. //
  506. NmpJoinTimer = NM_JOIN_TIMEOUT;
  507. }
  508. else {
  509. //
  510. // Abort the join
  511. //
  512. NmpJoinAbort(status, joinerNode);
  513. }
  514. }
  515. else {
  516. status = ERROR_CLUSTER_JOIN_ABORTED;
  517. ClRtlLogPrint(LOG_UNUSUAL,
  518. "[NMJOIN] SetNetworkName call for joining node "
  519. "%1!ws! failed because the join was aborted.\n",
  520. JoinerNodeId
  521. );
  522. }
  523. }
  524. }
  525. if (joinerNode != NULL) {
  526. OmDereferenceObject(joinerNode);
  527. }
  528. NmpLockedLeaveApi();
  529. }
  530. else {
  531. status = ERROR_NODE_NOT_AVAILABLE;
  532. ClRtlLogPrint(LOG_NOISE,
  533. "[NMJOIN] Not in valid state to process SetNetworkName request.\n"
  534. );
  535. }
  536. NmpReleaseLock();
  537. return(status);
  538. } // s_NmRpcSetNetworkName
  539. error_status_t
  540. s_NmRpcEnumNetworkDefinitions(
  541. IN handle_t IDL_handle,
  542. IN DWORD JoinSequence, OPTIONAL
  543. IN LPWSTR JoinerNodeId, OPTIONAL
  544. OUT PNM_NETWORK_ENUM * NetworkEnum
  545. )
  546. {
  547. DWORD status = ERROR_SUCCESS;
  548. PNM_NODE joinerNode = NULL;
  549. NmpAcquireLock();
  550. if (NmpLockedEnterApi(NmStateOnline)) {
  551. ClRtlLogPrint(LOG_NOISE,
  552. "[NMJOIN] Supplying network information to joining node.\n"
  553. );
  554. if (lstrcmpW(JoinerNodeId, NmpInvalidJoinerIdString) != 0) {
  555. joinerNode = OmReferenceObjectById(
  556. ObjectTypeNode,
  557. JoinerNodeId
  558. );
  559. if (joinerNode != NULL) {
  560. if ( (JoinSequence == NmpJoinSequence) &&
  561. (NmpJoinerNodeId == joinerNode->NodeId) &&
  562. (NmpSponsorNodeId == NmLocalNodeId) &&
  563. !NmpJoinAbortPending
  564. )
  565. {
  566. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  567. CL_ASSERT(NmpJoinerUp == FALSE);
  568. CL_ASSERT(NmpJoinTimer != 0);
  569. //
  570. // Suspend the join timer while we are working on
  571. // behalf of the joiner. This precludes an abort
  572. // from occuring as well.
  573. //
  574. NmpJoinTimer = 0;
  575. }
  576. else {
  577. status = ERROR_CLUSTER_JOIN_ABORTED;
  578. ClRtlLogPrint(LOG_UNUSUAL,
  579. "[NMJOIN] EnumNetworkDefinitions call for joining "
  580. "node %1!ws! failed because the join was aborted.\n",
  581. JoinerNodeId
  582. );
  583. }
  584. }
  585. else {
  586. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  587. ClRtlLogPrint(LOG_UNUSUAL,
  588. "[NMJOIN] EnumNetworkDefinitions call for joining "
  589. "node %1!ws! failed because the node is not a member "
  590. "of the cluster.\n",
  591. JoinerNodeId
  592. );
  593. }
  594. }
  595. if (status == ERROR_SUCCESS) {
  596. status = NmpEnumNetworkObjects(NetworkEnum);
  597. if (joinerNode != NULL) {
  598. if (status == ERROR_SUCCESS) {
  599. //
  600. // Restart the join timer.
  601. //
  602. NmpJoinTimer = NM_JOIN_TIMEOUT;
  603. }
  604. else {
  605. ClRtlLogPrint(LOG_CRITICAL,
  606. "[NMJOIN] Failed to enumerate network definitions, "
  607. "status %1!u!.\n",
  608. status
  609. );
  610. //
  611. // Abort the join
  612. //
  613. NmpJoinAbort(status, joinerNode);
  614. }
  615. }
  616. }
  617. if (joinerNode != NULL) {
  618. OmDereferenceObject(joinerNode);
  619. }
  620. NmpLockedLeaveApi();
  621. }
  622. else {
  623. status = ERROR_NODE_NOT_AVAILABLE;
  624. ClRtlLogPrint(LOG_NOISE,
  625. "[NMJOIN] Not in valid state to process EnumNetworkDefinitions "
  626. "request.\n"
  627. );
  628. }
  629. NmpReleaseLock();
  630. return(status);
  631. } // s_NmRpcEnumNetworkDefinitions
  632. error_status_t
  633. s_NmRpcEnumNetworkAndInterfaceStates(
  634. IN handle_t IDL_handle,
  635. IN DWORD JoinSequence,
  636. IN LPWSTR JoinerNodeId,
  637. OUT PNM_NETWORK_STATE_ENUM * NetworkStateEnum,
  638. OUT PNM_INTERFACE_STATE_ENUM * InterfaceStateEnum
  639. )
  640. {
  641. DWORD status = ERROR_SUCCESS;
  642. NmpAcquireLock();
  643. if (NmpLockedEnterApi(NmStateOnline)) {
  644. PNM_NODE joinerNode = OmReferenceObjectById(
  645. ObjectTypeNode,
  646. JoinerNodeId
  647. );
  648. ClRtlLogPrint(LOG_NOISE,
  649. "[NMJOIN] Supplying network and interface state information "
  650. "to joining node.\n"
  651. );
  652. if (joinerNode != NULL) {
  653. if ( (JoinSequence != NmpJoinSequence) ||
  654. (NmpJoinerNodeId != joinerNode->NodeId) ||
  655. (NmpSponsorNodeId != NmLocalNodeId) ||
  656. NmpJoinAbortPending
  657. )
  658. {
  659. status = ERROR_CLUSTER_JOIN_ABORTED;
  660. ClRtlLogPrint(LOG_UNUSUAL,
  661. "[NMJOIN] EnumNetworkAndInterfaceStates call for "
  662. "joining node %1!ws! failed because the join was "
  663. "aborted.\n",
  664. JoinerNodeId
  665. );
  666. }
  667. else {
  668. CL_ASSERT(joinerNode->State == ClusterNodeJoining);
  669. CL_ASSERT(NmpJoinerUp);
  670. CL_ASSERT(NmpJoinTimer == 0);
  671. }
  672. }
  673. else {
  674. status = ERROR_CLUSTER_NODE_NOT_MEMBER;
  675. ClRtlLogPrint(LOG_UNUSUAL,
  676. "[NMJOIN] EnumNetworkAndInterfaceStates call for joining "
  677. "node %1!ws! failed because the node is not a member of "
  678. "the cluster.\n",
  679. JoinerNodeId
  680. );
  681. }
  682. if (status == ERROR_SUCCESS) {
  683. status = NmpEnumNetworkObjectStates(NetworkStateEnum);
  684. if (status != ERROR_SUCCESS) {
  685. ClRtlLogPrint(LOG_CRITICAL,
  686. "[NMJOIN] EnumNetworkAndInterfaceStates failed, "
  687. "status %1!u!.\n",
  688. status
  689. );
  690. //
  691. // Abort the join
  692. //
  693. NmpJoinAbort(status, joinerNode);
  694. }
  695. status = NmpEnumInterfaceObjectStates(InterfaceStateEnum);
  696. if (status != ERROR_SUCCESS) {
  697. ClRtlLogPrint(LOG_CRITICAL,
  698. "[NMJOIN] EnumNetworkAndInterfaceStates failed, "
  699. "status %1!u!.\n",
  700. status
  701. );
  702. //
  703. // Abort the join
  704. //
  705. NmpJoinAbort(status, joinerNode);
  706. NmpFreeNetworkStateEnum(*NetworkStateEnum);
  707. *NetworkStateEnum = NULL;
  708. }
  709. }
  710. OmDereferenceObject(joinerNode);
  711. NmpLockedLeaveApi();
  712. }
  713. else {
  714. status = ERROR_NODE_NOT_AVAILABLE;
  715. ClRtlLogPrint(LOG_NOISE,
  716. "[NMJOIN] Not in valid state to process "
  717. "EnumNetworkAndInterfaceStates request.\n"
  718. );
  719. }
  720. NmpReleaseLock();
  721. return(status);
  722. } // s_NmRpcEnumNetworkAndInterfaceStates
  723. /////////////////////////////////////////////////////////////////////////////
  724. //
  725. // Routines used to make global configuration changes when the node
  726. // is online.
  727. //
  728. /////////////////////////////////////////////////////////////////////////////
  729. DWORD
  730. NmpGlobalCreateNetwork(
  731. IN PNM_NETWORK_INFO NetworkInfo,
  732. IN PNM_INTERFACE_INFO2 InterfaceInfo
  733. )
  734. /*++
  735. Notes:
  736. Called with the NmpLock held.
  737. --*/
  738. {
  739. DWORD status = ERROR_SUCCESS;
  740. DWORD networkPropertiesSize;
  741. PVOID networkProperties;
  742. ClRtlLogPrint(LOG_NOISE,
  743. "[NM] Issuing global update to create network %1!ws! and "
  744. "interface %2!ws!.\n",
  745. NetworkInfo->Id,
  746. InterfaceInfo->Id
  747. );
  748. //
  749. // Marshall the info structures into property lists.
  750. //
  751. status = NmpMarshallObjectInfo(
  752. NmpNetworkProperties,
  753. NetworkInfo,
  754. &networkProperties,
  755. &networkPropertiesSize
  756. );
  757. if (status == ERROR_SUCCESS) {
  758. DWORD interfacePropertiesSize;
  759. PVOID interfaceProperties;
  760. status = NmpMarshallObjectInfo(
  761. NmpInterfaceProperties,
  762. InterfaceInfo,
  763. &interfaceProperties,
  764. &interfacePropertiesSize
  765. );
  766. if (status == ERROR_SUCCESS) {
  767. NmpReleaseLock();
  768. //
  769. // Issue a global update to create the network
  770. //
  771. status = GumSendUpdateEx(
  772. GumUpdateMembership,
  773. NmUpdateCreateNetwork,
  774. 4,
  775. networkPropertiesSize,
  776. networkProperties,
  777. sizeof(networkPropertiesSize),
  778. &networkPropertiesSize,
  779. interfacePropertiesSize,
  780. interfaceProperties,
  781. sizeof(interfacePropertiesSize),
  782. &interfacePropertiesSize
  783. );
  784. if (status != ERROR_SUCCESS) {
  785. ClRtlLogPrint(LOG_CRITICAL,
  786. "[NM] Global update to create network %1!ws! failed, "
  787. "status %2!u!.\n",
  788. NetworkInfo->Id,
  789. status
  790. );
  791. }
  792. NmpAcquireLock();
  793. MIDL_user_free(interfaceProperties);
  794. }
  795. else {
  796. ClRtlLogPrint(LOG_CRITICAL,
  797. "[NM] Failed to marshall properties for new interface "
  798. "%1!ws!, status %2!u!\n",
  799. InterfaceInfo->Id,
  800. status
  801. );
  802. }
  803. MIDL_user_free(networkProperties);
  804. }
  805. else {
  806. ClRtlLogPrint(LOG_CRITICAL,
  807. "[NM] Failed to marshall properties for new network %1!ws!, "
  808. "status %2!u!\n",
  809. NetworkInfo->Id,
  810. status
  811. );
  812. }
  813. return(status);
  814. } // NmpGlobalCreateNetwork
  815. DWORD
  816. NmpGlobalSetNetworkName(
  817. IN PNM_NETWORK_INFO NetworkInfo
  818. )
  819. /*++
  820. Routine Description:
  821. Changes the name of a network defined for the cluster.
  822. Arguments:
  823. NetworkInfo - A pointer to info about the network to be modified.
  824. Return Value:
  825. ERROR_SUCCESS if the routine succeeds.
  826. A Win32 error code otherwise.
  827. Notes:
  828. Must not be called with NM lock held.
  829. --*/
  830. {
  831. DWORD status = ERROR_SUCCESS;
  832. if (status == ERROR_SUCCESS) {
  833. ClRtlLogPrint(LOG_NOISE,
  834. "[NM] Processing request to set name for network %1!ws! "
  835. "to '%2!ws!'.\n",
  836. NetworkInfo->Id,
  837. NetworkInfo->Name
  838. );
  839. //
  840. // Issue a global update
  841. //
  842. status = GumSendUpdateEx(
  843. GumUpdateMembership,
  844. NmUpdateSetNetworkName,
  845. 2,
  846. NM_WCSLEN(NetworkInfo->Id),
  847. NetworkInfo->Id,
  848. NM_WCSLEN( NetworkInfo->Name ),
  849. NetworkInfo->Name
  850. );
  851. if (status != ERROR_SUCCESS) {
  852. ClRtlLogPrint(LOG_CRITICAL,
  853. "[NM] Global update to set name of network %1!ws! "
  854. "failed, status %2!u!.\n",
  855. NetworkInfo->Id,
  856. status
  857. );
  858. }
  859. }
  860. else {
  861. ClRtlLogPrint(LOG_UNUSUAL,
  862. "[NM] New name parameter supplied for network %1!ws! is invalid\n",
  863. NetworkInfo->Id
  864. );
  865. }
  866. return(status);
  867. } // NmpGlobalSetNetworkName
  868. DWORD
  869. NmpGlobalSetNetworkAndInterfaceStates(
  870. PNM_NETWORK Network,
  871. CLUSTER_NETWORK_STATE NewNetworkState
  872. )
  873. /*++
  874. Notes:
  875. Called with NmpLock held and the Network referenced.
  876. --*/
  877. {
  878. DWORD status;
  879. DWORD i;
  880. LPCWSTR networkId = OmObjectId(Network);
  881. DWORD entryCount = Network->ConnectivityVector->EntryCount;
  882. DWORD vectorSize = sizeof(NM_STATE_ENTRY) * entryCount;
  883. PNM_STATE_ENTRY ifStateVector;
  884. ifStateVector = LocalAlloc(LMEM_FIXED, vectorSize);
  885. if (ifStateVector != NULL ) {
  886. for (i=0; i< entryCount; i++) {
  887. ifStateVector[i] = Network->StateWorkVector[i].State;
  888. }
  889. if (NmpState == NmStateOnline) {
  890. //
  891. // Issue a global state update for this network.
  892. //
  893. NmpReleaseLock();
  894. status = GumSendUpdateEx(
  895. GumUpdateMembership,
  896. NmUpdateSetNetworkAndInterfaceStates,
  897. 4,
  898. NM_WCSLEN(networkId),
  899. networkId,
  900. sizeof(NewNetworkState),
  901. &NewNetworkState,
  902. vectorSize,
  903. ifStateVector,
  904. sizeof(entryCount),
  905. &entryCount
  906. );
  907. NmpAcquireLock();
  908. }
  909. else {
  910. CL_ASSERT(NmpState == NmStateOnlinePending);
  911. //
  912. // We're still in the form process. Bypass GUM.
  913. //
  914. NmpSetNetworkAndInterfaceStates(
  915. Network,
  916. NewNetworkState,
  917. ifStateVector,
  918. entryCount
  919. );
  920. status = ERROR_SUCCESS;
  921. }
  922. LocalFree(ifStateVector);
  923. }
  924. else {
  925. status = ERROR_NOT_ENOUGH_MEMORY;
  926. }
  927. return(status);
  928. } // NmpGlobalSetNetworkAndInterfaceStates
  929. /////////////////////////////////////////////////////////////////////////////
  930. //
  931. // Routines called by other cluster service components
  932. //
  933. /////////////////////////////////////////////////////////////////////////////
  934. CLUSTER_NETWORK_STATE
  935. NmGetNetworkState(
  936. IN PNM_NETWORK Network
  937. )
  938. /*++
  939. Routine Description:
  940. Arguments:
  941. Return Value:
  942. Notes:
  943. Because the caller must have a reference on the object and the
  944. call is so simple, there is no reason to put the call through the
  945. EnterApi/LeaveApi dance.
  946. --*/
  947. {
  948. CLUSTER_NETWORK_STATE state;
  949. NmpAcquireLock();
  950. state = Network->State;
  951. NmpReleaseLock();
  952. return(state);
  953. } // NmGetNetworkState
  954. DWORD
  955. NmSetNetworkName(
  956. IN PNM_NETWORK Network,
  957. IN LPCWSTR Name
  958. )
  959. /*++
  960. Routine Description:
  961. Changes the name of a network defined for the cluster.
  962. Arguments:
  963. Network - A pointer to the object for the network to be modified.
  964. Return Value:
  965. ERROR_SUCCESS if the routine succeeds.
  966. A Win32 error code otherwise.
  967. Notes:
  968. The network object must be referenced by the caller.
  969. --*/
  970. {
  971. DWORD status = ERROR_SUCCESS;
  972. if (NmpEnterApi(NmStateOnline)) {
  973. LPCWSTR networkId = OmObjectId(Network);
  974. DWORD nameLength;
  975. //
  976. // Validate the name
  977. //
  978. try {
  979. nameLength = lstrlenW(Name);
  980. if (nameLength == 0) {
  981. status = ERROR_INVALID_PARAMETER;
  982. }
  983. }
  984. except (EXCEPTION_EXECUTE_HANDLER) {
  985. status = ERROR_INVALID_PARAMETER;
  986. }
  987. if (status == ERROR_SUCCESS) {
  988. ClRtlLogPrint(LOG_NOISE,
  989. "[NM] Processing request to set name for network %1!ws! "
  990. "to %2!ws!.\n",
  991. networkId,
  992. Name
  993. );
  994. //
  995. // Issue a global update
  996. //
  997. status = GumSendUpdateEx(
  998. GumUpdateMembership,
  999. NmUpdateSetNetworkName,
  1000. 2,
  1001. NM_WCSLEN(networkId),
  1002. networkId,
  1003. (nameLength + 1) * sizeof(WCHAR),
  1004. Name
  1005. );
  1006. if (status != ERROR_SUCCESS) {
  1007. ClRtlLogPrint(LOG_CRITICAL,
  1008. "[NM] Global update to set name of network %1!ws! "
  1009. "failed, status %2!u!.\n",
  1010. networkId,
  1011. status
  1012. );
  1013. }
  1014. }
  1015. else {
  1016. ClRtlLogPrint(LOG_UNUSUAL,
  1017. "[NM] New name parameter supplied for network %1!ws! "
  1018. "is invalid\n",
  1019. networkId
  1020. );
  1021. }
  1022. NmpLeaveApi();
  1023. }
  1024. else {
  1025. status = ERROR_NODE_NOT_AVAILABLE;
  1026. ClRtlLogPrint(LOG_NOISE,
  1027. "[NM] Not in valid state to process SetNetworkName request.\n"
  1028. );
  1029. }
  1030. return(status);
  1031. } // NmSetNetworkName
  1032. DWORD
  1033. NmSetNetworkPriorityOrder(
  1034. IN DWORD NetworkCount,
  1035. IN LPWSTR * NetworkIdList
  1036. )
  1037. /*++
  1038. Routine Description:
  1039. Sets the priority ordering of internal networks.
  1040. Arguments:
  1041. NetworkCount - Contains the count of items in NetworkIdList.
  1042. NetworkIdList - A pointer to an array of pointers to unicode strings.
  1043. Each string contains the ID of one internal network.
  1044. The array is sorted in priority order. The highest
  1045. priority network is listed first in the array.
  1046. Return Value:
  1047. ERROR_SUCCESS if the routine is successful.
  1048. A Win32 error code othewise.
  1049. --*/
  1050. {
  1051. DWORD status = ERROR_SUCCESS;
  1052. if (NetworkCount == 0) {
  1053. return(ERROR_INVALID_PARAMETER);
  1054. }
  1055. ClRtlLogPrint(LOG_NOISE,
  1056. "[NM] Received request to set network priority order.\n"
  1057. );
  1058. if (NmpEnterApi(NmStateOnline)) {
  1059. DWORD i;
  1060. DWORD multiSzLength = 0;
  1061. PVOID multiSz = NULL;
  1062. //
  1063. // Marshall the network ID list into a MULTI_SZ.
  1064. //
  1065. for (i=0; i< NetworkCount; i++) {
  1066. multiSzLength += NM_WCSLEN(NetworkIdList[i]);
  1067. }
  1068. multiSzLength += sizeof(UNICODE_NULL);
  1069. multiSz = MIDL_user_allocate(multiSzLength);
  1070. if (multiSz != NULL) {
  1071. LPWSTR tmp = multiSz;
  1072. for (i=0; i< NetworkCount; i++) {
  1073. lstrcpyW(tmp, NetworkIdList[i]);
  1074. tmp += lstrlenW(NetworkIdList[i]) + 1;
  1075. }
  1076. *tmp = UNICODE_NULL;
  1077. //
  1078. // Issue a global update
  1079. //
  1080. status = GumSendUpdateEx(
  1081. GumUpdateMembership,
  1082. NmUpdateSetNetworkPriorityOrder,
  1083. 1,
  1084. multiSzLength,
  1085. multiSz
  1086. );
  1087. if (status != ERROR_SUCCESS) {
  1088. ClRtlLogPrint(LOG_CRITICAL,
  1089. "[NM] Global update to reprioritize networks failed, "
  1090. "status %1!u!.\n",
  1091. status
  1092. );
  1093. }
  1094. MIDL_user_free(multiSz);
  1095. }
  1096. else {
  1097. status = ERROR_NOT_ENOUGH_MEMORY;
  1098. }
  1099. NmpLeaveApi();
  1100. }
  1101. else {
  1102. status = ERROR_NODE_NOT_AVAILABLE;
  1103. ClRtlLogPrint(LOG_NOISE,
  1104. "[NM] Not in valid state to process a request to set the "
  1105. "network priority order.\n"
  1106. );
  1107. }
  1108. return(status);
  1109. } // NmSetNetworkPriorityOrder
  1110. DWORD
  1111. NmEnumInternalNetworks(
  1112. OUT LPDWORD NetworkCount,
  1113. OUT PNM_NETWORK * NetworkList[]
  1114. )
  1115. /*++
  1116. Routine Description:
  1117. Returns a prioritized list of networks that are eligible to
  1118. carry internal communication.
  1119. Arguments:
  1120. NetworkCount - On output, contains the number of items in NetworkList.
  1121. NetworkList - On output, points to an array of pointers to network
  1122. objects. The highest priority network is first in the
  1123. array. Each pointer in the array must be dereferenced
  1124. by the caller. The storage for the array must be
  1125. deallocated by the caller.
  1126. Return Value:
  1127. ERROR_SUCCESS if the routine is successful.
  1128. A Win32 error code othewise.
  1129. --*/
  1130. {
  1131. DWORD status;
  1132. NmpAcquireLock();
  1133. if (NmpLockedEnterApi(NmStateOnline)) {
  1134. status = NmpEnumInternalNetworks(NetworkCount, NetworkList);
  1135. NmpLockedLeaveApi();
  1136. }
  1137. else {
  1138. status = ERROR_NODE_NOT_AVAILABLE;
  1139. ClRtlLogPrint(LOG_NOISE,
  1140. "[NM] Not in valid state to process EnumInternalNetworks "
  1141. "request.\n"
  1142. );
  1143. }
  1144. NmpReleaseLock();
  1145. return(status);
  1146. } // NmEnumInternalNetworks
  1147. DWORD
  1148. NmpEnumInternalNetworks(
  1149. OUT LPDWORD NetworkCount,
  1150. OUT PNM_NETWORK * NetworkList[]
  1151. )
  1152. /*++
  1153. Routine Description:
  1154. Returns a prioritized list of networks that are eligible to
  1155. carry internal communication.
  1156. Arguments:
  1157. NetworkCount - On output, contains the number of items in NetworkList.
  1158. NetworkList - On output, points to an array of pointers to network
  1159. objects. The highest priority network is first in the
  1160. array. Each pointer in the array must be dereferenced
  1161. by the caller. The storage for the array must be
  1162. deallocated by the caller.
  1163. Return Value:
  1164. ERROR_SUCCESS if the routine is successful.
  1165. A Win32 error code othewise.
  1166. Notes:
  1167. Called with NM Lock held.
  1168. --*/
  1169. {
  1170. DWORD status = ERROR_SUCCESS;
  1171. if (NmpInternalNetworkCount > 0) {
  1172. PNM_NETWORK * networkList = LocalAlloc(
  1173. LMEM_FIXED,
  1174. ( sizeof(PNM_NETWORK) *
  1175. NmpInternalNetworkCount)
  1176. );
  1177. if (networkList != NULL) {
  1178. PNM_NETWORK network;
  1179. PLIST_ENTRY entry;
  1180. DWORD networkCount = 0;
  1181. //
  1182. // The internal network list is sorted in priority order.
  1183. // The highest priority network is at the head of the list.
  1184. //
  1185. for (entry = NmpInternalNetworkList.Flink;
  1186. entry != &NmpInternalNetworkList;
  1187. entry = entry->Flink
  1188. )
  1189. {
  1190. network = CONTAINING_RECORD(
  1191. entry,
  1192. NM_NETWORK,
  1193. InternalLinkage
  1194. );
  1195. CL_ASSERT(NmpIsNetworkForInternalUse(network));
  1196. OmReferenceObject(network);
  1197. networkList[networkCount++] = network;
  1198. }
  1199. CL_ASSERT(networkCount == NmpInternalNetworkCount);
  1200. *NetworkCount = networkCount;
  1201. *NetworkList = networkList;
  1202. }
  1203. else {
  1204. status = ERROR_NOT_ENOUGH_MEMORY;
  1205. }
  1206. }
  1207. else {
  1208. *NetworkCount = 0;
  1209. *NetworkList = NULL;
  1210. }
  1211. return(status);
  1212. } // NmpEnumInternalNetworks
  1213. DWORD
  1214. NmEnumNetworkInterfaces(
  1215. IN PNM_NETWORK Network,
  1216. OUT LPDWORD InterfaceCount,
  1217. OUT PNM_INTERFACE * InterfaceList[]
  1218. )
  1219. /*++
  1220. Routine Description:
  1221. Returns the list of interfaces associated with a specified network.
  1222. Arguments:
  1223. Network - A pointer to the network object for which to enumerate
  1224. interfaces.
  1225. InterfaceCount - On output, contains the number of items in InterfaceList.
  1226. InterfaceList - On output, points to an array of pointers to interface
  1227. objects. Each pointer in the array must be dereferenced
  1228. by the caller. The storage for the array must be
  1229. deallocated by the caller.
  1230. Return Value:
  1231. ERROR_SUCCESS if the routine is successful.
  1232. A Win32 error code othewise.
  1233. --*/
  1234. {
  1235. DWORD status = ERROR_SUCCESS;
  1236. NmpAcquireLock();
  1237. if (NmpLockedEnterApi(NmStateOnline)) {
  1238. if (Network->InterfaceCount > 0) {
  1239. PNM_INTERFACE * interfaceList = LocalAlloc(
  1240. LMEM_FIXED,
  1241. ( sizeof(PNM_INTERFACE) *
  1242. Network->InterfaceCount)
  1243. );
  1244. if (interfaceList != NULL) {
  1245. PNM_INTERFACE netInterface;
  1246. PLIST_ENTRY entry;
  1247. DWORD i;
  1248. for (entry = Network->InterfaceList.Flink, i=0;
  1249. entry != &(Network->InterfaceList);
  1250. entry = entry->Flink, i++
  1251. )
  1252. {
  1253. netInterface = CONTAINING_RECORD(
  1254. entry,
  1255. NM_INTERFACE,
  1256. NetworkLinkage
  1257. );
  1258. OmReferenceObject(netInterface);
  1259. interfaceList[i] = netInterface;
  1260. }
  1261. *InterfaceCount = Network->InterfaceCount;
  1262. *InterfaceList = interfaceList;
  1263. }
  1264. else {
  1265. status = ERROR_NOT_ENOUGH_MEMORY;
  1266. }
  1267. }
  1268. else {
  1269. *InterfaceCount = 0;
  1270. *InterfaceList = NULL;
  1271. }
  1272. NmpLockedLeaveApi();
  1273. }
  1274. else {
  1275. status = ERROR_NODE_NOT_AVAILABLE;
  1276. ClRtlLogPrint(LOG_UNUSUAL,
  1277. "[NM] Not in valid state to process EnumNetworkInterfaces "
  1278. "request.\n"
  1279. );
  1280. }
  1281. NmpReleaseLock();
  1282. return(status);
  1283. } // NmEnumNetworkInterfaces
  1284. /////////////////////////////////////////////////////////////////////////////
  1285. //
  1286. // Handlers for global updates
  1287. //
  1288. /////////////////////////////////////////////////////////////////////////////
  1289. DWORD
  1290. NmpUpdateCreateNetwork(
  1291. IN BOOL IsSourceNode,
  1292. IN PVOID NetworkPropertyList,
  1293. IN LPDWORD NetworkPropertyListSize,
  1294. IN PVOID InterfacePropertyList,
  1295. IN LPDWORD InterfacePropertyListSize
  1296. )
  1297. /*++
  1298. Routine Description:
  1299. Global update handler for creating a new network. The network
  1300. definition is read from the cluster database, and a corresponding
  1301. object is instantiated. The cluster transport is also updated if
  1302. necessary.
  1303. Arguments:
  1304. IsSourceNode - Set to TRUE if this node is the source of the update.
  1305. Set to FALSE otherwise.
  1306. Return Value:
  1307. ERROR_SUCCESS if the routine succeeds.
  1308. A Win32 error code otherwise.
  1309. Notes:
  1310. This routine must not be called with NM lock held.
  1311. --*/
  1312. {
  1313. DWORD status;
  1314. NM_NETWORK_INFO networkInfo;
  1315. NM_INTERFACE_INFO2 interfaceInfo;
  1316. PNM_NETWORK network = NULL;
  1317. PNM_INTERFACE netInterface = NULL;
  1318. HLOCALXSACTION xaction = NULL;
  1319. BOOLEAN isInternalNetwork = FALSE;
  1320. BOOLEAN isLockAcquired = FALSE;
  1321. CL_NODE_ID joinerNodeId;
  1322. if (!NmpEnterApi(NmStateOnline)) {
  1323. ClRtlLogPrint(LOG_NOISE,
  1324. "[NM] Not in valid state to process CreateNetwork update.\n"
  1325. );
  1326. return(ERROR_NODE_NOT_AVAILABLE);
  1327. }
  1328. //
  1329. // Unmarshall the property lists.
  1330. //
  1331. ZeroMemory(&networkInfo, sizeof(networkInfo));
  1332. ZeroMemory(&interfaceInfo, sizeof(interfaceInfo));
  1333. status = ClRtlVerifyPropertyTable(
  1334. NmpNetworkProperties,
  1335. NULL, // Reserved
  1336. FALSE, // Don't allow unknowns
  1337. NetworkPropertyList,
  1338. *NetworkPropertyListSize,
  1339. (LPBYTE) &networkInfo
  1340. );
  1341. if ( status != ERROR_SUCCESS ) {
  1342. ClRtlLogPrint( LOG_CRITICAL,
  1343. "[NM] Failed to unmarshall properties for new network, "
  1344. "status %1!u!.\n",
  1345. status
  1346. );
  1347. goto error_exit;
  1348. }
  1349. status = ClRtlVerifyPropertyTable(
  1350. NmpInterfaceProperties,
  1351. NULL, // Reserved
  1352. FALSE, // Don't allow unknowns
  1353. InterfacePropertyList,
  1354. *InterfacePropertyListSize,
  1355. (LPBYTE) &interfaceInfo
  1356. );
  1357. if ( status != ERROR_SUCCESS ) {
  1358. ClRtlLogPrint( LOG_CRITICAL,
  1359. "[NM] Failed to unmarshall properties for new interface, "
  1360. "status %1!u!.\n",
  1361. status
  1362. );
  1363. goto error_exit;
  1364. }
  1365. ClRtlLogPrint(LOG_NOISE,
  1366. "[NM] Received update to create network %1!ws! & interface %2!ws!.\n",
  1367. networkInfo.Id,
  1368. interfaceInfo.Id
  1369. );
  1370. //
  1371. // Start a transaction - this must be done before acquiring the NM lock.
  1372. //
  1373. xaction = DmBeginLocalUpdate();
  1374. if (xaction == NULL) {
  1375. status = GetLastError();
  1376. ClRtlLogPrint(LOG_CRITICAL,
  1377. "[NM] Failed to begin a transaction, status %1!u!\n",
  1378. status
  1379. );
  1380. goto error_exit;
  1381. }
  1382. NmpAcquireLock(); isLockAcquired = TRUE;
  1383. //
  1384. // Fix up the network's priority, if needed.
  1385. //
  1386. if (networkInfo.Role & ClusterNetworkRoleInternalUse) {
  1387. CL_ASSERT(networkInfo.Priority == 0xFFFFFFFF);
  1388. //
  1389. // The network's priority is one greater than that of the lowest
  1390. // priority network already in the internal network list.
  1391. //
  1392. if (IsListEmpty(&NmpInternalNetworkList)) {
  1393. networkInfo.Priority = 1;
  1394. }
  1395. else {
  1396. PNM_NETWORK network = CONTAINING_RECORD(
  1397. NmpInternalNetworkList.Blink,
  1398. NM_NETWORK,
  1399. InternalLinkage
  1400. );
  1401. CL_ASSERT(network->Priority != 0);
  1402. CL_ASSERT(network->Priority != 0xFFFFFFFF);
  1403. networkInfo.Priority = network->Priority + 1;
  1404. }
  1405. isInternalNetwork = TRUE;
  1406. }
  1407. //
  1408. // Update the database.
  1409. //
  1410. status = NmpCreateNetworkDefinition(&networkInfo, xaction);
  1411. if (status != ERROR_SUCCESS) {
  1412. goto error_exit;
  1413. }
  1414. status = NmpCreateInterfaceDefinition(&interfaceInfo, xaction);
  1415. if (status != ERROR_SUCCESS) {
  1416. goto error_exit;
  1417. }
  1418. joinerNodeId = NmpJoinerNodeId;
  1419. NmpReleaseLock(); isLockAcquired = FALSE;
  1420. network = NmpCreateNetworkObject(&networkInfo);
  1421. if (network == NULL) {
  1422. status = GetLastError();
  1423. ClRtlLogPrint(LOG_CRITICAL,
  1424. "[NM] Failed to create object for network %1!ws!, "
  1425. "status %2!u!.\n",
  1426. networkInfo.Id,
  1427. status
  1428. );
  1429. goto error_exit;
  1430. }
  1431. netInterface = NmpCreateInterfaceObject(
  1432. &interfaceInfo,
  1433. TRUE // Do retry on failure
  1434. );
  1435. #ifdef CLUSTER_TESTPOINT
  1436. TESTPT(TpFailNmCreateNetwork) {
  1437. NmpAcquireLock();
  1438. NmpDeleteInterfaceObject(netInterface, FALSE); netInterface = NULL;
  1439. NmpReleaseLock();
  1440. SetLastError(999999);
  1441. }
  1442. #endif
  1443. NmpAcquireLock(); isLockAcquired = TRUE;
  1444. if (netInterface == NULL) {
  1445. status = GetLastError();
  1446. ClRtlLogPrint(LOG_CRITICAL,
  1447. "[NM] Failed to create object for interface %1!ws!, "
  1448. "status %2!u!.\n",
  1449. interfaceInfo.Id,
  1450. status
  1451. );
  1452. NmpDeleteNetworkObject(network, FALSE);
  1453. OmDereferenceObject(network);
  1454. goto error_exit;
  1455. }
  1456. //
  1457. // If a node happens to be joining right now, flag the fact that
  1458. // it is now out of synch with the cluster config.
  1459. //
  1460. if ( ( (joinerNodeId != ClusterInvalidNodeId) &&
  1461. (netInterface->Node->NodeId != joinerNodeId)
  1462. ) ||
  1463. ( (NmpJoinerNodeId != ClusterInvalidNodeId) &&
  1464. (netInterface->Node->NodeId != NmpJoinerNodeId)
  1465. )
  1466. )
  1467. {
  1468. NmpJoinerOutOfSynch = TRUE;
  1469. }
  1470. ClusterEvent(CLUSTER_EVENT_NETWORK_ADDED, network);
  1471. ClusterEvent(CLUSTER_EVENT_NETINTERFACE_ADDED, netInterface);
  1472. if (isInternalNetwork) {
  1473. NmpIssueClusterPropertyChangeEvent();
  1474. }
  1475. OmDereferenceObject(netInterface);
  1476. OmDereferenceObject(network);
  1477. CL_ASSERT(status == ERROR_SUCCESS);
  1478. error_exit:
  1479. if (isLockAcquired) {
  1480. NmpLockedLeaveApi();
  1481. NmpReleaseLock();
  1482. }
  1483. else {
  1484. NmpLeaveApi();
  1485. }
  1486. if (xaction != NULL) {
  1487. //
  1488. // Complete the transaction - this must be done after releasing
  1489. // the NM lock.
  1490. //
  1491. if (status == ERROR_SUCCESS) {
  1492. DmCommitLocalUpdate(xaction);
  1493. }
  1494. else {
  1495. DmAbortLocalUpdate(xaction);
  1496. }
  1497. }
  1498. ClNetFreeNetworkInfo(&networkInfo);
  1499. ClNetFreeInterfaceInfo(&interfaceInfo);
  1500. return(status);
  1501. } // NmpUpdateCreateNetwork
  1502. DWORD
  1503. NmpUpdateSetNetworkName(
  1504. IN BOOL IsSourceNode,
  1505. IN LPWSTR NetworkId,
  1506. IN LPWSTR NewNetworkName
  1507. )
  1508. /*++
  1509. Routine Description:
  1510. Global update handler for setting the name of a network.
  1511. Arguments:
  1512. IsSourceNode - Set to TRUE if this node is the source of the update.
  1513. Set to FALSE otherwise.
  1514. NetworkId - A pointer to a unicode string containing the ID of the
  1515. network to update.
  1516. NewNetworkName - A pointer to a unicode string containing the new network name.
  1517. Return Value:
  1518. ERROR_SUCCESS if the routine succeeds.
  1519. A Win32 error code otherwise.
  1520. Notes:
  1521. This routine must not be called with NM lock held.
  1522. --*/
  1523. {
  1524. DWORD status;
  1525. DWORD i;
  1526. PLIST_ENTRY entry;
  1527. HLOCALXSACTION xaction = NULL;
  1528. HDMKEY networkKey;
  1529. HDMKEY netInterfaceKey;
  1530. PNM_NETWORK network = NULL;
  1531. PNM_INTERFACE netInterface;
  1532. LPCWSTR netInterfaceId;
  1533. LPCWSTR netInterfaceName;
  1534. LPCWSTR networkName;
  1535. LPCWSTR nodeName;
  1536. LPWSTR oldNetworkName = NULL;
  1537. LPWSTR * oldNameVector = NULL;
  1538. LPWSTR * newNameVector = NULL;
  1539. BOOLEAN isLockAcquired = FALSE;
  1540. DWORD interfaceCount;
  1541. if (!NmpEnterApi(NmStateOnline)) {
  1542. ClRtlLogPrint(LOG_NOISE,
  1543. "[NM] Not in valid state to process SetNetworkName update.\n"
  1544. );
  1545. return(ERROR_NODE_NOT_AVAILABLE);
  1546. }
  1547. ClRtlLogPrint(LOG_NOISE,
  1548. "[NM] Received update to set the name for network %1!ws! "
  1549. "to '%2!ws!'.\n",
  1550. NetworkId,
  1551. NewNetworkName
  1552. );
  1553. //
  1554. // Find the network's object
  1555. //
  1556. network = OmReferenceObjectById(ObjectTypeNetwork, NetworkId);
  1557. if (network == NULL) {
  1558. ClRtlLogPrint(LOG_CRITICAL,
  1559. "[NM] Unable to find network %1!ws!.\n",
  1560. NetworkId
  1561. );
  1562. status = ERROR_CLUSTER_NETWORK_NOT_FOUND;
  1563. goto error_exit;
  1564. }
  1565. //
  1566. // Start a transaction - this must be done before acquiring the NM lock.
  1567. //
  1568. xaction = DmBeginLocalUpdate();
  1569. if (xaction == NULL) {
  1570. status = GetLastError();
  1571. ClRtlLogPrint(LOG_CRITICAL,
  1572. "[NM] Failed to begin a transaction, status %1!u!\n",
  1573. status
  1574. );
  1575. goto error_exit;
  1576. }
  1577. NmpAcquireLock(); isLockAcquired = TRUE;
  1578. //
  1579. // compare the names. If the same, return success
  1580. //
  1581. if ( _wcsicmp( OmObjectName( network ), NewNetworkName ) == 0 ) {
  1582. ClRtlLogPrint(LOG_NOISE, "[NM] Network name does not need changing.\n");
  1583. status = ERROR_SUCCESS;
  1584. goto error_exit;
  1585. }
  1586. networkName = OmObjectName(network);
  1587. oldNetworkName = LocalAlloc(LMEM_FIXED, NM_WCSLEN(networkName));
  1588. if (oldNetworkName == NULL) {
  1589. ClRtlLogPrint(LOG_CRITICAL,
  1590. "[NM] Failed to allocate memory for network %1!ws! name change!\n",
  1591. NetworkId
  1592. );
  1593. status = ERROR_NOT_ENOUGH_MEMORY;
  1594. goto error_exit;
  1595. }
  1596. wcscpy(oldNetworkName, networkName);
  1597. //
  1598. // Update the database.
  1599. //
  1600. // This processing can always be undone on error.
  1601. //
  1602. networkKey = DmOpenKey(DmNetworksKey, NetworkId, KEY_WRITE);
  1603. if (networkKey == NULL) {
  1604. status = GetLastError();
  1605. ClRtlLogPrint(LOG_CRITICAL,
  1606. "[NM] Failed to open database key for network %1!ws!, "
  1607. "status %2!u!\n",
  1608. NetworkId,
  1609. status
  1610. );
  1611. goto error_exit;
  1612. }
  1613. status = DmLocalSetValue(
  1614. xaction,
  1615. networkKey,
  1616. CLUSREG_NAME_NET_NAME,
  1617. REG_SZ,
  1618. (CONST BYTE *) NewNetworkName,
  1619. NM_WCSLEN(NewNetworkName)
  1620. );
  1621. DmCloseKey(networkKey);
  1622. if (status != ERROR_SUCCESS) {
  1623. ClRtlLogPrint(LOG_CRITICAL,
  1624. "[NM] Set of name value failed for network %1!ws!, "
  1625. "status %2!u!.\n",
  1626. NetworkId,
  1627. status
  1628. );
  1629. goto error_exit;
  1630. }
  1631. //
  1632. // Update the names of all of the interfaces on this network
  1633. //
  1634. interfaceCount = network->InterfaceCount;
  1635. oldNameVector = LocalAlloc(
  1636. LMEM_FIXED | LMEM_ZEROINIT,
  1637. interfaceCount * sizeof(LPWSTR)
  1638. );
  1639. newNameVector = LocalAlloc(
  1640. LMEM_FIXED | LMEM_ZEROINIT,
  1641. interfaceCount * sizeof(LPWSTR)
  1642. );
  1643. if ((oldNameVector == NULL) || (newNameVector == NULL)) {
  1644. ClRtlLogPrint(LOG_CRITICAL,
  1645. "[NM] Failed to allocate memory for net interface name change.\n"
  1646. );
  1647. goto error_exit;
  1648. }
  1649. for (entry = network->InterfaceList.Flink, i = 0;
  1650. entry != &(network->InterfaceList);
  1651. entry = entry->Flink, i++
  1652. )
  1653. {
  1654. netInterface = CONTAINING_RECORD(entry, NM_INTERFACE, NetworkLinkage);
  1655. netInterfaceId = OmObjectId(netInterface);
  1656. netInterfaceName = OmObjectName(netInterface);
  1657. nodeName = OmObjectName(netInterface->Node);
  1658. oldNameVector[i] = LocalAlloc(
  1659. LMEM_FIXED,
  1660. NM_WCSLEN(netInterfaceName)
  1661. );
  1662. newNameVector[i] = ClNetMakeInterfaceName(
  1663. NULL,
  1664. (LPWSTR) nodeName,
  1665. NewNetworkName
  1666. );
  1667. if ((oldNameVector[i] == NULL) || (newNameVector[i] == NULL)) {
  1668. ClRtlLogPrint(LOG_CRITICAL,
  1669. "[NM] Failed to allocate memory for net interface name "
  1670. "change.\n"
  1671. );
  1672. goto error_exit;
  1673. }
  1674. wcscpy(oldNameVector[i], netInterfaceName);
  1675. netInterfaceKey = DmOpenKey(
  1676. DmNetInterfacesKey,
  1677. netInterfaceId,
  1678. KEY_WRITE
  1679. );
  1680. if (netInterfaceKey == NULL) {
  1681. status = GetLastError();
  1682. ClRtlLogPrint(LOG_CRITICAL,
  1683. "[NM] Failed to open database key for net interface "
  1684. "%1!ws!, status %2!u!\n",
  1685. netInterfaceId,
  1686. status
  1687. );
  1688. goto error_exit;
  1689. }
  1690. status = DmLocalSetValue(
  1691. xaction,
  1692. netInterfaceKey,
  1693. CLUSREG_NAME_NETIFACE_NAME,
  1694. REG_SZ,
  1695. (CONST BYTE *) newNameVector[i],
  1696. NM_WCSLEN(newNameVector[i])
  1697. );
  1698. DmCloseKey(netInterfaceKey);
  1699. if (status != ERROR_SUCCESS) {
  1700. ClRtlLogPrint(LOG_CRITICAL,
  1701. "[NM] Set of name value failed for net interface %1!ws!, "
  1702. "status %2!u!.\n",
  1703. netInterfaceId,
  1704. status
  1705. );
  1706. goto error_exit;
  1707. }
  1708. }
  1709. //
  1710. // Update the in-memory objects.
  1711. //
  1712. // This processing may not be undoable on error.
  1713. //
  1714. //
  1715. // Update name of the network
  1716. //
  1717. status = OmSetObjectName(network, NewNetworkName);
  1718. if (status != ERROR_SUCCESS) {
  1719. ClRtlLogPrint(LOG_CRITICAL,
  1720. "[NM] Failed to change name for network %1!ws!, status %2!u!\n",
  1721. NetworkId,
  1722. status
  1723. );
  1724. goto error_exit;
  1725. }
  1726. //
  1727. // Update the names of all of the interfaces on the network.
  1728. //
  1729. for (entry = network->InterfaceList.Flink, i = 0;
  1730. entry != &(network->InterfaceList);
  1731. entry = entry->Flink, i++
  1732. )
  1733. {
  1734. netInterface = CONTAINING_RECORD(entry, NM_INTERFACE, NetworkLinkage);
  1735. netInterfaceId = OmObjectId(netInterface);
  1736. status = OmSetObjectName(netInterface, newNameVector[i]);
  1737. if (status != ERROR_SUCCESS) {
  1738. //
  1739. // Try to undo what has already been done. If we fail, we must
  1740. // commit suicide to preserve consistency.
  1741. //
  1742. DWORD j;
  1743. PLIST_ENTRY entry2;
  1744. DWORD undoStatus;
  1745. ClRtlLogPrint(LOG_CRITICAL,
  1746. "[NM] Failed to change name for net interface %1!ws!, "
  1747. "status %2!u!\n",
  1748. netInterfaceId,
  1749. status
  1750. );
  1751. //
  1752. // Undo the update of the network name
  1753. //
  1754. undoStatus = OmSetObjectName(network, oldNetworkName);
  1755. if (undoStatus != ERROR_SUCCESS) {
  1756. ClRtlLogPrint(LOG_CRITICAL,
  1757. "[NM] Failed to undo change of name for network %1!ws!, "
  1758. "status %2!u!\n",
  1759. NetworkId,
  1760. undoStatus
  1761. );
  1762. CsInconsistencyHalt(undoStatus);
  1763. }
  1764. //
  1765. // Undo update of network interface names
  1766. //
  1767. for (j = 0, entry2 = network->InterfaceList.Flink;
  1768. j < i;
  1769. j++, entry2 = entry2->Flink
  1770. )
  1771. {
  1772. netInterface = CONTAINING_RECORD(
  1773. entry2,
  1774. NM_INTERFACE,
  1775. NetworkLinkage
  1776. );
  1777. netInterfaceId = OmObjectId(netInterface);
  1778. undoStatus = OmSetObjectName(netInterface, oldNameVector[i]);
  1779. if (undoStatus != ERROR_SUCCESS) {
  1780. ClRtlLogPrint(LOG_CRITICAL,
  1781. "[NM] Failed to undo change of name for net "
  1782. "interface %1!ws!, status %2!u!\n",
  1783. netInterfaceId,
  1784. undoStatus
  1785. );
  1786. CsInconsistencyHalt(undoStatus);
  1787. }
  1788. }
  1789. goto error_exit;
  1790. }
  1791. }
  1792. //
  1793. // Set the corresponding connectoid object name if necessary.
  1794. //
  1795. if (network->LocalInterface != NULL) {
  1796. INetConnection * connectoid;
  1797. LPWSTR connectoidName;
  1798. DWORD tempStatus;
  1799. connectoid = ClRtlFindConnectoidByGuid(
  1800. network->LocalInterface->AdapterId
  1801. );
  1802. if (connectoid != NULL) {
  1803. connectoidName = ClRtlGetConnectoidName(connectoid);
  1804. if (connectoidName != NULL) {
  1805. if (lstrcmpW(connectoidName, NewNetworkName) != 0) {
  1806. tempStatus = ClRtlSetConnectoidName(
  1807. connectoid,
  1808. NewNetworkName
  1809. );
  1810. if (tempStatus != ERROR_SUCCESS) {
  1811. ClRtlLogPrint(LOG_UNUSUAL,
  1812. "[NM] Failed to set name of Network Connection "
  1813. "Object for interface on cluster network %1!ws! "
  1814. "(%2!ws!), status %3!u!\n",
  1815. oldNetworkName,
  1816. NetworkId,
  1817. tempStatus
  1818. );
  1819. }
  1820. }
  1821. }
  1822. else {
  1823. tempStatus = GetLastError();
  1824. ClRtlLogPrint(LOG_UNUSUAL,
  1825. "[NM] Failed to query name of Network Connection Object "
  1826. "for interface on cluster network %1!ws! (%2!ws!), "
  1827. "status %3!u!\n",
  1828. oldNetworkName,
  1829. NetworkId,
  1830. tempStatus
  1831. );
  1832. }
  1833. INetConnection_Release( connectoid );
  1834. }
  1835. else {
  1836. tempStatus = GetLastError();
  1837. ClRtlLogPrint(LOG_UNUSUAL,
  1838. "[NM] Failed to find Network Connection Object for "
  1839. "interface on cluster network %1!ws! (%2!ws!), "
  1840. "status %3!u!\n",
  1841. oldNetworkName,
  1842. NetworkId,
  1843. tempStatus
  1844. );
  1845. }
  1846. }
  1847. //
  1848. // Issue property change events.
  1849. //
  1850. ClusterEvent(CLUSTER_EVENT_NETWORK_PROPERTY_CHANGE, network);
  1851. for (entry = network->InterfaceList.Flink;
  1852. entry != &(network->InterfaceList);
  1853. entry = entry->Flink
  1854. )
  1855. {
  1856. netInterface = CONTAINING_RECORD(entry, NM_INTERFACE, NetworkLinkage);
  1857. ClusterEvent(
  1858. CLUSTER_EVENT_NETINTERFACE_PROPERTY_CHANGE,
  1859. netInterface
  1860. );
  1861. }
  1862. CL_ASSERT(status == ERROR_SUCCESS);
  1863. error_exit:
  1864. if (isLockAcquired) {
  1865. NmpLockedLeaveApi();
  1866. NmpReleaseLock();
  1867. }
  1868. else {
  1869. NmpLeaveApi();
  1870. }
  1871. if (xaction != NULL) {
  1872. //
  1873. // Complete the transaction - this must be done after releasing
  1874. // the NM lock.
  1875. //
  1876. if (status == ERROR_SUCCESS) {
  1877. DmCommitLocalUpdate(xaction);
  1878. }
  1879. else {
  1880. DmAbortLocalUpdate(xaction);
  1881. }
  1882. }
  1883. if (network != NULL) {
  1884. OmDereferenceObject(network);
  1885. if (oldNetworkName != NULL) {
  1886. LocalFree(oldNetworkName);
  1887. }
  1888. if (oldNameVector != NULL) {
  1889. for (i=0; i < interfaceCount; i++) {
  1890. if (oldNameVector[i] == NULL) {
  1891. break;
  1892. }
  1893. LocalFree(oldNameVector[i]);
  1894. }
  1895. LocalFree(oldNameVector);
  1896. }
  1897. if (newNameVector != NULL) {
  1898. for (i=0; i < interfaceCount; i++) {
  1899. if (newNameVector[i] == NULL) {
  1900. break;
  1901. }
  1902. LocalFree(newNameVector[i]);
  1903. }
  1904. LocalFree(newNameVector);
  1905. }
  1906. }
  1907. return(status);
  1908. } // NmpUpdateSetNetworkName
  1909. DWORD
  1910. NmpUpdateSetNetworkPriorityOrder(
  1911. IN BOOL IsSourceNode,
  1912. IN LPCWSTR NetworkIdList
  1913. )
  1914. {
  1915. DWORD status = ERROR_SUCCESS;
  1916. PNM_NETWORK network;
  1917. PLIST_ENTRY entry;
  1918. DWORD matchCount=0;
  1919. DWORD networkCount=0;
  1920. PNM_NETWORK * networkList=NULL;
  1921. DWORD i;
  1922. DWORD multiSzLength;
  1923. LPCWSTR networkId;
  1924. HLOCALXSACTION xaction = NULL;
  1925. BOOLEAN isLockAcquired = FALSE;
  1926. if (!NmpEnterApi(NmStateOnline)) {
  1927. ClRtlLogPrint(LOG_NOISE,
  1928. "[NM] Not in valid state to process SetNetworkPriorityOrder "
  1929. "update.\n"
  1930. );
  1931. return(ERROR_NODE_NOT_AVAILABLE);
  1932. }
  1933. ClRtlLogPrint(LOG_NOISE,
  1934. "[NM] Received update to set network priority order.\n"
  1935. );
  1936. //
  1937. // Unmarshall the MULTI_SZ
  1938. //
  1939. try {
  1940. multiSzLength = ClRtlMultiSzLength(NetworkIdList);
  1941. for (i=0; ; i++) {
  1942. networkId = ClRtlMultiSzEnum(
  1943. NetworkIdList,
  1944. multiSzLength,
  1945. i
  1946. );
  1947. if (networkId == NULL) {
  1948. break;
  1949. }
  1950. networkCount++;
  1951. }
  1952. }
  1953. except(EXCEPTION_EXECUTE_HANDLER) {
  1954. ClRtlLogPrint(LOG_UNUSUAL,
  1955. "[NM] Hit exception while parsing network ID list for "
  1956. "priority change\n"
  1957. );
  1958. status = ERROR_INVALID_PARAMETER;
  1959. goto error_exit;
  1960. }
  1961. if (networkCount == 0) {
  1962. status = ERROR_INVALID_PARAMETER;
  1963. goto error_exit;
  1964. }
  1965. networkList = LocalAlloc(
  1966. LMEM_ZEROINIT| LMEM_FIXED,
  1967. networkCount * sizeof(PNM_NETWORK)
  1968. );
  1969. if (networkList == NULL) {
  1970. status = ERROR_NOT_ENOUGH_MEMORY;
  1971. goto error_exit;
  1972. }
  1973. //
  1974. // Start a transaction - this must be done before acquiring the NM lock.
  1975. //
  1976. xaction = DmBeginLocalUpdate();
  1977. if (xaction == NULL) {
  1978. status = GetLastError();
  1979. ClRtlLogPrint(LOG_CRITICAL,
  1980. "[NM] Failed to start a transaction, status %1!u!\n",
  1981. status
  1982. );
  1983. goto error_exit;
  1984. }
  1985. NmpAcquireLock(); isLockAcquired = TRUE;
  1986. if (NmpJoinerNodeId != ClusterInvalidNodeId) {
  1987. status = ERROR_CLUSTER_JOIN_IN_PROGRESS;
  1988. ClRtlLogPrint(LOG_NOISE,
  1989. "[NM] Cannot set network priority order because a node is "
  1990. "joining the cluster.\n"
  1991. );
  1992. goto error_exit;
  1993. }
  1994. for (i=0; i<networkCount; i++) {
  1995. networkId = ClRtlMultiSzEnum(
  1996. NetworkIdList,
  1997. multiSzLength,
  1998. i
  1999. );
  2000. CL_ASSERT(networkId != NULL);
  2001. networkList[i] = OmReferenceObjectById(
  2002. ObjectTypeNetwork,
  2003. networkId
  2004. );
  2005. if (networkList[i] == NULL) {
  2006. goto error_exit;
  2007. }
  2008. }
  2009. //
  2010. // Verify that all of the networks specified are internal, and
  2011. // that all of the internal networks are specified.
  2012. //
  2013. if (networkCount != NmpInternalNetworkCount) {
  2014. ClRtlLogPrint(LOG_CRITICAL,
  2015. "[NM] Supplied network count %1!u! doesn't match internal "
  2016. "network count %2!u!\n",
  2017. networkCount,
  2018. NmpInternalNetworkCount
  2019. );
  2020. status = ERROR_INVALID_PARAMETER;
  2021. goto error_exit;
  2022. }
  2023. for (entry = NmpInternalNetworkList.Flink, matchCount = 0;
  2024. entry != &NmpInternalNetworkList;
  2025. entry = entry->Flink
  2026. )
  2027. {
  2028. network = CONTAINING_RECORD(entry, NM_NETWORK, InternalLinkage);
  2029. if (NmpIsNetworkForInternalUse(network)) {
  2030. for (i=0; i<networkCount; i++) {
  2031. if (network == networkList[i]) {
  2032. matchCount++;
  2033. break;
  2034. }
  2035. }
  2036. if (i == networkCount) {
  2037. //
  2038. // This network is not in the list.
  2039. //
  2040. ClRtlLogPrint(LOG_CRITICAL,
  2041. "[NM] Internal use network %1!ws! is not in priority "
  2042. "list\n",
  2043. (LPWSTR) OmObjectId(network)
  2044. );
  2045. status = ERROR_INVALID_PARAMETER;
  2046. goto error_exit;
  2047. }
  2048. }
  2049. }
  2050. if (matchCount != networkCount) {
  2051. //
  2052. // Some of the specified networks are not internal use.
  2053. //
  2054. ClRtlLogPrint(LOG_CRITICAL,
  2055. "[NM] Some non-internal use networks are in priority list\n"
  2056. );
  2057. status = ERROR_INVALID_PARAMETER;
  2058. goto error_exit;
  2059. }
  2060. //
  2061. // The list is kosher. Set the priorities.
  2062. //
  2063. status = NmpSetNetworkPriorityOrder(networkCount, networkList, xaction);
  2064. error_exit:
  2065. if (isLockAcquired) {
  2066. NmpLockedLeaveApi();
  2067. NmpReleaseLock();
  2068. }
  2069. else {
  2070. NmpLeaveApi();
  2071. }
  2072. if (xaction != NULL) {
  2073. //
  2074. // Complete the transaction - this must be done after releasing
  2075. // the NM lock.
  2076. //
  2077. if (status == ERROR_SUCCESS) {
  2078. DmCommitLocalUpdate(xaction);
  2079. }
  2080. else {
  2081. DmAbortLocalUpdate(xaction);
  2082. }
  2083. }
  2084. if (networkList != NULL) {
  2085. for (i=0; i<networkCount; i++) {
  2086. if (networkList[i] != NULL) {
  2087. OmDereferenceObject(networkList[i]);
  2088. }
  2089. }
  2090. LocalFree(networkList);
  2091. }
  2092. return(status);
  2093. } // NmpUpdateSetNetworkPriorityOrder
  2094. DWORD
  2095. NmpSetNetworkPriorityOrder(
  2096. IN DWORD NetworkCount,
  2097. IN PNM_NETWORK * NetworkList,
  2098. IN HLOCALXSACTION Xaction
  2099. )
  2100. /*++
  2101. Notes:
  2102. Called with NM Lock held.
  2103. --*/
  2104. {
  2105. DWORD status = ERROR_SUCCESS;
  2106. PNM_NETWORK network;
  2107. DWORD i;
  2108. LPCWSTR networkId;
  2109. HDMKEY networkKey;
  2110. DWORD priority;
  2111. //
  2112. // Update the database first.
  2113. //
  2114. for (i=0, priority = 1; i<NetworkCount; i++, priority++) {
  2115. network = NetworkList[i];
  2116. networkId = OmObjectId(network);
  2117. CL_ASSERT(NmpIsNetworkForInternalUse(network));
  2118. if (network->Priority != priority) {
  2119. networkKey = DmOpenKey(DmNetworksKey, networkId, KEY_WRITE);
  2120. if (networkKey == NULL) {
  2121. status = GetLastError();
  2122. ClRtlLogPrint(LOG_CRITICAL,
  2123. "[NM] Failed to open database key for network %1!ws!, "
  2124. "status %2!u!\n",
  2125. networkId,
  2126. status
  2127. );
  2128. return(status);
  2129. }
  2130. status = DmLocalSetValue(
  2131. Xaction,
  2132. networkKey,
  2133. CLUSREG_NAME_NET_PRIORITY,
  2134. REG_DWORD,
  2135. (CONST BYTE *) &priority,
  2136. sizeof(priority)
  2137. );
  2138. DmCloseKey(networkKey);
  2139. if (status != ERROR_SUCCESS) {
  2140. ClRtlLogPrint(LOG_CRITICAL,
  2141. "[NM] Set of priority value failed for network %1!ws!, "
  2142. "status %2!u!.\n",
  2143. networkId,
  2144. status
  2145. );
  2146. return(status);
  2147. }
  2148. }
  2149. }
  2150. #ifdef CLUSTER_TESTPOINT
  2151. TESTPT(TpFailNmSetNetworkPriorityOrder) {
  2152. status = 999999;
  2153. return(status);
  2154. }
  2155. #endif
  2156. //
  2157. // Update the in-memory representation
  2158. //
  2159. InitializeListHead(&NmpInternalNetworkList);
  2160. for (i=0, priority = 1; i<NetworkCount; i++, priority++) {
  2161. network = NetworkList[i];
  2162. networkId = OmObjectId(network);
  2163. InsertTailList(
  2164. &NmpInternalNetworkList,
  2165. &(network->InternalLinkage)
  2166. );
  2167. if (network->Priority != priority) {
  2168. ClRtlLogPrint(LOG_NOISE,
  2169. "[NM] Set priority for network %1!ws! to %2!u!.\n",
  2170. networkId,
  2171. priority
  2172. );
  2173. network->Priority = priority;
  2174. //
  2175. // If the local node is attached to this network, set its
  2176. // priority in the cluster transport
  2177. //
  2178. if (NmpIsNetworkRegistered(network)) {
  2179. status = ClusnetSetNetworkPriority(
  2180. NmClusnetHandle,
  2181. network->ShortId,
  2182. network->Priority
  2183. );
  2184. #ifdef CLUSTER_TESTPOINT
  2185. TESTPT(TpFailNmSetNetworkPriorityOrder2) {
  2186. status = 999999;
  2187. }
  2188. #endif
  2189. if (status != ERROR_SUCCESS) {
  2190. //
  2191. // We can't easily abort here. We must either continue
  2192. // or commit suicide. We choose to continue and log an
  2193. // event.
  2194. //
  2195. WCHAR string[16];
  2196. wsprintfW(&(string[0]), L"%u", status);
  2197. CsLogEvent2(
  2198. LOG_UNUSUAL,
  2199. NM_EVENT_SET_NETWORK_PRIORITY_FAILED,
  2200. OmObjectName(network),
  2201. string
  2202. );
  2203. ClRtlLogPrint(LOG_CRITICAL,
  2204. "[NM] Cluster transport failed to set priority for "
  2205. "network %1!ws!, status %2!u!\n",
  2206. networkId,
  2207. status
  2208. );
  2209. status = ERROR_SUCCESS;
  2210. }
  2211. }
  2212. }
  2213. }
  2214. CL_ASSERT(status == ERROR_SUCCESS);
  2215. //
  2216. // Issue a cluster property change event.
  2217. //
  2218. NmpIssueClusterPropertyChangeEvent();
  2219. return(ERROR_SUCCESS);
  2220. } // NmpSetNetworkPriorityOrder
  2221. DWORD
  2222. NmpUpdateSetNetworkCommonProperties(
  2223. IN BOOL IsSourceNode,
  2224. IN LPWSTR NetworkId,
  2225. IN UCHAR * PropertyList,
  2226. IN LPDWORD PropertyListLength
  2227. )
  2228. /*++
  2229. Routine Description:
  2230. Global update handler for setting the common properties of a network.
  2231. Arguments:
  2232. IsSourceNode - Set to TRUE if this node is the source of the update.
  2233. Set to FALSE otherwise.
  2234. NetworkId - A pointer to a unicode string containing the ID of the
  2235. network to update.
  2236. Return Value:
  2237. ERROR_SUCCESS if the routine succeeds.
  2238. A Win32 error code otherwise.
  2239. --*/
  2240. {
  2241. DWORD status = ERROR_SUCCESS;
  2242. NM_NETWORK_INFO networkInfo;
  2243. PNM_NETWORK network = NULL;
  2244. HLOCALXSACTION xaction = NULL;
  2245. HDMKEY networkKey = NULL;
  2246. DWORD descSize = 0;
  2247. LPWSTR descBuffer = NULL;
  2248. BOOLEAN propertyChanged = FALSE;
  2249. BOOLEAN isLockAcquired = FALSE;
  2250. if (!NmpEnterApi(NmStateOnline)) {
  2251. ClRtlLogPrint(LOG_NOISE,
  2252. "[NM] Not in valid state to process SetNetworkCommonProperties "
  2253. "update.\n"
  2254. );
  2255. return(ERROR_NODE_NOT_AVAILABLE);
  2256. }
  2257. ClRtlLogPrint(LOG_NOISE,
  2258. "[NM] Received update to set common properties for network %1!ws!.\n",
  2259. NetworkId
  2260. );
  2261. ZeroMemory(&networkInfo, sizeof(NM_NETWORK_INFO));
  2262. //
  2263. // Find the network's object
  2264. //
  2265. network = OmReferenceObjectById(ObjectTypeNetwork, NetworkId);
  2266. if (network == NULL) {
  2267. ClRtlLogPrint(LOG_CRITICAL,
  2268. "[NM] Unable to find network %1!ws!.\n",
  2269. NetworkId
  2270. );
  2271. status = ERROR_CLUSTER_NETWORK_NOT_FOUND;
  2272. goto error_exit;
  2273. }
  2274. //
  2275. // Open the network's database key
  2276. //
  2277. networkKey = DmOpenKey(DmNetworksKey, NetworkId, KEY_WRITE);
  2278. if (networkKey == NULL) {
  2279. status = GetLastError();
  2280. ClRtlLogPrint(LOG_CRITICAL,
  2281. "[NM] Failed to open database key for network %1!ws!, "
  2282. "status %2!u!\n",
  2283. NetworkId,
  2284. status
  2285. );
  2286. goto error_exit;
  2287. }
  2288. //
  2289. // Start a transaction - this must be done before acquiring the NM lock.
  2290. //
  2291. xaction = DmBeginLocalUpdate();
  2292. if (xaction == NULL) {
  2293. status = GetLastError();
  2294. ClRtlLogPrint(LOG_CRITICAL,
  2295. "[NM] Failed to begin a transaction, status %1!u!\n",
  2296. status
  2297. );
  2298. goto error_exit;
  2299. }
  2300. NmpAcquireLock(); isLockAcquired = TRUE;
  2301. if (NmpJoinerNodeId != ClusterInvalidNodeId) {
  2302. status = ERROR_CLUSTER_JOIN_IN_PROGRESS;
  2303. ClRtlLogPrint(LOG_NOISE,
  2304. "[NM] Cannot set network common properties because a node is "
  2305. "joining the cluster.\n"
  2306. );
  2307. goto error_exit;
  2308. }
  2309. //
  2310. // Validate the property list and convert it to a network params struct.
  2311. //
  2312. status = NmpNetworkValidateCommonProperties(
  2313. network,
  2314. PropertyList,
  2315. *PropertyListLength,
  2316. &networkInfo
  2317. );
  2318. if (status != ERROR_SUCCESS) {
  2319. ClRtlLogPrint(LOG_CRITICAL,
  2320. "[NM] Property list validation failed, status %1!u!.\n",
  2321. status
  2322. );
  2323. goto error_exit;
  2324. }
  2325. CL_ASSERT(network->Priority == networkInfo.Priority);
  2326. CL_ASSERT(wcscmp(NetworkId, networkInfo.Id) == 0);
  2327. CL_ASSERT(wcscmp(OmObjectName(network), networkInfo.Name) == 0);
  2328. CL_ASSERT(wcscmp(network->Transport, networkInfo.Transport) == 0);
  2329. CL_ASSERT(wcscmp(network->Address, networkInfo.Address) == 0);
  2330. CL_ASSERT(wcscmp(network->AddressMask, networkInfo.AddressMask) == 0);
  2331. //
  2332. // Check if the network's description has changed.
  2333. //
  2334. if (wcscmp(network->Description, networkInfo.Description) != 0) {
  2335. ClRtlLogPrint(LOG_NOISE,
  2336. "[NM] Setting description for network %1!ws! to %2!ws!.\n",
  2337. NetworkId,
  2338. networkInfo.Description
  2339. );
  2340. //
  2341. // Allocate a buffer for the description string
  2342. //
  2343. descSize = NM_WCSLEN(networkInfo.Description);
  2344. descBuffer = MIDL_user_allocate(descSize);
  2345. if (descBuffer == NULL) {
  2346. status = ERROR_NOT_ENOUGH_MEMORY;
  2347. goto error_exit;
  2348. }
  2349. RtlMoveMemory(descBuffer, networkInfo.Description, descSize);
  2350. //
  2351. // Update the database
  2352. //
  2353. status = DmLocalSetValue(
  2354. xaction,
  2355. networkKey,
  2356. CLUSREG_NAME_NET_DESC,
  2357. REG_SZ,
  2358. (CONST BYTE *) networkInfo.Description,
  2359. descSize
  2360. );
  2361. if (status != ERROR_SUCCESS) {
  2362. ClRtlLogPrint(LOG_CRITICAL,
  2363. "[NM] Set of description value failed for network %1!ws!, "
  2364. "status %2!u!.\n",
  2365. NetworkId,
  2366. status
  2367. );
  2368. goto error_exit;
  2369. }
  2370. //
  2371. // Updating the network object is deferred until the transaction
  2372. // commits.
  2373. //
  2374. propertyChanged = TRUE;
  2375. }
  2376. #ifdef CLUSTER_TESTPOINT
  2377. TESTPT(TpFailNmSetNetworkCommonProperties) {
  2378. status = 999999;
  2379. goto error_exit;
  2380. }
  2381. #endif
  2382. //
  2383. // Check if the network's role has changed.
  2384. //
  2385. //
  2386. // NOTE: This operation is not guaranteed to be reversible, so it must
  2387. // be the last thing we do in this routine. If it succeeds, the
  2388. // update must be committed.
  2389. //
  2390. if ( network->Role != ((CLUSTER_NETWORK_ROLE) networkInfo.Role) ) {
  2391. status = NmpSetNetworkRole(
  2392. network,
  2393. networkInfo.Role,
  2394. xaction,
  2395. networkKey
  2396. );
  2397. if (status != ERROR_SUCCESS) {
  2398. goto error_exit;
  2399. }
  2400. propertyChanged = TRUE;
  2401. }
  2402. if (propertyChanged) {
  2403. //
  2404. // Commit the updates to the network object in memory
  2405. //
  2406. if (descBuffer != NULL) {
  2407. MIDL_user_free(network->Description);
  2408. network->Description = descBuffer;
  2409. descBuffer = NULL;
  2410. }
  2411. //
  2412. // Issue a network property change event.
  2413. //
  2414. if (propertyChanged && (status == ERROR_SUCCESS)) {
  2415. ClusterEvent(CLUSTER_EVENT_NETWORK_PROPERTY_CHANGE, network);
  2416. }
  2417. }
  2418. CL_ASSERT(status == ERROR_SUCCESS);
  2419. error_exit:
  2420. if (isLockAcquired) {
  2421. NmpLockedLeaveApi();
  2422. NmpReleaseLock();
  2423. }
  2424. else {
  2425. NmpLeaveApi();
  2426. }
  2427. if (xaction != NULL) {
  2428. //
  2429. // Complete the transaction - this must be done after releasing
  2430. // the NM lock.
  2431. //
  2432. if (propertyChanged && (status == ERROR_SUCCESS)) {
  2433. DmCommitLocalUpdate(xaction);
  2434. }
  2435. else {
  2436. DmAbortLocalUpdate(xaction);
  2437. }
  2438. }
  2439. ClNetFreeNetworkInfo(&networkInfo);
  2440. if (descBuffer != NULL) {
  2441. MIDL_user_free(descBuffer);
  2442. }
  2443. if (networkKey != NULL) {
  2444. DmCloseKey(networkKey);
  2445. }
  2446. if (network != NULL) {
  2447. OmDereferenceObject(network);
  2448. }
  2449. return(status);
  2450. } // NmpUpdateSetNetworkCommonProperties
  2451. DWORD
  2452. NmpUpdateSetNetworkAndInterfaceStates(
  2453. IN BOOL IsSourceNode,
  2454. IN LPWSTR NetworkId,
  2455. IN CLUSTER_NETWORK_STATE * NewNetworkState,
  2456. IN PNM_STATE_ENTRY InterfaceStateVector,
  2457. IN LPDWORD InterfaceStateVectorSize
  2458. )
  2459. {
  2460. DWORD status = ERROR_SUCCESS;
  2461. PNM_NETWORK network;
  2462. NmpAcquireLock();
  2463. if (NmpLockedEnterApi(NmStateOnline)) {
  2464. ClRtlLogPrint(LOG_NOISE,
  2465. "[NM] Received update to set state for network %1!ws!.\n",
  2466. NetworkId
  2467. );
  2468. //
  2469. // Find the network's object
  2470. //
  2471. network = OmReferenceObjectById(ObjectTypeNetwork, NetworkId);
  2472. if (network != NULL) {
  2473. NmpSetNetworkAndInterfaceStates(
  2474. network,
  2475. *NewNetworkState,
  2476. InterfaceStateVector,
  2477. *InterfaceStateVectorSize
  2478. );
  2479. OmDereferenceObject(network);
  2480. }
  2481. else {
  2482. ClRtlLogPrint(LOG_CRITICAL,
  2483. "[NM] Unable to find network %1!ws!.\n",
  2484. NetworkId
  2485. );
  2486. status = ERROR_CLUSTER_NETWORK_NOT_FOUND;
  2487. }
  2488. }
  2489. else {
  2490. ClRtlLogPrint(LOG_NOISE,
  2491. "[NM] Not in valid state to process SetNetworkAndInterfaceStates "
  2492. "update.\n"
  2493. );
  2494. status = ERROR_NODE_NOT_AVAILABLE;
  2495. }
  2496. NmpLockedLeaveApi();
  2497. NmpReleaseLock();
  2498. return(status);
  2499. } // NmpUpdateSetNetworkAndInterfaceStates
  2500. /////////////////////////////////////////////////////////////////////////////
  2501. //
  2502. // Helper routines for updates
  2503. //
  2504. /////////////////////////////////////////////////////////////////////////////
  2505. DWORD
  2506. NmpSetNetworkRole(
  2507. PNM_NETWORK Network,
  2508. CLUSTER_NETWORK_ROLE NewRole,
  2509. HLOCALXSACTION Xaction,
  2510. HDMKEY NetworkKey
  2511. )
  2512. /*++
  2513. Called with the NmpLock acquired.
  2514. This operation is not guaranteed to be reversible, so this
  2515. function is coded such that it either succeeds and makes the update
  2516. or it fails and no update is made.
  2517. --*/
  2518. {
  2519. DWORD status = ERROR_SUCCESS;
  2520. CLUSTER_NETWORK_ROLE oldRole = Network->Role;
  2521. DWORD dwordNewRole = (DWORD) NewRole;
  2522. LPCWSTR networkId = OmObjectId(Network);
  2523. DWORD oldPriority = Network->Priority;
  2524. DWORD newPriority = oldPriority;
  2525. BOOLEAN internalNetworkListChanged = FALSE;
  2526. ClRtlLogPrint(LOG_NOISE,
  2527. "[NM] Changing role for network %1!ws! to %2!u!\n",
  2528. networkId,
  2529. NewRole
  2530. );
  2531. CL_ASSERT(NewRole != oldRole);
  2532. CL_ASSERT(
  2533. NmpValidateNetworkRoleChange(Network, NewRole) == ERROR_SUCCESS
  2534. );
  2535. //
  2536. // First, make any registry updates since these can be
  2537. // aborted by the caller.
  2538. //
  2539. //
  2540. // Update the role property.
  2541. //
  2542. status = DmLocalSetValue(
  2543. Xaction,
  2544. NetworkKey,
  2545. CLUSREG_NAME_NET_ROLE,
  2546. REG_DWORD,
  2547. (CONST BYTE *) &dwordNewRole,
  2548. sizeof(DWORD)
  2549. );
  2550. if (status != ERROR_SUCCESS) {
  2551. ClRtlLogPrint(LOG_CRITICAL,
  2552. "[NM] Set of role value failed for network %1!ws!, "
  2553. "status %2!u!.\n",
  2554. networkId,
  2555. status
  2556. );
  2557. return(status);
  2558. }
  2559. //
  2560. // Update the priority property, if needed.
  2561. //
  2562. if (oldRole & ClusterNetworkRoleInternalUse) {
  2563. if (!(NewRole & ClusterNetworkRoleInternalUse)) {
  2564. //
  2565. // This network is no longer used for internal communication.
  2566. // Invalidate its priority value.
  2567. //
  2568. newPriority = 0xFFFFFFFF;
  2569. internalNetworkListChanged = TRUE;
  2570. }
  2571. }
  2572. else if (NewRole & ClusterNetworkRoleInternalUse) {
  2573. //
  2574. // This network is now used for internal communication.
  2575. // The network's priority is one greater than that of the lowest
  2576. // (numerically highest) priority network already in the list.
  2577. //
  2578. if (IsListEmpty(&NmpInternalNetworkList)) {
  2579. newPriority = 1;
  2580. }
  2581. else {
  2582. PNM_NETWORK network = CONTAINING_RECORD(
  2583. NmpInternalNetworkList.Blink,
  2584. NM_NETWORK,
  2585. InternalLinkage
  2586. );
  2587. CL_ASSERT(network->Priority != 0);
  2588. CL_ASSERT(network->Priority != 0xFFFFFFFF);
  2589. newPriority = network->Priority + 1;
  2590. }
  2591. internalNetworkListChanged = TRUE;
  2592. }
  2593. if (newPriority != oldPriority) {
  2594. status = DmLocalSetValue(
  2595. Xaction,
  2596. NetworkKey,
  2597. CLUSREG_NAME_NET_PRIORITY,
  2598. REG_DWORD,
  2599. (CONST BYTE *) &newPriority,
  2600. sizeof(newPriority)
  2601. );
  2602. if (status != ERROR_SUCCESS) {
  2603. ClRtlLogPrint(LOG_CRITICAL,
  2604. "[NM] Failed to set priority value for network %1!ws!, "
  2605. "status %2!u!.\n",
  2606. networkId,
  2607. status
  2608. );
  2609. return(status);
  2610. }
  2611. }
  2612. //
  2613. // Update the network object. Some of the subsequent subroutine calls
  2614. // depend on this.
  2615. //
  2616. Network->Role = NewRole;
  2617. Network->Priority = newPriority;
  2618. //
  2619. // Do other housekeeping based on the change.
  2620. //
  2621. // Note that the housekeeping work is coded such that none of it needs
  2622. // to be reversed if an error occurs.
  2623. //
  2624. if (NewRole == ClusterNetworkRoleNone) {
  2625. PLIST_ENTRY entry;
  2626. PNM_INTERFACE netInterface;
  2627. //
  2628. // Case 1: This network is no longer used for clustering.
  2629. //
  2630. if (NmpIsNetworkRegistered(Network)) {
  2631. //
  2632. // Delete the network from the cluster transport.
  2633. // This will delete all of its interfaces as well.
  2634. //
  2635. NmpDeregisterNetwork(Network);
  2636. ClRtlLogPrint(LOG_NOISE,
  2637. "[NM] No longer hearbeating on network %1!ws!.\n",
  2638. networkId
  2639. );
  2640. }
  2641. //
  2642. // Invalidate the connectivity data for all interfaces on
  2643. // the network.
  2644. //
  2645. for ( entry = Network->InterfaceList.Flink;
  2646. entry != &(Network->InterfaceList);
  2647. entry = entry->Flink
  2648. )
  2649. {
  2650. netInterface = CONTAINING_RECORD(
  2651. entry,
  2652. NM_INTERFACE,
  2653. NetworkLinkage
  2654. );
  2655. NmpSetInterfaceConnectivityData(
  2656. Network,
  2657. netInterface->NetIndex,
  2658. ClusterNetInterfaceUnavailable
  2659. );
  2660. }
  2661. //
  2662. // Clean up tracking data.
  2663. //
  2664. if (oldRole & ClusterNetworkRoleInternalUse) {
  2665. RemoveEntryList(&(Network->InternalLinkage));
  2666. CL_ASSERT(NmpInternalNetworkCount > 0);
  2667. NmpInternalNetworkCount--;
  2668. }
  2669. if (oldRole & ClusterNetworkRoleClientAccess) {
  2670. CL_ASSERT(NmpClientNetworkCount > 0);
  2671. NmpClientNetworkCount--;
  2672. }
  2673. //
  2674. // Use the NT5 state logic.
  2675. //
  2676. if (NmpLeaderNodeId == NmLocalNodeId) {
  2677. //
  2678. // Schedule an immediate state update.
  2679. //
  2680. NmpScheduleNetworkStateRecalc(Network);
  2681. }
  2682. }
  2683. else if (oldRole == ClusterNetworkRoleNone) {
  2684. //
  2685. // Case 2: This network is now used for clustering.
  2686. //
  2687. if (Network->LocalInterface != NULL) {
  2688. //
  2689. // Register this network with the cluster transport.
  2690. //
  2691. // Note that this action will trigger a connectivity report,
  2692. // which will in turn trigger a state update under the NT5 logic.
  2693. //
  2694. status = NmpRegisterNetwork(
  2695. Network,
  2696. TRUE // Do retry on failure
  2697. );
  2698. if (status != ERROR_SUCCESS) {
  2699. goto error_exit;
  2700. }
  2701. ClRtlLogPrint(LOG_NOISE,
  2702. "[NM] Now heartbeating on network %1!ws!.\n",
  2703. networkId
  2704. );
  2705. }
  2706. else if (NmpLeaderNodeId == NmLocalNodeId) {
  2707. //
  2708. // Schedule a delayed state update in case none of the other
  2709. // nodes attached to this network are up right now.
  2710. //
  2711. NmpStartNetworkStateRecalcTimer(
  2712. Network,
  2713. NM_NET_STATE_RECALC_TIMEOUT
  2714. );
  2715. }
  2716. //
  2717. // Update tracking data.
  2718. //
  2719. if (NewRole & ClusterNetworkRoleInternalUse) {
  2720. InsertTailList(
  2721. &NmpInternalNetworkList,
  2722. &(Network->InternalLinkage)
  2723. );
  2724. NmpInternalNetworkCount++;
  2725. }
  2726. if (NewRole & ClusterNetworkRoleClientAccess) {
  2727. NmpClientNetworkCount++;
  2728. }
  2729. }
  2730. else {
  2731. //
  2732. // Case 3: We are using the network in a different way now.
  2733. // Note that the network is already registered with
  2734. // the cluster transport and will remain so. As a result,
  2735. // there is no need to perform a state update.
  2736. //
  2737. //
  2738. // First, examine the former and new use of the
  2739. // network for internal communication, and make any
  2740. // necessary updates to the cluster transport.
  2741. //
  2742. if (oldRole & ClusterNetworkRoleInternalUse) {
  2743. if (!(NewRole & ClusterNetworkRoleInternalUse)) {
  2744. //
  2745. // This network is no longer used for internal communication.
  2746. // It is used for client access.
  2747. //
  2748. CL_ASSERT(NewRole & ClusterNetworkRoleClientAccess);
  2749. if (NmpIsNetworkRegistered(Network)) {
  2750. //
  2751. // Restrict the network to heartbeats only.
  2752. //
  2753. status = ClusnetSetNetworkRestriction(
  2754. NmClusnetHandle,
  2755. Network->ShortId,
  2756. TRUE, // Network is restricted
  2757. 0
  2758. );
  2759. if (status != ERROR_SUCCESS) {
  2760. ClRtlLogPrint(LOG_CRITICAL,
  2761. "[NM] Failed to restrict network %1!ws!, "
  2762. "status %2!u!.\n",
  2763. networkId,
  2764. status
  2765. );
  2766. goto error_exit;
  2767. }
  2768. }
  2769. //
  2770. // Update tracking data
  2771. //
  2772. RemoveEntryList(&(Network->InternalLinkage));
  2773. CL_ASSERT(NmpInternalNetworkCount > 0);
  2774. NmpInternalNetworkCount--;
  2775. }
  2776. }
  2777. else {
  2778. //
  2779. // The network is now used for internal communication.
  2780. //
  2781. CL_ASSERT(NewRole & ClusterNetworkRoleInternalUse);
  2782. if (NmpIsNetworkRegistered(Network)) {
  2783. //
  2784. // Clear the restriction and set the priority.
  2785. //
  2786. status = ClusnetSetNetworkRestriction(
  2787. NmClusnetHandle,
  2788. Network->ShortId,
  2789. FALSE, // Network is not restricted
  2790. newPriority
  2791. );
  2792. if (status != ERROR_SUCCESS) {
  2793. ClRtlLogPrint(LOG_CRITICAL,
  2794. "[NM] Failed to unrestrict network %1!ws!, "
  2795. "status %2!u!.\n",
  2796. networkId,
  2797. status
  2798. );
  2799. goto error_exit;
  2800. }
  2801. }
  2802. //
  2803. // Update the tracking data
  2804. //
  2805. InsertTailList(
  2806. &NmpInternalNetworkList,
  2807. &(Network->InternalLinkage)
  2808. );
  2809. NmpInternalNetworkCount++;
  2810. }
  2811. //
  2812. // Now update the remaining tracking data based on former and
  2813. // current use of the network for client access.
  2814. //
  2815. if (oldRole & ClusterNetworkRoleClientAccess) {
  2816. if (!NewRole & ClusterNetworkRoleClientAccess) {
  2817. //
  2818. // This network is no longer used for client access.
  2819. //
  2820. CL_ASSERT(NmpClientNetworkCount > 0);
  2821. NmpClientNetworkCount--;
  2822. }
  2823. }
  2824. else {
  2825. //
  2826. // This network is now used for client access.
  2827. //
  2828. CL_ASSERT(NewRole & ClusterNetworkRoleClientAccess);
  2829. NmpClientNetworkCount++;
  2830. }
  2831. }
  2832. if (internalNetworkListChanged) {
  2833. NmpIssueClusterPropertyChangeEvent();
  2834. }
  2835. return(ERROR_SUCCESS);
  2836. error_exit:
  2837. //
  2838. // Undo the updates to the network object.
  2839. //
  2840. Network->Role = oldRole;
  2841. Network->Priority = oldPriority;
  2842. return(status);
  2843. } // NmpSetNetworkRole
  2844. VOID
  2845. NmpSetNetworkAndInterfaceStates(
  2846. IN PNM_NETWORK Network,
  2847. IN CLUSTER_NETWORK_STATE NewNetworkState,
  2848. IN PNM_STATE_ENTRY InterfaceStateVector,
  2849. IN DWORD VectorSize
  2850. )
  2851. /*++
  2852. Notes:
  2853. Called with NmpLock held.
  2854. Because NM_STATE_ENTRY is an unsigned type, while
  2855. CLUSTER_NETINTERFACE_STATE is a signed type, and
  2856. ClusterNetInterfaceStateUnknown is defined to be -1, we cannot cast
  2857. from NM_STATE_ENTRY to CLUSTER_NETINTERFACE_STATE and preserve the
  2858. value of ClusterNetInterfaceStateUnknown.
  2859. --*/
  2860. {
  2861. PLIST_ENTRY entry;
  2862. PNM_INTERFACE netInterface;
  2863. PNM_NODE node;
  2864. DWORD logLevel, logCode;
  2865. DWORD ifNetIndex;
  2866. LPCWSTR netInterfaceId;
  2867. LPCWSTR nodeName;
  2868. LPCWSTR networkName = OmObjectName(Network);
  2869. LPCWSTR networkId = OmObjectId(Network);
  2870. //
  2871. // Examine each interface on this network to see if its state
  2872. // has changed.
  2873. //
  2874. for ( entry = Network->InterfaceList.Flink;
  2875. entry != &(Network->InterfaceList);
  2876. entry = entry->Flink
  2877. )
  2878. {
  2879. netInterface = CONTAINING_RECORD(
  2880. entry,
  2881. NM_INTERFACE,
  2882. NetworkLinkage
  2883. );
  2884. ifNetIndex = netInterface->NetIndex;
  2885. netInterfaceId = OmObjectId(netInterface);
  2886. node = netInterface->Node;
  2887. nodeName = OmObjectName(node);
  2888. if ( (ifNetIndex < VectorSize) &&
  2889. (InterfaceStateVector[ifNetIndex] !=
  2890. (NM_STATE_ENTRY) netInterface->State
  2891. )
  2892. )
  2893. {
  2894. BOOLEAN logEvent = FALSE;
  2895. CLUSTER_EVENT eventCode = 0;
  2896. NM_STATE_ENTRY newState = InterfaceStateVector[ifNetIndex];
  2897. if (newState == (NM_STATE_ENTRY) ClusterNetInterfaceUnavailable) {
  2898. //
  2899. // Either the node has gone down or the network has been
  2900. // disabled.
  2901. //
  2902. netInterface->State = ClusterNetInterfaceUnavailable;
  2903. eventCode = CLUSTER_EVENT_NETINTERFACE_UNAVAILABLE;
  2904. ClRtlLogPrint(LOG_UNUSUAL,
  2905. "[NM] Interface %1!ws! is unavailable (node: %2!ws!, "
  2906. "network: %3!ws!).\n",
  2907. netInterfaceId,
  2908. nodeName,
  2909. networkName
  2910. );
  2911. }
  2912. else if (newState == (NM_STATE_ENTRY) ClusterNetInterfaceUp) {
  2913. netInterface->State = ClusterNetInterfaceUp;
  2914. eventCode = CLUSTER_EVENT_NETINTERFACE_UP;
  2915. logCode = NM_EVENT_CLUSTER_NETINTERFACE_UP;
  2916. logLevel = LOG_NOISE;
  2917. logEvent = TRUE;
  2918. ClRtlLogPrint(LOG_NOISE,
  2919. "[NM] Interface %1!ws! is up (node: %2!ws!, "
  2920. "network: %3!ws!).\n",
  2921. netInterfaceId,
  2922. nodeName,
  2923. networkName
  2924. );
  2925. }
  2926. else if ( newState ==
  2927. (NM_STATE_ENTRY) ClusterNetInterfaceUnreachable
  2928. )
  2929. {
  2930. netInterface->State = ClusterNetInterfaceUnreachable;
  2931. eventCode = CLUSTER_EVENT_NETINTERFACE_UNREACHABLE;
  2932. logCode = NM_EVENT_CLUSTER_NETINTERFACE_UNREACHABLE;
  2933. logLevel = LOG_UNUSUAL;
  2934. logEvent = TRUE;
  2935. ClRtlLogPrint(LOG_UNUSUAL,
  2936. "[NM] Interface %1!ws! is unreachable (node: %2!ws!, "
  2937. "network: %3!ws!).\n",
  2938. netInterfaceId,
  2939. nodeName,
  2940. networkName
  2941. );
  2942. }
  2943. else if (newState == (NM_STATE_ENTRY) ClusterNetInterfaceFailed) {
  2944. netInterface->State = ClusterNetInterfaceFailed;
  2945. eventCode = CLUSTER_EVENT_NETINTERFACE_FAILED;
  2946. logCode = NM_EVENT_CLUSTER_NETINTERFACE_FAILED;
  2947. logLevel = LOG_UNUSUAL;
  2948. logEvent = TRUE;
  2949. ClRtlLogPrint(LOG_UNUSUAL,
  2950. "[NM] Interface %1!ws! failed (node: %2!ws!, "
  2951. "network: %3!ws!).\n",
  2952. netInterfaceId,
  2953. nodeName,
  2954. networkName
  2955. );
  2956. }
  2957. else if ( newState ==
  2958. (NM_STATE_ENTRY) ClusterNetInterfaceStateUnknown
  2959. )
  2960. {
  2961. //
  2962. // This case can happen if a create update races with a
  2963. // state update. This will be the new interface. Just
  2964. // ignore it. Another state update will arrive shortly.
  2965. //
  2966. ClRtlLogPrint(LOG_UNUSUAL,
  2967. "[NM] State for interface %1!ws! is unknown "
  2968. "(node: %2!ws!, network: %3!ws!).\n",
  2969. netInterfaceId,
  2970. nodeName,
  2971. networkName
  2972. );
  2973. }
  2974. else {
  2975. ClRtlLogPrint(LOG_UNUSUAL,
  2976. "[NM] UpdateInterfaceState: Invalid state %1!u! "
  2977. "specified for interface %2!ws!\n",
  2978. newState,
  2979. netInterfaceId
  2980. );
  2981. CL_ASSERT(FALSE);
  2982. }
  2983. if (eventCode != 0) {
  2984. ClusterEvent(eventCode, netInterface);
  2985. }
  2986. if (logEvent && (NmpLeaderNodeId == NmLocalNodeId)) {
  2987. CsLogEvent2(
  2988. logLevel,
  2989. logCode,
  2990. nodeName,
  2991. networkName
  2992. );
  2993. }
  2994. }
  2995. }
  2996. if (Network->State != NewNetworkState) {
  2997. BOOLEAN logEvent = FALSE;
  2998. CLUSTER_EVENT eventCode = 0;
  2999. if (NewNetworkState == ClusterNetworkUnavailable) {
  3000. Network->State = ClusterNetworkUnavailable;
  3001. eventCode = CLUSTER_EVENT_NETWORK_UNAVAILABLE;
  3002. }
  3003. else if (NewNetworkState == ClusterNetworkUp) {
  3004. Network->State = ClusterNetworkUp;
  3005. eventCode = CLUSTER_EVENT_NETWORK_UP;
  3006. logCode = NM_EVENT_CLUSTER_NETWORK_UP;
  3007. logLevel = LOG_NOISE;
  3008. logEvent = TRUE;
  3009. ClRtlLogPrint(LOG_UNUSUAL,
  3010. "[NM] Network %1!ws! (%2!ws!) is up.\n",
  3011. networkId,
  3012. networkName
  3013. );
  3014. }
  3015. else if (NewNetworkState == ClusterNetworkDown) {
  3016. Network->State = ClusterNetworkDown;
  3017. eventCode = CLUSTER_EVENT_NETWORK_DOWN;
  3018. logCode = NM_EVENT_CLUSTER_NETWORK_DOWN;
  3019. logLevel = LOG_UNUSUAL;
  3020. logEvent = TRUE;
  3021. ClRtlLogPrint(LOG_UNUSUAL,
  3022. "[NM] Network %1!ws! (%2!ws!) is down.\n",
  3023. networkId,
  3024. networkName
  3025. );
  3026. }
  3027. else if (NewNetworkState == ClusterNetworkPartitioned) {
  3028. Network->State = ClusterNetworkPartitioned;
  3029. eventCode = CLUSTER_EVENT_NETWORK_PARTITIONED;
  3030. logCode = NM_EVENT_CLUSTER_NETWORK_PARTITIONED;
  3031. logLevel = LOG_UNUSUAL;
  3032. logEvent = TRUE;
  3033. ClRtlLogPrint(LOG_UNUSUAL,
  3034. "[NM] Network %1!ws! (%2!ws!) is partitioned.\n",
  3035. networkId,
  3036. networkName
  3037. );
  3038. }
  3039. else {
  3040. ClRtlLogPrint(LOG_UNUSUAL,
  3041. "[NM] Invalid state %1!u! for network %2!ws!\n",
  3042. Network->State,
  3043. networkId
  3044. );
  3045. CL_ASSERT(FALSE);
  3046. }
  3047. if (eventCode != 0) {
  3048. ClusterEvent(eventCode, Network);
  3049. }
  3050. if (logEvent && (NmpLeaderNodeId == NmLocalNodeId)) {
  3051. CsLogEvent1(
  3052. logLevel,
  3053. logCode,
  3054. networkName
  3055. );
  3056. }
  3057. }
  3058. return;
  3059. } // NmpSetNetworkAndInterfaceStates
  3060. /////////////////////////////////////////////////////////////////////////////
  3061. //
  3062. // Network state management routines
  3063. //
  3064. /////////////////////////////////////////////////////////////////////////////
  3065. VOID
  3066. NmpRecomputeNT5NetworkAndInterfaceStates(
  3067. VOID
  3068. )
  3069. {
  3070. PNM_NETWORK network;
  3071. PLIST_ENTRY entry;
  3072. for (entry = NmpNetworkList.Flink;
  3073. entry != &NmpNetworkList;
  3074. entry = entry->Flink
  3075. )
  3076. {
  3077. network = CONTAINING_RECORD(
  3078. entry,
  3079. NM_NETWORK,
  3080. Linkage
  3081. );
  3082. NmpStartNetworkStateRecalcTimer(
  3083. network,
  3084. NM_NET_STATE_RECALC_TIMEOUT_AFTER_REGROUP
  3085. );
  3086. }
  3087. return;
  3088. } // NmpRecomputeNT5NetworkAndInterfaceStates
  3089. BOOLEAN
  3090. NmpComputeNetworkAndInterfaceStates(
  3091. IN PNM_NETWORK Network,
  3092. IN BOOLEAN IsolateFailure,
  3093. OUT CLUSTER_NETWORK_STATE * NewNetworkState
  3094. )
  3095. /*++
  3096. Routine Description:
  3097. Computes the state of a network and all of its interfaces based on
  3098. connectivity reports from each constituent interface. Attempts
  3099. to distinguish between failures of individual interfaces and
  3100. failure of an entire network.
  3101. Arguments:
  3102. Network - A pointer to the network object to be processed.
  3103. IsolateFailure - Triggers failure isolation analysis if set to true.
  3104. NewNetworkState - A pointer to a variable that, upon return, contains
  3105. the new state of the network.
  3106. Return Value:
  3107. TRUE if either the state of the network or the state of at least one
  3108. of its constituent interfaces changed. FALSE otherwise.
  3109. Notes:
  3110. Called with NmpLock held and the network object referenced.
  3111. --*/
  3112. {
  3113. DWORD numIfUnavailable = 0;
  3114. DWORD numIfFailed = 0;
  3115. DWORD numIfUnreachable = 0;
  3116. DWORD numIfUp = 0;
  3117. DWORD numIfReachable = 0;
  3118. PNM_CONNECTIVITY_MATRIX matrix = Network->ConnectivityMatrix;
  3119. PNM_CONNECTIVITY_MATRIX matrixEntry;
  3120. PNM_STATE_WORK_VECTOR workVector = Network->StateWorkVector;
  3121. DWORD entryCount =
  3122. Network->ConnectivityVector->EntryCount;
  3123. DWORD reporter, ifNetIndex;
  3124. BOOLEAN stateChanged = FALSE;
  3125. LPCWSTR networkId = OmObjectId(Network);
  3126. LPCWSTR netInterfaceId;
  3127. PLIST_ENTRY entry;
  3128. PNM_INTERFACE netInterface;
  3129. NM_STATE_ENTRY state;
  3130. BOOLEAN selfDeclaredFailure = FALSE;
  3131. DWORD interfaceFailureTimeout = 0;
  3132. BOOLEAN abortComputation = FALSE;
  3133. ClRtlLogPrint(LOG_NOISE,
  3134. "[NM] Beginning phase 1 of state computation for network %1!ws!.\n",
  3135. networkId
  3136. );
  3137. //
  3138. // Phase 1 - Compute the state of each interface from the data
  3139. // in the connectivity matrix.
  3140. //
  3141. for ( entry = Network->InterfaceList.Flink;
  3142. entry != &(Network->InterfaceList);
  3143. entry = entry->Flink
  3144. )
  3145. {
  3146. netInterface = CONTAINING_RECORD(
  3147. entry,
  3148. NM_INTERFACE,
  3149. NetworkLinkage
  3150. );
  3151. netInterfaceId = OmObjectId(netInterface);
  3152. ifNetIndex = netInterface->NetIndex;
  3153. workVector[ifNetIndex].ReachableCount = 0;
  3154. if (NmpIsNetworkEnabledForUse(Network)) {
  3155. //
  3156. // First, check what the interface thinks its own state is
  3157. //
  3158. matrixEntry = NM_GET_CONNECTIVITY_MATRIX_ENTRY(
  3159. matrix,
  3160. ifNetIndex,
  3161. ifNetIndex,
  3162. entryCount
  3163. );
  3164. if ( *matrixEntry ==
  3165. (NM_STATE_ENTRY) ClusterNetInterfaceStateUnknown
  3166. )
  3167. {
  3168. //
  3169. // This case should never happen.
  3170. //
  3171. // An existing interface cannot think its own state is
  3172. // unknown. The reflexive entry is always initialized to
  3173. // Unavailable whenever an interface is created.
  3174. //
  3175. ClRtlLogPrint(LOG_NOISE,
  3176. "[NM] No data for interface %1!u! (%2!ws!) on network "
  3177. "%3!ws!\n",
  3178. ifNetIndex,
  3179. netInterfaceId,
  3180. networkId
  3181. );
  3182. CL_ASSERT(
  3183. *matrixEntry !=
  3184. (NM_STATE_ENTRY) ClusterNetInterfaceStateUnknown
  3185. );
  3186. state = ClusterNetInterfaceUnavailable;
  3187. numIfUnavailable++;
  3188. }
  3189. else if ( *matrixEntry ==
  3190. (NM_STATE_ENTRY) ClusterNetInterfaceUnavailable
  3191. )
  3192. {
  3193. if (NM_NODE_UP(netInterface->Node)) {
  3194. //
  3195. // The node is up, but its connectivity report has
  3196. // not been received yet. This case may happen while a
  3197. // node is joining. It can also happen if this node has
  3198. // just become the new leader.
  3199. //
  3200. // Abort the state computation.
  3201. //
  3202. ClRtlLogPrint(LOG_NOISE,
  3203. "[NM] Data is not yet valid for interface %1!u! "
  3204. "(%2!ws!) on network %3!ws!.\n",
  3205. ifNetIndex,
  3206. netInterfaceId,
  3207. networkId
  3208. );
  3209. abortComputation = TRUE;
  3210. break;
  3211. }
  3212. else {
  3213. //
  3214. // The owning node is down or joining.
  3215. // The interface is in the unavailable state.
  3216. //
  3217. ClRtlLogPrint(LOG_NOISE,
  3218. "[NM] Node is down for interface %1!u! (%2!ws!) on "
  3219. "network %3!ws!\n",
  3220. ifNetIndex,
  3221. netInterfaceId,
  3222. networkId
  3223. );
  3224. state = ClusterNetInterfaceUnavailable;
  3225. numIfUnavailable++;
  3226. }
  3227. }
  3228. else if ( *matrixEntry ==
  3229. (NM_STATE_ENTRY) ClusterNetInterfaceFailed
  3230. )
  3231. {
  3232. //
  3233. // The node declared its own interface as failed.
  3234. // The interface is in the failed state.
  3235. //
  3236. ClRtlLogPrint(LOG_NOISE,
  3237. "[NM] Interface %1!u! (%2!ws!) has failed on network "
  3238. "%3!ws!\n",
  3239. ifNetIndex,
  3240. netInterfaceId,
  3241. networkId
  3242. );
  3243. state = ClusterNetInterfaceFailed;
  3244. numIfFailed++;
  3245. if (netInterface->State == ClusterNetInterfaceUp) {
  3246. selfDeclaredFailure = TRUE;
  3247. }
  3248. }
  3249. else {
  3250. CL_ASSERT(
  3251. *matrixEntry == (NM_STATE_ENTRY) ClusterNetInterfaceUp
  3252. );
  3253. //
  3254. // The owning node thinks its interface is Up.
  3255. //
  3256. // If there are no other operational interfaces on the
  3257. // network, then the interface is in the Up state.
  3258. //
  3259. // If there are other operational interfaces on the
  3260. // network, but all of their reports are not yet valid,
  3261. // then we defer calculating a new state for the interface.
  3262. //
  3263. // If there are other operational interfaces on the network,
  3264. // and all of their reports are valid, then if at least one
  3265. // of the operational interfaces reports that the interface
  3266. // is unreachable, then then the interface is in the
  3267. // Unreachable state. If all of the other operational
  3268. // interfaces report that the interface is reachable, then
  3269. // the interface is in the Up state.
  3270. //
  3271. ClRtlLogPrint(LOG_NOISE,
  3272. "[NM] Examining connectivity data for interface %1!u! "
  3273. "(%2!ws!) on network %2!ws!.\n",
  3274. ifNetIndex,
  3275. netInterfaceId,
  3276. networkId
  3277. );
  3278. //
  3279. // Assume that the interface is Up until proven otherwise.
  3280. //
  3281. state = ClusterNetInterfaceUp;
  3282. //
  3283. // Examine the reports from other interfaces -
  3284. // i.e. scan the matrix column - to see if any node with
  3285. // an operational interface reports this interface to
  3286. // be unreachable.
  3287. //
  3288. for (reporter=0; reporter<entryCount; reporter++) {
  3289. if (reporter == ifNetIndex) {
  3290. continue;
  3291. }
  3292. //
  3293. // First, see if the reporting interface is operational
  3294. // by checking what the repoerter thinks of its own
  3295. // interface.
  3296. //
  3297. matrixEntry = NM_GET_CONNECTIVITY_MATRIX_ENTRY(
  3298. matrix,
  3299. reporter,
  3300. reporter,
  3301. entryCount
  3302. );
  3303. if (*matrixEntry == ClusterNetInterfaceUp) {
  3304. PNM_CONNECTIVITY_MATRIX matrixEntry2;
  3305. //
  3306. // Both the reporter and the reportee believe that
  3307. // their respective interfaces are operational.
  3308. // Check if they agree on the state of their
  3309. // connectivity before going any further.
  3310. // ClusNet guarantees that eventually they will
  3311. // agree.
  3312. //
  3313. matrixEntry = NM_GET_CONNECTIVITY_MATRIX_ENTRY(
  3314. matrix,
  3315. reporter,
  3316. ifNetIndex,
  3317. entryCount
  3318. );
  3319. matrixEntry2 = NM_GET_CONNECTIVITY_MATRIX_ENTRY(
  3320. matrix,
  3321. ifNetIndex,
  3322. reporter,
  3323. entryCount
  3324. );
  3325. if (*matrixEntry == *matrixEntry2) {
  3326. //
  3327. // The two interfaces agree on the state of
  3328. // their connectivity. Check what they agree on.
  3329. //
  3330. if (*matrixEntry == ClusterNetInterfaceUp) {
  3331. //
  3332. // The interface is reported to be up.
  3333. //
  3334. ClRtlLogPrint(LOG_NOISE,
  3335. "[NM] Interface %1!u! reports interface "
  3336. "%2!u! is up on network %3!ws!\n",
  3337. reporter,
  3338. ifNetIndex,
  3339. networkId
  3340. );
  3341. workVector[ifNetIndex].ReachableCount++;
  3342. }
  3343. else if ( *matrixEntry ==
  3344. ClusterNetInterfaceUnreachable
  3345. )
  3346. {
  3347. //
  3348. // The interface is reported to be
  3349. // unreachable.
  3350. //
  3351. ClRtlLogPrint(LOG_NOISE,
  3352. "[NM] Interface %1!u! reports interface "
  3353. "%2!u! is unreachable on network %3!ws!\n",
  3354. reporter,
  3355. ifNetIndex,
  3356. networkId
  3357. );
  3358. state = ClusterNetInterfaceUnreachable;
  3359. //
  3360. // If this interface is already in failed state do fault isolation immediately.
  3361. //
  3362. if(workVector[ifNetIndex].State == ClusterNetInterfaceFailed)
  3363. IsolateFailure = TRUE;
  3364. }
  3365. else {
  3366. CL_ASSERT(
  3367. *matrixEntry != ClusterNetInterfaceFailed
  3368. );
  3369. //
  3370. // The interface report is not valid yet.
  3371. // Abort the computation.
  3372. //
  3373. ClRtlLogPrint(LOG_NOISE,
  3374. "[NM] Report from interface %1!u! for "
  3375. "interface %2!u! is not valid yet on "
  3376. "network %3!ws!.\n",
  3377. reporter,
  3378. ifNetIndex,
  3379. *matrixEntry,
  3380. networkId
  3381. );
  3382. abortComputation = TRUE;
  3383. break;
  3384. }
  3385. }
  3386. else {
  3387. //
  3388. // The two interfaces do not yet agree on
  3389. // their connectivity. Abort the computation.
  3390. //
  3391. ClRtlLogPrint(LOG_NOISE,
  3392. "[NM] Interface %1!u! and interface %2!u! do "
  3393. "not agree on their connectivity on network "
  3394. "%3!ws!\n",
  3395. reporter,
  3396. ifNetIndex,
  3397. networkId
  3398. );
  3399. abortComputation = TRUE;
  3400. break;
  3401. }
  3402. }
  3403. else {
  3404. //
  3405. // The reporter does not think its own interface is
  3406. // operational.
  3407. //
  3408. ClRtlLogPrint(LOG_NOISE,
  3409. "[NM] The report from interface %1!u! is not "
  3410. "valid on network %2!ws!.\n",
  3411. reporter,
  3412. networkId
  3413. );
  3414. }
  3415. } // end of connectivity matrix scan loop
  3416. if (abortComputation) {
  3417. //
  3418. // Abort Phase 1 computation.
  3419. //
  3420. break;
  3421. }
  3422. if (state == ClusterNetInterfaceUp) {
  3423. ClRtlLogPrint(LOG_NOISE,
  3424. "[NM] Interface %1!u! (%2!ws!) is up on network "
  3425. "%3!ws!.\n",
  3426. ifNetIndex,
  3427. netInterfaceId,
  3428. networkId
  3429. );
  3430. numIfUp++;
  3431. }
  3432. else {
  3433. CL_ASSERT(state == ClusterNetInterfaceUnreachable);
  3434. ClRtlLogPrint(LOG_NOISE,
  3435. "[NM] Interface %1!u! (%2!ws!) is unreachable on "
  3436. "network %3!ws!\n",
  3437. ifNetIndex,
  3438. netInterfaceId,
  3439. networkId
  3440. );
  3441. numIfUnreachable++;
  3442. }
  3443. }
  3444. }
  3445. else {
  3446. //
  3447. // The network is disabled. It is in the Unavailable state.
  3448. //
  3449. ClRtlLogPrint(LOG_NOISE,
  3450. "[NM] Interface %1!u! (%2!ws!) is unavailable because "
  3451. "network %3!ws! is disabled. \n",
  3452. ifNetIndex,
  3453. netInterfaceId,
  3454. networkId
  3455. );
  3456. state = ClusterNetInterfaceUnavailable;
  3457. numIfUnavailable++;
  3458. }
  3459. workVector[ifNetIndex].State = state;
  3460. //
  3461. // Keep track of how many interfaces on the network are
  3462. // reachable by at least one peer.
  3463. //
  3464. if ( (state == ClusterNetInterfaceUp) ||
  3465. (workVector[ifNetIndex].ReachableCount > 0)
  3466. ) {
  3467. numIfReachable++;
  3468. }
  3469. if (netInterface->State != state) {
  3470. stateChanged = TRUE;
  3471. }
  3472. } // end of phase one interface loop
  3473. if (!abortComputation && !IsolateFailure && selfDeclaredFailure) {
  3474. interfaceFailureTimeout =
  3475. NmpGetNetworkInterfaceFailureTimerValue(networkId);
  3476. if (interfaceFailureTimeout > 0) {
  3477. ClRtlLogPrint(LOG_NOISE,
  3478. "[NM] Delaying state computation for network %1!ws! "
  3479. "for %2!u! ms to damp self-declared failure event.\n",
  3480. networkId, interfaceFailureTimeout
  3481. );
  3482. NmpStartNetworkFailureIsolationTimer(
  3483. Network,
  3484. interfaceFailureTimeout
  3485. );
  3486. abortComputation = TRUE;
  3487. }
  3488. }
  3489. if (abortComputation) {
  3490. if (interfaceFailureTimeout == 0) {
  3491. ClRtlLogPrint(LOG_NOISE,
  3492. "[NM] Aborting state computation for network %1!ws! "
  3493. " until connectivity data is valid.\n",
  3494. networkId
  3495. );
  3496. }
  3497. //
  3498. // Undo any changes we made to the work vector.
  3499. //
  3500. for ( entry = Network->InterfaceList.Flink;
  3501. entry != &(Network->InterfaceList);
  3502. entry = entry->Flink
  3503. )
  3504. {
  3505. netInterface = CONTAINING_RECORD(
  3506. entry,
  3507. NM_INTERFACE,
  3508. NetworkLinkage
  3509. );
  3510. ifNetIndex = netInterface->NetIndex;
  3511. workVector[ifNetIndex].State = (NM_STATE_ENTRY)
  3512. netInterface->State;
  3513. }
  3514. *NewNetworkState = Network->State;
  3515. return(FALSE);
  3516. }
  3517. //
  3518. // Phase 2
  3519. //
  3520. // Try to determine the scope of any failures and recompute the
  3521. // interface states. There are two cases in which we can isolate
  3522. // failures.
  3523. //
  3524. // Case 1: Three or more interfaces are operational. At least two
  3525. // interfaces can communicate with a peer. One or more
  3526. // interfaces cannot communicate with any peer.
  3527. // Those that cannot communicate at all have failed.
  3528. //
  3529. // Case 2: Exactly two interfaces are operational and they cannot
  3530. // communicate with one another. If one interface can
  3531. // communicate with an external host while the other
  3532. // cannot communicate with any external host, then the one
  3533. // that cannot communicate has failed.
  3534. //
  3535. // In any other situation, we do nothing.
  3536. //
  3537. ClRtlLogPrint(LOG_NOISE,
  3538. "[NM] Completed phase 1 of state computation for network "
  3539. "%1!ws!.\n",
  3540. networkId
  3541. );
  3542. ClRtlLogPrint(LOG_NOISE,
  3543. "[NM] Unavailable=%1!u!, Failed = %2!u!, Unreachable=%3!u!, "
  3544. "Reachable=%4!u!, Up=%5!u! on network %6!ws! \n",
  3545. numIfUnavailable,
  3546. numIfFailed,
  3547. numIfUnreachable,
  3548. numIfReachable,
  3549. numIfUp,
  3550. networkId
  3551. );
  3552. if (numIfUnreachable > 0) {
  3553. //
  3554. // Some interfaces are unreachable.
  3555. //
  3556. if ( ((numIfUp + numIfUnreachable) >= 3) && (numIfReachable >= 2) ) {
  3557. if (IsolateFailure) {
  3558. //
  3559. // Case 1.
  3560. //
  3561. ClRtlLogPrint(LOG_NOISE,
  3562. "[NM] Trying to determine scope of connectivity failure "
  3563. "for >3 interfaces on network %1!ws!.\n",
  3564. networkId
  3565. );
  3566. //
  3567. // Any operational interface that cannot communicate with at
  3568. // least one other operational interface has failed.
  3569. //
  3570. for ( entry = Network->InterfaceList.Flink;
  3571. entry != &(Network->InterfaceList);
  3572. entry = entry->Flink
  3573. )
  3574. {
  3575. netInterface = CONTAINING_RECORD(
  3576. entry,
  3577. NM_INTERFACE,
  3578. NetworkLinkage
  3579. );
  3580. ifNetIndex = netInterface->NetIndex;
  3581. netInterfaceId = OmObjectId(netInterface);
  3582. if ( ( workVector[ifNetIndex].State ==
  3583. ClusterNetInterfaceUnreachable
  3584. )
  3585. &&
  3586. (workVector[ifNetIndex].ReachableCount == 0)
  3587. )
  3588. {
  3589. ClRtlLogPrint(LOG_NOISE,
  3590. "[NM] Interface %1!u! (%2!ws!) has failed on "
  3591. "network %3!ws!\n",
  3592. ifNetIndex,
  3593. netInterfaceId,
  3594. networkId
  3595. );
  3596. workVector[ifNetIndex].State =
  3597. ClusterNetInterfaceFailed;
  3598. numIfUnreachable--;
  3599. numIfFailed++;
  3600. }
  3601. }
  3602. //
  3603. // If any interface, whose state is still unreachable, can see
  3604. // all other reachable interfaces, change its state to up.
  3605. //
  3606. for ( entry = Network->InterfaceList.Flink;
  3607. entry != &(Network->InterfaceList);
  3608. entry = entry->Flink
  3609. )
  3610. {
  3611. netInterface = CONTAINING_RECORD(
  3612. entry,
  3613. NM_INTERFACE,
  3614. NetworkLinkage
  3615. );
  3616. ifNetIndex = netInterface->NetIndex;
  3617. if ( ( workVector[ifNetIndex].State ==
  3618. ClusterNetInterfaceUnreachable
  3619. )
  3620. &&
  3621. ( workVector[ifNetIndex].ReachableCount ==
  3622. (numIfUp + numIfUnreachable - 1)
  3623. )
  3624. )
  3625. {
  3626. ClRtlLogPrint(LOG_NOISE,
  3627. "[NM] Interface %1!u! (%2!ws!) is up on network "
  3628. "%3!ws!\n",
  3629. ifNetIndex,
  3630. netInterfaceId,
  3631. networkId
  3632. );
  3633. workVector[ifNetIndex].State = ClusterNetInterfaceUp;
  3634. numIfUnreachable--;
  3635. numIfUp++;
  3636. }
  3637. }
  3638. ClRtlLogPrint(LOG_NOISE,
  3639. "[NM] Connectivity failure scope determination complete "
  3640. "for network %1!ws!.\n",
  3641. networkId
  3642. );
  3643. }
  3644. else {
  3645. //
  3646. // Schedule a failure isolation calculation to run later.
  3647. // Declaring a failure can affect cluster resources, so we
  3648. // don't want to do it unless we are sure. Delaying for a
  3649. // while reduces the risk of a false positive.
  3650. //
  3651. NmpStartNetworkFailureIsolationTimer(Network,
  3652. NM_NET_STATE_FAILURE_ISOLATION_TIMEOUT);
  3653. }
  3654. }
  3655. else if ((numIfUnreachable == 2) && (numIfUp == 0)) {
  3656. if (IsolateFailure) {
  3657. //
  3658. // Case 2.
  3659. //
  3660. PNM_INTERFACE interface1 = NULL;
  3661. BOOLEAN interface1HasConnectivity;
  3662. LPCWSTR interfaceId1;
  3663. PNM_INTERFACE interface2 = NULL;
  3664. BOOLEAN interface2HasConnectivity;
  3665. LPCWSTR interfaceId2;
  3666. DWORD status;
  3667. ClRtlLogPrint(LOG_NOISE,
  3668. "[NM] Trying to determine scope of connectivity failure "
  3669. "for 2 interfaces on network %1!ws!.\n",
  3670. networkId
  3671. );
  3672. for ( entry = Network->InterfaceList.Flink;
  3673. entry != &(Network->InterfaceList);
  3674. entry = entry->Flink
  3675. )
  3676. {
  3677. netInterface = CONTAINING_RECORD(
  3678. entry,
  3679. NM_INTERFACE,
  3680. NetworkLinkage
  3681. );
  3682. ifNetIndex = netInterface->NetIndex;
  3683. if ( workVector[ifNetIndex].State ==
  3684. ClusterNetInterfaceUnreachable
  3685. )
  3686. {
  3687. if (interface1 == NULL) {
  3688. interface1 = netInterface;
  3689. interfaceId1 = OmObjectId(interface1);
  3690. ClRtlLogPrint(LOG_NOISE,
  3691. "[NM] Unreachable interface 1 = %1!ws! on "
  3692. "network %2!ws!\n",
  3693. interfaceId1,
  3694. networkId
  3695. );
  3696. }
  3697. else {
  3698. interface2 = netInterface;
  3699. interfaceId2 = OmObjectId(interface2);
  3700. ClRtlLogPrint(LOG_NOISE,
  3701. "[NM] Unreachable interface 2 = %1!ws! on "
  3702. "network %2!ws!\n",
  3703. interfaceId2,
  3704. networkId
  3705. );
  3706. break;
  3707. }
  3708. }
  3709. }
  3710. //
  3711. // NmpTestInterfaceConnectivity releases and reacquires
  3712. // the NmpLock. We must reference the interface objects
  3713. // to ensure that they are still valid upon return from
  3714. // that routine.
  3715. //
  3716. OmReferenceObject(interface1);
  3717. OmReferenceObject(interface2);
  3718. status = NmpTestInterfaceConnectivity(
  3719. interface1,
  3720. &interface1HasConnectivity,
  3721. interface2,
  3722. &interface2HasConnectivity
  3723. );
  3724. if (status == ERROR_SUCCESS) {
  3725. if ( interface1HasConnectivity &&
  3726. !interface2HasConnectivity
  3727. )
  3728. {
  3729. ClRtlLogPrint(LOG_NOISE,
  3730. "[NM] Interface %1!u! (%2!ws!) has Failed on "
  3731. "network %3!ws!\n",
  3732. interface2->NetIndex,
  3733. interfaceId2,
  3734. networkId
  3735. );
  3736. workVector[interface2->NetIndex].State =
  3737. ClusterNetInterfaceFailed;
  3738. numIfUnreachable--;
  3739. numIfFailed++;
  3740. ClRtlLogPrint(LOG_NOISE,
  3741. "[NM] Interface %1!u! (%2!ws!) is Up on network "
  3742. "%3!ws!\n",
  3743. interface1->NetIndex,
  3744. interfaceId1,
  3745. networkId
  3746. );
  3747. workVector[interface1->NetIndex].State =
  3748. ClusterNetInterfaceUp;
  3749. numIfUnreachable--;
  3750. numIfUp++;
  3751. }
  3752. else if ( !interface1HasConnectivity &&
  3753. interface2HasConnectivity
  3754. )
  3755. {
  3756. ClRtlLogPrint(LOG_NOISE,
  3757. "[NM] Interface %1!u! (%2!ws!) has Failed on "
  3758. "network %3!ws!\n",
  3759. interface1->NetIndex,
  3760. interfaceId1,
  3761. networkId
  3762. );
  3763. workVector[interface1->NetIndex].State =
  3764. ClusterNetInterfaceFailed;
  3765. numIfUnreachable--;
  3766. numIfFailed++;
  3767. ClRtlLogPrint(LOG_NOISE,
  3768. "[NM] Interface %1!u! (%2!ws!) is Up on network "
  3769. "%3!ws!\n",
  3770. interface2->NetIndex,
  3771. interfaceId2,
  3772. networkId
  3773. );
  3774. workVector[interface2->NetIndex].State =
  3775. ClusterNetInterfaceUp;
  3776. numIfUnreachable--;
  3777. numIfUp++;
  3778. }
  3779. else {
  3780. ClRtlLogPrint(LOG_UNUSUAL,
  3781. "[NM] Network %1!ws! state is indeterminate, Scheduling"
  3782. " Failure Isolation poll\n",
  3783. networkId
  3784. );
  3785. NmpStartNetworkFailureIsolationTimer(Network,
  3786. NmpGetIsolationPollTimerValue());
  3787. }
  3788. }
  3789. else {
  3790. ClRtlLogPrint(LOG_UNUSUAL,
  3791. "[NM] Error in Interface Connectivity test for Network %1!ws!"
  3792. ", Scheduling Failure Isolation poll\n",
  3793. networkId
  3794. );
  3795. NmpStartNetworkFailureIsolationTimer(Network,
  3796. NmpGetIsolationPollTimerValue());
  3797. }
  3798. OmDereferenceObject(interface1);
  3799. OmDereferenceObject(interface2);
  3800. ClRtlLogPrint(LOG_NOISE,
  3801. "[NM] Connectivity failure scope determination complete "
  3802. "for network %1!ws!.\n",
  3803. networkId
  3804. );
  3805. }
  3806. else {
  3807. //
  3808. // Schedule a failure isolation calculation to run later.
  3809. // Declaring a failure can affect cluster resources, so we
  3810. // don't want to do it unless we are sure. Delaying for a
  3811. // while reduces the risk of a false positive.
  3812. //
  3813. NmpStartNetworkFailureIsolationTimer(Network,
  3814. NM_NET_STATE_FAILURE_ISOLATION_TIMEOUT);
  3815. }
  3816. }
  3817. else {
  3818. ClRtlLogPrint(LOG_NOISE,
  3819. "[NM] Cannot determine scope of connectivity failure on "
  3820. "network %1!ws!.\n",
  3821. networkId
  3822. );
  3823. }
  3824. }
  3825. else {
  3826. //
  3827. // No unreachable interfaces. Disable the failure isolation timer,
  3828. // if it is running.
  3829. //
  3830. Network->FailureIsolationTimer = 0;
  3831. Network->Flags &= ~NM_FLAG_NET_ISOLATE_FAILURE;
  3832. }
  3833. //
  3834. // Phase 3 - Compute the new network state.
  3835. //
  3836. if (numIfUnavailable == Network->InterfaceCount) {
  3837. //
  3838. // All interfaces are unavailable.
  3839. //
  3840. *NewNetworkState = ClusterNetworkUnavailable;
  3841. }
  3842. else if (numIfUnreachable > 0) {
  3843. //
  3844. // Some operational interfaces have experienced
  3845. // a loss of connectivity, but the fault could not be
  3846. // isolated to them.
  3847. //
  3848. if (numIfReachable > 0) {
  3849. CL_ASSERT(numIfReachable >= 2);
  3850. //
  3851. // At least two interfaces can still communicate
  3852. // with each other, so the network is not completely down.
  3853. //
  3854. *NewNetworkState = ClusterNetworkPartitioned;
  3855. }
  3856. else {
  3857. CL_ASSERT(numIfUp == 0);
  3858. //
  3859. // None of the operational interfaces can communicate
  3860. //
  3861. *NewNetworkState = ClusterNetworkDown;
  3862. }
  3863. }
  3864. else if (numIfUp > 0) {
  3865. //
  3866. // Some interfaces are Up, all others are Failed or Unavailable
  3867. //
  3868. *NewNetworkState = ClusterNetworkUp;
  3869. }
  3870. else {
  3871. //
  3872. // Some interfaces are Unavailable, rest are Failed.
  3873. //
  3874. *NewNetworkState = ClusterNetworkDown;
  3875. }
  3876. if (Network->State != *NewNetworkState) {
  3877. stateChanged = TRUE;
  3878. ClRtlLogPrint(LOG_NOISE,
  3879. "[NM] Network %1!ws! is now in state %2!u!\n",
  3880. networkId,
  3881. *NewNetworkState
  3882. );
  3883. }
  3884. return(stateChanged);
  3885. } // NmpComputeNetworkAndInterfaceStates
  3886. DWORD
  3887. NmpGetIsolationPollTimerValue(
  3888. VOID
  3889. )
  3890. /*--
  3891. * Reads the IsolationPollTimerValue Parameter from the registry if it's there
  3892. * else returns default value.
  3893. */
  3894. {
  3895. DWORD value;
  3896. DWORD type;
  3897. DWORD len = sizeof(value);
  3898. DWORD status;
  3899. // Release NM Lock to avoid deadlock with DM lock
  3900. NmpReleaseLock();
  3901. status = DmQueryValue(
  3902. DmClusterParametersKey,
  3903. L"IsolationPollTimerValue",
  3904. &type,
  3905. (LPBYTE)&value,
  3906. &len
  3907. );
  3908. NmpAcquireLock();
  3909. if((status != ERROR_SUCCESS) || (type != REG_DWORD) ||
  3910. (value < 10) || (value > 600000)) {
  3911. ClRtlLogPrint(LOG_UNUSUAL,
  3912. "[NM] Failed to read IsolationPollTimerValue or value out of range,"
  3913. "status %1!u! using default %2!u! ms\n",
  3914. status,
  3915. NM_NET_STATE_FAILURE_ISOLATION_POLL
  3916. );
  3917. return NM_NET_STATE_FAILURE_ISOLATION_POLL;
  3918. }
  3919. else {
  3920. ClRtlLogPrint(LOG_NOISE,
  3921. "[NM] IsolationPollTimerValue = %1!u!\n",
  3922. value
  3923. );
  3924. return value;
  3925. }
  3926. }
  3927. DWORD
  3928. NmpGetNetworkInterfaceFailureTimerValue(
  3929. IN LPCWSTR NetworkId
  3930. )
  3931. /*++
  3932. Routine Description:
  3933. Reads InterfaceFailure timer value from registry.
  3934. If a value is located in the network key, it is used.
  3935. Otherwise the cluster parameters key is checked.
  3936. If no value is present, returns default.
  3937. Arguments:
  3938. NetworkId - id of network whose timer value to determine
  3939. Return value:
  3940. InterfaceFailure timer value
  3941. Notes:
  3942. Called with NM lock held (from NmpComputeNetworkAndInterfaceStates).
  3943. This routine queries the cluster database; hence, it drops the
  3944. NM lock. Since NmpComputeNetworkAndInterfaceStates is always called
  3945. in the context of the NmpWorkerThread, the Network is always
  3946. referenced during execution of this routine.
  3947. --*/
  3948. {
  3949. HDMKEY networkKey, paramKey;
  3950. DWORD status;
  3951. DWORD type;
  3952. DWORD value = NM_NET_STATE_INTERFACE_FAILURE_TIMEOUT;
  3953. DWORD len = sizeof(value);
  3954. BOOLEAN found = FALSE;
  3955. //
  3956. // To avoid deadlock, the DM lock must be acquired before the
  3957. // NM lock. Hence, release the NM lock prior to querying the
  3958. // cluster database.
  3959. //
  3960. NmpReleaseLock();
  3961. //
  3962. // First check the network key
  3963. //
  3964. networkKey = DmOpenKey(DmNetworksKey, NetworkId, KEY_READ);
  3965. if (networkKey == NULL) {
  3966. status = GetLastError();
  3967. ClRtlLogPrint(LOG_UNUSUAL,
  3968. "[NM] Failed to open key for network %1!ws!, "
  3969. "status %1!u!\n",
  3970. NetworkId, status
  3971. );
  3972. }
  3973. else {
  3974. paramKey = DmOpenKey(networkKey, L"Parameters", KEY_READ);
  3975. if (paramKey == NULL) {
  3976. status = GetLastError();
  3977. ClRtlLogPrint(LOG_NOISE,
  3978. "[NM] Failed to find Parameters key "
  3979. "for network %1!ws!, status %2!u!. Checking "
  3980. "cluster parameters ...\n",
  3981. NetworkId, status
  3982. );
  3983. }
  3984. else {
  3985. status = DmQueryValue(
  3986. paramKey,
  3987. L"InterfaceFailureTimeout",
  3988. &type,
  3989. (LPBYTE) &value,
  3990. &len
  3991. );
  3992. if (status != ERROR_SUCCESS) {
  3993. ClRtlLogPrint(LOG_NOISE,
  3994. "[NM] Failed to read InterfaceFailureTimeout "
  3995. "for network %1!ws!, status %2!u!. Checking "
  3996. "cluster parameters ...\n",
  3997. NetworkId, status
  3998. );
  3999. }
  4000. else if (type != REG_DWORD) {
  4001. ClRtlLogPrint(LOG_NOISE,
  4002. "[NM] Unexpected type (%1!u!) for network "
  4003. "%2!ws! InterfaceFailureTimeout, status %3!u!. "
  4004. "Checking cluster parameters ...\n",
  4005. type, NetworkId, status
  4006. );
  4007. }
  4008. else {
  4009. found = TRUE;
  4010. }
  4011. DmCloseKey(paramKey);
  4012. }
  4013. DmCloseKey(networkKey);
  4014. }
  4015. //
  4016. // If no value was found under the network key, check the
  4017. // cluster parameters key.
  4018. //
  4019. if (!found) {
  4020. paramKey = DmOpenKey(DmClusterParametersKey, L"Parameters", KEY_READ);
  4021. if (paramKey == NULL) {
  4022. status = GetLastError();
  4023. ClRtlLogPrint(LOG_NOISE,
  4024. "[NM] Failed to find cluster Parameters key, status %1!u!.\n",
  4025. status
  4026. );
  4027. }
  4028. else {
  4029. status = DmQueryValue(
  4030. paramKey,
  4031. L"InterfaceFailureTimeout",
  4032. &type,
  4033. (LPBYTE) &value,
  4034. &len
  4035. );
  4036. if (status != ERROR_SUCCESS) {
  4037. ClRtlLogPrint(LOG_NOISE,
  4038. "[NM] Failed to read cluster "
  4039. "InterfaceFailureTimeout, status %1!u!. "
  4040. "Using default value ...\n",
  4041. status
  4042. );
  4043. value = NM_NET_STATE_INTERFACE_FAILURE_TIMEOUT;
  4044. }
  4045. else if (type != REG_DWORD) {
  4046. ClRtlLogPrint(LOG_NOISE,
  4047. "[NM] Unexpected type (%1!u!) for cluster "
  4048. "InterfaceFailureTimeout, status %2!u!. "
  4049. "Using default value ...\n",
  4050. type, status
  4051. );
  4052. value = NM_NET_STATE_INTERFACE_FAILURE_TIMEOUT;
  4053. }
  4054. DmCloseKey(paramKey);
  4055. }
  4056. }
  4057. ClRtlLogPrint(LOG_NOISE,
  4058. "[NM] Using InterfaceFailureTimeout of %1!u! ms "
  4059. "for network %2!ws!.\n",
  4060. value, NetworkId
  4061. );
  4062. //
  4063. // Reacquire NM lock.
  4064. //
  4065. NmpAcquireLock();
  4066. return(value);
  4067. }
  4068. VOID
  4069. NmpConnectivityReportWorker(
  4070. IN PCLRTL_WORK_ITEM WorkItem,
  4071. IN DWORD Status,
  4072. IN DWORD BytesTransferred,
  4073. IN ULONG_PTR IoContext
  4074. )
  4075. /*++
  4076. Routine Description:
  4077. Worker routine for deferred operations on network objects.
  4078. Invoked to process items placed in the cluster delayed work queue.
  4079. Arguments:
  4080. WorkItem - Ignored.
  4081. Status - Ignored.
  4082. BytesTransferred - Ignored.
  4083. IoContext - Ignored.
  4084. Return Value:
  4085. None.
  4086. Notes:
  4087. This routine is run in an asynchronous worker thread.
  4088. The NmpActiveThreadCount was incremented when the thread was
  4089. scheduled.
  4090. --*/
  4091. {
  4092. BOOLEAN rescheduled = FALSE;
  4093. NmpAcquireLock();
  4094. ClRtlLogPrint(LOG_NOISE,
  4095. "[NM] Connectivity report worker thread running.\n"
  4096. );
  4097. CL_ASSERT(NmpIsConnectivityReportWorkerRunning == TRUE);
  4098. CL_ASSERT(NmpNeedConnectivityReport == TRUE);
  4099. if (NmpState >= NmStateOnlinePending) {
  4100. PNM_NETWORK network;
  4101. LPCWSTR networkId;
  4102. PLIST_ENTRY entry;
  4103. DWORD status;
  4104. while(TRUE) {
  4105. NmpNeedConnectivityReport = FALSE;
  4106. for (entry = NmpNetworkList.Flink;
  4107. entry != &NmpNetworkList;
  4108. entry = entry->Flink
  4109. )
  4110. {
  4111. network = CONTAINING_RECORD(entry, NM_NETWORK, Linkage);
  4112. if (!NM_DELETE_PENDING(network)) {
  4113. networkId = OmObjectId(network);
  4114. //
  4115. // Deliver an InterfaceFailed event for the local interface
  4116. // if needed.
  4117. //
  4118. if (network->Flags & NM_FLAG_NET_REPORT_LOCAL_IF_FAILED) {
  4119. network->Flags &= ~NM_FLAG_NET_REPORT_LOCAL_IF_FAILED;
  4120. if (NmpIsNetworkRegistered(network)) {
  4121. ClRtlLogPrint(LOG_NOISE,
  4122. "[NM] Processing local interface failed "
  4123. " event for network %1!ws!.\n",
  4124. networkId
  4125. );
  4126. NmpProcessLocalInterfaceStateEvent(
  4127. network->LocalInterface,
  4128. ClusterNetInterfaceFailed
  4129. );
  4130. }
  4131. }
  4132. //
  4133. // Deliver an InterfaceUp event for the local interface
  4134. // if needed.
  4135. //
  4136. if (network->Flags & NM_FLAG_NET_REPORT_LOCAL_IF_UP) {
  4137. network->Flags &= ~NM_FLAG_NET_REPORT_LOCAL_IF_UP;
  4138. if (NmpIsNetworkRegistered(network)) {
  4139. ClRtlLogPrint(LOG_NOISE,
  4140. "[NM] Processing local interface up event "
  4141. "for network %1!ws!.\n",
  4142. networkId
  4143. );
  4144. NmpProcessLocalInterfaceStateEvent(
  4145. network->LocalInterface,
  4146. ClusterNetInterfaceUp
  4147. );
  4148. }
  4149. }
  4150. //
  4151. // Send a connectivity report if needed.
  4152. //
  4153. if (network->Flags & NM_FLAG_NET_REPORT_CONNECTIVITY) {
  4154. CL_NODE_ID leaderNodeId = NmpLeaderNodeId;
  4155. network->Flags &= ~NM_FLAG_NET_REPORT_CONNECTIVITY;
  4156. //
  4157. // Report our connectivity to the leader.
  4158. //
  4159. status = NmpReportNetworkConnectivity(network);
  4160. if (status == ERROR_SUCCESS) {
  4161. //
  4162. // Clear the report retry count.
  4163. //
  4164. network->ConnectivityReportRetryCount = 0;
  4165. }
  4166. else {
  4167. if (NmpLeaderNodeId == leaderNodeId) {
  4168. if (network->ConnectivityReportRetryCount++ <
  4169. NM_CONNECTIVITY_REPORT_RETRY_LIMIT
  4170. )
  4171. {
  4172. //
  4173. // Try again in 500ms.
  4174. //
  4175. network->ConnectivityReportTimer = 500;
  4176. }
  4177. else {
  4178. //
  4179. // We have failed to communicate with
  4180. // the leader for too long. Mutiny.
  4181. //
  4182. NmpAdviseNodeFailure(
  4183. NmpIdArray[NmpLeaderNodeId],
  4184. status
  4185. );
  4186. network->ConnectivityReportRetryCount = 0;
  4187. }
  4188. }
  4189. else {
  4190. //
  4191. // New leader, clear the retry count. We
  4192. // already scheduled another connectivity
  4193. // report in the node down handling.
  4194. //
  4195. network->ConnectivityReportRetryCount = 0;
  4196. }
  4197. }
  4198. }
  4199. }
  4200. } // end network for loop
  4201. if (NmpNeedConnectivityReport == FALSE) {
  4202. //
  4203. // No more work to do - break out of loop.
  4204. //
  4205. break;
  4206. }
  4207. //
  4208. // More work to do. Resubmit the work item. We do this instead
  4209. // of looping so we don't hog the worker thread. If
  4210. // rescheduling fails, we will loop again in this thread.
  4211. //
  4212. ClRtlLogPrint(LOG_NOISE,
  4213. "[NM] More connectivity reports to send. Rescheduling "
  4214. "worker thread.\n"
  4215. );
  4216. status = NmpScheduleConnectivityReportWorker();
  4217. if (status == ERROR_SUCCESS) {
  4218. rescheduled = TRUE;
  4219. break;
  4220. }
  4221. } // end while(TRUE)
  4222. }
  4223. if (!rescheduled) {
  4224. NmpIsConnectivityReportWorkerRunning = FALSE;
  4225. }
  4226. ClRtlLogPrint(LOG_NOISE,
  4227. "[NM] Connectivity report worker thread finished.\n"
  4228. );
  4229. //
  4230. // Decrement active thread reference count.
  4231. //
  4232. NmpLockedLeaveApi();
  4233. NmpReleaseLock();
  4234. return;
  4235. } // NmpConnectivityReportWorker
  4236. VOID
  4237. NmpNetworkWorker(
  4238. IN PCLRTL_WORK_ITEM WorkItem,
  4239. IN DWORD Status,
  4240. IN DWORD BytesTransferred,
  4241. IN ULONG_PTR IoContext
  4242. )
  4243. /*++
  4244. Routine Description:
  4245. Worker routine for deferred operations on network objects.
  4246. Invoked to process items placed in the cluster delayed work queue.
  4247. Arguments:
  4248. WorkItem - A pointer to a work item structure that identifies the
  4249. network for which to perform work.
  4250. Status - Ignored.
  4251. BytesTransferred - Ignored.
  4252. IoContext - Ignored.
  4253. Return Value:
  4254. None.
  4255. Notes:
  4256. This routine is run in an asynchronous worker thread.
  4257. The NmpActiveThreadCount was incremented when the thread was
  4258. scheduled. The network object was also referenced.
  4259. --*/
  4260. {
  4261. PNM_NETWORK network = (PNM_NETWORK) WorkItem->Context;
  4262. LPCWSTR networkId = OmObjectId(network);
  4263. BOOLEAN rescheduled = FALSE;
  4264. NmpAcquireLock();
  4265. ClRtlLogPrint(LOG_NOISE,
  4266. "[NM] Worker thread processing network %1!ws!.\n",
  4267. networkId
  4268. );
  4269. if ((NmpState >= NmStateOnlinePending) && !NM_DELETE_PENDING(network)) {
  4270. DWORD status;
  4271. while(TRUE) {
  4272. CL_ASSERT(network->Flags & NM_FLAG_NET_WORKER_RUNNING);
  4273. //
  4274. // Register the network if needed.
  4275. //
  4276. if (network->Flags & NM_FLAG_NET_NEED_TO_REGISTER) {
  4277. network->Flags &= ~NM_FLAG_NET_NEED_TO_REGISTER;
  4278. if (network->LocalInterface != NULL) {
  4279. (VOID) NmpRegisterNetwork(
  4280. network,
  4281. TRUE // Do retry on failure
  4282. );
  4283. }
  4284. }
  4285. //
  4286. // Isolate a network failure if needed.
  4287. //
  4288. if (network->Flags & NM_FLAG_NET_ISOLATE_FAILURE) {
  4289. BOOLEAN stateChanged;
  4290. CLUSTER_NETWORK_STATE newNetworkState;
  4291. network->Flags &= ~NM_FLAG_NET_ISOLATE_FAILURE;
  4292. //
  4293. // Turn off the state recalc timer and flag, since we will
  4294. // do a recalc here.
  4295. //
  4296. network->Flags &= ~NM_FLAG_NET_RECALC_STATE;
  4297. network->StateRecalcTimer = 0;
  4298. CL_ASSERT(NmpLeaderNodeId == NmLocalNodeId);
  4299. //
  4300. // Recompute the interface and network states
  4301. // with failure isolation enabled.
  4302. //
  4303. stateChanged = NmpComputeNetworkAndInterfaceStates(
  4304. network,
  4305. TRUE,
  4306. &newNetworkState
  4307. );
  4308. if (stateChanged) {
  4309. //
  4310. // Broadcast the new network and interface states to
  4311. // all nodes
  4312. //
  4313. status = NmpGlobalSetNetworkAndInterfaceStates(
  4314. network,
  4315. newNetworkState
  4316. );
  4317. if (status != ERROR_SUCCESS) {
  4318. //
  4319. // Try again in 1 second.
  4320. //
  4321. ClRtlLogPrint(LOG_NOISE,
  4322. "[NM] Global update failed for network %1!ws!, "
  4323. "status %2!u! - restarting failure isolation "
  4324. "timer.\n",
  4325. networkId,
  4326. status
  4327. );
  4328. network->FailureIsolationTimer = 1000;
  4329. }
  4330. }
  4331. }
  4332. //
  4333. // Recalculate the network and interface states if needed.
  4334. //
  4335. if (network->Flags & NM_FLAG_NET_RECALC_STATE) {
  4336. BOOLEAN stateChanged;
  4337. CLUSTER_NETWORK_STATE newNetworkState;
  4338. network->Flags &= ~NM_FLAG_NET_RECALC_STATE;
  4339. CL_ASSERT(NmpLeaderNodeId == NmLocalNodeId);
  4340. //
  4341. // Recompute the interface and network states
  4342. // with failure isolation disabled. It will be
  4343. // enabled if needed.
  4344. //
  4345. stateChanged = NmpComputeNetworkAndInterfaceStates(
  4346. network,
  4347. FALSE,
  4348. &newNetworkState
  4349. );
  4350. if (stateChanged) {
  4351. //
  4352. // Broadcast the new network and interface states to
  4353. // all nodes
  4354. //
  4355. status = NmpGlobalSetNetworkAndInterfaceStates(
  4356. network,
  4357. newNetworkState
  4358. );
  4359. if (status != ERROR_SUCCESS) {
  4360. //
  4361. // Try again in 500ms.
  4362. //
  4363. ClRtlLogPrint(LOG_NOISE,
  4364. "[NM] NetworkStateUpdateWorker failed issue "
  4365. "global update for network %1!ws!, status "
  4366. "%2!u! - restarting update timer.\n",
  4367. networkId,
  4368. status
  4369. );
  4370. network->StateRecalcTimer = 500;
  4371. }
  4372. }
  4373. }
  4374. if (!(network->Flags & NM_NET_WORK_FLAGS)) {
  4375. //
  4376. // No more work to do - break out of loop.
  4377. //
  4378. break;
  4379. }
  4380. //
  4381. // More work to do. Resubmit the work item. We do this instead
  4382. // of looping so we don't hog the worker thread. If
  4383. // rescheduling fails, we will loop again in this thread.
  4384. //
  4385. ClRtlLogPrint(LOG_NOISE,
  4386. "[NM] More work to do for network %1!ws!. Rescheduling "
  4387. "worker thread.\n",
  4388. networkId
  4389. );
  4390. status = NmpScheduleNetworkWorker(network);
  4391. if (status == ERROR_SUCCESS) {
  4392. rescheduled = TRUE;
  4393. break;
  4394. }
  4395. }
  4396. }
  4397. else {
  4398. network->Flags &= ~NM_NET_WORK_FLAGS;
  4399. }
  4400. if (!rescheduled) {
  4401. network->Flags &= ~NM_FLAG_NET_WORKER_RUNNING;
  4402. }
  4403. ClRtlLogPrint(LOG_NOISE,
  4404. "[NM] Worker thread finished processing network %1!ws!.\n",
  4405. networkId
  4406. );
  4407. NmpLockedLeaveApi();
  4408. NmpReleaseLock();
  4409. OmDereferenceObject(network);
  4410. return;
  4411. } // NmpNetworkWorker
  4412. VOID
  4413. NmpNetworkTimerTick(
  4414. IN DWORD MsTickInterval
  4415. )
  4416. /*++
  4417. Routine Description:
  4418. Called by NM periodic timer to decrement network timers.
  4419. Arguments:
  4420. MsTickInterval - The number of milliseconds that have passed since
  4421. the last timer tick.
  4422. Return Value:
  4423. None.
  4424. Notes:
  4425. Called with NmpLock held.
  4426. --*/
  4427. {
  4428. if (NmpLockedEnterApi(NmStateOnlinePending)) {
  4429. PLIST_ENTRY entry;
  4430. PNM_NETWORK network;
  4431. //
  4432. // Walk thru the list of networks and decrement any running timers.
  4433. //
  4434. for ( entry = NmpNetworkList.Flink;
  4435. entry != &NmpNetworkList;
  4436. entry = entry->Flink
  4437. )
  4438. {
  4439. network = CONTAINING_RECORD(entry, NM_NETWORK, Linkage);
  4440. //
  4441. // Network registration retry timer.
  4442. //
  4443. if (network->RegistrationRetryTimer != 0) {
  4444. if (network->RegistrationRetryTimer > MsTickInterval) {
  4445. network->RegistrationRetryTimer -= MsTickInterval;
  4446. }
  4447. else {
  4448. //
  4449. // The timer has expired. Schedule a worker thread
  4450. // to register the network.
  4451. //
  4452. LPCWSTR networkId = OmObjectId(network);
  4453. LPCWSTR networkName = OmObjectName(network);
  4454. ClRtlLogPrint(LOG_NOISE,
  4455. "[NM] Registration retry timer expired for "
  4456. "network %1!ws! (%2!ws!).\n",
  4457. networkId,
  4458. networkName
  4459. );
  4460. NmpScheduleNetworkRegistration(network);
  4461. }
  4462. }
  4463. //
  4464. // Connectivity report generation timer.
  4465. //
  4466. if (network->ConnectivityReportTimer != 0) {
  4467. if (network->ConnectivityReportTimer > MsTickInterval) {
  4468. network->ConnectivityReportTimer -= MsTickInterval;
  4469. }
  4470. else {
  4471. //
  4472. // The timer has expired. Schedule a worker thread
  4473. // to deliver a connectivity report.
  4474. //
  4475. LPCWSTR networkId = OmObjectId(network);
  4476. LPCWSTR networkName = OmObjectName(network);
  4477. ClRtlLogPrint(LOG_NOISE,
  4478. "[NM] Connectivity report timer expired for "
  4479. "network %1!ws! (%2!ws!).\n",
  4480. networkId,
  4481. networkName
  4482. );
  4483. NmpScheduleNetworkConnectivityReport(network);
  4484. }
  4485. }
  4486. //
  4487. // Network state recalculation timer.
  4488. //
  4489. if (network->StateRecalcTimer != 0) {
  4490. if (network->StateRecalcTimer > MsTickInterval) {
  4491. network->StateRecalcTimer -= MsTickInterval;
  4492. }
  4493. else {
  4494. //
  4495. // The timer has expired. Schedule a worker thread
  4496. // to recalculate the state of the network.
  4497. //
  4498. LPCWSTR networkId = OmObjectId(network);
  4499. LPCWSTR networkName = OmObjectName(network);
  4500. ClRtlLogPrint(LOG_NOISE,
  4501. "[NM] State recalculation timer expired for "
  4502. "network %1!ws! (%2!ws!).\n",
  4503. networkId,
  4504. networkName
  4505. );
  4506. NmpScheduleNetworkStateRecalc(network);
  4507. }
  4508. }
  4509. //
  4510. // Network multicast address renewal timer.
  4511. //
  4512. if (network->McastAddressRenewTimer != 0) {
  4513. if (network->McastAddressRenewTimer > MsTickInterval) {
  4514. network->McastAddressRenewTimer -= MsTickInterval;
  4515. }
  4516. else {
  4517. //
  4518. // The timer has expired. Schedule a worker thread
  4519. // to renew the network's multicast address.
  4520. //
  4521. LPCWSTR networkId = OmObjectId(network);
  4522. LPCWSTR networkName = OmObjectName(network);
  4523. ClRtlLogPrint(LOG_NOISE,
  4524. "[NM] Multicast address lease renewal timer "
  4525. "expired for network %1!ws! (%2!ws!).\n",
  4526. networkId,
  4527. networkName
  4528. );
  4529. NmpScheduleMulticastAddressRenewal(network);
  4530. }
  4531. }
  4532. //
  4533. // Network multicast address release timer.
  4534. //
  4535. if (network->McastAddressReleaseRetryTimer != 0) {
  4536. if (network->McastAddressReleaseRetryTimer > MsTickInterval) {
  4537. network->McastAddressReleaseRetryTimer -= MsTickInterval;
  4538. }
  4539. else {
  4540. //
  4541. // The timer has expired. Schedule a worker thread
  4542. // to release the network's multicast address.
  4543. //
  4544. LPCWSTR networkId = OmObjectId(network);
  4545. LPCWSTR networkName = OmObjectName(network);
  4546. ClRtlLogPrint(LOG_NOISE,
  4547. "[NM] Multicast address release timer "
  4548. "expired for network %1!ws! (%2!ws!).\n",
  4549. networkId,
  4550. networkName
  4551. );
  4552. NmpScheduleMulticastAddressRelease(network);
  4553. }
  4554. }
  4555. //
  4556. // Network failure isolation timer.
  4557. //
  4558. if (network->FailureIsolationTimer != 0) {
  4559. if (network->FailureIsolationTimer > MsTickInterval) {
  4560. network->FailureIsolationTimer -= MsTickInterval;
  4561. }
  4562. else {
  4563. //
  4564. // The timer has expired. Schedule a worker thread
  4565. // to perform failure isolation on the network.
  4566. //
  4567. DWORD status = ERROR_SUCCESS;
  4568. LPCWSTR networkId = OmObjectId(network);
  4569. LPCWSTR networkName = OmObjectName(network);
  4570. ClRtlLogPrint(LOG_NOISE,
  4571. "[NM] Failure isolation timer expired for network "
  4572. "%1!ws! (%2!ws!).\n",
  4573. networkId,
  4574. networkName
  4575. );
  4576. if (!NmpIsNetworkWorkerRunning(network)) {
  4577. status = NmpScheduleNetworkWorker(network);
  4578. }
  4579. //
  4580. // Zero out the timer if we succeeded in scheduling a
  4581. // worker thread. If we failed, leave the timer value
  4582. // non-zero and we'll try again on the next tick.
  4583. //
  4584. if (status == ERROR_SUCCESS) {
  4585. network->FailureIsolationTimer = 0;
  4586. network->Flags |= NM_FLAG_NET_ISOLATE_FAILURE;
  4587. }
  4588. }
  4589. }
  4590. }
  4591. NmpLockedLeaveApi();
  4592. }
  4593. return;
  4594. } // NmpNetworkTimerTick
  4595. VOID
  4596. NmpStartNetworkConnectivityReportTimer(
  4597. PNM_NETWORK Network
  4598. )
  4599. /*++
  4600. Routine Description:
  4601. Starts the connectivity report timer for a network. Connectivity
  4602. reports are delayed in order to aggregate events when a failure
  4603. occurs that affects multiple nodes.
  4604. Arguments:
  4605. Network - A pointer to the network for which to start the timer.
  4606. Return Value
  4607. None.
  4608. Notes:
  4609. Called with NM lock held.
  4610. --*/
  4611. {
  4612. //
  4613. // Check if the timer is already running.
  4614. //
  4615. if (Network->ConnectivityReportTimer == 0) {
  4616. //
  4617. // Check how many nodes are attached to this network.
  4618. //
  4619. if (Network->InterfaceCount <= 2) {
  4620. //
  4621. // There is no point in waiting to aggregate reports when
  4622. // only two nodes are connected to the network.
  4623. // Just schedule a worker thread to deliver the report.
  4624. //
  4625. NmpScheduleNetworkConnectivityReport(Network);
  4626. }
  4627. else {
  4628. //
  4629. // More than two nodes are connected to this network.
  4630. // Start the timer.
  4631. //
  4632. LPCWSTR networkId = OmObjectId(Network);
  4633. LPCWSTR networkName = OmObjectName(Network);
  4634. Network->ConnectivityReportTimer =
  4635. NM_NET_CONNECTIVITY_REPORT_TIMEOUT;
  4636. ClRtlLogPrint(LOG_NOISE,
  4637. "[NM] Started connectivity report timer (%1!u!ms) for "
  4638. "network %2!ws! (%3!ws!)\n",
  4639. Network->ConnectivityReportTimer,
  4640. networkId,
  4641. networkName
  4642. );
  4643. }
  4644. }
  4645. return;
  4646. } // NmpStartNetworkConnectivityReportTimer
  4647. VOID
  4648. NmpStartNetworkStateRecalcTimer(
  4649. PNM_NETWORK Network,
  4650. DWORD Timeout
  4651. )
  4652. {
  4653. LPCWSTR networkId = OmObjectId(Network);
  4654. LPCWSTR networkName = OmObjectName(Network);
  4655. if (Network->StateRecalcTimer == 0) {
  4656. Network->StateRecalcTimer = Timeout;
  4657. ClRtlLogPrint(LOG_NOISE,
  4658. "[NM] Started state recalculation timer (%1!u!ms) for "
  4659. "network %2!ws! (%3!ws!)\n",
  4660. Network->StateRecalcTimer,
  4661. networkId,
  4662. networkName
  4663. );
  4664. }
  4665. return;
  4666. } // NmpStartNetworkStateRecalcTimer
  4667. VOID
  4668. NmpStartNetworkFailureIsolationTimer(
  4669. PNM_NETWORK Network,
  4670. DWORD Timeout
  4671. )
  4672. {
  4673. if (Network->FailureIsolationTimer == 0) {
  4674. Network->FailureIsolationTimer = Timeout;
  4675. ClRtlLogPrint(LOG_NOISE,
  4676. "[NM] Started failure isolation timer (%1!u!ms) for "
  4677. "network %2!ws! (%3!ws!)\n",
  4678. Network->FailureIsolationTimer,
  4679. OmObjectId(Network),
  4680. OmObjectName(Network)
  4681. );
  4682. }
  4683. return;
  4684. } // NmpStartNetworkFailureIsolationTimer
  4685. VOID
  4686. NmpStartNetworkRegistrationRetryTimer(
  4687. PNM_NETWORK Network
  4688. )
  4689. {
  4690. if (Network->RegistrationRetryTimer == 0) {
  4691. if (Network->RegistrationRetryTimeout == 0) {
  4692. Network->RegistrationRetryTimeout =
  4693. NM_NET_MIN_REGISTRATION_RETRY_TIMEOUT;
  4694. }
  4695. else {
  4696. //
  4697. // Exponential backoff
  4698. //
  4699. Network->RegistrationRetryTimeout *= 2;
  4700. if ( Network->RegistrationRetryTimeout >
  4701. NM_NET_MAX_REGISTRATION_RETRY_TIMEOUT
  4702. )
  4703. {
  4704. Network->RegistrationRetryTimeout =
  4705. NM_NET_MAX_REGISTRATION_RETRY_TIMEOUT;
  4706. }
  4707. }
  4708. Network->RegistrationRetryTimer = Network->RegistrationRetryTimeout;
  4709. ClRtlLogPrint(LOG_NOISE,
  4710. "[NM] Started registration retry timer (%1!u!ms) for "
  4711. "network %2!ws! (%3!ws!)\n",
  4712. Network->RegistrationRetryTimer,
  4713. OmObjectId(Network),
  4714. OmObjectName(Network)
  4715. );
  4716. }
  4717. return;
  4718. } // NmpStartNetworkRegistrationRetryTimer
  4719. VOID
  4720. NmpScheduleNetworkConnectivityReport(
  4721. PNM_NETWORK Network
  4722. )
  4723. /*++
  4724. Routine Description:
  4725. Schedules a worker thread to deliver a connectivity report to
  4726. the leader node for the specified network. Called when the
  4727. ConnectivityReport timer expires for a network. Also called
  4728. directly in some cases.
  4729. Arguments:
  4730. A pointer to the network object for which to generate a report.
  4731. Return Value:
  4732. None.
  4733. Notes:
  4734. This routine is called with the NM lock held.
  4735. --*/
  4736. {
  4737. DWORD status = ERROR_SUCCESS;
  4738. //
  4739. // Check if a worker thread is already scheduled.
  4740. //
  4741. if (!NmpIsConnectivityReportWorkerRunning) {
  4742. status = NmpScheduleConnectivityReportWorker();
  4743. }
  4744. if (status == ERROR_SUCCESS) {
  4745. //
  4746. // We succeeded in scheduling a worker thread. Stop the
  4747. // ConnectivityReport timer and set the work flag to generate
  4748. // a report.
  4749. //
  4750. Network->ConnectivityReportTimer = 0;
  4751. Network->Flags |= NM_FLAG_NET_REPORT_CONNECTIVITY;
  4752. NmpNeedConnectivityReport = TRUE;
  4753. }
  4754. else {
  4755. //
  4756. // We failed to schedule a worker thread. Set the
  4757. // ConnecivityReport timer to expire on the next tick, so we
  4758. // can try again.
  4759. //
  4760. Network->ConnectivityReportTimer = 1;
  4761. }
  4762. return;
  4763. } // NmpScheduleNetworkConnectivityReport
  4764. VOID
  4765. NmpScheduleNetworkStateRecalc(
  4766. PNM_NETWORK Network
  4767. )
  4768. /*++
  4769. Routine Description:
  4770. Schedules a worker thread to recalculate the state of the
  4771. specified network and all of the network's interface. A network
  4772. state recalculation can be triggered by the arrival of a connectivity
  4773. report, the joining/death of a node, or a network role change.
  4774. Arguments:
  4775. A pointer to the network object whose state is to be recalculated.
  4776. Return Value:
  4777. None.
  4778. Notes:
  4779. This routine is called with the NM lock held.
  4780. --*/
  4781. {
  4782. DWORD status = ERROR_SUCCESS;
  4783. //
  4784. // Check if a worker thread is already scheduled to
  4785. // service this network.
  4786. //
  4787. if (!NmpIsNetworkWorkerRunning(Network)) {
  4788. status = NmpScheduleNetworkWorker(Network);
  4789. }
  4790. if (status == ERROR_SUCCESS) {
  4791. //
  4792. // We succeeded in scheduling a worker thread. Stop the
  4793. // StateRecalc timer and set the state recalculation work flag.
  4794. //
  4795. Network->StateRecalcTimer = 0;
  4796. Network->Flags |= NM_FLAG_NET_RECALC_STATE;
  4797. }
  4798. else {
  4799. //
  4800. // We failed to schedule a worker thread. Set the StateRecalc
  4801. // timer to expire on the next tick, so we can try again.
  4802. //
  4803. Network->ConnectivityReportTimer = 1;
  4804. }
  4805. return;
  4806. } // NmpScheduleNetworkStateRecalc
  4807. VOID
  4808. NmpScheduleNetworkRegistration(
  4809. PNM_NETWORK Network
  4810. )
  4811. /*++
  4812. Routine Description:
  4813. Schedules a worker thread to register a network with the cluster
  4814. transport.
  4815. Arguments:
  4816. A pointer to the network to register.
  4817. Return Value:
  4818. None.
  4819. Notes:
  4820. This routine is called with the NM lock held.
  4821. --*/
  4822. {
  4823. DWORD status = ERROR_SUCCESS;
  4824. //
  4825. // Check if a worker thread is already scheduled to
  4826. // service this network.
  4827. //
  4828. if (!NmpIsNetworkWorkerRunning(Network)) {
  4829. status = NmpScheduleNetworkWorker(Network);
  4830. }
  4831. if (status == ERROR_SUCCESS) {
  4832. //
  4833. // We succeeded in scheduling a worker thread. Stop the
  4834. // retry timer and set the registration work flag.
  4835. //
  4836. Network->RegistrationRetryTimer = 0;
  4837. Network->Flags |= NM_FLAG_NET_NEED_TO_REGISTER;
  4838. }
  4839. else {
  4840. //
  4841. // We failed to schedule a worker thread. Set the retry
  4842. // timer to expire on the next tick, so we can try again.
  4843. //
  4844. Network->RegistrationRetryTimer = 1;
  4845. }
  4846. return;
  4847. } // NmpScheduleNetworkRegistration
  4848. DWORD
  4849. NmpScheduleConnectivityReportWorker(
  4850. VOID
  4851. )
  4852. /*++
  4853. Routine Description:
  4854. Schedule a worker thread to deliver network connectivity reports.
  4855. Arguments:
  4856. None.
  4857. Return Value:
  4858. A Win32 status code.
  4859. Notes:
  4860. Called with the NM global lock held.
  4861. --*/
  4862. {
  4863. DWORD status;
  4864. ClRtlInitializeWorkItem(
  4865. &NmpConnectivityReportWorkItem,
  4866. NmpConnectivityReportWorker,
  4867. NULL
  4868. );
  4869. status = ClRtlPostItemWorkQueue(
  4870. CsDelayedWorkQueue,
  4871. &NmpConnectivityReportWorkItem,
  4872. 0,
  4873. 0
  4874. );
  4875. if (status == ERROR_SUCCESS) {
  4876. NmpActiveThreadCount++;
  4877. NmpIsConnectivityReportWorkerRunning = TRUE;
  4878. ClRtlLogPrint(LOG_NOISE,
  4879. "[NM] Scheduled network connectivity report worker thread.\n"
  4880. );
  4881. }
  4882. else {
  4883. ClRtlLogPrint(LOG_UNUSUAL,
  4884. "[NM] Failed to schedule network connectivity report worker "
  4885. "thread, status %1!u!\n",
  4886. status
  4887. );
  4888. }
  4889. return(status);
  4890. } // NmpScheduleConnectivityReportWorker
  4891. DWORD
  4892. NmpScheduleNetworkWorker(
  4893. PNM_NETWORK Network
  4894. )
  4895. /*++
  4896. Routine Description:
  4897. Schedule a worker thread to service this network
  4898. Arguments:
  4899. Network - Pointer to the network for which to schedule a worker thread.
  4900. Return Value:
  4901. A Win32 status code.
  4902. Notes:
  4903. Called with the NM global lock held.
  4904. --*/
  4905. {
  4906. DWORD status;
  4907. LPCWSTR networkId = OmObjectId(Network);
  4908. ClRtlInitializeWorkItem(
  4909. &(Network->WorkItem),
  4910. NmpNetworkWorker,
  4911. (PVOID) Network
  4912. );
  4913. status = ClRtlPostItemWorkQueue(
  4914. CsDelayedWorkQueue,
  4915. &(Network->WorkItem),
  4916. 0,
  4917. 0
  4918. );
  4919. if (status == ERROR_SUCCESS) {
  4920. ClRtlLogPrint(LOG_NOISE,
  4921. "[NM] Scheduled worker thread to service network %1!ws!.\n",
  4922. networkId
  4923. );
  4924. NmpActiveThreadCount++;
  4925. Network->Flags |= NM_FLAG_NET_WORKER_RUNNING;
  4926. OmReferenceObject(Network);
  4927. }
  4928. else {
  4929. ClRtlLogPrint(LOG_UNUSUAL,
  4930. "[NM] Failed to schedule worker thread to service network "
  4931. "%1!ws!, status %2!u!\n",
  4932. networkId,
  4933. status
  4934. );
  4935. }
  4936. return(status);
  4937. } // NmpScheduleNetworkWorker
  4938. DWORD
  4939. NmpReportNetworkConnectivity(
  4940. IN PNM_NETWORK Network
  4941. )
  4942. /*+
  4943. Notes:
  4944. Called with the NmpLock held.
  4945. May be called by asynchronous worker threads.
  4946. --*/
  4947. {
  4948. DWORD status = ERROR_SUCCESS;
  4949. LPCWSTR networkId = OmObjectId(Network);
  4950. //
  4951. // Since this routine is called by asynchronous worker threads,
  4952. // check if the report is still valid.
  4953. //
  4954. if (NmpIsNetworkRegistered(Network)) {
  4955. PNM_CONNECTIVITY_VECTOR vector = Network->ConnectivityVector;
  4956. PNM_INTERFACE localInterface = Network->LocalInterface;
  4957. //
  4958. // Record the information in our local data structures.
  4959. //
  4960. ClRtlLogPrint(LOG_UNUSUAL,
  4961. "[NM] Updating local connectivity info for network %1!ws!.\n",
  4962. networkId
  4963. );
  4964. NmpProcessInterfaceConnectivityReport(
  4965. localInterface,
  4966. vector
  4967. );
  4968. if (NmpLeaderNodeId != NmLocalNodeId) {
  4969. //
  4970. // Send the report to the leader via RPC.
  4971. //
  4972. PNM_CONNECTIVITY_VECTOR tmpVector;
  4973. DWORD vectorSize;
  4974. LPCWSTR localInterfaceId =
  4975. OmObjectId(localInterface);
  4976. //
  4977. // Allocate a temporary connectivity vector, since the
  4978. // one in the network object can be resized during the
  4979. // RPC call.
  4980. //
  4981. vectorSize = sizeof(NM_CONNECTIVITY_VECTOR) +
  4982. ((vector->EntryCount - 1) * sizeof(NM_STATE_ENTRY));
  4983. tmpVector = LocalAlloc(LMEM_FIXED, vectorSize);
  4984. if (tmpVector != NULL) {
  4985. CopyMemory(tmpVector, vector, vectorSize);
  4986. OmReferenceObject(Network);
  4987. OmReferenceObject(localInterface);
  4988. if (NM_NODE_UP(NmLocalNode) && (NmpState == NmStateOnline)) {
  4989. //
  4990. // This node is fully operational. Send the report
  4991. // directly to the leader.
  4992. //
  4993. PNM_NODE node = NmpIdArray[NmpLeaderNodeId];
  4994. RPC_BINDING_HANDLE rpcBinding = node->ReportRpcBinding;
  4995. OmReferenceObject(node);
  4996. status = NmpReportInterfaceConnectivity(
  4997. rpcBinding,
  4998. (LPWSTR) localInterfaceId,
  4999. tmpVector,
  5000. (LPWSTR) networkId
  5001. );
  5002. OmDereferenceObject(node);
  5003. }
  5004. else if (CsJoinSponsorBinding != NULL) {
  5005. //
  5006. // This node is joining. Forward the report to the
  5007. // sponsor.
  5008. //
  5009. ClRtlLogPrint(LOG_UNUSUAL,
  5010. "[NM] Reporting connectivity to sponsor for "
  5011. "network %1!ws!.\n",
  5012. networkId
  5013. );
  5014. NmpReleaseLock();
  5015. status = NmRpcReportJoinerInterfaceConnectivity(
  5016. CsJoinSponsorBinding,
  5017. NmpJoinSequence,
  5018. NmLocalNodeIdString,
  5019. (LPWSTR) localInterfaceId,
  5020. tmpVector
  5021. );
  5022. NmpAcquireLock();
  5023. }
  5024. else {
  5025. //
  5026. // This node must be shutting down
  5027. //
  5028. CL_ASSERT(NmpState == NmStateOfflinePending);
  5029. status = ERROR_SUCCESS;
  5030. }
  5031. if (status != ERROR_SUCCESS) {
  5032. ClRtlLogPrint(LOG_NOISE,
  5033. "[NM] Failed to report connectivity for network "
  5034. "%1!ws!, status %2!u!.\n",
  5035. networkId,
  5036. status
  5037. );
  5038. }
  5039. LocalFree(tmpVector);
  5040. OmDereferenceObject(localInterface);
  5041. OmDereferenceObject(Network);
  5042. }
  5043. else {
  5044. status = ERROR_NOT_ENOUGH_MEMORY;
  5045. }
  5046. }
  5047. }
  5048. return(status);
  5049. } // NmpReportNetworkConnectivity
  5050. VOID
  5051. NmpUpdateNetworkConnectivityForDownNode(
  5052. PNM_NODE Node
  5053. )
  5054. /*++
  5055. Notes:
  5056. Called with NmpLock held.
  5057. --*/
  5058. {
  5059. PLIST_ENTRY entry;
  5060. PNM_NETWORK network;
  5061. LPCWSTR networkId;
  5062. PNM_INTERFACE netInterface;
  5063. DWORD entryCount;
  5064. DWORD i;
  5065. PNM_CONNECTIVITY_MATRIX matrixEntry;
  5066. ClRtlLogPrint(LOG_NOISE,
  5067. "[NM] Cleaning up network and interface states for dead node %1!u!\n",
  5068. Node->NodeId
  5069. );
  5070. //
  5071. // Walk the dead node's interface list and clean up the network and
  5072. // interface states.
  5073. //
  5074. for (entry = Node->InterfaceList.Flink;
  5075. entry != &(Node->InterfaceList);
  5076. entry = entry->Flink
  5077. )
  5078. {
  5079. netInterface = CONTAINING_RECORD(
  5080. entry,
  5081. NM_INTERFACE,
  5082. NodeLinkage
  5083. );
  5084. network = netInterface->Network;
  5085. networkId = OmObjectId(network);
  5086. ClRtlLogPrint(LOG_NOISE,
  5087. "[NM] Cleaning up state of network %1!ws!\n",
  5088. networkId
  5089. );
  5090. //
  5091. // Invalidate the connectivity data for this interface.
  5092. //
  5093. NmpSetInterfaceConnectivityData(
  5094. network,
  5095. netInterface->NetIndex,
  5096. ClusterNetInterfaceUnavailable
  5097. );
  5098. //
  5099. // If the local node is attached to the network, schedule a
  5100. // connectivity report to the new leader.
  5101. //
  5102. if (NmpIsNetworkRegistered(network)) {
  5103. NmpScheduleNetworkConnectivityReport(network);
  5104. }
  5105. //
  5106. // If the local node is the (possibly new) leader, schedule
  5107. // a state update. We explicitly enable this timer here in case
  5108. // there are no active nodes attached to the network.
  5109. //
  5110. if (NmpLeaderNodeId == NmLocalNodeId) {
  5111. NmpStartNetworkStateRecalcTimer(
  5112. network,
  5113. NM_NET_STATE_RECALC_TIMEOUT_AFTER_REGROUP
  5114. );
  5115. }
  5116. }
  5117. return;
  5118. } // NmpUpdateNetworkConnectivityForDownNode
  5119. VOID
  5120. NmpFreeNetworkStateEnum(
  5121. PNM_NETWORK_STATE_ENUM NetworkStateEnum
  5122. )
  5123. {
  5124. PNM_NETWORK_STATE_INFO networkStateInfo;
  5125. DWORD i;
  5126. for (i=0; i<NetworkStateEnum->NetworkCount; i++) {
  5127. networkStateInfo = &(NetworkStateEnum->NetworkList[i]);
  5128. if (networkStateInfo->Id != NULL) {
  5129. MIDL_user_free(networkStateInfo->Id);
  5130. }
  5131. }
  5132. MIDL_user_free(NetworkStateEnum);
  5133. return;
  5134. } // NmpFreeNetworkStateEnum
  5135. /////////////////////////////////////////////////////////////////////////////
  5136. //
  5137. // Database management routines
  5138. //
  5139. /////////////////////////////////////////////////////////////////////////////
  5140. DWORD
  5141. NmpCreateNetworkDefinition(
  5142. IN PNM_NETWORK_INFO NetworkInfo,
  5143. IN HLOCALXSACTION Xaction
  5144. )
  5145. /*++
  5146. Routine Description:
  5147. Creates a new network definition in the cluster database.
  5148. Arguments:
  5149. NetworkInfo - A pointer to the information structure describing the
  5150. network to create.
  5151. Return Value:
  5152. ERROR_SUCCESS if successful.
  5153. A Win32 error code otherwise.
  5154. --*/
  5155. {
  5156. DWORD status;
  5157. HDMKEY networkKey = NULL;
  5158. DWORD valueLength;
  5159. DWORD disposition;
  5160. ClRtlLogPrint(LOG_NOISE,
  5161. "[NM] Creating database entry for network %1!ws!\n",
  5162. NetworkInfo->Id
  5163. );
  5164. networkKey = DmLocalCreateKey(
  5165. Xaction,
  5166. DmNetworksKey,
  5167. NetworkInfo->Id,
  5168. 0,
  5169. KEY_WRITE,
  5170. NULL,
  5171. &disposition
  5172. );
  5173. if (networkKey == NULL) {
  5174. status = GetLastError();
  5175. ClRtlLogPrint(LOG_CRITICAL,
  5176. "[NM] Failed to create network key, status %1!u!\n",
  5177. status
  5178. );
  5179. return(status);
  5180. }
  5181. CL_ASSERT(disposition == REG_CREATED_NEW_KEY);
  5182. //
  5183. // Write the name value for this network
  5184. //
  5185. valueLength = (wcslen(NetworkInfo->Name) + 1) * sizeof(WCHAR);
  5186. status = DmLocalSetValue(
  5187. Xaction,
  5188. networkKey,
  5189. CLUSREG_NAME_NET_NAME,
  5190. REG_SZ,
  5191. (CONST BYTE *) NetworkInfo->Name,
  5192. valueLength
  5193. );
  5194. if (status != ERROR_SUCCESS) {
  5195. ClRtlLogPrint(LOG_CRITICAL,
  5196. "[NM] Set of network name value failed, status %1!u!.\n",
  5197. status
  5198. );
  5199. goto error_exit;
  5200. }
  5201. //
  5202. // Write the description value for this network
  5203. //
  5204. valueLength = (wcslen(NetworkInfo->Description) + 1) * sizeof(WCHAR);
  5205. status = DmLocalSetValue(
  5206. Xaction,
  5207. networkKey,
  5208. CLUSREG_NAME_NET_DESC,
  5209. REG_SZ,
  5210. (CONST BYTE *) NetworkInfo->Description,
  5211. valueLength
  5212. );
  5213. if (status != ERROR_SUCCESS) {
  5214. ClRtlLogPrint(LOG_CRITICAL,
  5215. "[NM] Set of network description value failed, status %1!u!.\n",
  5216. status
  5217. );
  5218. goto error_exit;
  5219. }
  5220. //
  5221. // Write the role value for this network
  5222. //
  5223. status = DmLocalSetValue(
  5224. Xaction,
  5225. networkKey,
  5226. CLUSREG_NAME_NET_ROLE,
  5227. REG_DWORD,
  5228. (CONST BYTE *) &(NetworkInfo->Role),
  5229. sizeof(DWORD)
  5230. );
  5231. if (status != ERROR_SUCCESS) {
  5232. ClRtlLogPrint(LOG_CRITICAL,
  5233. "[NM] Set of network role value failed, status %1!u!.\n",
  5234. status
  5235. );
  5236. goto error_exit;
  5237. }
  5238. //
  5239. // Write the priority value for this network
  5240. //
  5241. status = DmLocalSetValue(
  5242. Xaction,
  5243. networkKey,
  5244. CLUSREG_NAME_NET_PRIORITY,
  5245. REG_DWORD,
  5246. (CONST BYTE *) &(NetworkInfo->Priority),
  5247. sizeof(DWORD)
  5248. );
  5249. if (status != ERROR_SUCCESS) {
  5250. ClRtlLogPrint(LOG_CRITICAL,
  5251. "[NM] Set of network priority value failed, status %1!u!.\n",
  5252. status
  5253. );
  5254. goto error_exit;
  5255. }
  5256. //
  5257. // Write the transport value for this network
  5258. //
  5259. valueLength = (wcslen(NetworkInfo->Transport) + 1) * sizeof(WCHAR);
  5260. status = DmLocalSetValue(
  5261. Xaction,
  5262. networkKey,
  5263. CLUSREG_NAME_NET_TRANSPORT,
  5264. REG_SZ,
  5265. (CONST BYTE *) NetworkInfo->Transport,
  5266. valueLength
  5267. );
  5268. if (status != ERROR_SUCCESS) {
  5269. ClRtlLogPrint(LOG_CRITICAL,
  5270. "[NM] Set of network transport value failed, status %1!u!.\n",
  5271. status
  5272. );
  5273. goto error_exit;
  5274. }
  5275. //
  5276. // Write the address value for this network
  5277. //
  5278. valueLength = (wcslen(NetworkInfo->Address) + 1) * sizeof(WCHAR);
  5279. status = DmLocalSetValue(
  5280. Xaction,
  5281. networkKey,
  5282. CLUSREG_NAME_NET_ADDRESS,
  5283. REG_SZ,
  5284. (CONST BYTE *) NetworkInfo->Address,
  5285. valueLength
  5286. );
  5287. if (status != ERROR_SUCCESS) {
  5288. ClRtlLogPrint(LOG_CRITICAL,
  5289. "[NM] Set of network address value failed, status %1!u!.\n",
  5290. status
  5291. );
  5292. goto error_exit;
  5293. }
  5294. //
  5295. // Write the address mask value for this network
  5296. //
  5297. valueLength = (wcslen(NetworkInfo->AddressMask) + 1) * sizeof(WCHAR);
  5298. status = DmLocalSetValue(
  5299. Xaction,
  5300. networkKey,
  5301. CLUSREG_NAME_NET_ADDRESS_MASK,
  5302. REG_SZ,
  5303. (CONST BYTE *) NetworkInfo->AddressMask,
  5304. valueLength
  5305. );
  5306. if (status != ERROR_SUCCESS) {
  5307. ClRtlLogPrint(LOG_CRITICAL,
  5308. "[NM] Set of network address mask value failed, status %1!u!.\n",
  5309. status
  5310. );
  5311. goto error_exit;
  5312. }
  5313. CL_ASSERT(status == ERROR_SUCCESS);
  5314. error_exit:
  5315. if (networkKey != NULL) {
  5316. DmCloseKey(networkKey);
  5317. }
  5318. return(status);
  5319. } // NmpCreateNetworkDefinition
  5320. DWORD
  5321. NmpSetNetworkNameDefinition(
  5322. IN PNM_NETWORK_INFO NetworkInfo,
  5323. IN HLOCALXSACTION Xaction
  5324. )
  5325. /*++
  5326. Routine Description:
  5327. Changes the network name in the local database
  5328. Arguments:
  5329. NetworkInfo - A pointer to the information structure describing the
  5330. network to create.
  5331. Return Value:
  5332. ERROR_SUCCESS if successful.
  5333. A Win32 error code otherwise.
  5334. --*/
  5335. {
  5336. DWORD status;
  5337. HDMKEY networkKey = NULL;
  5338. DWORD disposition;
  5339. ClRtlLogPrint(LOG_NOISE,
  5340. "[NM] Changing network name database entry for network %1!ws!\n",
  5341. NetworkInfo->Id
  5342. );
  5343. //
  5344. // Open the network's key.
  5345. //
  5346. networkKey = DmOpenKey(DmNetworksKey, NetworkInfo->Id, KEY_WRITE);
  5347. if (networkKey == NULL) {
  5348. status = GetLastError();
  5349. ClRtlLogPrint(LOG_CRITICAL,
  5350. "[NM] Failed to open network key, status %1!u!\n",
  5351. status
  5352. );
  5353. goto error_exit;
  5354. }
  5355. //
  5356. // Write the name value for this network
  5357. //
  5358. status = DmLocalSetValue(
  5359. Xaction,
  5360. networkKey,
  5361. CLUSREG_NAME_NET_NAME,
  5362. REG_SZ,
  5363. (CONST BYTE *) NetworkInfo->Name,
  5364. NM_WCSLEN( NetworkInfo->Name )
  5365. );
  5366. if (status != ERROR_SUCCESS) {
  5367. ClRtlLogPrint(LOG_CRITICAL,
  5368. "[NM] Set of network name value failed, status %1!u!.\n",
  5369. status
  5370. );
  5371. goto error_exit;
  5372. }
  5373. CL_ASSERT(status == ERROR_SUCCESS);
  5374. error_exit:
  5375. if (networkKey != NULL) {
  5376. DmCloseKey(networkKey);
  5377. }
  5378. return(status);
  5379. } // NmpSetNetworkNameDefinition
  5380. DWORD
  5381. NmpGetNetworkDefinition(
  5382. IN LPWSTR NetworkId,
  5383. OUT PNM_NETWORK_INFO NetworkInfo
  5384. )
  5385. /*++
  5386. Routine Description:
  5387. Reads information about a defined cluster network from the cluster
  5388. database and fills in a structure describing it.
  5389. Arguments:
  5390. NetworkId - A pointer to a unicode string containing the ID of the
  5391. network to query.
  5392. NetworkInfo - A pointer to the network info structure to fill in.
  5393. Return Value:
  5394. ERROR_SUCCESS if the routine succeeds.
  5395. A Win32 error code otherwise.
  5396. --*/
  5397. {
  5398. DWORD status;
  5399. HDMKEY networkKey = NULL;
  5400. DWORD valueLength, valueSize;
  5401. DWORD i;
  5402. ZeroMemory(NetworkInfo, sizeof(NM_NETWORK_INFO));
  5403. //
  5404. // Open the network's key.
  5405. //
  5406. networkKey = DmOpenKey(DmNetworksKey, NetworkId, KEY_READ);
  5407. if (networkKey == NULL) {
  5408. status = GetLastError();
  5409. ClRtlLogPrint(LOG_CRITICAL,
  5410. "[NM] Failed to open network key, status %1!u!\n",
  5411. status
  5412. );
  5413. goto error_exit;
  5414. }
  5415. //
  5416. // Copy the ID value.
  5417. //
  5418. NetworkInfo->Id = MIDL_user_allocate(NM_WCSLEN(NetworkId));
  5419. if (NetworkInfo->Id == NULL) {
  5420. status = ERROR_NOT_ENOUGH_MEMORY;
  5421. goto error_exit;
  5422. }
  5423. wcscpy(NetworkInfo->Id, NetworkId);
  5424. //
  5425. // Read the network's name.
  5426. //
  5427. valueLength = 0;
  5428. status = NmpQueryString(
  5429. networkKey,
  5430. CLUSREG_NAME_NET_NAME,
  5431. REG_SZ,
  5432. &(NetworkInfo->Name),
  5433. &valueLength,
  5434. &valueSize
  5435. );
  5436. if (status != ERROR_SUCCESS) {
  5437. ClRtlLogPrint(LOG_CRITICAL,
  5438. "[NM] Query of name value failed for network %1!ws!, "
  5439. "status %2!u!.\n",
  5440. NetworkId,
  5441. status
  5442. );
  5443. goto error_exit;
  5444. }
  5445. //
  5446. // Read the description value.
  5447. //
  5448. valueLength = 0;
  5449. status = NmpQueryString(
  5450. networkKey,
  5451. CLUSREG_NAME_NET_DESC,
  5452. REG_SZ,
  5453. &(NetworkInfo->Description),
  5454. &valueLength,
  5455. &valueSize
  5456. );
  5457. if (status != ERROR_SUCCESS) {
  5458. ClRtlLogPrint(LOG_CRITICAL,
  5459. "[NM] Query of description value failed for network %1!ws!, "
  5460. "status %2!u!.\n",
  5461. NetworkId,
  5462. status
  5463. );
  5464. goto error_exit;
  5465. }
  5466. //
  5467. // Read the role value.
  5468. //
  5469. status = DmQueryDword(
  5470. networkKey,
  5471. CLUSREG_NAME_NET_ROLE,
  5472. &(NetworkInfo->Role),
  5473. NULL
  5474. );
  5475. if (status != ERROR_SUCCESS) {
  5476. ClRtlLogPrint(LOG_CRITICAL,
  5477. "[NM] Query of role value failed for network %1!ws!, "
  5478. "status %2!u!.\n",
  5479. NetworkId,
  5480. status
  5481. );
  5482. goto error_exit;
  5483. }
  5484. //
  5485. // Read the priority value.
  5486. //
  5487. status = DmQueryDword(
  5488. networkKey,
  5489. CLUSREG_NAME_NET_PRIORITY,
  5490. &(NetworkInfo->Priority),
  5491. NULL
  5492. );
  5493. if (status != ERROR_SUCCESS) {
  5494. ClRtlLogPrint(LOG_CRITICAL,
  5495. "[NM] Query of priority value failed for network %1!ws!, "
  5496. "status %2!u!.\n",
  5497. NetworkId,
  5498. status
  5499. );
  5500. goto error_exit;
  5501. }
  5502. //
  5503. // Read the address value.
  5504. //
  5505. valueLength = 0;
  5506. status = NmpQueryString(
  5507. networkKey,
  5508. CLUSREG_NAME_NET_ADDRESS,
  5509. REG_SZ,
  5510. &(NetworkInfo->Address),
  5511. &valueLength,
  5512. &valueSize
  5513. );
  5514. if (status != ERROR_SUCCESS) {
  5515. ClRtlLogPrint(LOG_CRITICAL,
  5516. "[NM] Query of address value failed for network %1!ws!, "
  5517. "status %2!u!.\n",
  5518. NetworkId,
  5519. status
  5520. );
  5521. goto error_exit;
  5522. }
  5523. //
  5524. // Read the address mask.
  5525. //
  5526. valueLength = 0;
  5527. status = NmpQueryString(
  5528. networkKey,
  5529. CLUSREG_NAME_NET_ADDRESS_MASK,
  5530. REG_SZ,
  5531. &(NetworkInfo->AddressMask),
  5532. &valueLength,
  5533. &valueSize
  5534. );
  5535. if (status != ERROR_SUCCESS) {
  5536. ClRtlLogPrint(LOG_CRITICAL,
  5537. "[NM] Query of address mask value failed for network %1!ws!, "
  5538. "status %2!u!.\n",
  5539. NetworkId,
  5540. status
  5541. );
  5542. goto error_exit;
  5543. }
  5544. //
  5545. // Read the transport name.
  5546. //
  5547. valueLength = 0;
  5548. status = NmpQueryString(
  5549. networkKey,
  5550. CLUSREG_NAME_NET_TRANSPORT,
  5551. REG_SZ,
  5552. &(NetworkInfo->Transport),
  5553. &valueLength,
  5554. &valueSize
  5555. );
  5556. if (status != ERROR_SUCCESS) {
  5557. ClRtlLogPrint(LOG_CRITICAL,
  5558. "[NM] Query of transport value failed for network %1!ws!, "
  5559. "status %2!u!.\n",
  5560. NetworkId,
  5561. status
  5562. );
  5563. goto error_exit;
  5564. }
  5565. CL_ASSERT(status == ERROR_SUCCESS);
  5566. error_exit:
  5567. if (status != ERROR_SUCCESS) {
  5568. ClNetFreeNetworkInfo(NetworkInfo);
  5569. }
  5570. if (networkKey != NULL) {
  5571. DmCloseKey(networkKey);
  5572. }
  5573. return(status);
  5574. } // NmpGetNetworkDefinition
  5575. DWORD
  5576. NmpEnumNetworkDefinitions(
  5577. OUT PNM_NETWORK_ENUM * NetworkEnum
  5578. )
  5579. /*++
  5580. Routine Description:
  5581. Reads information about defined cluster networks from the cluster
  5582. database. and builds an enumeration structure to hold the information.
  5583. Arguments:
  5584. NetworkEnum - A pointer to the variable into which to place a pointer to
  5585. the allocated network enumeration.
  5586. Return Value:
  5587. ERROR_SUCCESS if the routine succeeds.
  5588. A Win32 error code otherwise.
  5589. --*/
  5590. {
  5591. DWORD status;
  5592. PNM_NETWORK_ENUM networkEnum = NULL;
  5593. PNM_NETWORK_INFO networkInfo;
  5594. WCHAR networkId[CS_NETWORK_ID_LENGTH + 1];
  5595. DWORD i;
  5596. DWORD valueLength;
  5597. DWORD numNetworks;
  5598. DWORD ignored;
  5599. FILETIME fileTime;
  5600. *NetworkEnum = NULL;
  5601. //
  5602. // First count the number of networks.
  5603. //
  5604. status = DmQueryInfoKey(
  5605. DmNetworksKey,
  5606. &numNetworks,
  5607. &ignored, // MaxSubKeyLen
  5608. &ignored, // Values
  5609. &ignored, // MaxValueNameLen
  5610. &ignored, // MaxValueLen
  5611. &ignored, // lpcbSecurityDescriptor
  5612. &fileTime
  5613. );
  5614. if (status != ERROR_SUCCESS) {
  5615. ClRtlLogPrint(LOG_CRITICAL,
  5616. "[NM] Failed to query Networks key information, status %1!u!\n",
  5617. status
  5618. );
  5619. return(status);
  5620. }
  5621. if (numNetworks == 0) {
  5622. valueLength = sizeof(NM_NETWORK_ENUM);
  5623. }
  5624. else {
  5625. valueLength = sizeof(NM_NETWORK_ENUM) +
  5626. (sizeof(NM_NETWORK_INFO) * (numNetworks-1));
  5627. }
  5628. valueLength = sizeof(NM_NETWORK_ENUM) +
  5629. (sizeof(NM_NETWORK_INFO) * (numNetworks-1));
  5630. networkEnum = MIDL_user_allocate(valueLength);
  5631. if (networkEnum == NULL) {
  5632. ClRtlLogPrint(LOG_CRITICAL, "[NM] Failed to allocate memory.\n");
  5633. return(ERROR_NOT_ENOUGH_MEMORY);
  5634. }
  5635. ZeroMemory(networkEnum, valueLength);
  5636. for (i=0; i < numNetworks; i++) {
  5637. networkInfo = &(networkEnum->NetworkList[i]);
  5638. valueLength = sizeof(networkId);
  5639. status = DmEnumKey(
  5640. DmNetworksKey,
  5641. i,
  5642. &(networkId[0]),
  5643. &valueLength,
  5644. NULL
  5645. );
  5646. if (status != ERROR_SUCCESS) {
  5647. ClRtlLogPrint(LOG_CRITICAL,
  5648. "[NM] Failed to enumerate network key, status %1!u!\n",
  5649. status
  5650. );
  5651. goto error_exit;
  5652. }
  5653. status = NmpGetNetworkDefinition(networkId, networkInfo);
  5654. if (status != ERROR_SUCCESS) {
  5655. goto error_exit;
  5656. }
  5657. networkEnum->NetworkCount++;
  5658. }
  5659. *NetworkEnum = networkEnum;
  5660. return(ERROR_SUCCESS);
  5661. error_exit:
  5662. if (networkEnum != NULL) {
  5663. ClNetFreeNetworkEnum(networkEnum);
  5664. }
  5665. return(status);
  5666. }
  5667. /////////////////////////////////////////////////////////////////////////////
  5668. //
  5669. // Object management routines
  5670. //
  5671. /////////////////////////////////////////////////////////////////////////////
  5672. DWORD
  5673. NmpCreateNetworkObjects(
  5674. IN PNM_NETWORK_ENUM NetworkEnum
  5675. )
  5676. /*++
  5677. Routine Description:
  5678. Processes a network information enumeration and creates network objects.
  5679. Arguments:
  5680. NetworkEnum - A pointer to a network information enumeration structure.
  5681. Return Value:
  5682. ERROR_SUCCESS if the routine completes successfully.
  5683. A Win32 error code otherwise.
  5684. --*/
  5685. {
  5686. DWORD status = ERROR_SUCCESS;
  5687. PNM_NETWORK_INFO networkInfo;
  5688. PNM_NETWORK network;
  5689. DWORD i;
  5690. for (i=0; i < NetworkEnum->NetworkCount; i++) {
  5691. networkInfo = &(NetworkEnum->NetworkList[i]);
  5692. network = NmpCreateNetworkObject(networkInfo);
  5693. if (network == NULL) {
  5694. status = GetLastError();
  5695. ClRtlLogPrint(LOG_CRITICAL,
  5696. "[NM] Failed to create network %1!ws!, status %2!u!.\n",
  5697. networkInfo->Id,
  5698. status
  5699. );
  5700. break;
  5701. }
  5702. else {
  5703. OmDereferenceObject(network);
  5704. }
  5705. }
  5706. return(status);
  5707. } // NmpCreateNetworkObjects
  5708. PNM_NETWORK
  5709. NmpCreateNetworkObject(
  5710. IN PNM_NETWORK_INFO NetworkInfo
  5711. )
  5712. /*++
  5713. Routine Description:
  5714. Instantiates a cluster network object.
  5715. Arguments:
  5716. NetworkInfo - A pointer to a structure describing the network to create.
  5717. Return Value:
  5718. A pointer to the new network object on success.
  5719. NULL on failure.
  5720. --*/
  5721. {
  5722. DWORD status;
  5723. PNM_NETWORK network = NULL;
  5724. BOOL created = FALSE;
  5725. DWORD i;
  5726. ClRtlLogPrint(LOG_NOISE,
  5727. "[NM] Creating object for network %1!ws! (%2!ws!).\n",
  5728. NetworkInfo->Id,
  5729. NetworkInfo->Name
  5730. );
  5731. //
  5732. // Make sure that an object with the same name doesn't already exist.
  5733. //
  5734. network = OmReferenceObjectById(ObjectTypeNetwork, NetworkInfo->Id);
  5735. if (network != NULL) {
  5736. OmDereferenceObject(network);
  5737. ClRtlLogPrint(LOG_CRITICAL,
  5738. "[NM] A network object named %1!ws! already exists. Cannot "
  5739. "create a new network with the same name.\n",
  5740. NetworkInfo->Id
  5741. );
  5742. SetLastError(ERROR_OBJECT_ALREADY_EXISTS);
  5743. return(NULL);
  5744. }
  5745. //
  5746. // Ensure that the IP (sub)network is unique in the cluster. Two
  5747. // nodes can race to create a new network in some cases.
  5748. //
  5749. network = NmpReferenceNetworkByAddress(
  5750. NetworkInfo->Address
  5751. );
  5752. if (network != NULL) {
  5753. OmDereferenceObject(network);
  5754. ClRtlLogPrint(LOG_CRITICAL,
  5755. "[NM] A network object already exists for IP network %1!ws!. "
  5756. "Cannot create a new network with the same address.\n",
  5757. NetworkInfo->Address
  5758. );
  5759. SetLastError(ERROR_OBJECT_ALREADY_EXISTS);
  5760. return(NULL);
  5761. }
  5762. //
  5763. // Create a network object.
  5764. //
  5765. network = OmCreateObject(
  5766. ObjectTypeNetwork,
  5767. NetworkInfo->Id,
  5768. NetworkInfo->Name,
  5769. &created
  5770. );
  5771. if (network == NULL) {
  5772. status = GetLastError();
  5773. ClRtlLogPrint(LOG_CRITICAL,
  5774. "[NM] Failed to create object for network %1!ws! (%2!ws!), status %3!u!\n",
  5775. NetworkInfo->Id,
  5776. NetworkInfo->Name,
  5777. status
  5778. );
  5779. goto error_exit;
  5780. }
  5781. CL_ASSERT(created == TRUE);
  5782. //
  5783. // Initialize the network object
  5784. //
  5785. ZeroMemory(network, sizeof(NM_NETWORK));
  5786. network->ShortId = InterlockedIncrement(&NmpNextNetworkShortId);
  5787. network->State = ClusterNetworkUnavailable;
  5788. network->Role = NetworkInfo->Role;
  5789. network->Priority = NetworkInfo->Priority;
  5790. network->Description = NetworkInfo->Description;
  5791. NetworkInfo->Description = NULL;
  5792. network->Transport = NetworkInfo->Transport;
  5793. NetworkInfo->Transport = NULL;
  5794. network->Address = NetworkInfo->Address;
  5795. NetworkInfo->Address = NULL;
  5796. network->AddressMask = NetworkInfo->AddressMask;
  5797. NetworkInfo->AddressMask = NULL;
  5798. InitializeListHead(&(network->InterfaceList));
  5799. InitializeListHead(&(network->McastAddressReleaseList));
  5800. //
  5801. // Allocate an initial connectivity vector.
  5802. // Note that we get one vector entry as part of
  5803. // the NM_CONNECTIVITY_VECTOR structure.
  5804. //
  5805. #define NM_INITIAL_VECTOR_SIZE 2
  5806. network->ConnectivityVector = LocalAlloc(
  5807. LMEM_FIXED,
  5808. ( sizeof(NM_CONNECTIVITY_VECTOR) +
  5809. ( ((NM_INITIAL_VECTOR_SIZE) - 1) *
  5810. sizeof(NM_STATE_ENTRY)
  5811. )
  5812. ));
  5813. if (network->ConnectivityVector == NULL) {
  5814. status = ERROR_NOT_ENOUGH_MEMORY;
  5815. ClRtlLogPrint(LOG_CRITICAL,
  5816. "[NM] Failed to allocate memory for connectivity vector\n"
  5817. );
  5818. goto error_exit;
  5819. }
  5820. network->ConnectivityVector->EntryCount = NM_INITIAL_VECTOR_SIZE;
  5821. FillMemory(
  5822. &(network->ConnectivityVector->Data[0]),
  5823. NM_INITIAL_VECTOR_SIZE * sizeof(NM_STATE_ENTRY),
  5824. (UCHAR) ClusterNetInterfaceStateUnknown
  5825. );
  5826. //
  5827. // Allocate a state work vector
  5828. //
  5829. network->StateWorkVector = LocalAlloc(
  5830. LMEM_FIXED,
  5831. (NM_INITIAL_VECTOR_SIZE) *
  5832. sizeof(NM_STATE_WORK_ENTRY)
  5833. );
  5834. if (network->StateWorkVector == NULL) {
  5835. status = ERROR_NOT_ENOUGH_MEMORY;
  5836. ClRtlLogPrint(LOG_CRITICAL,
  5837. "[NM] Failed to allocate memory for state work vector\n"
  5838. );
  5839. goto error_exit;
  5840. }
  5841. //
  5842. // Initialize the state work vector
  5843. //
  5844. for (i=0; i<NM_INITIAL_VECTOR_SIZE; i++) {
  5845. network->StateWorkVector[i].State =
  5846. (NM_STATE_ENTRY) ClusterNetInterfaceStateUnknown;
  5847. }
  5848. //
  5849. // Put a reference on the object for the caller.
  5850. //
  5851. OmReferenceObject(network);
  5852. NmpAcquireLock();
  5853. //
  5854. // Allocate the corresponding connectivity matrix
  5855. //
  5856. network->ConnectivityMatrix =
  5857. LocalAlloc(
  5858. LMEM_FIXED,
  5859. NM_SIZEOF_CONNECTIVITY_MATRIX(NM_INITIAL_VECTOR_SIZE)
  5860. );
  5861. if (network->ConnectivityMatrix == NULL) {
  5862. status = ERROR_NOT_ENOUGH_MEMORY;
  5863. NmpReleaseLock();
  5864. OmDereferenceObject(network);
  5865. ClRtlLogPrint(LOG_CRITICAL,
  5866. "[NM] Failed to allocate memory for connectivity matrix\n"
  5867. );
  5868. goto error_exit;
  5869. }
  5870. //
  5871. // Initialize the matrix
  5872. //
  5873. FillMemory(
  5874. network->ConnectivityMatrix,
  5875. NM_SIZEOF_CONNECTIVITY_MATRIX(NM_INITIAL_VECTOR_SIZE),
  5876. (UCHAR) ClusterNetInterfaceStateUnknown
  5877. );
  5878. //
  5879. // Make the network object available.
  5880. //
  5881. InsertTailList(&NmpNetworkList, &(network->Linkage));
  5882. NmpNetworkCount++;
  5883. if (NmpIsNetworkForInternalUse(network)) {
  5884. NmpInsertInternalNetwork(network);
  5885. NmpInternalNetworkCount++;
  5886. }
  5887. if (NmpIsNetworkForClientAccess(network)) {
  5888. NmpClientNetworkCount++;
  5889. }
  5890. network->Flags |= NM_FLAG_OM_INSERTED;
  5891. OmInsertObject(network);
  5892. NmpReleaseLock();
  5893. return(network);
  5894. error_exit:
  5895. if (network != NULL) {
  5896. NmpAcquireLock();
  5897. NmpDeleteNetworkObject(network, FALSE);
  5898. NmpReleaseLock();
  5899. }
  5900. SetLastError(status);
  5901. return(NULL);
  5902. } // NmpCreateNetworkObject
  5903. DWORD
  5904. NmpGetNetworkObjectInfo(
  5905. IN PNM_NETWORK Network,
  5906. OUT PNM_NETWORK_INFO NetworkInfo
  5907. )
  5908. /*++
  5909. Routine Description:
  5910. Reads information about a defined cluster network from the
  5911. network object and fills in a structure describing it.
  5912. Arguments:
  5913. Network - A pointer to the network object to query.
  5914. NetworkInfo - A pointer to the structure to fill in with network
  5915. information.
  5916. Return Value:
  5917. ERROR_SUCCESS if the routine succeeds.
  5918. A Win32 error code otherwise.
  5919. Notes:
  5920. Called with NmpLock held.
  5921. --*/
  5922. {
  5923. DWORD status = ERROR_NOT_ENOUGH_MEMORY;
  5924. LPWSTR tmpString = NULL;
  5925. LPWSTR networkId = (LPWSTR) OmObjectId(Network);
  5926. LPWSTR networkName = (LPWSTR) OmObjectName(Network);
  5927. ZeroMemory(NetworkInfo, sizeof(NM_NETWORK_INFO));
  5928. tmpString = MIDL_user_allocate(NM_WCSLEN(networkId));
  5929. if (tmpString == NULL) {
  5930. goto error_exit;
  5931. }
  5932. wcscpy(tmpString, networkId);
  5933. NetworkInfo->Id = tmpString;
  5934. tmpString = MIDL_user_allocate(NM_WCSLEN(networkName));
  5935. if (tmpString == NULL) {
  5936. goto error_exit;
  5937. }
  5938. wcscpy(tmpString, networkName);
  5939. NetworkInfo->Name = tmpString;
  5940. tmpString = MIDL_user_allocate(NM_WCSLEN(Network->Description));
  5941. if (tmpString == NULL) {
  5942. goto error_exit;
  5943. }
  5944. wcscpy(tmpString, Network->Description);
  5945. NetworkInfo->Description = tmpString;
  5946. NetworkInfo->Role = Network->Role;
  5947. NetworkInfo->Priority = Network->Priority;
  5948. tmpString = MIDL_user_allocate(NM_WCSLEN(Network->Transport));
  5949. if (tmpString == NULL) {
  5950. goto error_exit;
  5951. }
  5952. wcscpy(tmpString, Network->Transport);
  5953. NetworkInfo->Transport = tmpString;
  5954. tmpString = MIDL_user_allocate(NM_WCSLEN(Network->Address));
  5955. if (tmpString == NULL) {
  5956. goto error_exit;
  5957. }
  5958. wcscpy(tmpString, Network->Address);
  5959. NetworkInfo->Address = tmpString;
  5960. tmpString = MIDL_user_allocate(NM_WCSLEN(Network->AddressMask));
  5961. if (tmpString == NULL) {
  5962. goto error_exit;
  5963. }
  5964. wcscpy(tmpString, Network->AddressMask);
  5965. NetworkInfo->AddressMask = tmpString;
  5966. return(ERROR_SUCCESS);
  5967. error_exit:
  5968. ClNetFreeNetworkInfo(NetworkInfo);
  5969. return(status);
  5970. } // NmpGetNetworkObjectInfo
  5971. VOID
  5972. NmpDeleteNetworkObject(
  5973. IN PNM_NETWORK Network,
  5974. IN BOOLEAN IssueEvent
  5975. )
  5976. /*++
  5977. Routine Description:
  5978. Deletes a cluster network object.
  5979. Arguments:
  5980. Network - A pointer to the network object to delete.
  5981. IssueEvent - TRUE if a NETWORK_DELETED event should be issued when this
  5982. object is created. FALSE otherwise.
  5983. Return Value:
  5984. None.
  5985. Notes:
  5986. Called with NM global lock held.
  5987. --*/
  5988. {
  5989. DWORD status;
  5990. PLIST_ENTRY entry;
  5991. LPWSTR networkId = (LPWSTR) OmObjectId(Network);
  5992. BOOLEAN wasInternalNetwork = FALSE;
  5993. if (NM_DELETE_PENDING(Network)) {
  5994. CL_ASSERT(!NM_OM_INSERTED(Network));
  5995. return;
  5996. }
  5997. ClRtlLogPrint(LOG_NOISE,
  5998. "[NM] Deleting object for network %1!ws!.\n",
  5999. networkId
  6000. );
  6001. CL_ASSERT(IsListEmpty(&(Network->InterfaceList)));
  6002. Network->Flags |= NM_FLAG_DELETE_PENDING;
  6003. //
  6004. // Remove from the object lists
  6005. //
  6006. if (NM_OM_INSERTED(Network)) {
  6007. status = OmRemoveObject(Network);
  6008. CL_ASSERT(status == ERROR_SUCCESS);
  6009. Network->Flags &= ~NM_FLAG_OM_INSERTED;
  6010. RemoveEntryList(&(Network->Linkage));
  6011. CL_ASSERT(NmpNetworkCount > 0);
  6012. NmpNetworkCount--;
  6013. if (NmpIsNetworkForInternalUse(Network)) {
  6014. RemoveEntryList(&(Network->InternalLinkage));
  6015. CL_ASSERT(NmpInternalNetworkCount > 0);
  6016. NmpInternalNetworkCount--;
  6017. wasInternalNetwork = TRUE;
  6018. }
  6019. if (NmpIsNetworkForClientAccess(Network)) {
  6020. CL_ASSERT(NmpClientNetworkCount > 0);
  6021. NmpClientNetworkCount--;
  6022. }
  6023. }
  6024. //
  6025. // Place the object on the deleted list
  6026. //
  6027. #if DBG
  6028. {
  6029. PLIST_ENTRY entry;
  6030. for ( entry = NmpDeletedNetworkList.Flink;
  6031. entry != &NmpDeletedNetworkList;
  6032. entry = entry->Flink
  6033. )
  6034. {
  6035. if (entry == &(Network->Linkage)) {
  6036. break;
  6037. }
  6038. }
  6039. CL_ASSERT(entry != &(Network->Linkage));
  6040. }
  6041. #endif DBG
  6042. InsertTailList(&NmpDeletedNetworkList, &(Network->Linkage));
  6043. if (NmpIsNetworkEnabledForUse(Network)) {
  6044. //
  6045. // Deregister the network from the cluster transport
  6046. //
  6047. NmpDeregisterNetwork(Network);
  6048. }
  6049. //
  6050. // Issue an event if needed
  6051. //
  6052. if (IssueEvent) {
  6053. ClRtlLogPrint(LOG_NOISE,
  6054. "[NM] Issuing network deleted event for network %1!ws!.\n",
  6055. networkId
  6056. );
  6057. ClusterEvent(CLUSTER_EVENT_NETWORK_DELETED, Network);
  6058. //
  6059. // Issue a cluster property change event if this network was
  6060. // used for internal communication. The network priority list
  6061. // was changed.
  6062. //
  6063. if (wasInternalNetwork) {
  6064. NmpIssueClusterPropertyChangeEvent();
  6065. }
  6066. }
  6067. //
  6068. // Remove the initial reference so the object can be destroyed.
  6069. //
  6070. OmDereferenceObject(Network);
  6071. return;
  6072. } // NmpDeleteNetworkObject
  6073. BOOL
  6074. NmpDestroyNetworkObject(
  6075. PNM_NETWORK Network
  6076. )
  6077. {
  6078. DWORD status;
  6079. ClRtlLogPrint(LOG_NOISE,
  6080. "[NM] destroying object for network %1!ws!\n",
  6081. OmObjectId(Network)
  6082. );
  6083. CL_ASSERT(NM_DELETE_PENDING(Network));
  6084. CL_ASSERT(!NM_OM_INSERTED(Network));
  6085. CL_ASSERT(Network->InterfaceCount == 0);
  6086. //
  6087. // Remove the network from the deleted list
  6088. //
  6089. #if DBG
  6090. {
  6091. PLIST_ENTRY entry;
  6092. for ( entry = NmpDeletedNetworkList.Flink;
  6093. entry != &NmpDeletedNetworkList;
  6094. entry = entry->Flink
  6095. )
  6096. {
  6097. if (entry == &(Network->Linkage)) {
  6098. break;
  6099. }
  6100. }
  6101. CL_ASSERT(entry == &(Network->Linkage));
  6102. }
  6103. #endif DBG
  6104. RemoveEntryList(&(Network->Linkage));
  6105. NM_FREE_OBJECT_FIELD(Network, Description);
  6106. NM_FREE_OBJECT_FIELD(Network, Transport);
  6107. NM_FREE_OBJECT_FIELD(Network, Address);
  6108. NM_FREE_OBJECT_FIELD(Network, AddressMask);
  6109. if (Network->ConnectivityVector != NULL) {
  6110. LocalFree(Network->ConnectivityVector);
  6111. Network->ConnectivityVector = NULL;
  6112. }
  6113. if (Network->StateWorkVector != NULL) {
  6114. LocalFree(Network->StateWorkVector);
  6115. Network->StateWorkVector = NULL;
  6116. }
  6117. if (Network->ConnectivityMatrix != NULL) {
  6118. LocalFree(Network->ConnectivityMatrix);
  6119. Network->ConnectivityMatrix = NULL;
  6120. }
  6121. NM_MIDL_FREE_OBJECT_FIELD(Network, MulticastAddress);
  6122. NM_MIDL_FREE_OBJECT_FIELD(Network, MulticastKey);
  6123. NM_MIDL_FREE_OBJECT_FIELD(Network, MulticastKeySalt);
  6124. NM_MIDL_FREE_OBJECT_FIELD(Network, MulticastLeaseServer);
  6125. NM_MIDL_FREE_OBJECT_FIELD(Network, MulticastLeaseRequestId.ClientUID);
  6126. NmpFreeMulticastAddressReleaseList(Network);
  6127. return(TRUE);
  6128. } // NmpDestroyNetworkObject
  6129. DWORD
  6130. NmpEnumNetworkObjects(
  6131. OUT PNM_NETWORK_ENUM * NetworkEnum
  6132. )
  6133. /*++
  6134. Routine Description:
  6135. Reads information about defined cluster networks from the cluster
  6136. objects and builds an enumeration structure to hold the information.
  6137. Arguments:
  6138. NetworkEnum - A pointer to the variable into which to place a pointer to
  6139. the allocated network enumeration.
  6140. Return Value:
  6141. ERROR_SUCCESS if the routine succeeds.
  6142. A Win32 error code otherwise.
  6143. Notes:
  6144. Called with the NmpLock held.
  6145. --*/
  6146. {
  6147. DWORD status = ERROR_SUCCESS;
  6148. PNM_NETWORK_ENUM networkEnum = NULL;
  6149. DWORD i;
  6150. DWORD valueLength;
  6151. PLIST_ENTRY entry;
  6152. PNM_NETWORK network;
  6153. *NetworkEnum = NULL;
  6154. if (NmpNetworkCount == 0) {
  6155. valueLength = sizeof(NM_NETWORK_ENUM);
  6156. }
  6157. else {
  6158. valueLength = sizeof(NM_NETWORK_ENUM) +
  6159. (sizeof(NM_NETWORK_INFO) * (NmpNetworkCount - 1));
  6160. }
  6161. networkEnum = MIDL_user_allocate(valueLength);
  6162. if (networkEnum == NULL) {
  6163. return(ERROR_NOT_ENOUGH_MEMORY);
  6164. }
  6165. ZeroMemory(networkEnum, valueLength);
  6166. for (entry = NmpNetworkList.Flink, i=0;
  6167. entry != &NmpNetworkList;
  6168. entry = entry->Flink, i++
  6169. )
  6170. {
  6171. network = CONTAINING_RECORD(entry, NM_NETWORK, Linkage);
  6172. status = NmpGetNetworkObjectInfo(
  6173. network,
  6174. &(networkEnum->NetworkList[i])
  6175. );
  6176. if (status != ERROR_SUCCESS) {
  6177. ClNetFreeNetworkEnum(networkEnum);
  6178. return(status);
  6179. }
  6180. }
  6181. networkEnum->NetworkCount = NmpNetworkCount;
  6182. *NetworkEnum = networkEnum;
  6183. networkEnum = NULL;
  6184. return(ERROR_SUCCESS);
  6185. } // NmpEnumNetworkObjects
  6186. DWORD
  6187. NmpEnumNetworkObjectStates(
  6188. OUT PNM_NETWORK_STATE_ENUM * NetworkStateEnum
  6189. )
  6190. /*++
  6191. Routine Description:
  6192. Reads state information for all defined cluster networks
  6193. and fills in an enumeration structure.
  6194. Arguments:
  6195. NetworkStateEnum - A pointer to the variable into which to place a
  6196. pointer to the allocated interface enumeration.
  6197. Return Value:
  6198. ERROR_SUCCESS if the routine succeeds.
  6199. A Win32 error code otherwise.
  6200. Notes:
  6201. Called with the NmpLock held.
  6202. --*/
  6203. {
  6204. DWORD status = ERROR_SUCCESS;
  6205. PNM_NETWORK_STATE_ENUM networkStateEnum = NULL;
  6206. PNM_NETWORK_STATE_INFO networkStateInfo;
  6207. DWORD i;
  6208. DWORD valueLength;
  6209. PLIST_ENTRY entry;
  6210. PNM_NETWORK network;
  6211. LPWSTR networkId;
  6212. *NetworkStateEnum = NULL;
  6213. if (NmpNetworkCount == 0) {
  6214. valueLength = sizeof(NM_NETWORK_STATE_ENUM);
  6215. }
  6216. else {
  6217. valueLength =
  6218. sizeof(NM_NETWORK_STATE_ENUM) +
  6219. (sizeof(NM_NETWORK_STATE_INFO) * (NmpNetworkCount - 1));
  6220. }
  6221. networkStateEnum = MIDL_user_allocate(valueLength);
  6222. if (networkStateEnum == NULL) {
  6223. return(ERROR_NOT_ENOUGH_MEMORY);
  6224. }
  6225. ZeroMemory(networkStateEnum, valueLength);
  6226. for (entry = NmpNetworkList.Flink, i=0;
  6227. entry != &NmpNetworkList;
  6228. entry = entry->Flink, i++
  6229. )
  6230. {
  6231. network = CONTAINING_RECORD(entry, NM_NETWORK, Linkage);
  6232. networkId = (LPWSTR) OmObjectId(network);
  6233. networkStateInfo = &(networkStateEnum->NetworkList[i]);
  6234. networkStateInfo->State = network->State;
  6235. networkStateInfo->Id = MIDL_user_allocate(NM_WCSLEN(networkId));
  6236. if (networkStateInfo->Id == NULL) {
  6237. NmpFreeNetworkStateEnum(networkStateEnum);
  6238. return(ERROR_NOT_ENOUGH_MEMORY);
  6239. }
  6240. lstrcpyW(networkStateInfo->Id, networkId);
  6241. }
  6242. networkStateEnum->NetworkCount = NmpNetworkCount;
  6243. *NetworkStateEnum = networkStateEnum;
  6244. return(ERROR_SUCCESS);
  6245. } // NmpEnumNetworkObjectStates
  6246. /////////////////////////////////////////////////////////////////////////////
  6247. //
  6248. // Miscellaneous routines
  6249. //
  6250. /////////////////////////////////////////////////////////////////////////////
  6251. DWORD
  6252. NmpRegisterNetwork(
  6253. IN PNM_NETWORK Network,
  6254. IN BOOLEAN RetryOnFailure
  6255. )
  6256. /*++
  6257. Routine Description:
  6258. Registers a network and the associated interfaces with the
  6259. cluster transport and brings the network online.
  6260. Arguments:
  6261. Network - A pointer to the network to register.
  6262. Return Value:
  6263. ERROR_SUCCESS if successful.
  6264. A Win32 error code otherwise.
  6265. Notes:
  6266. Called with the NmpLock held.
  6267. --*/
  6268. {
  6269. PLIST_ENTRY entry;
  6270. PNM_INTERFACE netInterface;
  6271. DWORD status = ERROR_SUCCESS;
  6272. DWORD tempStatus;
  6273. PVOID tdiAddress = NULL;
  6274. ULONG tdiAddressLength = 0;
  6275. LPWSTR networkId = (LPWSTR) OmObjectId(Network);
  6276. PVOID tdiAddressInfo = NULL;
  6277. ULONG tdiAddressInfoLength = 0;
  6278. DWORD responseLength;
  6279. PNM_INTERFACE localInterface = Network->LocalInterface;
  6280. BOOLEAN restricted = FALSE;
  6281. BOOLEAN registered = FALSE;
  6282. if (Network->LocalInterface != NULL) {
  6283. if (!NmpIsNetworkRegistered(Network)) {
  6284. //
  6285. // Register the network
  6286. //
  6287. ClRtlLogPrint(LOG_NOISE,
  6288. "[NM] Registering network %1!ws! (%2!ws!) with cluster "
  6289. "transport.\n",
  6290. networkId,
  6291. OmObjectName(Network)
  6292. );
  6293. if (!NmpIsNetworkForInternalUse(Network)) {
  6294. restricted = TRUE;
  6295. }
  6296. status = ClusnetRegisterNetwork(
  6297. NmClusnetHandle,
  6298. Network->ShortId,
  6299. Network->Priority,
  6300. restricted
  6301. );
  6302. if (status == ERROR_SUCCESS) {
  6303. registered = TRUE;
  6304. //
  6305. // Bring the network online.
  6306. //
  6307. ClRtlLogPrint(LOG_NOISE,
  6308. "[NM] Bringing network %1!ws! online.\n",
  6309. networkId
  6310. );
  6311. status = ClRtlBuildTcpipTdiAddress(
  6312. localInterface->Address,
  6313. localInterface->ClusnetEndpoint,
  6314. &tdiAddress,
  6315. &tdiAddressLength
  6316. );
  6317. if (status == ERROR_SUCCESS) {
  6318. ClRtlQueryTcpipInformation(
  6319. NULL,
  6320. NULL,
  6321. &tdiAddressInfoLength
  6322. );
  6323. tdiAddressInfo = LocalAlloc(
  6324. LMEM_FIXED,
  6325. tdiAddressInfoLength
  6326. );
  6327. if (tdiAddressInfo != NULL) {
  6328. responseLength = tdiAddressInfoLength;
  6329. status = ClusnetOnlineNetwork(
  6330. NmClusnetHandle,
  6331. Network->ShortId,
  6332. L"\\Device\\Udp",
  6333. tdiAddress,
  6334. tdiAddressLength,
  6335. localInterface->AdapterId,
  6336. tdiAddressInfo,
  6337. &responseLength
  6338. );
  6339. if (status != ERROR_SUCCESS) {
  6340. ClRtlLogPrint(LOG_CRITICAL,
  6341. "[NM] Cluster transport failed to bring "
  6342. "network %1!ws! online, status %2!u!.\n",
  6343. networkId,
  6344. status
  6345. );
  6346. }
  6347. else {
  6348. CL_ASSERT(responseLength == tdiAddressInfoLength);
  6349. }
  6350. LocalFree(tdiAddressInfo);
  6351. }
  6352. else {
  6353. status = ERROR_NOT_ENOUGH_MEMORY;
  6354. ClRtlLogPrint(LOG_UNUSUAL,
  6355. "[NM] Failed to allocate memory to register "
  6356. "network %1!ws! with cluster transport.\n",
  6357. networkId
  6358. );
  6359. }
  6360. LocalFree(tdiAddress);
  6361. }
  6362. else {
  6363. ClRtlLogPrint(LOG_CRITICAL,
  6364. "[NM] Failed to build address to register "
  6365. "network %1!ws! withh cluster transport, "
  6366. "status %2!u!.\n",
  6367. networkId,
  6368. status
  6369. );
  6370. }
  6371. }
  6372. else {
  6373. ClRtlLogPrint(LOG_CRITICAL,
  6374. "[NM] Failed to register network %1!ws! with cluster "
  6375. "transport, status %2!u!.\n",
  6376. networkId,
  6377. status
  6378. );
  6379. }
  6380. if (status == ERROR_SUCCESS) {
  6381. Network->Flags |= NM_FLAG_NET_REGISTERED;
  6382. Network->RegistrationRetryTimeout = 0;
  6383. }
  6384. else {
  6385. WCHAR string[16];
  6386. wsprintfW(&(string[0]), L"%u", status);
  6387. CsLogEvent2(
  6388. LOG_UNUSUAL,
  6389. NM_EVENT_REGISTER_NETWORK_FAILED,
  6390. OmObjectName(Network),
  6391. string
  6392. );
  6393. if (registered) {
  6394. NmpDeregisterNetwork(Network);
  6395. }
  6396. //
  6397. // Retry if the error is transient.
  6398. //
  6399. if ( RetryOnFailure &&
  6400. ( (status == ERROR_INVALID_NETNAME) ||
  6401. (status == ERROR_NOT_ENOUGH_MEMORY) ||
  6402. (status == ERROR_NO_SYSTEM_RESOURCES)
  6403. )
  6404. )
  6405. {
  6406. NmpStartNetworkRegistrationRetryTimer(Network);
  6407. status = ERROR_SUCCESS;
  6408. }
  6409. return(status);
  6410. }
  6411. }
  6412. //
  6413. // Register the network's interfaces.
  6414. //
  6415. for (entry = Network->InterfaceList.Flink;
  6416. entry != &(Network->InterfaceList);
  6417. entry = entry->Flink
  6418. )
  6419. {
  6420. netInterface = CONTAINING_RECORD(
  6421. entry,
  6422. NM_INTERFACE,
  6423. NetworkLinkage
  6424. );
  6425. if (!NmpIsInterfaceRegistered(netInterface)) {
  6426. tempStatus = NmpRegisterInterface(
  6427. netInterface,
  6428. RetryOnFailure
  6429. );
  6430. if (tempStatus != ERROR_SUCCESS) {
  6431. status = tempStatus;
  6432. }
  6433. }
  6434. }
  6435. }
  6436. return(status);
  6437. } // NmpRegisterNetwork
  6438. VOID
  6439. NmpDeregisterNetwork(
  6440. IN PNM_NETWORK Network
  6441. )
  6442. /*++
  6443. Routine Description:
  6444. Deregisters a network and the associated interfaces from the
  6445. cluster transport.
  6446. Arguments:
  6447. Network - A pointer to the network to deregister.
  6448. Return Value:
  6449. None.
  6450. Notes:
  6451. Called with the NmpLock held.
  6452. --*/
  6453. {
  6454. DWORD status;
  6455. PNM_INTERFACE netInterface;
  6456. PLIST_ENTRY entry;
  6457. ClRtlLogPrint(LOG_NOISE,
  6458. "[NM] Deregistering network %1!ws! (%2!ws!) from cluster transport.\n",
  6459. OmObjectId(Network),
  6460. OmObjectName(Network)
  6461. );
  6462. status = ClusnetDeregisterNetwork(
  6463. NmClusnetHandle,
  6464. Network->ShortId
  6465. );
  6466. CL_ASSERT(
  6467. (status == ERROR_SUCCESS) ||
  6468. (status == ERROR_CLUSTER_NETWORK_NOT_FOUND)
  6469. );
  6470. //
  6471. // Mark all of the network's interfaces as deregistered.
  6472. //
  6473. for (entry = Network->InterfaceList.Flink;
  6474. entry != &(Network->InterfaceList);
  6475. entry = entry->Flink
  6476. )
  6477. {
  6478. netInterface = CONTAINING_RECORD(entry, NM_INTERFACE, NetworkLinkage);
  6479. netInterface->Flags &= ~NM_FLAG_IF_REGISTERED;
  6480. }
  6481. //
  6482. // Mark the network as deregistered
  6483. //
  6484. Network->Flags &= ~NM_FLAG_NET_REGISTERED;
  6485. return;
  6486. } // NmpDeregisterNetwork
  6487. VOID
  6488. NmpInsertInternalNetwork(
  6489. PNM_NETWORK Network
  6490. )
  6491. /*++
  6492. Routine Description:
  6493. Inserts a network into internal networks list based on its priority.
  6494. Arguments:
  6495. Network - A pointer to the network object to be inserted.
  6496. Return Value:
  6497. None.
  6498. Notes:
  6499. Called with the NmpLock held.
  6500. --*/
  6501. {
  6502. PLIST_ENTRY entry;
  6503. PNM_NETWORK network;
  6504. //
  6505. // Maintain internal networks in highest to lowest
  6506. // (numerically lowest to highest) priority order.
  6507. //
  6508. for (entry = NmpInternalNetworkList.Flink;
  6509. entry != &NmpInternalNetworkList;
  6510. entry = entry->Flink
  6511. )
  6512. {
  6513. network = CONTAINING_RECORD(entry, NM_NETWORK, InternalLinkage);
  6514. if (Network->Priority < network->Priority) {
  6515. break;
  6516. }
  6517. }
  6518. //
  6519. // Insert the network in front of this entry.
  6520. //
  6521. InsertTailList(entry, &(Network->InternalLinkage));
  6522. return;
  6523. } // NmpInsertNetwork
  6524. DWORD
  6525. NmpValidateNetworkRoleChange(
  6526. PNM_NETWORK Network,
  6527. CLUSTER_NETWORK_ROLE NewRole
  6528. )
  6529. {
  6530. if ( !(NewRole & ClusterNetworkRoleInternalUse) &&
  6531. NmpIsNetworkForInternalUse(Network)
  6532. )
  6533. {
  6534. //
  6535. // This change eliminates an internal network. This is only
  6536. // legal if we would still have at least one internal network
  6537. // between all active nodes.
  6538. //
  6539. if ((NmpInternalNetworkCount < 2) || !NmpVerifyConnectivity(Network)) {
  6540. return(ERROR_CLUSTER_LAST_INTERNAL_NETWORK);
  6541. }
  6542. }
  6543. if ( ( !(NewRole & ClusterNetworkRoleClientAccess) )
  6544. &&
  6545. NmpIsNetworkForClientAccess(Network)
  6546. )
  6547. {
  6548. BOOL hasDependents;
  6549. //
  6550. // This change eliminates a public network. This is only
  6551. // legal if there are no dependencies (IP address resources) on
  6552. // the network.
  6553. //
  6554. NmpReleaseLock();
  6555. hasDependents = FmCheckNetworkDependency(OmObjectId(Network));
  6556. NmpAcquireLock();
  6557. if (hasDependents) {
  6558. return(ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS);
  6559. }
  6560. }
  6561. return(ERROR_SUCCESS);
  6562. } // NmpValidateNetworkRoleChange
  6563. BOOLEAN
  6564. NmpVerifyNodeConnectivity(
  6565. PNM_NODE Node1,
  6566. PNM_NODE Node2,
  6567. PNM_NETWORK ExcludedNetwork
  6568. )
  6569. {
  6570. PLIST_ENTRY ifEntry1, ifEntry2;
  6571. PNM_NETWORK network;
  6572. PNM_INTERFACE interface1, interface2;
  6573. for (ifEntry1 = Node1->InterfaceList.Flink;
  6574. ifEntry1 != &(Node1->InterfaceList);
  6575. ifEntry1 = ifEntry1->Flink
  6576. )
  6577. {
  6578. interface1 = CONTAINING_RECORD(
  6579. ifEntry1,
  6580. NM_INTERFACE,
  6581. NodeLinkage
  6582. );
  6583. network = interface1->Network;
  6584. if ( (network != ExcludedNetwork) &&
  6585. NmpIsNetworkForInternalUse(network)
  6586. )
  6587. {
  6588. for (ifEntry2 = Node2->InterfaceList.Flink;
  6589. ifEntry2 != &(Node2->InterfaceList);
  6590. ifEntry2 = ifEntry2->Flink
  6591. )
  6592. {
  6593. interface2 = CONTAINING_RECORD(
  6594. ifEntry2,
  6595. NM_INTERFACE,
  6596. NodeLinkage
  6597. );
  6598. if (interface2->Network == interface1->Network) {
  6599. ClRtlLogPrint(LOG_NOISE,
  6600. "[NM] nodes %1!u! & %2!u! are connected over "
  6601. "network %3!ws!\n",
  6602. Node1->NodeId,
  6603. Node2->NodeId,
  6604. OmObjectId(interface1->Network)
  6605. );
  6606. return(TRUE);
  6607. }
  6608. }
  6609. }
  6610. }
  6611. ClRtlLogPrint(LOG_NOISE,
  6612. "[NM] Nodes %1!u! & %2!u! are not connected over any internal "
  6613. "networks\n",
  6614. Node1->NodeId,
  6615. Node2->NodeId
  6616. );
  6617. return(FALSE);
  6618. } // NmpVerifyNodeConnectivity
  6619. BOOLEAN
  6620. NmpVerifyConnectivity(
  6621. PNM_NETWORK ExcludedNetwork
  6622. )
  6623. {
  6624. PLIST_ENTRY node1Entry, node2Entry;
  6625. PNM_NODE node1, node2;
  6626. ClRtlLogPrint(LOG_NOISE, "[NM] Verifying connectivity\n");
  6627. for (node1Entry = NmpNodeList.Flink;
  6628. node1Entry != &NmpNodeList;
  6629. node1Entry = node1Entry->Flink
  6630. )
  6631. {
  6632. node1 = CONTAINING_RECORD(
  6633. node1Entry,
  6634. NM_NODE,
  6635. Linkage
  6636. );
  6637. if (NM_NODE_UP(node1)) {
  6638. for (node2Entry = node1->Linkage.Flink;
  6639. node2Entry != &NmpNodeList;
  6640. node2Entry = node2Entry->Flink
  6641. )
  6642. {
  6643. node2 = CONTAINING_RECORD(
  6644. node2Entry,
  6645. NM_NODE,
  6646. Linkage
  6647. );
  6648. if (NM_NODE_UP(node2)) {
  6649. ClRtlLogPrint(LOG_NOISE,
  6650. "[NM] Verifying nodes %1!u! & %2!u! are connected\n",
  6651. node1->NodeId,
  6652. node2->NodeId
  6653. );
  6654. if (!NmpVerifyNodeConnectivity(
  6655. node1,
  6656. node2,
  6657. ExcludedNetwork
  6658. )
  6659. )
  6660. {
  6661. return(FALSE);
  6662. }
  6663. }
  6664. }
  6665. }
  6666. }
  6667. return(TRUE);
  6668. } // NmpVerifyConnectivity
  6669. VOID
  6670. NmpIssueClusterPropertyChangeEvent(
  6671. VOID
  6672. )
  6673. {
  6674. DWORD status;
  6675. DWORD valueLength = 0;
  6676. DWORD valueSize = 0;
  6677. PWCHAR clusterName = NULL;
  6678. //
  6679. // The notification API expects a
  6680. // cluster name to be associated with this event.
  6681. //
  6682. status = NmpQueryString(
  6683. DmClusterParametersKey,
  6684. CLUSREG_NAME_CLUS_NAME,
  6685. REG_SZ,
  6686. &clusterName,
  6687. &valueLength,
  6688. &valueSize
  6689. );
  6690. if (status == ERROR_SUCCESS) {
  6691. ClusterEventEx(
  6692. CLUSTER_EVENT_PROPERTY_CHANGE,
  6693. EP_CONTEXT_VALID | EP_FREE_CONTEXT,
  6694. clusterName
  6695. );
  6696. //
  6697. // clusterName will be freed by the event processing code.
  6698. //
  6699. }
  6700. else {
  6701. ClRtlLogPrint(LOG_WARNING,
  6702. "[NM] Failed to issue cluster property change event, "
  6703. "status %1!u!.\n",
  6704. status
  6705. );
  6706. }
  6707. return;
  6708. } // NmpIssueClusterPropertyChangeEvent
  6709. DWORD
  6710. NmpMarshallObjectInfo(
  6711. IN const PRESUTIL_PROPERTY_ITEM PropertyTable,
  6712. IN PVOID ObjectInfo,
  6713. OUT PVOID * PropertyList,
  6714. OUT LPDWORD PropertyListSize
  6715. )
  6716. {
  6717. DWORD status;
  6718. PVOID propertyList = NULL;
  6719. DWORD propertyListSize = 0;
  6720. DWORD bytesReturned = 0;
  6721. DWORD bytesRequired = 0;
  6722. status = ClRtlPropertyListFromParameterBlock(
  6723. PropertyTable,
  6724. NULL,
  6725. &propertyListSize,
  6726. (LPBYTE) ObjectInfo,
  6727. &bytesReturned,
  6728. &bytesRequired
  6729. );
  6730. if (status != ERROR_MORE_DATA) {
  6731. CL_ASSERT(status != ERROR_SUCCESS);
  6732. return(status);
  6733. }
  6734. CL_ASSERT(bytesRequired > 0);
  6735. propertyList = MIDL_user_allocate(bytesRequired);
  6736. if (propertyList == NULL) {
  6737. return(ERROR_NOT_ENOUGH_MEMORY);
  6738. }
  6739. propertyListSize = bytesRequired;
  6740. status = ClRtlPropertyListFromParameterBlock(
  6741. PropertyTable,
  6742. propertyList,
  6743. &propertyListSize,
  6744. (LPBYTE) ObjectInfo,
  6745. &bytesReturned,
  6746. &bytesRequired
  6747. );
  6748. if (status != ERROR_SUCCESS) {
  6749. CL_ASSERT(status != ERROR_MORE_DATA);
  6750. MIDL_user_free(propertyList);
  6751. }
  6752. else {
  6753. CL_ASSERT(bytesReturned == propertyListSize);
  6754. *PropertyList = propertyList;
  6755. *PropertyListSize = bytesReturned;
  6756. }
  6757. return(status);
  6758. } // NmpMarshallObjectInfo
  6759. VOID
  6760. NmpReferenceNetwork(
  6761. PNM_NETWORK Network
  6762. )
  6763. {
  6764. OmReferenceObject(Network);
  6765. return;
  6766. }
  6767. VOID
  6768. NmpDereferenceNetwork(
  6769. PNM_NETWORK Network
  6770. )
  6771. {
  6772. OmDereferenceObject(Network);
  6773. return;
  6774. }
  6775. PNM_NETWORK
  6776. NmpReferenceNetworkByAddress(
  6777. LPWSTR NetworkAddress
  6778. )
  6779. /*++
  6780. Notes:
  6781. Called with NM lock held.
  6782. --*/
  6783. {
  6784. PNM_NETWORK network;
  6785. PLIST_ENTRY entry;
  6786. for ( entry = NmpNetworkList.Flink;
  6787. entry != &NmpNetworkList;
  6788. entry = entry->Flink
  6789. )
  6790. {
  6791. network = CONTAINING_RECORD(entry, NM_NETWORK, Linkage);
  6792. if (lstrcmpW(network->Address, NetworkAddress) == 0) {
  6793. NmpReferenceNetwork(network);
  6794. return(network);
  6795. }
  6796. }
  6797. return(NULL);
  6798. } // NmpReferenceNetworkByAddress
  6799. BOOLEAN
  6800. NmpCheckForNetwork(
  6801. VOID
  6802. )
  6803. /*++
  6804. Routine Description:
  6805. Checks whether at least one network on this node configured for MSCS
  6806. has media sense.
  6807. Arguments:
  6808. None.
  6809. Return Value:
  6810. TRUE if a viable network is found. FALSE otherwise.
  6811. Notes:
  6812. Called with and returns with no locks held.
  6813. --*/
  6814. {
  6815. PLIST_ENTRY entry;
  6816. PNM_NETWORK network;
  6817. BOOLEAN haveNetwork = FALSE;
  6818. NmpAcquireLock();
  6819. for (entry = NmpNetworkList.Flink;
  6820. entry != &NmpNetworkList;
  6821. entry = entry->Flink
  6822. )
  6823. {
  6824. network = CONTAINING_RECORD(
  6825. entry,
  6826. NM_NETWORK,
  6827. Linkage
  6828. );
  6829. // if a network's local interface is disabled, it is not
  6830. // considered a viable network. in this case the
  6831. // LocalInterface field is NULL.
  6832. if (network->LocalInterface != NULL) {
  6833. if (NmpVerifyLocalInterfaceConnected(network->LocalInterface)) {
  6834. haveNetwork = TRUE;
  6835. break;
  6836. } else {
  6837. ClRtlLogPrint(LOG_UNUSUAL,
  6838. "[NM] Network adapter %1!ws! with address %2!ws! "
  6839. "reported not connected.\n",
  6840. network->LocalInterface->AdapterId,
  6841. network->Address
  6842. );
  6843. }
  6844. }
  6845. }
  6846. NmpReleaseLock();
  6847. if (!haveNetwork) {
  6848. SetLastError(ERROR_NETWORK_NOT_AVAILABLE);
  6849. }
  6850. return(haveNetwork);
  6851. } // NmpCheckForNetwork