0.18.4
bugfix: a race condition could be triggered in permissions editor
+ new feature: "any mode" of user port in VLAN switch template
0.18.3 2010-06-15
bugfix: fix mktemp not working on Slackware (by Rafael Ganascim)
bugfix: Nexus 802.1Q fixes
--- /dev/null
+#!/bin/sh
+
+[ $# = 3 ] || exit 1
+
+ENDPOINT=$1
+COMMAND=$2
+WORKFILE=$3
+
+prepare_connect_commands()
+{
+ [ $# = 1 ] || exit 2
+ local skip=yes cval found=no MYDIR=`dirname $0`
+ while read line; do
+ if [ "$skip" = "yes" -a "$line" = "# S-T-A-R-T" ]; then
+ skip=no
+ continue
+ fi
+ if [ "$skip" = "no" -a "$line" = "# S-T-O-P" ]; then
+ skip=yes
+ continue
+ fi
+ [ "$skip" = "yes" ] && continue
+ # ignore comments
+ [ -z "${line###*}" ] && continue
+
+ # First endpoint string/regexp match is sufficient for us.
+ cval=`echo $line | cut -s -d' ' -f1`
+ if [ -z "${1##$cval}" ]; then
+ found=yes
+ username=`echo $line | cut -s -d' ' -f5`
+ [ "$username" != "-" ] && echo $username > "$SESSION"
+ # access password
+ access_password=`echo $line | cut -s -d' ' -f6`
+ [ "$access_password" != "-" ] && echo "$access_password" >> "$SESSION"
+ printf "super\n" >> "$SESSION"
+ enable_password=`echo $line | cut -s -d' ' -f7`
+ [ "$enable_password" != "-" ] && echo $enable_password >> "$SESSION"
+ break
+ fi
+ done < "$MYDIR/switch.secrets.php"
+ [ "$found" = "yes" ] && return
+ exit 3
+}
+
+MYNAME=`basename $0`
+SESSION=`mktemp /tmp/$MYNAME.XXXXXX`
+[ -f "$SESSION" ] || exit 5
+prepare_connect_commands $ENDPOINT
+case $COMMAND in
+get8021q)
+ printf 'display current-configuration\n' >> "$SESSION"
+ outfile="$WORKFILE"
+ ;;
+getlldpstatus)
+ printf 'display lldp neighbor\n' >> "$SESSION"
+ outfile="$WORKFILE"
+ ;;
+gethndp)
+ printf 'display ndp\n' >> "$SESSION"
+ outfile="$WORKFILE"
+ ;;
+deploy)
+ cat "$WORKFILE" >> "$SESSION"
+ outfile=/dev/null
+ ;;
+*)
+ rm -f "$SESSION"
+ exit 6
+ ;;
+esac
+printf 'quit\n' >> "$SESSION"
+rc=0
+# VRP 5.50 telnet server is broken, hence -i
+nc -w 30 -i1 $ENDPOINT 23 < "$SESSION" > "$outfile" || rc=4
+rm -f "$SESSION"
+exit $rc
'0.18.1' => 1352,
'0.18.2' => 1352,
'0.18.3' => 1356,
- '0.18.4' => 1361,
+ '0.18.4' => 1364,
);
define ('TAGNAME_REGEXP', '/^[\p{L}0-9]([. _~-]?[\p{L}0-9])*$/u');
function convertPDOException ($e)
{
- if ($e->getCode() != 23000)
- return $e;
- switch ($e->errorInfo[1])
+ switch ($e->getCode() . '-' . $e->errorInfo[1])
{
- case 1062:
+ case '23000-1062':
+ $text = 'such record already exists';
+ break;
+ case '23000-1205':
$text = 'such record already exists';
break;
- case 1451:
- case 1452:
+ case '23000-1451':
+ case '23000-1452':
$text = 'foreign key violation';
break;
- default:
- $text = 'unknown error code ' . $e->errorInfo[1];
+ case 'HY000-1205':
+ $text = 'lock wait timeout';
break;
+ default:
+ return $e;
}
- return new RTDBConstraintError ($text);
+ return new RTDatabaseError ($text);
}
// This is a swiss-knife blade to insert a record into a table.
{
global $dbxlink;
$query = "INSERT INTO ${tablename} (" . implode (', ', array_keys ($columns));
- $query .= ') VALUES (' . implode (', ', array_fill (0, count ($columns), '?')) . ')';
+ $query .= ') VALUES (' . questionMarks (count ($columns)) . ')';
// Now the query should be as follows:
// INSERT INTO table (c1, c2, c3) VALUES (?, ?, ?)
try
{
global $dbxlink;
$prepared = $dbxlink->prepare ($query);
- if (!$prepared->execute ($args))
- return FALSE;
- return $prepared;
+ try
+ {
+ if (!$prepared->execute ($args))
+ return FALSE;
+ return $prepared;
+ }
+ catch (PDOException $e)
+ {
+ throw convertPDOException ($e);
+ }
}
// Prepare and execute the statement with parameters, then return number of
);
if (FALSE === usePreparedDeleteBlade ($tablemap_8021q[$instance]['pav'], array ('object_id' => $object_id, 'port_name' => $port_name)))
throw new RackTablesError ('', RackTablesError::DB_WRITE_FAILED);
- // FIXME: The goal is to INSERT as many rows as there are values in 'allowed' list
+ // The goal is to INSERT as many rows as there are values in 'allowed' list
// without wrapping each row with own INSERT (otherwise the SQL connection
// instantly becomes the bottleneck).
- foreach ($port['allowed'] as $vlan_id)
- if (!usePreparedInsertBlade ($tablemap_8021q[$instance]['pav'], array ('object_id' => $object_id, 'port_name' => $port_name, 'vlan_id' => $vlan_id)))
- throw new RackTablesError ('', RackTablesError::DB_WRITE_FAILED);
+ foreach (listToRanges ($port['allowed']) as $range)
+ usePreparedExecuteBlade
+ (
+ 'INSERT INTO ' . $tablemap_8021q[$instance]['pav'] . ' (object_id, port_name, vlan_id) ' .
+ 'SELECT ?, ?, vlan_id FROM VLANValidID WHERE vlan_id BETWEEN ? AND ?',
+ array ($object_id, $port_name, $range['from'], $range['to'])
+ );
if
(
$port['native'] and
1359 => array ('chapter_id' => 12, 'dict_value' => 'Huawei%GPASS%Quidway S9312'),
1360 => array ('chapter_id' => 14, 'dict_value' => 'Huawei VRP 5.3'),
1361 => array ('chapter_id' => 14, 'dict_value' => 'Huawei VRP 5.5'),
+ 1362 => array ('chapter_id' => 12, 'dict_value' => '[[Brocade%GPASS%FCX 648 | http://www.brocade.com/sites/dotcom/products-solutions/products/ethernet-switches-routers/enterprise-mobility/product-details/fcx-series-data-center/index.page ]]'),
+ 1363 => array ('chapter_id' => 14, 'dict_value' => 'IronWare 5'),
+ 1364 => array ('chapter_id' => 14, 'dict_value' => 'IronWare 7'),
);
?>
// this wraps certain known PDO errors and is caught in process.php
// as a "soft" error
-class RTDBConstraintError extends RackTablesError
+class RTDatabaseError extends RackTablesError
{
public function dispatch()
{
- RackTablesError::genHTMLPage ('Database constraint violation', '<h2>Constraint violation</h2><br>' . $this->message);
+ RackTablesError::genHTMLPage ('Database soft error', '<h2>Database soft error</h2><br>' . $this->message);
}
}
case 'trunk': // 2-4094
case 'uplink':
case 'downlink':
+ case 'anymode':
$min = VLAN_MIN_ID + 1;
$max = VLAN_MAX_ID;
break;
// pack set of integers into list of integer ranges
// e.g. (1, 2, 3, 5, 6, 7, 9, 11) => ((1, 3), (5, 7), (9, 9), (11, 11))
-function listToRanges ($vlanidlist)
+// The second argument, when it is different from 0, limits amount of
+// items in each generated range.
+function listToRanges ($vlanidlist, $limit = 0)
{
sort ($vlanidlist);
$ret = array();
$from = $to = NULL;
foreach ($vlanidlist as $vlan_id)
if ($from == NULL)
- $from = $to = $vlan_id;
+ {
+ if ($limit == 1)
+ $ret[] = array ('from' => $vlan_id, 'to' => $vlan_id);
+ else
+ $from = $to = $vlan_id;
+ }
elseif ($to + 1 == $vlan_id)
+ {
$to = $vlan_id;
+ if ($to - $from + 1 == $limit)
+ {
+ // cut accumulated range and start over
+ $ret[] = array ('from' => $from, 'to' => $to);
+ $from = $to = NULL;
+ }
+ }
else
{
$ret[] = array ('from' => $from, 'to' => $to);
$ret = array();
foreach ($changes as $port_name => $port)
{
+ // VST violation ?
+ if (!goodModeForVSTRole ($port['mode'], $port['vst_role']))
+ continue; // ignore change request
// find and cancel any changes regarding immune VLANs
- switch ($port['vst_role'])
+ switch ($port['mode'])
{
case 'access':
- if ($port['mode'] != 'access') // VST violation
- continue 2; // ignore change request
foreach ($domain_immune_vlans as $immune)
// Reverting an attempt to set an access port from
// "normal" VLAN to immune one (or vice versa) requires
}
break;
case 'trunk':
- case 'uplink':
- case 'downlink':
- if ($port['mode'] != 'trunk')
- continue 2;
foreach ($domain_immune_vlans as $immune)
if (in_array ($immune, $before[$port_name]['allowed'])) // was allowed before
{
}
break;
default:
- continue 2;
+ throw new InvalidArgException ('mode', $port['mode']);
}
// save work
$ret[$port_name] = $port;
$a['native'] == $b['native'];
}
+// Return TRUE, if the port can be edited by the user.
+function editable8021QPort ($port)
+{
+ return in_array ($port['vst_role'], array ('trunk', 'access', 'anymode'));
+}
+
+// Decide, whether the given 802.1Q port mode is permitted by
+// VST port role.
+function goodModeForVSTRole ($mode, $role)
+{
+ switch ($mode)
+ {
+ case 'access':
+ return in_array ($role, array ('access', 'anymode'));
+ case 'trunk':
+ return in_array ($role, array ('trunk', 'uplink', 'downlink', 'anymode'));
+ default:
+ throw new InvalidArgException ('mode', $mode);
+ }
+}
+
/*
Relation between desired (D), cached (C) and running (R)
else // D != C, C != R, D != R: version conflict
$ret[$pn] = array
(
- 'status' => ($port['vst_role'] == 'access' or $port['vst_role'] == 'trunk') ?
+ 'status' => editable8021QPort ($port) ?
// In case the port is normally updated by user, let him
// resolve the conflict. If the system manages this port,
// arrange the data to let remote version go down.
str_replace (' ', ' ', htmlspecialchars (mb_substr ($string, 0, $maxlen - 1), ENT_QUOTES, 'UTF-8')) . $cutind . '</span>';
}
+// return a "?, ?, ?, ... ?, ?" string consisting of N question marks
+function questionMarks ($count = 0)
+{
+ return implode (', ', array_fill (0, $count, '?'));
+}
+
?>
'ios12' => 'ios12ReadVLANConfig',
'fdry5' => 'fdry5ReadVLANConfig',
'vrp53' => 'vrp53ReadVLANConfig',
+ 'vrp55' => 'vrp55Read8021QConfig',
'nxos4' => 'nxos4Read8021QConfig',
'xos12' => 'xos12Read8021QConfig',
);
'ios12' => 'ios12TranslatePushQueue',
'fdry5' => 'fdry5TranslatePushQueue',
'vrp53' => 'vrp53TranslatePushQueue',
+ 'vrp55' => 'vrp55TranslatePushQueue',
'nxos4' => 'ios12TranslatePushQueue', // employ syntax compatibility
'xos12' => 'xos12TranslatePushQueue',
);
);
$output = file_get_contents ($tmpfilename);
unlink ($tmpfilename);
+ if ($output === FALSE)
+ throw new RTGatewayError ('failed to read temporary file');
// Being here means having 'OK!' in the response.
return oneLiner (66, array ($handlername)); // ignore provided "Ok" text
}
function detectDeviceBreed ($object_id)
{
+ $breed_by_swcode = array
+ (
+ 251 => 'ios12',
+ 252 => 'ios12',
+ 254 => 'ios12',
+ 963 => 'nxos4',
+ 964 => 'nxos4',
+ 1352 => 'xos12',
+ 1360 => 'vrp53',
+ 1361 => 'vrp55',
+ 1363 => 'fdry5',
+ );
foreach (getAttrValues ($object_id) as $record)
- {
- if
- (
- $record['name'] == 'SW type' &&
- strlen ($record['o_value']) &&
- preg_match ('/^Cisco IOS 12\./', execGMarker ($record['o_value']))
- )
- return 'ios12';
- if
- (
- $record['name'] == 'SW type' &&
- strlen ($record['o_value']) &&
- preg_match ('/^Cisco NX-OS 4\./', execGMarker ($record['o_value']))
- )
- return 'nxos4';
- if
- (
- $record['id'] == 4 &&
- $record['key'] == 1352
- )
- return 'xos12';
- if
- (
- $record['name'] == 'HW type' &&
- strlen ($record['o_value']) &&
- preg_match ('/^Foundry FastIron GS /', execGMarker ($record['o_value']))
- )
- return 'fdry5';
- if
- (
- $record['name'] == 'HW type' &&
- strlen ($record['o_value']) &&
- preg_match ('/^Huawei Quidway S53/', execGMarker ($record['o_value']))
- )
- return 'vrp53';
- }
+ if ($record['id'] == 4 and array_key_exists ($record['key'], $breed_by_swcode))
+ return $breed_by_swcode[$record['key']];
return '';
}
'deviceconfig',
array ("${command} ${endpoint} ${breed} ${tmpfilename}")
);
- $configtext = dos2unix (file_get_contents ($tmpfilename));
+ $configtext = file_get_contents ($tmpfilename);
unlink ($tmpfilename);
+ if ($configtext === FALSE)
+ throw new RTGatewayError ('failed to read temporary file');
// Being here means it was alright.
- return $gwrxlator[$command][$breed] ($configtext);
+ return $gwrxlator[$command][$breed] (dos2unix ($configtext));
}
function gwDeployDeviceConfig ($object_id, $breed, $text)
return __FUNCTION__;
}
+function vrp55Read8021QConfig ($input)
+{
+ $ret = array
+ (
+ 'vlanlist' => array (1), // VRP 5.50 hides VLAN1 from config text
+ 'portdata' => array(),
+ );
+ foreach (explode ("\n", $input) as $line)
+ {
+ $matches = array();
+ // top level
+ if (!array_key_exists ('current', $ret))
+ switch (TRUE)
+ {
+ case (preg_match ('@^ vlan batch (.+)$@', $line, $matches)):
+ foreach (vrp53ParseVLANString ($matches[1]) as $vlan_id)
+ $ret['vlanlist'][] = $vlan_id;
+ continue 2;
+ case (preg_match ('@^interface ((GigabitEthernet|Eth-Trunk)([[:digit:]]+(/[[:digit:]]+)*))$@', $line, $matches)):
+ $matches[1] = preg_replace ('@^GigabitEthernet(.+)$@', 'gi\\1', $matches[1]);
+ $ret['current'] = array ('port_name' => $matches[1]);
+ continue 2;
+ default:
+ continue 2;
+ }
+ // inside an interface block
+ switch (TRUE)
+ {
+ case preg_match ('/^ port (link-type )?hybrid /', $line):
+ throw new RTGatewayError ("unsupported configuration: ${line}");
+ case preg_match ('/^ port link-type (.+)$/', $line, $matches):
+ $ret['current']['link-type'] = $matches[1];
+ break;
+ // Native VLAN is configured differently for each link-type case, but
+ // VRP is known to filter off clauses, which don't make sense for
+ // current link-type. This way any interface section should contain
+ // only one kind of "set native" clause (but if this constraint breaks,
+ // we get a problem).
+ case preg_match ('/^ port (default|trunk pvid) vlan ([[:digit:]]+)$/', $line, $matches):
+ $ret['current']['native'] = $matches[2];
+ if (!array_key_exists ('allowed', $ret['current']))
+ $ret['current']['allowed'] = array();
+ if (!in_array ($ret['current']['native'], $ret['current']['allowed']))
+ $ret['current']['allowed'][] = $ret['current']['native'];
+ break;
+ case preg_match ('/^ port trunk allow-pass vlan (.+)$/', $line, $matches):
+ if (!array_key_exists ('allowed', $ret['current']))
+ $ret['current']['allowed'] = array();
+ foreach (vrp53ParseVLANString ($matches[1]) as $vlan_id)
+ if (!in_array ($vlan_id, $ret['current']['allowed']))
+ $ret['current']['allowed'][] = $vlan_id;
+ break;
+ case $line == ' undo portswitch':
+ case preg_match ('/^ ip address /', $line):
+ $ret['current']['link-type'] = 'IP';
+ break;
+ case preg_match ('/^ eth-trunk /', $line):
+ $ret['current']['link-type'] = 'SKIP';
+ break;
+ case substr ($line, 0, 1) == '#': // end of interface section
+ if (!array_key_exists ('link-type', $ret['current']))
+ throw new RTGatewayError ('unsupported configuration: link-type is neither trunk nor access for ' . $ret['current']['port_name']);
+ if (!array_key_exists ('allowed', $ret['current']))
+ $ret['current']['allowed'] = array();
+ if (!array_key_exists ('native', $ret['current']))
+ $ret['current']['native'] = 0;
+ switch ($ret['current']['link-type'])
+ {
+ case 'access':
+ // In VRP 5.50 an access port has default VLAN ID == 1
+ $ret['portdata'][$ret['current']['port_name']] =
+ $ret['current']['native'] ? array
+ (
+ 'mode' => 'access',
+ 'allowed' => $ret['current']['allowed'],
+ 'native' => $ret['current']['native'],
+ ) : array
+ (
+ 'mode' => 'access',
+ 'allowed' => array (VLAN_DFL_ID),
+ 'native' => VLAN_DFL_ID,
+ );
+ break;
+ case 'trunk':
+ $ret['portdata'][$ret['current']['port_name']] = array
+ (
+ 'mode' => 'trunk',
+ 'allowed' => $ret['current']['allowed'],
+ 'native' => $ret['current']['native'],
+ );
+ break;
+ case 'IP':
+ $ret['portdata'][$ret['current']['port_name']] = array
+ (
+ 'mode' => 'none',
+ 'allowed' => array(),
+ 'native' => 0,
+ );
+ break;
+ case 'SKIP':
+ default: // dot1q-tunnel ?
+ }
+ unset ($ret['current']);
+ break;
+ default: // nom-nom
+ }
+ }
+ return $ret;
+}
+
function nxos4Read8021QConfig ($input)
{
$ret = array
return $ret;
}
+function vrp55TranslatePushQueue ($queue)
+{
+ $ret = '';
+ foreach ($queue as $cmd)
+ switch ($cmd['opcode'])
+ {
+ case 'create VLAN':
+ if ($cmd['arg1'] != 1)
+ $ret .= "vlan ${cmd['arg1']}\nquit\n";
+ break;
+ case 'destroy VLAN':
+ if ($cmd['arg1'] != 1)
+ $ret .= "undo vlan ${cmd['arg1']}\n";
+ break;
+ case 'add allowed':
+ case 'rem allowed':
+ $undo = $cmd['opcode'] == 'add allowed' ? '' : 'undo ';
+ $ret .= "interface ${cmd['port']}\n";
+ foreach (listToRanges ($cmd['vlans']) as $range)
+ $ret .= "${undo}port trunk allow-pass vlan " .
+ ($range['from'] == $range['to'] ? $range['to'] : "${range['from']} to ${range['to']}") .
+ "\n";
+ $ret .= "quit\n";
+ break;
+ case 'set native':
+ $ret .= "interface ${cmd['arg1']}\nport trunk pvid vlan ${cmd['arg2']}\nquit\n";
+ break;
+ case 'set access':
+ $ret .= "interface ${cmd['arg1']}\nport default vlan ${cmd['arg2']}\nquit\n";
+ break;
+ case 'unset native':
+ $ret .= "interface ${cmd['arg1']}\nundo port trunk pvid vlan\nquit\n";
+ break;
+ case 'unset access':
+ $ret .= "interface ${cmd['arg1']}\nundo port default vlan\nquit\n";
+ break;
+ case 'set mode':
+ // VRP 5.50's meaning of "trunk" is much like the one of IOS
+ // (unlike the way VRP 5.30 defines "trunk" and "hybrid"),
+ // but it is necessary to undo configured VLANs on a port
+ // for mode change command to succeed.
+ $undo = array
+ (
+ 'access' => "undo port trunk allow-pass vlan all\n" .
+ "port trunk allow-pass vlan 1\n" .
+ "undo port trunk pvid vlan\n",
+ 'trunk' => "undo port default vlan\n",
+ );
+ $ret .= "interface ${cmd['arg1']}\n" . $undo[$cmd['arg2']];
+ $ret .= "port link-type ${cmd['arg2']}\nquit\n";
+ break;
+ case 'begin configuration':
+ $ret .= "system-view\n";
+ break;
+ case 'end configuration':
+ $ret .= "return\n";
+ break;
+ case 'save configuration':
+ $ret .= "save\nY\n";
+ break;
+ default:
+ throw new InvalidArgException ('opcode', $cmd['opcode']);
+ }
+ return $ret;
+}
+
function xos12TranslatePushQueue ($queue)
{
$ret = '';
105 => array ('code' => 'error', 'format' => 'default VLAN cannot be changed'),
// ...
107 => array ('code' => 'error', 'format' => 'Assertion failed: %s'),
- 108 => array ('code' => 'error', 'format' => 'Constraint error: %s'),
+ 108 => array ('code' => 'error', 'format' => 'Database error: %s'),
109 => array ('code' => 'error', 'format' => 'Update failed!'),
110 => array ('code' => 'error', 'format' => 'Supplement failed!'),
111 => array ('code' => 'error', 'format' => 'Reduction failed!'),
$port['vst_role'] != $port['mode'] or
count (array_diff ($port['allowed'], array_keys ($vdom['vlanlist'])))
) ? 'trwarning' : 'trbusy';
- $linkparams = array
- (
- 'page' => $pageno,
- 'tab' => $tabno,
- 'object_id' => $object_id,
- );
- if ($port_name == $req_port_name)
- {
- $imagename = 'Zooming';
- $imagetext = 'zoom out';
- }
- else
- {
- $imagename = 'Zoom';
- $imagetext = 'zoom in';
- $linkparams['port_name'] = $port_name;
- }
- $text_right = "<a href='" . makeHref ($linkparams) . "'>" .
- getImageHREF ($imagename, $imagetext) . '</a>';
+ $text_right = getTrunkPortCursorCode ($object_id, $port_name, $req_port_name);
break;
case 'access':
$trclass =
$port['vst_role'] != $port['mode'] or
!array_key_exists ($port['native'], $vdom['vlanlist'])
) ? 'trwarning' : 'trbusy';
- if ($req_port_name != '')
- {
- // don't render a form for access ports, when a trunk port is zoomed
- $text_right = ' ';
- break;
- }
- if
- (
- array_key_exists ($port['native'], $vdom['vlanlist']) and
- $vdom['vlanlist'][$port['native']]['vlan_type'] == 'alien'
- )
- {
- $text_right = formatVLANName ($vdom['vlanlist'][$port['native']], 'label');
- break;
- }
- $text_right = "<input type=hidden name=pn_${nports} value=${port_name}>";
- $text_right .= "<input type=hidden name=pm_${nports} value=access>";
- $options = array();
- // Offer only options, which are listed in domain and fit into VST.
- // Never offer immune VLANs regardless of VST filter for this port.
- // Also exclude current VLAN from the options, unless current port
- // mode is "trunk" (in this case it should be possible to set VST-
- // approved mode without changing native VLAN ID).
- foreach ($vdom['vlanlist'] as $vlan_id => $vlan_info)
- if
- (
- ($vlan_id != $port['native'] or $port['mode'] == 'trunk') and
- $vlan_info['vlan_type'] != 'alien' and
- matchVLANFilter ($vlan_id, $port['wrt_vlans'])
- )
- $options[$vlan_id] = formatVLANName ($vlan_info, 'option');
- ksort ($options);
- $options['same'] = '-- no change --';
- $text_right .= getSelect ($options, array ('name' => "pnv_${nports}"), 'same');
- $nports++;
+ // ---
+ $text_right = getAccessPortControlCode ($req_port_name, $vdom, $port_name, $port, $nports);
+ break;
+ case 'anymode':
+ $trclass = count (array_diff ($port['allowed'], array_keys ($vdom['vlanlist']))) ?
+ 'trwarning' : 'trbusy';
+ $text_right = getAccessPortControlCode ($req_port_name, $vdom, $port_name, $port, $nports);
+ $text_right .= ' ';
+ $text_right .= getTrunkPortCursorCode ($object_id, $port_name, $req_port_name);
break;
+ default:
+ throw new InvalidArgException ('vst_role', $port['vst_role']);
}
if (!array_key_exists ($port_name, $sockets))
{
$socket_columns .= '<td>' . $tmp . '</td>';
}
echo "<tr class=${trclass} valign=top><td${td_extra}>${port_name}</td>" . $socket_columns;
- echo "<td${td_extra}>${text_left}</td><td${td_extra}>${text_right}</td></tr>";
+ echo "<td${td_extra}>${text_left}</td><td class=tdright nowrap${td_extra}>${text_right}</td></tr>";
if (!array_key_exists ($port_name, $sockets))
continue;
$first_socket = TRUE;
printOpFormIntro ('save8021QConfig', array ('mutex_rev' => $vswitch['mutex_rev'], 'form_mode' => 'duplicate'));
$port_options = array();
foreach ($desired_config as $pn => $portinfo)
- if ($portinfo['vst_role'] == 'trunk' or $portinfo['vst_role'] == 'access')
+ if (editable8021QPort ($portinfo))
$port_options[$pn] = same8021QConfigs ($desired_config[$pn], $cached_config[$pn]) ?
$pn : "${pn} (*)";
echo '<tr><td>' . getSelect ($port_options, array ('name' => 'from_port')) . '</td></tr>';
echo '</tr></table>';
}
+// Return the text to place into control column of VLAN ports list
+// and modify $nports, when this text was a series of INPUTs.
+function getAccessPortControlCode ($req_port_name, $vdom, $port_name, $port, &$nports)
+{
+ // don't render a form for access ports, when a trunk port is zoomed
+ if ($req_port_name != '')
+ return ' ';
+ if
+ (
+ array_key_exists ($port['native'], $vdom['vlanlist']) and
+ $vdom['vlanlist'][$port['native']]['vlan_type'] == 'alien'
+ )
+ return formatVLANName ($vdom['vlanlist'][$port['native']], 'label');
+
+ $ret = "<input type=hidden name=pn_${nports} value=${port_name}>";
+ $ret .= "<input type=hidden name=pm_${nports} value=access>";
+ $options = array();
+ // Offer only options, which are listed in domain and fit into VST.
+ // Never offer immune VLANs regardless of VST filter for this port.
+ // Also exclude current VLAN from the options, unless current port
+ // mode is "trunk" (in this case it should be possible to set VST-
+ // approved mode without changing native VLAN ID).
+ foreach ($vdom['vlanlist'] as $vlan_id => $vlan_info)
+ if
+ (
+ ($vlan_id != $port['native'] or $port['mode'] == 'trunk') and
+ $vlan_info['vlan_type'] != 'alien' and
+ matchVLANFilter ($vlan_id, $port['wrt_vlans'])
+ )
+ $options[$vlan_id] = formatVLANName ($vlan_info, 'option');
+ ksort ($options);
+ $options['same'] = '-- no change --';
+ $ret .= getSelect ($options, array ('name' => "pnv_${nports}"), 'same');
+ $nports++;
+ return $ret;
+}
+
+function getTrunkPortCursorCode ($object_id, $port_name, $req_port_name)
+{
+ global $pageno, $tabno;
+ $linkparams = array
+ (
+ 'page' => $pageno,
+ 'tab' => $tabno,
+ 'object_id' => $object_id,
+ );
+ if ($port_name == $req_port_name)
+ {
+ $imagename = 'Zooming';
+ $imagetext = 'zoom out';
+ }
+ else
+ {
+ $imagename = 'Zoom';
+ $imagetext = 'zoom in';
+ $linkparams['port_name'] = $port_name;
+ }
+ return "<a href='" . makeHref ($linkparams) . "'>" .
+ getImageHREF ($imagename, $imagetext) . '</a>';
+}
+
function renderTrunkPortControls ($vswitch, $vdom, $port_name, $vlanport)
{
if (!count ($vdom['vlanlist']))
// particular port, but it cannot be changed by user.
if ($option['vlan_type'] == 'alien')
$selected .= ' disabled';
- echo "<tr><td colspan=2 class=${class}>";
+ echo "<tr><td nowrap colspan=2 class=${class}>";
echo "<label><input type=checkbox name='pav_0[]' value='${vlan_id}'${selected}> ";
echo $option['text'] . "</label></td></tr>";
}
$option['vlan_type'] == 'alien'
)
$selected .= ' disabled';
- echo "<tr><td colspan=2 class=${class}>";
+ echo "<tr><td nowrap colspan=2 class=${class}>";
echo "<label><input type=radio name='pnv_0' value='${vlan_id}'${selected}> ";
echo $option['text'] . "</label></td></tr>";
}
(
!acceptable8021QConfig ($item['right']) or
count (array_diff ($item['right']['allowed'], $domvlans)) or
- $item['vst_role'] != $item['right']['mode']
+ !goodModeForVSTRole ($item['right']['mode'], $item['vst_role'])
)
$radio_attrs['left'] = ' disabled';
break;
$port_role_options = array
(
'none' => 'none',
- 'access' => 'access',
- 'trunk' => 'trunk',
- 'uplink' => 'uplink',
- 'downlink' => 'downlink',
+ 'access' => 'user: access only',
+ 'trunk' => 'user: trunk only',
+ 'anymode' => 'user: any mode',
+ 'uplink' => 'system: uplink trunk',
+ 'downlink' => 'system: downlink trunk',
);
if (getConfigVar ('ADDNEW_AT_TOP') == 'yes')
printNewItemTR ($port_role_options);
}
$msgcode['process8021QSyncRequest']['OK'] = 63;
-$msgcode['process8021QSyncRequest']['ERR1'] = 109;
-$msgcode['process8021QSyncRequest']['ERR2'] = 191;
+$msgcode['process8021QSyncRequest']['ERR'] = 191;
function process8021QSyncRequest ()
{
// behave depending on current operation: exec8021QPull or exec8021QPush
global $sic, $op;
- try
- {
- if (FALSE === $done = exec8021QDeploy ($sic['object_id'], $op == 'exec8021QPush'))
- return buildRedirectURL (__FUNCTION__, 'ERR2'); // specific case
- return buildRedirectURL (__FUNCTION__, 'OK', array ($done));
- }
- catch (Exception $e)
- {
- return buildRedirectURL (__FUNCTION__, 'ERR1'); // generic failure
- }
+ if (FALSE === $done = exec8021QDeploy ($sic['object_id'], $op == 'exec8021QPush'))
+ return buildRedirectURL (__FUNCTION__, 'ERR');
+ return buildRedirectURL (__FUNCTION__, 'OK', array ($done));
}
$msgcode['resolve8021QConflicts']['OK'] = 63;
'try_next_proc' => FALSE,
);
+$iftable_processors['fcx-uplinks'] = array
+(
+ 'pattern' => '@^10GigabitEthernet1/2/([[:digit:]]+)$@',
+ 'replacement' => 'e1/2/\\1',
+ 'dict_key' => '9-1084',
+ 'label' => 'X\\1',
+ 'try_next_proc' => FALSE,
+);
+
+$iftable_processors['fcx-management'] = array
+(
+ 'pattern' => '@^Management$@',
+ 'replacement' => 'management1',
+ 'dict_key' => '1-24',
+ 'label' => 'Management',
+ 'try_next_proc' => FALSE,
+);
+
$iftable_processors['summit-25-to-26-XFP-uplinks'] = array
(
'pattern' => '@^.+ Port (25|26)$@',
'text' => 'WS-C2960-48TT-L: 48 RJ-45/10-100TX + 2 RJ-45/10-100-1000T(X)',
'processors' => array ('catalyst-chassis-any-100TX', 'catalyst-chassis-any-1000T'),
),
+ '9.1.950' => array
+ (
+ 'dict_key' => 1347,
+ 'text' => 'WS-C2960-24PC: 44 RJ-45/10-100TX + 2 combo-gig',
+ 'processors' => array ('catalyst-chassis-1-to-2-combo-1000SFP', 'catalyst-chassis-any-1000T', 'catalyst-chassis-any-100TX'),
+ ),
'9.1.527' => array
(
'dict_key' => 210,
'text' => 'FGS648P-POE: 48 RJ-45/10-100-1000T(X) + 4 combo-gig + uplink slot',
'processors' => array ('fgs-1-to-4-comboSFP', 'fgs-any-1000T', 'fgs-uplinks'),
),
+ '1991.1.3.54.2.4.1.1' => array
+ (
+ 'dict_key' => 1362,
+ 'text' => 'FCX 648: 48 RJ-45/10-100-1000T(X) + uplink slot with 4 SFP+',
+ 'processors' => array ('fgs-any-1000T', 'fcx-uplinks', 'fcx-management'),
+ ),
'1916.2.71' => array
(
'dict_key' => 694,
$log = mergeLogs ($log, oneLiner (81, array ('netgear-generic')));
break;
case preg_match ('/^2011\.2\.23\./', $sysObjectID): // Huawei
+ $swtype_pcre = array
+ (
+ '/Huawei Versatile Routing Platform Software.+VRP.+Software, Version 5.30 /s' => 1360,
+ '/Huawei Versatile Routing Platform Software.+VRP.+Software, Version 5.50 /s' => 1361,
+ );
+ foreach ($swtype_pcre as $pattern => $dict_key)
+ if (preg_match ($pattern, $sysDescr))
+ {
+ updateStickerForCell ($objectInfo, 4, $dict_key);
+ break;
+ }
checkPIC ('1-681');
commitAddPort ($objectInfo['id'], 'con0', '1-681', 'console', ''); // DB-9 RS-232 console
$log = mergeLogs ($log, oneLiner (81, array ('huawei-generic')));
$log = mergeLogs ($log, oneLiner (81, array ('juniper-generic')));
break;
case preg_match ('/^1991\.1\.3\.45\./', $sysObjectID): // snFGSFamily
+ case preg_match ('/^1991\.1\.3\.54\.2\.4\.1\.1$/', $sysObjectID): // FCX 648
$exact_release = preg_replace ('/^.*, IronWare Version ([^ ]+) .*$/', '\\1', $sysDescr);
updateStickerForCell ($objectInfo, 5, $exact_release);
# FOUNDRY-SN-AGENT-MIB::snChasSerNum.0
`vst_id` int(10) unsigned NOT NULL,
`rule_no` int(10) unsigned NOT NULL,
`port_pcre` char(255) NOT NULL,
- `port_role` enum('access','trunk','uplink','downlink','none') NOT NULL default 'none',
+ `port_role` enum('access','trunk','anymode','uplink','downlink','none') NOT NULL default 'none',
`wrt_vlans` char(255) default NULL,
`description` char(255) default NULL,
UNIQUE KEY `vst-rule` (`vst_id`,`rule_no`),
if (count ($only_racks))
{
$query .= 'AND object_id IN (SELECT DISTINCT object_id FROM RackSpace WHERE rack_id IN (' .
- implode (', ', array_fill (0, count ($only_racks), '?')) . '))';
+ questionMarks (count ($only_racks)) . '))';
$qparams = array_merge ($qparams, $only_racks);
}
$query .= ' ORDER BY object_id, name';
ob_end_clean();
header ('Location: ' . buildWideRedirectURL (oneLiner (107, array ($e->getMessage()))));
}
-catch (RTDBConstraintError $e)
+catch (RTDatabaseError $e)
{
ob_end_clean();
header ('Location: ' . buildWideRedirectURL (oneLiner (108, array ($e->getMessage()))));
break;
case '0.18.4':
$query = array_merge ($query, reloadDictionary ($batchid));
+ $query[] = "ALTER TABLE VLANSTRule MODIFY port_role enum('access','trunk','anymode','uplink','downlink','none') NOT NULL default 'none'";
$query[] = "UPDATE Config SET varvalue = '0.18.4' WHERE varname = 'DB_VERSION'";
break;
default: