Issues (2963)

LibreNMS/Modules/Isis.php (1 issue)

1
<?php
2
/**
3
 * Isis.php
4
 *
5
 * -Description-
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 *
20
 * @link       http://librenms.org
21
 *
22
 * @copyright  2021 Otto Reinikainen
23
 * @author     Otto Reinikainen <[email protected]>
24
 */
25
26
namespace LibreNMS\Modules;
27
28
use App\Models\IsisAdjacency;
29
use App\Observers\ModuleModelObserver;
30
use Illuminate\Support\Arr;
31
use Illuminate\Support\Collection;
32
use LibreNMS\DB\SyncsModels;
33
use LibreNMS\Interfaces\Discovery\IsIsDiscovery;
34
use LibreNMS\Interfaces\Module;
35
use LibreNMS\Interfaces\Polling\IsIsPolling;
36
use LibreNMS\OS;
0 ignored issues
show
This use statement conflicts with another class in this namespace, LibreNMS\Modules\OS. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
37
use LibreNMS\Util\IP;
38
39
class Isis implements Module
40
{
41
    use SyncsModels;
42
43
    protected $isis_codes = [
44
        'l1IntermediateSystem' => 'L1',
45
        'l2IntermediateSystem' => 'L2',
46
        'l1L2IntermediateSystem' => 'L1L2',
47
        'unknown' => 'unknown',
48
    ];
49
50
    /**
51
     * Discover this module. Heavier processes can be run here
52
     * Run infrequently (default 4 times a day)
53
     *
54
     * @param  OS  $os
55
     */
56
    public function discover(OS $os)
57
    {
58
        $adjacencies = $os instanceof IsIsDiscovery
59
            ? $os->discoverIsIs()
60
            : $this->discoverIsIsMib($os);
61
62
        ModuleModelObserver::observe('\App\Models\IsisAdjacency');
63
        $this->syncModels($os->getDevice(), 'isisAdjacencies', $adjacencies);
64
    }
65
66
    /**
67
     * Poll data for this module and update the DB / RRD.
68
     * Try to keep this efficient and only run if discovery has indicated there is a reason to run.
69
     * Run frequently (default every 5 minutes)
70
     *
71
     * @param  OS  $os
72
     */
73
    public function poll(OS $os)
74
    {
75
        $adjacencies = $os->getDevice()->isisAdjacencies;
76
77
        if (empty($adjacencies)) {
78
            return; // no data to poll
79
        }
80
81
        $updated = $os instanceof IsIsPolling
82
            ? $os->pollIsIs($adjacencies)
83
            : $this->pollIsIsMib($adjacencies, $os);
84
85
        $updated->each->save();
86
    }
87
88
    /**
89
     * Remove all DB data for this module.
90
     * This will be run when the module is disabled.
91
     *
92
     * @param  OS  $os
93
     */
94
    public function cleanup(OS $os)
95
    {
96
        $os->getDevice()->isisAdjacencies()->delete();
97
98
        // clean up legacy components from old code
99
        $os->getDevice()->components()->where('type', 'ISIS')->delete();
100
    }
101
102
    public function discoverIsIsMib(OS $os): Collection
103
    {
104
        // Check if the device has any ISIS enabled interfaces
105
        $circuits = snmpwalk_cache_oid($os->getDeviceArray(), 'ISIS-MIB::isisCirc', []);
106
        $adjacencies = new Collection;
107
108
        if (! empty($circuits)) {
109
            $adjacencies_data = snmpwalk_cache_twopart_oid($os->getDeviceArray(), 'ISIS-MIB::isisISAdj', [], null, null, '-OQUstx');
110
            $ifIndex_port_id_map = $os->getDevice()->ports()->pluck('port_id', 'ifIndex');
111
112
            // No ISIS enabled interfaces -> delete the component
113
            foreach ($circuits as $circuit_id => $circuit_data) {
114
                if (! isset($circuit_data['isisCircIfIndex'])) {
115
                    continue;
116
                }
117
118
                if ($circuit_data['isisCircPassiveCircuit'] == 'true') {
119
                    continue; // Do not poll passive interfaces
120
                }
121
122
                $adjacency_data = Arr::last($adjacencies_data[$circuit_id] ?? [[]]);
123
124
                $attributes = [
125
                    'device_id' => $os->getDeviceId(),
126
                    'ifIndex' => $circuit_data['isisCircIfIndex'],
127
                    'port_id' => $ifIndex_port_id_map[$circuit_data['isisCircIfIndex']] ?? null,
128
                    'isisCircAdminState' => $circuit_data['isisCircAdminState'] ?? 'down',
129
                    'isisISAdjState' => $adjacency_data['isisISAdjState'] ?? 'down',
130
                ];
131
132
                if (! empty($adjacency_data)) {
133
                    $attributes = array_merge($attributes, [
134
                        'isisISAdjNeighSysType' => Arr::get($this->isis_codes, $adjacency_data['isisISAdjNeighSysType'] ?? 'unknown', 'unknown'),
135
                        'isisISAdjNeighSysID' => str_replace(' ', '.', trim($adjacency_data['isisISAdjNeighSysID'] ?? '')),
136
                        'isisISAdjNeighPriority' => $adjacency_data['isisISAdjNeighPriority'] ?? '',
137
                        'isisISAdjLastUpTime' => $this->parseAdjacencyTime($adjacency_data),
138
                        'isisISAdjAreaAddress' => str_replace(' ', '.', trim($adjacency_data['isisISAdjAreaAddress'] ?? '')),
139
                        'isisISAdjIPAddrType' => $adjacency_data['isisISAdjIPAddrType'] ?? '',
140
                        'isisISAdjIPAddrAddress' => (string) IP::fromHexstring($adjacency_data['isisISAdjIPAddrAddress'] ?? null, true),
141
                    ]);
142
                }
143
144
                $adjacencies->push(new IsisAdjacency($attributes));
145
            }
146
        }
147
148
        return $adjacencies;
149
    }
150
151
    public function pollIsIsMib(Collection $adjacencies, OS $os): Collection
152
    {
153
        $data = snmpwalk_cache_twopart_oid($os->getDeviceArray(), 'isisISAdjState', [], 'ISIS-MIB');
154
155
        if (count($data) !== $adjacencies->where('isisISAdjState', 'up')->count()) {
156
            echo 'New Adjacencies, running discovery';
157
            // don't enable, might be a bad heuristic
158
            return $this->fillNew($adjacencies, $this->discoverIsIsMib($os));
159
        }
160
161
        $data = snmpwalk_cache_twopart_oid($os->getDeviceArray(), 'isisISAdjLastUpTime', $data, 'ISIS-MIB', null, '-OQUst');
162
163
        $adjacencies->each(function (IsisAdjacency $adjacency) use (&$data) {
164
            $adjacency_data = Arr::last($data[$adjacency->ifIndex]);
165
            $adjacency->isisISAdjState = $adjacency_data['isisISAdjState'] ?? $adjacency->isisISAdjState;
166
            $adjacency->isisISAdjLastUpTime = $this->parseAdjacencyTime($adjacency_data);
167
            $adjacency->save();
168
            unset($data[$adjacency->ifIndex]);
169
        });
170
171
        return $adjacencies;
172
    }
173
174
    protected function parseAdjacencyTime($data): int
175
    {
176
        return (int) max($data['isisISAdjLastUpTime'] ?? 1, 1) / 100;
177
    }
178
}
179