Fix Cumulus Linux VLAN issues

Thinking this is more of a bug than a feature request since vlans are currently returned incorrectly.

Currently we are seeing an issue with Vlan to port association on Cumulus Linux. According to Cumulus this is the correct way to do it.

More info including Discovery, Poller, and Walk can be found at https://gist.github.com/theherodied/dba2fd38f459bf4b6481f3ec75d92d23

The dogt1qPvid indexing does not index by ifIndex. To get the ifindex you have to look at the ifindex to dot1xBasePortIfIndex. RFC 4188 (BRIDGE-MIB) defines the
dot1dBasePortIfIndex OBJECT-TYPE
SYNTAX InterfaceIndex
MAX-ACCESS read-only
STATUS current
DESCRIPTION
“The value of the instance of the ifIndex object,
defined in IF-MIB, for the interface corresponding
to this port.”
::= { dot1dBasePortEntry 2 }
And RF 4363 (Q-BRIDGE-MIB) is where the pvids are shown. These are indexed by

dot1qPortVlanTable OBJECT-TYPE
SYNTAX SEQUENCE OF Dot1qPortVlanEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
“A table containing per-port control and status
information for VLAN configuration in the device.”
::= { dot1qVlan 5 }
dot1qPortVlanEntry OBJECT-TYPE
SYNTAX Dot1qPortVlanEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
“Information controlling VLAN configuration for a port
on the device. This is indexed by dot1dBasePort.”
AUGMENTS { dot1dBasePortEntry }
::= { dot1qPortVlanTable 1 }
dot1qPvid OBJECT-TYPE
SYNTAX VlanIndex
MAX-ACCESS read-write
STATUS current
DESCRIPTION
“The PVID, the VLAN-ID assigned to untagged frames or
Priority-Tagged frames received on this port.
The value of this object MUST be retained across
reinitializations of the management system.”
REFERENCE
“IEEE 802.1Q/D11 Section 12.10.1.1”
DEFVAL { 1 }
::= { dot1qPortVlanEntry 1 }
So walking the Q-BRIDGE MIB bridge port ifindexing and then walk the BRIDGE-MIB to get the mapping from the bridge port ifindex to the ifindex.

There’s confusion caused by the fact that the pvid rows (as are most things in these mibs) are indexed by the bridge port number index and this is not the ifIndex you see when running “ip link show”. For some reason, the MIB authors felt the need to use their own indices and just map them back to the ifIndex.

Here’s an example that may help: I have a bridge with ports configured like

auto bridge
iface bridge
bridge-ports swp1 swp2 swp3 swp4 swp53 swp54s2 swp54s3
bridge-vids 11 100-110 666
bridge-vlan-aware yes

I get the bridge port number to IfIndex mapping in the BRIDGE-MIB (these are indeed the ifindex one sees when running ‘ip link show’):

BRIDGE-MIB::dot1dBasePortIfIndex.1 = INTEGER: 3
BRIDGE-MIB::dot1dBasePortIfIndex.2 = INTEGER: 4
BRIDGE-MIB::dot1dBasePortIfIndex.3 = INTEGER: 5
BRIDGE-MIB::dot1dBasePortIfIndex.4 = INTEGER: 6
BRIDGE-MIB::dot1dBasePortIfIndex.5 = INTEGER: 55
BRIDGE-MIB::dot1dBasePortIfIndex.6 = INTEGER: 59
BRIDGE-MIB::dot1dBasePortIfIndex.7 = INTEGER: 60

and so when I look at the PVID rows, I see the PVID for each bridge port number
down in the Q-BRIDGE-MIB, I can see:

Q-BRIDGE-MIB::dot1qPvid.1 = Gauge32: 1
Q-BRIDGE-MIB::dot1qPvid.2 = Gauge32: 1
Q-BRIDGE-MIB::dot1qPvid.3 = Gauge32: 1
Q-BRIDGE-MIB::dot1qPvid.4 = Gauge32: 1
Q-BRIDGE-MIB::dot1qPvid.5 = Gauge32: 1
Q-BRIDGE-MIB::dot1qPvid.6 = Gauge32: 1
Q-BRIDGE-MIB::dot1qPvid.7 = Gauge32: 1

So what I think needs to be done is map:
ifIndex.3 < dot1dBasePortIfIndex.1 < dot1qPvid.1
Which would give us:
Front facing port 1 = vlan 141

Examples can be seen here

Every Vlan in this image needs to be shifted down 2 interfaces. LO and Eth0 shouldn’t have any vlan.

Btw, we already map dot1dBasePort to ifIndex in includes/discovery/vlans.inc.php

// get a map of base port to ifIndex and the inverse
$base_to_index = array();
$tmp_base_indexes = snmpwalk_cache_oid($device, 'dot1dBasePortIfIndex', array(), 'BRIDGE-MIB');
// flatten the array
foreach ($tmp_base_indexes as $index => $array) {
    $base_to_index[$index] = $array['dot1dBasePortIfIndex'];
}
$index_to_base = array_flip($base_to_index);

What is your issue?

The snmpwalk you have provided is not useful. Please use snmpbulkwalk -OUneb -v2c -c COMMUNITY HOSTNAME . as outlined here: https://docs.librenms.org/Support/FAQ/#faq20

Sorry @murrant, I should have caught that. I updated the original gist with the new walk. It’s also here if you don’t want to wade through that long page.

I used snmp v3 so hopefully I didn’t mess up the command. This is what I used, which looks good to me.
-bash-4.2$ /usr/bin/snmpbulkwalk -OUneb -v3 -l ‘authPriv’ -a ‘MD5’ -A pass -u username -x ‘DES’ -X pass as4610-1.company.com .

@murrant, I see what you are talking about now that I’m more familiar with this, but the vlan associations are for the wrong interface somehow. See the attached image above. The vlan associations are off by two interfaces. Eth0 and lo shouldn’t have a vlan association.

It looks like we are getting this association:
dot1dBasePortIfIndex.1 = ifIndex.1
When we want:
dot1dBasePortIfIndex.1 = ifIndex.3

When I look at the array I see:

Array
(
[1] => Array
    (
        [ifName] => lo
        ...
        [dot1qPvid] => 141 (This shouldn't have a vlan. This value should be for array entry 3)
    )

[2] => Array
    (
        [ifName] => eth0
         ...
        [dot1qPvid] => 5 ( This shouldn't have a vlan. This value should be for array entry 4)
    )

[3] => Array
    (
        [ifName] => swp1
         ...
        [dot1qPvid] => 141
    )

[4] => Array
    (
        [ifName] => swp2
        ...
        [dot1qPvid] => 141( This should be vlan 5 that was assigned to array entry 2)
    )

dot1dBasePortIfIndex.2 = 4 (So this is Front Facing Port 2. Should be vlan 5)

Here is part of the port config. You can see that dot1dBasePortIfIndex.2 is set to vlan 5.

`interfaces:auto lo
interfaces:iface lo inet loopback

interfaces:auto eth0
interfaces:iface eth0

interfaces:auto swp1
interfaces:iface swp1
interfaces: bridge-pvid 141
interfaces: bridge-vids 100

interfaces:auto swp2
interfaces:iface swp2
interfaces: bridge-pvid 5
interfaces: bridge-vids 100`

Maybe the issue lies with the array when combined with dot1dBasePortIfIndex not including loopback and eth0?

So using dot1dBasePortIfIndex.2 as an example, if you are saying this should be vlan 5 then isn’t the snmpwalk output showing it being 4 means that this is a bug with the snmp output?

@laf and @murrant , in regards to the questions you asked. Am I crazy or does this not make sense? I feel like something is getting lost in translation because it makes sense to me. I woudldn’t have wrote it that way but I believe it to be functioning correctly. I’ve read and re-read the walks, will you take a look at them and see if you come to the same conclusion? If you can spot an issue with it then I would be more than happy to open a case with Cumulus.

For Cumulus Vlan mapping would be
Cumulus
ifIndex.3 <-- dot1dBasePortIfIndex.1 <-- dot1qPvid.1

ifIndex.3 = 3
dot1dBasePortIfIndex.1 = 3
dot1qPvid.1= 141

So we fetch ifIndex.3 and it gives us 3.
We then fetch dot1dBasePortIfIndex.1 and it tells us it associates to ifIndex.3
We then fetch dot1qPvid.1 and it tells us it associates to dot1dBasePortIfIndex.1

This makes it a little easier to look at and search than just the oids https://gist.github.com/theherodied/dba2fd38f459bf4b6481f3ec75d92d23

@laf, I changed the vlan to 1234 on swp1 in hopes it will stick out more in the example.

ifIndex.3 = 3
dot1dBasePortIfIndex.1 = 3
dot1qPvid.1 = 1234

@murrant confirmed the mapping should currently be
ifIndex.3 <-- dot1dBasePortIfIndex.1 <-- dot1qPvid.1.
I believe the array is somehow giving the first ifindex entry the first array entry. And since lo and eth0 do not have dot1… entries I think it’s shifting up two.

ifDescr.1 = lo
ifDescr.2 = eth0
ifDescr.3 = swp1
ifDescr.4 = swp2
ifDescr.5 = swp3
ifDescr.6 = swp4
ifDescr.7 = swp5
ifDescr.8 = swp6
ifDescr.9 = swp7
ifDescr.10 = swp8
ifDescr.11 = swp9
ifDescr.12 = swp10
ifDescr.13 = swp11
ifDescr.14 = swp12
ifDescr.15 = swp13
ifDescr.16 = swp14
ifDescr.17 = swp15
ifDescr.18 = swp16
ifDescr.19 = swp17
ifDescr.20 = swp18
ifDescr.21 = swp19
ifDescr.22 = swp20
ifDescr.23 = swp21
ifDescr.24 = swp22
ifDescr.25 = swp23
ifDescr.26 = swp24
ifDescr.27 = swp25
ifDescr.28 = swp26
ifDescr.29 = swp27
ifDescr.30 = swp28
ifDescr.31 = swp29
ifDescr.32 = swp30
ifDescr.33 = swp31
ifDescr.34 = swp32
ifDescr.35 = swp33
ifDescr.36 = swp34
ifDescr.37 = swp35
ifDescr.38 = swp36
ifDescr.39 = swp37
ifDescr.40 = swp38
ifDescr.41 = swp39
ifDescr.42 = swp40
ifDescr.43 = swp41
ifDescr.44 = swp42
ifDescr.45 = swp43
ifDescr.46 = swp44
ifDescr.47 = swp45
ifDescr.48 = swp46
ifDescr.49 = swp47
ifDescr.50 = swp48
ifDescr.51 = swp49
ifDescr.52 = swp50
ifDescr.53 = swp51
ifDescr.54 = swp52
ifDescr.55 = upstream1
ifDescr.56 = bridge
ifDescr.57 = vlan1

-bash-4.2$ /usr/bin/snmpbulkwalk ifindex
ifIndex.1 = 1
ifIndex.2 = 2
ifIndex.3 = 3
ifIndex.4 = 4
ifIndex.5 = 5
ifIndex.6 = 6
ifIndex.7 = 7
ifIndex.8 = 8
ifIndex.9 = 9
ifIndex.10 = 10
ifIndex.11 = 11
ifIndex.12 = 12
ifIndex.13 = 13
ifIndex.14 = 14
ifIndex.15 = 15
ifIndex.16 = 16
ifIndex.17 = 17
ifIndex.18 = 18
ifIndex.19 = 19
ifIndex.20 = 20
ifIndex.21 = 21
ifIndex.22 = 22
ifIndex.23 = 23
ifIndex.24 = 24
ifIndex.25 = 25
ifIndex.26 = 26
ifIndex.27 = 27
ifIndex.28 = 28
ifIndex.29 = 29
ifIndex.30 = 30
ifIndex.31 = 31
ifIndex.32 = 32
ifIndex.33 = 33
ifIndex.34 = 34
ifIndex.35 = 35
ifIndex.36 = 36
ifIndex.37 = 37
ifIndex.38 = 38
ifIndex.39 = 39
ifIndex.40 = 40
ifIndex.41 = 41
ifIndex.42 = 42
ifIndex.43 = 43
ifIndex.44 = 44
ifIndex.45 = 45
ifIndex.46 = 46
ifIndex.47 = 47
ifIndex.48 = 48
ifIndex.49 = 49
ifIndex.50 = 50
ifIndex.51 = 51
ifIndex.52 = 52
ifIndex.53 = 53
ifIndex.54 = 54
ifIndex.55 = 55
ifIndex.56 = 56
ifIndex.57 = 57
-bash-4.2$ /usr/bin/snmpbulkwalk dot1dBasePortIfIndex
dot1dBasePortIfIndex.1 = 3
dot1dBasePortIfIndex.2 = 4
dot1dBasePortIfIndex.3 = 5
dot1dBasePortIfIndex.4 = 6
dot1dBasePortIfIndex.5 = 7
dot1dBasePortIfIndex.6 = 8
dot1dBasePortIfIndex.7 = 9
dot1dBasePortIfIndex.8 = 10
dot1dBasePortIfIndex.9 = 11
dot1dBasePortIfIndex.10 = 12
dot1dBasePortIfIndex.11 = 13
dot1dBasePortIfIndex.12 = 14
dot1dBasePortIfIndex.13 = 15
dot1dBasePortIfIndex.14 = 16
dot1dBasePortIfIndex.15 = 17
dot1dBasePortIfIndex.16 = 18
dot1dBasePortIfIndex.17 = 19
dot1dBasePortIfIndex.18 = 20
dot1dBasePortIfIndex.19 = 21
dot1dBasePortIfIndex.20 = 22
dot1dBasePortIfIndex.21 = 23
dot1dBasePortIfIndex.22 = 24
dot1dBasePortIfIndex.23 = 25
dot1dBasePortIfIndex.24 = 26
dot1dBasePortIfIndex.25 = 27
dot1dBasePortIfIndex.26 = 28
dot1dBasePortIfIndex.27 = 29
dot1dBasePortIfIndex.28 = 30
dot1dBasePortIfIndex.29 = 31
dot1dBasePortIfIndex.30 = 32
dot1dBasePortIfIndex.31 = 33
dot1dBasePortIfIndex.32 = 34
dot1dBasePortIfIndex.33 = 35
dot1dBasePortIfIndex.34 = 36
dot1dBasePortIfIndex.35 = 37
dot1dBasePortIfIndex.36 = 38
dot1dBasePortIfIndex.37 = 39
dot1dBasePortIfIndex.38 = 40
dot1dBasePortIfIndex.39 = 41
dot1dBasePortIfIndex.40 = 42
dot1dBasePortIfIndex.41 = 43
dot1dBasePortIfIndex.42 = 44
dot1dBasePortIfIndex.43 = 45
dot1dBasePortIfIndex.44 = 46
dot1dBasePortIfIndex.45 = 47
dot1dBasePortIfIndex.46 = 48
dot1dBasePortIfIndex.47 = 49
dot1dBasePortIfIndex.48 = 50
dot1dBasePortIfIndex.49 = 55
-bash-4.2$ /usr/bin/snmpbulkwalk dot1qpvid
dot1qPvid.1 = 1234
dot1qPvid.2 = 5
dot1qPvid.3 = 141
dot1qPvid.4 = 141
dot1qPvid.5 = 141
dot1qPvid.6 = 141
dot1qPvid.7 = 141
dot1qPvid.8 = 141
dot1qPvid.9 = 141
dot1qPvid.10 = 141
dot1qPvid.11 = 141
dot1qPvid.12 = 141
dot1qPvid.13 = 141
dot1qPvid.14 = 141
dot1qPvid.15 = 141
dot1qPvid.16 = 141
dot1qPvid.17 = 141
dot1qPvid.18 = 141
dot1qPvid.19 = 141
dot1qPvid.20 = 141
dot1qPvid.21 = 141
dot1qPvid.22 = 141
dot1qPvid.23 = 141
dot1qPvid.24 = 141
dot1qPvid.25 = 141
dot1qPvid.26 = 141
dot1qPvid.27 = 141
dot1qPvid.28 = 141
dot1qPvid.29 = 141
dot1qPvid.30 = 141
dot1qPvid.31 = 141
dot1qPvid.32 = 141
dot1qPvid.33 = 141
dot1qPvid.34 = 141
dot1qPvid.35 = 141
dot1qPvid.36 = 141
dot1qPvid.37 = 141
dot1qPvid.38 = 141
dot1qPvid.39 = 141
dot1qPvid.40 = 141
dot1qPvid.41 = 141
dot1qPvid.42 = 141
dot1qPvid.43 = 141
dot1qPvid.44 = 141
dot1qPvid.45 = 141
dot1qPvid.46 = 141
dot1qPvid.47 = 5
dot1qPvid.48 = 50
dot1qPvid.49 = 1

But it’s giving me this array:

Array
(
[1] => Array
(
[ifName] => lo
[ifInMulticastPkts] => 0
[ifInBroadcastPkts] => 0
[ifOutMulticastPkts] => 0
[ifOutBroadcastPkts] => 0
[ifHCInOctets] => 2218
[ifHCInUcastPkts] => 0
[ifHCInMulticastPkts] => 0
[ifHCInBroadcastPkts] => 0
[ifHCOutOctets] => 2218
[ifHCOutUcastPkts] => 10
[ifHCOutMulticastPkts] => 0
[ifHCOutBroadcastPkts] => 0
[ifHighSpeed] => 10
[ifPromiscuousMode] => false
[ifConnectorPresent] => false
[ifAlias] => lo
[ifCounterDiscontinuityTime] => 0:0:00:00.00
[ifDescr] => lo
[ifAdminStatus] => up
[ifOperStatus] => up
[ifLastChange] => 106406749
[ifType] => softwareLoopback
[ifPhysAddress] =>
[ifMtu] => 65536
[ifInErrors] => 0
[ifOutErrors] => 0
[ifInDiscards] => 0
[ifOutDiscards] => 0
[dot1qPvid] => 1234
)
[2] => Array
(
[ifName] => eth0
[ifInMulticastPkts] => 0
[ifInBroadcastPkts] => 0
[ifOutMulticastPkts] => 0
[ifOutBroadcastPkts] => 0
[ifHCInOctets] => 0
[ifHCInUcastPkts] => 0
[ifHCInMulticastPkts] => 0
[ifHCInBroadcastPkts] => 0
[ifHCOutOctets] => 0
[ifHCOutUcastPkts] => 0
[ifHCOutMulticastPkts] => 0
[ifHCOutBroadcastPkts] => 0
[ifHighSpeed] => 0
[ifPromiscuousMode] => false
[ifConnectorPresent] => true
[ifAlias] => eth0
[ifCounterDiscontinuityTime] => 0:0:00:00.00
[ifDescr] => eth0
[ifAdminStatus] => up
[ifOperStatus] => down
[ifLastChange] => 106406749
[ifType] => ethernetCsmacd
[ifPhysAddress] => 8c:ea:1b:fb:92:80
[ifMtu] => 1500
[ifInErrors] => 0
[ifOutErrors] => 0
[ifInDiscards] => 0
[ifOutDiscards] => 0
[dot1qPvid] => 5
)
[3] => Array
(
[ifName] => swp1
[ifInMulticastPkts] => 0
[ifInBroadcastPkts] => 0
[ifOutMulticastPkts] => 0
[ifOutBroadcastPkts] => 0
[ifHCInOctets] => 0
[ifHCInUcastPkts] => 0
[ifHCInMulticastPkts] => 0
[ifHCInBroadcastPkts] => 0
[ifHCOutOctets] => 0
[ifHCOutUcastPkts] => 0
[ifHCOutMulticastPkts] => 0
[ifHCOutBroadcastPkts] => 0
[ifHighSpeed] => 0
[ifPromiscuousMode] => false
[ifConnectorPresent] => true
[ifAlias] => swp1
[ifCounterDiscontinuityTime] => 0:0:00:00.00
[ifDescr] => swp1
[ifAdminStatus] => up
[ifOperStatus] => down
[ifLastChange] => 106406749
[ifType] => ethernetCsmacd
[ifPhysAddress] => 8c:ea:1b:fb:92:81
[ifMtu] => 1500
[ifInErrors] => 0
[ifOutErrors] => 0
[ifInDiscards] => 0
[ifOutDiscards] => 0
[dot3StatsDuplexStatus] => unknown
[dot1qPvid] => 141
)
[4] => Array
(
[ifName] => swp2
[ifInMulticastPkts] => 0
[ifInBroadcastPkts] => 0
[ifOutMulticastPkts] => 0
[ifOutBroadcastPkts] => 0
[ifHCInOctets] => 0
[ifHCInUcastPkts] => 0
[ifHCInMulticastPkts] => 0
[ifHCInBroadcastPkts] => 0
[ifHCOutOctets] => 0
[ifHCOutUcastPkts] => 0
[ifHCOutMulticastPkts] => 0
[ifHCOutBroadcastPkts] => 0
[ifHighSpeed] => 0
[ifPromiscuousMode] => false
[ifConnectorPresent] => true
[ifAlias] => swp2
[ifCounterDiscontinuityTime] => 0:0:00:00.00
[ifDescr] => swp2
[ifAdminStatus] => up
[ifOperStatus] => down
[ifLastChange] => 106406749
[ifType] => ethernetCsmacd
[ifPhysAddress] => 8c:ea:1b:fb:92:82
[ifMtu] => 1500
[ifInErrors] => 0
[ifOutErrors] => 0
[ifInDiscards] => 0
[ifOutDiscards] => 0
[dot3StatsDuplexStatus] => unknown
[dot1qPvid] => 141
)

Meant ifIndex 4 = swp2 = vlan 5

Take a look at what I posted a minute ago with the walks and arrays. I think that shows the issue pretty well.