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 get8021QSyncOptions($vswitch, $D, $C, $R) { $default_port = array('mode' => 'access', 'allowed' => array(VLAN_DFL_ID), 'native' => VLAN_DFL_ID); $ret = array(); $allports = array(); foreach (array_unique(array_merge(array_keys($C), array_keys($R))) as $pn) { $allports[$pn] = array(); } foreach (apply8021QOrder($vswitch['template_id'], $allports) as $pn => $port) { // catch anomalies early if ($port['vst_role'] == 'none') { if ((!array_key_exists($pn, $R) or $R[$pn]['mode'] == 'none') and !array_key_exists($pn, $C)) { $ret[$pn] = array('status' => 'none'); } else { $ret[$pn] = array('status' => 'martian_conflict', 'left' => array_key_exists($pn, $C) ? $C[$pn] : array('mode' => 'none'), 'right' => array_key_exists($pn, $R) ? $R[$pn] : array('mode' => 'none')); } continue; } elseif ((!array_key_exists($pn, $R) or $R[$pn]['mode'] == 'none') and array_key_exists($pn, $C)) { $ret[$pn] = array('status' => 'martian_conflict', 'left' => array_key_exists($pn, $C) ? $C[$pn] : array('mode' => 'none'), 'right' => array_key_exists($pn, $R) ? $R[$pn] : array('mode' => 'none')); continue; } // (DC_): port missing from device if (!array_key_exists($pn, $R)) { $ret[$pn] = array('left' => $D[$pn]); if (same8021QConfigs($D[$pn], $default_port)) { $ret[$pn]['status'] = 'ok_to_delete'; } else { $ret[$pn]['status'] = 'delete_conflict'; $ret[$pn]['lastseen'] = $C[$pn]; } continue; } // (__R): port missing from DB if (!array_key_exists($pn, $C)) { // Allow importing any configuration, which passes basic // validation. If port mode doesn't match its VST role, // this will be handled later WRT each port. $ret[$pn] = array('status' => acceptable8021QConfig($R[$pn]) ? 'ok_to_add' : 'add_conflict', 'right' => $R[$pn]); continue; } $D_eq_C = same8021QConfigs($D[$pn], $C[$pn]); $C_eq_R = same8021QConfigs($C[$pn], $R[$pn]); // (DCR), D = C = R: data in sync if ($D_eq_C and $C_eq_R) { $ret[$pn] = array('status' => 'in_sync', 'both' => $R[$pn]); continue; } // (DCR), D = C: no local edit in the way if ($D_eq_C) { $ret[$pn] = array('status' => 'ok_to_pull', 'left' => $D[$pn], 'right' => $R[$pn]); } elseif ($C_eq_R) { $ret[$pn] = array('status' => 'ok_to_push', 'left' => $D[$pn], 'right' => $R[$pn]); } elseif (same8021QConfigs($D[$pn], $R[$pn])) { $ret[$pn] = array('status' => 'ok_to_merge', 'both' => $R[$pn]); } else { // D != C, C != R, D != R: version conflict $ret[$pn] = array('status' => editable8021QPort($port) ? 'merge_conflict' : 'ok_to_push_with_merge', 'left' => $D[$pn], 'right' => $R[$pn]); } } return $ret; }