function renderObject8021QPorts($object_id) { global $pageno, $tabno, $sic; $vswitch = getVLANSwitchInfo($object_id); $vdom = getVLANDomain($vswitch['domain_id']); $req_port_name = array_fetch($sic, 'port_name', ''); $desired_config = apply8021QOrder($vswitch, getStored8021QConfig($object_id, 'desired')); $cached_config = getStored8021QConfig($object_id, 'cached'); $desired_config = sortPortList($desired_config); $uplinks = filter8021QChangeRequests($vdom['vlanlist'], $desired_config, produceUplinkPorts($vdom['vlanlist'], $desired_config, $vswitch['object_id'])); echo '<table border=0 width="100%"><tr valign=top><td class=tdleft width="50%">'; // port list echo '<table cellspacing=0 cellpadding=5 align=center class=widetable>'; echo '<tr><th>port</th><th>interface</th><th>link</th><th width="25%">last saved config</th>'; echo $req_port_name == '' ? '<th width="25%">new config</th></tr>' : '<th>(zooming)</th></tr>'; if ($req_port_name == '') { } printOpFormIntro('save8021QConfig', array('mutex_rev' => $vswitch['mutex_rev'], 'form_mode' => 'save')); $object = spotEntity('object', $object_id); amplifyCell($object); $sockets = array(); if (isset($_REQUEST['hl_port_id'])) { assertUIntArg('hl_port_id'); $hl_port_id = intval($_REQUEST['hl_port_id']); $hl_port_name = NULL; addAutoScrollScript("port-{$hl_port_id}"); } foreach ($object['ports'] as $port) { if (mb_strlen($port['name']) and array_key_exists($port['name'], $desired_config)) { if (isset($hl_port_id) and $hl_port_id == $port['id']) { $hl_port_name = $port['name']; } $socket = array('interface' => formatPortIIFOIF($port)); if ($port['remote_object_id']) { $socket['link'] = formatLoggedSpan($port['last_log'], formatLinkedPort($port)); } elseif (strlen($port['reservation_comment'])) { $socket['link'] = formatLoggedSpan($port['last_log'], 'Rsv:', 'strong underline') . ' ' . formatLoggedSpan($port['last_log'], $port['reservation_comment']); } else { $socket['link'] = ' '; } $sockets[$port['name']][] = $socket; } } unset($object); $nports = 0; // count only access ports switchportInfoJS($object_id); // load JS code to make portnames interactive foreach ($desired_config as $port_name => $port) { $text_left = formatVLANPackDiff($cached_config[$port_name], $port); // decide on row class switch ($port['vst_role']) { case 'none': if ($port['mode'] == 'none') { continue 2; } // early miss $text_right = ' '; $trclass = 'trerror'; // stuck ghost port break; case 'downlink': $text_right = '(downlink)'; $trclass = get8021QPortTrClass($port, $vdom['vlanlist'], 'trunk'); break; case 'uplink': $text_right = '(uplink)'; $trclass = same8021QConfigs($port, $uplinks[$port_name]) ? 'trbusy' : 'trwarning'; break; case 'trunk': $text_right = getTrunkPortCursorCode($object_id, $port_name, $req_port_name); $trclass = get8021QPortTrClass($port, $vdom['vlanlist'], 'trunk'); break; case 'access': $text_right = getAccessPortControlCode($req_port_name, $vdom, $port_name, $port, $nports); $trclass = get8021QPortTrClass($port, $vdom['vlanlist'], 'access'); break; case 'anymode': $text_right = getAccessPortControlCode($req_port_name, $vdom, $port_name, $port, $nports); $text_right .= ' '; $text_right .= getTrunkPortCursorCode($object_id, $port_name, $req_port_name); $trclass = get8021QPortTrClass($port, $vdom['vlanlist'], NULL); break; default: throw new InvalidArgException('vst_role', $port['vst_role']); } if (!checkPortRole($vswitch, $port_name, $port)) { $trclass = 'trerror'; } if (!array_key_exists($port_name, $sockets)) { $socket_columns = '<td> </td><td> </td>'; $td_extra = ''; } else { $td_extra = count($sockets[$port_name]) > 1 ? ' rowspan=' . count($sockets[$port_name]) : ''; $socket_columns = ''; foreach ($sockets[$port_name][0] as $tmp) { $socket_columns .= '<td>' . $tmp . '</td>'; } } $anchor = ''; $tdclass = ''; if (isset($hl_port_name) and $hl_port_name == $port_name) { $tdclass .= 'class="border_highlight"'; $anchor = "name='port-{$hl_port_id}'"; } echo "<tr class='{$trclass}' valign=top><td{$td_extra} {$tdclass} NOWRAP><a class='interactive-portname port-menu nolink' {$anchor}>{$port_name}</a></td>" . $socket_columns; 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; foreach ($sockets[$port_name] as $socket) { if ($first_socket) { $first_socket = FALSE; } else { echo "<tr class={$trclass} valign=top>"; foreach ($socket as $tmp) { echo '<td>' . $tmp . '</td>'; } echo '</tr>'; } } } echo '<tr><td colspan=5 class=tdcenter><ul class="btns-8021q-sync">'; if ($req_port_name == '' and $nports) { echo "<input type=hidden name=nports value={$nports}>"; echo '<li>' . getImageHREF('SAVE', 'save configuration', TRUE, 100) . '</li>'; } echo '</form>'; if (permitted(NULL, NULL, NULL, array(array('tag' => '$op_recalc8021Q')))) { echo '<li>' . getOpLink(array('op' => 'exec8021QRecalc'), '', 'RECALC', 'Recalculate uplinks and downlinks') . '</li>'; } echo '</ul></td></tr></table>'; if ($req_port_name == '') { } echo '</form>'; echo '</td>'; // configuration of currently selected port, if any if (!array_key_exists($req_port_name, $desired_config)) { echo '<td>'; $port_options = array(); foreach ($desired_config as $pn => $portinfo) { if (editable8021QPort($portinfo)) { $port_options[$pn] = same8021QConfigs($desired_config[$pn], $cached_config[$pn]) ? $pn : "{$pn} (*)"; } } if (count($port_options) < 2) { echo ' '; } else { startPortlet('port duplicator'); echo '<table border=0 align=center>'; printOpFormIntro('save8021QConfig', array('mutex_rev' => $vswitch['mutex_rev'], 'form_mode' => 'duplicate')); echo '<tr><td>' . getSelect($port_options, array('name' => 'from_port')) . '</td></tr>'; echo '<tr><td>↓ ↓ ↓</td></tr>'; echo '<tr><td>' . getSelect($port_options, array('name' => 'to_ports[]', 'size' => getConfigVar('MAXSELSIZE'), 'multiple' => 1)) . '</td></tr>'; echo '<tr><td>' . getImageHREF('COPY', 'duplicate', TRUE) . '</td></tr>'; echo '</form></table>'; finishPortlet(); } echo '</td>'; } else { renderTrunkPortControls($vswitch, $vdom, $req_port_name, $desired_config[$req_port_name]); } echo '</tr></table>'; }
function apply8021qChangeRequest($switch_id, $changes, $verbose = TRUE, $mutex_rev = NULL) { global $dbxlink; $dbxlink->beginTransaction(); try { if (NULL === ($vswitch = getVLANSwitchInfo($switch_id, 'FOR UPDATE'))) { throw new InvalidArgException('object_id', $switch_id, 'VLAN domain is not set for this object'); } if (isset($mutex_rev) and $vswitch['mutex_rev'] != $mutex_rev) { throw new InvalidRequestArgException('mutex_rev', $mutex_rev, 'expired form data'); } $after = $before = apply8021QOrder($vswitch['template_id'], getStored8021QConfig($vswitch['object_id'], 'desired')); $domain_vlanlist = getDomainVLANs($vswitch['domain_id']); $changes = filter8021QChangeRequests($domain_vlanlist, $before, apply8021QOrder($vswitch['template_id'], $changes)); $desired_ports_count = count($changes); $changes = authorize8021QChangeRequests($before, $changes); if (count($changes) < $desired_ports_count) { showWarning(sprintf("Permission denied to change %d ports", $desired_ports_count - count($changes))); } foreach ($changes as $port_name => $port) { $after[$port_name] = $port; } $new_uplinks = filter8021QChangeRequests($domain_vlanlist, $after, produceUplinkPorts($domain_vlanlist, $after, $vswitch['object_id'])); $npulled = replace8021QPorts('desired', $vswitch['object_id'], $before, $changes); $nsaved_uplinks = replace8021QPorts('desired', $vswitch['object_id'], $before, $new_uplinks); if ($npulled + $nsaved_uplinks) { touchVLANSwitch($vswitch['object_id']); } $dbxlink->commit(); } catch (Exception $e) { $dbxlink->rollBack(); showError(sprintf("Failed to update switchports: %s", $e->getMessage())); return 0; } $nsaved_downlinks = 0; if ($nsaved_uplinks) { $nsaved_downlinks = initiateUplinksReverb($vswitch['object_id'], $new_uplinks); } // instant deploy to that switch if configured $done = 0; if ($npulled + $nsaved_uplinks > 0 and getConfigVar('8021Q_INSTANT_DEPLOY') == 'yes') { try { if (FALSE === ($done = exec8021QDeploy($vswitch['object_id'], TRUE))) { showError("deploy was blocked due to conflicting configuration versions"); } elseif ($verbose) { showSuccess(sprintf("Configuration for %u port(s) have been deployed", $done)); } } catch (Exception $e) { showError(sprintf("Failed to deploy changes to switch: %s", $e->getMessage())); } } // report number of changed ports $total = $npulled + $nsaved_uplinks + $nsaved_downlinks; if ($verbose) { $message = sprintf('%u port(s) have been changed', $total); if ($total > 0) { showSuccess($message); } else { showNotice($message); } } return $total; }