CDP.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. <?php
  2. /*
  3. Copyright (c) 2012, Open Source Solutions Limited, Dublin, Ireland
  4. All rights reserved.
  5. Contact: Barry O'Donovan - barry (at) opensolutions (dot) ie
  6. http://www.opensolutions.ie/
  7. This file is part of the OSS_SNMP package.
  8. Redistribution and use in source and binary forms, with or without
  9. modification, are permitted provided that the following conditions are met:
  10. * Redistributions of source code must retain the above copyright
  11. notice, this list of conditions and the following disclaimer.
  12. * Redistributions in binary form must reproduce the above copyright
  13. notice, this list of conditions and the following disclaimer in the
  14. documentation and/or other materials provided with the distribution.
  15. * Neither the name of Open Source Solutions Limited nor the
  16. names of its contributors may be used to endorse or promote products
  17. derived from this software without specific prior written permission.
  18. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  22. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. namespace OSS\SNMP\MIBS\Cisco;
  30. /**
  31. * A class for performing SNMP V2 queries on Cisco devices
  32. *
  33. * @copyright Copyright (c) 2012, Open Source Solutions Limited, Dublin, Ireland
  34. * @author Barry O'Donovan <barry@opensolutions.ie>
  35. */
  36. class CDP extends \OSS\SNMP\MIBS\Cisco
  37. {
  38. const OID_CDP_INTERFACE_ENABLED = '.1.3.6.1.4.1.9.9.23.1.1.1.1.2';
  39. const OID_CDP_INTERFACE_NAME = '.1.3.6.1.4.1.9.9.23.1.1.1.1.6';
  40. const OID_CDP_CACHE_NEIGHBOUR_ADDRESS_TYPE = '.1.3.6.1.4.1.9.9.23.1.2.1.1.3';
  41. const OID_CDP_CACHE_NEIGHBOUR_ADDRESS = '.1.3.6.1.4.1.9.9.23.1.2.1.1.4';
  42. const OID_CDP_CACHE_NEIGHBOUR_VERSION = '.1.3.6.1.4.1.9.9.23.1.2.1.1.5';
  43. const OID_CDP_CACHE_NEIGHBOUR_ID = '.1.3.6.1.4.1.9.9.23.1.2.1.1.6';
  44. const OID_CDP_CACHE_NEIGHBOUR_PORT = '.1.3.6.1.4.1.9.9.23.1.2.1.1.7';
  45. const OID_CDP_CACHE_NEIGHBOUR_PLATFORM = '.1.3.6.1.4.1.9.9.23.1.2.1.1.8';
  46. const OID_CDP_CACHE_NEIGHBOUR_CAPABILITY = '.1.3.6.1.4.1.9.9.23.1.2.1.1.9';
  47. const OID_CDP_CACHE_NEIGHBOUR_VTP_MGMT_DOMAIN = '.1.3.6.1.4.1.9.9.23.1.2.1.1.10';
  48. const OID_CDP_CACHE_NEIGHBOUR_NATIVE_VLAN = '.1.3.6.1.4.1.9.9.23.1.2.1.1.11';
  49. const OID_CDP_CACHE_NEIGHBOUR_DUPLEX = '.1.3.6.1.4.1.9.9.23.1.2.1.1.12';
  50. const OID_CDP_CACHE_NEIGHBOUR_LAST_CHANGE = '.1.3.6.1.4.1.9.9.23.1.2.1.1.24';
  51. const OID_CDP_GLOBAL_RUN = '.1.3.6.1.4.1.9.9.23.1.3.1.0';
  52. const OID_CDP_GLOBAL_MESSAGE_INTERVAL = '.1.3.6.1.4.1.9.9.23.1.3.2.0';
  53. const OID_CDP_GLOBAL_HOLDTIME = '.1.3.6.1.4.1.9.9.23.1.3.3.0';
  54. const OID_CDP_GLOBAL_DEVICE_ID = '.1.3.6.1.4.1.9.9.23.1.3.4.0';
  55. const OID_CDP_GLOBAL_LAST_CHANGE = '.1.3.6.1.4.1.9.9.23.1.3.5.0';
  56. /**
  57. * Get the device's global CDP (Cisco Discovery Protocol) run status
  58. *
  59. * "An indication of whether the Cisco Discovery Protocol is currently running. Entries in cdpCacheTable are
  60. * deleted when CDP is disabled."
  61. *
  62. * @return boolean True if enabled globally, else false
  63. */
  64. public function globalRun()
  65. {
  66. return $this->getSNMP()->ppTruthValue( $this->getSNMP()->get( self::OID_CDP_GLOBAL_RUN ) );
  67. }
  68. /**
  69. * Get the interval at which CDP messages are to be generated
  70. *
  71. * "The interval at which CDP messages are to be generated. The default value is 60 seconds."
  72. *
  73. * @return int The interval at which CDP messages are to be generated
  74. */
  75. public function globalMessageInterval()
  76. {
  77. return $this->getSNMP()->get( self::OID_CDP_GLOBAL_MESSAGE_INTERVAL );
  78. }
  79. /**
  80. * Get the time for the receiving device holds CDP message
  81. *
  82. * "The time for the receiving device holds CDP message. The default value is 180 seconds."
  83. *
  84. * @return int The time for the receiving device holds CDP message
  85. */
  86. public function globalHoldTime()
  87. {
  88. return $this->getSNMP()->get( self::OID_CDP_GLOBAL_HOLDTIME );
  89. }
  90. /**
  91. * The time when the cache table was last changed
  92. *
  93. * "Indicates the time when the cache table was last changed. It
  94. * is the most recent time at which any row was last created,
  95. * modified or deleted."
  96. *
  97. * @return int The time (timeticks) when the cache table was last changed
  98. */
  99. public function globalLastChange()
  100. {
  101. return $this->getSNMP()->get( self::OID_CDP_GLOBAL_LAST_CHANGE );
  102. }
  103. /**
  104. * Get the device's CDP (Cisco Discovery Protocol) ID
  105. *
  106. * @return string The device's CDP (Cisco Discovery Protocol) ID
  107. */
  108. public function id()
  109. {
  110. return $this->getSNMP()->get( self::OID_CDP_GLOBAL_DEVICE_ID );
  111. }
  112. /**
  113. * Get the device's interfaces CDP enabled status
  114. *
  115. * Applies the TruthValue post processor (self::ppTruthValue()) to turn
  116. * SNMP values into true / false.
  117. *
  118. * @return array The device's interfaces CDP enabled status' (as boolean true / false)
  119. */
  120. public function interfaceEnabled()
  121. {
  122. return $this->getSNMP()->ppTruthValue( $this->getSNMP()->walk1d( self::OID_CDP_INTERFACE_ENABLED ) );
  123. }
  124. /**
  125. * Get the device's interface names as seen in CDP
  126. *
  127. * "The name of the local interface as advertised by CDP in the Port-ID TLV"
  128. *
  129. * @return array The device's interface names as seen in CDP
  130. */
  131. public function interfaceNames()
  132. {
  133. return $this->getSNMP()->walk1d( self::OID_CDP_INTERFACE_NAME );
  134. }
  135. /**
  136. * Constant for possible value of CDP neighbour address type
  137. * @see neighbourAddressTypes()
  138. */
  139. const CDP_CACHE_NEIGHBOUR_ADDRESS_TYPE_IP = 1;
  140. /**
  141. * Text representation of CDP neighbour address type
  142. *
  143. * @see neighbourAddressTypes()
  144. * @var array Text representation of CDP neighbour address type
  145. */
  146. public static $CDP_CACHE_NEIGHBOUR_ADDRESS_TYPES = array(
  147. self::CDP_CACHE_NEIGHBOUR_ADDRESS_TYPE_IP => 'ip'
  148. );
  149. /**
  150. * Get the CDP neighbours' address type indexed by the current device's port ID
  151. *
  152. * "An indication of the type of address contained in the corresponding instance of cdpCacheAddress"
  153. *
  154. * @param boolean $translate If true, return the string representation via self::$VTP_VLAN_TYPES
  155. * @return array The CDP neighbours' address type indexed by the current device's port ID
  156. */
  157. public function neighbourAddressTypes( $translate = false )
  158. {
  159. $types = $this->getSNMP()->subOidWalk( self::OID_CDP_CACHE_NEIGHBOUR_ADDRESS_TYPE, 15 );
  160. if( !$translate )
  161. return $types;
  162. return $this->getSNMP()->translate( $types, self::$CDP_CACHE_NEIGHBOUR_ADDRESS_TYPES );
  163. }
  164. /**
  165. * Get the device's CDP neighbour addresses indexed by the current device's port ID
  166. *
  167. * "The (first) network-layer address of the device
  168. * as reported in the Address TLV of the most recently received
  169. * CDP message. For example, if the corresponding instance of
  170. * cacheAddressType had the value 'ip(1)', then this object
  171. * would be an IPv4-address. If the neighbor device is
  172. * SNMP-manageable, it is supposed to generate its CDP messages
  173. * such that this address is one at which it will receive SNMP
  174. * messages. Use cdpCtAddressTable to extract the remaining
  175. * addresses from the Address TLV received most recently."
  176. *
  177. * @return array The device's CDP neighbour addresses indexed by the current device's port ID
  178. */
  179. public function neighbourAddresses()
  180. {
  181. $addresses = $this->getSNMP()->subOidWalk( self::OID_CDP_CACHE_NEIGHBOUR_ADDRESS, 15 );
  182. foreach( $addresses as $portId => $address )
  183. {
  184. if( strlen( $address ) == 8 && $this->neighbourAddressTypes()[ $portId ] == self::CDP_CACHE_NEIGHBOUR_ADDRESS_TYPE_IP )
  185. $addresses[ $portId ] = long2ip( hexdec( $address ) );
  186. }
  187. return $addresses;
  188. }
  189. /**
  190. * Get the device's CDP neighbour version indexed by the current device's port ID
  191. *
  192. * "The Version string as reported in the most recent CDP
  193. * message. The zero-length string indicates no Version
  194. * field (TLV) was reported in the most recent CDP message."
  195. *
  196. * @return array The device's CDP neighbour version indexed by the current device's port ID
  197. */
  198. public function neighbourVersions()
  199. {
  200. return $this->getSNMP()->subOidWalk( self::OID_CDP_CACHE_NEIGHBOUR_VERSION, 15 );
  201. }
  202. /**
  203. * Get the device's CDP neighbours (by their CDP ID) indexed by the current device's port ID
  204. *
  205. * "The Device-ID string as reported in the most recent CDP
  206. * message. The zero-length string indicates no Device-ID
  207. * field (TLV) was reported in the most recent CDP message."
  208. *
  209. * @return array The device's CDP neighbours (by their CDP ID) indexed by the current device's port ID
  210. */
  211. public function neighbourId()
  212. {
  213. return $this->getSNMP()->subOidWalk( self::OID_CDP_CACHE_NEIGHBOUR_ID, 15 );
  214. }
  215. /**
  216. * Get the device's CDP neighbours connected port *description* indexed by the current device's port ID
  217. *
  218. * E.g. a sample call may return:
  219. *
  220. * Array
  221. * (
  222. * [10101] => GigabitEthernet0/1
  223. * [10102] => FastEthernet0/2
  224. * [10103] => GigabitEthernet1/0/24
  225. * [10105] => GigabitEthernet1/0/2
  226. * )
  227. *
  228. * meaning, for example, that our local port with ID 10101 is connected to port GigabitEthernet0/1 on the neighbour
  229. * connected to that local port. You can discover the neighbour ID via neighbourId().
  230. *
  231. * "The Port-ID string as reported in the most recent CDP
  232. * message. This will typically be the value of the ifName
  233. * object (e.g., 'Ethernet0'). The zero-length string
  234. * indicates no Port-ID field (TLV) was reported in the
  235. * most recent CDP message."
  236. *
  237. * @see neighbourId()
  238. * @return array The device's CDP neighbours connected port *description* indexed by the current device's port ID
  239. */
  240. public function neighbourPort()
  241. {
  242. return $this->getSNMP()->subOidWalk( self::OID_CDP_CACHE_NEIGHBOUR_PORT, 15 );
  243. }
  244. /**
  245. * Get the device's CDP neighbour platforms indexed by the current device's port ID
  246. *
  247. * "The Device's Hardware Platform as reported in the most recent CDP message. The zero-length string indicates
  248. * that no Platform field (TLV) was reported in the most recent CDP message."
  249. *
  250. * @return array The device's CDP neighbour platforms indexed by the current device's port ID
  251. */
  252. public function neighbourPlatforms()
  253. {
  254. return $this->getSNMP()->subOidWalk( self::OID_CDP_CACHE_NEIGHBOUR_PLATFORM, 15 );
  255. }
  256. /**
  257. * Constant for possible value of CDP neighbour capability
  258. * @see neighbourCapability()
  259. */
  260. const CDP_CACHE_NEIGHBOUR_CAPABILITY_ROUTER = 0b1;
  261. /**
  262. * Constant for possible value of CDP neighbour capability
  263. * @see neighbourCapability()
  264. */
  265. const CDP_CACHE_NEIGHBOUR_CAPABILITY_TRANSPARENT_BRIDGE = 0b10;
  266. /**
  267. * Constant for possible value of CDP neighbour capability
  268. * @see neighbourCapability()
  269. */
  270. const CDP_CACHE_NEIGHBOUR_CAPABILITY_SOURCE_ROUTE_BRIDGE = 0b100;
  271. /**
  272. * Constant for possible value of CDP neighbour capability
  273. * @see neighbourCapability()
  274. */
  275. const CDP_CACHE_NEIGHBOUR_CAPABILITY_SWITCH = 0b1000;
  276. /**
  277. * Constant for possible value of CDP neighbour capability
  278. * @see neighbourCapability()
  279. */
  280. const CDP_CACHE_NEIGHBOUR_CAPABILITY_HOST = 0b10000;
  281. /**
  282. * Constant for possible value of CDP neighbour capability
  283. * @see neighbourCapability()
  284. */
  285. const CDP_CACHE_NEIGHBOUR_CAPABILITY_IGMP_CAPABLE = 0b100000;
  286. /**
  287. * Constant for possible value of CDP neighbour capability
  288. * @see neighbourCapability()
  289. */
  290. const CDP_CACHE_NEIGHBOUR_CAPABILITY_REPEATER = 0b1000000;
  291. /**
  292. * Text representation of CDP capabilities
  293. *
  294. * @see neighbourCapability()
  295. * @var array Text representation of CDP neighbour capabilities
  296. */
  297. public static $CDP_CACHE_NEIGHBOUR_CAPABILITIES = array(
  298. self::CDP_CACHE_NEIGHBOUR_CAPABILITY_ROUTER => 'Router',
  299. self::CDP_CACHE_NEIGHBOUR_CAPABILITY_TRANSPARENT_BRIDGE => 'Transparent Bridge',
  300. self::CDP_CACHE_NEIGHBOUR_CAPABILITY_SOURCE_ROUTE_BRIDGE => 'Source Route Bridge',
  301. self::CDP_CACHE_NEIGHBOUR_CAPABILITY_SWITCH => 'Switch',
  302. self::CDP_CACHE_NEIGHBOUR_CAPABILITY_HOST => 'Host',
  303. self::CDP_CACHE_NEIGHBOUR_CAPABILITY_IGMP_CAPABLE => 'IGMP Capable',
  304. self::CDP_CACHE_NEIGHBOUR_CAPABILITY_REPEATER => 'Repeater'
  305. );
  306. /**
  307. * Get the device's CDP neighbour capabilities (as a decimal integer) indexed by the current device's port ID
  308. *
  309. * "The Device's Functional Capabilities as reported in the most recent CDP message. For latest set of specific
  310. * values, see the latest version of the CDP specification. The zero-length string indicates no Capabilities field
  311. * (TLV) was reported in the most recent CDP message."
  312. *
  313. * @see REFERENCE "Cisco Discovery Protocol Specification, 10/19/94."
  314. * @see http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm#xtocid12
  315. * @see http://wiki.wireshark.org/CDP
  316. *
  317. * @return array The device's CDP neighbour capabilities (as a decimal integer) indexed by the current device's port ID
  318. */
  319. public function neighbourCapability()
  320. {
  321. $rtn = $this->getSNMP()->subOidWalk( self::OID_CDP_CACHE_NEIGHBOUR_CAPABILITY, 15 );
  322. foreach( $rtn as $k => $v )
  323. $rtn[$k] = (int)hexdec( $v );
  324. return $rtn;
  325. }
  326. /**
  327. * Query if a given neighbour (by connected port ID) has the given capability
  328. *
  329. * Example:
  330. *
  331. * if( $host->useCisco_CDP()->neighbourHasCapability( $portId, \OSS\SNMP\MIBS\Cisco\CDP::CDP_CACHE_NEIGHBOUR_CAPABILITY_SWITCH )
  332. * echo "Host is a switch!!";
  333. *
  334. * @param int $portId The CDP neighbour by connected local port ID
  335. * @param int $capability The capability to query for (defined by self::CDP_CACHE_NEIGHBOUR_CAPABILITY_XXX constants)
  336. * @return boolean True if the neighbour has the given capability
  337. */
  338. public function neighbourHasCapability( $portId, $capability )
  339. {
  340. if( $this->neighbourCapability()[ $portId ] & $capability )
  341. return true;
  342. return false;
  343. }
  344. /**
  345. * Get an array of individual capabilities of a given neighbour (by connected port ID)
  346. *
  347. * Example:
  348. *
  349. * print_r( $host->useCisco_CDP()->neighbourCapabilities( 10111 ) )
  350. *
  351. * [0] => 8 // self::CDP_CACHE_NEIGHBOUR_CAPABILITY_SWITCH
  352. * [1] => 32 // self::CDP_CACHE_NEIGHBOUR_CAPABILITY_IGMP_CAPABLE
  353. *
  354. * print_r( $host->useCisco_CDP()->neighbourCapabilities( 10111, true ) )
  355. *
  356. * [0] => "Switch" // self::CDP_CACHE_NEIGHBOUR_CAPABILITY_SWITCH
  357. * [1] => "IGMP Capable" // self::CDP_CACHE_NEIGHBOUR_CAPABILITY_IGMP_CAPABLE
  358. *
  359. *
  360. *
  361. * @param int $portId The CDP neighbour by connected local port ID
  362. * @param int $translate Set to true to return descriptions rather than integers
  363. * @return array Individual capabilities of a given neighbour
  364. */
  365. public function neighbourCapabilities( $portId, $translate = false )
  366. {
  367. $capabilities = array();
  368. foreach( self::$CDP_CACHE_NEIGHBOUR_CAPABILITIES as $mask => $description )
  369. {
  370. if( $this->neighbourCapability()[ $portId ] & $mask )
  371. $capabilities[] = $mask;
  372. }
  373. if( $translate )
  374. return $this->getSNMP()->translate( $capabilities, self::$CDP_CACHE_NEIGHBOUR_CAPABILITIES );
  375. return $capabilities;
  376. }
  377. /**
  378. * Get the device's CDP neighbours' VTP management domain indexed by the current device's port ID
  379. *
  380. * "The VTP Management Domain for the remote device's interface, as reported in the most recently received CDP message.
  381. * This object is not instantiated if no VTP Management Domain field (TLV) was reported in the most recently received CDP message."
  382. *
  383. * @see REFERENCE "managementDomainName in CISCO-VTP-MIB"
  384. *
  385. * @return array The device's CDP neighbours' VTP management domain indexed by the current device's port ID
  386. */
  387. public function neighbourVTPMgmtDomain()
  388. {
  389. return $this->getSNMP()->subOidWalk( self::OID_CDP_CACHE_NEIGHBOUR_VTP_MGMT_DOMAIN, 15 );
  390. }
  391. /**
  392. * Get the remote device's interface's native VLAN (indexed by local portId)
  393. *
  394. * "The remote device's interface's native VLAN, as reported in the
  395. * most recent CDP message. The value 0 indicates
  396. * no native VLAN field (TLV) was reported in the most
  397. * recent CDP message."
  398. *
  399. * @return array The remote device's interface's native VLAN (indexed by local portId)
  400. */
  401. public function neighbourNativeVLAN()
  402. {
  403. return $this->getSNMP()->subOidWalk( self::OID_CDP_CACHE_NEIGHBOUR_NATIVE_VLAN, 15 );
  404. }
  405. /**
  406. * Constant for possible value of CDP neighbour duplex
  407. * @see neighbourDuplexMode()
  408. */
  409. const CDP_CACHE_NEIGHBOUR_DUPLEX_UNKNOWN = 1;
  410. /**
  411. * Constant for possible value of CDP neighbour duplex
  412. * @see neighbourDuplexMode()
  413. */
  414. const CDP_CACHE_NEIGHBOUR_DUPLEX_HALF = 2;
  415. /**
  416. * Constant for possible value of CDP neighbour duplex
  417. * @see neighbourDuplexMode()
  418. */
  419. const CDP_CACHE_NEIGHBOUR_DUPLEX_FULL = 3;
  420. /**
  421. * Text representation of CDP capabilities
  422. *
  423. * @see neighbourDuplexMode()
  424. * @var array Text representation of CDP neighbour duplex modes
  425. */
  426. public static $CDP_CACHE_NEIGHBOUR_DUPLEXES = array(
  427. self::CDP_CACHE_NEIGHBOUR_DUPLEX_UNKNOWN => 'unknown',
  428. self::CDP_CACHE_NEIGHBOUR_DUPLEX_HALF => 'half-duplex',
  429. self::CDP_CACHE_NEIGHBOUR_DUPLEX_FULL => 'full-duplex'
  430. );
  431. /**
  432. * Get the remote device's interface's duplex mode (indexed by local portId)
  433. *
  434. * "The remote device's interface's duplex mode, as reported in the
  435. * most recent CDP message. The value unknown(1) indicates
  436. * no duplex mode field (TLV) was reported in the most
  437. * recent CDP message."
  438. *
  439. * @param boolean $translate If true, return the string representation via self::$VTP_VLAN_TYPES
  440. * @return array The remote device's interface's duplex mode (indexed by local portId)
  441. */
  442. public function neighbourDuplexMode( $translate = false )
  443. {
  444. $modes = $this->getSNMP()->subOidWalk( self::OID_CDP_CACHE_NEIGHBOUR_DUPLEX, 15 );
  445. if( !$translate )
  446. return $modes;
  447. return $this->getSNMP()->translate( $modes, self::$CDP_CACHE_NEIGHBOUR_DUPLEXES );
  448. }
  449. /**
  450. * Get the remote device's last change time (indexed by local portId)
  451. *
  452. * "Indicates the time when this cache entry was last changed.
  453. * This object is initialised to the current time when the entry
  454. * gets created and updated to the current time whenever the value
  455. * of any (other) object instance in the corresponding row is
  456. * modified."
  457. *
  458. * @return array The remote device's last change time(indexed by local portId)
  459. */
  460. public function neighbourLastChange()
  461. {
  462. return $this->getSNMP()->subOidWalk( self::OID_CDP_CACHE_NEIGHBOUR_LAST_CHANGE, 15 );
  463. }
  464. /**
  465. * CDP utility function to get all CDP neighbours and their connected ports.
  466. *
  467. * Returns an array of neighbours indexed by the neighbour CDP ID. For example:
  468. *
  469. *
  470. * Array
  471. * (
  472. * [cr-sw03.ixdub1.opensolutions.ie] => Array
  473. * (
  474. * [0] => Array
  475. * (
  476. * [localPortId] => 10101
  477. * [localPort] => GigabitEthernet1/0/1
  478. * [remotePort] => GigabitEthernet0/1
  479. * )
  480. *
  481. * [1] => Array
  482. * (
  483. * [localPortId] => 10102
  484. * [localPort] => GigabitEthernet1/0/2
  485. * [remotePort] => FastEthernet0/2
  486. * )
  487. *
  488. * )
  489. * [ ... ]
  490. * )
  491. *
  492. * @see neighbourId()
  493. * @see \OSS\SNMP\MIBS\Interface::descriptions()
  494. * @see neighbourPort()
  495. * @return array CDP neighbours and their connected ports
  496. */
  497. public function neighbours()
  498. {
  499. $neighbours = array();
  500. foreach( $this->neighbourId() as $localPortId => $neighbourCdpId )
  501. {
  502. if( !isset( $neighbours[ $neighbourCdpId ] ) )
  503. {
  504. $neighbours[ $neighbourCdpId ] = array();
  505. $count = 0;
  506. }
  507. else
  508. $count = count( $neighbours[ $neighbourCdpId ] );
  509. $neighbours[ $neighbourCdpId ][$count]['localPortId'] = $localPortId;
  510. $neighbours[ $neighbourCdpId ][$count]['localPortName'] = $this->getSNMP()->useIface()->names()[$localPortId];
  511. $neighbours[ $neighbourCdpId ][$count]['localPort'] = $this->getSNMP()->useIface()->descriptions()[$localPortId];
  512. try
  513. {
  514. $neighbours[ $neighbourCdpId ][$count]['isLAG'] = $this->getSNMP()->useLAG()->isAggregatePorts()[$localPortId];
  515. }
  516. catch( \OSS\Exception $e )
  517. {
  518. $neighbours[ $neighbourCdpId ][$count]['isLAG'] = false;
  519. }
  520. $neighbours[ $neighbourCdpId ][$count]['remotePort'] = $this->neighbourPort()[$localPortId];
  521. }
  522. return $neighbours;
  523. }
  524. /**
  525. * Recursivily crawls all CDP neighbours to build up a flat array of all devices
  526. * indexed by the CDP device id.
  527. *
  528. * Array form is same as that returned by neighbours()
  529. *
  530. * @see neighbours()
  531. * @param array $devices Unless you're doing something funky, just pass an empty array. This is where the result will be found.
  532. * @param string $device CDP device ID of next host to crawl. On first pass, set to null - used internally when recursing
  533. * @param array $ignore An array of CDP device IDs to *ignore*. I.e. to not include in recursive crawling
  534. * @return array The resultant array of all crawled devices (same as that passed in the @param $devices parameter)
  535. */
  536. public function crawl( &$devices = array(), $device = null, $ignore = array() )
  537. {
  538. if( !count( $devices ) )
  539. {
  540. $device = $this->id();
  541. $devices[ $device ] = $this->neighbours();
  542. }
  543. foreach( $devices[ $device ] as $feNeighbour => $feConnections )
  544. {
  545. if( in_array( $feNeighbour, $ignore ) )
  546. {
  547. if( isset( $devices[ $device ][$feNeighbour] ) )
  548. unset( $devices[ $device ][$feNeighbour] );
  549. continue;
  550. }
  551. if( !isset( $devices[ $feNeighbour ] ) )
  552. {
  553. $snmp = new \OSS\SNMP( $feNeighbour, $this->getSNMP()->getCommunity() );
  554. $devices[ $feNeighbour ] = $snmp->useCisco_CDP()->neighbours();
  555. unset( $snmp );
  556. $this->crawl( $devices, $feNeighbour, $ignore );
  557. }
  558. }
  559. return $devices;
  560. }
  561. /**
  562. * Find the layer 2 topology as an array with no link mentioned more than once.
  563. *
  564. * Huh? This function:
  565. *
  566. * * takes the result of crawl() (or calls crawl()) to get the CDP topology
  567. * * foreach device, builds an array of device to device links
  568. * * SO LONG as that link has already not been accounted for in the other direction.
  569. *
  570. * I.e. if a link is found A -> B, then the same B -> A link will not be included
  571. *
  572. * The array returned is, for example:
  573. *
  574. * [cr-sw04.degkcp.example.ie] => Array
  575. * (
  576. * [cd-sw02.degkcp.example.ie] => Array
  577. * (
  578. * [GigabitEthernet1/0/3] => Array
  579. * (
  580. * [remotePort] => FastEthernet0/1
  581. * [isLAG] => false
  582. * )
  583. *
  584. * [cr-sw03.degkcp.example.ie] => Array
  585. * (
  586. * [GigabitEthernet1/0/23] => Array
  587. * (
  588. * [remotePort] => GigabitEthernet1/0/23
  589. * [isLAG] => false
  590. * )
  591. * [GigabitEthernet1/0/24] => Array
  592. * (
  593. * [remotePort] => GigabitEthernet1/0/24
  594. * [isLAG] => false
  595. * )
  596. * )
  597. * )
  598. *
  599. * This tells us that cr-sw04(GigabitEthernet1/0/3) is connected to cd-sw02(FastEthernet0/1).
  600. *
  601. * It also tells us that cr-sw04 has two connections to cr-sw03.
  602. *
  603. * You'll notice it also tells us if it's a LAG or not. More information can be added as needed.
  604. *
  605. * @see crawl()
  606. * @param array $devices The result of crawl() (if null, this function performs a crawl())
  607. * @return array L2 topology as described above.
  608. */
  609. public function linkTopology( $devices = null )
  610. {
  611. if( $devices == null )
  612. $devices = $this->crawl();
  613. $links = array();
  614. foreach( $devices as $feDevice => $feNeighbours )
  615. {
  616. foreach( $feNeighbours as $fe2Device => $fe2Links )
  617. {
  618. foreach( $fe2Links as $fe2Link )
  619. {
  620. // have we already accounted for this link on the other side?
  621. if( isset( $links[ $fe2Device ][ $feDevice ][ $fe2Link['remotePort'] ] ) )
  622. continue;
  623. if( !isset( $links[ $feDevice ] ) )
  624. $links[ $feDevice ] = array();
  625. if( !isset( $links[ $feDevice ][ $fe2Device ] ) )
  626. $links[ $feDevice ][ $fe2Device ] = array();
  627. $links[ $feDevice ][ $fe2Device ][ $fe2Link['localPort'] ] = array();
  628. $links[ $feDevice ][ $fe2Device ][ $fe2Link['localPort'] ][ 'remotePort' ] = $fe2Link['remotePort'];
  629. $links[ $feDevice ][ $fe2Device ][ $fe2Link['localPort'] ][ 'isLAG' ] = $fe2Link['isLAG'];
  630. }
  631. }
  632. }
  633. return $links;
  634. }
  635. }