Leaked source code of windows server 2003
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.

8387 lines
231 KiB

  1. //***************************************************************************
  2. //
  3. // ENGINE.CPP
  4. //
  5. // Module: NLB Manager (client-side exe)
  6. //
  7. // Purpose: Implements the engine used to operate on groups of NLB hosts.
  8. // This file has no UI aspects.
  9. //
  10. // Copyright (c)2001 Microsoft Corporation, All Rights Reserved
  11. //
  12. // History:
  13. //
  14. // 07/25/01 JosephJ Created
  15. //
  16. //***************************************************************************
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. #include "AboutDialog.h"
  20. #include "private.h"
  21. #include "engine.tmh"
  22. //
  23. // ENGINEHANDLE incodes the type of the object -- the following constant
  24. // is the number of bits used to encode the type.
  25. //
  26. #define TYPE_BIT_COUNT 0x3
  27. BOOL
  28. validate_extcfg(
  29. const NLB_EXTENDED_CLUSTER_CONFIGURATION &Config
  30. );
  31. BOOL
  32. get_used_port_rule_priorities(
  33. IN const NLB_EXTENDED_CLUSTER_CONFIGURATION &Config,
  34. IN UINT NumRules,
  35. IN const WLBS_PORT_RULE rgRules[],
  36. IN OUT ULONG rgUsedPriorities[] // At least NumRules
  37. );
  38. const WLBS_PORT_RULE *
  39. find_port_rule(
  40. const WLBS_PORT_RULE *pRules,
  41. UINT NumRules,
  42. LPCWSTR szVIP,
  43. UINT StartPort
  44. );
  45. VOID
  46. remove_dedicated_ip_from_nlbcfg(
  47. NLB_EXTENDED_CLUSTER_CONFIGURATION &ClusterCfg
  48. );
  49. NLBERROR
  50. analyze_nlbcfg(
  51. IN const NLB_EXTENDED_CLUSTER_CONFIGURATION &NlbCfg,
  52. IN const NLB_EXTENDED_CLUSTER_CONFIGURATION &OtherNlbCfg,
  53. IN LPCWSTR szOtherDescription,
  54. IN BOOL fClusterProps,
  55. IN BOOL fDisablePasswordCheck,
  56. IN OUT CLocalLogger &logger
  57. );
  58. DWORD
  59. WINAPI
  60. UpdateInterfaceWorkItemRoutine(
  61. LPVOID lpParameter // thread data
  62. );
  63. DWORD
  64. WINAPI
  65. AddClusterMembersWorkItemRoutine(
  66. LPVOID lpParameter // thread data
  67. );
  68. void
  69. CHostSpec::Copy(const CHostSpec &hs)
  70. /*
  71. This is the copy operator. Need to make a copy of strings in embedded
  72. vectors.
  73. */
  74. {
  75. *this = hs;
  76. }
  77. NLBERROR
  78. CClusterSpec::Copy(const CClusterSpec &cs)
  79. /*
  80. This is the copy operator. Need to munge the m_ClusterNlbCfg field.
  81. TODO: fix this hack.
  82. TODO: if we fail we leave CClusterSpec trashed!
  83. */
  84. {
  85. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  86. m_ClusterNlbCfg.Clear();
  87. *this = cs; // non-trivial copy
  88. ZeroMemory(&m_ClusterNlbCfg, sizeof(m_ClusterNlbCfg));
  89. m_ClusterNlbCfg.Clear(); // TODO: please! cleanup NLB_EXTENDED...
  90. //
  91. // Copy over the cluster configuration.
  92. //
  93. {
  94. WBEMSTATUS wStat;
  95. wStat = m_ClusterNlbCfg.Update(&cs.m_ClusterNlbCfg);
  96. if (FAILED(wStat))
  97. {
  98. //
  99. // We've trashed m_ClusterNlbCfg -- set defaults.
  100. //
  101. CfgUtilInitializeParams(&m_ClusterNlbCfg.NlbParams);
  102. if (wStat == WBEM_E_OUT_OF_MEMORY)
  103. {
  104. nerr = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  105. }
  106. else
  107. {
  108. //
  109. // We assume that it's because the cluster spec is invalid.
  110. //
  111. nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
  112. }
  113. }
  114. else
  115. {
  116. nerr = NLBERR_OK;
  117. }
  118. }
  119. return nerr;
  120. }
  121. void
  122. CInterfaceSpec::Copy(const CInterfaceSpec &is)
  123. /*
  124. This is the copy operator. Need to munge the m_NlbCfg field.
  125. TODO: fix this hack.
  126. TODO: add return value (m_NlbCfg.Update now returns an error).
  127. */
  128. {
  129. *this = is;
  130. ZeroMemory(&m_NlbCfg, sizeof(m_NlbCfg));
  131. m_NlbCfg.Update(&is.m_NlbCfg);
  132. }
  133. NLBERROR
  134. CNlbEngine::Initialize(
  135. IN IUICallbacks & ui,
  136. BOOL fDemo,
  137. BOOL fNoPing
  138. )
  139. {
  140. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  141. TRACE_INFO(L"-> %!FUNC! (bDemo=%lu)", fDemo);
  142. //
  143. // Enable the "SeLoadDriverPrivilege" privilege in the process access token.
  144. // This is needed in the case when the server is local (ie. same machine).
  145. // Do NOT check for the return value since this function will fail when called
  146. // as a non-admin. It is not only ok but also necessary to ignore the failure of
  147. // this function because:
  148. // 1. We already check in the wmi provider that the caller is an administrator on
  149. // the server and if the privilege is enabled. This is why it is ok to ignore
  150. // failures in this function.
  151. // 2. Non-admins can run nlb manager. They only need to be admins on the server.
  152. // This is why it is necessary to ignore failures in this function.
  153. //
  154. CfgUtils_Enable_Load_Unload_Driver_Privilege();
  155. WBEMSTATUS wStat = CfgUtilInitialize(FALSE, fNoPing);
  156. if (!FAILED(wStat))
  157. {
  158. mfn_Lock();
  159. //
  160. // Save away the callback object.
  161. //
  162. m_pCallbacks = &ui;
  163. mfn_Unlock();
  164. if (fDemo)
  165. {
  166. TRACE_CRIT("%!FUNC! RUNNING ENGINE IN DEMO MODE");
  167. NlbHostFake();
  168. }
  169. nerr = NLBERR_OK;
  170. }
  171. TRACE_INFO(L"<- %!FUNC!");
  172. return nerr;
  173. }
  174. void
  175. CNlbEngine::Deinitialize(void)
  176. // TODO: cleanup
  177. {
  178. TRACE_INFO(L"-> %!FUNC!");
  179. ASSERT(m_fPrepareToDeinitialize);
  180. // DummyAction(L"Engine::Deinitialize");
  181. TRACE_INFO(L"<- %!FUNC!");
  182. return;
  183. }
  184. NLBERROR
  185. CNlbEngine::ConnectToHost(
  186. IN PWMI_CONNECTION_INFO pConnInfo,
  187. IN BOOL fOverwriteConnectionInfo,
  188. OUT ENGINEHANDLE &ehHost,
  189. OUT _bstr_t &bstrError
  190. )
  191. /*
  192. Connect the the host specfieid in pConnInfo (includes username and password)
  193. If (fOverwriteConnectionInfo) is true, then it will overwrite
  194. connection-info (connection string, connection IP, credentials)
  195. that pre-exists for this host with the stuff in pConnInfo.
  196. */
  197. {
  198. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  199. LPWSTR szWmiMachineName = NULL;
  200. LPWSTR szWmiMachineGuid = NULL;
  201. WBEMSTATUS wStatus;
  202. ULONG uIpAddress;
  203. BOOL fNlbMgrProviderInstalled = FALSE;
  204. TRACE_INFO(L"-> %!FUNC!(%ws)", pConnInfo->szMachine);
  205. ehHost = NULL;
  206. wStatus = NlbHostPing(pConnInfo->szMachine, 2000, &uIpAddress);
  207. if (FAILED(wStatus))
  208. {
  209. nerr = NLBERR_PING_TIMEOUT; // todo more specific error.
  210. bstrError = GETRESOURCEIDSTRING(IDS_PING_FAILED);
  211. goto end;
  212. }
  213. wStatus = NlbHostGetMachineIdentification(
  214. pConnInfo,
  215. &szWmiMachineName,
  216. &szWmiMachineGuid,
  217. &fNlbMgrProviderInstalled
  218. );
  219. if (FAILED(wStatus))
  220. {
  221. GetErrorCodeText(wStatus, bstrError);
  222. if (wStatus == E_ACCESSDENIED)
  223. {
  224. nerr = NLBERR_ACCESS_DENIED;
  225. }
  226. else
  227. {
  228. // TODO: map proper errors.
  229. nerr = NLBERR_NOT_FOUND;
  230. }
  231. TRACE_CRIT(L"Connecting to %ws returns error %ws",
  232. pConnInfo->szMachine, (LPCWSTR) bstrError);
  233. szWmiMachineName = NULL;
  234. szWmiMachineGuid = NULL;
  235. goto end;
  236. }
  237. //
  238. // We use the MachineName (TODO: replace by MachineGuid) as the
  239. // primary key of Hosts.
  240. //
  241. {
  242. CHostSpec* pHost = NULL;
  243. BOOL fIsNew = FALSE;
  244. ehHost = NULL;
  245. mfn_Lock();
  246. nerr = mfn_LookupHostByNameLk(
  247. szWmiMachineName,
  248. TRUE, // create if needed
  249. REF ehHost,
  250. REF pHost,
  251. REF fIsNew
  252. );
  253. if (nerr != NLBERR_OK)
  254. {
  255. mfn_Unlock();
  256. goto end;
  257. }
  258. if (fIsNew)
  259. {
  260. pHost->m_fReal = FALSE; // set to true once the nics are populated.
  261. pHost->m_MachineGuid = _bstr_t(szWmiMachineGuid);
  262. pHost->m_ConnectionString = _bstr_t(pConnInfo->szMachine);
  263. pHost->m_ConnectionIpAddress = uIpAddress;
  264. pHost->m_UserName = _bstr_t(pConnInfo->szUserName);
  265. pHost->m_Password = _bstr_t(pConnInfo->szPassword);
  266. }
  267. mfn_Unlock();
  268. nerr = mfn_RefreshHost(
  269. pConnInfo,
  270. ehHost,
  271. fOverwriteConnectionInfo
  272. );
  273. }
  274. end:
  275. delete szWmiMachineName;
  276. delete szWmiMachineGuid;
  277. return nerr;
  278. }
  279. void
  280. CNlbEngine::DeleteCluster(
  281. IN ENGINEHANDLE ehCluster,
  282. IN BOOL fRemoveInterfaces)
  283. {
  284. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  285. vector<ENGINEHANDLE> RemovedInterfaces;
  286. TRACE_INFO(L"-> %!FUNC!(ehC=0x%lx)",ehCluster);
  287. mfn_Lock();
  288. do // while false
  289. {
  290. CEngineCluster *pECluster = m_mapIdToEngineCluster[ehCluster];
  291. CClusterSpec *pCSpec = NULL;
  292. BOOL fEmptyCluster = FALSE;
  293. if (pECluster == NULL)
  294. {
  295. // Invalid ehCluster
  296. TRACE_CRIT("%!FUNC! -- invalid ehCluster 0x%lx", ehCluster);
  297. break;
  298. }
  299. pCSpec = &pECluster->m_cSpec;
  300. fEmptyCluster = (pCSpec->m_ehInterfaceIdList.size()==0);
  301. //
  302. // fail if operations are pending on this cluster. We determine
  303. // this indirectly by checking if we're allowed to start a
  304. // cluster-wide operation, which will only succeed if
  305. // there no ongoing operations on the cluster OR its interfaces.
  306. //
  307. BOOL fCanStart = FALSE;
  308. nerr = mfn_ClusterOrInterfaceOperationsPendingLk(
  309. pECluster,
  310. REF fCanStart
  311. );
  312. if (NLBFAILED(nerr) || !fCanStart)
  313. {
  314. TRACE_CRIT("%!FUNC! Not deleting cluster eh0x%lx because of pending activity.",
  315. ehCluster);
  316. nerr = NLBERR_OTHER_UPDATE_ONGOING;
  317. break;
  318. }
  319. if (!fEmptyCluster)
  320. {
  321. if (!fRemoveInterfaces)
  322. {
  323. TRACE_CRIT("%!FUNC! Not deleting cluster eh0x%lx because it's not empty",
  324. ehCluster);
  325. break;
  326. }
  327. RemovedInterfaces = pCSpec->m_ehInterfaceIdList; // vector copy
  328. //
  329. // We unlink all the interfaces from this cluster.
  330. //
  331. while(!pCSpec->m_ehInterfaceIdList.empty())
  332. {
  333. vector <ENGINEHANDLE>::iterator iItem
  334. = pCSpec->m_ehInterfaceIdList.begin();
  335. ENGINEHANDLE ehIF = *iItem;
  336. CInterfaceSpec *pISpec = NULL;
  337. //
  338. // Unlink the interface from the cluster.
  339. // (this is with the lock held)
  340. //
  341. pISpec = m_mapIdToInterfaceSpec[ehIF]; // map
  342. if (pISpec != NULL)
  343. {
  344. if (pISpec->m_ehCluster == ehCluster)
  345. {
  346. pISpec->m_ehCluster = NULL;
  347. //
  348. // Delete the host and its interfaces if
  349. // none of them are managed by nlbmanager (i.e., show
  350. // up as members of a cluster managed by nlbmgr).
  351. //
  352. mfn_DeleteHostIfNotManagedLk(pISpec->m_ehHostId);
  353. }
  354. else
  355. {
  356. TRACE_CRIT(L"ehC(0x%x) points to ehI(0x%x), but ehI points to different cluster ehC(0x%x)",
  357. ehCluster, ehIF, pISpec->m_ehCluster);
  358. ASSERT(!"Cluser/interface handle corruption!");
  359. }
  360. }
  361. pCSpec->m_ehInterfaceIdList.erase(iItem);
  362. }
  363. }
  364. m_mapIdToEngineCluster.erase(ehCluster);
  365. delete pECluster;
  366. pECluster = NULL;
  367. nerr = NLBERR_OK;
  368. } while (FALSE);
  369. mfn_Unlock();
  370. if (nerr == NLBERR_OK)
  371. {
  372. //
  373. // Notify the UI
  374. //
  375. for( int i = 0; i < RemovedInterfaces.size(); ++i )
  376. {
  377. ENGINEHANDLE ehIId = RemovedInterfaces[i];
  378. m_pCallbacks->HandleEngineEvent(
  379. IUICallbacks::OBJ_INTERFACE,
  380. ehCluster,
  381. ehIId,
  382. IUICallbacks::EVT_INTERFACE_REMOVED_FROM_CLUSTER
  383. );
  384. }
  385. m_pCallbacks->HandleEngineEvent(
  386. IUICallbacks::OBJ_CLUSTER,
  387. ehCluster,
  388. ehCluster,
  389. IUICallbacks::EVT_REMOVED
  390. );
  391. }
  392. TRACE_INFO(L"<- %!FUNC!");
  393. return;
  394. }
  395. NLBERROR
  396. CNlbEngine::AutoExpandCluster(
  397. IN ENGINEHANDLE ehClusterId
  398. )
  399. {
  400. TRACE_INFO(L"-> %!FUNC!");
  401. TRACE_INFO(L"<- %!FUNC!");
  402. return NLBERR_OK;
  403. }
  404. NLBERROR
  405. CNlbEngine::AddInterfaceToCluster(
  406. IN ENGINEHANDLE ehClusterId,
  407. IN ENGINEHANDLE ehInterfaceId
  408. )
  409. {
  410. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  411. ENGINEHANDLE ehIfId = ehInterfaceId;
  412. TRACE_INFO(L"-> %!FUNC!");
  413. mfn_Lock();
  414. CInterfaceSpec *pISpec = NULL;
  415. CClusterSpec *pCSpec = NULL;
  416. do // while false
  417. {
  418. CEngineCluster *pECluster = NULL;
  419. pECluster = m_mapIdToEngineCluster[ehClusterId]; // map
  420. if (pECluster == NULL)
  421. {
  422. nerr = NLBERR_NOT_FOUND;
  423. TRACE_CRIT("%!FUNC! -- could not find cluster associated with id 0x%lx",
  424. (UINT) ehClusterId
  425. );
  426. break;
  427. }
  428. pCSpec = &pECluster->m_cSpec;
  429. pISpec = m_mapIdToInterfaceSpec[ehInterfaceId]; // map
  430. if (pISpec == NULL)
  431. {
  432. nerr = NLBERR_NOT_FOUND;
  433. TRACE_CRIT("%!FUNC! -- could not find interface associated with id 0x%lx",
  434. (UINT) ehInterfaceId
  435. );
  436. break;
  437. }
  438. //
  439. // The interface is valid. Now push in the interface if it is not
  440. // already a part of the this cluster.
  441. //
  442. if (pISpec->m_ehCluster != NULL)
  443. {
  444. if (pISpec->m_ehCluster != ehClusterId)
  445. {
  446. //
  447. // We don't allow the same interface to be part of
  448. // two clusters!
  449. //
  450. nerr = NLBERR_INTERNAL_ERROR;
  451. TRACE_CRIT("%!FUNC! -- Interface eh 0x%lx is a member of an other cluster eh0x%lx.", ehIfId, pISpec->m_ehCluster);
  452. break;
  453. }
  454. }
  455. //
  456. // Note: find is a pre-defined template function.
  457. //
  458. if(find(
  459. pCSpec->m_ehInterfaceIdList.begin(),
  460. pCSpec->m_ehInterfaceIdList.end(),
  461. ehIfId
  462. ) != pCSpec->m_ehInterfaceIdList.end())
  463. {
  464. // item already exists.
  465. // for now we'll ignore this.
  466. if (pISpec->m_ehCluster != ehClusterId)
  467. {
  468. TRACE_CRIT("%!FUNC! -- ERROR Interface eh 0x%lx ehCluster doesn't match!", ehIfId);
  469. nerr = NLBERR_INTERNAL_ERROR;
  470. break;
  471. }
  472. }
  473. else
  474. {
  475. pISpec->m_ehCluster = ehClusterId;
  476. pCSpec->m_ehInterfaceIdList.push_back(ehIfId);
  477. }
  478. nerr = NLBERR_OK;
  479. } while (FALSE);
  480. mfn_Unlock();
  481. if (nerr == NLBERR_OK)
  482. {
  483. //
  484. // Inform the UI of the addition of a new interface under the
  485. // specified cluster.
  486. //
  487. m_pCallbacks->HandleEngineEvent(
  488. IUICallbacks::OBJ_INTERFACE,
  489. ehClusterId,
  490. ehInterfaceId,
  491. IUICallbacks::EVT_INTERFACE_ADDED_TO_CLUSTER
  492. );
  493. }
  494. TRACE_INFO(L"<- %!FUNC! returns 0x%lx", nerr);
  495. return nerr;
  496. }
  497. NLBERROR
  498. CNlbEngine::RemoveInterfaceFromCluster(
  499. IN ENGINEHANDLE ehClusterId,
  500. IN ENGINEHANDLE ehIfId
  501. )
  502. {
  503. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  504. TRACE_INFO(L"-> %!FUNC!");
  505. BOOL fEmptyCluster = FALSE; // TRUE IFF no more interfaces in cluster.
  506. mfn_Lock();
  507. CInterfaceSpec *pISpec = NULL;
  508. CClusterSpec *pCSpec = NULL;
  509. do // while false
  510. {
  511. CEngineCluster *pECluster = m_mapIdToEngineCluster[ehClusterId]; // map
  512. if (pECluster == NULL)
  513. {
  514. nerr = NLBERR_NOT_FOUND;
  515. TRACE_CRIT("%!FUNC! -- could not find cluster associated with id 0x%lx",
  516. (UINT) ehClusterId
  517. );
  518. break;
  519. }
  520. pCSpec = &pECluster->m_cSpec;
  521. pISpec = m_mapIdToInterfaceSpec[ehIfId]; // map
  522. if (pISpec == NULL)
  523. {
  524. nerr = NLBERR_NOT_FOUND;
  525. TRACE_CRIT("%!FUNC! -- could not find interface associated with id 0x%lx",
  526. (UINT) ehIfId
  527. );
  528. break;
  529. }
  530. vector <ENGINEHANDLE>::iterator iFoundItem;
  531. //
  532. // The interface is valid. No push in the interface if it is not
  533. // already a part of the this cluster.
  534. //
  535. //
  536. // Note: find is a pre-defined template function.
  537. //
  538. iFoundItem = find(
  539. pCSpec->m_ehInterfaceIdList.begin(),
  540. pCSpec->m_ehInterfaceIdList.end(),
  541. ehIfId
  542. );
  543. if (iFoundItem != pCSpec->m_ehInterfaceIdList.end())
  544. {
  545. // item exists, remove it.
  546. pCSpec->m_ehInterfaceIdList.erase(iFoundItem);
  547. if (pISpec->m_ehCluster != ehClusterId)
  548. {
  549. // shouldn't get here!
  550. ASSERT(FALSE);
  551. TRACE_CRIT("%!FUNC!: ERROR pISpec->m_ehCluster(0x%lx) != ehCluster(0x%lx)", pISpec->m_ehCluster, ehClusterId);
  552. }
  553. else
  554. {
  555. fEmptyCluster = (pCSpec->m_ehInterfaceIdList.size()==0);
  556. pISpec->m_ehCluster = NULL;
  557. if (pCSpec->m_ehDefaultInterface == ehIfId)
  558. {
  559. //
  560. // We're removing the interface whose properties are
  561. // the basis of the cluser-wide view.
  562. //
  563. pCSpec->m_ehDefaultInterface = NULL;
  564. }
  565. nerr = NLBERR_OK;
  566. }
  567. }
  568. else
  569. {
  570. // item doesn't exist.
  571. }
  572. } while (FALSE);
  573. mfn_Unlock();
  574. if (nerr == NLBERR_OK)
  575. {
  576. //
  577. // Inform the UI of the removal of an interface under the
  578. // specified cluster.
  579. //
  580. m_pCallbacks->HandleEngineEvent(
  581. IUICallbacks::OBJ_INTERFACE,
  582. ehClusterId,
  583. ehIfId,
  584. IUICallbacks::EVT_INTERFACE_REMOVED_FROM_CLUSTER
  585. );
  586. if (fEmptyCluster)
  587. {
  588. //
  589. // The cluster is empty -- delete it.
  590. //
  591. this->DeleteCluster(ehClusterId, FALSE); // FALSE == don't remove IF.
  592. }
  593. }
  594. TRACE_INFO(L"<- %!FUNC!");
  595. return nerr;
  596. }
  597. NLBERROR
  598. CNlbEngine::RefreshAllHosts(
  599. void
  600. )
  601. {
  602. TRACE_INFO(L"-> %!FUNC!");
  603. /*
  604. For each host in host map
  605. Get Adapter List
  606. - Delete all Interfaces that are no longer present
  607. - Add/Update all host infos, one by one.
  608. Do all this in the background.
  609. */
  610. TRACE_INFO(L"<- %!FUNC!");
  611. return NLBERR_OK;
  612. }
  613. NLBERROR
  614. CNlbEngine::RefreshCluster(
  615. IN ENGINEHANDLE ehCluster
  616. )
  617. {
  618. TRACE_INFO(L"-> %!FUNC!");
  619. /*
  620. For each interface in cluster
  621. - Add/Update interface info, one by one.
  622. */
  623. TRACE_INFO(L"<- %!FUNC!");
  624. return NLBERR_OK;
  625. }
  626. NLBERROR
  627. CNlbEngine::mfn_RefreshInterface(
  628. IN ENGINEHANDLE ehInterface
  629. )
  630. /*
  631. Add/Update interface info, deleting interface info if it's no longer there.
  632. Take/share code from RefreshHost
  633. Get host connection string.
  634. Get szNicGuid.
  635. Ping host.
  636. GetClusterConfiguration.
  637. Update.
  638. Notify UI of status change.
  639. */
  640. {
  641. CLocalLogger logger;
  642. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  643. WBEMSTATUS wStatus = WBEM_E_CRITICAL_ERROR;
  644. ULONG uIpAddress=0;
  645. WMI_CONNECTION_INFO ConnInfo;
  646. NLB_EXTENDED_CLUSTER_CONFIGURATION NlbCfg; // class
  647. LPCWSTR szNic = NULL;
  648. _bstr_t bstrUserName;
  649. _bstr_t bstrPassword;
  650. _bstr_t bstrConnectionString;
  651. _bstr_t bstrNicGuid;
  652. _bstr_t bstrHostName;
  653. BOOL fMisconfigured = FALSE;
  654. LPCWSTR szHostName = NULL;
  655. ENGINEHANDLE ehHost;
  656. BOOL fCheckHost = FALSE;
  657. TRACE_INFO(L"-> %!FUNC! (ehIF=0x%lx)", (UINT) ehInterface);
  658. ZeroMemory(&ConnInfo, sizeof(ConnInfo));
  659. //
  660. // Get connection info from the interface's host.
  661. //
  662. {
  663. mfn_Lock();
  664. CHostSpec *pHSpec = NULL;
  665. CInterfaceSpec *pISpec = NULL;
  666. nerr = this->mfn_GetHostFromInterfaceLk(ehInterface,REF pISpec, REF pHSpec);
  667. if (nerr != NLBERR_OK)
  668. {
  669. TRACE_CRIT("%!FUNC!: ERROR couldn't get info on this if id!");
  670. mfn_Unlock();
  671. goto end;
  672. }
  673. //
  674. // We must make copies here because once we unlock
  675. // we don't know what's going to happen to pHSpec.
  676. //
  677. bstrUserName = pHSpec->m_UserName;
  678. bstrPassword = pHSpec->m_Password;
  679. bstrConnectionString = pHSpec->m_ConnectionString;
  680. bstrNicGuid = pISpec->m_Guid;
  681. bstrHostName = pHSpec->m_MachineName;
  682. ehHost = pISpec->m_ehHostId;
  683. //
  684. // If the host was previously marked unreachable, we'll
  685. // try to check again if it's there (and update it's state).
  686. //
  687. fCheckHost = pHSpec->m_fUnreachable;
  688. mfn_Unlock();
  689. }
  690. ConnInfo.szUserName = (LPCWSTR) bstrUserName;
  691. ConnInfo.szPassword = (LPCWSTR) bstrPassword;
  692. ConnInfo.szMachine = (LPCWSTR) bstrConnectionString;
  693. if (fCheckHost)
  694. {
  695. nerr = mfn_CheckHost(&ConnInfo, ehHost);
  696. if (NLBFAILED(nerr))
  697. {
  698. goto end;
  699. }
  700. }
  701. szNic = (LPCWSTR) bstrNicGuid;
  702. szHostName = (LPCWSTR) bstrHostName;
  703. wStatus = NlbHostPing(ConnInfo.szMachine, 2000, &uIpAddress);
  704. if (FAILED(wStatus))
  705. {
  706. m_pCallbacks->Log(
  707. IUICallbacks::LOG_ERROR,
  708. NULL, // szCluster
  709. szHostName,
  710. IDS_LOG_PING_FAILED,
  711. ConnInfo.szMachine
  712. );
  713. //
  714. // TODO update host
  715. //
  716. fMisconfigured = TRUE;
  717. logger.Log(IDS_LOG_COULD_NOT_PING_HOST);
  718. }
  719. else
  720. {
  721. wStatus = NlbHostGetConfiguration(
  722. &ConnInfo,
  723. szNic,
  724. &NlbCfg
  725. );
  726. if (FAILED(wStatus))
  727. {
  728. TRACE_CRIT(L"%!FUNC! Error reading extended configuration for %ws\n", szNic);
  729. m_pCallbacks->Log(
  730. IUICallbacks::LOG_ERROR,
  731. NULL, // szCluster
  732. szHostName,
  733. IDS_LOG_COULD_NOT_GET_IF_CONFIG,
  734. szNic,
  735. (UINT) wStatus
  736. );
  737. fMisconfigured = TRUE;
  738. logger.Log(IDS_LOG_COULD_NOT_READ_IF_CONFIG);
  739. }
  740. }
  741. //
  742. // Now that we've read the latest cfg info onto NlbCfg, let's update it
  743. // (or mark the IF as misconfigured if there's been an error.)
  744. //
  745. {
  746. CInterfaceSpec *pISpec = NULL;
  747. mfn_Lock();
  748. pISpec = m_mapIdToInterfaceSpec[ehInterface]; // map
  749. if (pISpec != NULL)
  750. {
  751. pISpec->m_fReal = TRUE;
  752. if (!fMisconfigured)
  753. {
  754. wStatus = pISpec->m_NlbCfg.Update(&NlbCfg);
  755. if (FAILED(wStatus))
  756. {
  757. TRACE_CRIT("%!FUNC! error updating nlbcfg for eh%lx", ehInterface);
  758. fMisconfigured = TRUE;
  759. logger.Log(IDS_LOG_FAILED_UPDATE);
  760. }
  761. //
  762. // Update the host's connection IP address
  763. //
  764. if (uIpAddress != 0)
  765. {
  766. CHostSpec *pHSpec = NULL;
  767. CInterfaceSpec *pTmpISpec = NULL;
  768. nerr = this->mfn_GetHostFromInterfaceLk(
  769. ehInterface,
  770. REF pTmpISpec,
  771. REF pHSpec
  772. );
  773. if (nerr == NLBERR_OK)
  774. {
  775. pHSpec->m_ConnectionIpAddress = uIpAddress;
  776. }
  777. }
  778. }
  779. //
  780. // Set/clear the misconfiguration state.
  781. //
  782. {
  783. LPCWSTR szDetails = NULL;
  784. UINT Size = 0;
  785. if (fMisconfigured)
  786. {
  787. logger.ExtractLog(szDetails, Size);
  788. }
  789. mfn_SetInterfaceMisconfigStateLk(pISpec, fMisconfigured, szDetails);
  790. }
  791. }
  792. mfn_Unlock();
  793. }
  794. if (fMisconfigured)
  795. {
  796. //
  797. // We couldn't read the latest settings for some reason --
  798. // check connectivity to the host and update the host status if
  799. // necessary.
  800. //
  801. nerr = mfn_CheckHost(&ConnInfo, ehHost);
  802. if (NLBOK(nerr))
  803. {
  804. //
  805. // We still want to fail this because we couldn't get
  806. // the updated configuration.
  807. //
  808. nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
  809. }
  810. }
  811. else
  812. {
  813. nerr = NLBERR_OK;
  814. }
  815. end:
  816. TRACE_INFO(L"<- %!FUNC!");
  817. return nerr;
  818. }
  819. NLBERROR
  820. CNlbEngine::RefreshInterface(
  821. IN ENGINEHANDLE ehInterface,
  822. IN BOOL fNewOperation,
  823. IN BOOL fClusterWide
  824. )
  825. /*
  826. Add/Update interface info, deleting interface info if it's no longer there.
  827. Take/share code from RefreshHost
  828. Get host connection string.
  829. Get szNicGuid.
  830. Ping host.
  831. GetClusterConfiguration.
  832. Update.
  833. Notify UI of status change.
  834. */
  835. {
  836. CLocalLogger logger;
  837. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  838. BOOL fMisconfigured = FALSE;
  839. BOOL fRemoveInterfaceFromCluster = FALSE;
  840. BOOL fStopOperationOnExit = FALSE;
  841. ENGINEHANDLE ehCluster = NULL;
  842. TRACE_INFO(L"-> %!FUNC! (ehIF=0x%lx)", (UINT) ehInterface);
  843. if (fNewOperation)
  844. {
  845. //
  846. // This function is to be run in the context of a NEW operation.
  847. // Verify that we can do a refresh at this time, and if so, start an
  848. // operation to track the refresh.
  849. //
  850. CInterfaceSpec *pISpec = NULL;
  851. mfn_Lock();
  852. pISpec = m_mapIdToInterfaceSpec[ehInterface]; // map
  853. if (pISpec == NULL)
  854. {
  855. TRACE_CRIT("%!FUNC!: ERROR couldn't get info on this if id!");
  856. goto end_unlock;
  857. }
  858. if (!fClusterWide)
  859. {
  860. ehCluster = pISpec->m_ehCluster;
  861. if (ehCluster != NULL)
  862. {
  863. //
  864. // Make sure that there's no pending cluster-wide operation
  865. // going on for the cluster that this IF is a part of.
  866. //
  867. CEngineCluster *pECluster = NULL;
  868. pECluster = m_mapIdToEngineCluster[ehCluster]; // map
  869. if (pECluster != NULL)
  870. {
  871. if (pECluster->m_cSpec.m_ehPendingOperation != NULL)
  872. {
  873. nerr = NLBERR_BUSY;
  874. TRACE_CRIT("%!FUNC!: ehIF 0x%lx: Can't proceed because of existing op 0x%lx",
  875. ehInterface,
  876. pECluster->m_cSpec.m_ehPendingOperation
  877. );
  878. goto end_unlock;
  879. }
  880. }
  881. }
  882. }
  883. //
  884. // Now try to start an operation...
  885. //
  886. {
  887. ENGINEHANDLE ExistingOp = NULL;
  888. nerr = mfn_StartInterfaceOperationLk(
  889. ehInterface,
  890. NULL, // pvCtxt
  891. GETRESOURCEIDSTRING(IDS_LOG_REFRESH_INTERFACE),
  892. &ExistingOp
  893. );
  894. if (NLBFAILED(nerr))
  895. {
  896. goto end_unlock;
  897. }
  898. //
  899. // We did start the operation -- so we keep track of this, so that
  900. // we stop the operation on exit.
  901. //
  902. fStopOperationOnExit = TRUE;
  903. }
  904. mfn_Unlock();
  905. }
  906. //
  907. // Here's where we actually refresh the interface.
  908. //
  909. nerr = mfn_RefreshInterface(ehInterface);
  910. if (!NLBOK(nerr))
  911. {
  912. mfn_Lock();
  913. goto end_unlock;
  914. }
  915. //
  916. // Now let's analyze the result ...
  917. //
  918. {
  919. CInterfaceSpec *pISpec = NULL;
  920. mfn_Lock();
  921. pISpec = m_mapIdToInterfaceSpec[ehInterface]; // map
  922. if (pISpec != NULL)
  923. {
  924. fMisconfigured = pISpec->m_fMisconfigured;
  925. ehCluster = pISpec->m_ehCluster;
  926. if (!fMisconfigured)
  927. {
  928. if (ehCluster != NULL)
  929. {
  930. if (!pISpec->m_NlbCfg.IsNlbBound())
  931. {
  932. //
  933. // NLB is not bound on this interface --
  934. // remove this interface from the cluster.
  935. fRemoveInterfaceFromCluster = TRUE;
  936. }
  937. else
  938. {
  939. nerr = this->mfn_AnalyzeInterfaceLk(ehInterface, REF logger);
  940. if (NLBFAILED(nerr))
  941. {
  942. fMisconfigured = TRUE;
  943. }
  944. }
  945. }
  946. //
  947. // Set the new misconfiguration state.
  948. //
  949. {
  950. LPCWSTR szDetails = NULL;
  951. UINT Size = 0;
  952. if (fMisconfigured)
  953. {
  954. logger.ExtractLog(szDetails, Size);
  955. }
  956. mfn_SetInterfaceMisconfigStateLk(pISpec, fMisconfigured, szDetails);
  957. }
  958. }
  959. }
  960. mfn_Unlock();
  961. }
  962. if (fRemoveInterfaceFromCluster)
  963. {
  964. this->RemoveInterfaceFromCluster(ehCluster, ehInterface);
  965. }
  966. else
  967. {
  968. //
  969. // Report state
  970. //
  971. if (fMisconfigured)
  972. {
  973. //
  974. // Log ...
  975. //
  976. LPCWSTR szDetails = NULL;
  977. LPCWSTR szCluster = NULL;
  978. LPCWSTR szHostName = NULL;
  979. LPCWSTR szInterface = NULL;
  980. UINT Size = 0;
  981. ENGINEHANDLE ehHost;
  982. _bstr_t bstrDisplayName;
  983. _bstr_t bstrFriendlyName;
  984. _bstr_t bstrHostName;
  985. _bstr_t bstrIpAddress;
  986. nerr = this->GetInterfaceIdentification(
  987. ehInterface,
  988. REF ehHost,
  989. REF ehCluster,
  990. REF bstrFriendlyName,
  991. REF bstrDisplayName,
  992. REF bstrHostName
  993. );
  994. if (NLBOK(nerr))
  995. {
  996. _bstr_t bstrDomainName;
  997. _bstr_t bstrClusterDisplayName;
  998. nerr = this->GetClusterIdentification(
  999. ehCluster,
  1000. REF bstrIpAddress,
  1001. REF bstrDomainName,
  1002. REF bstrClusterDisplayName
  1003. );
  1004. if (NLBOK(nerr))
  1005. {
  1006. szCluster = bstrIpAddress;
  1007. }
  1008. szHostName = bstrHostName;
  1009. szInterface = bstrFriendlyName;
  1010. }
  1011. logger.ExtractLog(szDetails, Size);
  1012. IUICallbacks::LogEntryHeader Header;
  1013. Header.szDetails = szDetails;
  1014. Header.type = IUICallbacks::LOG_ERROR;
  1015. Header.szCluster = szCluster;
  1016. Header.szHost = szHostName;
  1017. Header.szInterface = szInterface;
  1018. m_pCallbacks->LogEx(
  1019. &Header,
  1020. IDS_LOG_INTERFACE_MISCONFIGURATION
  1021. );
  1022. }
  1023. else
  1024. {
  1025. ControlClusterOnInterface( ehInterface, WLBS_QUERY, NULL, NULL, 0, FALSE);
  1026. }
  1027. }
  1028. nerr = NLBERR_OK;
  1029. mfn_Lock();
  1030. //
  1031. // Fall through ...
  1032. //
  1033. end_unlock:
  1034. if (fStopOperationOnExit)
  1035. {
  1036. mfn_StopInterfaceOperationLk(ehInterface);
  1037. }
  1038. mfn_Unlock();
  1039. if (fStopOperationOnExit && !fRemoveInterfaceFromCluster)
  1040. {
  1041. //
  1042. // Notify the UI of this update...
  1043. // (but only if we've not already removed it from
  1044. // the cluster!)
  1045. //
  1046. m_pCallbacks->HandleEngineEvent(
  1047. IUICallbacks::OBJ_INTERFACE,
  1048. ehCluster,
  1049. ehInterface,
  1050. IUICallbacks::EVT_STATUS_CHANGE
  1051. );
  1052. }
  1053. TRACE_INFO(L"<- %!FUNC!");
  1054. return nerr;
  1055. }
  1056. NLBERROR
  1057. CNlbEngine::AnalyzeCluster(
  1058. ENGINEHANDLE ehClusterId
  1059. )
  1060. {
  1061. TRACE_INFO(L"-> %!FUNC!");
  1062. /*
  1063. TODO: consider doing this with a specific host in mind
  1064. For each IF I1
  1065. AnalyzeHost(host-of(I1))
  1066. For each other IF I2
  1067. AnalyzeTwoHosts(I1, I2)
  1068. AnalyzeTwoHosts(I1, I2):
  1069. - check that cluster params match
  1070. - check that port rules are compatible
  1071. - check that host properties do not collide.
  1072. - check dedicated IP subnets match.
  1073. AnalyzeHost(H1)
  1074. For each IF I1
  1075. AnalyzeSingleIf(I1) (including checking dedicated ips)
  1076. */
  1077. TRACE_INFO(L"<- %!FUNC!");
  1078. return NLBERR_OK;
  1079. }
  1080. NLBERROR
  1081. CNlbEngine::mfn_AnalyzeInterfaceLk(
  1082. ENGINEHANDLE ehInterface,
  1083. CLocalLogger &logger
  1084. )
  1085. /*
  1086. -- check interface props against cluster properties
  1087. -- if cluster props match out,
  1088. for each host id NOT marked fMisconfigured,
  1089. check host properties.
  1090. -- Does NOT mark fMisconfigured if error detected -- caller is expected
  1091. to do so.
  1092. -- Spews stuff to log regarding any misconfigurations.
  1093. */
  1094. {
  1095. NLBERROR nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
  1096. const CEngineCluster *pECluster = NULL;
  1097. const CInterfaceSpec *pISpec = NULL;
  1098. BOOL fIgnoreRctPassword = FALSE;
  1099. TRACE_INFO(L"-> %!FUNC!");
  1100. pISpec = m_mapIdToInterfaceSpec[ehInterface]; // map
  1101. if (pISpec == NULL)
  1102. {
  1103. nerr = NLBERR_INTERFACE_NOT_FOUND;
  1104. goto end;
  1105. }
  1106. //
  1107. // If interface is NOT part of a cluster, we're done.
  1108. //
  1109. if (pISpec->m_ehCluster == NULL)
  1110. {
  1111. TRACE_CRIT("ehIF 0x%lx m_ehCluster member is NULL!", ehInterface);
  1112. goto end;
  1113. }
  1114. //
  1115. // Check the interface against itself ...
  1116. //
  1117. {
  1118. nerr = AnalyzeNlbConfiguration(REF pISpec->m_NlbCfg, logger);
  1119. if (NLBFAILED(nerr))
  1120. {
  1121. goto end;
  1122. }
  1123. }
  1124. //
  1125. // Get the cluster data that this interface is a part of.
  1126. //
  1127. pECluster = m_mapIdToEngineCluster[pISpec->m_ehCluster]; // map
  1128. if (pECluster == NULL)
  1129. {
  1130. TRACE_CRIT(L"ehIF 0x%lx m_ehCluster member 0x%lx is INVALID!",
  1131. ehInterface, pISpec->m_ehCluster);
  1132. nerr = NLBERR_INTERNAL_ERROR;
  1133. goto end;
  1134. }
  1135. //
  1136. // Check interface against cluster.
  1137. //
  1138. fIgnoreRctPassword = pECluster->m_cSpec.m_fNewRctPassword;
  1139. nerr = analyze_nlbcfg(
  1140. REF pISpec->m_NlbCfg,
  1141. REF pECluster->m_cSpec.m_ClusterNlbCfg,
  1142. (LPCWSTR) GETRESOURCEIDSTRING(IDS_CLUSTER),
  1143. // L"Cluster",
  1144. TRUE, // TRUE == ClusterProps
  1145. fIgnoreRctPassword, // TRUE==Disable RCT password check
  1146. REF logger
  1147. );
  1148. if (NLBFAILED(nerr))
  1149. {
  1150. //
  1151. // If analyzing against cluster props fails, we don't bother
  1152. // analyzing against other hosts...
  1153. //
  1154. TRACE_CRIT(L"analyze_nlbcfg returns error 0x%lx", nerr);
  1155. goto end;
  1156. }
  1157. //
  1158. // Now check against all hosts before us in the list of hosts in the
  1159. // cluster -- but only those that are not already marked misconfigured.
  1160. //
  1161. //
  1162. {
  1163. const vector<ENGINEHANDLE> &InterfaceList =
  1164. pECluster->m_cSpec.m_ehInterfaceIdList;
  1165. for( int i = 0; i < InterfaceList.size(); ++i )
  1166. {
  1167. ENGINEHANDLE ehIOther = InterfaceList[i];
  1168. const CInterfaceSpec *pISpecOther = NULL;
  1169. WCHAR rgOtherDescription[256];
  1170. *rgOtherDescription = 0;
  1171. if (ehIOther == ehInterface)
  1172. {
  1173. //
  1174. // We've reached the interface being analyzed -- we don't
  1175. // compare with any of the remaining interfaces.
  1176. //
  1177. break;
  1178. }
  1179. pISpecOther = m_mapIdToInterfaceSpec[ehIOther]; // map
  1180. if (pISpecOther == NULL)
  1181. {
  1182. TRACE_CRIT("Unexpected: NULL pISpec for ehInterface 0x%lx",
  1183. ehIOther);
  1184. continue;
  1185. }
  1186. //
  1187. // We don't compare of the other interface is marked misconfigured,
  1188. // or is not bound with NLB with valid nlb config data.
  1189. //
  1190. if ( pISpecOther->m_fMisconfigured
  1191. || !pISpecOther->m_NlbCfg.IsValidNlbConfig())
  1192. {
  1193. TRACE_VERB("%!FUNC!: Skipping misconfigured ISpec with ehInt 0x%lx",
  1194. ehIOther);
  1195. continue;
  1196. }
  1197. // Skip the other interface if it's properties are being updated.
  1198. //
  1199. if (pISpecOther->m_ehPendingOperation != NULL)
  1200. {
  1201. TRACE_VERB("%!FUNC!: Skipping ISpec with ehInt 0x%lx because of pending OP on it",
  1202. ehIOther);
  1203. continue;
  1204. }
  1205. //
  1206. // Create the description string of the other adapter.
  1207. //
  1208. {
  1209. WBEMSTATUS wStat;
  1210. LPWSTR szAdapter = NULL;
  1211. LPCWSTR szHostName = pISpecOther->m_bstrMachineName;
  1212. wStat = pISpecOther->m_NlbCfg.GetFriendlyName(&szAdapter);
  1213. if (FAILED(wStat))
  1214. {
  1215. szAdapter = NULL;
  1216. }
  1217. StringCbPrintf(
  1218. rgOtherDescription,
  1219. sizeof(rgOtherDescription),
  1220. L"%ws(%ws)",
  1221. (szHostName==NULL ? L"" : szHostName),
  1222. (szAdapter==NULL ? L"" : szAdapter)
  1223. );
  1224. delete szAdapter;
  1225. }
  1226. //
  1227. // Let's check this host's config with the other host's
  1228. //
  1229. NLBERROR nerrTmp;
  1230. nerrTmp = analyze_nlbcfg(
  1231. REF pISpec->m_NlbCfg,
  1232. REF pISpecOther->m_NlbCfg,
  1233. rgOtherDescription,
  1234. FALSE, // FALSE == Check host-specific props
  1235. FALSE, // FALSE == Enable remote-control password check
  1236. REF logger
  1237. );
  1238. if (NLBFAILED(nerrTmp))
  1239. {
  1240. nerr = nerrTmp; // so we don't overwrite failure with success
  1241. }
  1242. }
  1243. }
  1244. end:
  1245. TRACE_INFO(L"<- %!FUNC! returns 0x%lx", nerr);
  1246. return nerr;
  1247. }
  1248. NLBERROR
  1249. analyze_nlbcfg(
  1250. IN const NLB_EXTENDED_CLUSTER_CONFIGURATION &NlbCfg,
  1251. IN const NLB_EXTENDED_CLUSTER_CONFIGURATION &OtherNlbCfg,
  1252. IN LPCWSTR szOtherDescription, OPTIONAL
  1253. IN BOOL fClusterProps,
  1254. IN BOOL fDisablePasswordCheck,
  1255. IN OUT CLocalLogger &logger
  1256. /*
  1257. Analyze the NLB configuration NlbCfg against OtherNlbCfg.
  1258. If fClusterProps, treat OtherNlbCfg as cluster-wide props, else
  1259. treat OtherNlbCfg as the properties of a specific host.
  1260. When logging errors to logger, use szOtherDescription to refer to
  1261. OtherNlbCfg.
  1262. if szOtherDesctiption is NULL, DO NOT log.
  1263. Return value:
  1264. NLB_OK if the configurations are compatible.
  1265. NLBERR_INVALID_CLUSTER_SPECIFICATION if the NlbParams are incompatible.
  1266. NLBERR_INVALID_IP_ADDRESS_SPECIFICATION
  1267. NLBERR_SUBNET_MISMATCH
  1268. NLBERR_NLB_NOT_INSTALLED
  1269. or some other NLBERR_XXX error
  1270. */
  1271. )
  1272. {
  1273. NLBERROR nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
  1274. BOOL fMisconfigured = FALSE; // Start out assuming no misconfig.
  1275. #define LOG(_expr) if (szOtherDescription!=NULL) {_expr;}
  1276. if (szOtherDescription != NULL)
  1277. {
  1278. //
  1279. // We'll call ourselves RECURSIVELY just to determine up-front
  1280. // if any conflicts were detected.
  1281. // This is so we can put a log entry saying that conflicts were
  1282. // detected with szOtherDescription.
  1283. // Subsequent log entries do not specifiy szOtherDescription.
  1284. //
  1285. CLocalLogger null_logger;
  1286. nerr = analyze_nlbcfg( // RECURSIVE CALL
  1287. REF NlbCfg,
  1288. REF OtherNlbCfg,
  1289. NULL, // NULL == don't log.
  1290. fClusterProps,
  1291. fDisablePasswordCheck,
  1292. REF null_logger
  1293. );
  1294. if (NLBFAILED(nerr))
  1295. {
  1296. //
  1297. // There was a failure -- so we make a log entry saying so
  1298. //
  1299. logger.Log(IDS_LOG_CONFIG_CONFLICTS_WITH_OTHER, szOtherDescription);
  1300. }
  1301. else
  1302. {
  1303. // looks good...
  1304. goto end;
  1305. }
  1306. }
  1307. //
  1308. // Check cluster properties
  1309. //
  1310. {
  1311. if (NlbCfg.NlbParams.mcast_support != OtherNlbCfg.NlbParams.mcast_support)
  1312. {
  1313. LOG(logger.Log(IDS_LOG_CLUSTER_MODE_DIFFERS))
  1314. fMisconfigured = TRUE;
  1315. }
  1316. else if (NlbCfg.NlbParams.mcast_support &&
  1317. NlbCfg.NlbParams.fIGMPSupport != OtherNlbCfg.NlbParams.fIGMPSupport)
  1318. {
  1319. LOG(logger.Log(IDS_LOG_CLUSTER_MULTICAST_MODE_DIFFERS))
  1320. fMisconfigured = TRUE;
  1321. }
  1322. if (wcscmp(NlbCfg.NlbParams.cl_ip_addr, OtherNlbCfg.NlbParams.cl_ip_addr))
  1323. {
  1324. LOG(logger.Log(IDS_LOG_CIP_DIFFERS))
  1325. fMisconfigured = TRUE;
  1326. }
  1327. if (wcscmp(NlbCfg.NlbParams.cl_net_mask, OtherNlbCfg.NlbParams.cl_net_mask))
  1328. {
  1329. LOG(logger.Log(IDS_LOG_CIPMASK_DIFFERS))
  1330. fMisconfigured = TRUE;
  1331. }
  1332. if (wcscmp(NlbCfg.NlbParams.domain_name, OtherNlbCfg.NlbParams.domain_name))
  1333. {
  1334. LOG(logger.Log(IDS_LOG_DOMAIN_NAME_DIFFERS))
  1335. fMisconfigured = TRUE;
  1336. }
  1337. //
  1338. // Remote control
  1339. //
  1340. if (NlbCfg.GetRemoteControlEnabled() !=
  1341. OtherNlbCfg.GetRemoteControlEnabled())
  1342. {
  1343. LOG(logger.Log(IDS_LOG_RCT_DIFFERS))
  1344. fMisconfigured = TRUE;
  1345. }
  1346. else if (NlbCfg.GetRemoteControlEnabled() && !fDisablePasswordCheck)
  1347. {
  1348. //
  1349. // Check the password...
  1350. //
  1351. DWORD dw = CfgUtilGetHashedRemoteControlPassword(&NlbCfg.NlbParams);
  1352. DWORD dw1=CfgUtilGetHashedRemoteControlPassword(&OtherNlbCfg.NlbParams);
  1353. if (dw!=dw1)
  1354. {
  1355. LOG(logger.Log(IDS_LOG_RCT_PWD_DIFFERS, dw, dw1 ))
  1356. fMisconfigured = TRUE;
  1357. }
  1358. }
  1359. }
  1360. //
  1361. // Check port rules.
  1362. //
  1363. {
  1364. WLBS_PORT_RULE *pIRules = NULL;
  1365. WLBS_PORT_RULE *pCRules = NULL;
  1366. UINT NumIRules=0;
  1367. UINT NumCRules=0;
  1368. WBEMSTATUS wStat;
  1369. wStat = CfgUtilGetPortRules(&NlbCfg.NlbParams, &pIRules, &NumIRules);
  1370. if (FAILED(wStat))
  1371. {
  1372. LOG(logger.Log(IDS_LOG_CANT_EXTRACT_PORTRULES))
  1373. fMisconfigured = TRUE;
  1374. goto end;
  1375. }
  1376. wStat = CfgUtilGetPortRules(&OtherNlbCfg.NlbParams, &pCRules, &NumCRules);
  1377. if (FAILED(wStat))
  1378. {
  1379. LOG(logger.Log(IDS_LOG_CANT_EXTRACT_OTHER_PORT_RULES, szOtherDescription))
  1380. fMisconfigured = TRUE;
  1381. goto end;
  1382. }
  1383. if (NumIRules != NumCRules)
  1384. {
  1385. LOG(logger.Log(IDS_LOG_PORT_RULE_COUNT_DIFFERS))
  1386. // keep going.
  1387. fMisconfigured = TRUE;
  1388. }
  1389. else
  1390. {
  1391. //
  1392. // Let's assume that the order is the same, because I think it's
  1393. // returned sorted.
  1394. //
  1395. for (UINT u = 0; u< NumIRules; u++)
  1396. {
  1397. WLBS_PORT_RULE IRule = pIRules[u]; // struct copy
  1398. WLBS_PORT_RULE CRule = pCRules[u]; // struct copy
  1399. if (lstrcmpi(IRule.virtual_ip_addr, CRule.virtual_ip_addr))
  1400. {
  1401. LOG(logger.Log(IDS_LOG_PORT_RULE_CIP_DIFFERS,u+1))
  1402. fMisconfigured = TRUE;
  1403. continue;
  1404. }
  1405. if (IRule.start_port != CRule.start_port)
  1406. {
  1407. LOG(logger.Log(IDS_LOG_PORT_RULE_START_DIFFERS, u+1))
  1408. fMisconfigured = TRUE;
  1409. continue;
  1410. }
  1411. if (IRule.end_port != CRule.end_port)
  1412. {
  1413. LOG(logger.Log(IDS_LOG_PORT_RULE_END_DIFFERS, u+1))
  1414. fMisconfigured = TRUE;
  1415. }
  1416. if (IRule.protocol != CRule.protocol)
  1417. {
  1418. LOG(logger.Log(IDS_LOG_PORT_RULE_PROT_DIFFERS, u+1))
  1419. fMisconfigured = TRUE;
  1420. }
  1421. if (IRule.mode != CRule.mode)
  1422. {
  1423. LOG(logger.Log(IDS_LOG_PORT_RULE_MODE_DIFFERS, u+1))
  1424. fMisconfigured = TRUE;
  1425. }
  1426. if (IRule.mode == CVY_MULTI)
  1427. {
  1428. // Check that affinity matches -- none/single/class-C
  1429. if (IRule.mode_data.multi.affinity != CRule.mode_data.multi.affinity)
  1430. {
  1431. LOG(logger.Log(IDS_LOG_PORT_RULE_AFFINITY_DIFFERS, u+1))
  1432. fMisconfigured = TRUE;
  1433. }
  1434. }
  1435. if (!fClusterProps && IRule.mode == CVY_SINGLE)
  1436. {
  1437. if (IRule.mode_data.single.priority
  1438. == CRule.mode_data.single.priority)
  1439. {
  1440. LOG(logger.Log(IDS_LOG_PORT_RULE_PRIORITY_CONFLICT, u+1))
  1441. fMisconfigured = TRUE;
  1442. }
  1443. }
  1444. }
  1445. }
  1446. delete[] pIRules;
  1447. delete[] pCRules;
  1448. }
  1449. //
  1450. // Interface checks out against the cluster-wide parameters;
  1451. // Now check this interface's parameters against itself -- things
  1452. // like the dedicated IP address is bound on the nic itself and is the
  1453. // the first address on the NIC, etc.
  1454. //
  1455. if (!fClusterProps)
  1456. {
  1457. if (!NlbCfg.IsBlankDedicatedIp())
  1458. {
  1459. if (!wcscmp(NlbCfg.NlbParams.ded_ip_addr, OtherNlbCfg.NlbParams.ded_ip_addr))
  1460. {
  1461. //
  1462. // Same dedicated ip and it's not blank!
  1463. //
  1464. LOG(logger.Log(IDS_LOG_DIP_CONFLICT))
  1465. fMisconfigured = TRUE;
  1466. }
  1467. }
  1468. // Let's check host priority.
  1469. if (NlbCfg.NlbParams.host_priority == OtherNlbCfg.NlbParams.host_priority)
  1470. {
  1471. LOG(logger.Log(IDS_LOG_HOST_PRIORITY_CONFLICT))
  1472. fMisconfigured = TRUE;
  1473. }
  1474. }
  1475. nerr = NLBERR_OK;
  1476. end:
  1477. if (NLBOK(nerr) && fMisconfigured)
  1478. {
  1479. nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
  1480. }
  1481. return nerr;
  1482. }
  1483. NLBERROR
  1484. CNlbEngine::GetInterfaceSpec(
  1485. IN ENGINEHANDLE ehInterfaceId,
  1486. OUT CInterfaceSpec& refISpec
  1487. )
  1488. {
  1489. // TRACE_INFO(L"-> %!FUNC!");
  1490. NLBERROR err = NLBERR_OK;
  1491. mfn_Lock();
  1492. CInterfaceSpec *pISpec = m_mapIdToInterfaceSpec[ehInterfaceId]; // map
  1493. if (pISpec == NULL)
  1494. {
  1495. err = NLBERR_INTERFACE_NOT_FOUND;
  1496. }
  1497. else
  1498. {
  1499. refISpec.Copy(*pISpec);
  1500. }
  1501. mfn_Unlock();
  1502. // TRACE_INFO(L"<- %!FUNC!");
  1503. return err;
  1504. }
  1505. VOID
  1506. CNlbEngine::mfn_GetLogStrings(
  1507. IN WLBS_OPERATION_CODES Operation,
  1508. IN LPCWSTR szVip,
  1509. IN DWORD * pdwPortNum,
  1510. IN DWORD dwOperationStatus,
  1511. IN DWORD dwClusterOrPortStatus,
  1512. OUT IUICallbacks::LogEntryType & LogLevel,
  1513. OUT _bstr_t & OperationStr,
  1514. OUT _bstr_t & OperationStatusStr,
  1515. OUT _bstr_t & ClusterOrPortStatusStr)
  1516. {
  1517. if (szVip && pdwPortNum)
  1518. {
  1519. TRACE_INFO(L"-> %!FUNC! Operation : %d, Vip : %ls, Port : %u, Operation Status : %u, Port Status : %u",
  1520. Operation, szVip, *pdwPortNum, dwOperationStatus, dwClusterOrPortStatus);
  1521. }
  1522. else
  1523. {
  1524. TRACE_INFO(L"-> %!FUNC! Operation : %d, Operation Status : %u, Cluster Status : %u",
  1525. Operation, dwOperationStatus, dwClusterOrPortStatus);
  1526. }
  1527. struct STATUS_TO_DESCR_MAP
  1528. {
  1529. DWORD dwStatus;
  1530. DWORD dwResourceId;
  1531. }
  1532. AllNlbStatusToDescrMap[] =
  1533. {
  1534. // Cluster States
  1535. {WLBS_CONVERGING, IDS_STATE_CONVERGING},// Converging
  1536. {WLBS_CONVERGED, IDS_STATE_CONVERGED}, // Converged as non-default, we do not specify "default"/"non-default" in the description 'cos there is a
  1537. {WLBS_DEFAULT, IDS_STATE_CONVERGED}, // Converged as default, transient case where for a short duration, the default node shows up a non-default
  1538. {WLBS_DRAINING, IDS_STATE_CONVERGED_DRAINING}, // Converged, but draining
  1539. // Port States
  1540. {NLB_PORT_RULE_NOT_FOUND, IDS_PORT_RULE_NOT_FOUND},
  1541. {NLB_PORT_RULE_ENABLED, IDS_PORT_RULE_ENABLED},
  1542. {NLB_PORT_RULE_DISABLED, IDS_PORT_RULE_DISABLED},
  1543. {NLB_PORT_RULE_DRAINING, IDS_PORT_RULE_DRAINING},
  1544. // Operation Specific errors
  1545. {WLBS_SUSPENDED, IDS_HOST_SUSPENDED}, // start/stop/drain_stop/enable/disable/drain/query-failure-host is suspended
  1546. {WLBS_STOPPED, IDS_HOST_STOPPED}, // enable/disable/drain/query-failure-host is already stopped
  1547. {WLBS_BAD_PARAMS, IDS_BAD_PARAMS}, // start-failure-host is stopped due to bad parameters
  1548. {WLBS_NOT_FOUND, IDS_NOT_FOUND}, // enable/disable/drain-failure-not found
  1549. {WLBS_DISCONNECTED, IDS_DISCONNECTED}, // query-failure-media disconnected
  1550. // Generic errors
  1551. {WLBS_BAD_PASSW, IDS_BAD_PASSWORD}, // *-failure-Bad password
  1552. {WLBS_FAILURE, IDS_FAILURE}, // *-failure-critical error
  1553. {WLBS_REFUSED, IDS_REFUSED}, // *-failure-request refused by BDA
  1554. {WLBS_IO_ERROR, IDS_IO_ERROR}, // *-failure-error trying to connect to nlb driver
  1555. // Success values
  1556. {WLBS_OK, IDS_EMPTY_STRING}, // Success
  1557. {WLBS_ALREADY, IDS_ALREADY}, // host is already in this state
  1558. {WLBS_DRAIN_STOP, IDS_DRAIN_STOP}, // was draining
  1559. };
  1560. struct OPERATION_TO_DESCR_MAP
  1561. {
  1562. WLBS_OPERATION_CODES Operation;
  1563. DWORD dwResourceId;
  1564. bool bClusterOperation;
  1565. }
  1566. OperationToDescrMap[] =
  1567. {
  1568. {WLBS_START, IDS_COMMAND_START, true},
  1569. {WLBS_STOP, IDS_COMMAND_STOP, true},
  1570. {WLBS_DRAIN, IDS_COMMAND_DRAINSTOP, true},
  1571. {WLBS_SUSPEND, IDS_COMMAND_SUSPEND, true},
  1572. {WLBS_RESUME, IDS_COMMAND_RESUME, true},
  1573. {WLBS_QUERY, IDS_COMMAND_QUERY, true},
  1574. {WLBS_PORT_ENABLE, IDS_COMMAND_ENABLE, false},
  1575. {WLBS_PORT_DISABLE, IDS_COMMAND_DISABLE, false},
  1576. {WLBS_PORT_DRAIN, IDS_COMMAND_DRAIN, false},
  1577. {WLBS_QUERY_PORT_STATE, IDS_COMMAND_QUERY_PORT, false}
  1578. };
  1579. bool bClusterOperation;
  1580. DWORD dwResourceId, dwIdx, dwClusterOrPortResourceId, dwMaxOperations;
  1581. WCHAR wcTempStr[1024];
  1582. // Initialize log level to Informational
  1583. LogLevel = IUICallbacks::LOG_INFORMATIONAL;
  1584. // Initialize all return strings to empty string
  1585. OperationStr = GETRESOURCEIDSTRING(IDS_EMPTY_STRING);
  1586. OperationStatusStr = OperationStr;
  1587. ClusterOrPortStatusStr = OperationStr;
  1588. // Form the "Operation" string
  1589. dwMaxOperations = sizeof(OperationToDescrMap)/sizeof(OperationToDescrMap[0]);
  1590. for (dwIdx = 0; dwIdx < dwMaxOperations; dwIdx++)
  1591. {
  1592. if (OperationToDescrMap[dwIdx].Operation == Operation)
  1593. {
  1594. dwResourceId = OperationToDescrMap[dwIdx].dwResourceId;
  1595. bClusterOperation = OperationToDescrMap[dwIdx].bClusterOperation;
  1596. break;
  1597. }
  1598. }
  1599. if (dwIdx == dwMaxOperations)
  1600. {
  1601. dwResourceId = IDS_UNKNOWN;
  1602. bClusterOperation = true; // really a don't care
  1603. }
  1604. // If a cluster operation, merely assign the string, else (ie. port operation),
  1605. // put in the vip & port information as well
  1606. if (bClusterOperation)
  1607. {
  1608. ARRAYSTRCPY(wcTempStr, GETRESOURCEIDSTRING(dwResourceId));
  1609. }
  1610. else // Port operation
  1611. {
  1612. if (_wcsicmp(szVip, CVY_DEF_ALL_VIP) == 0)
  1613. {
  1614. StringCbPrintf(
  1615. wcTempStr,
  1616. sizeof(wcTempStr),
  1617. GETRESOURCEIDSTRING(dwResourceId), (LPWSTR)GETRESOURCEIDSTRING(IDS_ALL_VIP_DESCR), *pdwPortNum);
  1618. }
  1619. else
  1620. {
  1621. StringCbPrintf(
  1622. wcTempStr,
  1623. sizeof(wcTempStr),
  1624. GETRESOURCEIDSTRING(dwResourceId), szVip, *pdwPortNum);
  1625. }
  1626. }
  1627. OperationStr = wcTempStr;
  1628. // Form the "Operation Status" string
  1629. // Could take one of the following forms :
  1630. // SUCCESS,
  1631. // SUCCESS (Note : XXXX),
  1632. // FAILURE (Cause : XXXX)
  1633. if (dwOperationStatus == WLBS_OK)
  1634. {
  1635. ARRAYSTRCPY(
  1636. wcTempStr,
  1637. GETRESOURCEIDSTRING(IDS_SUCCESS_AND_COMMA)
  1638. );
  1639. }
  1640. else if (dwOperationStatus == WLBS_ALREADY)
  1641. {
  1642. if (bClusterOperation)
  1643. {
  1644. dwResourceId = IDS_HOST_ALREADY_STATE;
  1645. }
  1646. else // Port operation
  1647. {
  1648. dwResourceId = IDS_PORT_ALREADY_STATE;
  1649. }
  1650. StringCbPrintf(
  1651. wcTempStr,
  1652. sizeof(wcTempStr),
  1653. GETRESOURCEIDSTRING(IDS_SUCCESS_AND_NOTE), (LPWSTR)GETRESOURCEIDSTRING(dwResourceId)
  1654. );
  1655. }
  1656. else if ((dwOperationStatus == WLBS_DRAIN_STOP)
  1657. && ((Operation == WLBS_START) || (Operation == WLBS_STOP) || (Operation == WLBS_SUSPEND))
  1658. )
  1659. {
  1660. LogLevel = IUICallbacks::LOG_WARNING;
  1661. StringCbPrintf(
  1662. wcTempStr,
  1663. sizeof(wcTempStr),
  1664. GETRESOURCEIDSTRING(IDS_SUCCESS_AND_NOTE), (LPWSTR)GETRESOURCEIDSTRING(IDS_DRAIN_STOP)
  1665. );
  1666. }
  1667. else if ((dwOperationStatus == WLBS_STOPPED)
  1668. && ((Operation == WLBS_DRAIN) || (Operation == WLBS_SUSPEND))
  1669. )
  1670. {
  1671. LogLevel = IUICallbacks::LOG_WARNING;
  1672. if (Operation == WLBS_DRAIN)
  1673. {
  1674. dwResourceId = IDS_ALREADY_STOPPED;
  1675. }
  1676. else // Suspend
  1677. {
  1678. dwResourceId = IDS_HOST_STOPPED;
  1679. }
  1680. StringCbPrintf(
  1681. wcTempStr,
  1682. sizeof(wcTempStr),
  1683. GETRESOURCEIDSTRING(IDS_SUCCESS_AND_NOTE), (LPWSTR)GETRESOURCEIDSTRING(dwResourceId)
  1684. );
  1685. }
  1686. else // All other operation statuses
  1687. {
  1688. // We get here only on a failure
  1689. LogLevel = IUICallbacks::LOG_ERROR;
  1690. dwMaxOperations = sizeof(AllNlbStatusToDescrMap)/sizeof(AllNlbStatusToDescrMap[0]);
  1691. // Get the "Cause" string
  1692. for (dwIdx = 0; dwIdx < dwMaxOperations; dwIdx++)
  1693. {
  1694. if (AllNlbStatusToDescrMap[dwIdx].dwStatus == dwOperationStatus)
  1695. {
  1696. dwResourceId = AllNlbStatusToDescrMap[dwIdx].dwResourceId;
  1697. break;
  1698. }
  1699. }
  1700. if (dwIdx == dwMaxOperations)
  1701. {
  1702. dwResourceId = IDS_UNKNOWN;
  1703. }
  1704. StringCbPrintf(
  1705. wcTempStr,
  1706. sizeof(wcTempStr),
  1707. GETRESOURCEIDSTRING(IDS_FAILURE_AND_CAUSE), (LPWSTR)GETRESOURCEIDSTRING(dwResourceId)
  1708. );
  1709. }
  1710. OperationStatusStr = wcTempStr;
  1711. // If the operation's status is failure, return
  1712. if (LogLevel == IUICallbacks::LOG_ERROR)
  1713. {
  1714. TRACE_INFO(L"<- %!FUNC!, returning operation status : failure");
  1715. return;
  1716. }
  1717. // Get Cluster or Port Status
  1718. if (bClusterOperation)
  1719. {
  1720. dwClusterOrPortResourceId = IDS_HOST_STATE;
  1721. }
  1722. else // Port Operation
  1723. {
  1724. dwClusterOrPortResourceId = IDS_PORT_RULE_STATE;
  1725. }
  1726. // Get the "ClusterOrPortState" string
  1727. dwMaxOperations = sizeof(AllNlbStatusToDescrMap)/sizeof(AllNlbStatusToDescrMap[0]);
  1728. for (dwIdx = 0; dwIdx < dwMaxOperations; dwIdx++)
  1729. {
  1730. if (AllNlbStatusToDescrMap[dwIdx].dwStatus == dwClusterOrPortStatus)
  1731. {
  1732. dwResourceId = AllNlbStatusToDescrMap[dwIdx].dwResourceId;
  1733. break;
  1734. }
  1735. }
  1736. if (dwIdx == dwMaxOperations)
  1737. {
  1738. dwResourceId = IDS_UNKNOWN;
  1739. }
  1740. StringCbPrintf(
  1741. wcTempStr,
  1742. sizeof(wcTempStr),
  1743. GETRESOURCEIDSTRING(dwClusterOrPortResourceId), (LPWSTR)GETRESOURCEIDSTRING(dwResourceId)
  1744. );
  1745. ClusterOrPortStatusStr = wcTempStr;
  1746. // Determine if the value returned for Cluster/Port state is valid & if not, set the log level to "error"
  1747. if (bClusterOperation)
  1748. {
  1749. switch(dwClusterOrPortStatus)
  1750. {
  1751. case WLBS_CONVERGING:
  1752. case WLBS_CONVERGED:
  1753. case WLBS_DEFAULT:
  1754. case WLBS_DRAINING:
  1755. case WLBS_STOPPED: // really a failure in the sense of not being able to get the host map, but not flagging it here
  1756. case WLBS_SUSPENDED:// 'cos it is a "normal" case
  1757. break;
  1758. default:
  1759. LogLevel = IUICallbacks::LOG_ERROR;
  1760. break;
  1761. }
  1762. }
  1763. else // Port operation
  1764. {
  1765. switch(dwClusterOrPortStatus)
  1766. {
  1767. case NLB_PORT_RULE_ENABLED:
  1768. case NLB_PORT_RULE_DISABLED:
  1769. case NLB_PORT_RULE_DRAINING:
  1770. break;
  1771. default:
  1772. LogLevel = IUICallbacks::LOG_ERROR;
  1773. break;
  1774. }
  1775. }
  1776. TRACE_INFO(L"<- %!FUNC!");
  1777. return;
  1778. }
  1779. NLBERROR
  1780. CNlbEngine::ControlClusterOnInterface(
  1781. IN ENGINEHANDLE ehInterfaceId,
  1782. IN WLBS_OPERATION_CODES Operation,
  1783. IN CString szVipArray[],
  1784. IN DWORD pdwPortNumArray[],
  1785. IN DWORD dwNumOfPortRules,
  1786. IN BOOL fNewOperation
  1787. )
  1788. {
  1789. TRACE_INFO(L"-> %!FUNC!");
  1790. LPCWSTR szNicGuid, szHostName, szClusterIp;
  1791. NLBERROR err = NLBERR_OK;
  1792. CHostSpec *pHSpec = NULL;
  1793. CInterfaceSpec *pISpec = NULL;
  1794. DWORD dwOperationStatus, dwClusterOrPortStatus, dwHostMap, dwNumOfIterations, dwIdx;
  1795. WBEMSTATUS Status;
  1796. BOOL bClusterOperation;
  1797. IUICallbacks::LogEntryType LogLevel;
  1798. _bstr_t OperationStr, OperationStatusStr, ClusterOrPortStatusStr;
  1799. BOOL fStopOperationOnExit = FALSE;
  1800. if (fNewOperation)
  1801. {
  1802. //
  1803. // This function is to be run in the context of a NEW operation.
  1804. // Verify that we can do a control op at this time, and if so, start an
  1805. // operation to track the control.
  1806. //
  1807. mfn_Lock();
  1808. pISpec = m_mapIdToInterfaceSpec[ehInterfaceId]; // map
  1809. if (pISpec == NULL)
  1810. {
  1811. TRACE_CRIT("%!FUNC!: ERROR couldn't get info on this if id!");
  1812. goto end_unlock;
  1813. }
  1814. //
  1815. // Now try to start an operation...
  1816. //
  1817. {
  1818. ENGINEHANDLE ExistingOp = NULL;
  1819. err = mfn_StartInterfaceOperationLk(
  1820. ehInterfaceId,
  1821. NULL, // pvCtxt
  1822. GETRESOURCEIDSTRING(IDS_LOG_CONTROL_INTERFACE),
  1823. &ExistingOp
  1824. );
  1825. if (NLBFAILED(err))
  1826. {
  1827. goto end_unlock;
  1828. }
  1829. //
  1830. // We did start the operation -- so we keep track of this, so that
  1831. // we stop the operation on exit.
  1832. //
  1833. fStopOperationOnExit = TRUE;
  1834. }
  1835. pISpec = NULL;
  1836. mfn_Unlock();
  1837. }
  1838. mfn_Lock();
  1839. err = CNlbEngine::mfn_GetHostFromInterfaceLk(ehInterfaceId, REF pISpec, REF pHSpec);
  1840. if (err != NLBERR_OK)
  1841. {
  1842. TRACE_CRIT(L"%!FUNC! could not get pISpec,pHSpec for ehIF 0x%lx", ehInterfaceId);
  1843. goto end_unlock;
  1844. }
  1845. WMI_CONNECTION_INFO ConnInfo;
  1846. ConnInfo.szUserName = (LPCWSTR) pHSpec->m_UserName;
  1847. ConnInfo.szPassword = (LPCWSTR) pHSpec->m_Password;
  1848. ConnInfo.szMachine = (LPCWSTR) pHSpec->m_ConnectionString;
  1849. szNicGuid = (LPCWSTR)(pISpec->m_Guid);
  1850. szClusterIp= pISpec->m_NlbCfg.NlbParams.cl_ip_addr;
  1851. szHostName = (LPCWSTR)(pHSpec->m_MachineName);
  1852. if (szNicGuid == NULL)
  1853. {
  1854. TRACE_CRIT(L"%!FUNC! ERROR -- NULL szNicGuid!");
  1855. goto end_unlock;
  1856. }
  1857. mfn_Unlock();
  1858. if (dwNumOfPortRules == 0)
  1859. {
  1860. bClusterOperation = TRUE;
  1861. dwNumOfIterations = 1;
  1862. }
  1863. else // Port operation
  1864. {
  1865. bClusterOperation = FALSE;
  1866. dwNumOfIterations = dwNumOfPortRules;
  1867. }
  1868. m_pCallbacks->HandleEngineEvent(
  1869. IUICallbacks::OBJ_INTERFACE,
  1870. NULL, // ehClusterId,
  1871. ehInterfaceId,
  1872. IUICallbacks::EVT_STATUS_CHANGE
  1873. );
  1874. ProcessMsgQueue();
  1875. for (dwIdx = 0 ; dwIdx < dwNumOfIterations ; dwIdx++)
  1876. {
  1877. LPCWSTR szVip = (szVipArray) ? (LPCTSTR)(szVipArray[dwIdx]) : NULL;
  1878. DWORD *pdwPortNum = (pdwPortNumArray) ? &pdwPortNumArray[dwIdx] : NULL;
  1879. Status = NlbHostControlCluster(&ConnInfo,
  1880. szNicGuid,
  1881. szVip,
  1882. pdwPortNum,
  1883. Operation,
  1884. &dwOperationStatus,
  1885. &dwClusterOrPortStatus,
  1886. &dwHostMap);
  1887. if (FAILED(Status))
  1888. {
  1889. if (Status == WBEM_E_INVALID_PARAMETER)
  1890. {
  1891. err = NLBERR_INVALID_CLUSTER_SPECIFICATION;
  1892. dwOperationStatus = WLBS_BAD_PARAMS;
  1893. }
  1894. else // Critical Error
  1895. {
  1896. err = NLBERR_INTERNAL_ERROR;
  1897. dwOperationStatus = WLBS_FAILURE;
  1898. }
  1899. }
  1900. // Get the strings to log into log view
  1901. mfn_GetLogStrings(Operation,
  1902. szVip,
  1903. pdwPortNum,
  1904. dwOperationStatus,
  1905. dwClusterOrPortStatus,
  1906. REF LogLevel,
  1907. REF OperationStr,
  1908. REF OperationStatusStr,
  1909. REF ClusterOrPortStatusStr
  1910. );
  1911. // If operation is NOT Query, Log result in Log View
  1912. // We do NOT log results of a Query 'cos this is done for a "Refresh"
  1913. // and we do not want to tell what is happening underneath. Instead,
  1914. // the change in color coding will reflect any changes to the cluster state.
  1915. if (Operation != WLBS_QUERY)
  1916. {
  1917. m_pCallbacks->Log(LogLevel,
  1918. szClusterIp,
  1919. szHostName,
  1920. IDS_LOG_CONTROL_CLUSTER,
  1921. (LPWSTR)OperationStr,
  1922. (LPWSTR)OperationStatusStr,
  1923. (LPWSTR)ClusterOrPortStatusStr);
  1924. ProcessMsgQueue();
  1925. }
  1926. }
  1927. mfn_Lock();
  1928. if (bClusterOperation)
  1929. {
  1930. pISpec->m_fValidClusterState = TRUE;
  1931. pISpec->m_dwClusterState = dwClusterOrPortStatus;
  1932. }
  1933. end_unlock:
  1934. if (fStopOperationOnExit)
  1935. {
  1936. mfn_StopInterfaceOperationLk(ehInterfaceId);
  1937. }
  1938. mfn_Unlock();
  1939. if (fStopOperationOnExit)
  1940. {
  1941. m_pCallbacks->HandleEngineEvent(
  1942. IUICallbacks::OBJ_INTERFACE,
  1943. NULL, // ehClusterId,
  1944. ehInterfaceId,
  1945. IUICallbacks::EVT_STATUS_CHANGE
  1946. );
  1947. ProcessMsgQueue();
  1948. }
  1949. TRACE_INFO(L"<- %!FUNC! return : %u", err);
  1950. return err;
  1951. }
  1952. NLBERROR
  1953. CNlbEngine::ControlClusterOnCluster(
  1954. IN ENGINEHANDLE ehClusterId,
  1955. IN WLBS_OPERATION_CODES Operation,
  1956. IN CString szVipArray[],
  1957. IN DWORD pdwPortNumArray[],
  1958. IN DWORD dwNumOfPortRules
  1959. )
  1960. /*
  1961. Perform Cluster wide control operations
  1962. */
  1963. {
  1964. TRACE_INFO(L"-> %!FUNC!");
  1965. NLBERROR nerr = NLBERR_OK;
  1966. BOOL fStopOperationOnExit = FALSE;
  1967. vector<ENGINEHANDLE> InterfaceListCopy;
  1968. //
  1969. // First thing we do is to see if we can start the cluster operation...
  1970. //
  1971. {
  1972. BOOL fCanStart = FALSE;
  1973. nerr = this->CanStartClusterOperation(ehClusterId, REF fCanStart);
  1974. if (NLBFAILED(nerr))
  1975. {
  1976. goto end;
  1977. }
  1978. if (!fCanStart)
  1979. {
  1980. nerr = NLBERR_BUSY;
  1981. goto end;
  1982. }
  1983. }
  1984. {
  1985. mfn_Lock();
  1986. CClusterSpec *pCSpec = NULL;
  1987. CEngineCluster *pECluster = m_mapIdToEngineCluster[ehClusterId]; // map
  1988. if (pECluster == NULL)
  1989. {
  1990. nerr = NLBERR_NOT_FOUND;
  1991. goto end_unlock;
  1992. }
  1993. pCSpec = &pECluster->m_cSpec;
  1994. //
  1995. // Attempt to start the refresh operation -- will fail if there is
  1996. // already an operation started on this cluster.
  1997. //
  1998. {
  1999. ENGINEHANDLE ExistingOp= NULL;
  2000. CLocalLogger logDescription;
  2001. logDescription.Log(
  2002. IDS_LOG_CONTROL_CLUSTER_OPERATION_DESCRIPTION,
  2003. pCSpec->m_ClusterNlbCfg.NlbParams.cl_ip_addr
  2004. );
  2005. nerr = mfn_StartClusterOperationLk(
  2006. ehClusterId,
  2007. NULL, // pvCtxt
  2008. logDescription.GetStringSafe(),
  2009. &ExistingOp
  2010. );
  2011. if (NLBFAILED(nerr))
  2012. {
  2013. goto end_unlock;
  2014. }
  2015. else
  2016. {
  2017. fStopOperationOnExit = TRUE;
  2018. }
  2019. }
  2020. InterfaceListCopy = pCSpec->m_ehInterfaceIdList; // vector copy
  2021. mfn_Unlock();
  2022. }
  2023. m_pCallbacks->HandleEngineEvent(
  2024. IUICallbacks::OBJ_CLUSTER,
  2025. ehClusterId,
  2026. ehClusterId,
  2027. IUICallbacks::EVT_STATUS_CHANGE
  2028. );
  2029. ProcessMsgQueue();
  2030. mfn_Lock();
  2031. {
  2032. //
  2033. // Perform control operation on each interface in this cluster...
  2034. //
  2035. for( int i = 0; i < InterfaceListCopy.size(); ++i )
  2036. {
  2037. ENGINEHANDLE ehIId = InterfaceListCopy[i];
  2038. mfn_Unlock();
  2039. nerr = this->ControlClusterOnInterface(
  2040. ehIId,
  2041. Operation,
  2042. szVipArray,
  2043. pdwPortNumArray,
  2044. dwNumOfPortRules,
  2045. TRUE
  2046. );
  2047. mfn_Lock();
  2048. }
  2049. }
  2050. end_unlock:
  2051. if (fStopOperationOnExit)
  2052. {
  2053. //
  2054. // We'll stop the operation, assumed to be started in this function.
  2055. //
  2056. mfn_StopClusterOperationLk(ehClusterId);
  2057. }
  2058. mfn_Unlock();
  2059. if (fStopOperationOnExit)
  2060. {
  2061. m_pCallbacks->HandleEngineEvent(
  2062. IUICallbacks::OBJ_CLUSTER,
  2063. ehClusterId,
  2064. ehClusterId,
  2065. IUICallbacks::EVT_STATUS_CHANGE
  2066. );
  2067. ProcessMsgQueue();
  2068. }
  2069. end:
  2070. TRACE_INFO(L"<- %!FUNC! return : %u", nerr);
  2071. return nerr;
  2072. }
  2073. NLBERROR
  2074. CNlbEngine::FindInterfaceOnHostByClusterIp(
  2075. IN ENGINEHANDLE ehHostId,
  2076. IN LPCWSTR szClusterIp, // OPTIONAL
  2077. OUT ENGINEHANDLE &ehInterfaceId, // first found
  2078. OUT UINT &NumFound
  2079. )
  2080. /*
  2081. Return the handle of the interface on the specified host that is
  2082. bound to a cluster with the specified cluster IP address.
  2083. */
  2084. {
  2085. CHostSpec *pHSpec = NULL;
  2086. NLBERROR err = NLBERR_OK;
  2087. UINT uClusterIp = 0;
  2088. WBEMSTATUS wStat;
  2089. ENGINEHANDLE ehFoundIID = NULL;
  2090. UINT MyNumFound = 0;
  2091. ehInterfaceId = NULL;
  2092. NumFound = 0;
  2093. mfn_Lock();
  2094. if (szClusterIp != NULL)
  2095. {
  2096. wStat = CfgUtilsValidateNetworkAddress(
  2097. szClusterIp,
  2098. &uClusterIp,
  2099. NULL, // puSubnetMask
  2100. NULL // puDefaultSubnetMask
  2101. );
  2102. if (FAILED(wStat))
  2103. {
  2104. TRACE_CRIT("%!FUNC! invalid szClusterIp (%ws) specified", szClusterIp);
  2105. err = NLBERR_INVALID_IP_ADDRESS_SPECIFICATION;
  2106. goto end;
  2107. }
  2108. }
  2109. pHSpec = m_mapIdToHostSpec[ehHostId]; // map
  2110. if (pHSpec == NULL)
  2111. {
  2112. err = NLBERR_HOST_NOT_FOUND;
  2113. goto end;
  2114. }
  2115. //
  2116. // Now look through the interfaces, searching for a cluster ip.
  2117. //
  2118. for( int i = 0; i < pHSpec->m_ehInterfaceIdList.size(); ++i )
  2119. {
  2120. ENGINEHANDLE ehIID = NULL;
  2121. ehIID = pHSpec->m_ehInterfaceIdList[i];
  2122. CInterfaceSpec *pISpec = NULL;
  2123. pISpec = m_mapIdToInterfaceSpec[ehIID]; // map
  2124. if (pISpec == NULL)
  2125. {
  2126. TRACE_CRIT("%!FUNC! unexpected null pISpec for IID 0x%lx", ehIID);
  2127. continue;
  2128. }
  2129. if (szClusterIp == NULL)
  2130. {
  2131. if (pISpec->m_NlbCfg.IsNlbBound())
  2132. {
  2133. MyNumFound++;
  2134. if (ehFoundIID == NULL)
  2135. {
  2136. //
  2137. // First interface bound to NLB -- we'll save this away.
  2138. // and continue.
  2139. //
  2140. ehFoundIID = ehIID;
  2141. }
  2142. }
  2143. continue;
  2144. }
  2145. //
  2146. // A non-null szClusterIp is specified. We'll see if it matches
  2147. // the cluster IP (if any) on this interface.
  2148. //
  2149. if (pISpec->m_NlbCfg.IsValidNlbConfig())
  2150. {
  2151. UINT uThisClusterIp = 0;
  2152. LPCWSTR szThisClusterIp = pISpec->m_NlbCfg.NlbParams.cl_ip_addr;
  2153. wStat = CfgUtilsValidateNetworkAddress(
  2154. szThisClusterIp,
  2155. &uThisClusterIp,
  2156. NULL, // puSubnetMask
  2157. NULL // puDefaultSubnetMask
  2158. );
  2159. if (FAILED(wStat))
  2160. {
  2161. continue;
  2162. }
  2163. if (uThisClusterIp == uClusterIp)
  2164. {
  2165. MyNumFound++;
  2166. if (ehFoundIID == NULL)
  2167. {
  2168. //
  2169. // First interface bound to NLB -- we'll save this away.
  2170. // and continue.
  2171. //
  2172. ehFoundIID = ehIID;
  2173. }
  2174. else
  2175. {
  2176. //
  2177. // Hmm... more than one nlb cluster with the same IP?
  2178. // could be a bad config on one or both.
  2179. //
  2180. TRACE_CRIT("%!FUNC! two clusters on ehHost 0x%lx have cluster ip %ws", ehHostId, szClusterIp);
  2181. }
  2182. }
  2183. }
  2184. }
  2185. if (MyNumFound != 0)
  2186. {
  2187. ASSERT(ehFoundIID != NULL);
  2188. ehInterfaceId = ehFoundIID;
  2189. NumFound = MyNumFound;
  2190. err = NLBERR_OK;
  2191. }
  2192. else
  2193. {
  2194. err = NLBERR_INTERFACE_NOT_FOUND;
  2195. }
  2196. end:
  2197. mfn_Unlock();
  2198. return err;
  2199. }
  2200. NLBERROR
  2201. CNlbEngine::InitializeNewHostConfig(
  2202. IN ENGINEHANDLE ehCluster,
  2203. OUT NLB_EXTENDED_CLUSTER_CONFIGURATION &NlbCfg
  2204. )
  2205. /*
  2206. Initialize NlbCfg based on the current cluster parameters as well
  2207. as good host-specific defaults like host priority, taking into account
  2208. other members of the cluster.
  2209. */
  2210. {
  2211. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  2212. WBEMSTATUS wStatus = WBEM_E_CRITICAL_ERROR;
  2213. WLBS_PORT_RULE *pRules = NULL;
  2214. BOOL fAvailablePortRulePrioritiesSet = FALSE;
  2215. //
  2216. // Get the cluster spec and copy over it to NlbCfg.
  2217. //
  2218. {
  2219. mfn_Lock();
  2220. CEngineCluster *pECluster = m_mapIdToEngineCluster[ehCluster]; // map
  2221. if (pECluster == NULL)
  2222. {
  2223. nerr = NLBERR_NOT_FOUND;
  2224. mfn_Unlock();
  2225. goto end;
  2226. }
  2227. //
  2228. // Copy over the cluster spec's params.
  2229. //
  2230. wStatus = NlbCfg.Update(&pECluster->m_cSpec.m_ClusterNlbCfg);
  2231. mfn_Unlock();
  2232. }
  2233. if (FAILED(wStatus))
  2234. {
  2235. TRACE_CRIT("%!FUNC! Error copying over cluster params ehC=0x%lx",
  2236. ehCluster);
  2237. nerr = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  2238. goto end;
  2239. }
  2240. if(!NlbCfg.IsValidNlbConfig()) {
  2241. //
  2242. // We expect the configuration to be valid -- i.e., NLB bound, with
  2243. // valid parameters.
  2244. //
  2245. TRACE_CRIT("%!FUNC! -- current configuration is unbound/invalid!");
  2246. goto end;
  2247. }
  2248. //
  2249. // Set host-id (priority) to the first available host priority.
  2250. //
  2251. {
  2252. ULONG AvailablePriorities = this->GetAvailableHostPriorities(ehCluster);
  2253. ULONG HostId = 1;
  2254. for(ULONG u=0; u<32; u++)
  2255. {
  2256. if (AvailablePriorities & (((ULONG)1)<<u))
  2257. {
  2258. HostId = u+1; // let's pick the first available one.
  2259. break;
  2260. }
  2261. }
  2262. NlbCfg.NlbParams.host_priority = HostId;
  2263. }
  2264. //
  2265. // For each single-host-affinity port rule, set the host priority to
  2266. // the host-id if that's available, else the first available host priority
  2267. //
  2268. {
  2269. UINT NumRules=0;
  2270. ULONG rgAvailablePriorities[WLBS_MAX_RULES];
  2271. ZeroMemory(rgAvailablePriorities, sizeof(rgAvailablePriorities));
  2272. wStatus = CfgUtilGetPortRules(
  2273. &NlbCfg.NlbParams,
  2274. &pRules,
  2275. &NumRules
  2276. );
  2277. if (FAILED(wStatus))
  2278. {
  2279. TRACE_CRIT("%!FUNC! error 0x%08lx extracting port rules!", wStatus);
  2280. pRules = NULL;
  2281. goto end;
  2282. }
  2283. nerr = this->GetAvailablePortRulePriorities(
  2284. ehCluster,
  2285. NumRules,
  2286. pRules,
  2287. rgAvailablePriorities
  2288. );
  2289. if (NLBOK(nerr))
  2290. {
  2291. fAvailablePortRulePrioritiesSet = TRUE;
  2292. }
  2293. else
  2294. {
  2295. fAvailablePortRulePrioritiesSet = FALSE;
  2296. }
  2297. //
  2298. // Now for each rule, put defaults
  2299. //
  2300. for (UINT u=0; u<NumRules;u++)
  2301. {
  2302. WLBS_PORT_RULE *pRule = pRules+u;
  2303. UINT Mode = pRule->mode;
  2304. if (Mode != CVY_NEVER)
  2305. {
  2306. if (Mode == CVY_MULTI)
  2307. {
  2308. pRule->mode_data.multi.equal_load = TRUE; //default
  2309. //
  2310. // The equal_load value is set in the cluster
  2311. // properties dialog.
  2312. //
  2313. pRule->mode_data.multi.load = 50;
  2314. }
  2315. else if (Mode == CVY_SINGLE)
  2316. {
  2317. ULONG PortPriority = 0;
  2318. ULONG AvailablePriorities = 0;
  2319. //
  2320. // Default is set to this host's host ID (priority)
  2321. //
  2322. PortPriority = NlbCfg.NlbParams.host_priority;
  2323. if (fAvailablePortRulePrioritiesSet)
  2324. {
  2325. AvailablePriorities = rgAvailablePriorities[u];
  2326. }
  2327. if (AvailablePriorities != 0
  2328. && 0 == ((1<<(PortPriority-1)) & AvailablePriorities) )
  2329. {
  2330. //
  2331. // There are available priorities, but unfortunately
  2332. // the default priority is not available -- pick
  2333. // the first available priority.
  2334. //
  2335. for(ULONG v=0; v<32; v++)
  2336. {
  2337. if (AvailablePriorities & (((ULONG)1)<<v))
  2338. {
  2339. PortPriority = v+1; // let's pick this one
  2340. break;
  2341. }
  2342. }
  2343. }
  2344. pRule->mode_data.single.priority = PortPriority;
  2345. }
  2346. }
  2347. }
  2348. //
  2349. // Finally, set the port rules..
  2350. //
  2351. wStatus = CfgUtilSetPortRules(
  2352. pRules,
  2353. NumRules,
  2354. &NlbCfg.NlbParams
  2355. );
  2356. if (FAILED(wStatus))
  2357. {
  2358. TRACE_CRIT("%!FUNC! error 0x%08lx setting port rules!", wStatus);
  2359. goto end;
  2360. }
  2361. nerr = NLBERR_OK;
  2362. }
  2363. end:
  2364. delete pRules; // can be NULL
  2365. return nerr;
  2366. }
  2367. NLBERROR
  2368. CNlbEngine::UpdateInterface(
  2369. IN ENGINEHANDLE ehInterfaceId,
  2370. IN NLB_EXTENDED_CLUSTER_CONFIGURATION &refNewConfigIn,
  2371. // IN OUT BOOL &fClusterPropertiesUpdated,
  2372. OUT CLocalLogger logConflict
  2373. )
  2374. {
  2375. /*
  2376. Will MUNGE refNewConfig -- slightly munges refNewConfig.NlbParams,
  2377. and will fill in default pIpAddressInfo if it's not set.
  2378. */
  2379. NLBERROR err = NLBERR_OK;
  2380. BOOL fConnectivityChange = FALSE;
  2381. BOOL fStopOperationOnExit= FALSE;
  2382. NLB_EXTENDED_CLUSTER_CONFIGURATION
  2383. *pPendingConfig = NULL;
  2384. LPCWSTR szHostName = NULL;
  2385. LPCWSTR szClusterIp = NULL;
  2386. LPCWSTR szDisplayName = NULL; // of interface
  2387. ENGINEHANDLE ehHost = NULL;
  2388. ENGINEHANDLE ehCluster = NULL;
  2389. _bstr_t bstrFriendlyName;
  2390. _bstr_t bstrDisplayName;
  2391. _bstr_t bstrHostName;
  2392. //
  2393. // Following to decide whether to log that we're not adding the
  2394. // dedicated IP because it's already on another interface.
  2395. //
  2396. BOOL fDedicatedIpOnOtherIf = FALSE;
  2397. ENGINEHANDLE ehOtherIf = NULL;
  2398. TRACE_INFO(L"-> %!FUNC!");
  2399. err = this->GetInterfaceIdentification(
  2400. ehInterfaceId,
  2401. REF ehHost,
  2402. REF ehCluster,
  2403. REF bstrFriendlyName,
  2404. REF bstrDisplayName,
  2405. REF bstrHostName
  2406. );
  2407. if (NLBFAILED(err))
  2408. {
  2409. goto end;
  2410. }
  2411. szDisplayName = bstrDisplayName;
  2412. szHostName = bstrHostName;
  2413. if (szDisplayName == NULL)
  2414. {
  2415. szDisplayName = L"";
  2416. }
  2417. if (szHostName == NULL)
  2418. {
  2419. szHostName = L"";
  2420. }
  2421. mfn_Lock();
  2422. CInterfaceSpec *pISpec = m_mapIdToInterfaceSpec[ehInterfaceId]; // map
  2423. if (pISpec == NULL)
  2424. {
  2425. err = NLBERR_INTERFACE_NOT_FOUND;
  2426. goto end_unlock;
  2427. }
  2428. //
  2429. // Make a copy of refNewConfig, because we'll likely be doing
  2430. // the update operation in the background.
  2431. //
  2432. pPendingConfig = new NLB_EXTENDED_CLUSTER_CONFIGURATION;
  2433. if (pPendingConfig == NULL)
  2434. {
  2435. err = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  2436. goto end_unlock;
  2437. }
  2438. else
  2439. {
  2440. WBEMSTATUS wStat1;
  2441. wStat1 = pPendingConfig->Update(&refNewConfigIn);
  2442. if (FAILED(wStat1))
  2443. {
  2444. delete pPendingConfig;
  2445. pPendingConfig = NULL;
  2446. err = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  2447. goto end_unlock;
  2448. }
  2449. //
  2450. // Copy over the RCT password -- which does NOT get copied over
  2451. // by the Update method above. The new password can be in the form
  2452. // of a string or hashed-version.
  2453. //
  2454. //
  2455. if (refNewConfigIn.NewRemoteControlPasswordSet())
  2456. {
  2457. LPCWSTR szNewPassword = NULL;
  2458. szNewPassword = refNewConfigIn.GetNewRemoteControlPasswordRaw();
  2459. if (szNewPassword != NULL)
  2460. {
  2461. //
  2462. // Note: szNewPassword will be NULL UNLESS the user has explicitly
  2463. // specified a new password.
  2464. //
  2465. pPendingConfig->SetNewRemoteControlPassword(szNewPassword);
  2466. }
  2467. else
  2468. {
  2469. //
  2470. // This means the hash password is being updated...
  2471. // This typically means that this is a new host and we're
  2472. // setting up it's remote control password.
  2473. //
  2474. DWORD dwHash = 0;
  2475. BOOL fRet = refNewConfigIn.GetNewHashedRemoteControlPassword(
  2476. REF dwHash
  2477. );
  2478. if (fRet)
  2479. {
  2480. pPendingConfig->SetNewHashedRemoteControlPassword(
  2481. dwHash
  2482. );
  2483. }
  2484. else
  2485. {
  2486. TRACE_CRIT("refNewConfigIn fNewPassword set; but could not get either szPassword or new hashed password!");
  2487. }
  2488. }
  2489. }
  2490. }
  2491. NLB_EXTENDED_CLUSTER_CONFIGURATION &refNewConfig = *pPendingConfig;
  2492. szClusterIp = refNewConfig.NlbParams.cl_ip_addr;
  2493. //
  2494. // Attempt to start the update operation -- will fail if there is
  2495. // already an operation started on this interface.
  2496. //
  2497. {
  2498. ENGINEHANDLE ExistingOp= NULL;
  2499. CLocalLogger logDescription;
  2500. logDescription.Log(
  2501. IDS_LOG_UPDATE_INTERFACE_OPERATION_DESCRIPTION,
  2502. szDisplayName
  2503. );
  2504. err = mfn_StartInterfaceOperationLk(
  2505. ehInterfaceId,
  2506. pPendingConfig,
  2507. logDescription.GetStringSafe(),
  2508. &ExistingOp
  2509. );
  2510. if (NLBFAILED(err))
  2511. {
  2512. if (err == NLBERR_BUSY)
  2513. {
  2514. //
  2515. // This means that there was an existing operation.
  2516. // Let's get its description and add it to the log.
  2517. //
  2518. CEngineOperation *pExistingOp;
  2519. pExistingOp = mfn_GetOperationLk(ExistingOp);
  2520. if (pExistingOp != NULL)
  2521. {
  2522. LPCWSTR szDescrip = pExistingOp->bstrDescription;
  2523. if (szDescrip == NULL)
  2524. {
  2525. szDescrip = L"";
  2526. }
  2527. logConflict.Log(
  2528. IDS_LOG_OPERATION_PENDING_ON_INTERFACE,
  2529. szDescrip
  2530. );
  2531. }
  2532. }
  2533. goto end_unlock;
  2534. }
  2535. else
  2536. {
  2537. fStopOperationOnExit = TRUE;
  2538. }
  2539. }
  2540. ehHost = pISpec->m_ehHostId;
  2541. //
  2542. // Validate new config and get out if there's no real updating to
  2543. // be done.
  2544. //
  2545. {
  2546. if (refNewConfig.IsNlbBound())
  2547. {
  2548. if (refNewConfig.NumIpAddresses==0)
  2549. {
  2550. refNewConfig.fAddClusterIps = TRUE;
  2551. refNewConfig.fAddDedicatedIp = TRUE;
  2552. }
  2553. else
  2554. {
  2555. //
  2556. // refNewConfig has a non-null IP address list.
  2557. //
  2558. // We interpret this to be the list of cluster IP addresses
  2559. // with possibly the dedicated ip address as the
  2560. // first IP address.
  2561. //
  2562. //
  2563. // We'll re-order the ip address list to match the
  2564. // existing order of IP addresses on the adapter as
  2565. // far as possible.
  2566. //
  2567. // Then we'll add the dedicated IP address list if we
  2568. // need to.
  2569. //
  2570. BOOL fRet = FALSE;
  2571. NlbIpAddressList addrList;
  2572. //
  2573. // Make a copy of the old adddress list in addrList
  2574. //
  2575. fRet = addrList.Set(pISpec->m_NlbCfg.NumIpAddresses,
  2576. pISpec->m_NlbCfg.pIpAddressInfo, 1);
  2577. if (!fRet)
  2578. {
  2579. TRACE_CRIT(L"Unable to copy old IP address list");
  2580. err = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  2581. goto end_unlock;
  2582. }
  2583. //
  2584. // addrList.Apply will taken on the new ip address list,
  2585. // but try to preserve the old order.
  2586. //
  2587. fRet = addrList.Apply(refNewConfig.NumIpAddresses,
  2588. refNewConfig.pIpAddressInfo);
  2589. if (!fRet)
  2590. {
  2591. TRACE_CRIT(L"Unable to apply new IP address list");
  2592. err = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  2593. goto end_unlock;
  2594. }
  2595. //
  2596. // If there is a dedicated IP address AND it
  2597. // does not exist elsewhere on this host, add it to
  2598. // the beginning of the list.
  2599. //
  2600. if (!refNewConfig.IsBlankDedicatedIp())
  2601. {
  2602. ENGINEHANDLE ehIF = NULL;
  2603. err = this->mfn_LookupInterfaceByIpLk(
  2604. NULL, // NULL == look through all hosts.
  2605. refNewConfig.NlbParams.ded_ip_addr,
  2606. REF ehOtherIf
  2607. );
  2608. if (NLBOK(err) && ehOtherIf != ehInterfaceId)
  2609. {
  2610. //
  2611. // Hmm... another interface already has this
  2612. // interface?
  2613. //
  2614. // We'll log this and NOT add the dedicated IP
  2615. // address...
  2616. //
  2617. fDedicatedIpOnOtherIf = TRUE;
  2618. (VOID) addrList.Modify(
  2619. refNewConfig.NlbParams.ded_ip_addr,
  2620. NULL,
  2621. NULL
  2622. );
  2623. }
  2624. else
  2625. {
  2626. fRet = addrList.Modify(
  2627. NULL,
  2628. refNewConfig.NlbParams.ded_ip_addr,
  2629. refNewConfig.NlbParams.ded_net_mask
  2630. );
  2631. if (!fRet)
  2632. {
  2633. TRACE_CRIT(L"Unable to add ded IP to addr list");
  2634. err = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  2635. goto end_unlock;
  2636. }
  2637. }
  2638. }
  2639. //
  2640. // Set refNewConfig's ip address list to the newly
  2641. // computed values.
  2642. //
  2643. refNewConfig.SetNetworkAddressesRaw(NULL,0);
  2644. addrList.Extract(
  2645. REF refNewConfig.NumIpAddresses,
  2646. REF refNewConfig.pIpAddressInfo
  2647. );
  2648. }
  2649. }
  2650. err = pISpec->m_NlbCfg.AnalyzeUpdate(
  2651. &refNewConfig,
  2652. &fConnectivityChange
  2653. );
  2654. if (err == NLBERR_NO_CHANGE)
  2655. {
  2656. //
  2657. // Nothing has changed -- we skip
  2658. //
  2659. err = NLBERR_OK;
  2660. goto end_unlock;
  2661. }
  2662. //
  2663. // err could indicate failure -- we'll deal with that a little
  2664. // bit further down.
  2665. //
  2666. } // validate/munge refNewConfig
  2667. if (!NLBOK(err))
  2668. {
  2669. mfn_Unlock();
  2670. //
  2671. // Probably a parameter error -- we'll get the latest
  2672. // config and display it...
  2673. //
  2674. m_pCallbacks->Log(
  2675. IUICallbacks::LOG_ERROR,
  2676. szClusterIp,
  2677. szHostName,
  2678. IDS_LOG_CANT_UPDATE_BAD_PARAMS
  2679. );
  2680. (void) this->RefreshInterface(
  2681. ehInterfaceId,
  2682. FALSE, // FALSE == don't start a new operation
  2683. FALSE // FALSE == this is not cluster-wide
  2684. );
  2685. mfn_Lock();
  2686. goto end_unlock;
  2687. }
  2688. mfn_Unlock();
  2689. if (fDedicatedIpOnOtherIf)
  2690. {
  2691. LPCWSTR szOtherIf = NULL;
  2692. _bstr_t bstrOtherFriendlyName;
  2693. _bstr_t bstrOtherDisplayName;
  2694. _bstr_t bstrOtherHostName;
  2695. ENGINEHANDLE ehOtherHost;
  2696. ENGINEHANDLE ehOtherCluster;
  2697. NLBERROR tmpErr;
  2698. IUICallbacks::LogEntryType logType = IUICallbacks::LOG_WARNING;
  2699. tmpErr = this->GetInterfaceIdentification(
  2700. ehOtherIf,
  2701. REF ehOtherHost,
  2702. REF ehOtherCluster,
  2703. REF bstrOtherFriendlyName,
  2704. REF bstrOtherDisplayName,
  2705. REF bstrOtherHostName
  2706. );
  2707. if (NLBOK(tmpErr))
  2708. {
  2709. if (ehOtherHost != ehHost)
  2710. {
  2711. // Odd -- ded ip on another host?
  2712. logType = IUICallbacks::LOG_ERROR;
  2713. szOtherIf = bstrOtherDisplayName; // includes host name
  2714. }
  2715. else
  2716. {
  2717. szOtherIf = bstrOtherFriendlyName;
  2718. }
  2719. }
  2720. if (szOtherIf == NULL)
  2721. {
  2722. szOtherIf = L"";
  2723. }
  2724. //
  2725. // Let's log the fact that the dedicated Ip address is
  2726. // on some other interface.
  2727. //
  2728. TRACE_INFO(L"WARNING: dedicated IP address for eIF 0x%lx is on eIF 0x%lx",
  2729. ehInterfaceId, ehOtherIf);
  2730. m_pCallbacks->Log(
  2731. IUICallbacks::LOG_INFORMATIONAL,
  2732. szClusterIp,
  2733. szHostName,
  2734. IDS_LOG_DEDICATED_IP_ON_OTHER_INTERFACE,
  2735. refNewConfig.NlbParams.ded_ip_addr,
  2736. szOtherIf
  2737. );
  2738. }
  2739. if (!fConnectivityChange)
  2740. {
  2741. //
  2742. // If there's not going to be a connectivity change, we
  2743. // will not try to update the IP address list.
  2744. //
  2745. refNewConfig.SetNetworkAddresses(NULL, 0);
  2746. if (refNewConfig.IsNlbBound())
  2747. {
  2748. refNewConfig.fAddClusterIps = TRUE;
  2749. refNewConfig.fAddDedicatedIp = TRUE;
  2750. }
  2751. }
  2752. //
  2753. // Notify the UI that we're going to start the update
  2754. //
  2755. {
  2756. m_pCallbacks->Log(
  2757. IUICallbacks::LOG_INFORMATIONAL,
  2758. szClusterIp,
  2759. szHostName,
  2760. IDS_LOG_BEGIN_HOST_UPDATE
  2761. );
  2762. m_pCallbacks->HandleEngineEvent(
  2763. IUICallbacks::OBJ_INTERFACE,
  2764. NULL, // ehClusterId,
  2765. ehInterfaceId,
  2766. IUICallbacks::EVT_STATUS_CHANGE
  2767. );
  2768. ProcessMsgQueue();
  2769. }
  2770. #if BUGFIX334243
  2771. BOOL fUpdateNow = FALSE;
  2772. #else // !BUGFIX334243
  2773. BOOL fUpdateNow = TRUE;
  2774. #endif // !BUGFIX334243
  2775. //
  2776. // We are committed to going through with the update now -- either
  2777. // sync or async.
  2778. //
  2779. InterlockedIncrement(&m_WorkItemCount);
  2780. fStopOperationOnExit = FALSE;
  2781. //
  2782. // We MUST call UpdateInterfaceWorItemRoutine now (either sync or async),
  2783. // which will stop the operation when done and also decrement
  2784. // m_mWorkItemCount.
  2785. //
  2786. if (!fUpdateNow)
  2787. {
  2788. BOOL fRet;
  2789. //
  2790. // We'll attempt to perform the update in the background ...
  2791. //
  2792. fRet = QueueUserWorkItem(
  2793. UpdateInterfaceWorkItemRoutine,
  2794. (PVOID) (UINT_PTR) ehInterfaceId,
  2795. WT_EXECUTELONGFUNCTION
  2796. );
  2797. if (fRet)
  2798. {
  2799. fUpdateNow = FALSE;
  2800. }
  2801. else
  2802. {
  2803. fUpdateNow = TRUE; // Update now if QueueUsesrWorkItem fails.
  2804. }
  2805. }
  2806. if (fUpdateNow)
  2807. {
  2808. //
  2809. // Call the work item synchronously
  2810. //
  2811. UpdateInterfaceWorkItemRoutine((LPVOID) (UINT_PTR) ehInterfaceId);
  2812. }
  2813. goto end;
  2814. end_unlock:
  2815. if (fStopOperationOnExit)
  2816. {
  2817. //
  2818. // We'll stop the operation, assumed to be started in this function.
  2819. //
  2820. mfn_StopInterfaceOperationLk(ehInterfaceId);
  2821. fStopOperationOnExit = FALSE;
  2822. }
  2823. mfn_Unlock();
  2824. end:
  2825. ASSERT(!fStopOperationOnExit);
  2826. TRACE_INFO(L"<- %!FUNC!");
  2827. return err;
  2828. }
  2829. NLBERROR
  2830. CNlbEngine::UpdateCluster(
  2831. IN ENGINEHANDLE ehClusterId,
  2832. IN const NLB_EXTENDED_CLUSTER_CONFIGURATION *pNewConfig OPTIONAL,
  2833. IN OUT CLocalLogger &logConflict
  2834. )
  2835. /*
  2836. Attempt to push all the cluster-wide (i.e. non-host-specific)
  2837. information on *pNewConfig to each host in the cluster.
  2838. Update the cluster's copy of NlbConfig to be *pNewConfig.
  2839. Set cluster's pending state on starting and set it
  2840. appropriately when done (could be misconfigured).
  2841. */
  2842. {
  2843. NLBERROR nerr = NLBERR_OK;
  2844. _bstr_t bstrClusterIp;
  2845. TRACE_INFO(L"-> %!FUNC!");
  2846. vector<ENGINEHANDLE> InterfaceListCopy;
  2847. BOOL fStopOperationOnExit = FALSE;
  2848. //
  2849. // First thing we do is to see if we can start the cluster operation...
  2850. //
  2851. if (pNewConfig != NULL)
  2852. {
  2853. BOOL fCanStart = FALSE;
  2854. nerr = this->CanStartClusterOperation(ehClusterId, REF fCanStart);
  2855. if (NLBFAILED(nerr))
  2856. {
  2857. goto end;
  2858. }
  2859. if (!fCanStart)
  2860. {
  2861. nerr = NLBERR_BUSY;
  2862. goto end;
  2863. }
  2864. }
  2865. {
  2866. mfn_Lock();
  2867. CClusterSpec *pCSpec = NULL;
  2868. CEngineCluster *pECluster = m_mapIdToEngineCluster[ehClusterId]; // map
  2869. if (pECluster == NULL)
  2870. {
  2871. nerr = NLBERR_NOT_FOUND;
  2872. goto end_unlock;
  2873. }
  2874. pCSpec = &pECluster->m_cSpec;
  2875. //
  2876. // Attempt to start the update operation -- will fail if there is
  2877. // already an operation started on this cluster.
  2878. //
  2879. {
  2880. ENGINEHANDLE ExistingOp= NULL;
  2881. CLocalLogger logDescription;
  2882. logDescription.Log(
  2883. IDS_LOG_UPDATE_CLUSTER_OPERATION_DESCRIPTION,
  2884. pCSpec->m_ClusterNlbCfg.NlbParams.cl_ip_addr
  2885. );
  2886. nerr = mfn_StartClusterOperationLk(
  2887. ehClusterId,
  2888. NULL, // pvCtxt
  2889. logDescription.GetStringSafe(),
  2890. &ExistingOp
  2891. );
  2892. if (NLBFAILED(nerr))
  2893. {
  2894. if (nerr == NLBERR_BUSY)
  2895. {
  2896. //
  2897. // This means that there was an existing operation.
  2898. // Let's get its description and add it to the log.
  2899. //
  2900. CEngineOperation *pExistingOp;
  2901. pExistingOp = mfn_GetOperationLk(ExistingOp);
  2902. if (pExistingOp != NULL)
  2903. {
  2904. LPCWSTR szDescrip = pExistingOp->bstrDescription;
  2905. if (szDescrip == NULL)
  2906. {
  2907. szDescrip = L"";
  2908. }
  2909. logConflict.Log(
  2910. IDS_LOG_OPERATION_PENDING_ON_CLUSTER,
  2911. szDescrip
  2912. );
  2913. }
  2914. }
  2915. goto end_unlock;
  2916. }
  2917. else
  2918. {
  2919. fStopOperationOnExit = TRUE;
  2920. }
  2921. }
  2922. if (pNewConfig != NULL)
  2923. {
  2924. pCSpec->m_ClusterNlbCfg.Update(pNewConfig); // TODO: error ret
  2925. //
  2926. // Note: Update above has the side effect of setting
  2927. // m_ClusterNlbCfg's szNewPassword field to NULL -- this is what
  2928. // we want. However, we do mark the fact that the
  2929. // password is new -- because the cluster's version of the
  2930. // hashed-password is now obsolete -- it needs to be updated
  2931. // by reading one of the hosts' versions.
  2932. // pCSpec->m_fNewRctPassword track this state.
  2933. //
  2934. if (pNewConfig->GetNewRemoteControlPasswordRaw() != NULL)
  2935. {
  2936. pCSpec->m_fNewRctPassword = TRUE;
  2937. //
  2938. // The above flag will be cleared (and the hashed password
  2939. // value updated) at the end of the
  2940. // first update operation for one of the interfaces.
  2941. //
  2942. // It is also cleared when the cluster properties are
  2943. // updated as part of a refresh operation.
  2944. //
  2945. }
  2946. }
  2947. bstrClusterIp = _bstr_t(pCSpec->m_ClusterNlbCfg.NlbParams.cl_ip_addr);
  2948. InterfaceListCopy = pCSpec->m_ehInterfaceIdList; // vector copy
  2949. mfn_Unlock();
  2950. }
  2951. m_pCallbacks->HandleEngineEvent(
  2952. IUICallbacks::OBJ_CLUSTER,
  2953. ehClusterId,
  2954. ehClusterId,
  2955. IUICallbacks::EVT_STATUS_CHANGE
  2956. );
  2957. ProcessMsgQueue();
  2958. mfn_Lock();
  2959. BOOL fRetryUpdateCluster = FALSE;
  2960. do
  2961. {
  2962. LPCWSTR szClusterIp = bstrClusterIp;
  2963. UINT uNumModeChanges = 0; // number of IF's undergoing mode changes.
  2964. UINT uNumUpdateErrors = 0; // number of IF's with update errors.
  2965. //
  2966. // fClusterPropertiesUpdated keeps track of whether the cluster
  2967. // properties were updated as a course of refreshing and or updating
  2968. // the interface -- we update the cluster props at most once:
  2969. // for the first interface that successfully performs the update
  2970. // (or if pNewConfig == NULL) for the first interface that
  2971. // successfully refreshes its properties AND is still bound.
  2972. //
  2973. //
  2974. BOOL fClusterPropertiesUpdated = FALSE;
  2975. //
  2976. // Update each interface in this cluster...
  2977. //
  2978. for( int i = 0; i < InterfaceListCopy.size(); ++i )
  2979. {
  2980. CInterfaceSpec TmpISpec;
  2981. _bstr_t bstrHostName = L"";
  2982. ENGINEHANDLE ehIId = InterfaceListCopy[i];
  2983. mfn_GetInterfaceHostNameLk(
  2984. ehIId,
  2985. REF bstrHostName
  2986. );
  2987. mfn_Unlock();
  2988. //
  2989. // Get the latest interface information and (if
  2990. // pNewConfig != NULL) merge in the cluster information.
  2991. //
  2992. {
  2993. BOOL fSkipHost = TRUE;
  2994. if (pNewConfig == NULL)
  2995. {
  2996. //
  2997. // This is a REFRESH CLUSTER operation
  2998. //
  2999. nerr = this->RefreshInterface(ehIId, TRUE, TRUE);
  3000. if (NLBOK(nerr))
  3001. {
  3002. //
  3003. // Let's update the cluster-wide properties with
  3004. // this interface if:
  3005. //
  3006. // 1. We haven't already updated the props in this
  3007. // loop.
  3008. //
  3009. // 2. The above interface is bound to NLB,
  3010. // and the IP address matches
  3011. // the clusters' ip address.
  3012. //
  3013. if (!fClusterPropertiesUpdated)
  3014. {
  3015. fClusterPropertiesUpdated = mfn_UpdateClusterProps(
  3016. ehClusterId,
  3017. ehIId
  3018. );
  3019. }
  3020. }
  3021. }
  3022. else
  3023. {
  3024. //
  3025. // This is a CHANGE CLUSTER CONFIGURATION operation
  3026. // Let's first get the latest version of this interface'
  3027. // properties.
  3028. //
  3029. nerr = this->mfn_RefreshInterface(ehIId);
  3030. }
  3031. //
  3032. // If this fails, we don't try to update. Instead
  3033. // we send a log message and continue.
  3034. // Note: RefreshInterface will send an interface-status
  3035. // change machine.
  3036. //
  3037. if (nerr == NLBERR_OK)
  3038. {
  3039. nerr = this->GetInterfaceSpec(ehIId, REF TmpISpec);
  3040. if (nerr == NLBERR_OK)
  3041. {
  3042. fSkipHost = FALSE;
  3043. }
  3044. }
  3045. if (!fSkipHost && pNewConfig != NULL)
  3046. {
  3047. if (pNewConfig->fBound)
  3048. {
  3049. NLB_EXTENDED_CLUSTER_CONFIGURATION *pOldConfig
  3050. = &TmpISpec.m_NlbCfg;
  3051. //
  3052. // Check if there is a mode change involved...
  3053. // because if so, the provider will not add
  3054. // any cluster IP addresses.
  3055. //
  3056. // We keep track of all IFs with mode changes, and
  3057. // if any, we'll do this whole cluster-wide update
  3058. // process a 2nd time, at which time the IP addresses
  3059. // will be added.
  3060. //
  3061. if (pOldConfig->IsValidNlbConfig())
  3062. {
  3063. NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE tmOld, tmNew;
  3064. tmOld = pOldConfig->GetTrafficMode();
  3065. tmNew = pNewConfig->GetTrafficMode();
  3066. if (tmOld != tmNew)
  3067. {
  3068. // Mode change!
  3069. uNumModeChanges++;
  3070. TRACE_INFO(L"%!FUNC!: ehIF 0x%lx: Detected mode change!\n", ehIId);
  3071. }
  3072. }
  3073. //
  3074. // Merge in the cluster-specific information
  3075. //
  3076. nerr = ApplyClusterWideConfiguration(
  3077. REF *pNewConfig,
  3078. REF TmpISpec.m_NlbCfg
  3079. );
  3080. if (nerr != NLBERR_OK)
  3081. {
  3082. fSkipHost = TRUE;
  3083. }
  3084. }
  3085. else
  3086. {
  3087. //
  3088. // We're asked to unbind all hosts!
  3089. //
  3090. TmpISpec.m_NlbCfg.fAddDedicatedIp = FALSE;
  3091. TmpISpec.m_NlbCfg.SetNetworkAddresses(NULL, 0);
  3092. TmpISpec.m_NlbCfg.SetNlbBound(FALSE);
  3093. if (!TmpISpec.m_NlbCfg.IsBlankDedicatedIp())
  3094. {
  3095. WCHAR rgBuf[64];
  3096. LPCWSTR szAddr = rgBuf;
  3097. StringCbPrintf(
  3098. rgBuf,
  3099. sizeof(rgBuf),
  3100. L"%ws/%ws",
  3101. TmpISpec.m_NlbCfg.NlbParams.ded_ip_addr,
  3102. TmpISpec.m_NlbCfg.NlbParams.ded_net_mask
  3103. );
  3104. TmpISpec.m_NlbCfg.SetNetworkAddresses(&szAddr, 1);
  3105. }
  3106. }
  3107. }
  3108. if (fSkipHost && pNewConfig != NULL)
  3109. {
  3110. TRACE_CRIT(L"%!FUNC!: Couldn't get latest interface spec when trying to update cluster");
  3111. m_pCallbacks->Log(
  3112. IUICallbacks::LOG_ERROR,
  3113. szClusterIp,
  3114. (LPCWSTR) bstrHostName,
  3115. IDS_LOG_SKIP_INTERFACE_UPDATE_ON_ERROR, // "...%lx"
  3116. nerr // TODO -- replace by textual description.
  3117. );
  3118. mfn_Lock();
  3119. uNumUpdateErrors++;
  3120. continue;
  3121. }
  3122. }
  3123. //
  3124. // Actually update the interface -- likely it will complete
  3125. // in the background.
  3126. //
  3127. if (pNewConfig != NULL)
  3128. {
  3129. CLocalLogger logConflict;
  3130. nerr = this->UpdateInterface(
  3131. ehIId,
  3132. REF TmpISpec.m_NlbCfg,
  3133. // REF fClusterPropertiesUpdated,
  3134. REF logConflict
  3135. );
  3136. }
  3137. mfn_Lock();
  3138. }
  3139. //
  3140. // If there are mode changes for one-or-more nodes, we'll need
  3141. // to wait for ALL updates to complete, and then try again.
  3142. //
  3143. if (uNumUpdateErrors!=0)
  3144. {
  3145. nerr = NLBERR_OPERATION_FAILED;
  3146. }
  3147. else
  3148. {
  3149. if (fRetryUpdateCluster && uNumModeChanges!=0)
  3150. {
  3151. //
  3152. // We're gone through a 2nd time and STILL there are
  3153. // mode changes! We bail.
  3154. //
  3155. TRACE_CRIT(L"%!FUNC! ehC 0x%lx: %lu Mode changes on 2nd phase. Bailing", ehClusterId, uNumModeChanges);
  3156. nerr = NLBERR_OPERATION_FAILED;
  3157. }
  3158. else
  3159. {
  3160. nerr = NLBERR_OK;
  3161. }
  3162. }
  3163. fRetryUpdateCluster = FALSE;
  3164. if (NLBOK(nerr) && uNumModeChanges!=0)
  3165. {
  3166. BOOL fSameMode = FALSE;
  3167. //
  3168. // There were one or more mode changes!
  3169. // Let's wait for *all* updates to complete successfully.
  3170. // Then we'll check to make sure that the modes on all
  3171. // hosts match the cluster IP address' modes. If they do
  3172. // (and there were no update errors), we'll re-run the
  3173. // update process, this time hopefully adding
  3174. // the IP addresses that would have been stripped had there been
  3175. // mode changes.
  3176. //
  3177. mfn_Unlock();
  3178. nerr = mfn_WaitForInterfaceOperationCompletions(ehClusterId);
  3179. mfn_Lock();
  3180. if (NLBOK(nerr))
  3181. {
  3182. nerr = mfn_VerifySameModeLk(ehClusterId, REF fSameMode);
  3183. }
  3184. if (NLBOK(nerr) && fSameMode)
  3185. {
  3186. TRACE_CRIT(L"%!FUNC! chC 0x%lx: SECOND PHASE on CHANGE MODE",
  3187. ehClusterId);
  3188. fRetryUpdateCluster = TRUE;
  3189. }
  3190. }
  3191. if (uNumModeChanges && NLBFAILED(nerr))
  3192. {
  3193. mfn_Unlock();
  3194. //
  3195. // There was a problem, log it, as well as the list of
  3196. // cluster IP addresses/subnets.
  3197. // TODO: add details.
  3198. //
  3199. m_pCallbacks->Log(
  3200. IUICallbacks::LOG_INFORMATIONAL,
  3201. szClusterIp,
  3202. NULL,
  3203. IDS_LOG_ERRORS_DETECTED_DURING_MODE_CHANGE
  3204. );
  3205. mfn_Lock();
  3206. }
  3207. } while (NLBOK(nerr) && fRetryUpdateCluster);
  3208. //
  3209. // We're done -- set the cluster's fPending field to false, and if
  3210. // necessary (if no interfaces) delete the cluster.
  3211. //
  3212. {
  3213. BOOL fEmptyCluster = FALSE;
  3214. CClusterSpec *pCSpec = NULL;
  3215. CEngineCluster *pECluster = m_mapIdToEngineCluster[ehClusterId]; // map
  3216. if (pECluster == NULL)
  3217. {
  3218. nerr = NLBERR_NOT_FOUND;
  3219. goto end_unlock;
  3220. }
  3221. pCSpec = &pECluster->m_cSpec;
  3222. fEmptyCluster = (pCSpec->m_ehInterfaceIdList.size()==0);
  3223. ASSERT(fStopOperationOnExit);
  3224. mfn_StopClusterOperationLk(ehClusterId);
  3225. fStopOperationOnExit = FALSE;
  3226. mfn_Unlock();
  3227. if (fEmptyCluster)
  3228. {
  3229. //
  3230. // The cluster is empty -- delete it.
  3231. //
  3232. this->DeleteCluster(ehClusterId, FALSE); // FALSE == don't remove IF
  3233. }
  3234. else
  3235. {
  3236. m_pCallbacks->HandleEngineEvent(
  3237. IUICallbacks::OBJ_CLUSTER,
  3238. ehClusterId,
  3239. ehClusterId,
  3240. IUICallbacks::EVT_STATUS_CHANGE
  3241. );
  3242. ProcessMsgQueue();
  3243. }
  3244. mfn_Lock();
  3245. }
  3246. // fall through ...
  3247. end_unlock:
  3248. if (fStopOperationOnExit)
  3249. {
  3250. //
  3251. // We'll stop the operation, assumed to be started in this function.
  3252. //
  3253. mfn_StopClusterOperationLk(ehClusterId);
  3254. }
  3255. mfn_Unlock();
  3256. if (fStopOperationOnExit)
  3257. {
  3258. m_pCallbacks->HandleEngineEvent(
  3259. IUICallbacks::OBJ_CLUSTER,
  3260. ehClusterId,
  3261. ehClusterId,
  3262. IUICallbacks::EVT_STATUS_CHANGE
  3263. );
  3264. ProcessMsgQueue();
  3265. fStopOperationOnExit = FALSE;
  3266. }
  3267. end:
  3268. ASSERT(!fStopOperationOnExit);
  3269. TRACE_INFO(L"<- %!FUNC!");
  3270. return nerr;
  3271. }
  3272. NLBERROR
  3273. CNlbEngine::GetClusterSpec(
  3274. IN ENGINEHANDLE ehClusterId,
  3275. OUT CClusterSpec& refClusterSpec
  3276. )
  3277. {
  3278. // TRACE_INFO(L"-> %!FUNC!");
  3279. NLBERROR err = NLBERR_OK;
  3280. mfn_Lock();
  3281. CEngineCluster *pECluster = m_mapIdToEngineCluster[ehClusterId]; // map
  3282. if (pECluster == NULL)
  3283. {
  3284. err = NLBERR_INTERFACE_NOT_FOUND;
  3285. }
  3286. else
  3287. {
  3288. //
  3289. // This is really an assert condition -- the cluster spec should
  3290. // NEVER have a non-blank dedicated IP address.
  3291. //
  3292. if (!pECluster->m_cSpec.m_ClusterNlbCfg.IsBlankDedicatedIp())
  3293. {
  3294. err = NLBERR_INTERNAL_ERROR;
  3295. TRACE_CRIT(L"%!FUNC! unexpected: cluster eh 0x%lx has non-blank ded-ip!", ehClusterId);
  3296. }
  3297. else
  3298. {
  3299. refClusterSpec.Copy(pECluster->m_cSpec);
  3300. }
  3301. }
  3302. mfn_Unlock();
  3303. // TRACE_INFO(L"<- %!FUNC!");
  3304. return err;
  3305. }
  3306. NLBERROR
  3307. CNlbEngine::GetHostSpec(
  3308. IN ENGINEHANDLE ehHostId,
  3309. OUT CHostSpec& refHostSpec
  3310. )
  3311. {
  3312. NLBERROR err = NLBERR_OK;
  3313. // TRACE_INFO(L"-> %!FUNC!(0x%lx)", (UINT)ehHostId);
  3314. mfn_Lock();
  3315. CHostSpec *pHSpec = m_mapIdToHostSpec[ehHostId]; // map
  3316. if (pHSpec == NULL)
  3317. {
  3318. err = NLBERR_INTERFACE_NOT_FOUND;
  3319. }
  3320. else
  3321. {
  3322. refHostSpec.Copy(*pHSpec);
  3323. }
  3324. if (err != NLBERR_OK)
  3325. {
  3326. TRACE_INFO(
  3327. L"<- %!FUNC!(0x%lx) Host not found",
  3328. ehHostId
  3329. );
  3330. }
  3331. mfn_Unlock();
  3332. return err;
  3333. }
  3334. NLBERROR
  3335. CNlbEngine::GetHostConnectionInformation(
  3336. IN ENGINEHANDLE ehHost,
  3337. OUT ENGINEHANDLE &ehConnectionIF,
  3338. OUT _bstr_t &bstrConnectionString,
  3339. OUT UINT &uConnectionIp
  3340. )
  3341. /*
  3342. For the specified host ehHost,
  3343. Look up it's connection IP, and search all its interfaces
  3344. for the specific connection IP.
  3345. Return the found interface handle, connection string and connection IP.
  3346. */
  3347. {
  3348. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  3349. CHostSpec *pHSpec = NULL;
  3350. mfn_Lock();
  3351. pHSpec = m_mapIdToHostSpec[ehHost]; // map
  3352. if (pHSpec == NULL)
  3353. {
  3354. nerr = NLBERR_NOT_FOUND;
  3355. goto end_unlock;
  3356. }
  3357. //
  3358. // Lookup the interface that has the connection IP
  3359. //
  3360. uConnectionIp = pHSpec->m_ConnectionIpAddress;
  3361. if (uConnectionIp != 0)
  3362. {
  3363. WCHAR rgIp[128];
  3364. LPBYTE pb = (LPBYTE) &uConnectionIp;
  3365. StringCbPrintf(
  3366. rgIp,
  3367. sizeof(rgIp),
  3368. L"%lu.%lu.%lu.%lu",
  3369. pb[0], pb[1], pb[2], pb[3]
  3370. );
  3371. nerr = mfn_LookupInterfaceByIpLk(ehHost, rgIp, REF ehConnectionIF);
  3372. }
  3373. if (NLBOK(nerr))
  3374. {
  3375. bstrConnectionString = pHSpec->m_ConnectionString;
  3376. }
  3377. else
  3378. {
  3379. ehConnectionIF = NULL;
  3380. uConnectionIp = 0;
  3381. }
  3382. end_unlock:
  3383. mfn_Unlock();
  3384. return nerr;
  3385. }
  3386. NLBERROR
  3387. CNlbEngine::EnumerateClusters(
  3388. OUT vector <ENGINEHANDLE> & ClusterIdList
  3389. )
  3390. {
  3391. TRACE_INFO(L"-> %!FUNC!");
  3392. mfn_Lock();
  3393. map< ENGINEHANDLE, CEngineCluster* >::iterator iCluster;
  3394. ClusterIdList.clear();
  3395. for (iCluster = m_mapIdToEngineCluster.begin();
  3396. iCluster != m_mapIdToEngineCluster.end();
  3397. iCluster++)
  3398. {
  3399. ENGINEHANDLE ehClusterId = (*iCluster).first;
  3400. if (m_mapIdToEngineCluster[ehClusterId])
  3401. ClusterIdList.push_back(ehClusterId);
  3402. }
  3403. mfn_Unlock();
  3404. TRACE_INFO(L"<- %!FUNC!");
  3405. return NLBERR_OK;
  3406. }
  3407. NLBERROR
  3408. CNlbEngine::EnumerateHosts(
  3409. OUT vector <ENGINEHANDLE> & HostIdList
  3410. )
  3411. {
  3412. TRACE_INFO(L"-> %!FUNC!");
  3413. // TODO
  3414. TRACE_INFO(L"<- %!FUNC!");
  3415. return NLBERR_OK;
  3416. }
  3417. NLBERROR
  3418. CNlbEngine::GetAllHostConnectionStrings(
  3419. OUT vector <_bstr_t> & ConnectionStringList
  3420. )
  3421. //
  3422. // Actually only returns the strings for hosts that have at least one
  3423. // interface that is part of a cluster that is displayed by NLB Manager.
  3424. // (see .net server bug 499068)
  3425. //
  3426. {
  3427. TRACE_INFO(L"-> %!FUNC!");
  3428. mfn_Lock();
  3429. map< ENGINEHANDLE, CHostSpec* >::iterator iter;
  3430. for( iter = m_mapIdToHostSpec.begin();
  3431. iter != m_mapIdToHostSpec.end();
  3432. ++iter)
  3433. {
  3434. CHostSpec *pHSpec = (CHostSpec *) ((*iter).second);
  3435. if (pHSpec != NULL)
  3436. {
  3437. if (mfn_HostHasManagedClustersLk(pHSpec))
  3438. {
  3439. ConnectionStringList.push_back(pHSpec->m_ConnectionString);
  3440. }
  3441. }
  3442. }
  3443. mfn_Unlock();
  3444. TRACE_INFO(L"<- %!FUNC!");
  3445. return NLBERR_OK;
  3446. }
  3447. BOOL
  3448. CNlbEngine::GetObjectType(
  3449. IN ENGINEHANDLE ehObj,
  3450. OUT IUICallbacks::ObjectType &objType
  3451. )
  3452. {
  3453. BOOL fRet = FALSE;
  3454. UINT uType;
  3455. objType = IUICallbacks::OBJ_INVALID;
  3456. if (ehObj == NULL)
  3457. {
  3458. goto end;
  3459. }
  3460. //
  3461. // Extract object type -- the first TYPE_BIT_COUNT bits of ehObj.
  3462. //
  3463. uType = ((UINT) ehObj) & (0xffffffff>>(32-TYPE_BIT_COUNT));
  3464. mfn_Lock();
  3465. switch(uType)
  3466. {
  3467. case IUICallbacks::OBJ_INTERFACE:
  3468. if (m_mapIdToInterfaceSpec[ehObj] != NULL)
  3469. {
  3470. objType = IUICallbacks::OBJ_INTERFACE;
  3471. fRet = TRUE;
  3472. }
  3473. break;
  3474. case IUICallbacks::OBJ_CLUSTER:
  3475. if (m_mapIdToEngineCluster[ehObj] != NULL)
  3476. {
  3477. objType = IUICallbacks::OBJ_CLUSTER;
  3478. fRet = TRUE;
  3479. }
  3480. break;
  3481. case IUICallbacks::OBJ_HOST:
  3482. if (m_mapIdToHostSpec[ehObj] != NULL)
  3483. {
  3484. objType = IUICallbacks::OBJ_HOST;
  3485. fRet = TRUE;
  3486. }
  3487. break;
  3488. case IUICallbacks::OBJ_OPERATION:
  3489. if (m_mapIdToOperation[ehObj] != NULL)
  3490. {
  3491. objType = IUICallbacks::OBJ_OPERATION;
  3492. fRet = TRUE;
  3493. }
  3494. break;
  3495. default:
  3496. break;
  3497. }
  3498. mfn_Unlock();
  3499. end:
  3500. return fRet;
  3501. }
  3502. //
  3503. // Return a bitmap of available host IDs for the specified cluster.
  3504. //
  3505. ULONG
  3506. CNlbEngine::GetAvailableHostPriorities(
  3507. ENGINEHANDLE ehCluster // OPTIONAL
  3508. )
  3509. {
  3510. ULONG UsedPriorities = 0;
  3511. mfn_Lock();
  3512. do // while false
  3513. {
  3514. if (ehCluster == NULL) break;
  3515. CEngineCluster *pECluster = m_mapIdToEngineCluster[ehCluster]; // map
  3516. if (pECluster == NULL) break;
  3517. //
  3518. // For each interface,
  3519. // build up a bitmap of used priorities. Return the inverse of that
  3520. // bitmap.
  3521. //
  3522. for( int i = 0; i < pECluster->m_cSpec.m_ehInterfaceIdList.size(); ++i )
  3523. {
  3524. ENGINEHANDLE ehIId = pECluster->m_cSpec.m_ehInterfaceIdList[i];
  3525. CInterfaceSpec *pISpec = m_mapIdToInterfaceSpec[ehIId]; // map
  3526. if (pISpec == NULL)
  3527. {
  3528. TRACE_CRIT("%!FUNC! no interface in ehC 0x%x for ehI 0x%x",
  3529. ehCluster, ehIId);
  3530. continue;
  3531. }
  3532. if (pISpec->m_NlbCfg.IsValidNlbConfig())
  3533. {
  3534. UINT HostPriority = pISpec->m_NlbCfg.NlbParams.host_priority;
  3535. UsedPriorities |= (1<<(HostPriority-1));
  3536. }
  3537. }
  3538. } while (FALSE);
  3539. mfn_Unlock();
  3540. return ~UsedPriorities;
  3541. }
  3542. //
  3543. // Fill in an array of bitmaps of available priorities for each specified
  3544. // port rule. The port rule must be valid.
  3545. // If a port rule is not single-host-priority, the bitmap for that
  3546. // port rule is undefined.
  3547. //
  3548. NLBERROR
  3549. CNlbEngine::GetAvailablePortRulePriorities(
  3550. IN ENGINEHANDLE ehCluster, OPTIONAL
  3551. IN UINT NumRules,
  3552. IN WLBS_PORT_RULE rgRules[],
  3553. IN OUT ULONG rgAvailablePriorities[] // At least NumRules
  3554. )
  3555. {
  3556. //
  3557. // If ehCluster==NULL, set all to 0xffffffff
  3558. //
  3559. // For each interface, locate the specified port rules (based on vip and
  3560. // start port) and build up a bitmap of used priorities.
  3561. // fill in rgRules with the inverse of the bitmaps.
  3562. //
  3563. // Todo Account for priorities of pending operations.
  3564. //
  3565. mfn_Lock();
  3566. //
  3567. // We initially use rgAvailablePriorities to store USED priorities.
  3568. // Intialize to 0.
  3569. //
  3570. for (UINT u=0; u<NumRules; u++)
  3571. {
  3572. rgAvailablePriorities[u] = 0;
  3573. }
  3574. do // while false
  3575. {
  3576. ULONG *rgUsedPriorities = rgAvailablePriorities;
  3577. if (ehCluster == NULL) break;
  3578. CEngineCluster *pECluster = m_mapIdToEngineCluster[ehCluster]; // map
  3579. if (pECluster == NULL) break;
  3580. //
  3581. // For each interface, locate the specified port rule and
  3582. // build up a bitmap of used priorities. Return the inverse of that
  3583. // bitmap.
  3584. //
  3585. for( int i = 0; i < pECluster->m_cSpec.m_ehInterfaceIdList.size(); ++i )
  3586. {
  3587. ENGINEHANDLE ehIId = pECluster->m_cSpec.m_ehInterfaceIdList[i];
  3588. CInterfaceSpec *pISpec = m_mapIdToInterfaceSpec[ehIId]; // map
  3589. if (pISpec == NULL)
  3590. {
  3591. TRACE_CRIT("%!FUNC! no interface in ehC 0x%x for ehI 0x%x",
  3592. ehCluster, ehIId);
  3593. continue;
  3594. }
  3595. if (pISpec->m_NlbCfg.IsValidNlbConfig())
  3596. {
  3597. //
  3598. // get_used_port_rule_priorities will add its priority
  3599. // to the bitmap of each single-host port rule.
  3600. //
  3601. (void) get_used_port_rule_priorities(
  3602. REF pISpec->m_NlbCfg,
  3603. NumRules,
  3604. rgRules,
  3605. rgUsedPriorities
  3606. );
  3607. }
  3608. }
  3609. } while (FALSE);
  3610. //
  3611. // We initially used rgAvailablePriorities to store USED priorities.
  3612. // So invert each.
  3613. //
  3614. for (UINT u=0; u<NumRules; u++)
  3615. {
  3616. rgAvailablePriorities[u] = ~rgAvailablePriorities[u];
  3617. }
  3618. mfn_Unlock();
  3619. return NLBERR_OK;
  3620. }
  3621. NLBERROR
  3622. CNlbEngine::mfn_GetHostFromInterfaceLk(
  3623. IN ENGINEHANDLE ehIId,
  3624. OUT CInterfaceSpec* &pISpec,
  3625. OUT CHostSpec* &pHSpec
  3626. )
  3627. {
  3628. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  3629. pHSpec = NULL;
  3630. pISpec = m_mapIdToInterfaceSpec[ehIId]; // map
  3631. if (pISpec == NULL)
  3632. {
  3633. nerr = NLBERR_NOT_FOUND;
  3634. }
  3635. else
  3636. {
  3637. ENGINEHANDLE ehHost = pISpec->m_ehHostId;
  3638. pHSpec = m_mapIdToHostSpec[ehHost]; // map
  3639. nerr = NLBERR_OK;
  3640. }
  3641. return nerr;
  3642. }
  3643. void
  3644. CNlbEngine::mfn_GetInterfaceHostNameLk(
  3645. ENGINEHANDLE ehIId,
  3646. _bstr_t &bstrHostName
  3647. )
  3648. /*
  3649. This function returns the host name of the specified interface.
  3650. It sets bstrHostName to "" (not NULL) on error.
  3651. */
  3652. {
  3653. NLBERROR nerr;
  3654. _bstr_t *pName = NULL;
  3655. CHostSpec *pHSpec = NULL;
  3656. CInterfaceSpec *pISpec = NULL;
  3657. nerr = CNlbEngine::mfn_GetHostFromInterfaceLk(ehIId,REF pISpec, REF pHSpec);
  3658. if (nerr == NLBERR_OK)
  3659. {
  3660. pName = &pHSpec->m_MachineName;
  3661. }
  3662. if (pName == NULL)
  3663. {
  3664. bstrHostName = _bstr_t(L"");
  3665. }
  3666. else
  3667. {
  3668. bstrHostName = *pName;
  3669. }
  3670. }
  3671. ENGINEHANDLE
  3672. CNlbEngine::mfn_NewHandleLk(IUICallbacks::ObjectType type)
  3673. //
  3674. // Returns a unique number from 1 to 2^31-1 (1 to ~ 2 billion).
  3675. // If it is called more than 2 billion times it will start returning zero
  3676. // from then onwards.
  3677. //
  3678. {
  3679. ULONG uVal =0;
  3680. if (m_fPrepareToDeinitialize)
  3681. {
  3682. goto end;
  3683. }
  3684. if ((UINT)type >= (1<<TYPE_BIT_COUNT))
  3685. {
  3686. TRACE_CRIT(L"%!FUNC!: Invalid obj type");
  3687. goto end;
  3688. }
  3689. if (!m_fHandleOverflow)
  3690. {
  3691. uVal = (ULONG) InterlockedIncrement(&m_NewHandleValue);
  3692. //
  3693. // uVal could be less than 2^(32-TypeBitCount)) to save
  3694. // so that it doesn't over flow when we shift it by TypeBitCounts.
  3695. //
  3696. // Extreme cases: if TypeBitCount==32, uVal should be less
  3697. // then 1<<0, or 1 -- so it can only have one value 0.
  3698. //
  3699. // If TypeBitCount==0, uVal should be less than 1<<32, i.e., any
  3700. // valid uint value.
  3701. //
  3702. if (uVal >= (1<<(32-TYPE_BIT_COUNT)))
  3703. {
  3704. //
  3705. // Overflow!!!
  3706. //
  3707. TRACE_CRIT(L"%!FUNC!: Handle overflow!");
  3708. m_fHandleOverflow = TRUE;
  3709. uVal = 0;
  3710. goto end;
  3711. }
  3712. //
  3713. // Construct the handle by compositing the type and the counter value.
  3714. //
  3715. uVal = ((uVal<<TYPE_BIT_COUNT) | (UINT) type);
  3716. }
  3717. end:
  3718. return (ENGINEHANDLE) uVal;
  3719. }
  3720. NLBERROR
  3721. CNlbEngine::ApplyClusterWideConfiguration(
  3722. IN const NLB_EXTENDED_CLUSTER_CONFIGURATION &ClusterConfig,
  3723. IN OUT NLB_EXTENDED_CLUSTER_CONFIGURATION &ConfigToUpdate
  3724. )
  3725. /*
  3726. Apply only the cluster-wide parameters in ClusterConfig to
  3727. ConfigToUpdate.
  3728. When updateing port rules, try to preserve the host-specific info
  3729. (load weight, host priority).
  3730. NOTE: It WILL replace the ConfigToUpdate's list of IP addresses with
  3731. the list of IP addresses in ClusterConfig. This will REMOVE the
  3732. dedicated IP address from the list of IP addresses. The dedicated IP
  3733. address will be added before the interface is actually updated -- in
  3734. CNlbEngine::UpdateInterface.
  3735. WLBS_REG_PARAMS cluster-wide params...
  3736. BOOL fRctEnabled
  3737. BOOL fMcastSupport
  3738. BOOL fIGMPSupport
  3739. TCHAR cl_ip_addr[CVY_MAX_CL_IP_ADDR + 1]
  3740. TCHAR cl_net_mask[CVY_MAX_CL_NET_MASK + 1]
  3741. TCHAR domain_name[CVY_MAX_DOMAIN_NAME + 1]
  3742. bool fChangePassword
  3743. TCHAR szPassword[CVY_MAX_RCT_CODE + 1]
  3744. DWORD dwNumRules
  3745. NETCFG_WLBS_PORT_RULE port_rules[CVY_MAX_RULES]
  3746. */
  3747. {
  3748. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  3749. WLBS_PORT_RULE *pOldRules = NULL;
  3750. WLBS_PORT_RULE *pNewRules = NULL;
  3751. if (!ClusterConfig.fBound || !validate_extcfg(ClusterConfig))
  3752. {
  3753. TRACE_CRIT("%!FUNC! -- cluster configuration is invalid!");
  3754. goto end;
  3755. }
  3756. if(!ConfigToUpdate.IsValidNlbConfig())
  3757. {
  3758. //
  3759. // We expect the configuration to be valid -- i.e., NLB bound, with
  3760. // valid parameters.
  3761. //
  3762. TRACE_CRIT("%!FUNC! -- current configuration is unbound/invalid!");
  3763. goto end;
  3764. }
  3765. ConfigToUpdate.NlbParams.rct_enabled = ClusterConfig.NlbParams.rct_enabled;
  3766. ConfigToUpdate.NlbParams.mcast_support = ClusterConfig.NlbParams.mcast_support;
  3767. ConfigToUpdate.NlbParams.fIGMPSupport = ClusterConfig.NlbParams.fIGMPSupport;
  3768. CopyMemory(
  3769. ConfigToUpdate.NlbParams.cl_ip_addr,
  3770. ClusterConfig.NlbParams.cl_ip_addr,
  3771. sizeof(ConfigToUpdate.NlbParams.cl_ip_addr)
  3772. );
  3773. CopyMemory(
  3774. ConfigToUpdate.NlbParams.cl_net_mask,
  3775. ClusterConfig.NlbParams.cl_net_mask,
  3776. sizeof(ConfigToUpdate.NlbParams.cl_net_mask)
  3777. );
  3778. CopyMemory(
  3779. ConfigToUpdate.NlbParams.domain_name,
  3780. ClusterConfig.NlbParams.domain_name,
  3781. sizeof(ConfigToUpdate.NlbParams.domain_name)
  3782. );
  3783. //
  3784. // TODO -- we need to preserve Ip addresses and their order in
  3785. // hosts, as far as possible. For now we decide the order.
  3786. //
  3787. {
  3788. BOOL fRet = FALSE;
  3789. NlbIpAddressList addrList;
  3790. fRet = addrList.Set(ClusterConfig.NumIpAddresses,
  3791. ClusterConfig.pIpAddressInfo, 0);
  3792. if (!fRet)
  3793. {
  3794. TRACE_CRIT(L"Could not copy over ip addresses!");
  3795. goto end;
  3796. }
  3797. ConfigToUpdate.SetNetworkAddressesRaw(NULL,0);
  3798. addrList.Extract(
  3799. REF ConfigToUpdate.NumIpAddresses,
  3800. REF ConfigToUpdate.pIpAddressInfo
  3801. );
  3802. }
  3803. // password -- copy and set some flag only if changed.
  3804. {
  3805. LPCWSTR szNewPassword = NULL;
  3806. szNewPassword = ClusterConfig.GetNewRemoteControlPasswordRaw();
  3807. //
  3808. // Note: szNewPassword will be NULL UNLESS the user has explicitly
  3809. // specified a new password.
  3810. //
  3811. ConfigToUpdate.SetNewRemoteControlPassword(szNewPassword);
  3812. }
  3813. //
  3814. // Fold in port rules.
  3815. //
  3816. {
  3817. UINT NumOldRules=0;
  3818. UINT NumNewRules=0;
  3819. WBEMSTATUS wStat;
  3820. wStat = CfgUtilGetPortRules(
  3821. &ConfigToUpdate.NlbParams,
  3822. &pOldRules,
  3823. &NumOldRules
  3824. );
  3825. if (FAILED(wStat))
  3826. {
  3827. TRACE_CRIT("%!FUNC! error 0x%08lx extracting old port rules!", wStat);
  3828. pOldRules=NULL;
  3829. goto end;
  3830. }
  3831. wStat = CfgUtilGetPortRules(
  3832. &ClusterConfig.NlbParams,
  3833. &pNewRules,
  3834. &NumNewRules
  3835. );
  3836. if (FAILED(wStat))
  3837. {
  3838. TRACE_CRIT("%!FUNC! error 0x%08lx extracting new port rules!", wStat);
  3839. pNewRules = NULL;
  3840. goto end;
  3841. }
  3842. //
  3843. // Now for each new port rule, if it makes sense, pick up
  3844. // host-specific info from old port rules.
  3845. //
  3846. for (UINT u=0; u<NumNewRules;u++)
  3847. {
  3848. WLBS_PORT_RULE *pNewRule = pNewRules+u;
  3849. const WLBS_PORT_RULE *pOldRule = NULL; // mapStartPortToOldRule[pNewRule->start_port];
  3850. UINT NewMode = pNewRule->mode;
  3851. pOldRule = find_port_rule(
  3852. pOldRules,
  3853. NumOldRules,
  3854. pNewRule->virtual_ip_addr,
  3855. pNewRule->start_port
  3856. );
  3857. if (NewMode != CVY_NEVER)
  3858. {
  3859. //
  3860. // We need to fill in host-specific stuff
  3861. //
  3862. if (pOldRule!=NULL && pOldRule->mode == NewMode)
  3863. {
  3864. //
  3865. // We can pick up the old rule's info.
  3866. //
  3867. if (NewMode == CVY_MULTI)
  3868. {
  3869. //
  3870. // We ignore the cluster's equal_load and
  3871. // load fields.
  3872. //
  3873. pNewRule->mode_data.multi.equal_load =
  3874. pOldRule->mode_data.multi.equal_load;
  3875. pNewRule->mode_data.multi.load =
  3876. pOldRule->mode_data.multi.load;
  3877. }
  3878. else if (NewMode == CVY_SINGLE)
  3879. {
  3880. //
  3881. // TODO: priorities can potentially clash here.
  3882. //
  3883. pNewRule->mode_data.single.priority =
  3884. pOldRule->mode_data.single.priority;
  3885. }
  3886. }
  3887. else
  3888. {
  3889. //
  3890. // We need to pick defaults.
  3891. //
  3892. if (NewMode == CVY_MULTI)
  3893. {
  3894. pNewRule->mode_data.multi.equal_load = TRUE; //default
  3895. pNewRule->mode_data.multi.load = 50;
  3896. }
  3897. else if (NewMode == CVY_SINGLE)
  3898. {
  3899. //
  3900. // TODO: need to pick a new priority here!
  3901. // for now we pick the host's priority -- but
  3902. // we need to really pick one that
  3903. // doesn't clash!
  3904. //
  3905. pNewRule->mode_data.single.priority =
  3906. ConfigToUpdate.NlbParams.host_priority;
  3907. }
  3908. }
  3909. }
  3910. }
  3911. //
  3912. // Finally, set the new port rules..
  3913. //
  3914. wStat = CfgUtilSetPortRules(
  3915. pNewRules,
  3916. NumNewRules,
  3917. &ConfigToUpdate.NlbParams
  3918. );
  3919. if (FAILED(wStat))
  3920. {
  3921. TRACE_CRIT("%!FUNC! error 0x%08lx setting new port rules!", wStat);
  3922. goto end;
  3923. }
  3924. nerr = NLBERR_OK;
  3925. }
  3926. end:
  3927. delete pOldRules; // can be NULL
  3928. delete pNewRules; // can be NULL
  3929. return nerr;
  3930. }
  3931. NLBERROR
  3932. CNlbEngine::mfn_RefreshHost(
  3933. IN PWMI_CONNECTION_INFO pConnInfo,
  3934. IN ENGINEHANDLE ehHost,
  3935. IN BOOL fOverwriteConnectionInfo
  3936. )
  3937. {
  3938. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  3939. LPWSTR *pszNics = NULL;
  3940. UINT NumNics = 0;
  3941. UINT NumNlbBound = 0;
  3942. WBEMSTATUS wStatus = WBEM_E_CRITICAL_ERROR;
  3943. CHostSpec *pHost = NULL;
  3944. vector<ENGINEHANDLE> InterfaceListCopy;
  3945. wStatus = NlbHostGetCompatibleNics(
  3946. pConnInfo,
  3947. &pszNics,
  3948. &NumNics,
  3949. &NumNlbBound
  3950. );
  3951. if (FAILED(wStatus))
  3952. {
  3953. pszNics = NULL;
  3954. // TODO -- check for authentication failure -- ask for new creds.
  3955. }
  3956. //
  3957. // Update the connection string, IP, and status of the host.
  3958. //
  3959. {
  3960. mfn_Lock();
  3961. pHost = m_mapIdToHostSpec[ehHost]; // map
  3962. if (pHost != NULL)
  3963. {
  3964. pHost->m_fReal = TRUE;
  3965. if (fOverwriteConnectionInfo)
  3966. {
  3967. pHost->m_ConnectionString = _bstr_t(pConnInfo->szMachine);
  3968. pHost->m_UserName = _bstr_t(pConnInfo->szUserName);
  3969. pHost->m_Password = _bstr_t(pConnInfo->szPassword);
  3970. }
  3971. if (FAILED(wStatus))
  3972. {
  3973. pHost->m_fUnreachable = TRUE;
  3974. }
  3975. else
  3976. {
  3977. pHost->m_fUnreachable = FALSE;
  3978. }
  3979. }
  3980. pHost = NULL;
  3981. mfn_Unlock();
  3982. }
  3983. //
  3984. // Update that status of all interfaces in the host.
  3985. //
  3986. mfn_NotifyHostInterfacesChange(ehHost);
  3987. if (FAILED(wStatus))
  3988. {
  3989. // TODO -- proper return error.
  3990. goto end;
  3991. }
  3992. //
  3993. // We first go through and add all the interfaces-
  3994. //
  3995. mfn_Lock();
  3996. pHost = m_mapIdToHostSpec[ehHost]; // map
  3997. if (pHost == NULL)
  3998. {
  3999. mfn_Unlock();
  4000. goto end;
  4001. }
  4002. for (UINT u=0; u<NumNics; u++)
  4003. {
  4004. LPCWSTR szNic = pszNics[u];
  4005. ENGINEHANDLE ehInterface = NULL;
  4006. CInterfaceSpec *pISpec = NULL;
  4007. BOOL fIsNew = FALSE;
  4008. nerr = mfn_LookupInterfaceByGuidLk(
  4009. szNic,
  4010. TRUE, // TRUE==ok to create
  4011. REF ehInterface,
  4012. REF pISpec,
  4013. REF fIsNew
  4014. );
  4015. if (nerr == NLBERR_OK)
  4016. {
  4017. if (fIsNew)
  4018. {
  4019. //
  4020. // We've just created a brand new interface object.
  4021. // Add it to the host's list of interfaces, and
  4022. // add a reference to this host in the interface object.
  4023. //
  4024. pISpec->m_ehHostId = ehHost;
  4025. pISpec->m_fReal = FALSE; // we'll update this later.
  4026. pHost->m_ehInterfaceIdList.push_back(ehInterface);
  4027. }
  4028. //
  4029. // Keep a copy of the machine name in the interface.
  4030. // Here we'll update if it's changed -- could happen if
  4031. // host's machine name has changed while NLB manager is still
  4032. // running.
  4033. //
  4034. if (pISpec->m_bstrMachineName != pHost->m_MachineName) // bstr
  4035. {
  4036. pISpec->m_bstrMachineName = pHost->m_MachineName; // bstr
  4037. }
  4038. }
  4039. }
  4040. InterfaceListCopy = pHost->m_ehInterfaceIdList; // vector copy
  4041. pHost = NULL;
  4042. mfn_Unlock();
  4043. //
  4044. // Having added any new interfaces, we now we go through
  4045. // ALL interfaces in the host, refreshing them -- potentially getting
  4046. // rid of ones which are no longer in the host.
  4047. //
  4048. for(u = 0; u < InterfaceListCopy.size(); ++u )
  4049. {
  4050. ENGINEHANDLE ehIId = InterfaceListCopy[u];
  4051. (void) this->RefreshInterface(
  4052. ehIId,
  4053. TRUE, // TRUE == start a new operation
  4054. FALSE // FALSE == this is not cluster-wide
  4055. );
  4056. }
  4057. nerr = NLBERR_OK;
  4058. end:
  4059. delete pszNics;
  4060. return nerr;
  4061. }
  4062. NLBERROR
  4063. CNlbEngine::mfn_LookupInterfaceByGuidLk(
  4064. IN LPCWSTR szInterfaceGuid,
  4065. IN BOOL fCreate,
  4066. OUT ENGINEHANDLE &ehInterface,
  4067. OUT CInterfaceSpec* &pISpec,
  4068. OUT BOOL &fIsNew
  4069. )
  4070. {
  4071. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  4072. fIsNew = FALSE;
  4073. ehInterface = NULL;
  4074. pISpec=NULL;
  4075. map< ENGINEHANDLE, CInterfaceSpec* >::iterator iter;
  4076. for( iter = m_mapIdToInterfaceSpec.begin();
  4077. iter != m_mapIdToInterfaceSpec.end();
  4078. ++iter)
  4079. {
  4080. CInterfaceSpec* pTmp = (*iter).second;
  4081. ENGINEHANDLE ehTmp = (*iter).first;
  4082. if (pTmp == NULL || ehTmp == NULL)
  4083. {
  4084. TRACE_CRIT("%!FUNC! map: unexpected pair(eh=0x%lx, pISpec=%p)",
  4085. (UINT) ehTmp, pTmp);
  4086. continue;
  4087. }
  4088. else
  4089. {
  4090. TRACE_VERB("%!FUNC! map: pair(eh=0x%lx, pISpec=%p), szGuid=%ws",
  4091. (UINT) ehTmp, pTmp, (LPCWSTR) pTmp->m_Guid);
  4092. }
  4093. if (!_wcsicmp((LPCWSTR)pTmp->m_Guid, szInterfaceGuid))
  4094. {
  4095. // found it!
  4096. ehInterface = ehTmp;
  4097. pISpec = pTmp;
  4098. break;
  4099. }
  4100. }
  4101. if (pISpec!=NULL)
  4102. {
  4103. if (ehInterface==NULL)
  4104. {
  4105. TRACE_CRIT("%!FUNC! unexpected null handle for pISpec %ws", szInterfaceGuid);
  4106. }
  4107. else
  4108. {
  4109. nerr = NLBERR_OK;
  4110. }
  4111. goto end;
  4112. }
  4113. if (!fCreate)
  4114. {
  4115. nerr = NLBERR_NOT_FOUND;
  4116. goto end;
  4117. }
  4118. //
  4119. // Create a new interface
  4120. //
  4121. {
  4122. pISpec = new CInterfaceSpec;
  4123. if (pISpec == NULL)
  4124. {
  4125. nerr = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  4126. goto end;
  4127. }
  4128. fIsNew = TRUE;
  4129. pISpec->m_fReal = FALSE;
  4130. pISpec->m_Guid = _bstr_t(szInterfaceGuid);
  4131. //
  4132. // Get us a handle to this interface
  4133. //
  4134. ehInterface = CNlbEngine::mfn_NewHandleLk(IUICallbacks::OBJ_INTERFACE);
  4135. if (ehInterface == NULL)
  4136. {
  4137. TRACE_CRIT("%!FUNC! could not reserve a new interface handle");
  4138. nerr = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  4139. delete pISpec;
  4140. pISpec=NULL;
  4141. goto end;
  4142. }
  4143. TRACE_VERB("%!FUNC!: map new pair(eh=0x%lx, pISpec=%p), szGuid=%ws",
  4144. (UINT) ehInterface, pISpec, (LPCWSTR) pISpec->m_Guid);
  4145. m_mapIdToInterfaceSpec[ehInterface] = pISpec;
  4146. nerr = NLBERR_OK;
  4147. }
  4148. end:
  4149. return nerr;
  4150. }
  4151. NLBERROR
  4152. CNlbEngine::mfn_LookupInterfaceByIpLk(
  4153. IN ENGINEHANDLE ehHost, // OPTIONAL -- if NULL all hosts are looked
  4154. IN LPCWSTR szIpAddress,
  4155. OUT ENGINEHANDLE &ehInterface
  4156. )
  4157. {
  4158. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  4159. ehInterface = NULL;
  4160. map< ENGINEHANDLE, CInterfaceSpec* >::iterator iter;
  4161. for( iter = m_mapIdToInterfaceSpec.begin();
  4162. iter != m_mapIdToInterfaceSpec.end();
  4163. ++iter)
  4164. {
  4165. const CInterfaceSpec* pTmp = (*iter).second;
  4166. ENGINEHANDLE ehTmp = (*iter).first;
  4167. if (pTmp == NULL || ehTmp == NULL)
  4168. {
  4169. continue;
  4170. }
  4171. if (ehHost==NULL || ehHost==pTmp->m_ehHostId)
  4172. {
  4173. UINT NumIps = pTmp->m_NlbCfg.NumIpAddresses;
  4174. const NLB_IP_ADDRESS_INFO *pInfo = pTmp->m_NlbCfg.pIpAddressInfo;
  4175. for (UINT u = 0; u<NumIps; u++)
  4176. {
  4177. if (!wcscmp(pInfo[u].IpAddress, szIpAddress))
  4178. {
  4179. // found it!
  4180. TRACE_VERB(L"%!FUNC! found szIp %ws on ehIF 0x%lx",
  4181. szIpAddress, ehTmp);
  4182. ehInterface = ehTmp;
  4183. break;
  4184. }
  4185. }
  4186. }
  4187. }
  4188. if (ehInterface == NULL)
  4189. {
  4190. nerr = NLBERR_NOT_FOUND;
  4191. }
  4192. else
  4193. {
  4194. nerr = NLBERR_OK;
  4195. }
  4196. return nerr;
  4197. }
  4198. NLBERROR
  4199. CNlbEngine::mfn_LookupHostByNameLk(
  4200. IN LPCWSTR szHostName,
  4201. IN BOOL fCreate,
  4202. OUT ENGINEHANDLE &ehHost,
  4203. OUT CHostSpec* &pHostSpec,
  4204. OUT BOOL &fIsNew
  4205. )
  4206. {
  4207. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  4208. fIsNew = FALSE;
  4209. ehHost = NULL;
  4210. map< ENGINEHANDLE, CHostSpec* >::iterator iter;
  4211. pHostSpec = NULL;
  4212. for( iter = m_mapIdToHostSpec.begin();
  4213. iter != m_mapIdToHostSpec.end();
  4214. ++iter)
  4215. {
  4216. CHostSpec* pTmp= (*iter).second;
  4217. ENGINEHANDLE ehTmp = (*iter).first;
  4218. if (pTmp == NULL || ehTmp == NULL)
  4219. {
  4220. TRACE_CRIT("%!FUNC! map: unexpected pair(eh=0x%lx, pHSpec=%p)",
  4221. (UINT) ehTmp, pTmp);
  4222. continue;
  4223. }
  4224. else
  4225. {
  4226. TRACE_VERB("%!FUNC! map: pair(eh=0x%lx, pHSpec=%p), szHost=%ws",
  4227. (UINT) ehTmp, pTmp, (LPCWSTR) pTmp->m_MachineName);
  4228. }
  4229. if (!_wcsicmp(pTmp->m_MachineName, szHostName))
  4230. {
  4231. // found it!
  4232. ehHost = ehTmp;
  4233. pHostSpec = pTmp;
  4234. break;
  4235. }
  4236. }
  4237. if (pHostSpec!=NULL)
  4238. {
  4239. if (ehHost==NULL)
  4240. {
  4241. TRACE_CRIT("%!FUNC! unexpected null handle for pHostSpec %ws", szHostName);
  4242. }
  4243. else
  4244. {
  4245. nerr = NLBERR_OK;
  4246. }
  4247. goto end;
  4248. }
  4249. if (!fCreate)
  4250. {
  4251. nerr = NLBERR_NOT_FOUND;
  4252. goto end;
  4253. }
  4254. //
  4255. // Create a new host
  4256. //
  4257. {
  4258. pHostSpec = new CHostSpec;
  4259. if (pHostSpec == NULL)
  4260. {
  4261. nerr = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  4262. goto end;
  4263. }
  4264. fIsNew = TRUE;
  4265. pHostSpec->m_fReal = FALSE;
  4266. pHostSpec->m_MachineName = _bstr_t(szHostName);
  4267. //
  4268. // Get us a handle to this host
  4269. //
  4270. ehHost = CNlbEngine::mfn_NewHandleLk(IUICallbacks::OBJ_HOST);
  4271. if (ehHost == NULL)
  4272. {
  4273. TRACE_CRIT("%!FUNC! could not reserve a new host handle");
  4274. nerr = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  4275. delete pHostSpec;
  4276. pHostSpec=NULL;
  4277. goto end;
  4278. }
  4279. m_mapIdToHostSpec[ehHost] = pHostSpec;
  4280. TRACE_VERB("%!FUNC!: map new pair(eh=0x%lx, pHost=%p), szName=%ws",
  4281. (UINT) ehHost, pHostSpec, (LPCWSTR) pHostSpec->m_MachineName);
  4282. nerr = NLBERR_OK;
  4283. }
  4284. end:
  4285. return nerr;
  4286. }
  4287. VOID
  4288. CNlbEngine::mfn_NotifyHostInterfacesChange(ENGINEHANDLE ehHost)
  4289. {
  4290. vector<ENGINEHANDLE> InterfaceListCopy;
  4291. //
  4292. // Get copy of interface list (because we can't callback into the UI
  4293. // with locks held).
  4294. //
  4295. {
  4296. mfn_Lock();
  4297. CHostSpec *pHSpec = NULL;
  4298. pHSpec = m_mapIdToHostSpec[ehHost]; // map
  4299. if (pHSpec == NULL)
  4300. {
  4301. TRACE_CRIT("%!FUNC! invalid host handle 0x%lx", (UINT)ehHost);
  4302. }
  4303. else
  4304. {
  4305. InterfaceListCopy = pHSpec->m_ehInterfaceIdList; // vector copy
  4306. }
  4307. mfn_Unlock();
  4308. }
  4309. for(int i = 0; i < InterfaceListCopy.size(); ++i )
  4310. {
  4311. ENGINEHANDLE ehIId = InterfaceListCopy[i];
  4312. m_pCallbacks->HandleEngineEvent(
  4313. IUICallbacks::OBJ_INTERFACE,
  4314. NULL, // ehClusterId,
  4315. ehIId,
  4316. IUICallbacks::EVT_STATUS_CHANGE
  4317. );
  4318. }
  4319. }
  4320. NLBERROR
  4321. CNlbEngine::LookupClusterByIP(
  4322. IN LPCWSTR szIP,
  4323. IN const NLB_EXTENDED_CLUSTER_CONFIGURATION *pInitialConfig OPTIONAL,
  4324. OUT ENGINEHANDLE &ehCluster,
  4325. OUT BOOL &fIsNew
  4326. )
  4327. //
  4328. // if pInitialConfig below is NULL we'll lookup and not try to create.
  4329. // if not NULL and we don't find an existing cluster, well create
  4330. // a new one and initialize it with the specified configuration.
  4331. //
  4332. {
  4333. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  4334. mfn_Lock();
  4335. fIsNew = FALSE;
  4336. ehCluster = NULL;
  4337. map< ENGINEHANDLE, CEngineCluster* >::iterator iter;
  4338. for( iter = m_mapIdToEngineCluster.begin();
  4339. iter != m_mapIdToEngineCluster.end();
  4340. ++iter)
  4341. {
  4342. CEngineCluster* pTmp = (*iter).second;
  4343. ENGINEHANDLE ehTmp = (*iter).first;
  4344. LPCWSTR szTmpIp = NULL;
  4345. if (pTmp == NULL || ehTmp == NULL)
  4346. {
  4347. TRACE_CRIT("%!FUNC! map: unexpected pair(eh=0x%lx, pEC=%p)",
  4348. (UINT) ehTmp, pTmp);
  4349. continue;
  4350. }
  4351. else
  4352. {
  4353. szTmpIp = pTmp->m_cSpec.m_ClusterNlbCfg.NlbParams.cl_ip_addr;
  4354. TRACE_VERB("%!FUNC! map: pair(eh=0x%lx, pEC=%p), szIP=%ws",
  4355. (UINT) ehTmp, pTmp, szTmpIp);
  4356. }
  4357. if (!_wcsicmp(szTmpIp, szIP))
  4358. {
  4359. // found it!
  4360. ehCluster = ehTmp;
  4361. break;
  4362. }
  4363. }
  4364. if (ehCluster!=NULL)
  4365. {
  4366. nerr = NLBERR_OK;
  4367. goto end;
  4368. }
  4369. if (pInitialConfig == NULL)
  4370. {
  4371. nerr = NLBERR_NOT_FOUND;
  4372. goto end;
  4373. }
  4374. //
  4375. // Create a new cluster
  4376. //
  4377. {
  4378. CEngineCluster* pECluster = new CEngineCluster;
  4379. if (pECluster == NULL)
  4380. {
  4381. TRACE_CRIT("%!FUNC! could not allocate cluster object");
  4382. nerr = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  4383. goto end;
  4384. }
  4385. fIsNew = TRUE;
  4386. WBEMSTATUS wStatus;
  4387. wStatus = pECluster->m_cSpec.m_ClusterNlbCfg.Update(pInitialConfig);
  4388. //
  4389. // Note: Update above has the side effect of setting
  4390. // m_ClusterNlbCfg's szNewPassword field to NULL -- this is what
  4391. // we want.
  4392. //
  4393. if (FAILED(wStatus))
  4394. {
  4395. TRACE_CRIT("%!FUNC! could not copy cluster spec. Err=0x%lx!",
  4396. (UINT) wStatus);
  4397. nerr = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  4398. goto end;
  4399. }
  4400. //
  4401. // Remove the dedicated IP address, if any from the cluster version of
  4402. // NLB Config -- both from the NlbParams and from the IP address list.
  4403. //
  4404. remove_dedicated_ip_from_nlbcfg(REF pECluster->m_cSpec.m_ClusterNlbCfg);
  4405. //
  4406. // Get us a handle to this cluster
  4407. //
  4408. ehCluster = CNlbEngine::mfn_NewHandleLk(IUICallbacks::OBJ_CLUSTER);
  4409. if (ehCluster == NULL)
  4410. {
  4411. TRACE_CRIT("%!FUNC! could not reserve a new cluster handle");
  4412. nerr = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  4413. delete pECluster;
  4414. goto end;
  4415. }
  4416. m_mapIdToEngineCluster[ehCluster] = pECluster;
  4417. TRACE_VERB("%!FUNC!: map new pair(eh=0x%lx, pEC=%p)",
  4418. (UINT) ehCluster, pECluster);
  4419. mfn_Unlock();
  4420. //
  4421. // Call the ui to notify it about the new cluster creation.
  4422. //
  4423. m_pCallbacks->HandleEngineEvent(
  4424. IUICallbacks::OBJ_CLUSTER,
  4425. ehCluster,
  4426. ehCluster,
  4427. IUICallbacks::EVT_ADDED
  4428. );
  4429. ProcessMsgQueue();
  4430. mfn_Lock();
  4431. nerr = NLBERR_OK;
  4432. }
  4433. end:
  4434. mfn_Unlock();
  4435. return nerr;
  4436. }
  4437. NLBERROR
  4438. CNlbEngine::LookupInterfaceByIp(
  4439. IN ENGINEHANDLE ehHost, // OPTIONAL -- if NULL all hosts are looked
  4440. IN LPCWSTR szIpAddress,
  4441. OUT ENGINEHANDLE &ehIf
  4442. )
  4443. {
  4444. NLBERROR nerr;
  4445. mfn_Lock();
  4446. nerr = mfn_LookupInterfaceByIpLk(ehHost, szIpAddress, REF ehIf);
  4447. mfn_Unlock();
  4448. return nerr;
  4449. }
  4450. NLBERROR
  4451. CNlbEngine::LookupConnectionInfo(
  4452. IN LPCWSTR szConnectionString,
  4453. OUT _bstr_t &bstrUsername,
  4454. OUT _bstr_t &bstrPassword
  4455. )
  4456. //
  4457. // Look through existing hosts, looking for any which have a matching
  4458. // connection string. If found, fill out bstrUsername and bstrPassword
  4459. // for that host.
  4460. //
  4461. {
  4462. NLBERROR nerr = NLBERR_NOT_FOUND;
  4463. TRACE_VERB(L"-> Lookup: szConnString=%ws", szConnectionString);
  4464. bstrUsername = (LPCWSTR) NULL;
  4465. bstrPassword = (LPCWSTR) NULL;
  4466. mfn_Lock();
  4467. map< ENGINEHANDLE, CHostSpec* >::iterator iter;
  4468. for( iter = m_mapIdToHostSpec.begin();
  4469. iter != m_mapIdToHostSpec.end();
  4470. ++iter)
  4471. {
  4472. CHostSpec* pTmp = (*iter).second;
  4473. LPCWSTR szHostConnString = NULL;
  4474. ENGINEHANDLE ehTmp = (*iter).first;
  4475. if (pTmp == NULL || ehTmp == NULL)
  4476. {
  4477. continue;
  4478. }
  4479. szHostConnString = (LPCWSTR) pTmp->m_ConnectionString;
  4480. if (szHostConnString == NULL)
  4481. {
  4482. szHostConnString = L"";
  4483. }
  4484. if (!_wcsicmp(szHostConnString, szConnectionString))
  4485. {
  4486. // found it! Fill out username and password.
  4487. bstrUsername = pTmp->m_UserName;
  4488. bstrPassword = pTmp->m_Password;
  4489. LPCWSTR szU = (LPCWSTR) bstrUsername;
  4490. LPCWSTR szP = (LPCWSTR) bstrPassword;
  4491. if (szU == NULL) szU = L"";
  4492. if (szP == NULL) szP = L"";
  4493. nerr = NLBERR_OK;
  4494. TRACE_VERB(L"Found un=%ws pwd=%ws", szU, szP);
  4495. break;
  4496. }
  4497. }
  4498. mfn_Unlock();
  4499. TRACE_VERB("<- returns 0x%x", nerr);
  4500. return nerr;
  4501. }
  4502. NLBERROR
  4503. CNlbEngine::GetInterfaceInformation(
  4504. IN ENGINEHANDLE ehInterface,
  4505. OUT CHostSpec& hSpec,
  4506. OUT CInterfaceSpec& iSpec,
  4507. OUT _bstr_t& bstrDisplayName,
  4508. OUT INT& iIcon,
  4509. OUT _bstr_t& bstrStatus
  4510. )
  4511. /*
  4512. Looks up a bunch of information about the specified interface.
  4513. bstrDisplayName -- this is a combination of the host name and interface name
  4514. bstrDisplay -- text version of the interface's operational status.
  4515. iIcon -- icon version of the interface's operational status.
  4516. (one of the Document::IconNames enums)
  4517. */
  4518. {
  4519. // First get host and interface spec.
  4520. //
  4521. NLBERROR nerr;
  4522. LPCWSTR szHostName = L"";
  4523. LPCWSTR szStatus = L"";
  4524. bstrDisplayName = (LPCWSTR) NULL;
  4525. bstrStatus = (LPCWSTR) NULL;
  4526. iIcon = 0;
  4527. nerr = this->GetInterfaceSpec(
  4528. ehInterface,
  4529. REF iSpec
  4530. );
  4531. if (NLBFAILED(nerr))
  4532. {
  4533. TRACE_CRIT("%!FUNC! : could not get interface spec! nerr=0x%lx", nerr);
  4534. goto end;
  4535. }
  4536. nerr = this->GetHostSpec(
  4537. iSpec.m_ehHostId,
  4538. REF hSpec
  4539. );
  4540. if (NLBOK(nerr))
  4541. {
  4542. szHostName = (LPCWSTR) hSpec.m_MachineName;
  4543. if (szHostName == NULL)
  4544. {
  4545. szHostName = L"";
  4546. }
  4547. }
  4548. else
  4549. {
  4550. TRACE_CRIT("%!FUNC! : could not get host spec! nerr=0x%lx", nerr);
  4551. goto end;
  4552. }
  4553. //
  4554. // Determine the icon and bstrStatus
  4555. //
  4556. if (hSpec.m_fUnreachable)
  4557. {
  4558. szStatus = GETRESOURCEIDSTRING(IDS_HOST_STATE_UNREACHABLE); //"Unreachable";
  4559. iIcon = Document::ICON_HOST_UNREACHABLE;
  4560. }
  4561. else if (iSpec.m_fPending)
  4562. {
  4563. szStatus = GETRESOURCEIDSTRING(IDS_HOST_STATE_PENDING); //"Pending";
  4564. iIcon = Document::ICON_CLUSTER_PENDING;
  4565. }
  4566. else if (iSpec.m_fMisconfigured)
  4567. {
  4568. szStatus = GETRESOURCEIDSTRING(IDS_HOST_STATE_MISCONFIGURED); // "Misconfigured"
  4569. iIcon = Document::ICON_HOST_MISCONFIGURED;
  4570. }
  4571. else if (!hSpec.m_fReal)
  4572. {
  4573. szStatus = GETRESOURCEIDSTRING(IDS_HOST_STATE_UNKNOWN); // "Unknown";
  4574. iIcon = Document::ICON_HOST_UNKNOWN;
  4575. }
  4576. else
  4577. {
  4578. szStatus = GETRESOURCEIDSTRING(IDS_HOST_STATE_UNKNOWN); // "Unknown";
  4579. iIcon = Document::ICON_HOST_OK;
  4580. //
  4581. // Choose icon based on operational state if we have it
  4582. //
  4583. if (!iSpec.m_NlbCfg.IsNlbBound())
  4584. {
  4585. szStatus = GETRESOURCEIDSTRING(IDS_STATE_NLB_NOT_BOUND); // L"NLB not bound";
  4586. }
  4587. else if (iSpec.m_fValidClusterState)
  4588. {
  4589. switch(iSpec.m_dwClusterState)
  4590. {
  4591. case WLBS_CONVERGING:
  4592. iIcon = Document::ICON_HOST_CONVERGING;
  4593. szStatus = GETRESOURCEIDSTRING(IDS_STATE_CONVERGING);
  4594. // szStatus = L"Converging";
  4595. break;
  4596. case WLBS_CONVERGED:
  4597. case WLBS_DEFAULT:
  4598. iIcon = Document::ICON_HOST_STARTED;
  4599. szStatus = GETRESOURCEIDSTRING(IDS_STATE_CONVERGED);
  4600. // szStatus = L"Converged";
  4601. break;
  4602. case WLBS_STOPPED:
  4603. szStatus = GETRESOURCEIDSTRING(IDS_HOST_STATE_STOPPED);
  4604. iIcon = Document::ICON_HOST_STOPPED;
  4605. // szStatus = L"Stopped";
  4606. break;
  4607. case WLBS_SUSPENDED:
  4608. szStatus = GETRESOURCEIDSTRING(IDS_HOST_STATE_SUSPENDED);
  4609. iIcon = Document::ICON_HOST_SUSPENDED;
  4610. // szStatus = L"Suspended";
  4611. break;
  4612. case WLBS_DRAINING:
  4613. szStatus = GETRESOURCEIDSTRING(IDS_HOST_DRAINING);
  4614. // szStatus = L"Draining";
  4615. iIcon = Document::ICON_HOST_DRAINING;
  4616. break;
  4617. case WLBS_DISCONNECTED:
  4618. szStatus = GETRESOURCEIDSTRING(IDS_HOST_DISCONNECTED);
  4619. // szStatus = L"Disconnected";
  4620. iIcon = Document::ICON_HOST_DISCONNECTED;
  4621. break;
  4622. default:
  4623. //
  4624. // Don't know what this is -- default to "OK" icon.
  4625. //
  4626. szStatus = GETRESOURCEIDSTRING(IDS_HOST_STATE_UNKNOWN);
  4627. // szStatus = L"Unknown";
  4628. iIcon = Document::ICON_HOST_OK;
  4629. break;
  4630. }
  4631. }
  4632. }
  4633. bstrStatus = _bstr_t(szStatus);
  4634. //
  4635. // Fill out the DisplayName
  4636. //
  4637. {
  4638. WBEMSTATUS wStat;
  4639. LPWSTR szAdapter = L"";
  4640. WCHAR rgText[256];
  4641. wStat = iSpec.m_NlbCfg.GetFriendlyName(&szAdapter);
  4642. if (FAILED(wStat))
  4643. {
  4644. szAdapter = NULL;
  4645. }
  4646. StringCbPrintf(
  4647. rgText,
  4648. sizeof(rgText),
  4649. L"%ws(%ws)",
  4650. szHostName,
  4651. (szAdapter==NULL ? L"" : szAdapter)
  4652. );
  4653. delete szAdapter;
  4654. bstrDisplayName = _bstr_t(rgText);
  4655. }
  4656. end:
  4657. return nerr;
  4658. }
  4659. NLBERROR
  4660. CNlbEngine::GetInterfaceIdentification(
  4661. IN ENGINEHANDLE ehInterface,
  4662. OUT ENGINEHANDLE& ehHost,
  4663. OUT ENGINEHANDLE& ehCluster,
  4664. OUT _bstr_t& bstrFriendlyName,
  4665. OUT _bstr_t& bstrDisplayName,
  4666. OUT _bstr_t& bstrHostName
  4667. )
  4668. {
  4669. // First get host and interface spec.
  4670. //
  4671. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  4672. CInterfaceSpec *pISpec = NULL;
  4673. LPCWSTR szHostName = L"";
  4674. mfn_Lock();
  4675. bstrFriendlyName= (LPCWSTR) NULL;
  4676. bstrDisplayName = (LPCWSTR) NULL;
  4677. ehHost = NULL;
  4678. ehCluster = NULL;
  4679. pISpec = m_mapIdToInterfaceSpec[ehInterface]; // map
  4680. if (pISpec == NULL)
  4681. {
  4682. TRACE_CRIT("%!FUNC! : could not get interface spec for ehI 0x%lx!",
  4683. ehInterface);
  4684. nerr = NLBERR_INTERFACE_NOT_FOUND;
  4685. goto end;
  4686. }
  4687. if (pISpec->m_ehHostId == NULL)
  4688. {
  4689. TRACE_CRIT("%!FUNC! : ehI 0x%lx has NULL ehHost spec!", ehInterface);
  4690. goto end;
  4691. }
  4692. else
  4693. {
  4694. CHostSpec *pHSpec = NULL;
  4695. pHSpec = m_mapIdToHostSpec[pISpec->m_ehHostId]; // map
  4696. if (pHSpec == NULL)
  4697. {
  4698. TRACE_CRIT("%!FUNC! : ehI 0x%lx has invalid ehHost 0x%lx!",
  4699. ehInterface, pISpec->m_ehHostId);
  4700. goto end;
  4701. }
  4702. bstrHostName = pHSpec->m_MachineName;
  4703. szHostName = (LPCWSTR) pHSpec->m_MachineName;
  4704. if (szHostName == NULL)
  4705. {
  4706. szHostName = L"";
  4707. }
  4708. }
  4709. nerr = NLBERR_OK;
  4710. ehHost = pISpec->m_ehHostId;
  4711. ehCluster = pISpec->m_ehCluster;
  4712. //
  4713. // Fill out the bstrFriendlyName and bstrDisplayName
  4714. //
  4715. {
  4716. WBEMSTATUS wStat;
  4717. LPWSTR szAdapter = L"";
  4718. WCHAR rgText[256];
  4719. wStat = pISpec->m_NlbCfg.GetFriendlyName(&szAdapter);
  4720. if (FAILED(wStat))
  4721. {
  4722. szAdapter = NULL;
  4723. }
  4724. StringCbPrintf(
  4725. rgText,
  4726. sizeof(rgText),
  4727. L"%ws(%ws)",
  4728. szHostName,
  4729. (szAdapter==NULL ? L"" : szAdapter)
  4730. );
  4731. bstrFriendlyName = _bstr_t(szAdapter);
  4732. delete szAdapter;
  4733. bstrDisplayName = _bstr_t(rgText);
  4734. }
  4735. end:
  4736. mfn_Unlock();
  4737. return nerr;
  4738. }
  4739. NLBERROR
  4740. CNlbEngine::GetClusterIdentification(
  4741. IN ENGINEHANDLE ehCluster,
  4742. OUT _bstr_t& bstrIpAddress,
  4743. OUT _bstr_t& bstrDomainName,
  4744. OUT _bstr_t& bstrDisplayName
  4745. )
  4746. {
  4747. NLBERROR nerr = NLBERR_NOT_FOUND;
  4748. WCHAR rgTmp[256];
  4749. bstrIpAddress = (LPCWSTR) NULL;
  4750. bstrDomainName = (LPCWSTR) NULL;
  4751. bstrDisplayName = (LPCWSTR) NULL;
  4752. mfn_Lock();
  4753. CEngineCluster *pECluster = m_mapIdToEngineCluster[ehCluster]; // map
  4754. if (pECluster != NULL)
  4755. {
  4756. WLBS_REG_PARAMS *pParams =&pECluster->m_cSpec.m_ClusterNlbCfg.NlbParams;
  4757. StringCbPrintf(
  4758. rgTmp,
  4759. sizeof(rgTmp),
  4760. L"%ws(%ws)",
  4761. pParams->domain_name,
  4762. pParams->cl_ip_addr
  4763. );
  4764. bstrIpAddress = _bstr_t(pParams->cl_ip_addr);
  4765. bstrDomainName = _bstr_t(pParams->domain_name);
  4766. bstrDisplayName = _bstr_t(rgTmp);
  4767. nerr = NLBERR_OK;
  4768. }
  4769. mfn_Unlock();
  4770. return nerr;
  4771. }
  4772. NLBERROR
  4773. CNlbEngine::ValidateNewClusterIp(
  4774. IN ENGINEHANDLE ehCluster, // OPTIONAL
  4775. IN LPCWSTR szIp,
  4776. OUT BOOL &fExistsOnRawIterface,
  4777. IN OUT CLocalLogger &logConflict
  4778. )
  4779. {
  4780. NLBERROR nerr = NLBERR_INVALID_IP_ADDRESS_SPECIFICATION;
  4781. BOOL fRet = FALSE;
  4782. ENGINEHANDLE ehTmp = NULL;
  4783. BOOL fIsNew = FALSE;
  4784. fExistsOnRawIterface = FALSE;
  4785. //
  4786. // Check that CIP is not used elsewhere
  4787. //
  4788. nerr = this->LookupClusterByIP(
  4789. szIp,
  4790. NULL, // pInitialConfig
  4791. REF ehTmp,
  4792. REF fIsNew
  4793. );
  4794. if (NLBOK(nerr) && ehCluster != ehTmp)
  4795. {
  4796. //
  4797. // CIP matches some other cluster!
  4798. //
  4799. _bstr_t bstrIpAddress;
  4800. _bstr_t bstrDomainName;
  4801. _bstr_t bstrClusterDisplayName;
  4802. LPCWSTR szCluster = NULL;
  4803. nerr = this->GetClusterIdentification(
  4804. ehTmp,
  4805. REF bstrIpAddress,
  4806. REF bstrDomainName,
  4807. REF bstrClusterDisplayName
  4808. );
  4809. if (NLBOK(nerr))
  4810. {
  4811. szCluster = bstrClusterDisplayName;
  4812. }
  4813. if (szCluster == NULL)
  4814. {
  4815. szCluster = L"";
  4816. }
  4817. logConflict.Log(IDS_CLUSTER_XXX, szCluster);
  4818. goto end;
  4819. }
  4820. ehTmp = NULL;
  4821. nerr = this->LookupInterfaceByIp(
  4822. NULL, // NULL == search for all hosts
  4823. szIp,
  4824. REF ehTmp
  4825. );
  4826. if (NLBOK(nerr))
  4827. {
  4828. ENGINEHANDLE ehExistingCluster;
  4829. ENGINEHANDLE ehExistingHost;
  4830. _bstr_t bstrDisplayName;
  4831. _bstr_t bstrFriendlyName;
  4832. _bstr_t bstrHostName;
  4833. LPCWSTR szInterface = NULL;
  4834. nerr = this->GetInterfaceIdentification(
  4835. ehTmp,
  4836. ehExistingHost,
  4837. ehExistingCluster,
  4838. bstrFriendlyName,
  4839. bstrDisplayName,
  4840. bstrHostName
  4841. );
  4842. if (NLBOK(nerr))
  4843. {
  4844. if (ehCluster == NULL || ehCluster != ehExistingCluster)
  4845. {
  4846. //
  4847. // CONFLICT
  4848. //
  4849. if (ehExistingCluster == NULL)
  4850. {
  4851. //
  4852. // Conflicting interface NOT part of an existing cluster.
  4853. //
  4854. fExistsOnRawIterface = TRUE;
  4855. }
  4856. szInterface = bstrDisplayName;
  4857. if (szInterface == NULL)
  4858. {
  4859. szInterface = L"";
  4860. }
  4861. logConflict.Log(IDS_INTERFACE_XXX, szInterface);
  4862. goto end;
  4863. }
  4864. }
  4865. }
  4866. fRet = TRUE;
  4867. end:
  4868. if (fRet)
  4869. {
  4870. nerr = NLBERR_OK;
  4871. }
  4872. else
  4873. {
  4874. nerr = NLBERR_INVALID_IP_ADDRESS_SPECIFICATION;
  4875. }
  4876. return nerr;
  4877. }
  4878. NLBERROR
  4879. CNlbEngine::ValidateNewDedicatedIp(
  4880. IN ENGINEHANDLE ehIF,
  4881. IN LPCWSTR szDip,
  4882. IN OUT CLocalLogger &logConflict
  4883. )
  4884. {
  4885. NLBERROR nerr = NLBERR_INVALID_IP_ADDRESS_SPECIFICATION;
  4886. BOOL fRet = FALSE;
  4887. ENGINEHANDLE ehTmp = NULL;
  4888. BOOL fIsNew = FALSE;
  4889. if (ehIF == NULL)
  4890. {
  4891. ASSERT(FALSE);
  4892. goto end;
  4893. }
  4894. //
  4895. // Check that DIP is not used elsewhere
  4896. //
  4897. nerr = this->LookupClusterByIP(
  4898. szDip,
  4899. NULL, // pInitialConfig
  4900. REF ehTmp,
  4901. REF fIsNew
  4902. );
  4903. if (NLBOK(nerr))
  4904. {
  4905. //
  4906. // DIP matches some cluster!
  4907. //
  4908. _bstr_t bstrIpAddress;
  4909. _bstr_t bstrDomainName;
  4910. _bstr_t bstrClusterDisplayName;
  4911. LPCWSTR szCluster = NULL;
  4912. nerr = this->GetClusterIdentification(
  4913. ehTmp,
  4914. REF bstrIpAddress,
  4915. REF bstrDomainName,
  4916. REF bstrClusterDisplayName
  4917. );
  4918. if (NLBOK(nerr))
  4919. {
  4920. szCluster = bstrClusterDisplayName;
  4921. }
  4922. if (szCluster == NULL)
  4923. {
  4924. szCluster = L"";
  4925. }
  4926. logConflict.Log(IDS_CLUSTER_XXX, szCluster);
  4927. goto end;
  4928. }
  4929. ehTmp = NULL;
  4930. nerr = this->LookupInterfaceByIp(
  4931. NULL, // NULL == search for all hosts
  4932. szDip,
  4933. REF ehTmp
  4934. );
  4935. if (NLBOK(nerr))
  4936. {
  4937. if (ehTmp != ehIF)
  4938. {
  4939. ENGINEHANDLE ehHost1;
  4940. ENGINEHANDLE ehCluster1;
  4941. _bstr_t bstrDisplayName1;
  4942. _bstr_t bstrFriendlyName;
  4943. _bstr_t bstrHostName;
  4944. LPCWSTR szInterface = NULL;
  4945. nerr = this->GetInterfaceIdentification(
  4946. ehTmp,
  4947. ehHost1,
  4948. ehCluster1,
  4949. bstrFriendlyName,
  4950. bstrDisplayName1,
  4951. bstrHostName
  4952. );
  4953. szInterface = bstrDisplayName1;
  4954. if (szInterface == NULL)
  4955. {
  4956. szInterface = L"";
  4957. }
  4958. logConflict.Log(IDS_INTERFACE_XXX, szInterface);
  4959. goto end;
  4960. }
  4961. }
  4962. fRet = TRUE;
  4963. end:
  4964. if (fRet)
  4965. {
  4966. nerr = NLBERR_OK;
  4967. }
  4968. else
  4969. {
  4970. nerr = NLBERR_INVALID_IP_ADDRESS_SPECIFICATION;
  4971. }
  4972. return nerr;
  4973. }
  4974. VOID
  4975. CNlbEngine::mfn_ReallyUpdateInterface(
  4976. IN ENGINEHANDLE ehInterface,
  4977. IN NLB_EXTENDED_CLUSTER_CONFIGURATION &refNewConfig
  4978. //IN OUT BOOL &fClusterPropertiesUpdated
  4979. )
  4980. {
  4981. #define NLBMGR_MAX_OPERATION_DURATION 120 // 2 minutes
  4982. BOOL fCancelled = FALSE;
  4983. CHostSpec *pHSpec = NULL;
  4984. CInterfaceSpec *pISpec = NULL;
  4985. WBEMSTATUS CompletionStatus, wStatus;
  4986. _bstr_t bstrNicGuid;
  4987. _bstr_t bstrHostName;
  4988. _bstr_t bstrUserName;
  4989. _bstr_t bstrConnectionString;
  4990. _bstr_t bstrPassword;
  4991. NLBERROR nerr;
  4992. CLocalLogger logClientIdentification;
  4993. WCHAR rgMachineName[512];
  4994. DWORD cbMachineName = (DWORD) ASIZE(rgMachineName);
  4995. BOOL fRet;
  4996. DWORD StartTime = GetTickCount();
  4997. fRet = GetComputerNameEx(
  4998. ComputerNameDnsFullyQualified,
  4999. rgMachineName,
  5000. &cbMachineName
  5001. );
  5002. if (!fRet)
  5003. {
  5004. *rgMachineName = 0;
  5005. }
  5006. logClientIdentification.Log(IDS_CLIENT_IDENTIFICATION, rgMachineName);
  5007. mfn_Lock();
  5008. nerr = CNlbEngine::mfn_GetHostFromInterfaceLk(ehInterface,REF pISpec, REF pHSpec);
  5009. if (nerr != NLBERR_OK)
  5010. {
  5011. TRACE_CRIT("%!FUNC! could not get pISpec,pHSpec for ehIF 0x%lx",
  5012. ehInterface);
  5013. goto end_unlock;
  5014. }
  5015. //
  5016. // We need to keep local bstrs because once we release the lock
  5017. // pHSpec may go away (or re-assign it's bstrs) -- .net svr bug 513056.
  5018. //
  5019. bstrUserName = pHSpec->m_UserName;
  5020. bstrConnectionString= pHSpec->m_ConnectionString;
  5021. bstrPassword = pHSpec->m_Password;
  5022. bstrNicGuid = pISpec->m_Guid;
  5023. bstrHostName = pHSpec->m_MachineName;
  5024. WMI_CONNECTION_INFO ConnInfo;
  5025. ConnInfo.szUserName = (LPCWSTR) bstrUserName;
  5026. ConnInfo.szPassword = (LPCWSTR) bstrPassword;
  5027. ConnInfo.szMachine = (LPCWSTR) bstrConnectionString;
  5028. LPCWSTR szNicGuid = (LPCWSTR) bstrNicGuid;
  5029. LPCWSTR szHostName = (LPCWSTR) bstrHostName;
  5030. if (szNicGuid == NULL)
  5031. {
  5032. TRACE_CRIT("%!FUNC! ERROR -- NULL szNicGuid!");
  5033. goto end_unlock;
  5034. }
  5035. mfn_Unlock();
  5036. UINT Generation; // TODO track the generation
  5037. LPWSTR pLog = NULL;
  5038. LPCWSTR szClusterIp = refNewConfig.NlbParams.cl_ip_addr;
  5039. ProcessMsgQueue(); // TODO: eliminate when doing this in the background
  5040. wStatus = NlbHostDoUpdate(
  5041. &ConnInfo,
  5042. szNicGuid,
  5043. logClientIdentification.GetStringSafe(),
  5044. // L"NLB Manager on <this machine>", // TODO: localize
  5045. &refNewConfig,
  5046. &Generation,
  5047. &pLog
  5048. );
  5049. if (wStatus == WBEM_S_PENDING)
  5050. {
  5051. m_pCallbacks->Log(
  5052. IUICallbacks::LOG_INFORMATIONAL,
  5053. szClusterIp,
  5054. szHostName,
  5055. IDS_LOG_WAITING_FOR_PENDING_OPERATION, // %d
  5056. Generation
  5057. );
  5058. }
  5059. while (wStatus == WBEM_S_PENDING)
  5060. {
  5061. //
  5062. // Check if we've exceeded the absolute time for cancellation.
  5063. //
  5064. {
  5065. DWORD CurrentTime = GetTickCount();
  5066. UINT DurationInSeconds=0;
  5067. if (CurrentTime < StartTime)
  5068. {
  5069. //
  5070. // Timer overflow -- fixup: we do this the "cheap" way
  5071. // of re-setting start time, so that we'll end up with at most
  5072. // twice the max delay in the event of a timer overflow.
  5073. //
  5074. StartTime = CurrentTime;
  5075. }
  5076. DurationInSeconds= (UINT) (CurrentTime - StartTime)/1000;
  5077. if ( DurationInSeconds > NLBMGR_MAX_OPERATION_DURATION)
  5078. {
  5079. TRACE_CRIT("%!FUNC! Operation canceled because max time exceeded");
  5080. fCancelled = TRUE;
  5081. break;
  5082. }
  5083. }
  5084. //
  5085. // Check if this pending operation is cancelled...
  5086. //
  5087. {
  5088. CInterfaceSpec *pTmpISpec = NULL;
  5089. ENGINEHANDLE ehOperation = NULL;
  5090. mfn_Lock();
  5091. pTmpISpec = m_mapIdToInterfaceSpec[ehInterface]; // map
  5092. if (pTmpISpec == NULL)
  5093. {
  5094. ASSERT(FALSE);
  5095. wStatus = WBEM_E_CRITICAL_ERROR;
  5096. mfn_Unlock();
  5097. break;
  5098. }
  5099. ehOperation = pTmpISpec->m_ehPendingOperation;
  5100. if (ehOperation != NULL)
  5101. {
  5102. CEngineOperation *pOperation;
  5103. pOperation = m_mapIdToOperation[ehOperation];
  5104. if (pOperation != NULL)
  5105. {
  5106. if (pOperation->fCanceled)
  5107. {
  5108. TRACE_CRIT("%!FUNC! ehOp 0x%lx CANCELLED!",
  5109. ehOperation);
  5110. fCancelled = TRUE;
  5111. }
  5112. }
  5113. }
  5114. mfn_Unlock();
  5115. if (fCancelled)
  5116. {
  5117. break;
  5118. }
  5119. }
  5120. if (pLog != NULL)
  5121. {
  5122. mfn_UpdateInterfaceStatusDetails(ehInterface, pLog);
  5123. delete pLog;
  5124. pLog = NULL;
  5125. }
  5126. for (UINT u=0;u<50;u++)
  5127. {
  5128. ProcessMsgQueue(); // TODO: eliminate when doing this in the background
  5129. Sleep(100);
  5130. }
  5131. ULONG uIpAddress = 0;
  5132. wStatus = NlbHostPing(ConnInfo.szMachine, 2000, &uIpAddress);
  5133. if (FAILED(wStatus))
  5134. {
  5135. TRACE_CRIT("%!FUNC!: ping %ws failed!", ConnInfo.szMachine);
  5136. wStatus = WBEM_S_PENDING;
  5137. continue;
  5138. }
  5139. wStatus = NlbHostGetUpdateStatus(
  5140. &ConnInfo,
  5141. szNicGuid,
  5142. Generation,
  5143. &CompletionStatus,
  5144. &pLog
  5145. );
  5146. if (!FAILED(wStatus))
  5147. {
  5148. wStatus = CompletionStatus;
  5149. }
  5150. }
  5151. if (fCancelled == TRUE)
  5152. {
  5153. wStatus = WBEM_S_OPERATION_CANCELLED;
  5154. }
  5155. else
  5156. {
  5157. BOOL fNewRctPassword = FALSE;
  5158. //
  5159. // Get latest information from the host
  5160. //
  5161. (void) this->RefreshInterface(
  5162. ehInterface,
  5163. FALSE, // FALSE == don't start a new operation
  5164. FALSE // FALSE == this is not cluster-wide
  5165. );
  5166. //
  5167. // If we're doing a RCT password-change, AND the updated operation
  5168. // completed successfully AND the cluster's fNewRctPassword flag is
  5169. // set, we'll update the cluster's rct hash value and clear the
  5170. // fNewRctPassword flag.
  5171. //
  5172. fNewRctPassword = (refNewConfig.GetNewRemoteControlPasswordRaw()!=NULL);
  5173. if (fNewRctPassword && !FAILED(wStatus))
  5174. {
  5175. CEngineCluster *pECluster = NULL;
  5176. mfn_Lock();
  5177. pISpec = m_mapIdToInterfaceSpec[ehInterface]; // map
  5178. if (pISpec != NULL)
  5179. {
  5180. ENGINEHANDLE ehCluster = pISpec->m_ehCluster;
  5181. if (ehCluster != NULL)
  5182. {
  5183. pECluster = m_mapIdToEngineCluster[ehCluster]; // map
  5184. }
  5185. }
  5186. if (pECluster != NULL)
  5187. {
  5188. if (pECluster->m_cSpec.m_fNewRctPassword)
  5189. {
  5190. //
  5191. // Update cluster's rct hash and clear m_fNewRctPassword
  5192. //
  5193. DWORD dwNewHash;
  5194. dwNewHash = CfgUtilGetHashedRemoteControlPassword(
  5195. &pISpec->m_NlbCfg.NlbParams
  5196. );
  5197. TRACE_VERB(L"Updating cluster remote control password to %lu",
  5198. dwNewHash
  5199. );
  5200. CfgUtilSetHashedRemoteControlPassword(
  5201. &pECluster->m_cSpec.m_ClusterNlbCfg.NlbParams,
  5202. dwNewHash
  5203. );
  5204. pECluster->m_cSpec.m_fNewRctPassword = FALSE;
  5205. }
  5206. }
  5207. mfn_Unlock();
  5208. }
  5209. }
  5210. //
  5211. // Log the final results.
  5212. //
  5213. {
  5214. IUICallbacks::LogEntryHeader Header;
  5215. Header.szDetails = pLog;
  5216. Header.szCluster = szClusterIp;
  5217. Header.szHost = szHostName;
  5218. if (FAILED(wStatus))
  5219. {
  5220. Header.type = IUICallbacks::LOG_ERROR;
  5221. if (Generation != 0)
  5222. {
  5223. m_pCallbacks->LogEx(
  5224. &Header,
  5225. IDS_LOG_FINAL_STATUS_FAILED,
  5226. Generation,
  5227. wStatus
  5228. );
  5229. }
  5230. else
  5231. {
  5232. m_pCallbacks->LogEx(
  5233. &Header,
  5234. IDS_LOG_FINAL_STATUS_FAILED_NOGEN,
  5235. wStatus
  5236. );
  5237. }
  5238. }
  5239. else
  5240. {
  5241. Header.type = IUICallbacks::LOG_INFORMATIONAL;
  5242. m_pCallbacks->LogEx(
  5243. &Header,
  5244. IDS_LOG_FINAL_STATUS_SUCCEEDED,
  5245. Generation
  5246. );
  5247. }
  5248. }
  5249. if (pLog != NULL)
  5250. {
  5251. delete pLog;
  5252. pLog = NULL;
  5253. }
  5254. ProcessMsgQueue(); // TODO: eliminate when doing this in the background
  5255. mfn_Lock();
  5256. end_unlock:
  5257. mfn_Unlock();
  5258. return;
  5259. }
  5260. VOID
  5261. CNlbEngine::mfn_SetInterfaceMisconfigStateLk(
  5262. IN CInterfaceSpec *pIF,
  5263. IN BOOL fMisconfig,
  5264. IN LPCWSTR szMisconfigDetails
  5265. )
  5266. /*
  5267. Set/clear the interface misconfigured status.
  5268. If fMisconfig, save away the szMisconfigDetails, else clear the
  5269. internal misconfig details field.
  5270. */
  5271. {
  5272. pIF->m_fMisconfigured = fMisconfig;
  5273. if (fMisconfig)
  5274. {
  5275. pIF->m_bstrStatusDetails = _bstr_t(szMisconfigDetails);
  5276. }
  5277. else
  5278. {
  5279. pIF->m_bstrStatusDetails = LPCWSTR(NULL);
  5280. }
  5281. }
  5282. BOOL
  5283. CNlbEngine::mfn_HostHasManagedClustersLk(CHostSpec *pHSpec)
  5284. //
  5285. // Return true if there exists at least one IF which is part of
  5286. // a cluster displayed by NLB Manager.
  5287. //
  5288. {
  5289. BOOL fRet = FALSE;
  5290. vector<ENGINEHANDLE> &InterfaceList = pHSpec->m_ehInterfaceIdList;
  5291. for(UINT u = 0; u < InterfaceList.size(); ++u )
  5292. {
  5293. ENGINEHANDLE ehI = InterfaceList[u];
  5294. CInterfaceSpec *pISpec = m_mapIdToInterfaceSpec[ehI]; // map
  5295. if (pISpec != NULL)
  5296. {
  5297. if (pISpec->m_ehCluster != NULL)
  5298. {
  5299. fRet = TRUE;
  5300. break;
  5301. }
  5302. }
  5303. }
  5304. return fRet;
  5305. }
  5306. void
  5307. CNlbEngine::mfn_UpdateInterfaceStatusDetails(
  5308. ENGINEHANDLE ehIF,
  5309. LPCWSTR szDetails
  5310. )
  5311. //
  5312. // Update the textual status details field of the interface.
  5313. // These details give the detailed information on the current status
  5314. // of the interface. For example: if misconfigured, misconfig details,
  5315. // or if there is an update operation ongoing, details about that operation.
  5316. //
  5317. {
  5318. CInterfaceSpec *pISpec = NULL;
  5319. mfn_Lock();
  5320. pISpec = m_mapIdToInterfaceSpec[ehIF]; // map
  5321. if (pISpec != NULL)
  5322. {
  5323. pISpec->m_bstrStatusDetails = szDetails;
  5324. }
  5325. mfn_Unlock();
  5326. }
  5327. BOOL
  5328. validate_extcfg(
  5329. const NLB_EXTENDED_CLUSTER_CONFIGURATION &Config
  5330. )
  5331. /*
  5332. Do some internal checks to make sure that the data is valid.
  5333. Does not change internal state.
  5334. */
  5335. {
  5336. BOOL fRet = FALSE;
  5337. if (Config.fBound)
  5338. {
  5339. WBEMSTATUS Status;
  5340. //
  5341. // NLB is bound -- let's validate NLB paramaters.
  5342. //
  5343. WLBS_REG_PARAMS TmpParams = Config.NlbParams; // struct copy.
  5344. BOOL fConnectivityChange = FALSE;
  5345. Status = CfgUtilsAnalyzeNlbUpdate(
  5346. NULL, // OPTIONAL pCurrentParams
  5347. &TmpParams,
  5348. &fConnectivityChange
  5349. );
  5350. if (FAILED(Status))
  5351. {
  5352. goto end;
  5353. }
  5354. }
  5355. fRet = TRUE;
  5356. end:
  5357. return fRet;
  5358. }
  5359. VOID
  5360. remove_dedicated_ip_from_nlbcfg(
  5361. NLB_EXTENDED_CLUSTER_CONFIGURATION &ClusterCfg
  5362. )
  5363. {
  5364. LPCWSTR szDedIp = ClusterCfg.NlbParams.ded_ip_addr;
  5365. UINT NumIps = ClusterCfg.NumIpAddresses;
  5366. NLB_IP_ADDRESS_INFO
  5367. *pIpInfo = ClusterCfg.pIpAddressInfo;
  5368. if (*szDedIp == 0) goto end;
  5369. //
  5370. // Go through address list, looking for this Ip address. If we find it,
  5371. // we remove it.
  5372. //
  5373. for (UINT u=0; u<NumIps; u++)
  5374. {
  5375. if (!wcscmp(szDedIp, pIpInfo[u].IpAddress))
  5376. {
  5377. //
  5378. // Found it! Move everything ahead up by one.
  5379. //
  5380. for (UINT v=u+1; v<NumIps; v++)
  5381. {
  5382. pIpInfo[v-1]=pIpInfo[v]; // Struct copy.
  5383. }
  5384. ClusterCfg.NumIpAddresses--;
  5385. //
  5386. // Zero-out last entry just for grins...
  5387. //
  5388. pIpInfo[NumIps-1].IpAddress[0]=0;
  5389. pIpInfo[NumIps-1].SubnetMask[0]=0;
  5390. break;
  5391. }
  5392. }
  5393. ARRAYSTRCPY(ClusterCfg.NlbParams.ded_ip_addr, CVY_DEF_DED_IP_ADDR);
  5394. ARRAYSTRCPY(ClusterCfg.NlbParams.ded_net_mask, CVY_DEF_DED_NET_MASK);
  5395. end:
  5396. return;
  5397. }
  5398. BOOL
  5399. get_used_port_rule_priorities(
  5400. IN const NLB_EXTENDED_CLUSTER_CONFIGURATION &Config,
  5401. IN UINT NumRules,
  5402. IN const WLBS_PORT_RULE rgRules[],
  5403. IN OUT ULONG rgUsedPriorities[] // At least NumRules
  5404. )
  5405. /*
  5406. Add to the array of bitmaps the priority that
  5407. that represents the used priorities for
  5408. each specified port rule. If the port rule is not single-host
  5409. the bitmap for that port rule is left unmodified
  5410. */
  5411. {
  5412. const WLBS_REG_PARAMS *pParams = &Config.NlbParams;
  5413. WLBS_PORT_RULE *pCfgRules = NULL;
  5414. WBEMSTATUS wStatus;
  5415. UINT NumCfgRules = 0;
  5416. BOOL fRet = FALSE;
  5417. //
  5418. // Get the list of port rules in Config.
  5419. //
  5420. wStatus = CfgUtilGetPortRules(
  5421. pParams,
  5422. &pCfgRules,
  5423. &NumCfgRules
  5424. );
  5425. if (FAILED(wStatus))
  5426. {
  5427. pCfgRules = NULL;
  5428. goto end;
  5429. }
  5430. //
  5431. // For each port rule in rgRules, if single-host mode,
  5432. // locate the corresponding port rule in Config, and if found,
  5433. // (and the latter port rule is single-host) make a bitmap out of
  5434. // the single-host priority.
  5435. //
  5436. for (UINT u=0; u<NumRules; u++)
  5437. {
  5438. const WLBS_PORT_RULE *pCfgRule = NULL;
  5439. const WLBS_PORT_RULE *pRule = rgRules+u;
  5440. if (pRule->mode == CVY_SINGLE)
  5441. {
  5442. UINT uPriority = 0;
  5443. pCfgRule = find_port_rule(
  5444. pCfgRules,
  5445. NumCfgRules,
  5446. rgRules[u].virtual_ip_addr,
  5447. rgRules[u].start_port
  5448. );
  5449. if (pCfgRule != NULL && pCfgRule->mode == CVY_SINGLE)
  5450. {
  5451. uPriority = pCfgRule->mode_data.single.priority;
  5452. }
  5453. if (uPriority!=0)
  5454. {
  5455. rgUsedPriorities[u] |= 1<<(uPriority-1);
  5456. }
  5457. }
  5458. }
  5459. end:
  5460. delete[] pCfgRules;
  5461. return fRet;
  5462. }
  5463. const WLBS_PORT_RULE *
  5464. find_port_rule(
  5465. const WLBS_PORT_RULE *pRules,
  5466. UINT NumRules,
  5467. LPCWSTR szVIP,
  5468. UINT StartPort
  5469. )
  5470. /*
  5471. Locate the port rule with the specified vip and start-port.
  5472. Return pointer to the found rule or NULL if not found.
  5473. */
  5474. {
  5475. const WLBS_PORT_RULE *pFoundRule = NULL;
  5476. LPCWSTR szAllVip = GETRESOURCEIDSTRING(IDS_REPORT_VIP_ALL);
  5477. for (UINT u=0;u<NumRules; u++)
  5478. {
  5479. const WLBS_PORT_RULE *pRule = pRules+u;
  5480. LPCWSTR szRuleVip = pRule->virtual_ip_addr;
  5481. //
  5482. // Unfortunately, "All" and "255.255.255.255" are synonomous :-(
  5483. //
  5484. if (!lstrcmpi(szVIP, L"255.255.255.255"))
  5485. {
  5486. szVIP = szAllVip;
  5487. }
  5488. if (!lstrcmpi(szRuleVip, L"255.255.255.255"))
  5489. {
  5490. szRuleVip = szAllVip;
  5491. }
  5492. if ( !lstrcmpi(szVIP, szRuleVip)
  5493. && StartPort == pRule->start_port)
  5494. {
  5495. pFoundRule = pRule;
  5496. break;
  5497. }
  5498. }
  5499. return pFoundRule;
  5500. }
  5501. CEngineOperation *
  5502. CNlbEngine::mfn_NewOperationLk(ENGINEHANDLE ehObj, PVOID pvCtxt, LPCWSTR szDescription)
  5503. {
  5504. ENGINEHANDLE ehOperation;
  5505. CEngineOperation *pOperation = NULL;
  5506. if (m_fPrepareToDeinitialize)
  5507. {
  5508. goto end;
  5509. }
  5510. ehOperation = CNlbEngine::mfn_NewHandleLk(IUICallbacks::OBJ_OPERATION);
  5511. if (ehOperation == NULL)
  5512. {
  5513. TRACE_CRIT("%!FUNC! could not reserve a new operation handle");
  5514. goto end;
  5515. }
  5516. pOperation = new CEngineOperation(ehOperation, ehObj, pvCtxt);
  5517. if (pOperation == NULL)
  5518. {
  5519. TRACE_CRIT("%!FUNC!: allocation failure");
  5520. goto end;
  5521. }
  5522. pOperation->bstrDescription = _bstr_t(szDescription);
  5523. TRACE_VERB(L"%!FUNC!: map new pair(eh=0x%lx, pISpec=%p), szDescr=%ws",
  5524. (UINT) ehOperation, pOperation,
  5525. szDescription==NULL? L"<null>" : szDescription);
  5526. m_mapIdToOperation[ehOperation] = pOperation;
  5527. end:
  5528. return pOperation;
  5529. }
  5530. VOID
  5531. CNlbEngine::mfn_DeleteOperationLk(ENGINEHANDLE ehOperation)
  5532. {
  5533. CEngineOperation *pOperation;
  5534. pOperation = m_mapIdToOperation[ehOperation];
  5535. if (pOperation == NULL)
  5536. {
  5537. ASSERT(!"corrupted operation");
  5538. TRACE_CRIT("%!FUNC! corrupted operation eh 0x%lx!", ehOperation);
  5539. }
  5540. else
  5541. {
  5542. m_mapIdToOperation.erase(ehOperation);
  5543. TRACE_VERB("%!FUNC! deleting operation eh 0x%lx pOp 0x%p",
  5544. ehOperation, pOperation);
  5545. pOperation->ehOperation = NULL;
  5546. delete pOperation;
  5547. }
  5548. }
  5549. CEngineOperation *
  5550. CNlbEngine::mfn_GetOperationLk(ENGINEHANDLE ehOp)
  5551. {
  5552. CEngineOperation *pOperation;
  5553. pOperation = m_mapIdToOperation[ehOp];
  5554. if (pOperation == NULL || pOperation->ehOperation != ehOp)
  5555. {
  5556. TRACE_CRIT("%!FUNC! invalid or corrupt ehOp 0x%lx (pOp=0x%p)",
  5557. ehOp, pOperation);
  5558. pOperation = NULL;
  5559. }
  5560. return pOperation;
  5561. }
  5562. NLBERROR
  5563. CNlbEngine::mfn_StartInterfaceOperationLk(
  5564. IN ENGINEHANDLE ehIF,
  5565. IN PVOID pvCtxt,
  5566. IN LPCWSTR szDescription,
  5567. OUT ENGINEHANDLE *pExistingOperation
  5568. )
  5569. {
  5570. NLBERROR nerr = NLBERR_OK;
  5571. CInterfaceSpec *pISpec = NULL;
  5572. CEngineOperation *pOperation = NULL;
  5573. *pExistingOperation = NULL;
  5574. pISpec = m_mapIdToInterfaceSpec[ehIF]; // map
  5575. if (pISpec == NULL)
  5576. {
  5577. nerr = NLBERR_NOT_FOUND;
  5578. goto end;
  5579. }
  5580. if (pISpec->m_ehPendingOperation != NULL)
  5581. {
  5582. TRACE_CRIT("%!FUNC!: Not starting operation on ehIF 0x%lx because operation 0x%lx already pending",
  5583. ehIF, pISpec->m_ehPendingOperation);
  5584. *pExistingOperation = pISpec->m_ehPendingOperation;
  5585. nerr = NLBERR_BUSY;
  5586. goto end;
  5587. }
  5588. pOperation = mfn_NewOperationLk(
  5589. ehIF,
  5590. pvCtxt,
  5591. szDescription
  5592. );
  5593. if (pOperation == NULL)
  5594. {
  5595. nerr = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  5596. goto end;
  5597. }
  5598. TRACE_VERB("%!FUNC!: Starting operation eh 0x%lx on ehIF 0x%lx",
  5599. pOperation->ehOperation, ehIF);
  5600. pISpec->m_ehPendingOperation = pOperation->ehOperation;
  5601. pISpec->m_fPending = TRUE;
  5602. nerr = NLBERR_OK;
  5603. // fall through ...
  5604. end:
  5605. return nerr;
  5606. }
  5607. VOID
  5608. CNlbEngine::mfn_StopInterfaceOperationLk(
  5609. IN ENGINEHANDLE ehIF
  5610. )
  5611. {
  5612. CInterfaceSpec *pISpec = NULL;
  5613. ENGINEHANDLE ehOperation = NULL;
  5614. pISpec = m_mapIdToInterfaceSpec[ehIF]; // map
  5615. if (pISpec == NULL)
  5616. {
  5617. TRACE_CRIT("%!FUNC!: Invalid ehIF 0x%lx", ehIF);
  5618. goto end;
  5619. }
  5620. ehOperation = pISpec->m_ehPendingOperation;
  5621. if (ehOperation != NULL)
  5622. {
  5623. TRACE_VERB("%!FUNC!: Stopping operation eh 0x%lx on pIspec 0x%p",
  5624. ehOperation, pISpec);
  5625. pISpec->m_ehPendingOperation = NULL;
  5626. pISpec->m_fPending = FALSE;
  5627. mfn_DeleteOperationLk(ehOperation);
  5628. }
  5629. else
  5630. {
  5631. TRACE_VERB("%!FUNC!: No operation to stop on pISpec 0x%p", pISpec);
  5632. }
  5633. end:
  5634. return;
  5635. }
  5636. NLBERROR
  5637. CNlbEngine::mfn_StartClusterOperationLk(
  5638. IN ENGINEHANDLE ehCluster,
  5639. IN PVOID pvCtxt,
  5640. IN LPCWSTR szDescription,
  5641. OUT ENGINEHANDLE *pExistingOperation
  5642. )
  5643. {
  5644. NLBERROR nerr = NLBERR_OK;
  5645. CEngineCluster *pECluster = NULL;
  5646. CClusterSpec *pCSpec = NULL;
  5647. CEngineOperation *pOperation = NULL;
  5648. *pExistingOperation = NULL;
  5649. pECluster = m_mapIdToEngineCluster[ehCluster]; // map
  5650. if (pECluster == NULL)
  5651. {
  5652. nerr = NLBERR_NOT_FOUND;
  5653. goto end;
  5654. }
  5655. pCSpec = &pECluster->m_cSpec;
  5656. if (pCSpec->m_ehPendingOperation != NULL)
  5657. {
  5658. TRACE_CRIT("%!FUNC!: Not starting operation on ehCluster 0x%lx because operation 0x%lx already pending",
  5659. ehCluster, pCSpec->m_ehPendingOperation);
  5660. *pExistingOperation = pCSpec->m_ehPendingOperation;
  5661. nerr = NLBERR_BUSY;
  5662. goto end;
  5663. }
  5664. pOperation = mfn_NewOperationLk(
  5665. ehCluster,
  5666. pvCtxt,
  5667. szDescription
  5668. );
  5669. if (pOperation == NULL)
  5670. {
  5671. nerr = NLBERR_RESOURCE_ALLOCATION_FAILURE;
  5672. goto end;
  5673. }
  5674. TRACE_VERB("%!FUNC!: Starting operation eh 0x%lx on ehC 0x%lx",
  5675. pOperation->ehOperation, ehCluster);
  5676. pCSpec->m_ehPendingOperation = pOperation->ehOperation;
  5677. pCSpec->m_fPending = TRUE;
  5678. nerr = NLBERR_OK;
  5679. // fall through ...
  5680. end:
  5681. return nerr;
  5682. }
  5683. VOID
  5684. CNlbEngine::mfn_StopClusterOperationLk(
  5685. ENGINEHANDLE ehCluster
  5686. )
  5687. {
  5688. CEngineCluster *pECluster = NULL;
  5689. CClusterSpec *pCSpec = NULL;
  5690. ENGINEHANDLE ehOperation = NULL;
  5691. pECluster = m_mapIdToEngineCluster[ehCluster]; // map
  5692. if (pECluster == NULL)
  5693. {
  5694. TRACE_CRIT("%!FUNC!: Invalid ehC 0x%lx", ehCluster);
  5695. goto end;
  5696. }
  5697. pCSpec = &pECluster->m_cSpec;
  5698. ehOperation = pCSpec->m_ehPendingOperation;
  5699. if (ehOperation != NULL)
  5700. {
  5701. TRACE_VERB("%!FUNC!: Stopping operation eh 0x%lx on pCSpec 0x%p",
  5702. ehOperation, pCSpec);
  5703. pCSpec->m_ehPendingOperation = NULL;
  5704. pCSpec->m_fPending = FALSE;
  5705. mfn_DeleteOperationLk(ehOperation);
  5706. }
  5707. else
  5708. {
  5709. TRACE_VERB("%!FUNC!: No operation to stop on pCSpec 0x%p", pCSpec);
  5710. }
  5711. end:
  5712. return;
  5713. }
  5714. UINT
  5715. CNlbEngine::ListPendingOperations(
  5716. CLocalLogger &logOperations
  5717. )
  5718. //
  5719. // List pending operations -- but ONLY list those operations that
  5720. // contain non-null, non-blank descriptions.
  5721. //
  5722. {
  5723. UINT uCount = 0;
  5724. mfn_Lock();
  5725. map< ENGINEHANDLE, CEngineOperation* >::iterator iter;
  5726. for( iter = m_mapIdToOperation.begin();
  5727. iter != m_mapIdToOperation.end();
  5728. ++iter)
  5729. {
  5730. CEngineOperation *pOperation = ((*iter).second);
  5731. if (pOperation != NULL)
  5732. {
  5733. LPCWSTR szDescr = pOperation->bstrDescription;
  5734. //
  5735. // Only add operations with non-null, non-blank descriptions.
  5736. // We don't list "hidden" operations -- specifically
  5737. // the transient operation created in the background work item
  5738. // to make sure that the app doesn't go away while in the work item.
  5739. //
  5740. if (szDescr != NULL && *szDescr!=0)
  5741. {
  5742. logOperations.Log(
  5743. IDS_LOG_PENDING_OPERATION,
  5744. szDescr
  5745. );
  5746. uCount++;
  5747. }
  5748. }
  5749. }
  5750. mfn_Unlock();
  5751. return uCount;
  5752. }
  5753. VOID
  5754. CNlbEngine::UpdateInterfaceWorkItem(ENGINEHANDLE ehIF)
  5755. {
  5756. ENGINEHANDLE ehOperation = NULL;
  5757. ENGINEHANDLE ehClusterId = NULL;
  5758. CEngineOperation *pExistingOp = NULL;
  5759. CInterfaceSpec *pISpec = NULL;
  5760. ENGINEHANDLE ehHostToTryRemove = NULL;
  5761. NLB_EXTENDED_CLUSTER_CONFIGURATION
  5762. *pNewCfg = NULL;
  5763. _bstr_t bstrHostName;
  5764. _bstr_t bstrClusterIp;
  5765. mfn_Lock();
  5766. pISpec = m_mapIdToInterfaceSpec[ehIF]; // map
  5767. if (pISpec == NULL)
  5768. {
  5769. ASSERT(FALSE);
  5770. TRACE_CRIT("%!FUNC! Invalid ehIF 0x%lx", ehIF);
  5771. goto end_unlock;
  5772. }
  5773. ehOperation = pISpec->m_ehPendingOperation;
  5774. if (ehOperation == NULL)
  5775. {
  5776. ASSERT(FALSE);
  5777. TRACE_CRIT("%!FUNC! ehIF 0x%lx: No pending operation", ehIF);
  5778. goto end_unlock;
  5779. }
  5780. pExistingOp = mfn_GetOperationLk(ehOperation);
  5781. if (pExistingOp == NULL)
  5782. {
  5783. ASSERT(FALSE);
  5784. TRACE_CRIT("%!FUNC! ehIF 0x%lx: Invalid ehOp 0x%lx", ehIF, ehOperation);
  5785. goto end_unlock;
  5786. }
  5787. pNewCfg = (NLB_EXTENDED_CLUSTER_CONFIGURATION *) pExistingOp->pvContext;
  5788. if (pNewCfg == NULL)
  5789. {
  5790. ASSERT(FALSE);
  5791. TRACE_CRIT("%!FUNC! ehIF 0x%lx: ehOp 0x%lx: NULL pvContext",
  5792. ehIF, ehOperation);
  5793. goto end_unlock;
  5794. }
  5795. bstrClusterIp = pNewCfg->NlbParams.cl_ip_addr;
  5796. ehClusterId = pISpec->m_ehCluster;
  5797. mfn_GetInterfaceHostNameLk(
  5798. ehIF,
  5799. REF bstrHostName
  5800. );
  5801. mfn_Unlock();
  5802. //
  5803. // Actually do the update...
  5804. //
  5805. // BOOL fClusterPropertiesUpdated = TRUE; // so we won't update...
  5806. mfn_ReallyUpdateInterface(
  5807. ehIF,
  5808. *pNewCfg
  5809. // REF fClusterPropertiesUpdated
  5810. );
  5811. m_pCallbacks->Log(
  5812. IUICallbacks::LOG_INFORMATIONAL,
  5813. (LPCWSTR) bstrClusterIp,
  5814. (LPCWSTR) bstrHostName,
  5815. IDS_LOG_END_HOST_UPDATE
  5816. );
  5817. mfn_Lock();
  5818. //
  5819. // We'll stop the operation, assumed to be started in this function.
  5820. //
  5821. mfn_StopInterfaceOperationLk(ehIF);
  5822. //
  5823. // The operation could have added or removed the IF to a cluster,
  5824. // so we need to re-obtain the cluster ID (could be NULL).
  5825. //
  5826. {
  5827. pISpec = m_mapIdToInterfaceSpec[ehIF]; // map
  5828. if (pISpec != NULL)
  5829. {
  5830. ehClusterId = pISpec->m_ehCluster;
  5831. //
  5832. // If NLB is unbound we need to check if the host can be
  5833. // completely removed from nlbmgr (if no interfaces on
  5834. // the host are managed by this instance of nlbmgr).
  5835. //
  5836. if (!pISpec->m_NlbCfg.IsNlbBound())
  5837. {
  5838. ehHostToTryRemove = pISpec->m_ehHostId;
  5839. }
  5840. }
  5841. }
  5842. mfn_Unlock();
  5843. //
  5844. // Notify the UI about the status change (operation complete)
  5845. //
  5846. m_pCallbacks->HandleEngineEvent(
  5847. IUICallbacks::OBJ_INTERFACE,
  5848. ehClusterId,
  5849. ehIF,
  5850. IUICallbacks::EVT_STATUS_CHANGE
  5851. );
  5852. mfn_Lock();
  5853. //fall through
  5854. end_unlock:
  5855. //
  5856. // pNewCfg (if non null) was allocated before this function was
  5857. // called, and saved as the pOperation->pvContext. It's our responsibility
  5858. // to delete it here.
  5859. //
  5860. delete pNewCfg;
  5861. if (ehHostToTryRemove != NULL)
  5862. {
  5863. mfn_DeleteHostIfNotManagedLk(ehHostToTryRemove);
  5864. }
  5865. mfn_Unlock();
  5866. //
  5867. // This must be the LAST function call, because the engine may get
  5868. // wiped out after this.
  5869. //
  5870. InterlockedDecrement(&m_WorkItemCount);
  5871. }
  5872. NLBERROR
  5873. CNlbEngine::CanStartInterfaceOperation(
  5874. IN ENGINEHANDLE ehIF,
  5875. IN BOOL &fCanStart
  5876. )
  5877. {
  5878. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  5879. CInterfaceSpec *pISpec = NULL;
  5880. fCanStart = FALSE;
  5881. mfn_Lock();
  5882. pISpec = m_mapIdToInterfaceSpec[ehIF]; // map
  5883. if (pISpec == NULL)
  5884. {
  5885. nerr = NLBERR_NOT_FOUND;
  5886. goto end_unlock;
  5887. }
  5888. //
  5889. // If there is an operation ongoing, we can't start
  5890. //
  5891. if (pISpec->m_ehPendingOperation != NULL)
  5892. {
  5893. fCanStart = FALSE;
  5894. nerr = NLBERR_OK;
  5895. goto end_unlock;
  5896. }
  5897. //
  5898. // If the interface is part of a cluster, and there is a pending operation
  5899. // on that cluster, we can't start
  5900. //
  5901. if (pISpec->m_ehCluster != NULL)
  5902. {
  5903. CEngineCluster *pECluster = m_mapIdToEngineCluster[pISpec->m_ehCluster]; // map
  5904. if (pECluster == NULL)
  5905. {
  5906. //
  5907. // Invalid cluster!
  5908. //
  5909. TRACE_CRIT("%!FUNC! ehIF:0x%lx; Invalid ehCluster 0x%lx",
  5910. ehIF, pISpec->m_ehCluster);
  5911. goto end_unlock;
  5912. }
  5913. if (pECluster->m_cSpec.m_ehPendingOperation != NULL)
  5914. {
  5915. //
  5916. // A cluster-wide operation is pending -- so can't start.
  5917. //
  5918. fCanStart = FALSE;
  5919. nerr = NLBERR_OK;
  5920. goto end_unlock;
  5921. }
  5922. }
  5923. //
  5924. // Looks like we CAN start at this time (although the moment we
  5925. // exit the lock the situation may change).
  5926. //
  5927. fCanStart = TRUE;
  5928. nerr = NLBERR_OK;
  5929. end_unlock:
  5930. mfn_Unlock();
  5931. return nerr;
  5932. }
  5933. NLBERROR
  5934. CNlbEngine::mfn_ClusterOrInterfaceOperationsPendingLk(
  5935. IN CEngineCluster *pECluster,
  5936. OUT BOOL &fCanStart
  5937. )
  5938. {
  5939. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  5940. fCanStart = FALSE;
  5941. //
  5942. // If there is an operation ongoing, we can't start
  5943. //
  5944. if (pECluster->m_cSpec.m_ehPendingOperation != NULL)
  5945. {
  5946. fCanStart = FALSE;
  5947. nerr = NLBERR_OK;
  5948. goto end;
  5949. }
  5950. //
  5951. // Lets look at all of our interfaces, checking if there are pending
  5952. // operations on each of the interfaces.
  5953. //
  5954. {
  5955. BOOL fOperationPending = FALSE;
  5956. vector<ENGINEHANDLE> &InterfaceList =
  5957. pECluster->m_cSpec.m_ehInterfaceIdList; // vector reference
  5958. for( int i = 0; i < InterfaceList.size(); ++i )
  5959. {
  5960. ENGINEHANDLE ehIF = InterfaceList[i];
  5961. CInterfaceSpec *pISpec = m_mapIdToInterfaceSpec[ehIF]; // map
  5962. if (pISpec == NULL)
  5963. {
  5964. //
  5965. // Hmm... invalid interface handle? We'll ignore this one.
  5966. //
  5967. continue;
  5968. }
  5969. if (pISpec->m_ehPendingOperation != NULL)
  5970. {
  5971. fOperationPending = TRUE;
  5972. break;
  5973. }
  5974. }
  5975. if (fOperationPending)
  5976. {
  5977. fCanStart = FALSE;
  5978. nerr = NLBERR_OK;
  5979. goto end;
  5980. }
  5981. }
  5982. //
  5983. // Looks like we CAN start at this time (although the moment we
  5984. // exit the lock the situation may change).
  5985. //
  5986. fCanStart = TRUE;
  5987. nerr = NLBERR_OK;
  5988. end:
  5989. return nerr;
  5990. }
  5991. NLBERROR
  5992. CNlbEngine::CanStartClusterOperation(
  5993. IN ENGINEHANDLE ehCluster,
  5994. IN BOOL &fCanStart
  5995. )
  5996. {
  5997. CEngineCluster *pECluster = NULL;
  5998. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  5999. fCanStart = FALSE;
  6000. mfn_Lock();
  6001. pECluster = m_mapIdToEngineCluster[ehCluster]; // map
  6002. if (pECluster == NULL)
  6003. {
  6004. nerr = NLBERR_NOT_FOUND;
  6005. }
  6006. else
  6007. {
  6008. nerr = mfn_ClusterOrInterfaceOperationsPendingLk(pECluster, REF fCanStart);
  6009. }
  6010. mfn_Unlock();
  6011. return nerr;
  6012. }
  6013. DWORD
  6014. WINAPI
  6015. UpdateInterfaceWorkItemRoutine(
  6016. LPVOID lpParameter // thread data
  6017. )
  6018. {
  6019. gEngine.UpdateInterfaceWorkItem((ENGINEHANDLE) (UINT_PTR) lpParameter);
  6020. return 0;
  6021. }
  6022. DWORD
  6023. WINAPI
  6024. AddClusterMembersWorkItemRoutine(
  6025. LPVOID lpParameter // thread data
  6026. )
  6027. {
  6028. gEngine.AddOtherClusterMembersWorkItem(
  6029. (ENGINEHANDLE) (UINT_PTR) lpParameter
  6030. );
  6031. return 0;
  6032. }
  6033. BOOL
  6034. CNlbEngine::mfn_UpdateClusterProps(
  6035. ENGINEHANDLE ehCluster,
  6036. ENGINEHANDLE ehInterface
  6037. )
  6038. /*
  6039. Update the specified cluster properties to be the specified interface
  6040. properties PROVIDED:
  6041. 1. The IF is a member of the cluster
  6042. 2. The configuration shows that it is bound to the same cluster IP.
  6043. Return true iff the cluter props were actually updated.
  6044. */
  6045. {
  6046. BOOL fClusterUpdated = FALSE;
  6047. CEngineCluster *pECluster = NULL;
  6048. CInterfaceSpec *pISpec = NULL;
  6049. mfn_Lock();
  6050. pECluster = m_mapIdToEngineCluster[ehCluster]; // map
  6051. pISpec = m_mapIdToInterfaceSpec[ehInterface]; // map
  6052. if (pECluster == NULL || pISpec == NULL)
  6053. {
  6054. goto end_unlock;
  6055. }
  6056. if (pISpec->m_ehCluster != ehCluster)
  6057. {
  6058. goto end_unlock;
  6059. }
  6060. if ( pISpec->m_NlbCfg.IsValidNlbConfig()
  6061. && !_wcsicmp(
  6062. pECluster->m_cSpec.m_ClusterNlbCfg.NlbParams.cl_ip_addr,
  6063. pISpec->m_NlbCfg.NlbParams.cl_ip_addr
  6064. ) )
  6065. {
  6066. pECluster->m_cSpec.m_ehDefaultInterface = ehInterface;
  6067. pECluster->m_cSpec.m_ClusterNlbCfg.Update(&pISpec->m_NlbCfg);
  6068. TRACE_INFO(L"Updating ehCluster 0x%lx spec -- using ehIF 0x%lx",
  6069. ehCluster, ehInterface);
  6070. //
  6071. // Remove the dedicated IP address from cluster's version of
  6072. // the NlbParams and the IP address list.
  6073. //
  6074. remove_dedicated_ip_from_nlbcfg(REF pECluster->m_cSpec.m_ClusterNlbCfg);
  6075. //
  6076. // Since we've just read all the config (including remote control hash
  6077. // value) we can now clear the pECluster->m_cSpec.m_fNewRctPassword
  6078. // flag.
  6079. //
  6080. TRACE_VERB(L"Clearing pECluster->m_cSpec.m_fNewRctPassword");
  6081. pECluster->m_cSpec.m_fNewRctPassword = FALSE;
  6082. fClusterUpdated = TRUE;
  6083. }
  6084. end_unlock:
  6085. mfn_Unlock();
  6086. if (fClusterUpdated)
  6087. {
  6088. m_pCallbacks->HandleEngineEvent(
  6089. IUICallbacks::OBJ_CLUSTER,
  6090. ehCluster,
  6091. ehCluster,
  6092. IUICallbacks::EVT_STATUS_CHANGE
  6093. );
  6094. }
  6095. return fClusterUpdated;
  6096. }
  6097. void
  6098. CNlbEngine::CancelAllPendingOperations(
  6099. BOOL fBlock
  6100. )
  6101. {
  6102. //
  6103. // if (fBlock), we wait until BOTH m_WorkItemCount and
  6104. // the number of operations goes to zero.
  6105. //
  6106. // An Operations are created BEFORE the workitemcount is incremented,
  6107. // so we don't have to deal with the transient possibility that
  6108. // both are zero (and we get out) but soon after the count goes to non
  6109. // zero
  6110. //
  6111. map< ENGINEHANDLE, CEngineOperation* >::iterator iter;
  6112. if (!fBlock)
  6113. {
  6114. mfn_Lock();
  6115. for( iter = m_mapIdToOperation.begin();
  6116. iter != m_mapIdToOperation.end();
  6117. ++iter)
  6118. {
  6119. CEngineOperation *pOperation = ((*iter).second);
  6120. if (pOperation != NULL)
  6121. {
  6122. pOperation->fCanceled = TRUE;
  6123. }
  6124. }
  6125. mfn_Unlock();
  6126. }
  6127. else
  6128. {
  6129. //
  6130. // If we're asked to block, we assume that this is while
  6131. // we're prepairing to deinitialize, at which point we are
  6132. // guaranteed that no new operations can be added.
  6133. // It is possible that new work items can be added,
  6134. // however a work item is created in the context of
  6135. // an operation, so once the operation count goes
  6136. // to zero, no new work items will be created.
  6137. //
  6138. ASSERT(m_fPrepareToDeinitialize);
  6139. BOOL fPending = FALSE;
  6140. do
  6141. {
  6142. fPending = FALSE;
  6143. mfn_Lock();
  6144. for( iter = m_mapIdToOperation.begin();
  6145. iter != m_mapIdToOperation.end();
  6146. ++iter)
  6147. {
  6148. CEngineOperation *pOperation = ((*iter).second);
  6149. if (pOperation != NULL)
  6150. {
  6151. pOperation->fCanceled = TRUE;
  6152. fPending = TRUE;
  6153. }
  6154. }
  6155. //
  6156. // The additional check below must come AFTER the previous
  6157. // loop. If we had this check before the loop, it could be that
  6158. // there are no work item's before we check the loop, but the
  6159. // instant we check the loop for operations, the work item count
  6160. // goes positive but when we actually check the loop here are zero
  6161. // operations. Actually that's not possible because we have
  6162. // mfn_Lock held, so never mind.
  6163. //
  6164. //
  6165. fPending |= (m_WorkItemCount > 0);
  6166. mfn_Unlock();
  6167. if (fPending)
  6168. {
  6169. ProcessMsgQueue();
  6170. Sleep(50);
  6171. }
  6172. } while (fPending);
  6173. }
  6174. return;
  6175. }
  6176. NLBERROR
  6177. CNlbEngine::mfn_WaitForInterfaceOperationCompletions(
  6178. IN ENGINEHANDLE ehCluster
  6179. )
  6180. {
  6181. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  6182. CEngineCluster *pECluster = NULL;
  6183. CClusterSpec *pCSpec = NULL;
  6184. ENGINEHANDLE ehOperation = NULL;
  6185. BOOL fOperationsPending = FALSE;
  6186. mfn_Lock();
  6187. pECluster = m_mapIdToEngineCluster[ehCluster]; // map
  6188. if (pECluster == NULL)
  6189. {
  6190. TRACE_CRIT("%!FUNC!: Invalid ehC 0x%lx", ehCluster);
  6191. goto end_unlock;
  6192. }
  6193. pCSpec = &pECluster->m_cSpec;
  6194. ehOperation = pCSpec->m_ehPendingOperation;
  6195. if (ehOperation == NULL)
  6196. {
  6197. //
  6198. // We expect that this function is only called when there is a
  6199. // pending cluster-wide operation.
  6200. //
  6201. TRACE_CRIT("%!FUNC! ehC 0x%lx Failing because no cluster operation pending", ehCluster);
  6202. goto end_unlock;
  6203. }
  6204. //
  6205. // Now in a loop, enumerate the interfaces in the cluster,
  6206. // cheking for pending operations.
  6207. //
  6208. TRACE_INFO(L"%!FUNC! Begin wait for cluster ehC 0x%lx operations to complete", ehCluster);
  6209. do
  6210. {
  6211. fOperationsPending = FALSE;
  6212. vector<ENGINEHANDLE> &InterfaceList =
  6213. pECluster->m_cSpec.m_ehInterfaceIdList; // vector reference
  6214. for( int i = 0; i < InterfaceList.size(); ++i )
  6215. {
  6216. ENGINEHANDLE ehIF = InterfaceList[i];
  6217. CInterfaceSpec *pISpec = m_mapIdToInterfaceSpec[ehIF]; // map
  6218. if (pISpec == NULL)
  6219. {
  6220. //
  6221. // Hmm... invalid interface handle? We'll ignore this one.
  6222. //
  6223. continue;
  6224. }
  6225. if (pISpec->m_ehPendingOperation != NULL)
  6226. {
  6227. fOperationsPending = TRUE;
  6228. break;
  6229. }
  6230. }
  6231. if (fOperationsPending)
  6232. {
  6233. mfn_Unlock();
  6234. for (UINT u=0;u<50;u++)
  6235. {
  6236. ProcessMsgQueue();
  6237. Sleep(100);
  6238. }
  6239. mfn_Lock();
  6240. }
  6241. }
  6242. while (fOperationsPending);
  6243. TRACE_INFO(L"%!FUNC! End wait for cluster ehC 0x%lx operations to complete.", ehCluster);
  6244. nerr = NLBERR_OK;
  6245. end_unlock:
  6246. mfn_Unlock();
  6247. return nerr;
  6248. }
  6249. //
  6250. // Verifies that all interfaces and the cluster have the same cluster mode.
  6251. //
  6252. // Will fail if any interface is marked misconfigured or is
  6253. // not bound to NLB.
  6254. //
  6255. // On returning success, fSameMode is set to TRUE iff all IFs and the
  6256. // cluster have the same mode.
  6257. //
  6258. NLBERROR
  6259. CNlbEngine::mfn_VerifySameModeLk(
  6260. IN ENGINEHANDLE ehCluster,
  6261. OUT BOOL &fSameMode
  6262. )
  6263. {
  6264. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  6265. CEngineCluster *pECluster = NULL;
  6266. CClusterSpec *pCSpec = NULL;
  6267. fSameMode = FALSE;
  6268. mfn_Lock();
  6269. pECluster = m_mapIdToEngineCluster[ehCluster]; // map
  6270. if (pECluster == NULL)
  6271. {
  6272. TRACE_CRIT("%!FUNC!: Invalid ehC 0x%lx", ehCluster);
  6273. goto end_unlock;
  6274. }
  6275. pCSpec = &pECluster->m_cSpec;
  6276. //
  6277. // Let's check for mode changes...
  6278. //
  6279. {
  6280. BOOL fConfigError = FALSE;
  6281. NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE tmC;
  6282. tmC = pCSpec->m_ClusterNlbCfg.GetTrafficMode();
  6283. vector<ENGINEHANDLE> &InterfaceList =
  6284. pECluster->m_cSpec.m_ehInterfaceIdList; // vector reference
  6285. fSameMode = TRUE;
  6286. for( int i = 0; i < InterfaceList.size(); ++i )
  6287. {
  6288. ENGINEHANDLE ehIF = InterfaceList[i];
  6289. CInterfaceSpec *pISpec = m_mapIdToInterfaceSpec[ehIF]; // map
  6290. if (pISpec == NULL)
  6291. {
  6292. //
  6293. // Hmm... invalid interface handle? We'll ignore this one.
  6294. //
  6295. continue;
  6296. }
  6297. //
  6298. // Note: we can't check for pISpec->m_fMisconfigured because
  6299. // the cluster may be marked misconfig because it doesn't
  6300. // match the cluster parameters, which can happen on
  6301. // mode changes (the ip addresses could be missing in the
  6302. // interface).
  6303. //
  6304. if (!pISpec->m_NlbCfg.IsValidNlbConfig())
  6305. {
  6306. fConfigError = TRUE;
  6307. break;
  6308. }
  6309. {
  6310. NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE tmI;
  6311. tmI = pISpec->m_NlbCfg.GetTrafficMode();
  6312. if (tmI != tmC)
  6313. {
  6314. //
  6315. // Mode change!
  6316. //
  6317. fSameMode = FALSE;
  6318. break;
  6319. }
  6320. }
  6321. }
  6322. if (fConfigError)
  6323. {
  6324. nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION;
  6325. fSameMode = FALSE;
  6326. }
  6327. else
  6328. {
  6329. nerr = NLBERR_OK;
  6330. }
  6331. }
  6332. end_unlock:
  6333. mfn_Unlock();
  6334. return nerr;
  6335. }
  6336. VOID
  6337. CNlbEngine::AddOtherClusterMembers(
  6338. IN ENGINEHANDLE ehInterface,
  6339. IN BOOL fSync
  6340. )
  6341. {
  6342. BOOL fStopOperationOnExit = FALSE;
  6343. ENGINEHANDLE ehCluster = NULL;
  6344. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  6345. //
  6346. // Get cluster ID, and attempt to start a cluster-wide operation
  6347. // on it
  6348. //
  6349. {
  6350. mfn_Lock();
  6351. CInterfaceSpec *pISpec = NULL;
  6352. CClusterSpec *pCSpec = NULL;
  6353. pISpec = m_mapIdToInterfaceSpec[ehInterface]; // map
  6354. if (pISpec != NULL)
  6355. {
  6356. ehCluster = pISpec->m_ehCluster;
  6357. if (ehCluster != NULL)
  6358. {
  6359. CEngineCluster *pECluster = NULL;
  6360. pECluster = m_mapIdToEngineCluster[ehCluster]; // map
  6361. pCSpec = &pECluster->m_cSpec;
  6362. }
  6363. }
  6364. if (pCSpec == NULL)
  6365. {
  6366. TRACE_CRIT(L"%!FUNC! Could not get interface or cluster associated with ehIF 0x%08lx", ehInterface);
  6367. goto end_unlock;
  6368. }
  6369. //
  6370. // Attempt to start the update operation -- will fail if there is
  6371. // already an operation started on this cluster.
  6372. //
  6373. {
  6374. ENGINEHANDLE ExistingOp= NULL;
  6375. CLocalLogger logDescription;
  6376. logDescription.Log(
  6377. IDS_LOG_ADD_CLUSTER_MEMBERS_OPERATION_DESCRIPTION,
  6378. pCSpec->m_ClusterNlbCfg.NlbParams.cl_ip_addr
  6379. );
  6380. nerr = mfn_StartClusterOperationLk(
  6381. ehCluster,
  6382. NULL, // pvCtxt
  6383. logDescription.GetStringSafe(),
  6384. &ExistingOp
  6385. );
  6386. if (NLBFAILED(nerr))
  6387. {
  6388. //
  6389. // TODO: Log the fact that we couldn't do the update because
  6390. // of existing activity.
  6391. //
  6392. goto end_unlock;
  6393. }
  6394. else
  6395. {
  6396. //
  6397. // At this point we're cleared to do a cluster-wide operation.
  6398. //
  6399. fStopOperationOnExit = TRUE;
  6400. InterlockedIncrement(&m_WorkItemCount);
  6401. }
  6402. }
  6403. mfn_Unlock();
  6404. m_pCallbacks->HandleEngineEvent(
  6405. IUICallbacks::OBJ_CLUSTER,
  6406. ehCluster,
  6407. ehCluster,
  6408. IUICallbacks::EVT_STATUS_CHANGE
  6409. );
  6410. }
  6411. if (fSync)
  6412. {
  6413. this->AddOtherClusterMembersWorkItem(
  6414. ehInterface
  6415. );
  6416. fStopOperationOnExit = FALSE; // it'll be stopped by the above func.
  6417. }
  6418. else
  6419. {
  6420. BOOL fRet;
  6421. //
  6422. // We'll perform the operation in the background...
  6423. //
  6424. fRet = QueueUserWorkItem(
  6425. AddClusterMembersWorkItemRoutine,
  6426. (PVOID) (UINT_PTR) ehInterface,
  6427. WT_EXECUTELONGFUNCTION
  6428. );
  6429. if (fRet)
  6430. {
  6431. fStopOperationOnExit = FALSE; // it'll be stopped in the background
  6432. }
  6433. else
  6434. {
  6435. TRACE_CRIT(L"%!FUNC! Could not queue work item");
  6436. //
  6437. // We don't bother to log this evidently low-resource situation.
  6438. //
  6439. }
  6440. }
  6441. mfn_Lock();
  6442. end_unlock:
  6443. if (fStopOperationOnExit)
  6444. {
  6445. mfn_StopClusterOperationLk(ehCluster);
  6446. }
  6447. mfn_Unlock();
  6448. if (fStopOperationOnExit)
  6449. {
  6450. m_pCallbacks->HandleEngineEvent(
  6451. IUICallbacks::OBJ_CLUSTER,
  6452. ehCluster,
  6453. ehCluster,
  6454. IUICallbacks::EVT_STATUS_CHANGE
  6455. );
  6456. InterlockedDecrement(&m_WorkItemCount);
  6457. }
  6458. return;
  6459. }
  6460. VOID
  6461. CNlbEngine::AddOtherClusterMembersWorkItem(
  6462. IN ENGINEHANDLE ehInterface
  6463. )
  6464. {
  6465. ENGINEHANDLE ehCluster = NULL;
  6466. ENGINEHANDLE ehHost = NULL;
  6467. _bstr_t bstrUserName;
  6468. _bstr_t bstrPassword;
  6469. _bstr_t bstrConnectionString;
  6470. _bstr_t bstrNicGuid;
  6471. _bstr_t bstrClusterIp;
  6472. DWORD NumMembers = 0;
  6473. NLB_CLUSTER_MEMBER_INFO *pMembers = NULL;
  6474. {
  6475. mfn_Lock();
  6476. CInterfaceSpec *pISpec = NULL;
  6477. CClusterSpec *pCSpec = NULL;
  6478. CHostSpec *pHSpec = NULL;
  6479. pISpec = m_mapIdToInterfaceSpec[ehInterface]; // map
  6480. if (pISpec != NULL)
  6481. {
  6482. ehCluster = pISpec->m_ehCluster;
  6483. if (ehCluster != NULL)
  6484. {
  6485. CEngineCluster *pECluster = NULL;
  6486. pECluster = m_mapIdToEngineCluster[ehCluster]; // map
  6487. pCSpec = &pECluster->m_cSpec;
  6488. if (pCSpec->m_ClusterNlbCfg.IsValidNlbConfig())
  6489. {
  6490. bstrClusterIp = pCSpec->m_ClusterNlbCfg.NlbParams.cl_ip_addr;
  6491. }
  6492. }
  6493. }
  6494. if (pCSpec == NULL)
  6495. {
  6496. TRACE_CRIT(L"%!FUNC! Could not get interface or cluster associated with ehIF 0x%08lx", ehInterface);
  6497. goto end_unlock;
  6498. }
  6499. ehHost = pISpec->m_ehHostId;
  6500. //
  6501. // Get the host ID
  6502. //
  6503. if (ehHost != NULL)
  6504. {
  6505. pHSpec = m_mapIdToHostSpec[ehHost]; // map
  6506. }
  6507. if (pHSpec == NULL)
  6508. {
  6509. TRACE_CRIT("%!FUNC! Could not get ptr to host spec. Bailing.");
  6510. goto end_unlock;
  6511. }
  6512. //
  6513. // Save copies of these in local bstrs before we unlock...
  6514. //
  6515. bstrUserName = pHSpec->m_UserName;
  6516. bstrPassword = pHSpec->m_Password;
  6517. bstrConnectionString = pHSpec->m_ConnectionString;
  6518. bstrNicGuid = pISpec->m_Guid;
  6519. if ((LPCWSTR)bstrNicGuid == (LPCWSTR)NULL)
  6520. {
  6521. // probably a low-memory situation...
  6522. goto end_unlock;
  6523. }
  6524. mfn_Unlock();
  6525. }
  6526. //
  6527. // Attempt to get the list of other cluster members from the
  6528. // interface
  6529. //
  6530. {
  6531. WMI_CONNECTION_INFO ConnInfo;
  6532. WBEMSTATUS wStat;
  6533. LPCWSTR szNicGuid = bstrNicGuid;
  6534. ZeroMemory(&ConnInfo, sizeof(ConnInfo));
  6535. ConnInfo.szMachine = (LPCWSTR) bstrConnectionString;
  6536. ConnInfo.szUserName = (LPCWSTR) bstrUserName;
  6537. ConnInfo.szPassword = (LPCWSTR) bstrPassword;
  6538. wStat = NlbHostGetClusterMembers(
  6539. &ConnInfo,
  6540. szNicGuid,
  6541. &NumMembers,
  6542. &pMembers // free using delete[]
  6543. );
  6544. if (FAILED(wStat))
  6545. {
  6546. NumMembers = 0;
  6547. pMembers = NULL;
  6548. //
  6549. // TODO: Log error
  6550. //
  6551. mfn_Lock();
  6552. goto end_unlock;
  6553. }
  6554. }
  6555. //
  6556. // For each member, attempt to connect to that host and add the specific
  6557. // cluster.
  6558. //
  6559. {
  6560. WBEMSTATUS wStat;
  6561. LPCWSTR szNicGuid = bstrNicGuid;
  6562. #if 0
  6563. CLocalLogger logger;
  6564. for (UINT u=0; u<NumMembers; u++)
  6565. {
  6566. NLB_CLUSTER_MEMBER_INFO *pMember = pMembers+u;
  6567. logger.Log(
  6568. IDS_DBG_LOG_ADD_CLUSTER_MEMBER,
  6569. pMember->HostId,
  6570. pMember->DedicatedIpAddress,
  6571. pMember->HostName
  6572. );
  6573. }
  6574. ::MessageBox(
  6575. NULL,
  6576. logger.GetStringSafe(), // contents
  6577. L"DEBUGINFO: GOING TO ADD THESE HOSTS...",
  6578. MB_ICONINFORMATION | MB_OK
  6579. );
  6580. #endif // 0
  6581. for (UINT u=0; u<NumMembers; u++)
  6582. {
  6583. NLB_CLUSTER_MEMBER_INFO *pMember = pMembers+u;
  6584. WMI_CONNECTION_INFO ConnInfo;
  6585. ZeroMemory(&ConnInfo, sizeof(ConnInfo));
  6586. ConnInfo.szUserName = (LPCWSTR) bstrUserName;
  6587. ConnInfo.szPassword = (LPCWSTR) bstrPassword;
  6588. if (*pMember->HostName != 0)
  6589. {
  6590. ConnInfo.szMachine = pMember->HostName;
  6591. } else if (*pMember->DedicatedIpAddress != 0
  6592. && (_wcsicmp(pMember->DedicatedIpAddress,
  6593. L"0.0.0.0")))
  6594. {
  6595. // non-blank dedicated IP -- let's try that...
  6596. ConnInfo.szMachine = pMember->DedicatedIpAddress;
  6597. }
  6598. if (ConnInfo.szMachine == NULL)
  6599. {
  6600. // Can't connect to this IP
  6601. // TODO: inform user in some way
  6602. continue;
  6603. }
  6604. //
  6605. // Now actually attempt to add the host
  6606. //
  6607. this->LoadHost(&ConnInfo, (LPCWSTR) bstrClusterIp);
  6608. }
  6609. }
  6610. mfn_Lock();
  6611. end_unlock:
  6612. if (ehCluster != NULL)
  6613. {
  6614. mfn_StopClusterOperationLk(ehCluster);
  6615. }
  6616. mfn_Unlock();
  6617. m_pCallbacks->HandleEngineEvent(
  6618. IUICallbacks::OBJ_CLUSTER,
  6619. ehCluster,
  6620. ehCluster,
  6621. IUICallbacks::EVT_STATUS_CHANGE
  6622. );
  6623. delete [] pMembers; // may be NULL
  6624. InterlockedDecrement(&m_WorkItemCount); // Don't touch this after this,
  6625. // because it may no longer be valid
  6626. return;
  6627. }
  6628. NLBERROR
  6629. CNlbEngine::LoadHost(
  6630. IN PWMI_CONNECTION_INFO pConnInfo,
  6631. IN LPCWSTR szClusterIp OPTIONAL
  6632. )
  6633. {
  6634. ENGINEHANDLE ehHostId;
  6635. _bstr_t bstrConnectError;
  6636. CHostSpec hSpec;
  6637. NLBERROR err = NLBERR_INTERNAL_ERROR;
  6638. TRACE_INFO(L"-> %!FUNC! Host name : %ls", (LPCWSTR)(pConnInfo->szMachine));
  6639. if (m_fPrepareToDeinitialize)
  6640. {
  6641. err = NLBERR_CANCELLED;
  6642. goto end;
  6643. }
  6644. m_pCallbacks->Log(IUICallbacks::LOG_INFORMATIONAL, NULL, NULL,
  6645. IDS_LOADFILE_LOOKING_FOR_CLUSTERS, pConnInfo->szMachine);
  6646. ProcessMsgQueue();
  6647. err = this->ConnectToHost(
  6648. pConnInfo,
  6649. FALSE, // FALSE == don't overwrite connection info if
  6650. // already present
  6651. REF ehHostId,
  6652. REF bstrConnectError
  6653. );
  6654. if (err != NLBERR_OK)
  6655. {
  6656. m_pCallbacks->Log(IUICallbacks::LOG_ERROR, NULL, NULL, IDS_CONNECT_TO_HOST_FAILED, (LPCWSTR)bstrConnectError, (LPCWSTR)(pConnInfo->szMachine));
  6657. TRACE_CRIT(L"<- %!FUNC! ConnectToHost returned error (string : %ls, retval : 0x%x)",(LPCWSTR)bstrConnectError, err);
  6658. goto end;
  6659. }
  6660. if ((err = this->GetHostSpec(ehHostId, REF hSpec)) != NLBERR_OK)
  6661. {
  6662. m_pCallbacks->Log(IUICallbacks::LOG_ERROR, NULL, NULL, IDS_CRITICAL_ERROR_HOST, (LPCWSTR)(pConnInfo->szMachine));
  6663. TRACE_CRIT(L"<- %!FUNC! GetHostSpec returned error : 0x%x", err);
  6664. goto end;
  6665. }
  6666. //
  6667. // Extract list of interfaces
  6668. //
  6669. for( int i = 0; i < hSpec.m_ehInterfaceIdList.size(); ++i )
  6670. {
  6671. ENGINEHANDLE ehIID = hSpec.m_ehInterfaceIdList[i];
  6672. CInterfaceSpec iSpec;
  6673. ProcessMsgQueue();
  6674. if ((err = this->GetInterfaceSpec(ehIID, REF iSpec)) != NLBERR_OK)
  6675. {
  6676. m_pCallbacks->Log(IUICallbacks::LOG_ERROR, NULL, NULL, IDS_CRITICAL_ERROR_HOST, (LPCWSTR)(pConnInfo->szMachine));
  6677. TRACE_CRIT(L"%!FUNC! GetInterfaceSpec returned error : 0x%x", err);
  6678. continue;
  6679. }
  6680. //
  6681. // Check if interface has NLB bound to it
  6682. // AND it is NOT part of a cluster that nlb manager is already managing
  6683. // AND (if szClusterIp NON-NULL, it matches the specified cluster IP
  6684. //
  6685. //
  6686. if (iSpec.m_NlbCfg.IsNlbBound() && (iSpec.m_ehCluster == NULL))
  6687. {
  6688. LPCWSTR szThisClusterIp;
  6689. ENGINEHANDLE ehCluster;
  6690. BOOL fIsNew;
  6691. szThisClusterIp = iSpec.m_NlbCfg.NlbParams.cl_ip_addr;
  6692. if ( szClusterIp != NULL
  6693. && _wcsicmp(szClusterIp, szThisClusterIp))
  6694. {
  6695. // different cluster ip
  6696. TRACE_INFO(L"%!FUNC! Skipping cluster with CIP %ws because it doesn't match passed-in CIP %ws",
  6697. szThisClusterIp, szClusterIp);
  6698. continue;
  6699. }
  6700. if ((err = this->LookupClusterByIP(szThisClusterIp, &(iSpec.m_NlbCfg), REF ehCluster, REF fIsNew)) != NLBERR_OK)
  6701. {
  6702. m_pCallbacks->Log(IUICallbacks::LOG_ERROR, NULL, NULL, IDS_CRITICAL_ERROR_HOST, (LPCWSTR)(pConnInfo->szMachine));
  6703. TRACE_CRIT(L"%!FUNC! LookupClusterByIP returned error : 0x%x for cluster ip : %ls", err, szThisClusterIp);
  6704. continue;
  6705. }
  6706. if (this->AddInterfaceToCluster(ehCluster, ehIID) != NLBERR_OK)
  6707. {
  6708. m_pCallbacks->Log(IUICallbacks::LOG_ERROR, NULL, NULL, IDS_CRITICAL_ERROR_HOST, (LPCWSTR)(pConnInfo->szMachine));
  6709. TRACE_CRIT(L"%!FUNC! AddInterfaceToCluster returned error : 0x%x", err);
  6710. continue;
  6711. }
  6712. /* Analyze this interface for misconfiguration */
  6713. this->AnalyzeInterface_And_LogResult(ehIID);
  6714. }
  6715. }
  6716. end:
  6717. ProcessMsgQueue();
  6718. TRACE_INFO(L"<- %!FUNC!");
  6719. return err;
  6720. }
  6721. /*
  6722. The following function analyzes the specified NLB interface for misconfiguration and logs
  6723. the result. I created this function (as opposed to adding it inline) because this code
  6724. needs to run in two cases:
  6725. 1. CNLBEngine::LoadHost
  6726. 2. LeftView::OnWorldConnect
  6727. --KarthicN, July 31, 2002
  6728. */
  6729. VOID
  6730. CNlbEngine::AnalyzeInterface_And_LogResult(ENGINEHANDLE ehIID)
  6731. {
  6732. CLocalLogger logger;
  6733. NLBERROR err;
  6734. mfn_Lock();
  6735. err = this->mfn_AnalyzeInterfaceLk(ehIID, REF logger);
  6736. if (NLBFAILED(err))
  6737. {
  6738. ENGINEHANDLE ehCluster;
  6739. LPCWSTR szDetails = NULL;
  6740. UINT Size = 0;
  6741. logger.ExtractLog(szDetails, Size);
  6742. mfn_SetInterfaceMisconfigStateLk(m_mapIdToInterfaceSpec[ehIID], TRUE, szDetails);
  6743. mfn_Unlock();
  6744. //
  6745. // Log ...
  6746. //
  6747. LPCWSTR szCluster = NULL;
  6748. LPCWSTR szHostName = NULL;
  6749. LPCWSTR szInterface = NULL;
  6750. ENGINEHANDLE ehHost;
  6751. _bstr_t bstrDisplayName;
  6752. _bstr_t bstrFriendlyName;
  6753. _bstr_t bstrHostName;
  6754. _bstr_t bstrIpAddress;
  6755. err = this->GetInterfaceIdentification(
  6756. ehIID,
  6757. REF ehHost,
  6758. REF ehCluster,
  6759. REF bstrFriendlyName,
  6760. REF bstrDisplayName,
  6761. REF bstrHostName
  6762. );
  6763. if (NLBOK(err))
  6764. {
  6765. _bstr_t bstrDomainName;
  6766. _bstr_t bstrClusterDisplayName;
  6767. err = this->GetClusterIdentification(
  6768. ehCluster,
  6769. REF bstrIpAddress,
  6770. REF bstrDomainName,
  6771. REF bstrClusterDisplayName
  6772. );
  6773. if (NLBOK(err))
  6774. {
  6775. szCluster = bstrIpAddress;
  6776. }
  6777. szHostName = bstrHostName;
  6778. szInterface = bstrFriendlyName;
  6779. }
  6780. IUICallbacks::LogEntryHeader Header;
  6781. Header.szDetails = szDetails;
  6782. Header.type = IUICallbacks::LOG_ERROR;
  6783. Header.szCluster = szCluster;
  6784. Header.szHost = szHostName;
  6785. Header.szInterface = szInterface;
  6786. m_pCallbacks->LogEx(
  6787. &Header,
  6788. IDS_LOG_INTERFACE_MISCONFIGURATION
  6789. );
  6790. // Change Icon to "Banged out"
  6791. m_pCallbacks->HandleEngineEvent(
  6792. IUICallbacks::OBJ_INTERFACE,
  6793. ehCluster,
  6794. ehIID,
  6795. IUICallbacks::EVT_STATUS_CHANGE
  6796. );
  6797. }
  6798. else
  6799. {
  6800. mfn_Unlock();
  6801. }
  6802. return;
  6803. }
  6804. VOID
  6805. CNlbEngine::mfn_DeleteHostIfNotManagedLk(
  6806. ENGINEHANDLE ehHost
  6807. )
  6808. /*
  6809. Checks all the interfaces of host ehHost. If none of them are
  6810. members of any cluster, and no pending operations are existing on
  6811. them, we will delete the host and all its interfaces.
  6812. Called with lock held!
  6813. */
  6814. {
  6815. CHostSpec *pHSpec = NULL;
  6816. BOOL fBusy = FALSE;
  6817. UINT u;
  6818. pHSpec = m_mapIdToHostSpec[ehHost]; // map
  6819. if (pHSpec == NULL) goto end;
  6820. // DummyAction(L"DeleteHostIfNotManaged");
  6821. //
  6822. // Go through the list of interfaces, seeing if ANY interface
  6823. // is part of a cluster or there are updates pending on it..
  6824. //
  6825. for(u = 0; u < pHSpec->m_ehInterfaceIdList.size(); ++u )
  6826. {
  6827. ENGINEHANDLE ehIId = pHSpec->m_ehInterfaceIdList[u];
  6828. CInterfaceSpec *pISpec = NULL;
  6829. pISpec = m_mapIdToInterfaceSpec[ehIId]; // map
  6830. if (pISpec == NULL) continue;
  6831. ASSERT(pISpec->m_ehHostId == ehHost);
  6832. if (pISpec->m_ehCluster != NULL)
  6833. {
  6834. // Found an interface still part of a cluster, bail.
  6835. fBusy = TRUE;
  6836. break;
  6837. }
  6838. //
  6839. //
  6840. //
  6841. if (pISpec->m_ehPendingOperation != NULL)
  6842. {
  6843. //
  6844. // We really don't expect this, but it COULD happen.
  6845. //
  6846. TRACE_CRIT("Ignoring eh(0x%x) because it has pending operation 0x%x even though it's not a part of a cluster.",
  6847. ehIId,
  6848. pISpec->m_ehPendingOperation
  6849. );
  6850. fBusy = TRUE;
  6851. break;
  6852. }
  6853. }
  6854. if (fBusy) goto end;
  6855. TRACE_INFO(L"Deleting all interfaces under host eh(0x%x)", ehHost);
  6856. for(u = 0; u < pHSpec->m_ehInterfaceIdList.size(); ++u )
  6857. {
  6858. ENGINEHANDLE ehIId = pHSpec->m_ehInterfaceIdList[u];
  6859. CInterfaceSpec *pISpec = NULL;
  6860. pISpec = m_mapIdToInterfaceSpec[ehIId]; // map
  6861. if (pISpec == NULL) continue;
  6862. ASSERT(pISpec->m_ehHostId == ehHost);
  6863. ASSERT(pISpec->m_ehCluster == NULL); // we checked above
  6864. ASSERT(pISpec->m_ehPendingOperation == NULL); // we checked above
  6865. //
  6866. // Kill this interface!
  6867. //
  6868. TRACE_INFO(L"Deleting Interface eh=0x%x pISpec=0x%p",
  6869. ehIId, pISpec);
  6870. m_mapIdToInterfaceSpec.erase(ehIId);
  6871. delete pISpec;
  6872. }
  6873. //
  6874. // Erase the list of intefaces for this host...
  6875. //
  6876. pHSpec->m_ehInterfaceIdList.clear();
  6877. #if 1
  6878. //
  6879. // Now delete the host
  6880. //
  6881. TRACE_INFO(L"Deleting Host eh=0x%x pHSpec=0x%p",
  6882. ehHost, pHSpec);
  6883. m_mapIdToHostSpec.erase(ehHost);
  6884. delete pHSpec;
  6885. #endif // 0
  6886. end:
  6887. return;
  6888. }
  6889. VOID
  6890. CNlbEngine::PurgeUnmanagedHosts(void)
  6891. {
  6892. vector <ENGINEHANDLE> PurgeHostList;
  6893. TRACE_INFO(L"-> %!FUNC!");
  6894. mfn_Lock();
  6895. map< ENGINEHANDLE, CHostSpec* >::iterator iter;
  6896. for( iter = m_mapIdToHostSpec.begin();
  6897. iter != m_mapIdToHostSpec.end();
  6898. ++iter)
  6899. {
  6900. CHostSpec *pHSpec = (CHostSpec *) ((*iter).second);
  6901. ENGINEHANDLE ehHost = (ENGINEHANDLE) ((*iter).first);
  6902. if (pHSpec != NULL)
  6903. {
  6904. if (!mfn_HostHasManagedClustersLk(pHSpec))
  6905. {
  6906. //
  6907. // No managed clusters on this host -- a candidate
  6908. // for deleting.
  6909. //
  6910. PurgeHostList.push_back(ehHost);
  6911. }
  6912. }
  6913. }
  6914. //
  6915. // Now try to delete the hosts...
  6916. // We do this out of the enumeration above because we want to
  6917. // avoid modifying the map while we're iterating through it.
  6918. //
  6919. for(int i = 0; i < PurgeHostList.size(); ++i )
  6920. {
  6921. ENGINEHANDLE ehHost = PurgeHostList[i];
  6922. if (ehHost != NULL)
  6923. {
  6924. mfn_DeleteHostIfNotManagedLk(ehHost);
  6925. }
  6926. }
  6927. mfn_Unlock();
  6928. TRACE_INFO(L"<- %!FUNC!");
  6929. }
  6930. NLBERROR
  6931. CNlbEngine::mfn_CheckHost(
  6932. IN PWMI_CONNECTION_INFO pConnInfo,
  6933. IN ENGINEHANDLE ehHost // OPTIONAL
  6934. )
  6935. /*
  6936. TODO -- this function shares code with ConnectToHost -- get rid of
  6937. the duplicated code somehow.
  6938. */
  6939. {
  6940. NLBERROR nerr = NLBERR_INTERNAL_ERROR;
  6941. LPWSTR szWmiMachineName = NULL;
  6942. LPWSTR szWmiMachineGuid = NULL;
  6943. WBEMSTATUS wStatus;
  6944. ULONG uIpAddress;
  6945. BOOL fNlbMgrProviderInstalled = FALSE;
  6946. _bstr_t bstrError;
  6947. TRACE_INFO(L"-> %!FUNC!(%ws)", pConnInfo->szMachine);
  6948. wStatus = NlbHostPing(pConnInfo->szMachine, 2000, &uIpAddress);
  6949. if (FAILED(wStatus))
  6950. {
  6951. nerr = NLBERR_PING_TIMEOUT; // todo more specific error.
  6952. bstrError = GETRESOURCEIDSTRING(IDS_PING_FAILED);
  6953. }
  6954. else
  6955. {
  6956. wStatus = NlbHostGetMachineIdentification(
  6957. pConnInfo,
  6958. &szWmiMachineName,
  6959. &szWmiMachineGuid,
  6960. &fNlbMgrProviderInstalled
  6961. );
  6962. if (FAILED(wStatus))
  6963. {
  6964. GetErrorCodeText(wStatus, bstrError);
  6965. if (wStatus == E_ACCESSDENIED)
  6966. {
  6967. nerr = NLBERR_ACCESS_DENIED;
  6968. }
  6969. else
  6970. {
  6971. // TODO: map proper errors.
  6972. nerr = NLBERR_NOT_FOUND;
  6973. }
  6974. TRACE_CRIT(L"Connecting to %ws returns error %ws",
  6975. pConnInfo->szMachine, (LPCWSTR) bstrError);
  6976. szWmiMachineName = NULL;
  6977. szWmiMachineGuid = NULL;
  6978. }
  6979. else
  6980. {
  6981. nerr = NLBERR_OK;
  6982. }
  6983. }
  6984. delete szWmiMachineName;
  6985. delete szWmiMachineGuid;
  6986. if (ehHost!=NULL)
  6987. {
  6988. CHostSpec *pHSpec = NULL;
  6989. mfn_Lock();
  6990. pHSpec = m_mapIdToHostSpec[ehHost]; // map
  6991. if (pHSpec != NULL)
  6992. {
  6993. if (NLBOK(nerr) || nerr == NLBERR_ACCESS_DENIED)
  6994. {
  6995. pHSpec->m_fUnreachable = FALSE;
  6996. }
  6997. else
  6998. {
  6999. pHSpec->m_fUnreachable = TRUE;
  7000. }
  7001. }
  7002. else
  7003. {
  7004. }
  7005. mfn_Unlock();
  7006. //
  7007. // Update the status of the specified host...
  7008. //
  7009. mfn_NotifyHostInterfacesChange(ehHost);
  7010. //
  7011. // Log error
  7012. //
  7013. if (NLBFAILED(nerr))
  7014. {
  7015. m_pCallbacks->Log(
  7016. IUICallbacks::LOG_ERROR,
  7017. NULL,
  7018. (LPCWSTR)(pConnInfo->szMachine),
  7019. IDS_CONNECT_TO_HOST_FAILED,
  7020. (LPCWSTR)bstrError,
  7021. (LPCWSTR)(pConnInfo->szMachine)
  7022. );
  7023. TRACE_CRIT(L"<- %!FUNC! returning error (string : %ls, retval : 0x%x)",
  7024. (LPCWSTR)bstrError, nerr);
  7025. }
  7026. }
  7027. return nerr;
  7028. }
  7029. VOID
  7030. CNlbEngine::mfn_UnlinkHostFromClusters(
  7031. IN ENGINEHANDLE ehHost
  7032. )
  7033. {
  7034. CHostSpec *pHSpec = NULL;
  7035. BOOL fBusy = FALSE;
  7036. UINT u;
  7037. vector <ENGINEHANDLE> UnlinkInterfaceList;
  7038. mfn_Lock();
  7039. pHSpec = m_mapIdToHostSpec[ehHost]; // map
  7040. if (pHSpec == NULL) goto end;
  7041. //
  7042. // Go through the list of interfaces, adding any interfaces
  7043. // that are part of a cluster to a temporary list.
  7044. //
  7045. for(u = 0; u < pHSpec->m_ehInterfaceIdList.size(); ++u )
  7046. {
  7047. ENGINEHANDLE ehIId = pHSpec->m_ehInterfaceIdList[u];
  7048. CInterfaceSpec *pISpec = NULL;
  7049. pISpec = m_mapIdToInterfaceSpec[ehIId]; // map
  7050. if (pISpec == NULL) continue;
  7051. ASSERT(pISpec->m_ehHostId == ehHost);
  7052. if (pISpec->m_ehCluster != NULL)
  7053. {
  7054. //
  7055. // Add this to the list of interfaces we're going to unlink
  7056. // from its cluster.
  7057. //
  7058. UnlinkInterfaceList.push_back(ehIId);
  7059. }
  7060. }
  7061. pHSpec = NULL;
  7062. TRACE_INFO(L"Unlinking all interfaces under host eh(0x%x)", ehHost);
  7063. for(u = 0; u < UnlinkInterfaceList.size(); ++u )
  7064. {
  7065. ENGINEHANDLE ehIId = UnlinkInterfaceList[u];
  7066. CInterfaceSpec *pISpec = NULL;
  7067. ENGINEHANDLE ehCluster = NULL;
  7068. pISpec = m_mapIdToInterfaceSpec[ehIId]; // map
  7069. if (pISpec == NULL) continue;
  7070. ASSERT(pISpec->m_ehHostId == ehHost);
  7071. ehCluster = pISpec->m_ehCluster;
  7072. if (ehCluster != NULL)
  7073. {
  7074. mfn_Unlock();
  7075. (VOID) CNlbEngine::RemoveInterfaceFromCluster(ehCluster, ehIId);
  7076. mfn_Lock();
  7077. }
  7078. }
  7079. end:
  7080. mfn_Unlock();
  7081. return;
  7082. }
  7083. VOID
  7084. CNlbEngine::UnmanageHost(ENGINEHANDLE ehHost)
  7085. {
  7086. mfn_UnlinkHostFromClusters(ehHost);
  7087. mfn_Lock();
  7088. mfn_DeleteHostIfNotManagedLk(ehHost);
  7089. mfn_Unlock();
  7090. }