I had a play with this and I think I got most of the way there. Here's generator.yml:
modules:
bridge_mib:
walk:
- dot1dBasePortTable
- dot1dTpFdbTable
lookups:
- source_indexes: [dot1dTpFdbAddress]
lookup: dot1dTpFdbPort
- source_indexes: [dot1dTpFdbPort]
lookup: dot1dBasePortIfIndex
overrides:
dot1dBasePort:
ignore: true
dot1dTpFdbStatus:
type: EnumAsInfo
dot1dTpFdbPort:
ignore: true
Here's the snmp.yml that it creates:
# WARNING: This file was auto-generated using snmp_exporter generator, manual changes will be lost.
modules:
bridge_mib:
walk:
- 1.3.6.1.2.1.17.1.4
- 1.3.6.1.2.1.17.4.3
metrics:
- name: dot1dBasePortIfIndex
oid: 1.3.6.1.2.1.17.1.4.1.2
type: gauge
help: The value of the instance of the ifIndex object, defined in IF-MIB, for
the interface corresponding to this port. - 1.3.6.1.2.1.17.1.4.1.2
indexes:
- labelname: dot1dBasePort
type: gauge
- name: dot1dBasePortCircuit
oid: 1.3.6.1.2.1.17.1.4.1.3
type: OctetString
help: For a port that (potentially) has the same value of dot1dBasePortIfIndex
as another port on the same bridge - 1.3.6.1.2.1.17.1.4.1.3
indexes:
- labelname: dot1dBasePort
type: gauge
- name: dot1dBasePortDelayExceededDiscards
oid: 1.3.6.1.2.1.17.1.4.1.4
type: counter
help: The number of frames discarded by this port due to excessive transit delay
through the bridge - 1.3.6.1.2.1.17.1.4.1.4
indexes:
- labelname: dot1dBasePort
type: gauge
- name: dot1dBasePortMtuExceededDiscards
oid: 1.3.6.1.2.1.17.1.4.1.5
type: counter
help: The number of frames discarded by this port due to an excessive size -
1.3.6.1.2.1.17.1.4.1.5
indexes:
- labelname: dot1dBasePort
type: gauge
- name: dot1dTpFdbAddress
oid: 1.3.6.1.2.1.17.4.3.1.1
type: PhysAddress48
help: A unicast MAC address for which the bridge has forwarding and/or filtering
information. - 1.3.6.1.2.1.17.4.3.1.1
indexes:
- labelname: dot1dTpFdbAddress
type: PhysAddress48
fixed_size: 6
- labelname: dot1dTpFdbPort
type: gauge
lookups:
- labels:
- dot1dTpFdbAddress
labelname: dot1dTpFdbPort
oid: 1.3.6.1.2.1.17.4.3.1.2
type: gauge
- labels:
- dot1dTpFdbPort
labelname: dot1dBasePortIfIndex
oid: 1.3.6.1.2.1.17.1.4.1.2
type: gauge
- name: dot1dTpFdbStatus
oid: 1.3.6.1.2.1.17.4.3.1.3
type: EnumAsInfo
help: The status of this entry - 1.3.6.1.2.1.17.4.3.1.3
indexes:
- labelname: dot1dTpFdbAddress
type: PhysAddress48
fixed_size: 6
- labelname: dot1dTpFdbPort
type: gauge
lookups:
- labels:
- dot1dTpFdbAddress
labelname: dot1dTpFdbPort
oid: 1.3.6.1.2.1.17.4.3.1.2
type: gauge
- labels:
- dot1dTpFdbPort
labelname: dot1dBasePortIfIndex
oid: 1.3.6.1.2.1.17.1.4.1.2
type: gauge
enum_values:
1: other
2: invalid
3: learned
4: self
5: mgmt
Output:
# HELP dot1dBasePortCircuit For a port that (potentially) has the same value of dot1dBasePortIfIndex as another port on the same bridge - 1.3.6.1.2.1.17.1.4.1.3
# TYPE dot1dBasePortCircuit gauge
dot1dBasePortCircuit{dot1dBasePort="15",dot1dBasePortCircuit="0.0"} 1
dot1dBasePortCircuit{dot1dBasePort="16",dot1dBasePortCircuit="0.0"} 1
dot1dBasePortCircuit{dot1dBasePort="17",dot1dBasePortCircuit="0.0"} 1
...
# HELP dot1dBasePortIfIndex The value of the instance of the ifIndex object, defined in IF-MIB, for the interface corresponding to this port. - 1.3.6.1.2.1.17.1.4.1.2
# TYPE dot1dBasePortIfIndex gauge
dot1dBasePortIfIndex{dot1dBasePort="15"} 6
dot1dBasePortIfIndex{dot1dBasePort="16"} 7
dot1dBasePortIfIndex{dot1dBasePort="17"} 8
...
# HELP dot1dTpFdbAddress A unicast MAC address for which the bridge has forwarding and/or filtering information. - 1.3.6.1.2.1.17.4.3.1.1
# TYPE dot1dTpFdbAddress gauge
dot1dTpFdbAddress{dot1dBasePortIfIndex="",dot1dTpFdbAddress="XX:XX:XX:9C:3A:06",dot1dTpFdbPort="0"} 1
dot1dTpFdbAddress{dot1dBasePortIfIndex="10",dot1dTpFdbAddress="XX:XX:XX:5F:6C:B2",dot1dTpFdbPort="23"} 1
dot1dTpFdbAddress{dot1dBasePortIfIndex="10",dot1dTpFdbAddress="XX:XX:XX:81:98:C4",dot1dTpFdbPort="23"} 1
...
# HELP dot1dTpFdbStatus_info The status of this entry - 1.3.6.1.2.1.17.4.3.1.3 (EnumAsInfo)
# TYPE dot1dTpFdbStatus_info gauge
dot1dTpFdbStatus_info{dot1dBasePortIfIndex="",dot1dTpFdbAddress="XX:XX:XX:9C:3A:06",dot1dTpFdbPort="0",dot1dTpFdbStatus="self"} 1
dot1dTpFdbStatus_info{dot1dBasePortIfIndex="10",dot1dTpFdbAddress="XX:XX:XX:5F:6C:B2",dot1dTpFdbPort="23",dot1dTpFdbStatus="learned"} 1
dot1dTpFdbStatus_info{dot1dBasePortIfIndex="10",dot1dTpFdbAddress="XX:XX:XX:81:98:C4",dot1dTpFdbPort="23",dot1dTpFdbStatus="learned"} 1
...
I think dot1dTpFdbAddress now gives more or less what you want. A few niggles:
(1) I would like to change "dot1dBasePortIfIndex" to "ifIndex" to make joins easier, without having to use label_replace(). I couldn't see a way to rename a metric in snmp_exporter.
(2) I would like to merge the enumerated dot1dTpFdbStatus strings into dot1dTpFdbAddress. However if I add this:
lookups:
- source_indexes: [dot1dTpFdbAddress]
lookup: dot1dTpFdbPort
- source_indexes: [dot1dTpFdbAddress]
lookup: dot1dTpFdbStatus
- source_indexes: [dot1dTpFdbPort]
lookup: dot1dBasePortIfIndex
then I get scraping errors, e.g.
* error collecting metric Desc{fqName: "snmp_error", help: "Error calling NewConstMetric for EnumAsInfo", constLabels: {}, variableLabels: {}}: error for metric dot1dTpFdbStatus with labels [9 3 5 XX:XX:XX:27:29:BA learned]: duplicate label names in constant and variable labels for metric "dot1dTpFdbStatus_info"
If I remove the override
dot1dTpFdbStatus:
type: EnumAsInfo
then scraping works, but I only get the numeric status code e.g. dot1dTpFdbStatus="3"
-------
Note that if you want to avoid the join in PromQL, you *can* walk if[X]Table as well:
modules:
bridge_mib:
walk:
- dot1dBasePortTable
- dot1dTpFdbTable
- ifIndex
- ifAlias
- 1.3.6.1.2.1.2.2.1.2
- 1.3.6.1.2.1.31.1.1.1.1
lookups:
- source_indexes: [dot1dTpFdbAddress]
lookup: dot1dTpFdbPort
- source_indexes: [dot1dTpFdbPort]
lookup: dot1dBasePortIfIndex
- source_indexes: [dot1dBasePortIfIndex]
lookup: ifIndex
drop_source_indexes: true
- source_indexes: [ifIndex]
lookup: ifAlias
- source_indexes: [ifIndex]
# Uis OID to avoid conflict with PaloAlto PAN-COMMON-MIB.
lookup: 1.3.6.1.2.1.2.2.1.2 # ifDescr
- source_indexes: [ifIndex]
# Use OID to avoid conflict with Netscaler NS-ROOT-MIB.
lookup: 1.3.6.1.2.1.31.1.1.1.1 # ifName
overrides:
dot1dBasePort:
ignore: true
dot1dTpFdbStatus:
type: EnumAsInfo
dot1dTpFdbPort:
ignore: true
ifAlias:
ignore: true
ifDescr:
ignore: true
ifName:
ignore: true
In this case, dot1dTpFdbAddress includes ifIndex *and* the other interface info, which makes the metric rather convenient to use:
# HELP dot1dTpFdbAddress A unicast MAC address for which the bridge has forwarding and/or filtering information. - 1.3.6.1.2.1.17.4.3.1.1
# TYPE dot1dTpFdbAddress gauge
dot1dTpFdbAddress{dot1dTpFdbAddress="XX:XX:XX:C5:A2:F2",dot1dTpFdbPort="9",ifAlias="",ifDescr="ether5",ifIndex="5",ifName="ether5"} 1
dot1dTpFdbAddress{dot1dTpFdbAddress="XX:XX:XX:12:91:4B",dot1dTpFdbPort="6",ifAlias="",ifDescr="ether2",ifIndex="2",ifName="ether2"} 1
dot1dTpFdbAddress{dot1dTpFdbAddress="XX:XX:XX:27:FE:A9",dot1dTpFdbPort="6",ifAlias="",ifDescr="ether2",ifIndex="2",ifName="ether2"} 1
...
But I suspect that if you're scraping if_mib as well, then snmp_exporter will end up walking bits of ifTable/ifXTable twice, making it less efficient network-wise.