RFC 2233

The Interfaces Group MIB using SMIv2

πŸ“… published November 1997, from ietf

RFC 2233: The Interfaces Group MIB using SMIv2 πŸŽ€

Network Working Group 🧚 This one came out of the Network Working Group, so it's an IETF doc, bestie.

Authors: K. McCloghrie (Cisco Systems) and F. Kastenholz (FTP Software) πŸ‘‘

Category: Standards Track πŸ”₯

Date: November 1997 🌸

Obsoletes: RFC 1573 πŸ’… This one replaces RFC 1573, so that's the old version you can retire.


Status of This Memo ✨

This document specifies an Internet standards track protocol for the Internet community, and requests discussion and suggestions for improvements. Please refer to the current edition of the "Internet Official Protocol Standards" (STD 1) for the standardization state and status of this protocol. Distribution of this memo is unlimited. πŸ¦‹

Copyright (C) The Internet Society (1997). All Rights Reserved.

Table of Contents πŸ“š

1 Introduction ..............................................    2
2 The SNMP Network Management Framework .....................    2
2.1 Object Definitions ......................................    3
3 Experience with the Interfaces Group ......................    3
3.1 Clarifications/Revisions ................................    3
3.1.1 Interface Sub-Layers ..................................    4
3.1.2 Guidance on Defining Sub-layers .......................    6
3.1.3 Virtual Circuits ......................................    8
3.1.4 Bit, Character, and Fixed-Length Interfaces ...........    8
3.1.5 Interface Numbering ...................................   10
3.1.6 Counter Size ..........................................   14
3.1.7 Interface Speed .......................................   16
3.1.8 Multicast/Broadcast Counters ..........................   17
3.1.9 Trap Enable ...........................................   18
3.1.10 Addition of New ifType values ........................   18
3.1.11 InterfaceIndex Textual Convention ....................   18
3.1.12 New states for IfOperStatus ..........................   19
3.1.13 IfAdminStatus and IfOperStatus .......................   20
3.1.14 IfOperStatus in an Interface Stack ...................   21
3.1.15 Traps ................................................   21
3.1.16 ifSpecific ...........................................   23
3.1.17 Creation/Deletion of Interfaces ......................   24
3.1.18 All Values Must be Known .............................   24
4 Media-Specific MIB Applicability ..........................   25
5 Overview ..................................................   26
6 Interfaces Group Definitions ..............................   26
7 Acknowledgements ..........................................   64
8 References ................................................   64
9 Security Considerations ...................................   65
10 Authors' Addresses .......................................   65
11 Full Copyright Statement .................................   66

1. Introduction ✨

Okay so this memo defines a chunk of the Management Information Base (MIB) that network management protocols in the Internet community use. Specifically, it's all about the managed objects you use to manage Network Interfaces. 🌈

It digs into the 'interfaces' group of MIB-II, especially what we learned from defining a bunch of media-specific MIB modules that go with the 'interfaces' group. Those modules manage the various sub-layers under the internetwork-layer. The memo also spells out clarifications to, and extensions of, the architectural stuff in the previous model for the 'interfaces' group. It's giving upgrade πŸ’…

This memo also includes a MIB module. Along with the new MIB definitions that support the architectural extensions, the module re-specifies the 'interfaces' group of MIB-II. It does this in a way that's compliant with the SNMPv2 SMI and semantically identical to the existing SNMPv1-based definitions. So nothing breaks, it's just cleaner 🫢

The key words "MUST" and "MUST NOT" in this document are to be interpreted as described in RFC 2119 [10]. πŸ”₯ Those caps words are the important ones, so pay attention to them!

2. The SNMP Network Management Framework πŸ¦‹

The SNMP Network Management Framework currently has three major components. They are:

  • RFC 1902 which defines the SMI, the mechanisms used for describing and naming objects for the purpose of management. 🧚
  • STD 17, RFC 1213 defines MIB-II, the core set of managed objects for the Internet suite of protocols. πŸ‘‘
  • STD 15, RFC 1157 and RFC 1905 which define two versions of the protocol used for network access to managed objects. πŸ’–

The Framework lets people define new objects for experimentation and evaluation. Lowkey a fun little escape hatch πŸ“

2.1. Object Definitions 🌸

Managed objects are accessed through a virtual information store, called the Management Information Base or MIB. Objects in the MIB are defined using the subset of Abstract Syntax Notation One (ASN.1) that the SMI defines. Each object type is named by an OBJECT IDENTIFIER, which is an administratively assigned name. The object type together with an object instance is what uniquely identifies one specific instantiation of the object. ✨

For human convenience, we often use a textual string called the descriptor to refer to the object type. Honestly, it's way easier to say than a whole OID πŸ™ˆ

3. Experience with the Interfaces Group πŸ’œ

One of the strengths of internetwork-layer protocols like IP [6] is that they're designed to run over any network interface. IP treats every protocol it runs over as one single "network interface" layer, and other internetwork-layer protocols take the same view. That's the whole idea behind the 'interfaces' group in MIB-II. It defines a generic set of managed objects, so any network interface can be managed in an interface-independent way. πŸ¦‹

The 'interfaces' group also gives you a way to add managed objects for particular types of network interface, like a specific medium such as Ethernet. These get defined as extensions to the 'interfaces' group for media-specific management. Ever since MIB-II was standardized, a lot of media-specific MIB modules have been defined πŸ”₯

Here's the tea β˜• Experience defining those media-specific modules showed that the MIB-II model is too simplistic and/or static for some kinds of media-specific management. So some of those modules assume the model has evolved or loosened up a bit. This memo documents and standardizes that evolution and fills in the gaps it left behind. It also brings in the interfaces group extensions documented in RFC 1229 [7]. Main character energy πŸ‘‘

3.1. Clarifications/Revisions πŸŽ€

There are several areas where experience has shown that clarifying, revising, or extending the model would help. The following sections talk about the changes to the 'interfaces' group that this memo adopts in each of those areas. 🌈

Some sections have one or more paragraphs discussing alternatives to the model that this memo rejected. If you're not familiar with the MIB-II model and aren't into the reasoning behind the new one, you can skip those paragraphs. No judgment 🫢

3.1.1. Interface Sub-Layers ✨

Okay so bestie, experience with defining media-specific management info showed we NEED to tell apart the multiple sub-layers beneath the internetwork-layer πŸ’…. We also have to manage these sub-layers on devices (like MAC-layer bridges) that have no idea whether any internetwork protocols run over them πŸ™ˆ. So the idea of one conceptual row in the interfaces table (MIB-II's ifTable) representing a whole interface under the internetwork-layer, with one media-specific MIB module referenced through the ifType object, is just too simplistic 😭. And ifType has enumerated values for each type of interface, which adds its own mess.

Take PPP running over an HDLC link that uses an RS232-like connector πŸ”Œ. Each of those sub-layers has its own media-specific MIB module. If you cram all of it into a single ifTable row, you'd need an enumerated ifType value for that exact combo that maps to that exact combo of media-specific MIBs. And even then, the model still has no way to describe how all the sub-layers in the MIB stack relate to each other πŸ₯Ί.

There's also the issue of upward and downward multiplexing of the sub-layers 🧩. Upward multiplexing is MLP (Multi-Link-Procedure), which does load-sharing over several serial lines but appears as a single point-to-point link to the sub-layer(s) above it. Downward multiplexing would be several instances of PPP, each framed inside its own X.25 virtual circuit, all running over one fractional T1 channel while the rest of the T1 link is used for other stuff at the same time πŸŽ€. The MIB structure has to be able to describe these kinds of relationships.

Several solutions for representing multiple sub-layers got rejected, and here's the tea β˜•. The first one kept one conceptual row for all the sub-layers of an interface and had each media-specific MIB module name its "superior" and "subordinate" sub-layers using OBJECT IDENTIFIER "pointers". This was giving drawbacks πŸ’€. The superior/subordinate pointers would live inside the media-specific MIB modules, so a manager couldn't learn an interface's structure without poking through multiple pointers across different MIB modules. That's overly complex, and it'd only work if the manager knew about every relevant media-specific MIB module. Every MIB module would also need retrofitting with these new "pointers", it wouldn't properly handle upward and downward multiplexing, and enumerated values of ifType would be needed for every combination of sub-layers. Not it πŸ™…β€β™€οΈ.

The second rejected solution also kept one conceptual row for all the sub-layers of an interface, but added a new separate MIB table to identify the "superior" and "subordinate" sub-layers and hold OBJECT IDENTIFIER "pointers" to the media-specific MIB module for each sub-layer. Effectively, one ifTable row would represent each combination of sub-layers between the internetwork-layer and the wire πŸ§ƒ. This one had fewer drawbacks, but it still couldn't support downward multiplexing, like PPP over MLP. Here's the thing: MLP makes two (or more) serial lines look like a single physical interface to the layers above, so PPP over MLP should appear to the internetwork-layer as one interface. With this scheme, you'd get two (or more) ifTable rows, and the internetwork-layer would run over both of them 😡. It would also still need enumerated ifType values for each combination of sub-layers.

So the solution this memo actually adopts is giving each sub-layer its own individual conceptual row in the ifTable πŸ¦‹. Then there's a new separate MIB table (the ifStackTable, see section 6 below) that identifies the "superior" and "subordinate" sub-layers through INTEGER "pointers" to the right conceptual rows in the ifTable. This supports both upward and downward multiplexing ✨. It lets the IANAifType to Media-Specific MIB mapping identify the media-specific MIB module for each sub-layer, so the new table only needs to be referenced for info about layering. And it only needs enumerated ifType values for each sub-layer, not for combinations of them πŸ‘‘. The catch is that some ifTable object descriptions have to be generalized so they apply to any sub-layer, not just a sub-layer sitting right beneath the network layer like before. Those objects are ifType, ifPhysAddress, ifInUcastPkts, and ifOutUcastPkts. On top of that, ifSpeed needs appropriate values identified for when a generalized definition doesn't fit a particular sub-layer 🌈.

Also, this adopted solution doesn't require that a device, where a sub-layer is instrumented by an ifTable conceptual row, know whether an internetwork protocol runs on top of that sub-layer (i.e., at some layer above it) 🫢. In fact, the counters of packets received on an interface are defined as counting the number "delivered to a higher-layer protocol". This "higher-layer" meaning includes:

(1) Delivery to a forwarding module which accepts packets/frames/octets and forwards them on at the same protocol layer. For example, for the purposes of this definition, the forwarding module of a MAC-layer bridge counts as a "higher-layer" to the MAC-layer of each port on the bridge.

(2) Delivery to a higher sub-layer within an interface stack. For example, for the purposes of this definition, if a PPP module operated directly over a serial interface, the PPP module would count as the higher sub-layer to the serial interface.

(3) Delivery to a higher protocol layer which does not do packet forwarding for sub-layers that are "at the top of" the interface stack. For example, for the purposes of this definition, the local IP module would count as the higher layer to a SLIP serial interface.

Similarly, for output, the counters of packets transmitted out an interface are defined as counting the number "that higher-level protocols requested to be transmitted". This "higher-layer" meaning includes:

(1) A forwarding module, at the same protocol layer, which transmits packets/frames/octets that were received on a different interface. For example, for the purposes of this definition, the forwarding module of a MAC-layer bridge counts as a "higher-layer" to the MAC-layer of each port on the bridge.

(2) The next higher sub-layer within an interface stack. For example, for the purposes of this definition, if a PPP module operated directly over a serial interface, the PPP module would be a "higher layer" to the serial interface.

(3) For sub-layers that are "at the top of" the interface stack, a higher element in the network protocol stack. For example, for the purposes of this definition, the local IP module would count as the higher layer to an Ethernet interface.

3.1.2. Guidance on Defining Sub-layers 🧭

The designer of a media-specific MIB has to decide whether to divide the interface into sub-layers or not, and if so, how to make those divisions πŸ€”. The guidance below is here to help the media-specific MIB designer make those calls.

In general, the number of entries in the ifTable should be kept to the minimum required for network management πŸ“‰. In particular, a group of related interfaces should be treated as a single interface with one ifTable entry as long as:

(1) None of the group of interfaces performs multiplexing for any other interface in the agent, (2) There is a meaningful and useful way for all of the ifTable's information (e.g., the counters, and the status variables), and all of the ifTable's capabilities (e.g., write access to ifAdminStatus), to apply to the group of interfaces as a whole.

Under these circumstances, there should be one ifTable entry for that group of interfaces, and any internal structure that needs to be represented to network management should be captured in a MIB module specific to that type of interface πŸ’–.

Heads up, though: applying bullet 2 above to the ifTable's ifType object requires that there's a meaningful media-specific MIB and a meaningful ifType value that both apply to the group of interfaces as a whole ⚠️. For example, it's not appropriate to treat an HDLC sub-layer and an RS-232 sub-layer as a single ifTable entry when the media-specific MIBs and the ifType values for HDLC and RS-232 are separate (rather than combined).

Subject to the above, it's appropriate to assign an ifIndex value to any interface that can occur in an interface stack (in the ifStackTable) where the bottom of the stack is a physical interface (ifConnectorPresent has the value 'true') and there's a layer-3 or other application that "points down" to the top of this stack 🎯. One example of an application that points down to the top of the stack is the Character MIB [9].

Note that the sub-layers of an interface on one device will sometimes be different from the sub-layers of the interconnected interface on another device πŸ”. For example, for a frame-relay DTE interface connected to a frameRelayService interface, the interconnected DTE and DCE interfaces have different ifType values and media-specific MIBs.

These guidelines are just that, guidelines 🫢. The designer of a media-specific MIB is free to lay out the MIB in whatever SMI conformant manner they want. However, while doing so, the media-specific MIB MUST completely specify the sub-layering model used for the MIB, and provide the assumptions, reasoning, and rationale used to develop that model πŸ“.

3.1.3. Virtual Circuits πŸ¦‹

Several of the sub-layers that have media-specific MIB modules defined for them are connection oriented (e.g., Frame Relay, X.25) 🌸. Experience has shown that every effort to define one of these MIB modules ends up revisiting the question of whether separate conceptual rows in the ifTable are needed for each virtual circuit. Most, if not all, of those efforts so far have decided to have all virtual circuits reference a single conceptual row in the ifTable πŸ’….

This memo strongly recommends that connection-oriented sub-layers do not have a conceptual row in the ifTable for each virtual circuit. This avoids a proliferation of conceptual rows, especially ones with lots of redundant information πŸ™„. (As a comparison, note that connection-less sub-layers don't have conceptual rows for each remote address.) That said, there may be circumstances where it's appropriate for a virtual circuit of a connection-oriented sub-layer to get its own conceptual row in the ifTable. One example of that might be PPP over an X.25 virtual circuit 🧚. The MIB in section 6 of this memo supports those circumstances.

If a media-specific MIB wants to assign an ifTable entry to each virtual circuit, the MIB designer must present the rationale for that decision in the media-specific MIB's specification πŸ“‹.

3.1.4. Bit, Character, and Fixed-Length Interfaces ✨

okay so RS-232 is a character-oriented sub-layer πŸ’…, and you can totally send IP datagrams over it (e.g., through use of PPP 🧚). But a lot of the objects in the ifTable are packet-based, and experience has shown that it's not appropriate to give a character-oriented sub-layer a whole conceptual row in the ifTable πŸ™ˆ.

bit-oriented interfaces have a similar problem. sometimes you still want management info for them, and that's just as awkward to fit into a whole ifTable row. for example, you might want to manage the channels of a DS1 circuit when only some of those channels are carrying packet-based data πŸŽ€.

then there's the fixed-length plot twist 😭. some subnetwork technologies send data in fixed-length transmission units. cell relay is the big example, specifically Asynchronous Transfer Mode (ATM), which sends data in fixed-length cells πŸ¦‹. if you represent that as a packet-based interface, you end up with redundant objects whenever the relationship between the number of packets and the number of octets in either direction is fixed by the size of the transmission unit (e.g., the size of a cell).

here's the tea 🍡: about half the objects in the ifTable apply to every type of interface (packet-oriented, character-oriented, and bit-oriented). Of the other half, two apply to both character-oriented and packet-oriented interfaces, and the rest only apply to packet-oriented ones. So yes, it would be consistent to represent every interface type in the ifTable, but it's not possible to implement the full ifTable for bit- and character-oriented sub-layers πŸ’€.

A rejected idea was to split the ifTable into two (or more) new MIB tables: one for objects relevant only to packet-oriented interfaces (e.g., PPP), and another that all interfaces could use. This is highly undesirable 🚫 because it would require changes in every agent implementing the ifTable (i.e., just about every existing SNMP agent).

so the solution in this memo is built on a neat fact: compliance statements in SNMPv2 (unlike SNMPv1) refer to object groups, and object groups are explicitly defined by listing the objects they contain πŸ‘‘. That means you can have multiple compliance statements, one for all interfaces and extra ones for specific types of interfaces. The group for all interfaces only contains the ifTable objects that are appropriate for every type of interface, and every sub-layer gets its own conceptual row in the ifTable πŸ™Œ.

Section 6 of this memo defines the objects of the existing 'interfaces' group of MIB-II. These definitions are SNMPv2-compliant and semantically equivalent to the existing MIB-II definitions πŸ’–. With equivalent semantics and BER ("on the wire") encodings unchanged, they keep the same OBJECT IDENTIFIER values assigned by MIB-II. so in general, existing agents that conform to MIB-II and the ifExtensions MIB don't need a rewrite 🫢.

This memo also defines several object groups, which say which objects apply to which types of interface 🌈:

  1. ifGeneralInformationGroup: contains the objects applicable to all types of network interfaces, including bit-oriented interfaces.
  2. ifPacketGroup: contains the objects applicable to packet-oriented network interfaces.
  3. ifFixedLengthGroup: contains the objects applicable not only to character-oriented interfaces, such as RS-232, but also to subnetwork technologies like cell-relay/ATM that transmit data in fixed-length transmission units. Besides the octet counters, there are a few other counters (e.g., the error counters) that are useful for this type of interface but are currently defined as packet-oriented. To make that work, their definitions are generalized to apply to character-oriented interfaces and fixed-length-transmission interfaces ⭐.
It should be noted that the octet counters in the ifTable aggregate octet counts for unicast and non-unicast packets into a single octet counter per direction (received/transmitted). So, with the fixed-length-transmission definition above, if such interfaces support non-unicast packets, separate counts of unicast and multicast/broadcast transmissions can only be maintained in a media-specific MIB module πŸ“.

3.1.5. Interface Numbering πŸ”’βœ¨

okay so MIB-II has this object called ifNumber, and it's basically the head count of network interfaces on the system. Its description says:

"The number of network interfaces (regardless of their
current state) present on this system."

Every interface gets its own unique ifIndex value, and the ifIndex description puts a limit on what that value can be:

"Its value ranges between 1 and the value of ifNumber.  The
value for each interface must remain constant at least from
one re-initialization of the entity's network management
system to the next re-initialization."

So the number has to stay the same for each interface from one re-initialization to the next. 🫢 This constancy is super important for efficient management, honestly iconic. The problem is that more and more devices let you add and remove network interfaces on the fly. One example is being able to set up SLIP/PPP over a character-oriented port whenever you want. 😭 For those dynamic additions and removals, the constancy rule plus the rule that ifIndex is less than ifNumber just don't get along. It's giving tension. πŸ’€

We looked at redefining ifNumber as the largest ifIndex value, and it got rejected because it wouldn't actually help. That change would force ifNumber to be deprecated, and the redefined object would be pretty questionable to use. We also thought about deprecating ifNumber without replacing it, but that would mean changing the part of the ifIndex definition that mentions ifNumber. Since ifIndex has to be changed anyway to fix this, touching ifNumber doesn't add any benefit to the solution. πŸ™„

The fix in this memo is simple: just delete the requirement that ifIndex must be less than ifNumber, and keep ifNumber exactly as it's defined now. πŸ’… This is a minor change to the semantics of ifIndex, but all the existing agent implementations already conform to the new definition. To avoid making everyone change existing agents and the many media-specific MIBs, this memo assumes the change does not require ifIndex to be deprecated. Experience shows it does "break" a few management applications, but that's considered way better than breaking all the agent implementations. πŸŽ€

This solution also means the ifTable can have "holes." The ifIndex values of its conceptual rows don't have to be contiguous. The good news is that SNMP's GetNext (and SNMPv2's GetBulk) operation handles those gaps easily. ✨ The value of ifNumber still counts the conceptual rows, and it goes up or down as interfaces get dynamically added or removed. πŸ“ˆ

Now the constancy requirement for an interface's ifIndex value (between re-initializations) is met by making sure that after an interface is dynamically removed, its ifIndex value doesn't get reused by a different dynamically added interface until after the next re-initialization of the network management system. 🧚 This means you don't have to pre-assign ifIndex values for every possible interface that might ever get added dynamically, which is a huge relief. The exact meaning of a "different" interface is hard to pin down, and there will be gray areas. Any firm definition in this document would likely turn out to be inadequate, so instead, implementors must choose what "different" means in their own situation, subject to these rules:

  1. a previously-unused value of ifIndex must be assigned to a dynamically added interface if an agent has no knowledge of whether the interface is the "same" or "different" to a previously incarnated interface.
  2. a management station, not noticing that an interface has gone away and another has come into existence, must not be confused when calculating the difference between the counter values retrieved on successive polls for a particular ifIndex value.

Now, when the new interface is the same as an old one, but a discontinuity in the interface's counters can't be avoided, the ifTable (until now) has required that a new ifIndex value be assigned to the returning interface. 😀 So either all the counter values had to be kept while the interface was gone (so the same ifIndex could be used on its return), or the returning interface had to get a brand new ifIndex value. Both options have turned out to be burdensome for some implementations:

  1. maintaining the counter values may not be possible (e.g., if they are maintained on removable hardware),
  2. using a new ifIndex value presents extra work for management applications. While the potential need for such extra work is unavoidable on agent re-initializations, it is desirable to avoid it between re-initializations.

To fix this, there's a new object called ifCounterDiscontinuityTime, which records the time of the last discontinuity in an interface's counters. πŸ¦‹ By watching this object, a management application can now spot counter discontinuities without the interface's ifIndex value changing. So an agent that implements this new object should, when a new interface is the same as an old interface, keep that interface's ifIndex value and update the interface's ifCounterDiscontinuityTime value if necessary. ✨ Management applications, meanwhile, must, when calculating differences between counter values retrieved on successive polls, discard any calculated difference where the value of ifCounterDiscontinuityTime is different between the two polls. (Note that this check has to be done in addition to the normal checking of sysUpTime to detect an agent re-initialization. πŸ‘€) Discards are a waste of network management processing and bandwidth, so an agent should not update the value of ifCounterDiscontinuityTime unless absolutely necessary. πŸ™

Yes, defining this new object is a change to the semantics of the ifTable counter objects. But it's impractical to deprecate and redefine all these counters, because they're widely deployed and really important. πŸ’– Also, a survey of implementations shows that many agents and management applications don't correctly implement this part of the current semantics (because of the burdensome issues above). So the practical impact of this change is small. Because of that, this breach of the SMI's rules is considered acceptable. πŸ€·β€β™€οΈ

Still, adding ifCounterDiscontinuityTime doesn't change the fact that:

It is necessary at certain times for the assignment of ifIndex values to change on a reinitialization of the agent (such as a reboot).

So a management application must always be ready for ifIndex re-assignment whenever the value of sysUpTime is reset to zero. πŸ”„

Some agents also support multiple "naming scopes." For example, an SNMPv1 agent can have multiple values of the SNMPv1 community string. πŸ“ For an agent like that (say, a CNM agent that supports a different subset of interfaces for different customers), there's no required relationship between the ifIndex values that identify interfaces in one naming scope and the ones that identify interfaces in another. It's up to the agent whether the same or different ifIndex values identify the same or different interfaces across different naming scopes. 🌈

Here's a cute bit of history. Because ifIndex had to be less than ifNumber, interfaces got small integer numbers, and humans started using those ifIndex values as (sort of) friendly names, like "interface number 3." πŸ₯° Now that the restriction is relaxed, ifIndex values could end up as really large numbers (like memory addresses), and those would be way less friendly. So this memo recommends that ifIndex values still be assigned as (relatively) small integer values starting at 1, even though the values in use at any one time won't necessarily be contiguous. (This also makes it easy for agents that dynamically add new interfaces to remember which values have already been assigned. 🧠)

Representing each sub-layer as its own ifTable entry brings a new problem. Before, there was usually a simple, direct mapping from interfaces to the physical ports on a system, and that mapping was based on the ifIndex value. πŸ˜΅β€πŸ’« But once every interface sub-layer has its own ifTable entry, mapping interfaces to physical ports gets more and more messy.

To deal with this, a new object called ifName has been added to the MIB. πŸŽ€ It holds the device's local name for the interface that the relevant ifTable entry is a component of (the name you'd see at the device's local console). For example, picture a router with an interface made of PPP running over an RS-232 port. If the router calls the combined interface wan1, then the ifName objects for the matching PPP and RS-232 entries in the ifTable would both have the value wan1. But if the router calls the PPP interface wan1.1 and the RS-232 port wan1.2, then the ifName objects for those entries would have the values wan1.1 and wan1.2, respectively. πŸ’…

Here's another one: say an agent answers SNMP queries about an interface on some other (proxied) device. If that proxied device gives an interface a particular identifier, it's appropriate to use that identifier as the interface's ifName value. The reason is that the "local console" in this case belongs to the proxied device. πŸ§šβ€β™€οΈ

Meanwhile, the existing ifDescr object is meant to hold a description of an interface. Another new object, ifAlias, gives a network management application a spot to store a non-volatile interface-naming value of its choice. 🫧 The ifAlias object lets a network manager give one or more interfaces their own unique names, no matter what the interface-stack relationship looks like. Also, the ifAlias name is non-volatile, so an interface must keep its assigned ifAlias value across reboots, even if the agent picks a new ifIndex value for that interface. πŸ‘‘

3.1.6. Counter Size ✨

okay so bestie, as network media gets faster, the time it takes a 32 bit counter to wrap gets shorter πŸ“‰πŸ’€. A 10Mbs stream of back-to-back, full-size packets makes ifInOctets wrap in just over 57 minutes 😭. At 100Mbs the minimum wrap time is 5.7 minutes, and at 1Gbs it's only 34 seconds. Requiring that interfaces get polled often enough to never miss a counter wrap is becoming so problematic πŸ™ˆ

A solution that got rejected was scaling the counters. For example, ifInOctets could count received octets in, say, 1024 byte blocks πŸ™…β€β™€οΈ. It's fine at high rates of counted events, but it totally suffers at low rates. If there's barely any traffic, the scaled counter could sit there for ages before it ticks up. The traffic would then look super bursty, and people would draw the wrong conclusions about how the network is performing πŸ’”

So instead, this memo goes with expanded, 64 bit, counters πŸ¦‹. They live in new "high capacity" groups. The old 32-bit counters have not been deprecated, though 🀍. The 64-bit counters are only meant to be used when the 32-bit counters don't have enough capacity, meaning when the 32-bit counters could wrap too fast.

Here's the speed breakdown:

  • For interfaces that operate at 20,000,000 (20 million) bits per second or less, 32-bit byte and packet counters MUST be used.
  • For interfaces that operate faster than 20,000,000 bits/second, and slower than 650,000,000 bits/second, 32-bit packet counters MUST be used and 64-bit octet counters MUST be used.
  • For interfaces that operate at 650,000,000 bits/second or faster, 64-bit packet counters AND 64-bit octet counters MUST be used.

These speed thresholds were picked as reasonable compromises, and here's why 🧠✨:

  1. The cost of maintaining 64-bit counters is relatively high, so it's good to keep the number of agents that have to support them as small as possible. Common interfaces (like 10Mbs Ethernet) shouldn't need them.
  2. 64-bit counters are a new feature, introduced in SNMPv2. It's reasonable to expect support for them to be spotty for the immediate future, so we want to limit them to as few systems as possible. This basically means 64-bit counters should be limited to higher speed interfaces. Ethernet (10,000,000 bps) and Token Ring (16,000,000 bps) are pretty widespread, so it seems reasonable to not require 64-bit counters for those interfaces 🌸.
  3. The 32-bit octet counters will wrap in these times, for these interfaces (when transmitting maximum-sized packets back-to-back) ⏰:
    • 10Mbs Ethernet: 57 minutes
    • 16Mbs Token Ring: 36 minutes
    • a US T3 line (45 megabits): 12 minutes
    • FDDI: 5.7 minutes
  4. The 32-bit packet counters wrap in about 57 minutes when 64-byte packets are transmitted back-to-back on a 650,000,000 bit/second link.

As an aside πŸ‘€, a 1-terabit/second (1,000 Gbs) link will make a 64 bit octet counter wrap in just under 5 years. On the flip side, you'd need an 81,000,000 terabit/second link to make a 64-bit counter wrap in 30 minutes 🀯. The authors believe that, even though technology is marching forward fast, a link that fast won't show up for at least several years. That leaves plenty of time to evaluate introducing 96 bit counters πŸš€.

When 64-bit counters are in use, the 32-bit counters MUST still be available πŸ’…. They report the low 32-bits of the associated 64-bit count. For example, ifInOctets will report the least significant 32 bits of ifHCInOctets. This keeps things compatible with existing implementations at a very minimal cost to agents 🫢.

The new "high capacity" groups are:

  1. the ifHCFixedLengthGroup for character-oriented/fixed-length interfaces, and the ifHCPacketGroup for packet-based interfaces. Both of these groups include 64 bit counters for octets, and
  2. the ifVHCPacketGroup for packet-based interfaces. This group includes 64 bit counters for octets and packets πŸŽ€.

3.1.7. Interface Speed 🏎️

Network speeds keep climbing πŸ“ˆ. The range of ifSpeed is limited to reporting a maximum speed of (2**31)-1 bits/second, which is approximately 2.2Gbs. SONET defines an OC-48 interface, operating at 48 times 51 Mbs, which is a speed over 2.4Gbs. So ifSpeed just isn't enough for the future 😀, and this memo defines an additional object: ifHighSpeed πŸ‘‘.

The ifHighSpeed object reports the speed of the interface in 1,000,000 (1 million) bits/second units. That means the true speed of the interface is the value reported by this object, plus or minus 500,000 bits/second 🎯.

Other alternatives were considered and rejected too πŸ™…β€β™€οΈ:

  1. Making the interface speed a 64-bit gauge. This got rejected because the current SMI doesn't allow that syntax. Plus, even if 64-bit gauges were available, using them would add complexity to agents because of the increased need for 64-bit operations.
  2. Making "high-32 bit" and "low-32-bit" objects which, when combined, would form a 64-bit value. This just seemed overly complex for what we're trying to do. Also, full 64-bit precision isn't really necessary. The value of ifHighSpeed will be the only report of interface speed for interfaces faster than 4,294,967,295 bits per second. At that speed, the granularity of ifHighSpeed is 1,000,000 bits per second, so the error is 1/4294, or about 0.02%. That seems reasonable ✨.
  3. Adding a "scale" object that would define the units ifSpeed's value is in. This would need two additional objects: one for the scaling, and one to replace the current ifSpeed. That later object is required because the semantics of ifSpeed would be significantly altered, and manager stations that don't understand the new semantics would get confused πŸ˜΅β€πŸ’«.

3.1.8. Multicast/Broadcast Counters πŸ“¦

In MIB-II, the ifTable counters for multicast and broadcast packets are combined into counters of non-unicast packets. The ifExtensions MIB [7] is different, though πŸ€”. It defined one set of counters for multicast and a separate set for broadcast packets. With the separate counters, the original combined counters become redundant. To get rid of that redundancy, the non-unicast counters are deprecated πŸ—‘οΈ.

For the output broadcast and multicast counters defined in RFC 1229, their definitions varied a little from the packet counters in the ifTable. They didn't count errors/discarded packets. So this memo defines new objects with better-aligned definitions πŸ’–. Counters with 64 bits of range are needed too, as explained above.


3.1.9. Trap Enable πŸ””

In the multi-layer interface model, each sub-layer that has an entry in the ifTable can generate linkUp/Down Traps. Interface state changes tend to propagate through the interface (from top to bottom, or bottom to top), so several traps would likely be generated for each linkUp/Down occurrence 😩.

It's really useful to give manager stations a way to control the generation of these traps. To that end, the ifLinkUpDownTrapEnable object was added πŸŽ‰. This object lets managers limit trap generation to just the sub-layers they care about.

The default setting should limit the number of traps generated to one per interface per linkUp/Down event. Also, the state changes most interesting to network managers tend to happen at the lowest level of an interface stack. So by default, we specify that only the lowest sub-layer of the interface generates traps 🧚.


3.1.10. Addition of New ifType values πŸ†•

Over time, there's a need to add new ifType enumerated values for new interface types. If the syntax of ifType were defined in the MIB in section 6, a new version of this MIB would have to be re-issued just to define new values. In the past, re-issuing a MIB only happened after several years 😴.

So the syntax of ifType is changed to be a textual convention. The enumerated integer values are now defined in the textual convention IANAifType, which is defined in a different document. This lets additional values get documented without having to re-issue this document πŸ™Œ. The Internet Assigned Number Authority (IANA) is responsible for assigning all Internet numbers, including various SNMP-related numbers, and specifically, new ifType values 🌈.


3.1.11. InterfaceIndex Textual Convention 🧩

A new textual convention, InterfaceIndex, has been defined. This textual convention "contains" all of the semantics of the ifIndex object. That means other MIB modules can easily import the semantics of ifIndex πŸ’œ.


3.1.12. New states for IfOperStatus 🚦

Three new states have been added to ifOperStatus: 'dormant', 'notPresent', and 'lowerLayerDown' ✨.

The dormant state means the interface isn't actually in a condition to pass packets (it isn't "up"). Instead, it's in a "pending" state, waiting for some external event ⏳. For "on-demand" interfaces, this new state covers the situation where the interface is waiting for events to bring it up. Examples of such events might be:

  1. having packets to transmit before establishing a connection to a remote system;
  2. having a remote system establish a connection to the interface (e.g. dialing up to a slip-server) πŸ“ž.

The notPresent state is a refinement of the down state. It says the interface is down specifically because some component (typically a hardware component) isn't present in the managed system πŸ”Œ. Examples of using the notPresent state are:

  1. to let an interface's conceptual row, including its counter values, be retained across a "hot swap" of a card/module, and/or
  2. to let an interface's conceptual row be created, so interfaces can be pre-configured before the hardware needed to make them operational gets installed πŸ› οΈ.

Agents are not required to support interfaces in the notPresent state. However, conceptually, when a row in the ifTable is created, it first enters the notPresent state and then transitions into the down state. Similarly, when a row in the ifTable is deleted, it first enters the notPresent state and then the object instances are deleted 🫠. For an agent with no support for notPresent, both of these transitions (from notPresent to down, and from notPresent to the instances being removed) are immediate. In other words, the transition doesn't last long enough to be recorded by ifOperStatus. Even for agents that do support interfaces in the notPresent state, how long and under what conditions an interface stays there is implementation-specific πŸ€·β€β™€οΈ.

The lowerLayerDown state is also a refinement of the down state. This new state means the interface runs "on top of" one or more other interfaces (see ifStackTable), and the interface is down specifically because one or more of those lower-layer interfaces are down πŸ§±πŸ’€.

3.1.13. IfAdminStatus and IfOperStatus ✨

okay so the down state of ifOperStatus is lowkey two-faced πŸ’… It means different things depending on what ifAdminStatus says:

  1. if ifAdminStatus is not down and ifOperStatus is down, then a fault condition is presumed to exist on the interface. 😬
  2. if ifAdminStatus is down, then ifOperStatus will normally also be down (or notPresent), i.e., there is not (necessarily) a fault condition on the interface. 🌸

when ifAdminStatus transitions to down, ifOperStatus will normally transition to down too. 🫢 It's possible that ifOperStatus's transition won't happen right away, and instead happens after a small time lag while the interface finishes certain operations before it goes "down". for example, it might need to finish sending a packet first. πŸ“¦ If a manager station sees that ifAdminStatus is down and ifOperStatus is not down for a particular interface, the manager station should wait a short while and check again. Only if the condition still exists should it raise an error indication. 🚨 It should also make sure that ifLastChange hasn't changed during that interval. bestie, double-checking is everything πŸ™ˆ

whenever an interface table entry is created (usually as a result of system initialization), the relevant instance of ifAdminStatus is set to down, and presumably ifOperStatus will be down or notPresent. 🧚

an interface can be enabled in two ways: either through explicit management action (e.g. setting ifAdminStatus to up), or as a result of the managed system's initialization process. ✨ When ifAdminStatus changes to the up state, the related ifOperStatus should do one of the following:

  1. Change to the up state if and only if the interface is able to send and receive packets. πŸ¦‹
  2. Change to the lowerLayerDown state if and only if the interface is prevented from entering the up state because of the state of one or more of the interfaces beneath it in the interface stack. 🧱
  3. Change to the dormant state if and only if the interface is found to be operable, but is waiting for other, external, events to occur before it can transmit or receive packets. presumably, once those expected events happen, the interface will then change to the up state. πŸ’€
  4. Remain in the down state if an error or other fault condition is detected on the interface. πŸ’€
  5. Change to the unknown state if, for some reason, the state of the interface cannot be ascertained. πŸ€·β€β™€οΈ
  6. Change to the testing state if some test(s) must be performed on the interface. presumably, after the test is complete, the interface's state will change to up, dormant, or down, as appropriate. πŸ§ͺ
  7. Remain in the notPresent state if interface components are missing. πŸ”Œ

3.1.14. IfOperStatus in an Interface Stack πŸ₯ž

when an interface is part of an interface-stack, but isn't the lowest interface in the stack, then:

  1. ifOperStatus has the value 'up' if it is able to pass packets because one or more interfaces below it in the stack are 'up', no matter whether the other interfaces below it are 'down', 'dormant', 'notPresent', 'lowerLayerDown', 'unknown' or 'testing'. πŸ‘‘
  2. ifOperStatus may have the value 'up' or 'dormant' if one or more interfaces below it in the stack are 'dormant', and all the others below it are either 'down', 'dormant', 'notPresent', 'lowerLayerDown', 'unknown' or 'testing'. πŸŒ™
  3. ifOperStatus has the value 'lowerLayerDown' while all interfaces below it in the stack are either 'down', 'notPresent', 'lowerLayerDown', or 'testing'. πŸ“

3.1.15. Traps πŸ””

the exact definition of when linkUp and linkDown traps get generated has been changed to match the changes to ifAdminStatus and ifOperStatus. πŸŽ€

operational experience shows that management stations care most about an interface being in the down state, and about the fact that this state may point to a failure. 😭 So it's most useful to instrument transitions into and out of either the up state or the down state.

instrumenting transitions into or out of the up state was rejected, because a demand interface might bounce between up and dormant a bunch of times. that would mean lots of linkUp traps and zero linkDown traps. πŸ™ƒ Plus, if a node's only interface is the demand interface, then a transition to dormant would mean generating a linkDown trap, which would force the link back up to the up state (and a linkUp trap)!! πŸŒ€ chaotic

on the other hand, instrumenting transitions into or out of the down state (to and from every other state except notPresent) has these perks:

  1. A transition into the down state (from a state other than notPresent) happens when an error is detected on an interface. Error conditions are presumably of great interest to network managers. 🚩
  2. Leaving the down state (to a state other than notPresent) generally means the interface is going to either up or dormant, and both of those are considered "healthy" states. πŸ’š

it's also believed that generating traps on transitions into or out of the down state (except to and from the notPresent state) is generally consistent with current usage and how manager stations interpret these traps. 🧠

transitions to and from the notPresent state are about inserting and removing hardware, so they're outside the scope of these traps. πŸ”§

so, this memo defines that linkUp and linkDown traps are generated just after ifOperStatus leaves the down state, or just before it enters the down state, respectively. The exception is that linkUp and linkDown traps are never generated on transitions to or from the notPresent state. ✨

note that this definition lets a node with only one interface send a linkDown trap before that interface goes down. (Of course, when the interface goes down because of a failure condition, the linkDown trap probably can't be successfully sent anyway. πŸ’€)

some interfaces do a link "training" function when they're trying to come up. If such an interface were defective, the training function would fail, the interface would stay down, and the training function might get repeated at appropriate intervals. πŸ‹οΈβ€β™€οΈ If the interface were considered to be in the testing state while doing this training, then linkUp and linkDown traps would be generated for each start and end of the training function. That's not the point of linkUp and linkDown traps, so while the interface is doing this kind of training function, its state should be represented as down. πŸ™…β€β™€οΈ

there's one exception to generating linkUp/linkDown traps on changes in ifOperStatus. It happens when an interface is "flapping", i.e., rapidly oscillating between the up and down states. If traps were generated for every single oscillation, the network and the network management system would get flooded with unnecessary traps. 🌊 In that situation, the agent should rate-limit its trap generation. πŸ›‘

3.1.16. ifSpecific 🧩

the original definition of the OBJECT IDENTIFIER value of ifSpecific wasn't clear enough. As a result, different implementors used it differently, and it got confusing. πŸ˜΅β€πŸ’« Some implementations set the value of ifSpecific to the OBJECT IDENTIFIER that defines the media-specific MIB, i.e., the "foo" of:

foo OBJECT IDENTIFIER ::= { transmission xxx }

others set it to the OBJECT IDENTIFIER of the specific table or entry in the appropriate media-specific MIB (i.e., fooTable or fooEntry), and still others set it to the OBJECT IDENTIFIER of the index object of the table's row, including the instance identifier (i.e., fooIfIndex.ifIndex). A definition based on the latter wouldn't be enough unless it also allowed for media-specific MIBs that include several tables, where each table has its own (different) indexing. πŸ“š

the only definition that can be made explicit and cover all the useful situations is to have ifSpecific be the most general value for the media-specific MIB module (the first example above). πŸ’… That makes it redundant, though, because it contains no more information than ifType already provides. So ifSpecific has been deprecated. πŸ‘‹

3.1.17. Creation/Deletion of Interfaces πŸ—οΈ

some interfaces, like most physical ones, can't be created through network management, but other interfaces, like logical ones, sometimes can be. The ifTable only holds generic information about an interface. Almost all 'create-able' interfaces have other, media-specific information where configuration parameters can be supplied before the interface gets created. πŸŽ›οΈ So the ifTable doesn't itself support creating or deleting an interface (it doesn't have a RowStatus [2] column, specifically). Instead, if a particular interface type supports dynamically creating and/or deleting an interface of that type, then that media-specific MIB should include an appropriate RowStatus object (see the ATM LAN-Emulation Client MIB [8] for an example of a MIB that does this). πŸ“– Typically, when a RowStatus object is created or deleted, the conceptual row in the ifTable appears or disappears as a by-product, and an ifIndex value (chosen by the agent) is stored in an appropriate object in the media-specific MIB. 🧁

3.1.18. All Values Must be Known πŸ”

there are a bunch of situations where an agent doesn't know the value of one or more objects for a particular interface. In all of these circumstances, an agent MUST NOT instantiate an object with an incorrect value. Instead, it MUST respond with the appropriate error/exception condition (e.g., noSuchInstance for SNMPv2). 🚫

one example is when an agent can't count the occurrences defined by one (or more) of the ifTable counters. In this case, the agent MUST NOT instantiate the particular counter with a value of, say, zero. πŸ™…β€β™€οΈ That would hand a network management application misinformation: it would read the zero and assume the event never happened (e.g., no input errors, because ifInErrors is always zero). 😱

sometimes not knowing an object's value is only temporary. For example, the MTU of an interface might be a configured value that a device only learns dynamically through (or after) exchanging messages over the interface (e.g., ATM LAN-Emulation [8]). In that case, the value isn't known until after the ifTable entry has already been created. So the ifTable entry should be created without an instance of the object whose value is unknown. Later, when the value becomes known, the missing object can then be instantiated (e.g., the instance of ifMtu is only instantiated once the interface's MTU becomes known). ⏳

because of this "known values" rule, management applications MUST be able to cope with responses to retrieving the object instances within a conceptual row of the ifTable that reveal some of the row's columnar objects are missing or not available. 🫢

4. Media-Specific MIB Applicability ✨

okay so this MIB is super generic (it's built to fit basically everything 🫢), which means the exact use and meaning of a lot of its objects is kinda open to interpretation πŸ€”. It's not always possible to write text that's specific and unambiguous for every case and still keep that generic vibe, so it's giving... tricky πŸ’….

So it's on the media-specific MIB designer to clarify how the objects in this MIB get used with their media-specific MIB, wherever that's needed. The areas that need clarifying include:

  • Layering Model: The media-specific MIB designer MUST completely and unambiguously specify the layering model used. Each individual sub-layer must be identified, as must the ifStackTable's portrayal of the relationship(s) between the sub-layers.
  • Virtual Circuits: The media-specific MIB designer MUST specify whether virtual circuits are assigned entries in the ifTable or not. If they are, compelling rationale must be presented.
  • ifRcvAddressTable: The media-specific MIB designer MUST specify the applicability of the ifRcvAddressTable.
  • ifType: For each of the ifType values to which the media-specific MIB applies, it must specify the mapping of ifType values to media-specific MIB module(s) and instances of MIB objects within those modules.

However, wherever this interface MIB is specific about the semantics, DESCRIPTION, or applicability of objects, the media-specific MIB designer MUST NOT change said semantics, DESCRIPTION, or applicability πŸ™…β€β™€οΈ. Hands off the good stuff, bestie πŸŽ€.


5. Overview 🌸

okay so this MIB has 4 tables πŸ¦‹:

  • ifTable: This table is the ifTable from MIB-II.
  • ifXTable: This table holds objects that were added to the Interface MIB because of the Interface Evolution effort, plus replacements for objects from the original (MIB-II) ifTable that got deprecated because their semantics changed a lot. It also holds objects that used to live in the ifExtnsTable πŸ’….
  • ifStackTable: This table holds objects that define the relationships among the sub-layers of an interface 🧚.
  • ifRcvAddressTable: This table holds objects used to define the media-level addresses this interface will receive. It's a generic table, so the designers of media-specific MIBs must define exactly how it applies to their MIB 🫢.

6. Interfaces Group Definitions πŸ‘‘

here's the actual MIB module, the main event πŸ”₯. It's copied exactly, so don't touch a single character πŸ™ˆ:

   IF-MIB DEFINITIONS ::= BEGIN

   IMPORTS
       MODULE-IDENTITY, OBJECT-TYPE, Counter32, Gauge32, Counter64,
       Integer32, TimeTicks, mib-2,
       NOTIFICATION-TYPE                        FROM SNMPv2-SMI
       TEXTUAL-CONVENTION, DisplayString,
       PhysAddress, TruthValue, RowStatus,
       TimeStamp, AutonomousType, TestAndIncr   FROM SNMPv2-TC
       MODULE-COMPLIANCE, OBJECT-GROUP          FROM SNMPv2-CONF
       snmpTraps                                FROM SNMPv2-MIB
       IANAifType                               FROM IANAifType-MIB;

   ifMIB MODULE-IDENTITY
       LAST-UPDATED "9611031355Z"
       ORGANIZATION "IETF Interfaces MIB Working Group"
       CONTACT-INFO
               "   Keith McCloghrie
                   Cisco Systems, Inc.
                   170 West Tasman Drive
                   San Jose, CA  95134-1706
                   US

                   408-526-5260
                   kzm@cisco.com"
       DESCRIPTION
               "The MIB module to describe generic objects for
               network interface sub-layers.  This MIB is an updated
               version of MIB-II's ifTable, and incorporates the
               extensions defined in RFC 1229."
       REVISION      "9602282155Z"
       DESCRIPTION
               "Revisions made by the Interfaces MIB WG."
       REVISION      "9311082155Z"
       DESCRIPTION
               "Initial revision, published as part of RFC 1573."
       ::= { mib-2 31 }


   ifMIBObjects OBJECT IDENTIFIER ::= { ifMIB 1 }

   interfaces   OBJECT IDENTIFIER ::= { mib-2 2 }


   OwnerString ::= TEXTUAL-CONVENTION
       DISPLAY-HINT "255a"
       STATUS       current
       DESCRIPTION
               "This data type is used to model an administratively
               assigned name of the owner of a resource.  This
               information is taken from the NVT ASCII character set.
               It is suggested that this name contain one or more of
               the following: ASCII form of the manager station's
               transport address, management station name (e.g.,
               domain name), network management personnel's name,
               location, or phone number.  In some cases the agent
               itself will be the owner of an entry.  In these cases,
               this string shall be set to a string starting with
               'agent'."
       SYNTAX       OCTET STRING (SIZE(0..255))

   -- InterfaceIndex contains the semantics of ifIndex and
   -- should be used for any objects defined on other mib
   -- modules that need these semantics.

   InterfaceIndex ::= TEXTUAL-CONVENTION
       DISPLAY-HINT "d"
       STATUS       current
       DESCRIPTION
               "A unique value, greater than zero, for each interface
               or interface sub-layer in the managed system.  It is
               recommended that values are assigned contiguously
               starting from 1.  The value for each interface sub-
               layer must remain constant at least from one re-
               initialization of the entity's network management
               system to the next re-initialization."
       SYNTAX       Integer32 (1..2147483647)


   InterfaceIndexOrZero ::= TEXTUAL-CONVENTION
       DISPLAY-HINT "d"
       STATUS       current
       DESCRIPTION
               "This textual convention is an extension of the
               InterfaceIndex convention.  The latter defines a
               greater than zero value used to identify an interface
               or interface sub-layer in the managed system.  This
               extension permits the additional value of zero.  the
               value zero is object-specific and must therefore be
               defined as part of the description of any object which
               uses this syntax.  Examples of the usage of zero might
               include situations where interface was unknown, or
               when none or all interfaces need to be referenced."
       SYNTAX       Integer32 (0..2147483647)


   ifNumber  OBJECT-TYPE
       SYNTAX      Integer32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The number of network interfaces (regardless of their
               current state) present on this system."
       ::= { interfaces 1 }

   ifTableLastChange  OBJECT-TYPE
       SYNTAX      TimeTicks
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The value of sysUpTime at the time of the last
               creation or deletion of an entry in the ifTable.  If
               the number of entries has been unchanged since the
               last re-initialization of the local network management
               subsystem, then this object contains a zero value."
       ::= { ifMIBObjects 5 }


   -- the Interfaces table

   -- The Interfaces table contains information on the entity's
   -- interfaces.  Each sub-layer below the internetwork-layer
   -- of a network interface is considered to be an interface.

   ifTable OBJECT-TYPE
       SYNTAX      SEQUENCE OF IfEntry
       MAX-ACCESS  not-accessible
       STATUS      current
       DESCRIPTION
               "A list of interface entries.  The number of entries
               is given by the value of ifNumber."
       ::= { interfaces 2 }

   ifEntry OBJECT-TYPE
       SYNTAX      IfEntry
       MAX-ACCESS  not-accessible
       STATUS      current
       DESCRIPTION
               "An entry containing management information applicable
               to a particular interface."
       INDEX   { ifIndex }



       ::= { ifTable 1 }

   IfEntry ::=
       SEQUENCE {
           ifIndex                 InterfaceIndex,
           ifDescr                 DisplayString,
           ifType                  IANAifType,
           ifMtu                   Integer32,
           ifSpeed                 Gauge32,
           ifPhysAddress           PhysAddress,
           ifAdminStatus           INTEGER,
           ifOperStatus            INTEGER,
           ifLastChange            TimeTicks,
           ifInOctets              Counter32,
           ifInUcastPkts           Counter32,
           ifInNUcastPkts          Counter32,  -- deprecated
           ifInDiscards            Counter32,
           ifInErrors              Counter32,
           ifInUnknownProtos       Counter32,
           ifOutOctets             Counter32,
           ifOutUcastPkts          Counter32,
           ifOutNUcastPkts         Counter32,  -- deprecated
           ifOutDiscards           Counter32,
           ifOutErrors             Counter32,
           ifOutQLen               Gauge32,    -- deprecated
           ifSpecific              OBJECT IDENTIFIER -- deprecated
       }


   ifIndex OBJECT-TYPE
       SYNTAX      InterfaceIndex
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "A unique value, greater than zero, for each
               interface.  It is recommended that values are assigned
               contiguously starting from 1.  The value for each
               interface sub-layer must remain constant at least from
               one re-initialization of the entity's network
               management system to the next re-initialization."
       ::= { ifEntry 1 }

   ifDescr OBJECT-TYPE
       SYNTAX      DisplayString (SIZE (0..255))
       MAX-ACCESS  read-only


       STATUS      current
       DESCRIPTION
               "A textual string containing information about the
               interface.  This string should include the name of the
               manufacturer, the product name and the version of the
               interface hardware/software."
       ::= { ifEntry 2 }

   ifType OBJECT-TYPE
       SYNTAX      IANAifType
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The type of interface.  Additional values for ifType
               are assigned by the Internet Assigned Numbers
               Authority (IANA), through updating the syntax of the
               IANAifType textual convention."
       ::= { ifEntry 3 }

   ifMtu OBJECT-TYPE
       SYNTAX      Integer32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The size of the largest packet which can be
               sent/received on the interface, specified in octets.
               For interfaces that are used for transmitting network
               datagrams, this is the size of the largest network
               datagram that can be sent on the interface."
       ::= { ifEntry 4 }

okay so this next batch is all about the ifEntry columns, aka the per-interface stats and status fields, and bestie, they're doing a lot πŸ’… Speed, addresses, admin vs. oper status, and the counters that tally up packets in and out. I'm keeping the MIB definitions word for word, since implementers rely on every single one 🫢

The big one first: ifSpeed is the bandwidth check ⚑ It's a Gauge32, and when the real bandwidth is too big to fit, it maxes out and ifHighSpeed takes over πŸ¦‹

   ifSpeed OBJECT-TYPE
       SYNTAX      Gauge32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "An estimate of the interface's current bandwidth in
               bits per second.  For interfaces which do not vary in
               bandwidth or for those where no accurate estimation
               can be made, this object should contain the nominal
               bandwidth.  If the bandwidth of the interface is
               greater than the maximum value reportable by this
               object then this object should report its maximum
               value (4,294,967,295) and ifHighSpeed must be used to
               report the interace's speed.  For a sub-layer which
               has no concept of bandwidth, this object should be
               zero."
       ::= { ifEntry 5 }

ifPhysAddress is the interface's address at its own protocol sub-layer 🌸 For an 802.x interface that's usually a MAC address. The media-specific MIB decides the bit ordering and format, and if there's no address at all (a serial line, for example), you get a zero-length octet string 🧚

   ifPhysAddress OBJECT-TYPE
       SYNTAX      PhysAddress
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The interface's address at its protocol sub-layer.
               For example, for an 802.x interface, this object
               normally contains a MAC address.  The interface's
               media-specific MIB must define the bit and byte
               ordering and the format of the value of this object.
               For interfaces which do not have such an address
               (e.g., a serial line), this object should contain an
               octet string of zero length."
       ::= { ifEntry 6 }

Now the admin vs. oper status situation, which is very much a "two sides of the same coin" moment πŸͺ™ ifAdminStatus is what you WANT the interface to do (up, down, or testing), and every interface starts out down(2) when the system boots πŸ”₯

   ifAdminStatus OBJECT-TYPE
       SYNTAX  INTEGER {
                   up(1),       -- ready to pass packets
                   down(2),
                   testing(3)   -- in some test mode
               }
       MAX-ACCESS  read-write
       STATUS      current
       DESCRIPTION
               "The desired state of the interface.  The testing(3)
               state indicates that no operational packets can be
               passed.  When a managed system initializes, all
               interfaces start with ifAdminStatus in the down(2)
               state.  As a result of either explicit management
               action or per configuration information retained by
               the managed system, ifAdminStatus is then changed to
               either the up(1) or testing(3) states (or remains in
               the down(2) state)."
       ::= { ifEntry 7 }

ifOperStatus is the real-life state, the vibe the interface is actually giving πŸ‘‘ It has more options, like unknown(4), dormant(5), notPresent(6), and lowerLayerDown(7), and the description spells out how it should follow ifAdminStatus πŸ’€

   ifOperStatus OBJECT-TYPE
       SYNTAX  INTEGER {
                   up(1),        -- ready to pass packets
                   down(2),
                   testing(3),   -- in some test mode
                   unknown(4),   -- status can not be determined
                                 -- for some reason.
                   dormant(5),
                   notPresent(6),    -- some component is missing
                   lowerLayerDown(7) -- down due to state of
                                     -- lower-layer interface(s)
               }

       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The current operational state of the interface.  The
               testing(3) state indicates that no operational packets
               can be passed.  If ifAdminStatus is down(2) then
               ifOperStatus should be down(2).  If ifAdminStatus is
               changed to up(1) then ifOperStatus should change to
               up(1) if the interface is ready to transmit and
               receive network traffic; it should change to
               dormant(5) if the interface is waiting for external
               actions (such as a serial line waiting for an incoming
               connection); it should remain in the down(2) state if
               and only if there is a fault that prevents it from
               going to the up(1) state; it should remain in the
               notPresent(6) state if the interface has missing
               (typically, hardware) components."
       ::= { ifEntry 8 }

ifLastChange is the timestamp for when the interface last changed its operational state ⏰ It's measured against sysUpTime, and if the change happened before the management subsystem last re-initialized, it just reads zero πŸ™ˆ

   ifLastChange OBJECT-TYPE
       SYNTAX      TimeTicks
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The value of sysUpTime at the time the interface
               entered its current operational state.  If the current
               state was entered prior to the last re-initialization
               of the local network management subsystem, then this
               object contains a zero value."
       ::= { ifEntry 9 }

Now the counters, which are giving "keeping receipts" energy 🧾 Every counter below has the same discontinuity note, so the important bit is that they can reset at re-initialization or whenever ifCounterDiscontinuityTime says so 🌈

   ifInOctets OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The total number of octets received on the interface,
               including framing characters.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifEntry 10 }

   ifInUcastPkts OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The number of packets, delivered by this sub-layer to
               a higher (sub-)layer, which were not addressed to a
               multicast or broadcast address at this sub-layer.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifEntry 11 }

   ifInNUcastPkts OBJECT-TYPE
       SYNTAX  Counter32
       MAX-ACCESS  read-only
       STATUS      deprecated
       DESCRIPTION
               "The number of packets, delivered by this sub-layer to
               a higher (sub-)layer, which were addressed to a
               multicast or broadcast address at this sub-layer.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime.

               This object is deprecated in favour of
               ifInMulticastPkts and ifInBroadcastPkts."
       ::= { ifEntry 12 }

   ifInDiscards OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The number of inbound packets which were chosen to be
               discarded even though no errors had been detected to
               prevent their being deliverable to a higher-layer
               protocol.  One possible reason for discarding such a
               packet could be to free up buffer space.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."

       ::= { ifEntry 13 }

   ifInErrors OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "For packet-oriented interfaces, the number of inbound
               packets that contained errors preventing them from
               being deliverable to a higher-layer protocol.  For
               character-oriented or fixed-length interfaces, the
               number of inbound transmission units that contained
               errors preventing them from being deliverable to a
               higher-layer protocol.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifEntry 14 }

   ifInUnknownProtos OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "For packet-oriented interfaces, the number of packets
               received via the interface which were discarded
               because of an unknown or unsupported protocol.  For
               character-oriented or fixed-length interfaces that
               support protocol multiplexing the number of
               transmission units received via the interface which
               were discarded because of an unknown or unsupported
               protocol.  For any interface that does not support
               protocol multiplexing, this counter will always be 0.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifEntry 15 }

   ifOutOctets OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The total number of octets transmitted out of the
               interface, including framing characters.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifEntry 16 }

   ifOutUcastPkts OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The total number of packets that higher-level
               protocols requested be transmitted, and which were not
               addressed to a multicast or broadcast address at this
               sub-layer, including those that were discarded or not
               sent.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifEntry 17 }

   ifOutNUcastPkts OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      deprecated
       DESCRIPTION
               "The total number of packets that higher-level
               protocols requested be transmitted, and which were
               addressed to a multicast or broadcast address at this
               sub-layer, including those that were discarded or not
               sent.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime.

               This object is deprecated in favour of
               ifOutMulticastPkts and ifOutBroadcastPkts."
       ::= { ifEntry 18 }

   ifOutDiscards OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The number of outbound packets which were chosen to
               be discarded even though no errors had been detected
               to prevent their being transmitted.  One possible
               reason for discarding such a packet could be to free
               up buffer space.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifEntry 19 }

   ifOutErrors OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "For packet-oriented interfaces, the number of
               outbound packets that could not be transmitted because
               of errors.  For character-oriented or fixed-length
               interfaces, the number of outbound transmission units
               that could not be transmitted because of errors.
               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifEntry 20 }


   ifOutQLen OBJECT-TYPE
       SYNTAX      Gauge32
       MAX-ACCESS  read-only
       STATUS      deprecated
       DESCRIPTION
               "The length of the output packet queue (in packets)."
       ::= { ifEntry 21 }

   ifSpecific OBJECT-TYPE
       SYNTAX      OBJECT IDENTIFIER
       MAX-ACCESS  read-only
       STATUS      deprecated
       DESCRIPTION
               "A reference to MIB definitions specific to the
               particular media being used to realize the interface.
               It is recommended that this value point to an instance
               of a MIB object in the media-specific MIB, i.e., that
               this object have the semantics associated with the
               InstancePointer textual convention defined in RFC
               1903.  In fact, it is recommended that the media-
               specific MIB specify what value ifSpecific should/can
               take for values of ifType.  If no MIB definitions
               specific to the particular media are available, the
               value should be set to the OBJECT IDENTIFIER { 0 0 }."
       ::= { ifEntry 22 }

okay so ifOutQLen is marked deprecated, which is giving retired-but-still-in-the-group-chat energy πŸ₯€. ifSpecific is deprecated too, but its DESCRIPTION is a whole pointer situation. It talks about the InstancePointer textual convention from RFC 1903, and it says what the value should be when no media-specific MIB exists: the OBJECT IDENTIFIER { 0 0 } 🫢


   --
   --   Extension to the interface table
   --
   -- This table replaces the ifExtnsTable table.
   --

   ifXTable        OBJECT-TYPE
       SYNTAX      SEQUENCE OF IfXEntry
       MAX-ACCESS  not-accessible
       STATUS      current
       DESCRIPTION
               "A list of interface entries.  The number of entries
               is given by the value of ifNumber.  This table
               contains additional objects for the interface table."
       ::= { ifMIBObjects 1 }

   ifXEntry        OBJECT-TYPE
       SYNTAX      IfXEntry
       MAX-ACCESS  not-accessible
       STATUS      current
       DESCRIPTION
               "An entry containing additional management information
               applicable to a particular interface."
       AUGMENTS    { ifEntry }
       ::= { ifXTable 1 }

   IfXEntry ::=
       SEQUENCE {
           ifName                  DisplayString,
           ifInMulticastPkts       Counter32,
           ifInBroadcastPkts       Counter32,
           ifOutMulticastPkts      Counter32,
           ifOutBroadcastPkts      Counter32,
           ifHCInOctets            Counter64,
           ifHCInUcastPkts         Counter64,
           ifHCInMulticastPkts     Counter64,
           ifHCInBroadcastPkts     Counter64,
           ifHCOutOctets           Counter64,
           ifHCOutUcastPkts        Counter64,
           ifHCOutMulticastPkts    Counter64,
           ifHCOutBroadcastPkts    Counter64,
           ifLinkUpDownTrapEnable  INTEGER,
           ifHighSpeed             Gauge32,
           ifPromiscuousMode       TruthValue,
           ifConnectorPresent      TruthValue,
           ifAlias                 DisplayString,
           ifCounterDiscontinuityTime TimeStamp
       }

ooh, the ifXTable is the new extension table, and the file literally says it replaces the ifExtnsTable πŸ’… It hangs off ifMIBObjects 1, and each row is an ifXEntry that augments ifEntry. The IfXEntry SEQUENCE is the full lineup of columns, from the 32-bit multicast and broadcast counters all the way to ifCounterDiscontinuityTime πŸ¦‹


   ifName OBJECT-TYPE
       SYNTAX      DisplayString
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The textual name of the interface.  The value of this
               object should be the name of the interface as assigned
               by the local device and should be suitable for use in
               commands entered at the device's `console'.  This
               might be a text name, such as `le0' or a simple port
               number, such as `1', depending on the interface naming
               syntax of the device.  If several entries in the
               ifTable together represent a single interface as named
               by the device, then each will have the same value of
               ifName.  Note that for an agent which responds to SNMP
               queries concerning an interface on some other
               (proxied) device, then the value of ifName for such an
               interface is the proxied device's local name for it.

               If there is no local name, or this object is otherwise
               not applicable, then this object contains a zero-
               length string."
       ::= { ifXEntry 1 }

   ifInMulticastPkts OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The number of packets, delivered by this sub-layer to
               a higher (sub-)layer, which were addressed to a
               multicast address at this sub-layer.  For a MAC layer
               protocol, this includes both Group and Functional
               addresses.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifXEntry 2 }

   ifInBroadcastPkts OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The number of packets, delivered by this sub-layer to
               a higher (sub-)layer, which were addressed to a
               broadcast address at this sub-layer.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifXEntry 3 }

   ifOutMulticastPkts OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The total number of packets that higher-level
               protocols requested be transmitted, and which were
               addressed to a multicast address at this sub-layer,
               including those that were discarded or not sent.  For
               a MAC layer protocol, this includes both Group and
               Functional addresses.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."

       ::= { ifXEntry 4 }

   ifOutBroadcastPkts OBJECT-TYPE
       SYNTAX      Counter32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The total number of packets that higher-level
               protocols requested be transmitted, and which were
               addressed to a broadcast address at this sub-layer,
               including those that were discarded or not sent.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifXEntry 5 }

this part is giving name and counters realness πŸŽ€ ifName is the device's own name for the interface, like le0 or just 1, and if several ifTable rows make up one interface, they all share the same ifName. For proxied devices it's the proxied device's local name, and if there's no local name it's a zero-length string 🌸 The multicast and broadcast packet counters are the 32-bit ones, and each has that same discontinuity note tied to ifCounterDiscontinuityTime πŸ’œ


   --
   -- High Capacity Counter objects.  These objects are all
   -- 64 bit versions of the "basic" ifTable counters.  These
   -- objects all have the same basic semantics as their 32-bit
   -- counterparts, however, their syntax has been extended
   -- to 64 bits.
   --

   ifHCInOctets OBJECT-TYPE
       SYNTAX      Counter64
       MAX-ACCESS  read-only
       STATUS      current

       DESCRIPTION
               "The total number of octets received on the interface,
               including framing characters.  This object is a 64-bit
               version of ifInOctets.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifXEntry 6 }

   ifHCInUcastPkts OBJECT-TYPE
       SYNTAX      Counter64
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The number of packets, delivered by this sub-layer to
               a higher (sub-)layer, which were not addressed to a
               multicast or broadcast address at this sub-layer.
               This object is a 64-bit version of ifInUcastPkts.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifXEntry 7 }

   ifHCInMulticastPkts OBJECT-TYPE
       SYNTAX      Counter64
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The number of packets, delivered by this sub-layer to
               a higher (sub-)layer, which were addressed to a
               multicast address at this sub-layer.  For a MAC layer
               protocol, this includes both Group and Functional
               addresses.  This object is a 64-bit version of
               ifInMulticastPkts.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifXEntry 8 }


   ifHCInBroadcastPkts OBJECT-TYPE
       SYNTAX      Counter64
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The number of packets, delivered by this sub-layer to
               a higher (sub-)layer, which were addressed to a
               broadcast address at this sub-layer.  This object is a
               64-bit version of ifInBroadcastPkts.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifXEntry 9 }

   ifHCOutOctets OBJECT-TYPE
       SYNTAX      Counter64
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The total number of octets transmitted out of the
               interface, including framing characters.  This object
               is a 64-bit version of ifOutOctets.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifXEntry 10 }

   ifHCOutUcastPkts OBJECT-TYPE
       SYNTAX      Counter64
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The total number of packets that higher-level
               protocols requested be transmitted, and which were not
               addressed to a multicast or broadcast address at this
               sub-layer, including those that were discarded or not
               sent.  This object is a 64-bit version of
               ifOutUcastPkts.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifXEntry 11 }

   ifHCOutMulticastPkts OBJECT-TYPE
       SYNTAX      Counter64
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The total number of packets that higher-level
               protocols requested be transmitted, and which were
               addressed to a multicast address at this sub-layer,
               including those that were discarded or not sent.  For
               a MAC layer protocol, this includes both Group and
               Functional addresses.  This object is a 64-bit version
               of ifOutMulticastPkts.

the high capacity counters are the big-brain upgrades 🧚 The comment says it outright: they're all 64-bit versions of the basic ifTable counters, with the same semantics but a wider syntax, so the numbers can go way higher without wrapping around as fast πŸ”₯ Every one of them has the same discontinuity note, so it's giving consistency, bestie πŸ™ˆ

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifXEntry 12 }

   ifHCOutBroadcastPkts OBJECT-TYPE
       SYNTAX      Counter64
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The total number of packets that higher-level
               protocols requested be transmitted, and which were
               addressed to a broadcast address at this sub-layer,
               including those that were discarded or not sent.  This
               object is a 64-bit version of ifOutBroadcastPkts.

               Discontinuities in the value of this counter can occur
               at re-initialization of the management system, and at
               other times as indicated by the value of
               ifCounterDiscontinuityTime."
       ::= { ifXEntry 13 }

   ifLinkUpDownTrapEnable  OBJECT-TYPE
       SYNTAX      INTEGER { enabled(1), disabled(2) }
       MAX-ACCESS  read-write
       STATUS      current
       DESCRIPTION

               "Indicates whether linkUp/linkDown traps should be
               generated for this interface.

               By default, this object should have the value
               enabled(1) for interfaces which do not operate on
               'top' of any other interface (as defined in the
               ifStackTable), and disabled(2) otherwise."
       ::= { ifXEntry 14 }

   ifHighSpeed OBJECT-TYPE
       SYNTAX      Gauge32
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "An estimate of the interface's current bandwidth in
               units of 1,000,000 bits per second.  If this object
               reports a value of `n' then the speed of the interface
               is somewhere in the range of `n-500,000' to
               `n+499,999'.  For interfaces which do not vary in
               bandwidth or for those where no accurate estimation
               can be made, this object should contain the nominal
               bandwidth.  For a sub-layer which has no concept of
               bandwidth, this object should be zero."
       ::= { ifXEntry 15 }

   ifPromiscuousMode  OBJECT-TYPE
       SYNTAX      TruthValue
       MAX-ACCESS  read-write
       STATUS      current
       DESCRIPTION
               "This object has a value of false(2) if this interface
               only accepts packets/frames that are addressed to this
               station.  This object has a value of true(1) when the
               station accepts all packets/frames transmitted on the
               media.  The value true(1) is only legal on certain
               types of media.  If legal, setting this object to a
               value of true(1) may require the interface to be reset
               before becoming effective.

               The value of ifPromiscuousMode does not affect the
               reception of broadcast and multicast packets/frames by
               the interface."
       ::= { ifXEntry 16 }

   ifConnectorPresent   OBJECT-TYPE
       SYNTAX      TruthValue
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "This object has the value 'true(1)' if the interface
               sublayer has a physical connector and the value
               'false(2)' otherwise."
       ::= { ifXEntry 17 }

   ifAlias   OBJECT-TYPE
       SYNTAX      DisplayString (SIZE(0..64))
       MAX-ACCESS  read-write
       STATUS      current
       DESCRIPTION
               "This object is an 'alias' name for the interface as
               specified by a network manager, and provides a non-
               volatile 'handle' for the interface.

               On the first instantiation of an interface, the value
               of ifAlias associated with that interface is the
               zero-length string.  As and when a value is written
               into an instance of ifAlias through a network
               management set operation, then the agent must retain
               the supplied value in the ifAlias instance associated
               with the same interface for as long as that interface
               remains instantiated, including across all re-
               initializations/reboots of the network management
               system, including those which result in a change of
               the interface's ifIndex value.

               An example of the value which a network manager might
               store in this object for a WAN interface is the
               (Telco's) circuit number/identifier of the interface.

               Some agents may support write-access only for
               interfaces having particular values of ifType.  An
               agent which supports write access to this object is
               required to keep the value in non-volatile storage,
               but it may limit the length of new values depending on
               how much storage is already occupied by the current
               values for other interfaces."
       ::= { ifXEntry 18 }

   ifCounterDiscontinuityTime OBJECT-TYPE
       SYNTAX      TimeStamp
       MAX-ACCESS  read-only
       STATUS      current
       DESCRIPTION
               "The value of sysUpTime on the most recent occasion at
               which any one or more of this interface's counters
               suffered a discontinuity.  The relevant counters are
               the specific instances associated with this interface
               of any Counter32 or Counter64 object contained in the
               ifTable or ifXTable.  If no such discontinuities have
               occurred since the last re-initialization of the local
               management subsystem, then this object contains a zero
               value."
       ::= { ifXEntry 19 }


   --           The Interface Stack Group
   --
   -- Implementation of this group is mandatory for all systems
   --

   ifStackTable  OBJECT-TYPE
        SYNTAX        SEQUENCE OF IfStackEntry
        MAX-ACCESS    not-accessible
        STATUS        current
        DESCRIPTION

               "The table containing information on the relationships
               between the multiple sub-layers of network interfaces.
               In particular, it contains information on which sub-
               layers run 'on top of' which other sub-layers, where
               each sub-layer corresponds to a conceptual row in the
               ifTable.  For example, when the sub-layer with ifIndex
               value x runs over the sub-layer with ifIndex value y,
               then this table contains:

                 ifStackStatus.x.y=active

               For each ifIndex value, I, which identifies an active
               interface, there are always at least two instantiated
               rows in this table associated with I.  For one of
               these rows, I is the value of ifStackHigherLayer; for
               the other, I is the value of ifStackLowerLayer.  (If I
               is not involved in multiplexing, then these are the
               only two rows associated with I.)

               For example, two rows exist even for an interface
               which has no others stacked on top or below it:

                 ifStackStatus.0.x=active
                 ifStackStatus.x.0=active "
        ::= { ifMIBObjects 2 }


   ifStackEntry  OBJECT-TYPE
        SYNTAX        IfStackEntry
        MAX-ACCESS    not-accessible
        STATUS        current
        DESCRIPTION
               "Information on a particular relationship between two
               sub-layers, specifying that one sub-layer runs on
               'top' of the other sub-layer.  Each sub-layer
               corresponds to a conceptual row in the ifTable."
        INDEX { ifStackHigherLayer, ifStackLowerLayer }
        ::= { ifStackTable 1 }


   IfStackEntry ::=
       SEQUENCE {
           ifStackHigherLayer  Integer32,
           ifStackLowerLayer   Integer32,
           ifStackStatus       RowStatus
        }

   ifStackHigherLayer  OBJECT-TYPE
        SYNTAX        Integer32
        MAX-ACCESS    not-accessible
        STATUS        current
        DESCRIPTION
               "The value of ifIndex corresponding to the higher
               sub-layer of the relationship, i.e., the sub-layer
               which runs on 'top' of the sub-layer identified by the
               corresponding instance of ifStackLowerLayer.  If there
               is no higher sub-layer (below the internetwork layer),
               then this object has the value 0."
        ::= { ifStackEntry 1 }


   ifStackLowerLayer  OBJECT-TYPE
        SYNTAX        Integer32
        MAX-ACCESS    not-accessible
        STATUS        current
        DESCRIPTION
               "The value of ifIndex corresponding to the lower sub-
               layer of the relationship, i.e., the sub-layer which
               runs 'below' the sub-layer identified by the
               corresponding instance of ifStackHigherLayer.  If
               there is no lower sub-layer, then this object has the
               value 0."
        ::= { ifStackEntry 2 }


   ifStackStatus  OBJECT-TYPE
       SYNTAX         RowStatus
       MAX-ACCESS     read-create
       STATUS         current
       DESCRIPTION
               "The status of the relationship between two sub-
               layers.

               Changing the value of this object from 'active' to
               'notInService' or 'destroy' will likely have
               consequences up and down the interface stack.  Thus,
               write access to this object is likely to be
               inappropriate for some types of interfaces, and many
               implementations will choose not to support write-
               access for any type of interface."
       ::= { ifStackEntry 3 }

   ifStackLastChange OBJECT-TYPE
       SYNTAX         TimeTicks
       MAX-ACCESS     read-only
       STATUS         current
       DESCRIPTION
               "The value of sysUpTime at the time of the last change
               of the (whole) interface stack.  A change of the
               interface stack is defined to be any creation,
               deletion, or change in value of any instance of
               ifStackStatus.  If the interface stack has been
               unchanged since the last re-initialization of the
               local network management subsystem, then this object
               contains a zero value."
       ::= { ifMIBObjects 6 }


   --   Generic Receive Address Table
   --
   -- This group of objects is mandatory for all types of
   -- interfaces which can receive packets/frames addressed to
   -- more than one address.
   --
   -- This table replaces the ifExtnsRcvAddr table.  The main
   -- difference is that this table makes use of the RowStatus
   -- textual convention, while ifExtnsRcvAddr did not.

   ifRcvAddressTable  OBJECT-TYPE
       SYNTAX      SEQUENCE OF IfRcvAddressEntry
       MAX-ACCESS  not-accessible
       STATUS      current
       DESCRIPTION
               "This table contains an entry for each address
               (broadcast, multicast, or uni-cast) for which the
               system will receive packets/frames on a particular
               interface, except as follows:

               - for an interface operating in promiscuous mode,
               entries are only required for those addresses for
               which the system would receive frames were it not
               operating in promiscuous mode.

               - for 802.5 functional addresses, only one entry is
               required, for the address which has the functional
               address bit ANDed with the bit mask of all functional
               addresses for which the interface will accept frames.
Okay bestie, that's the whole MIB chunk for now, and the functional address bit trick at the bottom is giving pure main character energy πŸ¦‹βœ¨

Okay so the ifRcvAddressTable description wraps up right here, and it's giving "a system can totally use these addresses as its source address" πŸ’…

               A system is normally able to use any unicast address
               which corresponds to an entry in this table as a
               source address."
       ::= { ifMIBObjects 4 }

Bestie, the ifRcvAddressEntry is the row, and it's the main character of this whole table πŸ‘‘ Its INDEX is { ifIndex, ifRcvAddressAddress }, so each row is keyed by an interface and an address that interface will accept packets or frames for πŸ¦‹

   ifRcvAddressEntry  OBJECT-TYPE
       SYNTAX      IfRcvAddressEntry
       MAX-ACCESS  not-accessible
       STATUS      current
       DESCRIPTION
               "A list of objects identifying an address for which
               the system will accept packets/frames on the
               particular interface identified by the index value
               ifIndex."
       INDEX  { ifIndex, ifRcvAddressAddress }
       ::= { ifRcvAddressTable 1 }

   IfRcvAddressEntry ::=
       SEQUENCE {
           ifRcvAddressAddress   PhysAddress,
           ifRcvAddressStatus    RowStatus,
           ifRcvAddressType      INTEGER
       }

So the row has three columns πŸŽ€ First up is ifRcvAddressAddress, a PhysAddress that's not-accessible (it's the index, so no peeking directly, iykyk πŸ™ˆ). It's basically the address the interface accepts packets or frames on.

   ifRcvAddressAddress OBJECT-TYPE
       SYNTAX      PhysAddress
       MAX-ACCESS  not-accessible
       STATUS      current
       DESCRIPTION
               "An address for which the system will accept
               packets/frames on this entry's interface."

       ::= { ifRcvAddressEntry 1 }

Next is ifRcvAddressStatus, which is a RowStatus and is the object you use to create and delete rows 🌸 It's read-create, so you can actually write to it, and yes that's how the table grows and shrinks.

   ifRcvAddressStatus OBJECT-TYPE
       SYNTAX      RowStatus
       MAX-ACCESS  read-create
       STATUS      current
       DESCRIPTION
               "This object is used to create and delete rows in the
               ifRcvAddressTable."

       ::= { ifRcvAddressEntry 2 }

Then there's ifRcvAddressType, which is the drama queen of the row 😭 It's an INTEGER with three options: other(1), volatile(2), and nonVolatile(3). It defaults to volatile, and the description explains how each value is about whether the entry survives a restart of the managed system. nonVolatile(3) means it's valid and won't get deleted by the next restart, volatile(2) means it's valid but hasn't been saved so it won't exist after restart, and other(1) means it's valid but it isn't classified as to whether it'll stick around. Very "will we or won't we" energy πŸ’€

   ifRcvAddressType OBJECT-TYPE
       SYNTAX      INTEGER {
                       other(1),
                       volatile(2),
                       nonVolatile(3)
                   }

       MAX-ACCESS  read-create
       STATUS      current
       DESCRIPTION
               "This object has the value nonVolatile(3) for those
               entries in the table which are valid and will not be
               deleted by the next restart of the managed system.
               Entries having the value volatile(2) are valid and
               exist, but have not been saved, so that will not exist
               after the next restart of the managed system.  Entries
               having the value other(1) are valid and exist but are
               not classified as to whether they will continue to
               exist after the next restart."

       DEFVAL  { volatile }
       ::= { ifRcvAddressEntry 3 }

Now we're on to the interface-related traps, which are basically the alarm bells of the whole MIB πŸ”” linkDown is the one that gets sent when the agent notices that an interface's ifOperStatus is about to drop to the down state from some other state. The trap carries ifIndex, ifAdminStatus, and ifOperStatus, and the description says that the notPresent state doesn't count here 🚨

   -- definition of interface-related traps.

   linkDown NOTIFICATION-TYPE
           OBJECTS { ifIndex, ifAdminStatus, ifOperStatus }
           STATUS  current
           DESCRIPTION
               "A linkDown trap signifies that the SNMPv2 entity,
               acting in an agent role, has detected that the
               ifOperStatus object for one of its communication links
               is about to enter the down state from some other state
               (but not from the notPresent state).  This other state
               is indicated by the included value of ifOperStatus."
       ::= { snmpTraps 3 }

linkUp is the glow-up version of that, the one for when an interface has left the down state and moved into some other state, again excluding notPresent ✨ It's got the same three objects. (Heads up, the original description here says "A linkDown trap signifies" even though it's the linkUp trap, so I've kept it exactly as written, no cap πŸ™ˆ)

   linkUp NOTIFICATION-TYPE
           OBJECTS { ifIndex, ifAdminStatus, ifOperStatus }
           STATUS  current
           DESCRIPTION
               "A linkDown trap signifies that the SNMPv2 entity,
               acting in an agent role, has detected that the
               ifOperStatus object for one of its communication links
               left the down state and transitioned into some other
               state (but not into the notPresent state).  This other
               state is indicated by the included value of
               ifOperStatus."
       ::= { snmpTraps 4 }

Okay, now the conformance section, which is where the whole "who has to implement what" energy lives 🧚 ifConformance sits under ifMIB, and it has two branches: ifGroups for the groups and ifCompliances for the compliance statements.

   -- conformance information

   ifConformance OBJECT IDENTIFIER ::= { ifMIB 2 }

   ifGroups      OBJECT IDENTIFIER ::= { ifConformance 1 }
   ifCompliances OBJECT IDENTIFIER ::= { ifConformance 2 }
   -- compliance statements

The big one is ifCompliance2, which is the compliance statement for SNMPv2 entities that have network interfaces 🌈 It lists three MANDATORY-GROUPS: ifGeneralInformationGroup, ifStackGroup2, and ifCounterDiscontinuityGroup. Then it goes through the conditional groups one by one, and this is where the vibes get very specific about speed and type πŸ“ The ifFixedLengthGroup is for character-oriented or fixed-length-transmission interfaces. The ifHCFixedLengthGroup is only for those same kinds of interfaces when ifSpeed is greater than 20,000,000 bits/second. The ifPacketGroup is for packet-oriented interfaces, and the ifHCPacketGroup is only for packet-oriented interfaces with ifSpeed greater than 650,000,000 bits/second. The ifRcvAddressGroup is the one where the media-specific MIBs get to decide everything, so they have to define the exact meaning, use, and semantics of those addresses 🫢

   ifCompliance2 MODULE-COMPLIANCE
       STATUS  current
       DESCRIPTION
               "The compliance statement for SNMPv2 entities which
               have network interfaces."

       MODULE  -- this module
           MANDATORY-GROUPS { ifGeneralInformationGroup, ifStackGroup2,
                              ifCounterDiscontinuityGroup }

           GROUP       ifFixedLengthGroup
           DESCRIPTION
               "This group is mandatory for all network interfaces
               which are character-oriented or transmit data in
               fixed-length transmission units."

           GROUP       ifHCFixedLengthGroup
           DESCRIPTION
               "This group is mandatory only for those network
               interfaces which are character-oriented or transmit
               data in fixed-length transmission units, and for which
               the value of the corresponding instance of ifSpeed is
               greater than 20,000,000 bits/second."

           GROUP       ifPacketGroup
           DESCRIPTION
               "This group is mandatory for all network interfaces
               which are packet-oriented."

           GROUP       ifHCPacketGroup
           DESCRIPTION
               "This group is mandatory only for those network
               interfaces which are packet-oriented and for which the
               value of the corresponding instance of ifSpeed is
               greater than 650,000,000 bits/second."

           GROUP       ifRcvAddressGroup
           DESCRIPTION
               "The applicability of this group MUST be defined by
               the media-specific MIBs.  Media-specific MIBs must
               define the exact meaning, use, and semantics of the
               addresses in this group."

           OBJECT      ifLinkUpDownTrapEnable
           MIN-ACCESS  read-only
           DESCRIPTION
               "Write access is not required."

           OBJECT      ifPromiscuousMode
           MIN-ACCESS  read-only
           DESCRIPTION
               "Write access is not required."

           OBJECT      ifStackStatus
           SYNTAX      INTEGER { active(1) } -- subset of RowStatus
           MIN-ACCESS  read-only
           DESCRIPTION
               "Write access is not required, and only one of the six
               enumerated values for the RowStatus textual convention
               need be supported, specifically: active(1)."

           OBJECT       ifAdminStatus
           SYNTAX       INTEGER { up(1), down(2) }
           MIN-ACCESS   read-only
           DESCRIPTION
               "Write access is not required, nor is support for the
               value testing(3)."

           OBJECT       ifAlias
           MIN-ACCESS   read-only
           DESCRIPTION
               "Write access is not required."

       ::= { ifCompliances 2 }

Next up are the units of conformance, which are the groups themselves πŸŽ€ Starting with ifGeneralInformationGroup, the "info for every interface" group, which holds ifIndex, ifDescr, ifType, ifSpeed, ifPhysAddress, ifAdminStatus, ifOperStatus, ifLastChange, ifLinkUpDownTrapEnable, ifConnectorPresent, ifHighSpeed, ifName, ifNumber, ifAlias, and ifTableLastChange. Basically the whole family photo πŸ“Έ

   -- units of conformance

   ifGeneralInformationGroup    OBJECT-GROUP
       OBJECTS { ifIndex, ifDescr, ifType, ifSpeed, ifPhysAddress,
                 ifAdminStatus, ifOperStatus, ifLastChange,
                 ifLinkUpDownTrapEnable, ifConnectorPresent,
                 ifHighSpeed, ifName, ifNumber, ifAlias,
                 ifTableLastChange }
       STATUS  current
       DESCRIPTION
               "A collection of objects providing information
               applicable to all network interfaces."
       ::= { ifGroups 10 }

Now here's a little group drama πŸ’… The next five groups (ifFixedLengthGroup, ifHCFixedLengthGroup, ifPacketGroup, ifHCPacketGroup, and ifVHCPacketGroup) are mutually exclusive, so at most one of them is implemented for any interface. Pick your lane, babe πŸ¦‹

   -- the following five groups are mutually exclusive; at most
   -- one of these groups is implemented for any interface
   ifFixedLengthGroup    OBJECT-GROUP
       OBJECTS { ifInOctets, ifOutOctets, ifInUnknownProtos,
                 ifInErrors, ifOutErrors }
       STATUS  current
       DESCRIPTION
               "A collection of objects providing information
               specific to non-high speed (non-high speed interfaces
               transmit and receive at speeds less than or equal to
               20,000,000 bits/second) character-oriented or fixed-
               length-transmission network interfaces."
       ::= { ifGroups 2 }

   ifHCFixedLengthGroup    OBJECT-GROUP
       OBJECTS { ifHCInOctets, ifHCOutOctets,
                 ifInOctets, ifOutOctets, ifInUnknownProtos,
                 ifInErrors, ifOutErrors }
       STATUS  current
       DESCRIPTION
               "A collection of objects providing information
               specific to high speed (greater than 20,000,000
               bits/second) character-oriented or fixed-length-
               transmission network interfaces."
       ::= { ifGroups 3 }

   ifPacketGroup    OBJECT-GROUP
       OBJECTS { ifInOctets, ifOutOctets, ifInUnknownProtos,
                 ifInErrors, ifOutErrors,
                 ifMtu, ifInUcastPkts, ifInMulticastPkts,
                 ifInBroadcastPkts, ifInDiscards,
                 ifOutUcastPkts, ifOutMulticastPkts,
                 ifOutBroadcastPkts, ifOutDiscards,
                 ifPromiscuousMode }
       STATUS  current
       DESCRIPTION
               "A collection of objects providing information
               specific to non-high speed (non-high speed interfaces
               transmit and receive at speeds less than or equal to
               20,000,000 bits/second) packet-oriented network
               interfaces."
       ::= { ifGroups 4 }

   ifHCPacketGroup    OBJECT-GROUP
       OBJECTS { ifHCInOctets, ifHCOutOctets,
                 ifInOctets, ifOutOctets, ifInUnknownProtos,
                 ifInErrors, ifOutErrors,
                 ifMtu, ifInUcastPkts, ifInMulticastPkts,
                 ifInBroadcastPkts, ifInDiscards,
                 ifOutUcastPkts, ifOutMulticastPkts,
                 ifOutBroadcastPkts, ifOutDiscards,
                 ifPromiscuousMode }
       STATUS  current
       DESCRIPTION
               "A collection of objects providing information
               specific to high speed (greater than 20,000,000
               bits/second but less than or equal to 650,000,000
               bits/second) packet-oriented network interfaces."
       ::= { ifGroups 5 }

   ifVHCPacketGroup    OBJECT-GROUP
       OBJECTS { ifHCInUcastPkts, ifHCInMulticastPkts,
                 ifHCInBroadcastPkts, ifHCOutUcastPkts,
                 ifHCOutMulticastPkts, ifHCOutBroadcastPkts,
                 ifHCInOctets, ifHCOutOctets,
                 ifInOctets, ifOutOctets, ifInUnknownProtos,
                 ifInErrors, ifOutErrors,
                 ifMtu, ifInUcastPkts, ifInMulticastPkts,
                 ifInBroadcastPkts, ifInDiscards,
                 ifOutUcastPkts, ifOutMulticastPkts,
                 ifOutBroadcastPkts, ifOutDiscards,
                 ifPromiscuousMode }
       STATUS  current
       DESCRIPTION
               "A collection of objects providing information
               specific to higher speed (greater than 650,000,000
               bits/second) packet-oriented network interfaces."
       ::= { ifGroups 6 }

The last few groups are the ones for addresses and stacking. ifRcvAddressGroup covers ifRcvAddressStatus and ifRcvAddressType, which is the "multiple addresses an interface receives" crew 🌸 ifStackGroup2 covers ifStackStatus and ifStackLastChange for the layering of MIB-II interfaces 🧚 And ifCounterDiscontinuityGroup holds ifCounterDiscontinuityTime, which tracks interface counter discontinuities ⭐

   ifRcvAddressGroup    OBJECT-GROUP
       OBJECTS { ifRcvAddressStatus, ifRcvAddressType }
       STATUS  current
       DESCRIPTION
               "A collection of objects providing information on the
               multiple addresses which an interface receives."
       ::= { ifGroups 7 }

   ifStackGroup2    OBJECT-GROUP
       OBJECTS { ifStackStatus, ifStackLastChange }
       STATUS  current
       DESCRIPTION
               "A collection of objects providing information on the
               layering of MIB-II interfaces."
       ::= { ifGroups 11 }

   ifCounterDiscontinuityGroup  OBJECT-GROUP
       OBJECTS { ifCounterDiscontinuityTime }
       STATUS  current
       DESCRIPTION
               "A collection of objects providing information
               specific to interface counter discontinuities."
       ::= { ifGroups 13 }

And we're at the deprecated stuff πŸ₯€ There's a comment block for the Interface Test Table, which is optional, though a media-specific MIB might make it mandatory. This table replaces the ifExtnsTestTable, so it's a glow-up with a fresh start πŸ’œ

   -- Deprecated Definitions - Objects


   --
   --    The Interface Test Table
   --
   -- This group of objects is optional.  However, a media-specific
   -- MIB may make implementation of this group mandatory.
   --
   -- This table replaces the ifExtnsTestTable
   --

okay so the ifTestTable is where the manager station gets to run diagnostics on an interface, and it's giving main character energy 🧚✨ This table has one entry per interface, and each entry holds the objects a network manager uses to tell an agent to test that interface for different faults πŸ” The tests themselves are defined in the media-specific MIB for each interface πŸ’…

   ifTestTable   OBJECT-TYPE
       SYNTAX      SEQUENCE OF IfTestEntry
       MAX-ACCESS  not-accessible
       STATUS      deprecated
       DESCRIPTION
               "This table contains one entry per interface.  It
               defines objects which allow a network manager to
               instruct an agent to test an interface for various
               faults.  Tests for an interface are defined in the
               media-specific MIB for that interface.  After invoking
               a test, the object ifTestResult can be read to
               determine the outcome.  If an agent can not perform
               the test, ifTestResult is set to so indicate.  The
               object ifTestCode can be used to provide further
               test-specific or interface-specific (or even
               enterprise-specific) information concerning the
               outcome of the test.  Only one test can be in progress
               on each interface at any one time.  If one test is in
               progress when another test is invoked, the second test
               is rejected.  Some agents may reject a test when a
               prior test is active on another interface.

               Before starting a test, a manager-station must first
               obtain 'ownership' of the entry in the ifTestTable for
               the interface to be tested.  This is accomplished with
               the ifTestId and ifTestStatus objects as follows:

            try_again:
                get (ifTestId, ifTestStatus)
                while (ifTestStatus != notInUse)
                    /*

                     * Loop while a test is running or some other
                     * manager is configuring a test.
                     */
                    short delay
                    get (ifTestId, ifTestStatus)
                }

                /*
                 * Is not being used right now -- let's compete
                 * to see who gets it.
                 */
                lock_value = ifTestId

                if ( set(ifTestId = lock_value, ifTestStatus = inUse,
                         ifTestOwner = 'my-IP-address') == FAILURE)
                    /*
                     * Another manager got the ifTestEntry -- go
                     * try again
                     */
                    goto try_again;

                /*
                 * I have the lock
                 */
                set up any test parameters.

                /*
                 * This starts the test
                 */
                set(ifTestType = test_to_run);

                wait for test completion by polling ifTestResult

                when test completes, agent sets ifTestResult
                     agent also sets ifTestStatus = 'notInUse'

                retrieve any additional test results, and ifTestId

                if (ifTestId == lock_value+1) results are valid

The way ownership works is a little dance πŸ’ƒ A manager first grabs the current ifTestId and ifTestStatus values and keeps re-checking them, periodically, until ifTestStatus says 'notInUse'. Then it tries to set that same ifTestId back to the value it just got, flip ifTestStatus to 'inUse', and put itself down as the ifTestOwner. If the set works, the manager owns the ifTestEntry, and the agent bumps ifTestId up (that's the TestAndIncr semantics doing its thing 😀). If the set fails, someone else snagged it first, so you just go back and try again 🫢

Once you've got ownership, you can set up whatever test parameters you need and then kick off the test by setting ifTestType. When the test finishes, the agent sets ifTestStatus back to 'notInUse', and only then can you read the results πŸ“Š Now, the (rare) case where two managers' tests overlap is a bit of a mess 😭 The first test's results could get overwritten by the second test's results before the first ones get read. You can catch this by reading ifTestId at the same time as the results and checking that the results match the request you actually made πŸ•΅οΈβ€β™€οΈ

   ifTestId         OBJECT-TYPE
       SYNTAX       TestAndIncr
       MAX-ACCESS   read-write
       STATUS       deprecated
       DESCRIPTION
               "This object identifies the current invocation of the
               interface's test."
       ::= { ifTestEntry 1 }

   ifTestStatus     OBJECT-TYPE
       SYNTAX       INTEGER { notInUse(1), inUse(2) }
       MAX-ACCESS   read-write
       STATUS       deprecated
       DESCRIPTION
               "This object indicates whether or not some manager
               currently has the necessary 'ownership' required to
               invoke a test on this interface.  A write to this
               object is only successful when it changes its value
               from 'notInUse(1)' to 'inUse(2)'.  After completion of
               a test, the agent resets the value back to
               'notInUse(1)'."
       ::= { ifTestEntry 2 }

   ifTestType       OBJECT-TYPE
       SYNTAX       AutonomousType
       MAX-ACCESS   read-write
       STATUS       deprecated
       DESCRIPTION
               "A control variable used to start and stop operator-
               initiated interface tests.  Most OBJECT IDENTIFIER
               values assigned to tests are defined elsewhere, in
               association with specific types of interface.
               However, this document assigns a value for a full-
               duplex loopback test, and defines the special meanings
               of the subject identifier:

                   noTest  OBJECT IDENTIFIER ::= { 0 0 }

               When the value noTest is written to this object, no
               action is taken unless a test is in progress, in which
               case the test is aborted.  Writing any other value to
               this object is only valid when no test is currently in
               progress, in which case the indicated test is
               initiated.

               When read, this object always returns the most recent
               value that ifTestType was set to.  If it has not been
               set since the last initialization of the network
               management subsystem on the agent, a value of noTest
               is returned."
       ::= { ifTestEntry 3 }

   ifTestResult  OBJECT-TYPE
       SYNTAX       INTEGER {
                        none(1),          -- no test yet requested
                        success(2),
                        inProgress(3),
                        notSupported(4),
                        unAbleToRun(5),   -- due to state of system
                        aborted(6),
                        failed(7)
                    }
       MAX-ACCESS   read-only
       STATUS       deprecated
       DESCRIPTION
               "This object contains the result of the most recently
               requested test, or the value none(1) if no tests have
               been requested since the last reset.  Note that this
               facility provides no provision for saving the results
               of one test when starting another, as could be
               required if used by multiple managers concurrently."

       ::= { ifTestEntry 4 }

   ifTestCode  OBJECT-TYPE
       SYNTAX       OBJECT IDENTIFIER
       MAX-ACCESS   read-only
       STATUS       deprecated
       DESCRIPTION
               "This object contains a code which contains more
               specific information on the test result, for example
               an error-code after a failed test.  Error codes and
               other values this object may take are specific to the
               type of interface and/or test.  The value may have the
               semantics of either the AutonomousType or
               InstancePointer textual conventions as defined in RFC
               1903.  The identifier:

                   testCodeUnknown  OBJECT IDENTIFIER ::= { 0 0 }

               is defined for use if no additional result code is
               available."
       ::= { ifTestEntry 5 }

   ifTestOwner      OBJECT-TYPE
       SYNTAX       OwnerString
       MAX-ACCESS   read-write
       STATUS       deprecated
       DESCRIPTION
               "The entity which currently has the 'ownership'
               required to invoke a test on this interface."
       ::= { ifTestEntry 6 }

Now the ifTestEntry itself, which is the row that the table is built from πŸ“‹ Here's the full structure, plus what each column is for πŸ‘‡

   ifTestEntry OBJECT-TYPE
       SYNTAX       IfTestEntry
       MAX-ACCESS   not-accessible
       STATUS       deprecated
       DESCRIPTION
               "An entry containing objects for invoking tests on an
               interface."
       AUGMENTS  { ifEntry }
       ::= { ifTestTable 1 }

   IfTestEntry ::=
       SEQUENCE {
           ifTestId           TestAndIncr,
           ifTestStatus       INTEGER,
           ifTestType         AutonomousType,
           ifTestResult       INTEGER,
           ifTestCode         OBJECT IDENTIFIER,
           ifTestOwner        OwnerString
       }

Okay, the rest of the story is about timing and what happens when things go sideways 😬 If ifTestType doesn't get set in a really long time after ownership was grabbed, the agent should time out the manager and set ifTestStatus back to 'notInUse'. The suggested timeout is 5 minutes ⏰

Also, a management station must not resend a request to start a test when it doesn't get a response back πŸ™…β€β™€οΈ Instead, it should look at the agent's MIB to figure out whether the invocation actually worked. The request only gets resent if the invocation didn't work.

Some tests might need the interface taken offline, or even a reboot once they're done πŸ”„ In those cases, the manager might lose contact with the agent until the test is over. An agent isn't required to support these tests. But if it does support them, it should really try its best to send a response to the request that started the test before it drops off 🫠 Once the agent is back to normal, the test results should show up in the right objects. This only works if the ifIndex value for an interface stays the same, even when the test causes a reboot πŸ”’ An agent must reject any test it can't handle, maybe because of resource limits, if it can't make at least the minimum amount of info available after the test finishes πŸ’€

Heads up bestie: a lot of these objects are deprecated, so the ifTestTable is kind of a legacy vibe now πŸ₯Ή

Last up is the group definition. This one's deprecated too, and it's been replaced by ifGeneralInformationGroup, so it's mostly here for old implementations πŸ“

   -- Deprecated Definitions - Groups


   ifGeneralGroup    OBJECT-GROUP
       OBJECTS { ifDescr, ifType, ifSpeed, ifPhysAddress,
                 ifAdminStatus, ifOperStatus, ifLastChange,
                 ifLinkUpDownTrapEnable, ifConnectorPresent,
                 ifHighSpeed, ifName }
       STATUS  deprecated
       DESCRIPTION
               "A collection of objects deprecated in favour of
               ifGeneralInformationGroup."
       ::= { ifGroups 1 }

that's the whole vibe for this part, periodt πŸ’–πŸŒˆ

   ifTestGroup    OBJECT-GROUP
       OBJECTS { ifTestId, ifTestStatus, ifTestType,

                 ifTestResult, ifTestCode, ifTestOwner }
       STATUS  deprecated
       DESCRIPTION
               "A collection of objects providing the ability to
               invoke tests on an interface."
       ::= { ifGroups 8 }


   ifStackGroup    OBJECT-GROUP
       OBJECTS { ifStackStatus }
       STATUS  deprecated
       DESCRIPTION
               "The previous collection of objects providing
               information on the layering of MIB-II interfaces."
       ::= { ifGroups 9 }


   ifOldObjectsGroup    OBJECT-GROUP
       OBJECTS { ifInNUcastPkts, ifOutNUcastPkts,
                 ifOutQLen, ifSpecific }
       STATUS  deprecated
       DESCRIPTION
               "The collection of objects deprecated from the
               original MIB-II interfaces group."
       ::= { ifGroups 12 }


   -- Deprecated Definitions - Compliance

   ifCompliance MODULE-COMPLIANCE
       STATUS  deprecated
       DESCRIPTION
               "The previous compliance statement for SNMPv2 entities
               which have network interfaces."

       MODULE  -- this module
           MANDATORY-GROUPS { ifGeneralGroup, ifStackGroup }

           GROUP       ifFixedLengthGroup
           DESCRIPTION
               "This group is mandatory for all network interfaces
               which are character-oriented or transmit data in
               fixed-length transmission units."

           GROUP       ifHCFixedLengthGroup
           DESCRIPTION
               "This group is mandatory only for those network
               interfaces which are character-oriented or transmit
               data in fixed-length transmission units, and for which
               the value of the corresponding instance of ifSpeed is
               greater than 20,000,000 bits/second."

           GROUP       ifPacketGroup
           DESCRIPTION
               "This group is mandatory for all network interfaces
               which are packet-oriented."

           GROUP       ifHCPacketGroup
           DESCRIPTION
               "This group is mandatory only for those network
               interfaces which are packet-oriented and for which the
               value of the corresponding instance of ifSpeed is
               greater than 650,000,000 bits/second."

           GROUP       ifTestGroup
           DESCRIPTION
               "This group is optional.  Media-specific MIBs which
               require interface tests are strongly encouraged to use
               this group for invoking tests and reporting results.
               A medium specific MIB which has mandatory tests may
               make implementation of this group mandatory."

           GROUP       ifRcvAddressGroup
           DESCRIPTION
               "The applicability of this group MUST be defined by
               the media-specific MIBs.  Media-specific MIBs must
               define the exact meaning, use, and semantics of the
               addresses in this group."

           OBJECT      ifLinkUpDownTrapEnable
           MIN-ACCESS  read-only
           DESCRIPTION
               "Write access is not required."

           OBJECT      ifPromiscuousMode
           MIN-ACCESS  read-only
           DESCRIPTION
               "Write access is not required."

           OBJECT      ifStackStatus
           SYNTAX      INTEGER { active(1) } -- subset of RowStatus
           MIN-ACCESS  read-only
           DESCRIPTION
               "Write access is not required, and only one of the six
               enumerated values for the RowStatus textual convention
               need be supported, specifically: active(1)."

           OBJECT       ifAdminStatus
           SYNTAX       INTEGER { up(1), down(2) }
           MIN-ACCESS   read-only
           DESCRIPTION
               "Write access is not required, nor is support for the
               value testing(3)."
       ::= { ifCompliances 1 }

   END

7. Acknowledgements 🫢

This memo was cooked up by the IETF's Interfaces MIB working group, and it's giving teamwork ✨

The original proposal evolved from conversations and discussions with many people, including at least the following: Fred Baker, Ted Brunner, Chuck Davin, Jeremy Greene, Marshall Rose, Kaj Tesink, and Dean Throop. πŸ’–


8. References πŸ“š

[1] Case, J., McCloghrie, K., Rose, M., and S. Waldbusser, "Structure of Management Information for version 2 of the Simple Network Management Protocol (SNMPv2)", RFC 1902, January 1996.

[2] Case, J., McCloghrie, K., Rose, M., and S. Waldbusser, "Textual Conventions for version 2 of the Simple Network Management Protocol (SNMPv2)", RFC 1903, January 1996.

[3] Case, J., McCloghrie, K., Rose, M., and S. Waldbusser, "Protocol Operations for version 2 of the Simple Network Management Protocol (SNMPv2)", RFC 1905, January 1996.

[4] McCloghrie, K., and M. Rose, "Management Information Base for Network Management of TCP/IP-based internets - MIB-II", STD 17, RFC 1213, March 1991.

[5] Case, J., Fedor, M., Schoffstall, M., and J. Davin, "Simple Network Management Protocol", STD 15, RFC 1157, May 1990.

[6] Postel, J., "Internet Protocol", STD 5, RFC 791, September 1981.

[7] McCloghrie, K., "Extensions to the Generic-Interface MIB", RFC 1229, May 1991.

[8] ATM Forum Technical Committee, "LAN Emulation Client Management: Version 1.0 Specification", af-lane-0044.000, ATM Forum, September 1995.

[9] Stewart, B., "Definitions of Managed Objects for Character Stream Devices using SMIv2", RFC 1658, July 1994.

[10] Bradner, S., "Key words for use in RFCs to Indicate Requirements Levels", RFC 2119, March 1997.


9. Security Considerations πŸ”’

Okay bestie, this part is SERIOUS 😭 This MIB has two kinds of objects. The readable ones tell you the number and status of a device's network interfaces, and the write-able ones let an admin control the interfaces and run tests on them. Unauthorized access to the readable objects is relatively innocuous. Unauthorized access to the write-able objects could cause a denial of service, or, combined with other (e.g., physical) security breaches, could cause unauthorized connectivity to a device. 🚨


10. Authors' Addresses πŸ’Œ

Keith McCloghrie Cisco Systems, Inc. 170 West Tasman Drive San Jose, CA 95134-1706

Phone: 408-526-5260 EMail: kzm@cisco.com

Frank Kastenholz FTP Software 2 High Street North Andover, Mass. USA 01845

Phone: 508-685-4000 EMail: kasten@ftp.com


The legal text below stays word for word, because you can't go changing copyright language πŸ™ˆ

Copyright (C) The Internet Society (1997). All Rights Reserved.

This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English.

The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns.

This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. πŸ¦‹

πŸ“¦ where this page comes from