/** * Update a switches ports using SNMP polling * * There is an optional ``$results`` array which can be passed by reference. If * so, it will be indexed by the SNMP port index (or a decresing nagative index * beginning -1 if the port only exists in the database). The contents of this * associative array is: * * "port" => \Entities\SwitchPort object * "bullet" => * - false for existing ports * - "new" for newly found ports * - "db" for ports that exist in the database only * * **Note:** It is assumed that the Doctrine2 Entity Manager is available in the * Zend registry as ``d2em`` in this function. * * @throws \OSS_SNMP\Exception * * @param \OSS_SNMP\SNMP $host An instance of \OSS_SNMP\SNMP for this switch * @param \OSS_Logger $logger An instance of the logger or false * @param array Call by reference to an array in which to store results as outlined above * @return \Entities\Switcher For fluent interfaces */ public function snmpPollSwitchPorts($host, $logger = false, &$result = false) { // clone the ports currently known to this switch as we'll be playing with this array $existingPorts = clone $this->getPorts(); // iterate over all the ports discovered on the switch: foreach ($host->useIface()->indexes() as $index) { // we're only interested in Ethernet ports here (right?) if ($host->useIface()->types()[$index] != \OSS_SNMP\MIBS\Iface::IF_TYPE_ETHERNETCSMACD) { continue; } // find the matching switchport that may already be in the database (or create a new one) $switchport = false; foreach ($existingPorts as $ix => $ep) { if ($ep->getIfIndex() == $index) { $switchport = $ep; if (is_array($result)) { $result[$index] = ["port" => $switchport, 'bullet' => false]; } if ($logger) { $logger->info(" - {$this->getName()} - found pre-existing port for ifIndex {$index}"); } // remove this from the array so later we'll know what ports exist only in the database unset($existingPorts[$ix]); break; } } $new = false; if (!$switchport) { // no existing port in database so we have found a new port $switchport = new \Entities\SwitchPort(); $switchport->setSwitcher($this); $this->addPort($switchport); $switchport->setType(\Entities\SwitchPort::TYPE_UNSET); $switchport->setIfIndex($index); $switchport->setActive(true); \Zend_Registry::get('d2em')['default']->persist($switchport); if (is_array($result)) { $result[$index] = ["port" => $switchport, 'bullet' => "new"]; } $new = true; if ($logger) { $logger->info("Found new port for {$this->getName()} with index {$index}"); } } // update / set port details from SNMP $switchport->snmpUpdate($host, $logger); } if (count($existingPorts)) { $i = -1; foreach ($existingPorts as $ep) { if (is_array($result)) { $result[$i--] = ["port" => $ep, 'bullet' => "db"]; } if ($logger) { $logger->warn("{$this->getName()} - port found in database with no matching port on the switch: " . " [{$ep->getId()}] {$ep->getName()}"); } } } return $this; }
/** * Update switch port details from a SNMP poll of the device. * * Pass an instance of OSS_Logger if you want logging enabled. * * @link https://github.com/opensolutions/OSS_SNMP * * @throws \OSS_SNMP\Exception * * @param \OSS_SNMP\SNMP $host An instance of the SNMP host object * @param \OSS_Logger $logger An instance of the logger or false * @return \Entities\SwitchPort For fluent interfaces */ public function snmpUpdate($host, $logger = false) { foreach (self::$OSS_SNMP_MAP as $snmp => $entity) { $fn = "get{$entity}"; switch ($snmp) { case 'lastChanges': $n = $host->useIface()->{$snmp}(true)[$this->getIfIndex()]; // need to allow for small changes due to rounding errors if ($logger && $this->{$fn}() != $n && abs($this->{$fn}() - $n) > 60) { $logger->info("[{$this->getSwitcher()->getName()}]:{$this->getName()} [Index: {$this->getIfIndex()}] Updating {$entity} from [{$this->{$fn}()}] to [{$n}]"); } break; default: $n = $host->useIface()->{$snmp}()[$this->getIfIndex()]; if ($logger && $this->{$fn}() != $n) { $logger->info("[{$this->getSwitcher()->getName()}]:{$this->getName()} [Index: {$this->getIfIndex()}] Updating {$entity} from [{$this->{$fn}()}] to [{$n}]"); } break; } $fn = "set{$entity}"; $this->{$fn}($n); } if ($this->getSwitcher()->getMauSupported()) { foreach (self::$OSS_SNMP_MAU_MAP as $snmp => $entity) { $getfn = "get{$entity['fn']}"; $setfn = "set{$entity['fn']}"; try { if (isset($entity['xlate'])) { $n = $host->useMAU()->{$snmp}($entity['xlate'])[$this->getIfIndex()]; } else { $n = $host->useMAU()->{$snmp}()[$this->getIfIndex()]; } } catch (\OSS_SNMP\Exception $e) { // looks like the switch supports MAU but not all of the MIBs $logger->debug("[{$this->getSwitcher()->getName()}]:{$this->getName()} [Index: {$this->getIfIndex()}] MAU MIB for {$fn} not supported"); $n = null; } if ($n == '*** UNKNOWN ***' && $snmp == 'types') { $n = '(empty)'; } if ($logger && $this->{$getfn}() != $n) { $logger->info("[{$this->getSwitcher()->getName()}]:{$this->getName()} [Index: {$this->getIfIndex()}] Updating {$entity['fn']} from [{$this->{$getfn}()}] to [{$n}]"); } $this->{$setfn}($n); } } try { // not all switches support this // FIXME is there a vendor agnostic way of doing this? // are we a LAG port? $isAggregatePorts = $host->useLAG()->isAggregatePorts(); if (isset($isAggregatePorts[$this->getIfIndex()]) && $isAggregatePorts[$this->getIfIndex()]) { $this->setLagIfIndex($host->useLAG()->portAttachedIds()[$this->getIfIndex()]); } else { $this->setLagIfIndex(null); } } catch (\OSS_SNMP\Exception $e) { } $this->setLastSnmpPoll(new \DateTime()); return $this; }