r1931 + tossing SNMP code around
[racktables] / inc / snmp.php
CommitLineData
2ffd5a2a
DO
1<?php
2
3function doSNMPmining ($object_id, $community)
4{
5 $log = array();
6// IDs: http://cisco.com/en/US/products/sw/cscowork/ps2064/products_device_support_table09186a0080803bb4.html
7// 2950: http://www.cisco.com/en/US/products/hw/switches/ps628/prod_models_home.html
8// 2960: http://www.cisco.com/en/US/products/ps6406/prod_models_comparison.html
9// 2970: http://cisco.com/en/US/products/hw/switches/ps5206/products_qanda_item09186a00801b1750.shtml
10// 3500XL: http://cisco.com/en/US/products/hw/switches/ps637/products_eol_models.html
11// 3560: http://cisco.com/en/US/products/hw/switches/ps5528/products_data_sheet09186a00801f3d7f.html
12// 3750: http://cisco.com/en/US/products/hw/switches/ps5023/products_data_sheet09186a008016136f.html
13
14 $ciscomodel = array
15 (
16 283 => 'WS-C6509-E (9-slot system)',
17# 694 => 'WS-C2960-24TC-L (24 Ethernet 10/100 ports and 2 dual-purpose uplinks)',
18# 695 => 'WS-C2960-48TC-L (48 Ethernet 10/100 ports and 2 dual-purpose uplinks)',
19 696 => 'WS-C2960G-24TC-L (20 Ethernet 10/100/1000 ports and 4 dual-purpose uplinks)',
20 697 => 'WS-C2960G-48TC-L (44 Ethernet 10/100/1000 ports and 4 dual-purpose uplinks)',
21# 716 => 'WS-C2960-24TT-L (24 Ethernet 10/100 ports and 2 10/100/1000 uplinks)',
22# 717 => 'WS-C2960-48TT-L (48 Ethernet 10/100 ports and 2 10/100/1000 uplinks)',
23 527 => 'WS-C2970G-24T (24 Ethernet 10/100/1000 ports)',
24 561 => 'WS-C2970G-24TS (24 Ethernet 10/100/1000 ports and 4 10/100/1000 SFP uplinks)',
25 633 => 'WS-C3560-24TS (24 Ethernet 10/100 ports and 2 10/100/1000 SFP uplinks)',
26 634 => 'WS-C3560-48TS (48 Ethernet 10/100 ports and 4 10/100/1000 SFP uplinks)',
27 563 => 'WS-C3560-24PS (24 Ethernet 10/100 POE ports and 2 10/100/1000 SFP uplinks)',
28 564 => 'WS-C3560-48PS (48 Ethernet 10/100 POE ports and 4 10/100/1000 SFP uplinks)',
29 614 => 'WS-C3560G-24PS (24 Ethernet 10/100/1000 POE ports and 4 10/100/1000 SFP uplinks)',
30 615 => 'WS-C3560G-24TS (24 Ethernet 10/100/1000 ports and 4 10/100/1000 SFP uplinks)',
31 616 => 'WS-C3560G-48PS (48 Ethernet 10/100/1000 POE ports and 4 10/100/1000 SFP uplinks)',
32 617 => 'WS-C3560G-48TS (48 Ethernet 10/100/1000 ports and 4 10/100/1000 SFP uplinks)',
33 58 => 'WS-C4503 (3-slot system)',
34 503 => '4503 (3-slot system)',
35 59 => 'WS-C4506 (6-slot system)',
36 502 => '4506 (6-slot system)',
37 626 => 'WS-C4948 (48 Ethernet 10/100/1000 ports and 4 10/100/1000 SFP uplinks)',
38 659 => 'WS-C4948-10GE (48 Ethernet 10/100/1000 ports and 2 10Gb X2 uplinks)',
39 );
40 $hwtype = array
41 (
42 283 => 148,
43 696 => 167,
44 697 => 166,
45 527 => 210,
46 561 => 115,
47 633 => 169,
48 634 => 170,
49 563 => 171,
50 564 => 172,
51 614 => 175,
52 615 => 173,
53 616 => 176,
54 617 => 174,
55 58 => 145,
56 503 => 145,
57 59 => 156,
58 502 => 156,
59 626 => 147,
60 659 => 377
61 );
62
63 $objectInfo = getObjectInfo ($object_id);
64 $endpoints = findAllEndpoints ($object_id, $objectInfo['name']);
65 $sysName = substr (snmpget ($endpoints[0], $community, 'sysName.0'), strlen ('STRING: '));
66 $sysDescr = snmpget ($endpoints[0], $community, 'sysDescr.0');
67 $sysChassi = snmpget ($endpoints[0], $community, '1.3.6.1.4.1.9.3.6.3.0');
68 // Strip the object type, it's always string here.
69 $sysDescr = substr ($sysDescr, strlen ('STRING: '));
70 $sysChassi = str_replace ('"', '', substr ($sysChassi, strlen ('STRING: ')));
71 if (strpos ($sysDescr, 'Cisco IOS Software') === 0 or strpos ($sysDescr, 'Cisco Internetwork Operating System Software') === 0)
72 $log[] = array ('code' => 'success', 'message' => 'Seems to be a Cisco box');
73 else
74 {
75 $log[] = array ('code' => 'error', 'message' => 'No idea how to handle ' . $sysDescr);
76 printLog ($log);
77 return;
78 }
79
80 // It's a Cisco box. Go on.
81 $attrs = getAttrValues ($object_id);
82 // Only fill in attribute values, if they are not set.
83 // FIXME: this is hardcoded
84
85 if (empty ($attrs[3]['value']) && !empty ($sysName)) // FQDN
86 {
87 $error = commitUpdateAttrValue ($object_id, 3, $sysName);
88 if ($error == TRUE)
89 $log[] = array ('code' => 'success', 'message' => 'FQDN set to ' . $sysName);
90 else
91 $log[] = array ('code' => 'error', 'message' => 'Failed settig FQDN: ' . $error);
92 }
93
94 if (empty ($attrs[5]['value'])) // SW version
95 {
96 $IOSversion = ereg_replace ('^.*, Version ([^ ]+), .*$', '\\1', $sysDescr);
97 $error = commitUpdateAttrValue ($object_id, 5, $IOSversion);
98 if ($error == TRUE)
99 $log[] = array ('code' => 'success', 'message' => 'SW version set to ' . $IOSversion);
100 else
101 $log[] = array ('code' => 'error', 'message' => 'Failed settig SW version: ' . $error);
102 }
103
104 if (empty ($attrs[1]['value']) and strlen ($sysChassi) > 0) // OEM Serial #1
105 {
106 $error = commitUpdateAttrValue ($object_id, 1, $sysChassi);
107 if ($error == TRUE)
108 $log[] = array ('code' => 'success', 'message' => 'OEM S/N 1 set to ' . $sysChassi);
109 else
110 $log[] = array ('code' => 'error', 'message' => 'Failed settig OEM S/N 1: ' . $error);
111 }
112
113 if (empty ($attrs[4]['value'])) // switch OS type
114 switch (substr ($IOSversion, 0, 4))
115 {
116 case '12.2':
117 $error = commitUpdateAttrValue ($object_id, 4, 252);
118 break;
119 case '12.1':
120 $error = commitUpdateAttrValue ($object_id, 4, 251);
121 break;
122 case '12.0':
123 $error = commitUpdateAttrValue ($object_id, 4, 244);
124 break;
125 }
126 if ($error == TRUE)
127 $log[] = array ('code' => 'success', 'message' => 'Switch OS type set to Cisco IOS ' . substr ($IOSversion, 0, 4));
128 else
129 $log[] = array ('code' => 'error', 'message' => 'Failed settig Switch OS type');
130
131 $sysObjectID = snmpget ($endpoints[0], $community, 'sysObjectID.0');
132 // Transform OID
133 $sysObjectID = substr ($sysObjectID, strlen ('OID: SNMPv2-SMI::enterprises.9.1.'));
134 if (!isset ($ciscomodel[$sysObjectID]))
135 {
136 $log[] = array ('code' => 'error', 'message' => 'Could not guess exact HW model!');
137 printLog ($log);
138 return;
139 }
140 $log[] = array ('code' => 'success', 'message' => 'HW is ' . $ciscomodel[$sysObjectID]);
141 if (empty ($attrs[2]['value']) and isset ($hwtype[$sysObjectID])) // switch HW type
142 {
143 $error = commitUpdateAttrValue ($object_id, 2, $hwtype[$sysObjectID]);
144 if ($error == TRUE)
145 $log[] = array ('code' => 'success', 'message' => 'HW type updated Ok');
146 else
147 $log[] = array ('code' => 'error', 'message' => 'Failed settig HW type: ' . $error);
148 }
149 // Now fetch ifType, ifDescr and ifPhysAddr and let model-specific code sort the data out.
150 $ifType = snmpwalkoid ($endpoints[0], $community, 'ifType');
151 $ifDescr = snmpwalkoid ($endpoints[0], $community, 'ifdescr');
152 $ifPhysAddress = snmpwalkoid ($endpoints[0], $community, 'ifPhysAddress');
153 // Combine 3 tables into 1...
154 $ifList1 = array();
155 foreach ($ifType as $key => $val)
156 {
157 list ($dummy, $ifIndex) = explode ('.', $key);
158 list ($dummy, $type) = explode (' ', $val);
159 $ifList1[$ifIndex]['type'] = $type;
160 }
161 foreach ($ifDescr as $key => $val)
162 {
163 list ($dummy, $ifIndex) = explode ('.', $key);
164 list ($dummy, $descr) = explode (' ', $val);
165 $ifList1[$ifIndex]['descr'] = trim ($descr, '"');
166 }
167 foreach ($ifPhysAddress as $key => $val)
168 {
169 list ($dummy, $ifIndex) = explode ('.', $key);
170 list ($dummy, $addr) = explode (':', $val);
171 $addr = str_replace (' ', '', $addr);
172 $ifList1[$ifIndex]['phyad'] = $addr;
173 }
174 // ...and then reverse it inside out to make description the key.
175 $ifList2 = array();
176 foreach ($ifList1 as $ifIndex => $data)
177 {
178 $ifList2[$data['descr']]['type'] = $data['type'];
179 $ifList2[$data['descr']]['phyad'] = $data['phyad'];
180 $ifList2[$data['descr']]['idx'] = $ifIndex;
181 }
182 $newports = 0;
183 // Now we can directly pick necessary ports from the table accordingly
184 // to our known hardware model.
185 switch ($sysObjectID)
186 {
187 // FIXME: chassis edge switches often share a common naming scheme, so
188 // the sequences below have to be generalized. Let's have some duplicated
189 // code for the time being, as this is the first implementation ever.
190 case '697': // WS-C2960G-48TC-L
191 // 44 copper ports: 1X, 2X, 3X...
192 // 4 combo ports: 45, 46, 47, 48. Don't list SFP connectors atm, as it's not
193 // clear how to fit them into current Ports table structure.
194 for ($i = 1; $i <= 48; $i++)
195 {
196 $label = ($i >= 45) ? "${i}" : "${i}X";
197 $error = commitAddPort ($object_id, 'gi0/' . $i, 24, $label, $ifList2["GigabitEthernet0/${i}"]['phyad']);
198 if ($error == '')
199 $newports++;
200 else
201 $log[] = array ('code' => 'error', 'message' => 'Failed to add port ' . $label . ': ' . $error);
202 }
203 break;
204 case '696': // WS-C2960G-24TC-L
205 // Quite similar to the above.
206 for ($i = 1; $i <= 24; $i++)
207 {
208 $label = ($i >= 21) ? "${i}" : "${i}X";
209 $error = commitAddPort ($object_id, 'gi0/' . $i, 24, $label, $ifList2["GigabitEthernet0/${i}"]['phyad']);
210 if ($error == '')
211 $newports++;
212 else
213 $log[] = array ('code' => 'error', 'message' => 'Failed to add port ' . $label . ': ' . $error);
214 }
215 break;
216 case '563': // WS-C3560-24PS
217 case '633': // WS-C3560-24TS
218 for ($i = 1; $i <= 24; $i++)
219 {
220 $label = "${i}X";
221 $error = commitAddPort ($object_id, 'fa0/' . $i, 19, $label, $ifList2["FastEthernet0/${i}"]['phyad']);
222 if ($error == '')
223 $newports++;
224 else
225 $log[] = array ('code' => 'error', 'message' => 'Failed to add port ' . $label . ': ' . $error);
226 }
227 for ($i = 1; $i <= 2; $i++)
228 {
229 $label = "${i}";
230 $error = commitAddPort ($object_id, 'gi0/' . $i, 24, $label, $ifList2["GigabitEthernet0/${i}"]['phyad']);
231 if ($error == '')
232 $newports++;
233 else
234 $log[] = array ('code' => 'error', 'message' => 'Failed to add port ' . $label . ': ' . $error);
235 }
236 break;
237 case '564': // WS-C3560-48PS
238 case '634': // WS-C3560-48TS
239 for ($i = 1; $i <= 48; $i++)
240 {
241 $label = "${i}X";
242 $error = commitAddPort ($object_id, 'fa0/' . $i, 19, $label, $ifList2["FastEthernet0/${i}"]['phyad']);
243 if ($error == '')
244 $newports++;
245 else
246 $log[] = array ('code' => 'error', 'message' => 'Failed to add port ' . $label . ': ' . $error);
247 }
248 for ($i = 1; $i <= 4; $i++)
249 {
250 $label = "${i}";
251 $error = commitAddPort ($object_id, 'gi0/' . $i, 24, $label, $ifList2["GigabitEthernet0/${i}"]['phyad']);
252 if ($error == '')
253 $newports++;
254 else
255 $log[] = array ('code' => 'error', 'message' => 'Failed to add port ' . $label . ': ' . $error);
256 }
257 break;
258 case '614': // WS-C3560G-24PS
259 case '615': // WS-C3560G-24TS
260 case '527': // WS-C2970G-24T
261 case '561': // WS-C2970G-24TS
262 case '428': // WS-C2950G-24
263 for ($i = 1; $i <= 24; $i++)
264 {
265 $label = "${i}X";
266 $error = commitAddPort ($object_id, 'gi0/' . $i, 24, $label, $ifList2["GigabitEthernet0/${i}"]['phyad']);
267 if ($error == '')
268 $newports++;
269 else
270 $log[] = array ('code' => 'error', 'message' => 'Failed to add port ' . $label . ': ' . $error);
271 }
272 break;
273 case '616': // WS-C3560G-48PS
274 case '617': // WS-C3560G-48TS
275 case '429': // WS-C2950G-48
276 for ($i = 1; $i <= 48; $i++)
277 {
278 $label = "${i}X";
279 $error = commitAddPort ($object_id, 'gi0/' . $i, 24, $label, $ifList2["GigabitEthernet0/${i}"]['phyad']);
280 if ($error == '')
281 $newports++;
282 else
283 $log[] = array ('code' => 'error', 'message' => 'Failed to add port ' . $label . ': ' . $error);
284 }
285 break;
286 case '626': // WS-C4948
287 case '659': // WS-C4948-10GE
288 for ($i = 1; $i <= 48; $i++)
289 {
290 $label = "${i}X";
291 $error = commitAddPort ($object_id, 'gi1/' . $i, 24, $label, $ifList2["GigabitEthernet1/${i}"]['phyad']);
292 if ($error == '')
293 $newports++;
294 else
295 $log[] = array ('code' => 'error', 'message' => 'Failed to add port ' . $label . ': ' . $error);
296 }
297 break;
298 // For modular devices we don't iterate over all possible port names,
299 // but use the first list to pick everything that looks legitimate
300 // for this hardware. It would be correct to fetch the list of modules
301 // installed to generate lists of ports, but who is going to implement
302 // this?
303 case '503': // 4503
304 case '58': // WS-C4503
305 case '502': // 4506
306 case '59': // WS-C4506
307 case '283': // WS-C6509-E
308 foreach ($ifList1 as $port)
309 {
310 if ($port['type'] != 'ethernet-csmacd(6)')
311 continue;
312 // Copper Fa/Gi harvesting is relatively simple, while 10Gig ports can
313 // have random samples of transciever units.
314 if (strpos ($port['descr'], 'FastEthernet') === 0) // Fa
315 {
316 $prefix = 'fa';
317 $ptype = 19; // RJ-45/100Base-TX
318 list ($slotno, $portno) = explode ('/', substr ($port['descr'], strlen ('FastEthernet')));
319 }
320 elseif (strpos ($port['descr'], 'GigabitEthernet') === 0) // Gi
321 {
322 $prefix = 'gi';
323 $ptype = 24; // RJ-45/1000Base-T
324 list ($slotno, $portno) = explode ('/', substr ($port['descr'], strlen ('GigabitEthernet')));
325 }
326 else continue;
327 $label = "slot ${slotno} port ${portno}";
328 $pname = "${prefix}${slotno}/${portno}";
329 $error = commitAddPort ($object_id, $pname, $ptype, $label, $port['phyad']);
330 if ($error == '')
331 $newports++;
332 else
333 $log[] = array ('code' => 'error', 'message' => 'Failed to add port ' . $pname . ': ' . $error);
334 }
335 break;
336 default:
337 showError ("Unexpected sysObjectID '${sysObjectID}'", __FUNCTION__);
338 }
339 $error = commitAddPort ($object_id, 'con0', 29, 'console', '');
340 if ($error == '')
341 $newports++;
342 else
343 $log[] = array ('code' => 'error', 'message' => 'Failed to add console port : ' . $error);
344 if ($newports > 0)
345 $log[] = array ('code' => 'success', 'message' => "Added ${newports} new ports");
346 return $log;
347}
348
349?>