0; // Faster (and easy) way for get untagged/primary vlans //$dot1q_ports = snmpwalk_cache_oid($device, 'dot1qPortVlanTable', array(), 'Q-BRIDGE-MIB'); $dot1q_ports = snmpwalk_cache_oid($device, 'dot1qPvid', [], 'Q-BRIDGE-MIB'); if (snmp_status() && $use_baseports) { echo("dot1qPortVlanTable "); if ($is_juniper) // EX switches. Unsure if other Juniper platforms "affected" { //JUNIPER-VLAN-MIB::jnxExVlanPortAccessMode.22.549 = INTEGER: access(1) //JUNIPER-VLAN-MIB::jnxExVlanPortAccessMode.25.3 = INTEGER: trunk(2) //JUNIPER-VLAN-MIB::jnxExVlanPortAccessMode.25.513 = INTEGER: access(1) foreach (snmpwalk_cache_oid($device, 'jnxExVlanPortAccessMode', [], 'JUNIPER-VLAN-MIB') as $index => $entry) { [, $index] = explode('.', $index); $dot1q_ports[$index]['jnxExVlanPortAccessMode'] = $entry['jnxExVlanPortAccessMode']; } } else { $dot1q_ports = snmpwalk_cache_oid($device, 'dot1qPortAcceptableFrameTypes', $dot1q_ports, 'Q-BRIDGE-MIB'); $dot1q_ports = snmpwalk_cache_oid($device, 'dot1qPortIngressFiltering', $dot1q_ports, 'Q-BRIDGE-MIB'); } print_debug_vars($dot1q_ports); // Collect trunk port ids and vlans //$trunk_ports = dbFetchColumn('SELECT DISTINCT `port_id` FROM `ports_vlans` WHERE `device_id` = ?', [ $device['device_id'] ]); $trunk_ports = []; foreach (dbFetchRows('SELECT `port_id`, `vlan` FROM `ports_vlans` WHERE `device_id` = ?', [$device['device_id']]) as $entry) { $trunk_ports[$entry['port_id']][] = $entry['vlan']; } print_debug_vars($trunk_ports); $vlan_rows = []; foreach ($dot1q_ports as $index => $entry) { $vlan_num = $entry['dot1qPvid']; $ifIndex = $dot1d_baseports[$index]['dot1dBasePortIfIndex']; if (isset($entry['jnxExVlanPortAccessMode']) && $entry['jnxExVlanPortAccessMode'] === 'trunk') { $trunk = 'dot1Q'; } elseif (isset($entry['dot1qPortAcceptableFrameTypes']) && $entry['dot1qPortAcceptableFrameTypes'] === 'admitOnlyVlanTagged') { $trunk = 'dot1Q'; } elseif ((isset($entry['dot1qPortIngressFiltering']) && $entry['dot1qPortIngressFiltering'] === 'true')) { // Additionally, check if port have trunk ports $port = get_port_by_index_cache($device, $ifIndex); print_debug("CHECK. ifIndex: $ifIndex, port_id: " . $port['port_id']); if (isset($trunk_ports[$port['port_id']]) && (count($trunk_ports[$port['port_id']]) > 1 || $trunk_ports[$port['port_id']][0] != $vlan_num)) { $trunk = 'dot1Q'; } else { $trunk = ''; // access } } else { $trunk = ''; // access } $vlan_rows[] = [$ifIndex, $vlan_num, $trunk]; // Set Vlan and Trunk if (isset($port_stats[$ifIndex])) { $port_stats[$ifIndex]['ifVlan'] = $vlan_num; $port_stats[$ifIndex]['ifTrunk'] = $trunk; } } } elseif ($is_juniper) { // For juniper Q-BRIDGE is derp, but still required for trunk ports // skipped here, use only dot1qPvid } else { if ($device['os'] == 'zyxeles') { // On this devices dot1qVlanStaticUntaggedPorts store incorrect vlan data, ie; // Note, dot1qVlanStaticEgressPorts - fine! //Q-BRIDGE-MIB::dot1qVlanStaticUntaggedPorts.609 = Hex-STRING: FF FF FF FF FF FF C0 00 00 00 00 00 00 00 00 00 //Q-BRIDGE-MIB::dot1qVlanStaticUntaggedPorts.862 = Hex-STRING: FF FF FF FF FF FF C0 00 00 00 00 00 00 00 00 00 //Q-BRIDGE-MIB::dot1qVlanStaticUntaggedPorts.917 = Hex-STRING: FF FF FF FF FF FF F0 00 00 00 00 00 00 00 00 00 // Use dot1qVlanCurrentUntaggedPorts instead //Q-BRIDGE-MIB::dot1qVlanCurrentUntaggedPorts.0.609 = Hex-STRING: 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 //Q-BRIDGE-MIB::dot1qVlanCurrentUntaggedPorts.0.862 = Hex-STRING: 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 //Q-BRIDGE-MIB::dot1qVlanCurrentUntaggedPorts.0.917 = Hex-STRING: 00 00 00 00 00 00 80 00 00 00 00 00 00 00 00 00 $oid_name = 'dot1qVlanCurrentUntaggedPorts'; $dot1q_ports = snmpwalk_cache_oid($device, 'dot1qVlanCurrentUntaggedPorts.0', $dot1q_ports, 'Q-BRIDGE-MIB', NULL, OBS_SNMP_ALL_MULTILINE | OBS_SNMP_HEX); } else { // Common dot1qVlanStaticUntaggedPorts $oid_name = 'dot1qVlanStaticUntaggedPorts'; $dot1q_ports = snmpwalk_cache_oid($device, 'dot1qVlanStaticUntaggedPorts', $dot1q_ports, 'Q-BRIDGE-MIB', NULL, OBS_SNMP_ALL_MULTILINE | OBS_SNMP_HEX); } if ($is_juniper) // EX switches. Unsure if other Juniper platforms "affected" { // Fetch Juniper VLAN table for correct tag $dot1q_ports = snmpwalk_cache_oid($device, 'jnxExVlanTag', $dot1q_ports, 'JUNIPER-VLAN-MIB'); } // This is very slow (on some devices and with many ports), very hard to detect correct ports echo("$oid_name "); // Detect min ifIndex for vlan base ports // Why, see here: http://jira.observium.org/browse/OBS-963 /* if ($use_baseports) { $vlan_ifindex_min = $dot1d_baseports[key($dot1d_baseports)]['dot1dBasePortIfIndex']; // First element foreach ($dot1d_baseports as $entry) { // But min ifIndex can be in any entry $vlan_ifindex_min = min($vlan_ifindex_min, $entry['dot1dBasePortIfIndex']); } } else { $vlan_ifindex_min = 0; } */ foreach ($dot1q_ports as $index => $entry) { if (is_device_mib($device, 'JUNIPER-VLAN-MIB')) { $vlan_num = $entry['jnxExVlanTag']; } else { $index_array = explode('.', $index); $vlan_num = end($index_array); // need explode for dot1qVlanCurrentUntaggedPorts.0 } // Convert hex to binary map $binary = hex2binmap($entry[$oid_name]); $trunk = ''; // unknown if ($device['os'] === 'ftos') { // FTOS specific // FTOS devices use harder way for detect VLANs and associate ports // See: https://www.force10networks.com/CSPortal20/TechTips/0041B_displaying_vlan_ports.aspx // Q-BRIDGE-MIB::dot1qVlanStaticUntaggedPorts.1107787777, where 1107787777 is ifIndex for Vlan interface // Port associations based on slot/port, each 12 hex pair (96 bin) is slot //IF-MIB::ifDescr.1107787777 = STRING: Vlan 1 //IF-MIB::ifDescr.1107787998 = STRING: Vlan 222 [, $vlan_num] = explode(' ', $port_stats[$index]['ifDescr']); if (!is_numeric($vlan_num)) { continue; } // Skip unknown foreach (str_split($binary, 96) as $slot => $binary_map) { $length = strlen($binary_map); for ($i = 0; $i < $length; $i++) { if ($binary_map[$i]) { // Now find slot/port from ifDescr $port_map = ' ' . $slot . '/' . ($i + 1); foreach ($port_stats as $ifIndex => $entry) { if (str_ends($entry['ifDescr'], $port_map)) { $vlan_rows[] = [$ifIndex, $vlan_num, $trunk]; // Set Vlan and Trunk $port_stats[$ifIndex]['ifVlan'] = $vlan_num; $port_stats[$ifIndex]['ifTrunk'] = $trunk; break; // Stop ports loop } } } } } } else { // All other // Assign binary vlans map to ports $length = strlen($binary); for ($i = 0; $i < $length; $i++) { if ($binary[$i]) { //$ifIndex = $i + $vlan_ifindex_min; // This is incorrect ifIndex association! if ($use_baseports) { $ifIndex = $dot1d_baseports[$i + 1]['dot1dBasePortIfIndex']; } else { $ifIndex = $i; } $vlan_rows[] = [$ifIndex, $vlan_num, $trunk]; // Set Vlan and Trunk if (isset($port_stats[$ifIndex])) { if (isset($port_stats[$ifIndex]['ifVlan'])) { print_debug("WARNING. Oid dot1qVlanStaticUntaggedPorts pass incorrect vlan data."); } $port_stats[$ifIndex]['ifVlan'] = $vlan_num; $port_stats[$ifIndex]['ifTrunk'] = $trunk; } } } } } } $headers = ['%WifIndex%n', '%WVlan%n', '%WTrunk%n']; print_cli_table($vlan_rows, $headers); //$process_port_functions[$port_module] = $GLOBALS['snmp_status']; // Additional db fields for update //$process_port_db[$port_module][] = 'ifVlan'; //$process_port_db[$port_module][] = 'ifTrunk'; // EOF