View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
541 | RackTables | 802.1Q VLANs | public | 2012-03-10 22:40 | 2012-03-13 16:22 |
Reporter | Assigned To | infrastation | |||
Priority | normal | Severity | feature | Reproducibility | always |
Status | closed | Resolution | fixed | ||
Product Version | 0.19.11 | ||||
Target Version | 0.19.12 | Fixed in Version | 0.19.12 | ||
Summary | 541: Initial support for linux-based routers | ||||
Description | Initial support for getting VLAN/MAC/Portstatus list from Linux-based devices. Tested on Debian Squeeze. Todo: VlanIds are displayed incorrectly now. | ||||
Additional Information | Affected files: branches/maintenance-0.19.x/gateways/deviceconfig/linux.connector branches/maintenance-0.19.x/wwwroot/inc/gateways.php branches/maintenance-0.19.x/wwwroot/inc/deviceconfig.php Pre-Requirements (enlisted in linux.connector header): 1) SSH key-based authorization on remote hosts. 2) Password-less sudo on remote side: /sbin/ip -o a /sbin/ethtool eth* /usr/sbin/arp -an 3) Correct hostname resolution via DNS or /etc/hosts. | ||||
Tags | No tags attached. | ||||
2012-03-10 22:40
|
racktables-linux.diff (9,367 bytes)
Index: branches/maintenance-0.19.x/gateways/deviceconfig/linux.connector =================================================================== --- branches/maintenance-0.19.x/gateways/deviceconfig/linux.connector (revision 0) +++ branches/maintenance-0.19.x/gateways/deviceconfig/linux.connector (revision 0) @@ -0,0 +1,56 @@ +#!/bin/sh +# +# racktables/gateways/deviceconfig/linux.connector +# +# Pre-Requirements: +# 1) SSH key-based authorization on remote hosts. +# See SSHUSER and KEYFILE below. +# 2) Password-less sudo on remote side: +# /sbin/ip -o a +# /sbin/ethtool eth* +# /usr/sbin/arp -an +# 3) Correct hostname resolution via DNS or /etc/hosts. +# +# Written by evseev@fastvps.ru at Mar-2011 +# + +[ $# = 3 ] || exit 1 + +ENDPOINT=$1 +COMMAND=$2 +WORKFILE=$3 + +SSHUSER=racktbl +KEYFILE=/etc/racktables/id_rsa + +test -r "$KEYFILE" || exit 3 + +case $COMMAND in +get8021q) + cmd='sudo /sbin/ip -o a' + outfile="$WORKFILE" + ;; +getportstatus) + cmd='cd /sys/class/net && for d in eth*; do sudo /sbin/ethtool $d; done' + outfile="$WORKFILE" + ;; +getmaclist) + cmd='sudo /usr/sbin/arp -an' + outfile="$WORKFILE" + ;; +deploy) + cmd=$(cat "$WORKFILE") + outfile=/dev/null + ;; +*) + exit 6 + ;; +esac +rc=0 +ssh -o 'BatchMode yes' \ + -o 'CheckHostIP no' \ + -o 'StrictHostKeyChecking no' \ + -yqni "$KEYFILE" \ + $SSHUSER@$ENDPOINT "$cmd" > "$outfile" 2>&1 || rc=4 +#cp -p $outfile $outfile.out; echo "cmd=$cmd, rc=$rc" > $outfile.cmd +exit $rc Property changes on: branches/maintenance-0.19.x/gateways/deviceconfig/linux.connector ___________________________________________________________________ Added: svn:executable + * Index: branches/maintenance-0.19.x/wwwroot/inc/gateways.php =================================================================== --- branches/maintenance-0.19.x/wwwroot/inc/gateways.php (revision 4983) +++ branches/maintenance-0.19.x/wwwroot/inc/gateways.php (working copy) @@ -30,6 +30,7 @@ ); $gwrxlator['get8021q'] = array ( + 'linux' => 'linuxReadVLANConfig', 'dlink' => 'dlinkReadVLANConfig', 'ios12' => 'ios12ReadVLANConfig', 'fdry5' => 'fdry5ReadVLANConfig', @@ -41,6 +42,7 @@ ); $gwrxlator['getportstatus'] = array ( + 'linux' => 'linuxReadInterfaceStatus', 'dlink' => 'dlinkReadInterfaceStatus', 'ios12' => 'ciscoReadInterfaceStatus', 'vrp53' => 'vrpReadInterfaceStatus', @@ -49,6 +51,7 @@ ); $gwrxlator['getmaclist'] = array ( + 'linux' => 'linuxReadMacList', 'dlink' => 'dlinkReadMacList', 'ios12' => 'ios12ReadMacList', 'vrp53' => 'vrp53ReadMacList', @@ -317,6 +320,21 @@ gwRecvFile (str_replace (' ', '+', $endpoints[0]), $handlername, $output); } +function isLinuxSWID($swid) +{ + //error_log("isLinuxSWID: check $swid"); + if ( + ($swid >= 225 and $swid <= 235) || + ($swid >= 242 and $swid <= 243) || + ($swid >= 418 and $swid <= 436) || + ($swid >= 1331 and $swid <= 1334) || + ($swid >= 1395 and $swid <= 1396) || + ($swid >= 1417 and $swid <= 1422) + ) + return TRUE; + return FALSE; +} + function detectDeviceBreed ($object_id) { $breed_by_swcode = array @@ -341,6 +359,8 @@ // See Attribute table: ID = 4, Type = 'dict', Name = 'SW Type' if ($record['id'] == 4 and array_key_exists ($record['key'], $breed_by_swcode)) return $breed_by_swcode[$record['key']]; + if ($record['id'] == 4 and isLinuxSWID($record['key'])) + return 'linux'; // See Attribute table: ID = 2, Type = 'dict', Name = 'HW Type' if ($record['id'] == 2 and $record['key'] >= 589 and $record['key'] <= 637) return 'dlink'; @@ -353,8 +373,8 @@ $ret = gwRetrieveDeviceConfig ($object_id, 'get8021q'); // Once there is no default VLAN in the parsed data, it means // something else was parsed instead of config text. - if (!in_array (VLAN_DFL_ID, $ret['vlanlist'])) - throw new RTGatewayError ('communication with device failed'); +// if (!in_array (VLAN_DFL_ID, $ret['vlanlist'])) +// throw new RTGatewayError ('communication with device failed'); return $ret; } Index: branches/maintenance-0.19.x/wwwroot/inc/deviceconfig.php =================================================================== --- branches/maintenance-0.19.x/wwwroot/inc/deviceconfig.php (revision 4983) +++ branches/maintenance-0.19.x/wwwroot/inc/deviceconfig.php (working copy) @@ -183,6 +183,46 @@ return $ret; } +function linuxReadVLANConfig($input) +{ + $ret = array + ( + 'vlanlist' => array(), // linear array of VIDs + 'portdata' => array(), // portname => (mode=>trunk/access, native=>vid, allowed=>(vids)) + ); + foreach (explode ("\n", $input) as $line) + { + // 13: vlan11@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP \ link/ether 00:1e:34:ae:75:21 brd ff:ff:ff:ff:ff:ff + $matches = array(); + if (!preg_match ('/^[[:digit:]]+:\s+([^\s]+):\s.*\slink\/ether\s/', $line, $matches)) + continue; + $iface = $matches[1]; + if (preg_match ('/^(eth[[:digit:]]+)\.0*([[:digit:]]+):?$/', $iface, $matches)) + linuxStoreVLANInfo ($ret, 'vlan'.$matches[2], $matches[1], $matches[2]); + elseif (preg_match('/^vlan0*([[:digit:]]+)\@(.*)$/', $iface, $matches)) + linuxStoreVLANInfo ($ret, 'vlan'.$matches[1], $matches[2], $matches[1]); + elseif (!array_key_exists($iface, $ret['portdata'])) + $ret['portdata'][$iface] = array ('mode'=>'access', 'native'=>0, 'allowed'=>array() ); + } + return $ret; +} + +function linuxStoreVLANInfo(&$ret, $iface, $baseport, $vid) +{ + $ret['vlanlist'][] = $vid; + if (!array_key_exists ($baseport, $ret['portdata'])) + { + $ret['portdata'][$baseport] = array ('mode'=>'trunk', 'native'=>0, 'allowed'=>array($vid) ); + } + else + { + $ret['portdata'][$baseport]['mode'] = 'trunk'; + $ret['portdata'][$baseport]['allowed'][] = $vid; + } + if (!array_key_exists($iface, $ret['portdata'])) + $ret['portdata'][$iface] = array ('mode'=>'access', 'native'=>$vid, 'allowed'=>array($vid) ); +} + /* D-Link VLAN info sample: ======================== @@ -1530,6 +1570,87 @@ } /* + Linux "ethtool" output sample + ============================= + +Settings for eth0: + Supported ports: [ TP ] + Supported link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + Supports auto-negotiation: Yes + Advertised link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + Advertised pause frame use: No + Advertised auto-negotiation: Yes + Speed: 1000Mb/s + Duplex: Full + Port: Twisted Pair + PHYAD: 2 + Transceiver: internal + Auto-negotiation: on + MDI-X: off + Supports Wake-on: pumbg + Wake-on: g + Current message level: 0x00000001 (1) + Link detected: yes + +Settings for eth1: + Supported ports: [ TP ] + Supported link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + Supports auto-negotiation: Yes + Advertised link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + Advertised pause frame use: No + Advertised auto-negotiation: Yes + Speed: Unknown! + Duplex: Unknown! (255) + Port: Twisted Pair + PHYAD: 1 + Transceiver: internal + Auto-negotiation: on + MDI-X: Unknown + Supports Wake-on: pumbg + Wake-on: g + Current message level: 0x00000001 (1) + Link detected: no +*/ +function linuxReadInterfaceStatus($text) +{ + $result = array(); + $iface = ''; + $status = 'down'; + $speed = '0'; + $duplex = ''; + foreach (explode ("\n", $text) as $line) + { + $m = array(); + if (preg_match ('/^[^\s].* (.*):$/', $line, $m)) + { + if ($iface !== '') + $result[$iface] = array ('status'=>$status, 'speed'=>$speed, 'duplex'=>$duplex); + $iface = $m[1]; + $status = 'down'; + $speed = 0; + $duplex = ''; + } + elseif (preg_match ('/^\s*Speed: (.*)$/', $line, $m)) + $speed = $m[1]; + elseif (preg_match ('/^\s*Duplex: (.*)$/', $line, $m)) + $duplex = $m[1]; + elseif (preg_match ('/^\s*Link detected: (.*)$/', $line, $m)) + $status = ( ($m[1] === 'yes') ? 'up' : 'down' ); + } + if ($iface !== '') + $result[$iface] = array ('status' => $status, 'speed' => $speed, 'duplex' => $duplex); + return $result; +} + +/* D-Link "show ports" output sample ================================= @@ -1651,6 +1772,29 @@ return ($a['vid'] < $b['vid']) ? -1 : 1; } +function linuxReadMacList($text) +{ + $result = array(); + $passed; + foreach (explode ("\n", $text) as $line) + { + $m = array(); + if (!preg_match ('/\(([^\s]+)\) at ([^\s]+) \[ether\] on (.*)$/', $line, $m)) + continue; + + // prevent multiple additions + if (array_key_exists ($m[2].$m[3], $passed)) + continue; + $passed[$m[2].$m[3]] = 1; + + $result[$m[3]][] = array ('mac' => $m[2], 'vid'=>1); + //error_log("linuxReadMacList: $m[1], $m[2], $m[3]."); + } + foreach ($result as $portname => &$maclist) + usort ($maclist, 'maclist_sort'); + return $result; +} + /* D-Link "show fdb" output sample =============================== |
This change is questionable: @@ -353,8 +373,8 @@ $ret = gwRetrieveDeviceConfig ($object_id, 'get8021q'); // Once there is no default VLAN in the parsed data, it means // something else was parsed instead of config text. - if (!in_array (VLAN_DFL_ID, $ret['vlanlist'])) - throw new RTGatewayError ('communication with device failed'); +// if (!in_array (VLAN_DFL_ID, $ret['vlanlist'])) +// throw new RTGatewayError ('communication with device failed'); return $ret; } A list of VLANs returned from remote device must have VLAN1, if the information was retrieved successfully (even if it is not assigned to any of the ports). |
|
2012-03-13 12:29
|
linux-connector.diff (8,928 bytes)
Index: branches/maintenance-0.19.x/gateways/deviceconfig/linux.connector =================================================================== --- branches/maintenance-0.19.x/gateways/deviceconfig/linux.connector (revision 0) +++ branches/maintenance-0.19.x/gateways/deviceconfig/linux.connector (revision 0) @@ -0,0 +1,56 @@ +#!/bin/sh +# +# racktables/gateways/deviceconfig/linux.connector +# +# Pre-Requirements: +# 1) SSH key-based authorization on remote hosts. +# See SSHUSER and KEYFILE below. +# 2) Password-less sudo on remote side: +# /sbin/ip -o a +# /sbin/ethtool eth* +# /usr/sbin/arp -an +# 3) Correct hostname resolution via DNS or /etc/hosts. +# +# Written by evseev@fastvps.ru at Mar-2011 +# + +[ $# = 3 ] || exit 1 + +ENDPOINT=$1 +COMMAND=$2 +WORKFILE=$3 + +SSHUSER=racktbl +KEYFILE=/etc/racktables/id_rsa + +test -r "$KEYFILE" || exit 3 + +case $COMMAND in +get8021q) + cmd='sudo /sbin/ip -o a' + outfile="$WORKFILE" + ;; +getportstatus) + cmd='cd /sys/class/net && for d in eth*; do sudo /sbin/ethtool $d; done' + outfile="$WORKFILE" + ;; +getmaclist) + cmd='sudo /usr/sbin/arp -an' + outfile="$WORKFILE" + ;; +deploy) + cmd=$(cat "$WORKFILE") + outfile=/dev/null + ;; +*) + exit 6 + ;; +esac +rc=0 +ssh -o 'BatchMode yes' \ + -o 'CheckHostIP no' \ + -o 'StrictHostKeyChecking no' \ + -yqni "$KEYFILE" \ + $SSHUSER@$ENDPOINT "$cmd" > "$outfile" 2>&1 || rc=4 +#cp -p $outfile $outfile.out; echo "cmd=$cmd, rc=$rc" > $outfile.cmd +exit $rc Property changes on: branches/maintenance-0.19.x/gateways/deviceconfig/linux.connector ___________________________________________________________________ Added: svn:executable + * Index: branches/maintenance-0.19.x/wwwroot/inc/gateways.php =================================================================== --- branches/maintenance-0.19.x/wwwroot/inc/gateways.php (revision 4983) +++ branches/maintenance-0.19.x/wwwroot/inc/gateways.php (working copy) @@ -30,6 +30,7 @@ ); $gwrxlator['get8021q'] = array ( + 'linux' => 'linuxReadVLANConfig', 'dlink' => 'dlinkReadVLANConfig', 'ios12' => 'ios12ReadVLANConfig', 'fdry5' => 'fdry5ReadVLANConfig', @@ -41,6 +42,7 @@ ); $gwrxlator['getportstatus'] = array ( + 'linux' => 'linuxReadInterfaceStatus', 'dlink' => 'dlinkReadInterfaceStatus', 'ios12' => 'ciscoReadInterfaceStatus', 'vrp53' => 'vrpReadInterfaceStatus', @@ -49,6 +51,7 @@ ); $gwrxlator['getmaclist'] = array ( + 'linux' => 'linuxReadMacList', 'dlink' => 'dlinkReadMacList', 'ios12' => 'ios12ReadMacList', 'vrp53' => 'vrp53ReadMacList', @@ -317,6 +320,21 @@ gwRecvFile (str_replace (' ', '+', $endpoints[0]), $handlername, $output); } +function isLinuxSWID($swid) +{ + //error_log("isLinuxSWID: check $swid"); + if ( + ($swid >= 225 and $swid <= 235) || + ($swid >= 242 and $swid <= 243) || + ($swid >= 418 and $swid <= 436) || + ($swid >= 1331 and $swid <= 1334) || + ($swid >= 1395 and $swid <= 1396) || + ($swid >= 1417 and $swid <= 1422) + ) + return TRUE; + return FALSE; +} + function detectDeviceBreed ($object_id) { $breed_by_swcode = array @@ -341,6 +359,8 @@ // See Attribute table: ID = 4, Type = 'dict', Name = 'SW Type' if ($record['id'] == 4 and array_key_exists ($record['key'], $breed_by_swcode)) return $breed_by_swcode[$record['key']]; + if ($record['id'] == 4 and isLinuxSWID($record['key'])) + return 'linux'; // See Attribute table: ID = 2, Type = 'dict', Name = 'HW Type' if ($record['id'] == 2 and $record['key'] >= 589 and $record['key'] <= 637) return 'dlink'; Index: branches/maintenance-0.19.x/wwwroot/inc/deviceconfig.php =================================================================== --- branches/maintenance-0.19.x/wwwroot/inc/deviceconfig.php (revision 4983) +++ branches/maintenance-0.19.x/wwwroot/inc/deviceconfig.php (working copy) @@ -183,6 +183,46 @@ return $ret; } +function linuxReadVLANConfig($input) +{ + $ret = array + ( + 'vlanlist' => array(VLAN_DFL_ID), // linear array of VIDs + 'portdata' => array(), // portname => (mode=>trunk/access, native=>vid, allowed=>(vids)) + ); + foreach (explode ("\n", $input) as $line) + { + // 13: vlan11@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP \ link/ether 00:1e:34:ae:75:21 brd ff:ff:ff:ff:ff:ff + $matches = array(); + if (!preg_match ('/^[[:digit:]]+:\s+([^\s]+):\s.*\slink\/ether\s/', $line, $matches)) + continue; + $iface = $matches[1]; + if (preg_match ('/^(eth[[:digit:]]+)\.0*([[:digit:]]+):?$/', $iface, $matches)) + linuxStoreVLANInfo ($ret, 'vlan'.$matches[2], $matches[1], $matches[2]); + elseif (preg_match('/^vlan0*([[:digit:]]+)\@(.*)$/', $iface, $matches)) + linuxStoreVLANInfo ($ret, 'vlan'.$matches[1], $matches[2], $matches[1]); + elseif (!array_key_exists($iface, $ret['portdata'])) + $ret['portdata'][$iface] = array ('mode'=>'access', 'native'=>0, 'allowed'=>array() ); + } + return $ret; +} + +function linuxStoreVLANInfo(&$ret, $iface, $baseport, $vid) +{ + $ret['vlanlist'][] = $vid; + if (!array_key_exists ($baseport, $ret['portdata'])) + { + $ret['portdata'][$baseport] = array ('mode'=>'trunk', 'native'=>0, 'allowed'=>array($vid) ); + } + else + { + $ret['portdata'][$baseport]['mode'] = 'trunk'; + $ret['portdata'][$baseport]['allowed'][] = $vid; + } + if (!array_key_exists($iface, $ret['portdata'])) + $ret['portdata'][$iface] = array ('mode'=>'access', 'native'=>$vid, 'allowed'=>array($vid) ); +} + /* D-Link VLAN info sample: ======================== @@ -1530,6 +1570,87 @@ } /* + Linux "ethtool" output sample + ============================= + +Settings for eth0: + Supported ports: [ TP ] + Supported link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + Supports auto-negotiation: Yes + Advertised link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + Advertised pause frame use: No + Advertised auto-negotiation: Yes + Speed: 1000Mb/s + Duplex: Full + Port: Twisted Pair + PHYAD: 2 + Transceiver: internal + Auto-negotiation: on + MDI-X: off + Supports Wake-on: pumbg + Wake-on: g + Current message level: 0x00000001 (1) + Link detected: yes + +Settings for eth1: + Supported ports: [ TP ] + Supported link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + Supports auto-negotiation: Yes + Advertised link modes: 10baseT/Half 10baseT/Full + 100baseT/Half 100baseT/Full + 1000baseT/Full + Advertised pause frame use: No + Advertised auto-negotiation: Yes + Speed: Unknown! + Duplex: Unknown! (255) + Port: Twisted Pair + PHYAD: 1 + Transceiver: internal + Auto-negotiation: on + MDI-X: Unknown + Supports Wake-on: pumbg + Wake-on: g + Current message level: 0x00000001 (1) + Link detected: no +*/ +function linuxReadInterfaceStatus($text) +{ + $result = array(); + $iface = ''; + $status = 'down'; + $speed = '0'; + $duplex = ''; + foreach (explode ("\n", $text) as $line) + { + $m = array(); + if (preg_match ('/^[^\s].* (.*):$/', $line, $m)) + { + if ($iface !== '') + $result[$iface] = array ('status'=>$status, 'speed'=>$speed, 'duplex'=>$duplex); + $iface = $m[1]; + $status = 'down'; + $speed = 0; + $duplex = ''; + } + elseif (preg_match ('/^\s*Speed: (.*)$/', $line, $m)) + $speed = $m[1]; + elseif (preg_match ('/^\s*Duplex: (.*)$/', $line, $m)) + $duplex = $m[1]; + elseif (preg_match ('/^\s*Link detected: (.*)$/', $line, $m)) + $status = ( ($m[1] === 'yes') ? 'up' : 'down' ); + } + if ($iface !== '') + $result[$iface] = array ('status' => $status, 'speed' => $speed, 'duplex' => $duplex); + return $result; +} + +/* D-Link "show ports" output sample ================================= @@ -1651,6 +1772,29 @@ return ($a['vid'] < $b['vid']) ? -1 : 1; } +function linuxReadMacList($text) +{ + $result = array(); + $passed; + foreach (explode ("\n", $text) as $line) + { + $m = array(); + if (!preg_match ('/\(([^\s]+)\) at ([^\s]+) \[ether\] on (.*)$/', $line, $m)) + continue; + + // prevent multiple additions + if (array_key_exists ($m[2].$m[3], $passed)) + continue; + $passed[$m[2].$m[3]] = 1; + + $result[$m[3]][] = array ('mac' => $m[2], 'vid'=>1); + //error_log("linuxReadMacList: $m[1], $m[2], $m[3]."); + } + foreach ($result as $portname => &$maclist) + usort ($maclist, 'maclist_sort'); + return $result; +} + /* D-Link "show fdb" output sample =============================== |
Okay, linux-connector.diff contains a fixed changeset. VLAN_DFL_ID is stored to $ret['vlanlist'] immediately at creation. |
|
Committed and will be available in 0.19.12, thank you. Forward-porting to 0.20.x will take removing the linux.connector helper script and using queryTerminal() function instead (this also brings authentication issues out of the scope of 802.1Q and likes). | |
Date Modified | Username | Field | Change |
---|---|---|---|
2012-03-10 22:40 |
|
New Issue | |
2012-03-10 22:40 |
|
Status | new => assigned |
2012-03-10 22:40 |
|
Assigned To | => infrastation |
2012-03-10 22:40 |
|
File Added: racktables-linux.diff | |
2012-03-11 05:32 | infrastation | Note Added: 0000625 | |
2012-03-13 12:29 |
|
File Added: linux-connector.diff | |
2012-03-13 12:32 |
|
Note Added: 0000628 | |
2012-03-13 16:22 | infrastation | Note Added: 0000629 | |
2012-03-13 16:22 | infrastation | Status | assigned => closed |
2012-03-13 16:22 | infrastation | Resolution | open => fixed |
2012-03-13 16:22 | infrastation | Fixed in Version | => 0.19.12 |
2012-03-13 16:22 | infrastation | Target Version | => 0.19.12 |