1<?php
2
3/**
4 * Observium
5 *
6 *   This file is part of Observium.
7 *
8 * @package    observium
9 * @subpackage poller
10 * @copyright  (C) 2006-2013 Adam Armstrong, (C) 2013-2019 Observium Limited
11 *
12 */
13
14// FIXME -- we're walking, so we can discover here too.
15
16/// FIXME FIXME REWRITE ME please ;)
17
18print_cli_data_field('MIBs', 2);
19
20// Cache DB entries
21$sql  = 'SELECT * FROM `mac_accounting`';
22$sql .= ' WHERE `device_id` = ?';
23
24$acc_id_db = array();
25foreach (dbFetchRows($sql, array($device['device_id'])) as $acc)
26{
27  $port = get_port_by_id($acc['port_id']);
28  if (is_array($port))
29  {
30    $acc['ifIndex'] = $port['ifIndex'];
31    unset($port);
32    $ma_db_array[$acc['ifIndex'].'-'.$acc['vlan_id'].'-'.$acc['mac']] = $acc;
33  }
34  $acc_id_db[$acc['ma_id']] = $acc['ma_id'];
35}
36
37if (OBS_DEBUG > 1 && count($ma_db_array))
38{
39  print_vars($ma_db_array);
40}
41
42if (is_device_mib($device, 'JUNIPER-MAC-MIB'))
43{
44  $datas = snmp_walk($device, 'jnxMacStatsEntry', '-OUqsX', 'JUNIPER-MAC-MIB');
45  if ($GLOBALS['snmp_status'])
46  {
47    foreach (explode("\n", $datas) as $data)
48    {
49      list($oid,$ifIndex,$vlan,$mac,$value) = parse_oid2($data);
50      list($a_a, $a_b, $a_c, $a_d, $a_e, $a_f) = explode(':', $mac);
51      $ah_a = zeropad($a_a); $ah_b = zeropad($a_b); $ah_c = zeropad($a_c); $ah_d = zeropad($a_d); $ah_e = zeropad($a_e); $ah_f = zeropad($a_f);
52      $mac = "$ah_a$ah_b$ah_c$ah_d$ah_e$ah_f";
53      if ($mac == '000000000000') { continue; } // Skip entries with "zero" mac
54
55      $oid = str_replace(array('cipMacSwitchedBytes', 'cipMacSwitchedPkts'), array('bytes', 'pkts'), $oid);
56
57      if ($oid == 'jnxMacHCOutFrames') { $oid = 'pkts'; $dir = 'output'; }
58      if ($oid == 'jnxMacHCInFrames')  { $oid = 'pkts'; $dir = 'input'; }
59      if ($oid == 'jnxMacHCOutOctets') { $oid = 'bytes'; $dir = 'output'; }
60      if ($oid == 'jnxMacHCInOctets')  { $oid = 'bytes'; $dir = 'input'; }
61
62      $ma_array[$ifIndex.'-'.$vlan.'-'.$mac]['ifIndex'] = $ifIndex;
63      $ma_array[$ifIndex.'-'.$vlan.'-'.$mac]['vlan'] = $vlan;
64      $ma_array[$ifIndex.'-'.$vlan.'-'.$mac]['mac'] = $mac;
65      $ma_array[$ifIndex.'-'.$vlan.'-'.$mac][$oid][$dir] = $value;
66    }
67  }
68}
69
70// Cisco MAC Accounting
71// FIXME. Rewrite
72if (is_device_mib($device, 'CISCO-IP-STAT-MIB'))
73{
74  echo('Cisco ');
75
76  $device_context = $device;
77  if (!count($ma_db_array))
78  {
79    // Set retries to 0 for speedup first walking, only if previously polling also empty (DB empty)
80    $device_context['snmp_retries'] = 0;
81  }
82  $datas32 = snmp_walk($device_context, 'cipMacSwitchedBytes', '-OUqsX', 'CISCO-IP-STAT-MIB');
83  unset($device_context);
84  if ($GLOBALS['snmp_status'])
85  {
86    $datas = snmp_walk($device, 'cipMacHCSwitchedBytes', '-OUqsX', 'CISCO-IP-STAT-MIB');
87    if ($GLOBALS['snmp_status'])
88    {
89      $datas .= "\n".snmp_walk($device, 'cipMacHCSwitchedPkts', '-OUqsX', 'CISCO-IP-STAT-MIB');
90    } else {
91      // No 64-bit counters? Try 32-bit. How necessary is this? How lacking is 64-bit support?
92      $datas = $datas32;
93      $datas .= "\n".snmp_walk($device, 'cipMacSwitchedPkts', '-OUqsX', 'CISCO-IP-STAT-MIB');
94    }
95
96    foreach (explode("\n", $datas) as $data)
97    {
98      list($oid,$ifIndex,$dir,$mac,$value) = parse_oid2($data);
99      list($a_a, $a_b, $a_c, $a_d, $a_e, $a_f) = explode(':', $mac);
100      $ah_a = zeropad($a_a); $ah_b = zeropad($a_b); $ah_c = zeropad($a_c); $ah_d = zeropad($a_d); $ah_e = zeropad($a_e); $ah_f = zeropad($a_f);
101      $mac = "$ah_a$ah_b$ah_c$ah_d$ah_e$ah_f";
102      if ($mac == '000000000000') { continue; } // Skip entries with "zero" mac
103
104      // Cisco isn't per-VLAN.
105      $vlan = '0';
106
107      $oid = str_replace(array('cipMacSwitchedBytes', 'cipMacSwitchedPkts', 'cipMacHCSwitchedBytes', 'cipMacHCSwitchedPkts'), array('bytes', 'pkts', 'bytes', 'pkts'), $oid);
108      $ma_array[$ifIndex.'-'.$vlan.'-'.$mac]['ifIndex'] = $ifIndex;
109      $ma_array[$ifIndex.'-'.$vlan.'-'.$mac]['vlan'] = $vlan;
110      $ma_array[$ifIndex.'-'.$vlan.'-'.$mac]['mac'] = $mac;
111      $ma_array[$ifIndex.'-'.$vlan.'-'.$mac][$oid][$dir] = $value;
112    }
113  }
114}
115
116// Below this should be MIB / vendor agnostic.
117
118#function array_defuffle_three($array)
119#{
120#  foreach ($array as $key_a => $a)
121#  {
122#    foreach ($a as $key_b => $b)
123#    {
124#      foreach ($b as $key_c => $c)
125#      {
126#        $new_array[] = array($key_a, $key_b, $key_c, $c);
127#      }
128#    }
129#  }
130#  return $new_array;
131#}
132
133$acc_id = array(); // Count exist ma_ids
134if (count($ma_array))
135{
136  if (OBS_DEBUG > 1) { print_vars($ma_array); }
137  $polled = time();
138  $mac_entries = 0;
139  echo('Entries: '.count($ma_array).PHP_EOL);
140
141  foreach ($ma_array as $id => $ma)
142  {
143    $port = get_port_by_index_cache($device['device_id'], $ma['ifIndex']);
144
145    echo(' '.$id.' ');
146
147    if (!is_array($ma_db_array[$id]))
148    {
149      $ma_id = dbInsert(array('port_id' => $port['port_id'], 'device_id' => $device['device_id'], 'vlan_id' => $ma['vlan'], 'mac' => $ma['mac'] ), 'mac_accounting');
150      if ($ma_id)
151      {
152        echo('+');
153        $acc_id[$ma_id] = $ma_id;
154      } else {
155        echo('-');
156        continue; // wrong adding to DB, not exist id - delete
157      }
158    } else {
159      echo('.');
160      $ma_db = $ma_db_array[$id];
161      $acc_id[$ma_db['ma_id']] = $ma_db['ma_id'];
162    }
163
164    $polled_period = $polled - $acc['poll_time'];
165
166    if (OBS_DEBUG > 1) { print_vars($ma_array[$ifIndex][$vlan_id][$mac]); }
167
168    $ma['update']['poll_time'] = $polled;
169    $ma['update']['poll_period'] = $polled_period;
170    $mac_entries++;
171    $b_in = $ma['bytes']['input'];
172    $b_out = $ma['bytes']['output'];
173    $p_in = $ma['pkts']['input'];
174    $p_out = $ma['pkts']['output'];
175
176    echo(' '.$port['ifDescr'].'('.$ifIndex.') -> '.$mac);
177
178    // Update metrics
179    foreach (array('bytes','pkts') as $oid)
180    {
181      foreach (array('input','output') as $dir)
182      {
183        $oid_dir = $oid . '_' . $dir;
184        $ma['update'][$oid_dir] = $ma[$oid][$dir];
185
186        if ($ma[$oid][$dir] && $ma_db[$oid_dir])
187        {
188          $oid_diff = $ma[$oid][$dir] - $ma_db[$oid_dir];
189          $oid_rate  = $oid_diff / $polled_period;
190          $ma['update'][$oid_dir.'_rate'] = $oid_rate;
191          $ma['update'][$oid_dir.'_delta'] = $oid_diff;
192          print_debug("\n $oid_dir ($oid_diff B) $oid_rate Bps $polled_period secs");
193        }
194      }
195
196      print_debug($ma['hostname'].' '.$ma['ifDescr'] . "  $mac -> $b_in:$b_out:$p_in:$p_out ");
197
198      // FIXME - use memory tables to make sure these values don't go backwards?
199      rrdtool_update_ng($device, 'mac_acc', array(
200        'IN'   => $b_in,
201        'OUT'  => $b_out,
202        'PIN'  => $p_in,
203        'POUT' => $p_out,
204      ), $port['ifIndex'] . '-' . $ma['vlan'] .'-' . $ma['mac']);
205
206      if (OBS_DEBUG > 1) { print_vars($ma['update']); }
207
208      if (is_array($ma['update']))
209      { // Do Updates
210        dbUpdate($ma['update'], 'mac_accounting', '`ma_id` = ?', array($ma_db['ma_id']));
211      } // End Updates
212    }
213  }
214
215  unset($ma_array);
216
217  if ($mac_entries) { echo(" $mac_entries MAC accounting entries\n"); }
218
219  echo(PHP_EOL);
220}
221
222// CLEAN not exist entries
223foreach ($acc_id_db as $ma_id => $entry)
224{
225  if (!isset($acc_id[$ma_id]))
226  {
227    dbDelete('mac_accounting', '`ma_id` = ?', array($ma_id));
228  }
229}
230echo(PHP_EOL);
231
232// EOF
233