RFC 1227

SNMP MUX protocol and MIB

πŸ“… published May 1991, from ietf

RFC 1227: SNMP MUX Protocol and MIB πŸŽ€

Okay bestie, this is RFC 1227, written by M. Rose at Performance Systems International, Inc. and dated May 1991 πŸ¦‹ It's an Experimental Protocol, which basically means "try it out and tell us what's broken." The header doesn't list anything it obsoletes or updates. It's published through the Network Working Group.

Status of This Memo πŸ“œ

This memo suggests a way for a user process to plug itself into the local SNMP agent on a host so it can implement parts of the MIB. The whole mechanism stays local to that host, no cap πŸ’…

This is an Experimental Protocol for the Internet community, and they're actively asking for discussion and suggestions for improvement 🫢 For the standardization state and status of this protocol, check the current edition of the "IAB Official Protocol Standards." Distribution of this memo is unlimited ✨


Table of Contents

   1. Introduction ..........................................    1
   2. Architecture ..........................................    2
   3. Protocol ..............................................    3
   3.1 Tricky Things ........................................    3
   3.1.1 Registration .......................................    4
   3.1.2 Removing Registration ..............................    4
   3.1.3 Atomic Sets ........................................    4
   3.1.4 Variables in Requests ..............................    5
   3.1.5 Request-ID .........................................    5
   3.1.6 The powerful get-next operator .....................    5
   3.2 Protocol Data Units ..................................    6
   3.3 Mappings on Transport Service ........................    8
   3.3.1 Mapping onto the TCP ...............................    8
   4. MIB for the SMUX ......................................    9
   5. Acknowledgements ......................................   12
   6. References ............................................   12
   7. Security Considerations................................   13
   8. Author's Address.......................................   13

1. Introduction 🌸

On a typical kernel/user system, the SNMP [1] agent is often just a user process. It reads kernel variables so it can serve the Internet-standard MIB [2] 🧚 That works great as long as everything the agent needs lives either in the kernel or in stable storage, like files. The problem shows up when other user processes handle other network services, like routing protocols. Then talking between the SNMP agent and those processes gets messy 😭

So this doc introduces the fix: the SNMP multiplexing (SMUX) protocol πŸ¦‹ When a user process, called a SMUX peer, wants to export a MIB module, it opens a SMUX association with the local SNMP agent, registers itself, and then (later on) hands over management operations for the objects in that MIB module.

Taking this idea all the way, the SNMP agent could know about just the SNMP group of the Internet-standard MIB, while every other part of the MIB gets handled by another process. This is super useful when, say, a computer manufacturer wants to ship SNMP access for its operating system in binary form πŸ’…

Besides the SMUX protocol itself, this document also defines a MIB for the SMUX. Obviously, that MIB module has to be implemented in the local SNMP agent too πŸŽ€

2. Architecture 🌈

There are two approaches for integrating arbitrary MIB modules with the SNMP agent: request-response and cache-ahead πŸ‘‘

The request-response model just passes the SNMP requests the agent receives along to the user process that exported the MIB module. The SMUX peer does the work and sends back a response, and then the SNMP agent forwards that response to the network management station. This model is called agent-driven, because after registration the SNMP agent starts all the transactions ✨

The cache-ahead model needs the SMUX peer to periodically push the subtree for its registered MIB module up to the SNMP agent after registration. When the agent gets an SNMP request for retrieving information, it handles the operation locally and sends the response to the network management station. (SNMP set requests go straight to the SMUX peer.) This model is called peer-driven, because after registration the SMUX peer starts all the transactions 🫢

Both approaches have pros and cons πŸ™ˆ So the architecture supports both models like this: the protocol between the SNMP agent and the SMUX peer is based on the request-response model. But the SMUX peer itself can be a user process that uses the cache-ahead model with other user processes.

Obviously, a SMUX peer using the cache-ahead model acts as a "firewall" for the user processes that actually implement the managed objects in that MIB module πŸ’€

Heads up: this document only describes the SMUX protocol for the request-response model. Each SMUX peer is free to define its own cache-ahead protocol for whatever application it's running πŸ“

3. Protocol πŸ’œ

The SMUX protocol is simple, bestie. The SNMP agent listens for incoming connections. Once a connection is up, the SMUX peer sends an OpenPDU to start the SMUX association. If the SNMP agent turns the association down, it sends a closePDU and closes the connection. If the SNMP agent accepts, it doesn't send any response at all πŸ‘€

For each subtree defined in a MIB module that the SMUX peer wants to register (or unregister), the SMUX peer sends an RReqPDU. When the SNMP agent gets one of those, it sends back a matching RRspPDU. The SNMP agent returns RRspPDUs in the same order the RReqPDUs came in ⭐

When the SMUX peer wants to send a trap, it issues an SNMP Trap-PDU. When the SNMP agent receives one, it passes the trap along to the network management stations it's configured to send traps to πŸ”₯

When the SNMP agent gets an SNMP GetRequest-PDU, GetNextRequest-PDU, or SetRequest-PDU that includes one or more variable-bindings inside a subtree registered by a SMUX peer, it sends an equivalent SNMP PDU that contains only the variables inside that peer's registered subtree. When the SMUX peer gets that PDU, it performs the operation and sends back a corresponding SNMP GetResponse-PDU. The SNMP agent then correlates that result and passes the resulting GetResponse-PDU along to the network management station πŸŽ€

When either the SNMP agent or the SMUX peer wants to end the SMUX association, the ClosePDU is sent, the connection closes, and all the subtree registrations for that association get released. Bye bye πŸ‘‹

3.1. Tricky Things πŸ™ˆ

It's pretty straightforward, but there are a few nuances 🧐

3.1.1. Registration πŸ“Œ

Every registration has an integer priority, anywhere from 0 to (2^31)-1. The lower the number, the higher the priority πŸ‘‘

Multiple SMUX peers can register the same subtree. They must do so at different priorities, though. In other words, a subtree plus a priority uniquely identifies a SMUX peer 🫢 So if a SMUX peer tries to register a subtree at a priority that's already taken, the SNMP agent keeps incrementing the integer until it finds a free priority.

When registering a subtree, you can use the special priority -1, which picks the highest available priority πŸ¦‹

The SNMP agent can also assign a much worse priority to a SMUX peer based on local (configuration) information. No notes πŸ“

Here's the main thing: when a subtree is registered, the SMUX peer with the highest registration priority is the only one consulted for all operations on that subtree. Also, SNMP agents must enforce the "subtree mounting effect," which hides registrations by other SMUX peers for objects inside the subtree. For example, say a SMUX peer registered sysDescr, and later another SMUX peer registered system (which scopes sysDescr). Then every request for sysDescr gets handed to the latter SMUX peer 🀯

An SNMP agent should disallow any attempt to register above, at, or below the SNMP and SMUX subtrees of the MIB. Other subtrees may also be disallowed as an implementation-specific option πŸ“

3.1.2. Removing Registration πŸ—‘οΈ

A SMUX peer can only remove registrations for subtrees it has registered itself. If the priority in the RReqPDU is -1, then the registration with the highest priority is the one selected for deletion. Otherwise, only the registration with that exact priority gets selected ✨

3.1.3. Atomic Sets βš›οΈ

The SNMP agent and the SMUX peers use a simple two-phase commit protocol πŸ’… When an SNMP SetRequest-PDU arrives, the SNMP agent figures out which SMUX peers will take part in the transaction. For each of those peers, at least one SNMP SetRequest-PDU gets sent, containing only the variables that matter to that peer.

Each SMUX peer must either accept or refuse the set operation, without actually performing it yet πŸ™…β€β™€οΈ If the peer decides to accept, it sends back an SNMP GetResponse-PDU with an error-status of noError(0). If it refuses, the GetResponse-PDU comes back with a non-zero error-status instead.

The SNMP agent looks at all of the responses. If at least one SMUX peer refused, then a SMUX SOutPDU with the value rollback gets sent to each SMUX peer, telling them to throw away any knowledge of the requested operation 😭

Otherwise, if every SMUX peer accepted, a SMUX SOutPDU with the value commit gets sent to each SMUX peer, telling them to actually perform the operation πŸ”₯

Either way, the SMUX peer doesn't generate a response to the SMUX SOutPDU 🫢

3.1.4. Variables in Requests 🧩

When the SNMP agent builds an SNMP GetRequest-PDU or GetNextRequest-PDU for a SMUX peer, it can send one variable or more than one variable in a single request. In every case, the SNMP agent should process each variable sequentially, and block accordingly whenever a SMUX peer is contacted 🌸

3.1.5. Request-ID πŸ†”

When the SNMP agent builds an SNMP GetRequest-PDU, GetNextRequest-PDU, or SetRequest-PDU for a SMUX peer, the request_id field of the SNMP PDU takes on a special meaning. If the SNMP agent generates multiple PDUs for a SMUX peer after receiving a single PDU from the network management station, then the request_id field of every PDU sent to the SMUX peer must have the same value. That value doesn't need to match the request_id from the PDU the SNMP agent originally received 🧚

3.1.6. The powerful get-next operator πŸ‘‘

Each SMUX peer acts as though it holds the entire MIB when it processes an SNMP GetNext-PDU from the SNMP agent. That means the SNMP agent has to check each variable returned in the SNMP GetResponse-PDU from the SMUX peer, to make sure it's still inside the same registered subtree that caused the SNMP GetNext-PDU to be sent to that peer in the first place 🌈 For any variable that isn't, the SNMP agent must put it into an SNMP GetNext-PDU sent to the peer for the next registered subtree. It keeps doing that until responses exist for all variables within their expected registered subtree. Main character energy, iykyk πŸ’–

3.2. Protocol Data Units ✨

okay bestie, so the SMUX PDUs are written in ASN.1 (Abstract Syntax Notation One) [3], and I'm not even going to lie, it's giving very formal energy πŸ’… but it's actually super clean once you see it laid out:

SMUX DEFINITIONS ::= BEGIN

IMPORTS
        DisplayString, ObjectName
                FROM RFC1155-SMI

        PDUs
                FROM RFC1157-SNMP;


-- tags for SMUX-specific PDUs are application-wide to
-- avoid conflict with tags for current (and future)
-- SNMP-generic PDUs

SMUX-PDUs ::=
    CHOICE {
        open            -- SMUX peer uses
            OpenPDU,    -- immediately after TCP open

        close           -- either uses immediately before TCP close
            ClosePDU,

        registerRequest -- SMUX peer uses
            RReqPDU,

        registerResponse -- SNMP agent uses
            RRspPDU,

            PDUs,       -- note that roles are reversed:
                        --   SNMP agent does get/get-next/set
                        --   SMUX peer does get-response/trap

        commitOrRollback -- SNMP agent uses
            SOutPDU
   }


-- open PDU
-- currently only simple authentication

OpenPDU ::=
    CHOICE {
       simple

           SimpleOpen
    }

SimpleOpen ::=
    [APPLICATION 0] IMPLICIT
        SEQUENCE {
            version     -- of SMUX protocol
                INTEGER {
                    version-1(0)
                },

            identity    -- of SMUX peer, authoritative
                OBJECT IDENTIFIER,

            description -- of SMUX peer, implementation-specific
                DisplayString,

            password    -- zero length indicates no authentication
                OCTET STRING
        }


-- close PDU

ClosePDU ::=
    [APPLICATION 1] IMPLICIT
        INTEGER {
            goingDown(0),
            unsupportedVersion(1),
            packetFormat(2),
            protocolError(3),
            internalError(4),
            authenticationFailure(5)
        }


-- insert PDU

RReqPDU ::=
    [APPLICATION 2] IMPLICIT
        SEQUENCE {
            subtree
                ObjectName,

            priority    -- the lower the better, "-1" means default
                INTEGER (-1..2147483647),

            operation

                INTEGER {
                    delete(0),    -- remove registration
                    readOnly(1),  -- add registration, objects are RO
                    readWrite(2)  --   .., objects are RW
                }
        }

RRspPDU ::=
    [APPLICATION 3] IMPLICIT
        INTEGER {
            failure(-1)

           -- on success the non-negative priority is returned
        }

SOutPDU ::=
    [APPLICATION 4] IMPLICIT
        INTEGER {
            commit(0),
            rollback(1)
        }

END

3.3. Mappings on Transport Service πŸš€

so the SMUX protocol can be mapped onto any CO-mode transport service πŸ¦‹ ngl that's a lot of words for "pick a pipe," and right now there's only one mapping defined, so it's not a big choice yet 🌸

3.3.1. Mapping onto the TCP πŸ’–

when TCP is the transport backing SMUX, the SNMP agent listens on TCP port 199 πŸŽ€

every SMUX PDU gets serialized with the Basic Encoding Rules [4] and then shipped over TCP. the cute part? ASN.1 objects are self-delimiting when you encode them with BER, so you literally don't need any extra packetization protocol 😭✨ BER already knows where each message ends, no cap, iconic πŸ‘‘


4. MIB for the SMUX 🌈

okay so the MIB objects for SMUX are implemented by the local SNMP agent. here's the whole SMUX-MIB, and it's giving organized chaos πŸ’œ

      SMUX-MIB DEFINITIONS ::= BEGIN

      IMPORTS
              enterprises
                      FROM RFC1155-SMI
              OBJECT-TYPE
                      FROM RFC1212;

      unix    OBJECT IDENTIFIER ::= { enterprises 4 }

      smux    OBJECT IDENTIFIER ::= { unix 4 }

      smuxPeerTable   OBJECT-TYPE
              SYNTAX  SEQUENCE OF SmuxPeerEntry
              ACCESS  not-accessible
              STATUS  mandatory
              DESCRIPTION
                  "The SMUX peer table."
              ::= { smux 1 }

      smuxPeerEntry   OBJECT-TYPE
              SYNTAX  SmuxPeerEntry
              ACCESS  not-accessible
              STATUS  mandatory
              DESCRIPTION
                  "An entry in the SMUX peer table."
              INDEX   { smuxPindex }
              ::= { smuxPeerTable 1}

      SmuxPeerEntry ::=
          SEQUENCE {
              smuxPindex
                  INTEGER,
              smuxPidentity
                  OBJECT IDENTIFIER,
              smuxPdescription
                  DisplayString,
              smuxPstatus
                  INTEGER
          }

      smuxPindex      OBJECT-TYPE
              SYNTAX  INTEGER
              ACCESS  read-only
              STATUS  mandatory
              DESCRIPTION
                  "An index which uniquely identifies a SMUX peer."
              ::= { smuxPeerEntry 1 }

      smuxPidentity   OBJECT-TYPE
              SYNTAX  OBJECT IDENTIFIER
              ACCESS  read-only
              STATUS  mandatory
              DESCRIPTION
                  "The authoritative designation for a SMUX peer."
              ::= { smuxPeerEntry 2 }

      smuxPdescription OBJECT-TYPE
              SYNTAX  DisplayString (SIZE (0..255))
              ACCESS  read-only
              STATUS  mandatory
              DESCRIPTION
                  "A human-readable description of a SMUX peer."
              ::= { smuxPeerEntry 3 }

      smuxPstatus     OBJECT-TYPE
              SYNTAX  INTEGER { valid(1), invalid(2), connecting(3) }
              ACCESS  read-write
              STATUS  mandatory
              DESCRIPTION
                  "The type of SMUX peer.

                  Setting this object to the value invalid(2) has
                  the effect of invaliding the corresponding entry
                  in the smuxPeerTable.  It is an implementation-
                  specific matter as to whether the agent removes an
                  invalidated entry from the table.  Accordingly,
                  management stations must be prepared to receive
                  tabular information from agents that correspond to
                  entries not currently in use.  Proper
                  interpretation of such entries requires
                  examination of the relative smuxPstatus object."
              ::= { smuxPeerEntry 4 }

      smuxTreeTable   OBJECT-TYPE
              SYNTAX  SEQUENCE OF SmuxTreeEntry
              ACCESS  not-accessible
              STATUS  mandatory
              DESCRIPTION
                  "The SMUX tree table."
              ::= { smux 2 }

      smuxTreeEntry   OBJECT-TYPE
              SYNTAX  SmuxTreeEntry
              ACCESS  not-accessible
              STATUS  mandatory
              DESCRIPTION
                  "An entry in the SMUX tree table."
              INDEX   { smuxTsubtree, smuxTpriority }
              ::= { smuxTreeTable 1}

      SmuxTreeEntry ::=
          SEQUENCE {
              smuxTsubtree
                  OBJECT IDENTIFIER,
              smuxTpriority
                  INTEGER,
              smuxTindex
                  INTEGER,
              smuxTstatus
                  INTEGER
          }

      smuxTsubtree    OBJECT-TYPE
              SYNTAX  OBJECT IDENTIFIER
              ACCESS  read-only
              STATUS  mandatory
              DESCRIPTION
                  "The MIB subtree being exported by a SMUX peer."
              ::= { smuxTreeEntry 1 }

      smuxTpriority OBJECT-TYPE
              SYNTAX  INTEGER (0..'07fffffff'h)
              ACCESS  read-only
              STATUS  mandatory
              DESCRIPTION
                  "The SMUX peer's priority when exporting the MIB
                  subtree."
              ::= { smuxTreeEntry 2 }

      smuxTindex OBJECT-TYPE
              SYNTAX  INTEGER
              ACCESS  read-only
              STATUS  mandatory
              DESCRIPTION
                  "The SMUX peer's identity."
              ::= { smuxTreeEntry 3 }

      smuxTstatus     OBJECT-TYPE
              SYNTAX  INTEGER { valid(1), invalid(2) }
              ACCESS  read-write
              STATUS  mandatory
              DESCRIPTION
                  "The type of SMUX tree.

                  Setting this object to the value invalid(2) has
                  the effect of invaliding the corresponding entry
                  in the smuxTreeTable.  It is an implementation-
                  specific matter as to whether the agent removes an
                  invalidated entry from the table.  Accordingly,
                  management stations must be prepared to receive
                  tabular information from agents that correspond to
                  entries not currently in use.  Proper
                  interpretation of such entries requires
                  examination of the relative smuxTstatus object."
              ::= { smuxTreeEntry 4 }

      END

5. Acknowledgements πŸ’•

SMUX was designed one afternoon by these people, which is honestly iconic behaviour 🫢

            Jeffrey S. Case, UTK-CS
            James R. Davin, MIT-LCS
            Mark S. Fedor, PSI
            Jeffrey C. Honig, Cornell
            Louie A. Mamakos, UMD
            Michael G. Petry, UMD
            Yakov Rekhter, IBM
            Marshall T. Rose, PSI

6. References πŸ“š

  • [1] Case, J., Fedor, M., Schoffstall, M., and J. Davin, "Simple Network Management Protocol", RFC 1157, SNMP Research, Performance Systems International, Performance Systems International, MIT Laboratory for Computer Science, May 1990.
  • [2] McCloghrie K., and M. Rose, "Management Information Base for Network Management of TCP/IP-based Internets", RFC 1156, Performance Systems International and Hughes LAN Systems, May 1990.
  • [3] Information processing systems - Open Systems Interconnection - Specification of Abstract Syntax Notation One (ASN.1), International Organization for Standardization, International Standard 8824, December 1987.
  • [4] Information processing systems - Open Systems Interconnection - Specification of Basic Encoding Rules for Abstract Notation One (ASN.1), International Organization for Standardization, International Standard 8825, December 1987.
  • [5] Rose, M., and K. McCloghrie, "Structure and Identification of Management Information for TCP/IP-based Internets", RFC 1155, Performance Systems International and Hughes LAN Systems, May 1990.

7. Security Considerations πŸ”

Security issues are not discussed in this memo. πŸ’€ bestie, this is the one section where the RFC just goes "nothing to see here," so take it seriously and keep your guard up πŸ™ˆ

8. Author's Address πŸ¦‹

Marshall T. Rose Performance Systems International, Inc. 5201 Great America Parkway Suite 3106 Santa Clara, CA 95054

Phone: +1 408 562 6222

EMail: mrose@psi.com X.500: rose, psi, us

πŸ“¦ where this page comes from