api.fdbarchive.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. <?php
  2. /**
  3. * Network equipment FDB tables archive implementation
  4. */
  5. class FDBArchive {
  6. /**
  7. * Contains system alter config as key=>value
  8. *
  9. * @var array
  10. */
  11. protected $altCfg = array();
  12. /**
  13. * Contains all available switches devices as id=>data
  14. *
  15. * @var array
  16. */
  17. protected $allSwitches = array();
  18. /**
  19. * Contains existing switches MAC addresses as mac=>id
  20. *
  21. * @var array
  22. */
  23. protected $allSwitchesMac = array();
  24. /**
  25. * Contains available users data from cache
  26. *
  27. * @var array
  28. */
  29. protected $allUserData = array();
  30. /**
  31. * Contains available users mac address as mac=>login
  32. *
  33. * @var array
  34. */
  35. protected $allUsersMac = array();
  36. /**
  37. * Contains available ONU devices mac address as mac=>id
  38. *
  39. * @var array
  40. */
  41. protected $allOnuMac = array();
  42. /**
  43. * Contains available ONU devices assigned users id=>login
  44. *
  45. * @var array
  46. */
  47. protected $allOnuUsers = array();
  48. /**
  49. * Protected database model placeholder
  50. *
  51. * @var object
  52. */
  53. protected $archive = '';
  54. /**
  55. * Object wide json helper placeholder
  56. *
  57. * @var object
  58. */
  59. protected $json = '';
  60. /**
  61. * Days counter before automatic archive cleanup/rotation
  62. *
  63. * @var int
  64. */
  65. protected $daysRotate = 0;
  66. /**
  67. * Placeholder for SW_FDB_EXTEN_INFO alter.ini option
  68. */
  69. protected $fdbExtenInfo = false;
  70. /**
  71. * Contains default FDB caches storage path
  72. */
  73. const PATH_CACHE = 'exports/';
  74. /**
  75. * Contains default FDB caches storage path for OLTs
  76. */
  77. const OLT_PATH_CACHE = 'exports/pondata/fdb/';
  78. /**
  79. * Contains default switches FDB cache record postfix
  80. */
  81. const EXT_SWITCHES = '_fdb';
  82. /**
  83. * Contains default switches FDB VLAN cache record postfix
  84. */
  85. const EXT_SWITCHES_VLAN = '_vlan';
  86. /**
  87. * Contains default switches FDB ports descriptions cache record postfix
  88. */
  89. const EXT_SWITCHES_PORTDESCR = '_portdescr';
  90. /**
  91. * Contains default PON OLT FDB cache record postfix
  92. */
  93. const EXT_OLTS = '_OLTFDB';
  94. /**
  95. * Contains default archive database table name
  96. */
  97. const TABLE_ARCHIVE = 'fdbarchive';
  98. /**
  99. * Contains default module controller URL
  100. */
  101. const URL_ME = '?module=fdbarchive';
  102. /**
  103. * Contains default fdb cache module URL
  104. */
  105. const URL_CACHE = '?module=switchpoller';
  106. /**
  107. * Another required URLs for internal routing
  108. */
  109. const URL_SWITCHPROFILE = '?module=switches&edit=';
  110. const URL_USERPROFILE = '?module=userprofile&username=';
  111. const URL_ONUPROFILE = '?module=ponizer&editonu=';
  112. public function __construct() {
  113. $this->loadConfigs();
  114. $this->initJson();
  115. $this->initArchive();
  116. $this->loadSwitches();
  117. }
  118. /**
  119. * Preloads system configs into protected props for further usage
  120. *
  121. * @global object $ubillingConfig
  122. *
  123. * @return void
  124. */
  125. protected function loadConfigs() {
  126. global $ubillingConfig;
  127. $this->altCfg = $ubillingConfig->getAlter();
  128. if (isset($this->altCfg['FDBARCHIVE_MAX_AGE'])) {
  129. if (!empty($this->altCfg['FDBARCHIVE_MAX_AGE'])) {
  130. if (is_numeric($this->altCfg['FDBARCHIVE_MAX_AGE'])) {
  131. $this->daysRotate = $this->altCfg['FDBARCHIVE_MAX_AGE'];
  132. }
  133. }
  134. }
  135. $this->fdbExtenInfo = $ubillingConfig->getAlterParam('SW_FDB_EXTEN_INFO');
  136. }
  137. /**
  138. * Inits archive model as protected property for further usage
  139. *
  140. * @return void
  141. */
  142. protected function initArchive() {
  143. $this->archive = new NyanORM(self::TABLE_ARCHIVE);
  144. }
  145. /**
  146. * Inits archive model as protected property for further usage
  147. *
  148. * @return void
  149. */
  150. protected function initJson() {
  151. $this->json = new wf_JqDtHelper();
  152. }
  153. /**
  154. * Loads switches into protected property
  155. *
  156. * @return void
  157. */
  158. protected function loadSwitches() {
  159. $switches = new nya_switches();
  160. $this->allSwitches = $switches->getAll('id');
  161. if (!empty($this->allSwitches)) {
  162. foreach ($this->allSwitches as $io => $each) {
  163. if (!empty($each['swid'])) {
  164. $this->allSwitchesMac[$each['swid']] = $each['id'];
  165. }
  166. }
  167. }
  168. }
  169. /**
  170. * Loads user data into protected properties for further usage
  171. *
  172. * @return void
  173. */
  174. protected function loadUserData() {
  175. $this->allUserData = zb_UserGetAllDataCache();
  176. if (!empty($this->allUserData)) {
  177. $this->allUsersMac = zb_UserGetAllMACs();
  178. $this->allUsersMac = array_flip($this->allUsersMac);
  179. }
  180. }
  181. /**
  182. * Loads PON ONU devices data into protected properties for further usage
  183. *
  184. * @return void
  185. */
  186. protected function loadOnuData() {
  187. $onu = new nya_pononu();
  188. $allOnu = $onu->getAll();
  189. if (!empty($allOnu)) {
  190. foreach ($allOnu as $io => $each) {
  191. if (!empty($each['mac'])) {
  192. $this->allOnuMac[$each['mac']] = $each['id'];
  193. if (!empty($each['login'])) {
  194. $this->allOnuUsers[$each['id']] = $each['login'];
  195. }
  196. }
  197. }
  198. }
  199. }
  200. /**
  201. * Extracts IP address from switch cache record name
  202. *
  203. * @param string $cacheRecord
  204. *
  205. * @return string
  206. */
  207. protected function extractSwitchIP($cacheRecord) {
  208. $result = '';
  209. if (!empty($cacheRecord)) {
  210. $result .= zb_ExtractIpAddress($cacheRecord);
  211. }
  212. return($result);
  213. }
  214. /**
  215. * Tryin to detect switch ID by its IP address
  216. *
  217. * @param string $ip
  218. *
  219. * @return int/void
  220. */
  221. protected function getSwitchId($ip) {
  222. $result = '';
  223. if (!empty($this->allSwitches)) {
  224. foreach ($this->allSwitches as $io => $each) {
  225. if ($each['ip'] == $ip) {
  226. $result = $each['id'];
  227. return($result);
  228. }
  229. }
  230. }
  231. return($result);
  232. }
  233. /**
  234. * Extracts OLT id from cache record name
  235. *
  236. * @param string $cacheRecord
  237. *
  238. * @return int
  239. */
  240. protected function extractOltId($cacheRecord) {
  241. $result = '';
  242. if (!empty($cacheRecord)) {
  243. $result = ubRouting::filters($cacheRecord, 'int');
  244. }
  245. return($result);
  246. }
  247. /**
  248. * Trying to get OLT IP for existing device by its ID
  249. *
  250. * @param int $id
  251. *
  252. * @return string
  253. */
  254. protected function getOltIp($id) {
  255. $result = '';
  256. if (isset($this->allSwitches[$id])) {
  257. $result .= $this->allSwitches[$id]['ip'];
  258. }
  259. return($result);
  260. }
  261. /**
  262. * Performs cache scanning and saving into archive of current PON devices FDB cache
  263. *
  264. * @return void
  265. */
  266. protected function saveOltCache() {
  267. $newDate = curdatetime();
  268. if (@$this->altCfg['PON_ENABLED']) {
  269. $allCachedData = rcms_scandir(self::OLT_PATH_CACHE, '*' . self::EXT_OLTS);
  270. if (!empty($allCachedData)) {
  271. foreach ($allCachedData as $cacheIndex => $cacheFile) {
  272. $rawData = file_get_contents(self::OLT_PATH_CACHE . $cacheFile);
  273. if (!empty($rawData)) {
  274. $oltId = $this->extractOltId($cacheFile);
  275. $oltIp = $this->getOltIp($oltId);
  276. //filling new archive record
  277. $this->archive->data('date', $newDate);
  278. $this->archive->data('devid', $oltId);
  279. $this->archive->data('devip', $oltIp);
  280. $this->archive->data('data', $rawData);
  281. //we need some different parsing of raw data in this case
  282. $this->archive->data('pon', '1');
  283. $this->archive->create();
  284. }
  285. }
  286. }
  287. }
  288. }
  289. /**
  290. * Performs cache scanning and saving into archive of current switches FDB cache
  291. *
  292. * @return void
  293. */
  294. protected function saveSwitchesCache() {
  295. $newDate = curdatetime();
  296. $allCachedData = rcms_scandir(self::PATH_CACHE, '*' . self::EXT_SWITCHES);
  297. if (!empty($allCachedData)) {
  298. foreach ($allCachedData as $cacheIndex => $cacheFile) {
  299. $rawData = file_get_contents(self::PATH_CACHE . $cacheFile);
  300. if (!empty($rawData)) {
  301. $rawDataVLAN = '';
  302. $rawDataPortDescr = '';
  303. if (file_exists(self::PATH_CACHE . $cacheFile . self::EXT_SWITCHES_VLAN)) {
  304. $rawDataVLAN = file_get_contents(self::PATH_CACHE . $cacheFile . self::EXT_SWITCHES_VLAN);
  305. }
  306. if (file_exists(self::PATH_CACHE . $cacheFile . self::EXT_SWITCHES_PORTDESCR)) {
  307. $rawDataPortDescr = file_get_contents(self::PATH_CACHE . $cacheFile . self::EXT_SWITCHES_PORTDESCR);
  308. }
  309. $switchIp = $this->extractSwitchIP($cacheFile);
  310. $switchId = $this->getSwitchId($switchIp);
  311. //filling new archive record
  312. $this->archive->data('date', $newDate);
  313. $this->archive->data('devid', $switchId);
  314. $this->archive->data('devip', $switchIp);
  315. $this->archive->data('data', $rawData);
  316. $this->archive->data('datavlan', $rawDataVLAN);
  317. $this->archive->data('dataportdescr', $rawDataPortDescr);
  318. $this->archive->data('pon', '0');
  319. $this->archive->create();
  320. }
  321. }
  322. }
  323. }
  324. /**
  325. * Performs cache scanning and storing into archive
  326. *
  327. * @return void
  328. */
  329. public function storeArchive() {
  330. $this->saveSwitchesCache();
  331. if ($this->altCfg['PON_ENABLED']) {
  332. $this->saveOltCache();
  333. }
  334. $this->rotateArchive();
  335. }
  336. /**
  337. * Performs automatic archived data rotation
  338. *
  339. * @return void
  340. */
  341. protected function rotateArchive() {
  342. if ($this->daysRotate) {
  343. $this->archive->whereRaw("`date` <= NOW() - INTERVAL " . $this->daysRotate . " DAY");
  344. $this->archive->delete();
  345. }
  346. }
  347. /**
  348. * Renders archive container
  349. *
  350. * @return string
  351. */
  352. public function renderArchive() {
  353. $result = '';
  354. $macFilter = '';
  355. $switchIdFilter = '';
  356. if (ubRouting::checkGet('macfilter')) {
  357. $macFilter .= '&macfilter=' . ubRouting::get('macfilter');
  358. }
  359. if (ubRouting::checkGet('switchidfilter')) {
  360. $macFilter .= '&switchidfilter=' . ubRouting::get('switchidfilter');
  361. }
  362. if ($this->fdbExtenInfo) {
  363. $columns = array('Date', __('Switch') . ' / ' . __('OLT'), 'Port', __('Port description'), 'VLAN', 'Location', 'MAC', __('User') . ' / ' . __('Device'));
  364. } else {
  365. $columns = array('Date', __('Switch') . ' / ' . __('OLT'), 'Port', 'Location', 'MAC', __('User') . ' / ' . __('Device'));
  366. }
  367. $opts = '"order": [[ 0, "desc" ]]';
  368. $result .= wf_JqDtLoader($columns, self::URL_ME . '&ajax=true' . $macFilter . $switchIdFilter, false, 'Objects', 100, $opts);
  369. return($result);
  370. }
  371. /**
  372. * Trying to detect is device switch/user or ONU by mac. Returns profile view control.
  373. *
  374. * @param string $mac
  375. *
  376. * @return string
  377. */
  378. protected function getEntityControl($mac) {
  379. $result = '';
  380. if (isset($this->allUsersMac[$mac])) {
  381. $userLogin = $this->allUsersMac[$mac];
  382. $result .= wf_Link(self::URL_USERPROFILE . $userLogin, web_profile_icon() . ' ' . @$this->allUserData[$userLogin]['fulladress']);
  383. return($result);
  384. }
  385. if (isset($this->allSwitchesMac[$mac])) {
  386. $switchId = $this->allSwitchesMac[$mac];
  387. $switchIcon = wf_img('skins/menuicons/switches.png', __('Switch')) . ' ';
  388. $result .= wf_Link(self::URL_SWITCHPROFILE . $switchId, $switchIcon . @$this->allSwitches[$switchId]['location']);
  389. return($result);
  390. }
  391. if (isset($this->allOnuMac[$mac])) {
  392. $onuId = $this->allOnuMac[$mac];
  393. $onuIcon = wf_img('skins/switch_models.png', __('ONU')) . ' ';
  394. $onuAssignedUser = '';
  395. if (isset($this->allOnuUsers[$onuId])) {
  396. $onuUserLogin = $this->allOnuUsers[$onuId];
  397. if (isset($this->allUserData[$onuUserLogin])) {
  398. $onuAssignedUser .= @$this->allUserData[$onuUserLogin]['fulladress'];
  399. }
  400. }
  401. $result .= wf_Link(self::URL_ONUPROFILE . $onuId, $onuIcon . $onuAssignedUser);
  402. }
  403. return($result);
  404. }
  405. /**
  406. * Trying to detect ONU device by mac. Returns profile view control.
  407. *
  408. * @param string $onuMac
  409. *
  410. * @return string
  411. */
  412. protected function getOnuHandle($onuMac) {
  413. $result = '';
  414. if (!empty($onuMac)) {
  415. if (isset($this->allOnuMac[$onuMac])) {
  416. $onuId = $this->allOnuMac[$onuMac];
  417. $result .= wf_Link(self::URL_ONUPROFILE . $onuId, $onuId);
  418. }
  419. }
  420. return($result);
  421. }
  422. /**
  423. * Parses archive raw data and stores data into instance json helper
  424. *
  425. * @param array $archiveRecord
  426. * @param string $macFilter
  427. * @param int $switchIdFilter
  428. *
  429. * @return void
  430. */
  431. protected function parseData($archiveRecord, $macFilter = '', $switchIdFilter = '') {
  432. if (!empty($archiveRecord)) {
  433. $recordDate = $archiveRecord['date'];
  434. $recordId = $archiveRecord['devid'];
  435. $recordIp = $archiveRecord['devip'];
  436. $switchIcon = wf_img('skins/menuicons/switches.png') . ' ';
  437. //normal switch data
  438. if ($archiveRecord['pon'] != 1) {
  439. $fdbData = @unserialize($archiveRecord['data']);
  440. if (!empty($fdbData)) {
  441. $fdbDataVLAN = array();
  442. $fdbDataPortDescr = array();
  443. if ($this->fdbExtenInfo) {
  444. $fdbDataVLAN = @unserialize($archiveRecord['datavlan']);
  445. $fdbDataPortDescr = @unserialize($archiveRecord['dataportdescr']);
  446. }
  447. foreach ($fdbData as $eachMac => $eachPort) {
  448. // if we have MACs stored along with VLANs (separated with underscore '_')
  449. // - we need to extract MAC portion
  450. $eachMAC_VLAN = '';
  451. if (ispos($eachMac, '_')) {
  452. // storing original value in "MAC_VLAN" representation
  453. $eachMAC_VLAN = $eachMac;
  454. // storing only extracted MAC portion
  455. $eachMac = substr($eachMac, 0, stripos($eachMac, '_'));
  456. }
  457. $filtered = true;
  458. //basic user MAC filtering
  459. if ($macFilter) {
  460. if ($eachMac != $macFilter) {
  461. $filtered = false;
  462. }
  463. }
  464. //filter records only from some switch ID
  465. if ($switchIdFilter) {
  466. if ($recordId != $switchIdFilter) {
  467. $filtered = false;
  468. }
  469. }
  470. if ($filtered) {
  471. $switchLink = $switchIcon . ' ' . __('Not exists');
  472. if (!empty($recordId)) {
  473. $switchLink = wf_Link(self::URL_SWITCHPROFILE . $recordId, $switchIcon . @$this->allSwitches[$recordId]['location']);
  474. }
  475. $data[] = $recordDate;
  476. $data[] = $recordIp;
  477. $data[] = $eachPort;
  478. if ($this->fdbExtenInfo) {
  479. $eachPortDescr = '';
  480. $eachVLAN = '';
  481. if (!empty($fdbDataPortDescr[$eachPort])) {
  482. $eachPortDescr = $fdbDataPortDescr[$eachPort];
  483. }
  484. if (!empty($fdbDataVLAN[$eachMAC_VLAN])) {
  485. $eachVLAN = $fdbDataVLAN[$eachMAC_VLAN];
  486. }
  487. $data[] = $eachPortDescr;
  488. $data[] = $eachVLAN;
  489. }
  490. $data[] = $switchLink;
  491. $data[] = $eachMac;
  492. $data[] = $this->getEntityControl($eachMac);
  493. $this->json->addRow($data);
  494. unset($data);
  495. }
  496. }
  497. }
  498. } else {
  499. //PON FDB data
  500. $fdbData = @unserialize($archiveRecord['data']);
  501. if (!empty($fdbData)) {
  502. foreach ($fdbData as $eachMacPon => $eachOnuData) {
  503. $switchLink = $switchIcon . ' ' . __('Not exists');
  504. if (!empty($recordId)) {
  505. $switchLink = wf_Link(self::URL_SWITCHPROFILE . $recordId, $switchIcon . @$this->allSwitches[$recordId]['location']);
  506. }
  507. if (!empty($eachOnuData)) {
  508. foreach ($eachOnuData as $eachOnuId => $onuFdb) {
  509. $filtered = true;
  510. //basic MAC filtering behind ONU
  511. if ($macFilter) {
  512. if ($onuFdb['mac'] != $macFilter) {
  513. $filtered = false;
  514. }
  515. }
  516. //filter records only from some OLT ID
  517. if ($switchIdFilter) {
  518. if ($recordId != $switchIdFilter) {
  519. $filtered = false;
  520. }
  521. }
  522. if ($filtered) {
  523. $data[] = $recordDate;
  524. $data[] = $recordIp;
  525. $data[] = $this->getOnuHandle($eachMacPon);
  526. if ($this->fdbExtenInfo) {
  527. $data[] = '';
  528. $data[] = @$onuFdb['vlan'];
  529. }
  530. $data[] = $switchLink;
  531. $data[] = $onuFdb['mac'];
  532. $data[] = $this->getEntityControl($eachMacPon);
  533. $this->json->addRow($data);
  534. unset($data);
  535. }
  536. }
  537. }
  538. }
  539. }
  540. }
  541. }
  542. }
  543. /**
  544. * Renders JSON data for background ajax requests
  545. *
  546. * @return void
  547. */
  548. public function ajArchiveData() {
  549. if (!ubRouting::checkGet('macfilter') AND ! ubRouting::checkGet('switchidfilter')) {
  550. //ugly hack to prevent memory overusage.
  551. $this->archive->whereRaw("`date` >= DATE_SUB(NOW(),INTERVAL 4 HOUR)");
  552. }
  553. $allArchiveRecords = $this->archive->getAll();
  554. $macFilter = '';
  555. $switchIdFilter = '';
  556. if (ubRouting::checkGet('macfilter')) {
  557. $macFilter = ubRouting::get('macfilter');
  558. }
  559. if (ubRouting::checkGet('switchidfilter')) {
  560. $switchIdFilter = ubRouting::get('switchidfilter', 'int');
  561. }
  562. if (!empty($allArchiveRecords)) {
  563. $this->loadUserData();
  564. if ($this->altCfg['PON_ENABLED']) {
  565. $this->loadOnuData();
  566. }
  567. foreach ($allArchiveRecords as $io => $each) {
  568. $this->parseData($each, $macFilter, $switchIdFilter);
  569. }
  570. }
  571. $this->json->getJson();
  572. }
  573. /**
  574. * Renders basic navigation controls
  575. *
  576. * @return string
  577. */
  578. public static function renderNavigationPanel() {
  579. $result = wf_Link(self::URL_CACHE, wf_img_sized('skins/fdbmacsearch.png', '', '16', '16') . ' ' . __('Current FDB cache'), false, 'ubButton') . ' ';
  580. $result .= wf_Link(self::URL_ME, wf_img('skins/fdbarchive.png', '', '16', '16') . ' ' . __('FDB') . ' ' . __('Archive'), false, 'ubButton') . ' ';
  581. if (ubRouting::checkGet('macfilter') OR ubRouting::checkGet('switchidfilter')) {
  582. $result .= wf_Link(self::URL_ME, wf_img('skins/icon_cleanup.png') . __('Cleanup') . ' ' . __('Filters'), false, 'ubButton') . ' ';
  583. }
  584. return($result);
  585. }
  586. }