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;
}
Example #2
0
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;
}