function vrp85Read8021QConfig($input) { $ret = constructRunning8021QConfig(); $ret['vlanlist'][] = VLAN_DFL_ID; // VRP 8+ hides VLAN1 from config text $state = 'skip'; $current = array(); foreach (explode("\n", $input) as $line) { $line = rtrim($line); do { switch ($state) { case 'skip': if (preg_match('/^Port\\s+.*PVID/i', $line)) { $state = 'ports'; } break; case 'ports': if (isset($current['name'])) { if (preg_match('/^\\s+(\\d.*)/', $line, $m)) { $current['allowed'] .= ' ' . $m[1]; } else { // port-channel members are displayed in 'display port vlan' with PVID = 0. if ($current['native'] >= VLAN_MIN_ID && $current['native'] <= VLAN_MAX_ID) { // commit $current into portdata $data = array('mode' => $current['mode'], 'native' => $current['native'], 'allowed' => array()); $range = trim(preg_replace('/\\s+/', ',', $current['allowed']), ',-'); $data['allowed'] = $range == '' ? array() : iosParseVLANString($range); if ($data['mode'] == 'access') { $data['allowed'] = array($current['native']); } elseif ($data['mode'] == 'trunk') { if (!in_array($data['native'], $data['allowed'])) { $data['native'] = 0; } } else { $data['allowed'] = array(); $data['native'] = 0; } $ret['portdata'][$current['name']] = $data; } $current = array(); } } if (preg_match('/^</', $line)) { $state = 'conf'; } elseif (preg_match('/^(\\S+)\\s+(\\w+)\\s+(\\d+)\\s+(.*)$/', $line, $m)) { $current['name'] = shortenIfName($m[1]); $current['mode'] = $m[2] == 'access' || $m[2] == 'trunk' ? $m[2] : 'none'; $current['native'] = intval($m[3]); $current['allowed'] = $m[4]; } break; case 'conf': if (preg_match('/^interface (\\S+)$/', $line, $m)) { $current['name'] = shortenIfName($m[1]); $current['lines'] = array(array('type' => 'line-header', 'line' => $line)); $state = 'iface'; } elseif (preg_match('@vlan batch (.+)@', $line, $matches)) { foreach (vrp53ParseVLANString($matches[1]) as $vlan_id) { $ret['vlanlist'][] = $vlan_id; } } break; case 'iface': $line_class = $line == '#' ? 'line-header' : 'line-other'; if (preg_match('/^\\s*port (trunk|link-type|default vlan)/', $line)) { $line_class = 'line-8021q'; } $current['lines'][] = array('type' => $line_class, 'line' => $line); if ($line == '#') { // commit $current into portconfig $ret['portconfig'][$current['name']] = $current['lines']; $current = array(); $state = 'conf'; } break; default: throw new RackTablesError("Unknown FSM state '{$state}'", RackTablesError::INTERNAL); } } while (FALSE); } return $ret; }
function vrp55Read8021QConfig($input) { $ret = array('vlanlist' => array(1), 'portdata' => array(), 'portconfig' => 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; } break; case preg_match('@^interface ((Ethernet|GigabitEthernet|XGigabitEthernet|Eth-Trunk)([[:digit:]]+(/[[:digit:]]+)*))$@', $line, $matches): $port_name = shortenIfName($matches[1]); $ret['current'] = array('port_name' => $port_name, 'allowed' => array(VLAN_DFL_ID), 'native' => VLAN_DFL_ID); $ret['portconfig'][$port_name][] = array('type' => 'line-header', 'line' => $line); break; } continue; } $port_name = $ret['current']['port_name']; // inside an interface block $line_class = 'line-8021q'; switch (TRUE) { case preg_match('/^ port (link-type )?hybrid /', $line): throw new RTGatewayError("unsupported hybrid link-type for {$port_name}: {$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 that 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). // Native VLAN is configured differently for each link-type case, but // VRP is known to filter off clauses that 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]; break; case preg_match('/^ port trunk allow-pass vlan (.+)$/', $line, $matches): foreach (vrp53ParseVLANString($matches[1]) as $vlan_id) { if (!in_array($vlan_id, $ret['current']['allowed'])) { $ret['current']['allowed'][] = $vlan_id; } } break; case preg_match('/^ undo port trunk allow-pass vlan (.+)$/', $line, $matches): $ret['current']['allowed'] = array_diff($ret['current']['allowed'], vrp53ParseVLANString($matches[1])); break; case $line == ' undo portswitch': case preg_match('/^ ip address /', $line): case preg_match('/^ service type /', $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 $line_class = 'line-header'; if (!array_key_exists('link-type', $ret['current'])) { $ret['current']['link-type'] = 'hybrid'; } switch ($ret['current']['link-type']) { case 'access': // In VRP 5.50 an access port has default VLAN ID == 1 $ret['portdata'][$port_name] = $ret['current']['native'] ? array('mode' => 'access', 'allowed' => array($ret['current']['native']), 'native' => $ret['current']['native']) : array('mode' => 'access', 'allowed' => array(VLAN_DFL_ID), 'native' => VLAN_DFL_ID); break; case 'trunk': $ret['portdata'][$port_name] = array('mode' => 'trunk', 'allowed' => $ret['current']['allowed'], 'native' => in_array($ret['current']['native'], $ret['current']['allowed']) ? $ret['current']['native'] : 0); break; case 'IP': case 'SKIP': break; case 'hybrid': // hybrid ports are not supported // hybrid ports are not supported default: // dot1q-tunnel ? $ret['portdata'][$port_name] = array('mode' => 'none', 'allowed' => array(), 'native' => 0); break; } unset($ret['current']); break; default: // nom-nom $line_class = 'line-other'; } $ret['portconfig'][$port_name][] = array('type' => $line_class, 'line' => $line); } return $ret; }