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"}
 
1dot1dTpFdbAddress{dot1dBasePortIfIndex="10",dot1dTpFdbAddress="XX:XX:XX:5F:6C:B2",dot1dTpFdbPort="23"}
 
1dot1dTpFdbAddress{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.

On Saturday 20 July 2024 at 10:20:53 UTC+1 Brian Candler wrote:

> I found a relevant issue: 
> https://github.com/prometheus/snmp_exporter/issues/405
>
> Firstly, the PromQL count_values 
> <https://prometheus.io/docs/prometheus/latest/querying/operators/#aggregation-operators>
>  
> operator can be used to convert a metric value to a label (very neat trick).
>
> And secondly, the ability to do "chainable lookups" was added:
> https://github.com/prometheus/snmp_exporter/pull/527/files
> This might be a way to solve this in the exporter - but I haven't got my 
> head around this. I'm not sure if you'd need to walk ifTable in your 
> generator, even if you're not actually interested in any additional values 
> from ifTable.
>
> On Saturday 20 July 2024 at 09:48:26 UTC+1 Brian Candler wrote:
>
>> > dot1dBasePortIfIndex{dot1dBasePort="12"} 12  - *This won't always be 
>> the same number*
>>
>> The MIB help text says "The value of the instance of the ifIndex object". 
>> So I'm guessing that what you currently get as
>>
>>     dot1dBasePortIfIndex{dot1dBasePort="12"} 42
>>
>> would be more usefully returned as
>>
>>     dot1dBasePortIfIndex{dot1dBasePort="12",ifIndex="42"} 1
>>
>> But I'm afraid I don't have enough generator.yml foo to know how to do 
>> that :-(
>>
>> On Thursday 18 July 2024 at 20:04:35 UTC+1 Matthew Koch wrote:
>>
>>>
>>> *This is a physical port ifIndex example*
>>>
>>> ifAdminStatus{ifAlias="Device; Device 
>>> (DEVICE)",ifDescr="GigabitEthernet1/12",ifIndex="12",ifName="Gi1/12"} 1
>>>
>>>
>>> *1. dot1dBasePortIfIndex is an equivalent of ifIndex but dot1dBasePort 
>>> is not. dot1dBasePort is used to get the MAC address. *
>>>
>>> dot1dBasePortIfIndex{dot1dBasePort="12"} 12  - *This won't always be 
>>> the same number*
>>>
>>> *2. I get the MAC address and port pair from this*
>>>
>>> dot1dTpFdbPort{dot1dTpFdbAddress="11:E0:E4:66:5E:11"} 12
>>>
>>>
>>> *3.  I get the MAC address and IP pair from this. But 
>>> the ipNetToMediaIfIndex is a VLAN not a physical port. *
>>>
>>> ipNetToMediaPhysAddress{ipNetToMediaIfIndex="28",ipNetToMediaNetAddress="
>>> 10.10.1.33",ipNetToMediaPhysAddress="11:E0:E4:66:5E:11"} 1
>>>
>>>
>>>
>>> On Thursday, July 18, 2024 at 2:42:10 PM UTC-4 Brian Candler wrote:
>>>
>>>> > The challenge I am having is using promql to join the data so I can 
>>>> show the IP associated with the MAC address on the physical port. 
>>>>
>>>> Can you show some examples of the metrics you're trying to join?
>>>>
>>>> On Thursday 18 July 2024 at 18:48:35 UTC+1 Matthew Koch wrote:
>>>>
>>>>> I am working on a project to gather the MAC address and IP which is on 
>>>>> a specific port on a network switch. I've been able to gather this 
>>>>> information with the below SNMP config but the challenge is the MAC 
>>>>> address 
>>>>> comes back against the physical port index and the IPs come back against 
>>>>> the VLANs index which is expected. The challenge I am having is using 
>>>>> promql to join the data so I can show the IP associated with the MAC 
>>>>> address on the physical port. 
>>>>>
>>>>>  walk:
>>>>>     - 1.3.6.1.2.1.17.1.4.1
>>>>>     - 1.3.6.1.2.1.17.4.3.1
>>>>>     - 1.3.6.1.2.1.4.22.1
>>>>>     - 1.3.6.1.2.1.4.35.1
>>>>>     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 MIB-II, for
>>>>>         the interface corresponding to this port. - 
>>>>> 1.3.6.1.2.1.17.1.4.1.2
>>>>>       indexes:
>>>>>       - labelname: dot1dBasePort
>>>>>         type: gauge
>>>>>     - name: dot1dTpFdbPort
>>>>>       oid: 1.3.6.1.2.1.17.4.3.1.2
>>>>>       type: gauge
>>>>>       help: Either the value '0', or the port number of the port on 
>>>>> which a frame
>>>>>         having a source address equal to the value of the 
>>>>> corresponding instance of
>>>>>         dot1dTpFdbAddress has been seen - 1.3.6.1.2.1.17.4.3.1.2
>>>>>       indexes:
>>>>>       - labelname: dot1dTpFdbAddress
>>>>>         type: PhysAddress48
>>>>>         fixed_size: 6
>>>>>     - 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
>>>>>       enum_values:
>>>>>         1: other
>>>>>         2: invalid
>>>>>         3: learned
>>>>>         4: self
>>>>>         5: mgmt
>>>>>     - name: ipNetToMediaPhysAddress
>>>>>       oid: 1.3.6.1.2.1.4.22.1.2
>>>>>       type: PhysAddress48
>>>>>       help: ' - 1.3.6.1.2.1.4.22.1.2'
>>>>>       indexes:
>>>>>       - labelname: ipNetToMediaIfIndex
>>>>>         type: gauge
>>>>>       - labelname: ipNetToMediaNetAddress
>>>>>         type: InetAddressIPv4
>>>>>     - name: ipNetToMediaType
>>>>>       oid: 1.3.6.1.2.1.4.22.1.4
>>>>>       type: EnumAsInfo
>>>>>       help: ' - 1.3.6.1.2.1.4.22.1.4'
>>>>>       indexes:
>>>>>       - labelname: ipNetToMediaIfIndex
>>>>>         type: gauge
>>>>>       - labelname: ipNetToMediaNetAddress
>>>>>         type: InetAddressIPv4
>>>>>       enum_values:
>>>>>         1: other
>>>>>         2: invalid
>>>>>         3: dynamic
>>>>>         4: static
>>>>>     - name: ipNetToPhysicalIfIndex
>>>>>       oid: 1.3.6.1.2.1.4.35.1.1
>>>>>       type: gauge
>>>>>       help: The index value that uniquely identifies the interface to 
>>>>> which this entry
>>>>>         is applicable - 1.3.6.1.2.1.4.35.1.1
>>>>>       indexes:
>>>>>       - labelname: ipNetToPhysicalIfIndex
>>>>>         type: gauge
>>>>>       - labelname: ipNetToPhysicalNetAddress
>>>>>         type: InetAddress
>>>>>     - name: ipNetToPhysicalNetAddressType
>>>>>       oid: 1.3.6.1.2.1.4.35.1.2
>>>>>       type: EnumAsInfo
>>>>>       help: The type of ipNetToPhysicalNetAddress. - 
>>>>> 1.3.6.1.2.1.4.35.1.2
>>>>>       indexes:
>>>>>       - labelname: ipNetToPhysicalIfIndex
>>>>>         type: gauge
>>>>>       - labelname: ipNetToPhysicalNetAddress
>>>>>         type: InetAddress
>>>>>       enum_values:
>>>>>         0: unknown
>>>>>         1: ipv4
>>>>>         2: ipv6
>>>>>         3: ipv4z
>>>>>         4: ipv6z
>>>>>         16: dns
>>>>>     - name: ipNetToPhysicalNetAddress
>>>>>       oid: 1.3.6.1.2.1.4.35.1.3
>>>>>       type: InetAddress
>>>>>       help: The IP Address corresponding to the media-dependent 
>>>>> `physical' address
>>>>>         - 1.3.6.1.2.1.4.35.1.3
>>>>>       indexes:
>>>>>       - labelname: ipNetToPhysicalIfIndex
>>>>>         type: gauge
>>>>>       - labelname: ipNetToPhysicalNetAddress
>>>>>         type: InetAddress
>>>>>     - name: ipNetToPhysicalPhysAddress
>>>>>       oid: 1.3.6.1.2.1.4.35.1.4
>>>>>       type: PhysAddress48
>>>>>       help: The media-dependent `physical' address - 
>>>>> 1.3.6.1.2.1.4.35.1.4
>>>>>       indexes:
>>>>>       - labelname: ipNetToPhysicalIfIndex
>>>>>         type: gauge
>>>>>       - labelname: ipNetToPhysicalNetAddress
>>>>>         type: InetAddress
>>>>>     - name: ipNetToPhysicalLastUpdated
>>>>>       oid: 1.3.6.1.2.1.4.35.1.5
>>>>>       type: gauge
>>>>>       help: The value of sysUpTime at the time this entry was last 
>>>>> updated - 1.3.6.1.2.1.4.35.1.5
>>>>>       indexes:
>>>>>       - labelname: ipNetToPhysicalIfIndex
>>>>>         type: gauge
>>>>>       - labelname: ipNetToPhysicalNetAddress
>>>>>         type: InetAddress
>>>>>     - name: ipNetToPhysicalType
>>>>>       oid: 1.3.6.1.2.1.4.35.1.6
>>>>>       type: EnumAsInfo
>>>>>       help: The type of mapping - 1.3.6.1.2.1.4.35.1.6
>>>>>       indexes:
>>>>>       - labelname: ipNetToPhysicalIfIndex
>>>>>         type: gauge
>>>>>       - labelname: ipNetToPhysicalNetAddress
>>>>>         type: InetAddress
>>>>>       enum_values:
>>>>>         1: other
>>>>>         2: invalid
>>>>>         3: dynamic
>>>>>         4: static
>>>>>         5: local
>>>>>     - name: ipNetToPhysicalState
>>>>>       oid: 1.3.6.1.2.1.4.35.1.7
>>>>>       type: EnumAsInfo
>>>>>       help: The Neighbor Unreachability Detection state for the 
>>>>> interface when the
>>>>>         address mapping in this entry is used - 1.3.6.1.2.1.4.35.1.7
>>>>>       indexes:
>>>>>       - labelname: ipNetToPhysicalIfIndex
>>>>>         type: gauge
>>>>>       - labelname: ipNetToPhysicalNetAddress
>>>>>         type: InetAddress
>>>>>       enum_values:
>>>>>         1: reachable
>>>>>         2: stale
>>>>>         3: delay
>>>>>         4: probe
>>>>>         5: invalid
>>>>>         6: unknown
>>>>>         7: incomplete
>>>>>     - name: ipNetToPhysicalRowStatus
>>>>>       oid: 1.3.6.1.2.1.4.35.1.8
>>>>>       type: EnumAsInfo
>>>>>       help: The status of this conceptual row - 1.3.6.1.2.1.4.35.1.8
>>>>>       indexes:
>>>>>       - labelname: ipNetToPhysicalIfIndex
>>>>>         type: gauge
>>>>>       - labelname: ipNetToPhysicalNetAddress
>>>>>         type: InetAddress
>>>>>       enum_values:
>>>>>         1: active
>>>>>         2: notInService
>>>>>         3: notReady
>>>>>         4: createAndGo
>>>>>         5: createAndWait
>>>>>         6: destroy
>>>>>
>>>>

-- 
You received this message because you are subscribed to the Google Groups 
"Prometheus Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/prometheus-users/b912bd42-0b50-48ab-a71c-4675cb895405n%40googlegroups.com.

Reply via email to