fixup more code style
[racktables] / wwwroot / inc / breed-hpprocurveN1178.php
1 <?php
2
3 # This file is a part of RackTables, a datacenter and server room management
4 # framework. See accompanying file "COPYING" for the full copyright and
5 # licensing information.
6
7 // Functions for HP Procurve switches
8
9 function hpprocurveN1178ReadLLDPStatus ($input)
10 {
11 $ret = array();
12 foreach (explode ("\n", $input) as $line)
13 {
14 $matches = array();
15 switch (TRUE)
16 {
17 case preg_match ('/^ Local Port.+:(.+)$/', $line, $matches):
18 if (trim ($matches[1]) == '')
19 $ret['current']['local_port'] = 'NULL';
20 else
21 $ret['current']['local_port'] = shortenIfName (trim ($matches[1]));
22 break;
23 case preg_match ('/^ PortId.+:(.+)$/', $line, $matches):
24 if (trim ($matches[1]) == '')
25 $ret['current']['remote_port'] = 'NULL';
26 else
27 $ret['current']['remote_port'] = trim ($matches[1]);
28 break;
29 case preg_match ('/^ SysName\s+:(.+)?$/', $line, $matches):
30 if (trim ($matches[1]) == '')
31 $ret['current']['sys_name'] = 'NULL';
32 else
33 $ret['current']['sys_name'] = trim ($matches[1]);
34 break;
35 case preg_match ('/^ PortDescr\s+:(.+)?$/', $line, $matches):
36 if (trim ($matches[1]) == '')
37 {
38 $ret['current']['sys_name'] = 'NULL';
39 break;
40 }
41 $ret['current']['port_descr'] = trim ($matches[1]);
42 if
43 (
44 array_key_exists ('current', $ret) &&
45 array_key_exists ('local_port', $ret['current']) &&
46 array_key_exists ('port_descr', $ret['current']) &&
47 array_key_exists ('sys_name', $ret['current']) &&
48 array_key_exists ('remote_port', $ret['current'])
49 )
50 {
51 $port = NULL;
52 if (preg_match ('/^[a-f0-9]{2} [a-f0-9]{2} [a-f0-9]{2} [a-f0-9]{2} [a-f0-9]{2} [a-f0-9]{2}$/', $ret['current']['remote_port']))
53 $port = $ret['current']['port_descr'];
54 else
55 $port = $ret['current']['remote_port'];
56 if (isset ($port))
57 $ret[$ret['current']['local_port']][] = array
58 (
59 'device' => $ret['current']['sys_name'],
60 'port' => $port,
61 );
62 }
63 unset ($ret['current']);
64 break;
65 default:
66 }
67 }
68 unset ($ret['current']);
69 return $ret;
70 }
71
72 function hpprocurveN1178ReadInterfaceStatus ($text)
73 {
74 $result = array();
75 $state = 'headerSearch';
76 foreach (explode ("\n", $text) as $line)
77 {
78 switch ($state)
79 {
80 case 'headerSearch':
81 if (preg_match ('/\s?Port\s+Type\s+/', $line))
82 {
83 $name_field_borders = getColumnCoordinates ($line, 'Port');
84 if (isset ($name_field_borders['from']))
85 $state = 'readPort';
86 }
87 break;
88 case 'readPort':
89 if (preg_match('/^[0-9]+/', trim (substr ($line, 0, $name_field_borders['length'])), $matches))
90 $portname = $matches[0];
91 if (! isset($portname))
92 $portname = NULL;
93 if (preg_match ('/^[0-9]+.+/', trim (substr ($line, $name_field_borders['from'] + $name_field_borders['length'] + 1)), $matches))
94 $rest = $matches[0];
95 if (! isset($rest))
96 $rest = NULL;
97
98 $field_list = preg_split ('/\s+/', $rest);
99 if (count ($field_list) < 4)
100 break;
101 list ($type, $delim, $alert, $adm_status, $status_raw, $mode) = $field_list;
102 if ($status_raw == 'Up')
103 $status = 'up';
104 elseif ($status_raw == 'Down')
105 $status = 'down';
106 elseif ($adm_status == 'No')
107 $status = 'disabled';
108 if (preg_match ('/([01]+)/', $mode, $matches))
109 $speed = $matches[0];
110 if (preg_match ('/([a-zA-Z]+)/', $mode, $matches))
111 $duplex = $matches[0];
112 $result[$portname] = array
113 (
114 'status' => $status,
115 'speed' => $speed,
116 'duplex' => $duplex,
117 );
118 break;
119 }
120 }
121 return $result;
122 }
123
124 function hpprocurveN1178ReadMacList ($text)
125 {
126 $result = array();
127 $state = 'headerSearch';
128 foreach (explode ("\n", $text) as $line)
129 {
130 switch ($state)
131 {
132 case 'headerSearch':
133 if (preg_match ('/\s?MAC Address\s+Located on Port\s?/', $line))
134 $state = 'readPort_all';
135 elseif (preg_match ('/^\s*Status and Counters -\s*Port Address Table -\s*([0-9]+)$/', $line, $portdata))
136 {
137 $state = 'readPort_single';
138 $portname = $portdata[1];
139 }
140 break;
141 case 'readPort_all':
142 if (! preg_match ('/^\s*([a-f0-9]{6}\-[a-f0-9]{6})\s*(\S+)$/', trim ($line), $matches))
143 break;
144 $portname = shortenIfName ($matches[2]);
145 $vid = NULL;
146 $result[$portname][] = array
147 (
148 'mac' => implode (":", str_split (str_replace ('-', '', $matches[1]), 2)),
149 'vid' => '',
150 );
151 break;
152 case 'readPort_single':
153 if (! preg_match ('/^\s*([a-f0-9]{6}\-[a-f0-9]{6})\s*$/', trim ($line), $matches))
154 break;
155 $vid = NULL;
156 $result[$portname][] = array
157 (
158 'mac' => implode (":", str_split (str_replace ('-', '', $matches[1]), 2)),
159 'vid' => '',
160 );
161 break;
162 }
163 }
164 foreach ($result as $portname => &$maclist)
165 sort ($maclist);
166 return $result;
167 }
168
169 function hpprocurveN1178Read8021QConfig ($input)
170 {
171 $ret = constructRunning8021QConfig();
172 $ret['vlanlist'][] = VLAN_DFL_ID; // HP hides VLAN1 from config text
173 $matches = array();
174 $vlanlist = array();
175 $rawdata = explode ("Status and Counters - VLAN Information - for ports", $input);
176 array_shift ($rawdata);
177
178 foreach ($rawdata as $line)
179 {
180 $port = array
181 (
182 'port_id' => '',
183 'port_name' => '',
184 'vlan_data' => array(),
185 'port_mode' => FALSE,
186 );
187 $port_mode = '';
188 foreach (explode ("\n", $line) as $vlans)
189 {
190 if (preg_match ('/^ VLAN ID Name |^\s*-------/', $vlans))
191 continue;
192 if (preg_match ('/^((?:[0-9]+)|(?:[Tt]rk[0-9]+))$/', trim ($vlans), $matches))
193 {
194 $port['port_id'] = $matches[1];
195 continue;
196 }
197 if (preg_match ('/^\s+Port name: (.+)$/', $vlans, $matches))
198 {
199 $port['port_name'] = $matches[1];
200 continue;
201 }
202 if (preg_match ('/^\S*\s*(\d+)\s+(\S+)\s+\S+\s+\S+\s+([T]agged|[U]ntagged).*$/', $vlans, $matches))
203 {
204 $port['vlan_data'][$matches[1]]['vlan_name'] = $matches[2];
205 $port['vlan_data'][$matches[1]]['vlan_mode'] = $matches[3];
206 $vlanlist[] = $matches[1];
207 }
208 }
209 // Here we add parsed data into $ret array
210 $port_id = $port['port_id'];
211 $port_name = $port['port_name'];
212
213 // Port config
214 $ret['portconfig'][$port_id][] = array ('type' => 'line-header', 'line' => 'interface ' . $port_id);
215 if ($port_name != '')
216 $ret['portconfig'][$port_id][] = array ('type' => 'line-other', 'line' => 'name ' . $port_name);
217
218 // Port data
219 $allowed_vlans = array();
220 if (array_search ('Tagged', array_column ($port['vlan_data'], 'vlan_mode')) === FALSE)
221 {
222 $port_mode = 'access';
223 foreach ($port['vlan_data'] as $vid => $value)
224 {
225 $allowed_vlans[] = $vid;
226 $native = $vid;
227 }
228 }
229 else
230 {
231 $port_mode = 'trunk';
232 foreach ($port['vlan_data'] as $vid => $value)
233 if (preg_match ('/\d+/', $vid))
234 $allowed_vlans[] = $vid;
235 foreach ($port['vlan_data'] as $vid => $value)
236 if (preg_match ('/\d+/', $vid) && $value['vlan_mode'] === "Untagged")
237 {
238 $native = $vid;
239 break;
240 }
241 else
242 $native = 0;
243 }
244 $ret['portdata'][$port_id] = array ('mode' => $port_mode, 'allowed' => $allowed_vlans, 'native' => $native);
245
246 unset ($port);
247 unset ($allowed_vlans);
248 }
249 // Return de-duplicated and sorted list of vlans
250 $ret['vlanlist'] = array_merge ($ret['vlanlist'], array_keys (array_flip ($vlanlist)));
251 sort ($ret['vlanlist']);
252 unset ($vlanlist);
253 unset ($matches);
254 unset ($rawdata);
255 return $ret;
256 }
257
258 function hpprocurveN1178TranslatePushQueue ($dummy_object_id, $queue, $dummy_vlan_names)
259 {
260 $ret = '';
261 $rem_allowed_data = array();
262 $rem_tagged_data = array();
263 $unset_access_data = array();
264
265 foreach ($queue as $cmd)
266 switch ($cmd['opcode'])
267 {
268 case 'create VLAN':
269 $ret .= "vlan ${cmd['arg1']}\nexit\n";
270 break;
271 case 'destroy VLAN':
272 $ret .= "no vlan ${cmd['arg1']}\n";
273 break;
274 case 'add allowed':
275 foreach ($cmd['vlans'] as $vlan_id)
276 $ret .= "vlan ${vlan_id} tagged ${cmd['port']}\n";
277 ///////////////////////////////////////////////////////////////////////////////////////
278 // Here is a workaround: remove untagged port for case access->trunk(non-native)
279 if
280 (
281 array_key_exists ('port_id', $unset_access_data) &&
282 array_key_exists ('vlan_id', $unset_access_data) &&
283 $unset_access_data['port_id'] === $cmd['port']
284 )
285 {
286 $ret .= "no vlan ${unset_access_data['vlan_id']} untagged ${unset_access_data['port_id']}\n";
287 unset ($unset_access_data);
288 }
289 ///////////////////////////////////////////////////////////////////////////////////////
290 // Here is a workaround: remove port tagged from vlans again for case trunk(non-native)->trunk(non-native)
291 if ($rem_tagged_data)
292 foreach ($rem_tagged_data as $port_id => $vlan_list)
293 if (! empty ($port_id) && $port_id === $cmd['port'])
294 foreach ($vlan_list as $key => $vlan_id)
295 if (isset ($vlan_id))
296 $ret .= "no vlan ${vlan_id} tagged ${port_id}\n";
297 $rem_tagged_data = array();
298 break;
299 case 'rem allowed':
300 foreach ($cmd['vlans'] as $vlan_id)
301 {
302 $ret .= "no vlan ${vlan_id} tagged ${cmd['port']}\n";
303 ///////////////////////////////////////////////////////////////////////////////////////
304 // Here is a workaround: we should remove untagged port before
305 // add it as tagged for case access->trunk(non-native)
306 // HP L2 switches doesn't allow "orphaned" ports (without tags)
307 $rem_allowed_data[$cmd['port']][] = $vlan_id;
308 $rem_tagged_data[$cmd['port']][] = $vlan_id;
309 }
310 break;
311 case 'set access':
312 $ret .= "vlan ${cmd['arg2']} untagged ${cmd['arg1']}\n";
313 ///////////////////////////////////////////////////////////////////////////////////////
314 // Now remove tagged port for case trunk(non-native)->access
315 //file_put_contents ('/var/log/racktables.log', var_export($rem_allowed_data, true), FILE_APPEND | LOCK_EX);
316 foreach ($rem_allowed_data as $port_id => $vlan_list)
317 if (! empty ($port_id) && $port_id === $cmd['arg1'] )
318 foreach ($vlan_list as $key => $vlan_id)
319 if (isset ($vlan_id))
320 $ret .= "no vlan ${vlan_id} tagged ${cmd['arg1']}\n";
321 $rem_allowed_data = array();
322 break;
323 case 'unset access':
324 ///////////////////////////////////////////////////////////////////////////////////////
325 // Here is a workaround: we should remove untagged port before we
326 // add it as tagged, for case access->trunk(non-native)
327 // HP L2 switches doesn't allow "orphaned" ports (without tags)
328 $unset_access_data['port_id'] = $cmd['arg1'];
329 $unset_access_data['vlan_id'] = $cmd['arg2'];
330 $ret .= "no vlan ${cmd['arg2']} untagged ${cmd['arg1']}\n";
331 break;
332 case 'set native':
333 $ret .= "vlan ${cmd['arg2']} untagged ${cmd['arg1']}\n";
334 ///////////////////////////////////////////////////////////////////////////////////////
335 // Here is a workaround: we should add tagged port again for case
336 // when we remove native but keep it as tagged
337 $ret .= "no vlan ${cmd['arg2']} tagged ${cmd['arg1']}\n";
338 break;
339 case 'unset native': // NOP
340 $ret .= "no vlan ${cmd['arg2']} untagged ${cmd['arg1']}\n";
341 $ret .= "vlan ${cmd['arg2']} tagged ${cmd['arg1']}\n";
342 break;
343 case 'set mode': // NOP
344 break;
345 case 'begin configuration':
346 $ret .= "configure\n";
347 break;
348 case 'end configuration':
349 $ret .= "end\n";
350 break;
351 case 'save configuration':
352 $ret .= "write memory\n";
353 break;
354 case 'cite':
355 $ret .= $cmd['arg1'];
356 break;
357 // query list
358 case 'get8021q':
359 $ret .= "show vlans ports ethernet all detail\n";
360 break;
361 case 'getlldpstatus':
362 $ret .= "show lldp info remote-device all\n";
363 break;
364 case 'getallconf':
365 $ret .= "show running-config\n";
366 break;
367 case 'getportstatus':
368 $ret .= "show int brief\n";
369 break;
370 case 'getmaclist':
371 $ret .= "show mac-address\n";
372 break;
373 case 'getportmaclist':
374 $ret .= "show mac-address ethernet {$cmd['arg1']}\n";
375 break;
376 default:
377 throw new InvalidArgException ('opcode', $cmd['opcode']);
378 }
379 return $ret;
380 }
381
382 function hpprocurveN1178SpotConfigText ($input)
383 {
384 return $input;
385 }