network-programmingdevopssnmpinfrastructurepdu

snmpget returns successfully, yet snmpset claims the same OID does not exist


I'm working with a CyberPower PDU: https://www.cyberpowersystems.com/product/pdu/switched-ats/pdu15swhviec12atnet/

According to snmpwalk -v1 -m CyberPower_MIB_v2.9.MIB -c public 10.42.0.2 iso.3.6.1.4.1.3808, the management card model is RMCARD205 and the full model name is PDU15SWHVIEC12ATNET.

I would like to programmatically control the power to the ports, doing this via SNMP seems the most robust option. I can query the status of port 3 (say) with,

# snmpget -v1 -c private 10.42.0.2 iso.3.6.1.4.1.3808.1.1.5.6.3.1.3.3
SNMPv2-SMI::enterprises.3808.1.1.5.6.3.1.3.3 = INTEGER: 2

That is, the OID iso.3.6.1.4.1.3808.1.1.5.6.3.1.3.3 clearly exists and has the value of 2 (which means OFF in this case). Now, let me set it to 1 (meaning ON), with an integer value type (encoded as i in SNMP),

snmpset -v1 -c private 10.42.0.2 iso.3.6.1.4.1.3808.1.1.5.6.3.1.3.3 i 1
Error in packet.
Reason: (noSuchName) There is no such variable name in this MIB.
Failed object: SNMPv2-SMI::enterprises.3808.1.1.5.6.3.1.3.3

I found in this SO question an answer suggesting it's not at all uncommon for these devices to have bugs, but the behaviour was a bit different to what I've got here. Similarly, the SNMP FAQ didn't offer any specific advice on this issue for me.

It seems the above interactions are proof that the device is faulty, but SNMP is sufficiently nuts that I wouldn't be surprised if there's some weird thing I should actually be doing to get this to work.


Solution

  • I found the answer to my question and will post some details here, in case others are as confused as I was!

    The first tip is to use the device manufacturers MIB files. CyberPower published a single MIB file (which is basically a textual description of all the properties in the hardware devices) that allows the net-snmp tools to print descriptive names for the otherwise opaque OIDs. For example, to see what I was attempting to set above, after downloading the MIB file into the current working directory,

    # snmpwalk -v1 -c private -M +.  -m ALL  10.42.0.2 iso.3.6.1.4.1.3808.1.1.5.6.3.1.3
    CPS-MIB::atsOutletStatusOutletState.1 = INTEGER: outletStatusOn(1)
    CPS-MIB::atsOutletStatusOutletState.2 = INTEGER: outletStatusOn(1)
    CPS-MIB::atsOutletStatusOutletState.3 = INTEGER: outletStatusOff(2)
    CPS-MIB::atsOutletStatusOutletState.4 = INTEGER: outletStatusOff(2)
    CPS-MIB::atsOutletStatusOutletState.5 = INTEGER: outletStatusOn(1)
    CPS-MIB::atsOutletStatusOutletState.6 = INTEGER: outletStatusOn(1)
    CPS-MIB::atsOutletStatusOutletState.7 = INTEGER: outletStatusOn(1)
    CPS-MIB::atsOutletStatusOutletState.8 = INTEGER: outletStatusOn(1)
    CPS-MIB::atsOutletStatusOutletState.9 = INTEGER: outletStatusOn(1)
    CPS-MIB::atsOutletStatusOutletState.10 = INTEGER: outletStatusOn(1)
    CPS-MIB::atsOutletStatusOutletState.11 = INTEGER: outletStatusOn(1)
    CPS-MIB::atsOutletStatusOutletState.12 = INTEGER: outletStatusOn(1)
    

    At first this seemed like the right place to change the statuses, but this PDU, unlike others I've encountered, has a separate OID tree for control operations, in addition to the above OID tree for status operations,

    # snmpwalk -v1 -c private -M +.  -m ALL  10.42.0.2 iso.3.6.1.4.1.3808.1.1.5.6.5
    CPS-MIB::atsOutletCtrlTableIndex.1 = INTEGER: 1
    CPS-MIB::atsOutletCtrlTableIndex.2 = INTEGER: 2
    CPS-MIB::atsOutletCtrlTableIndex.3 = INTEGER: 3
    CPS-MIB::atsOutletCtrlTableIndex.4 = INTEGER: 4
    CPS-MIB::atsOutletCtrlTableIndex.5 = INTEGER: 5
    CPS-MIB::atsOutletCtrlTableIndex.6 = INTEGER: 6
    CPS-MIB::atsOutletCtrlTableIndex.7 = INTEGER: 7
    CPS-MIB::atsOutletCtrlTableIndex.8 = INTEGER: 8
    CPS-MIB::atsOutletCtrlTableIndex.9 = INTEGER: 9
    CPS-MIB::atsOutletCtrlTableIndex.10 = INTEGER: 10
    CPS-MIB::atsOutletCtrlTableIndex.11 = INTEGER: 11
    CPS-MIB::atsOutletCtrlTableIndex.12 = INTEGER: 12
    CPS-MIB::atsOutletCtrlOutletName.1 = STRING: "Outlet1"
    CPS-MIB::atsOutletCtrlOutletName.2 = STRING: "Outlet2"
    CPS-MIB::atsOutletCtrlOutletName.3 = STRING: "Outlet3"
    CPS-MIB::atsOutletCtrlOutletName.4 = STRING: "Outlet4"
    CPS-MIB::atsOutletCtrlOutletName.5 = STRING: "Outlet5"
    CPS-MIB::atsOutletCtrlOutletName.6 = STRING: "Outlet6"
    CPS-MIB::atsOutletCtrlOutletName.7 = STRING: "Outlet7"
    CPS-MIB::atsOutletCtrlOutletName.8 = STRING: "Outlet8"
    CPS-MIB::atsOutletCtrlOutletName.9 = STRING: "Outlet9"
    CPS-MIB::atsOutletCtrlOutletName.10 = STRING: "Outlet10"
    CPS-MIB::atsOutletCtrlOutletName.11 = STRING: "Outlet11"
    CPS-MIB::atsOutletCtrlOutletName.12 = STRING: "Outlet12"
    CPS-MIB::atsOutletCtrlCommand.1 = INTEGER: none(1)
    CPS-MIB::atsOutletCtrlCommand.2 = INTEGER: none(1)
    CPS-MIB::atsOutletCtrlCommand.3 = INTEGER: none(1)
    CPS-MIB::atsOutletCtrlCommand.4 = INTEGER: none(1)
    CPS-MIB::atsOutletCtrlCommand.5 = INTEGER: none(1)
    CPS-MIB::atsOutletCtrlCommand.6 = INTEGER: none(1)
    CPS-MIB::atsOutletCtrlCommand.7 = INTEGER: none(1)
    CPS-MIB::atsOutletCtrlCommand.8 = INTEGER: none(1)
    CPS-MIB::atsOutletCtrlCommand.9 = INTEGER: none(1)
    CPS-MIB::atsOutletCtrlCommand.10 = INTEGER: none(1)
    CPS-MIB::atsOutletCtrlCommand.11 = INTEGER: none(1)
    CPS-MIB::atsOutletCtrlCommand.12 = INTEGER: none(1)
    

    It is the CPS-MIB::atsOutletCtrlCommand tree that can be set, to change the outlet state, by doing the following,

    # snmpset -M +. -m ALL -v1 -c private 10.42.0.2 SNMPv2-SMI::enterprises.3808.1.1.5.6.5.1.3.3 i 3
    CPS-MIB::atsOutletCtrlCommand.3 = INTEGER: immediateOff(3)
    

    And the port changes state. The state mappings can be found by consulting the MIB file mentioned above (in this reading, a file named CyberPower_MIB_v2.9.MIB). For example, I found the following definitions which helped me learn which integer represents off/on and so on,

    ...
    atsOutletCtrlCommand OBJECT-TYPE
            SYNTAX INTEGER {
                none                                        (1),
                immediateOn                         (2),
                immediateOff                        (3),
                immediateReboot                 (4),
                delayedOn                               (5),
                delayedOff                          (6),
                delayedReboot                       (7),
                cancelPendingCommand        (8)
            }
    ...
    

    Here, it can be discerned that to turn a port off, it's integer 3, on is 2, and so on.

    It remains a mystery to me why the SNMP tools don't give clearer errors (noSuchName is misleading, the name very much does exist, it simply is read-only, but such is life in tech)