RFC 3416
Version 2 of the Protocol Operations for the Simple Network Management Protocol (SNMP)
๐ Part 1 of 7 โ the title block, the boring-but-important legal bits, and the first big chunk of the spec. Part 2 is coming, bestie ๐ฆ
RFC 3416 ๐
- Number: RFC 3416, STD 62
- Title: Version 2 of the Protocol Operations for the Simple Network Management Protocol (SNMP)
- Editor of this version: R. Presuhn, BMC Software, Inc.
- Authors of the previous version: J. Case (SNMP Research, Inc.), K. McCloghrie (Cisco Systems, Inc.), M. Rose (Dover Beach Consulting, Inc.), S. Waldbusser (International Network Services)
- Category: Standards Track ๐ฅ
- Date: December 2002
- Obsoletes: RFC 1905 ๐
- Updates: nothing listed here ๐
Status of this Memo โจ
okay so this doc is a standards track protocol spec for the internet community, and it's basically asking everyone to talk about it and suggest improvements ๐ซถ if you want the official standardization state of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1), because that's the source of truth. distribution of this memo is unlimited, so share it with everyone ๐
Copyright Notice โจ
Copyright (C) The Internet Society (2002). All Rights Reserved. ๐ธ
Abstract ๐ฆ
this document defines version 2 of the protocol operations for the Simple Network Management Protocol (SNMP) ๐ง it covers the syntax and elements of procedure for sending, receiving, and processing SNMP PDUs. and yes, it obsoletes RFC 1905, so that one's officially retired ๐
Table of Contents ๐
1. Introduction ................................................ 3
2. Overview .................................................... 4
2.1. Management Information .................................... 4
2.2. Retransmission of Requests ................................ 4
2.3. Message Sizes ............................................. 4
2.4. Transport Mappings ........................................ 5
2.5. SMIv2 Data Type Mappings .................................. 6
3. Definitions ................................................. 6
4. Protocol Specification ...................................... 9
4.1. Common Constructs ......................................... 9
4.2. PDU Processing ............................................ 10
4.2.1. The GetRequest-PDU ...................................... 10
4.2.2. The GetNextRequest-PDU .................................. 11
4.2.2.1. Example of Table Traversal ............................ 12
4.2.3. The GetBulkRequest-PDU .................................. 14
4.2.3.1. Another Example of Table Traversal .................... 17
4.2.4. The Response-PDU ........................................ 18
4.2.5. The SetRequest-PDU ...................................... 19
4.2.6. The SNMPv2-Trap-PDU ..................................... 22
4.2.7. The InformRequest-PDU ................................... 23
5. Notice on Intellectual Property ............................. 24
6. Acknowledgments ............................................. 24
7. Security Considerations ..................................... 26
8. References .................................................. 26
8.1. Normative References ...................................... 26
8.2. Informative References .................................... 27
9. Changes from RFC 1905 ....................................... 28
10. Editor's Address ........................................... 30
11. Full Copyright Statement ................................... 31
1. Introduction โจ
okay so the SNMP Management Framework, as of when this was written, has five major pieces ๐
- the overall architecture, described in STD 62, RFC 3411 [RFC3411] ๐๏ธ
- the ways to describe and name objects and events for management. the first version of this Structure of Management Information (SMI) is called SMIv1 and it's in STD 16, RFC 1155 [RFC1155], STD 16, RFC 1212 [RFC1212] and RFC 1215 [RFC1215]. the second version, SMIv2, is in STD 58, RFC 2578 [RFC2578], STD 58, RFC 2579 [RFC2579] and STD 58, RFC 2580 [RFC2580] ๐ง
- the message protocols for moving management info around. the first version of the SNMP message protocol is SNMPv1, described in STD 15, RFC 1157 [RFC1157]. the second version, SNMPv2c, is not an Internet standards track protocol, and it's described in RFC 1901 [RFC1901] and STD 62, RFC 3417 [RFC3417]. the third version, SNMPv3, is described in STD 62, RFC 3417 [RFC3417], RFC 3412 [RFC3412] and RFC 3414 [RFC3414] ๐
- the protocol operations for accessing management information. the first set of operations and their PDU formats is in STD 15, RFC 1157 [RFC1157]. the second set is what this document is about ๐ฅ
- a set of fundamental applications in STD 62, RFC 3413 [RFC3413], plus the view-based access control mechanism in STD 62, RFC 3415 [RFC3415] ๐
if you want a deeper intro to the SNMP Management Framework as of when this was written, it's in RFC 3410 [RFC3410] ๐
managed objects are accessed through a virtual information store called the Management Information Base, or MIB ๐ฆ objects in the MIB are defined using the mechanisms the SMI lays out.
this document, Version 2 of the Protocol Operations for the Simple Network Management Protocol, defines how the protocol operates when it sends and receives PDUs that get carried by the message protocol. it's giving "the rules for the handshake" energy ๐ค
2. Overview ๐ธ
SNMP entities that support command generator or notification receiver applications (traditionally called "managers") talk to SNMP entities that support command responder or notification originator applications (traditionally called "agents") ๐ซถ the whole point of this protocol is moving management information and operations between them.
2.1. Management Information ๐
the term "variable" refers to an instance of a non-aggregate object type, defined using the conventions in the SMI [RFC2578] or the textual conventions based on the SMI [RFC2579] โจ a "variable binding" usually means the pairing of a variable's name with its value. BUT, if some exceptional conditions pop up while a retrieval request is being processed, a variable binding will pair a name with an indication of that exception instead ๐ญ
a variable-binding list is just a simple list of variable bindings ๐
the name of a variable is an OBJECT IDENTIFIER made by concatenating the OBJECT IDENTIFIER of the corresponding object-type with an OBJECT IDENTIFIER fragment that identifies the instance ๐ง the OBJECT IDENTIFIER of the corresponding object-type is called the OBJECT IDENTIFIER prefix of the variable.
2.2. Retransmission of Requests ๐
for every type of request in this protocol, the receiver is required, under normal circumstances, to generate and transmit a response to whoever originated the request ๐ whether a request should be retransmitted when no response shows up in a reasonable time is up to the application that originated it. this usually depends on how urgent the request is ๐จ but that application needs to act responsibly about how often and how long it retransmits ๐ซถ for the congestion control principles, see BCP 41 [RFC2914].
2.3. Message Sizes ๐
the maximum size of an SNMP message is limited to the minimum of:
(1) the maximum message size which the destination SNMP entity can accept; and,
(2) the maximum message size which the source SNMP entity can generate.
the first one may be known on a per-recipient basis. if that's not known, it's indicated by the transport domain used when sending the message ๐ the second one is set by implementation-specific local constraints ๐ ๏ธ
each transport mapping for SNMP indicates the minimum message size that an SNMP implementation MUST be able to produce or consume. implementations are encouraged to support larger values whenever they can ๐ but a conformant implementation MUST never generate messages larger than the receiving SNMP entity allows ๐ซ
one of the aims of the GetBulkRequest-PDU, specified in this protocol, is to cut down the number of protocol exchanges needed to grab a huge amount of management information ๐งบ so this PDU type lets an SNMP entity that supports command generator applications ask for the response to be as big as possible, given the message size constraints. those constraints include the limits on how big a message the SNMP entity supporting command responder applications can generate, and how big a message the command generator side can receive ๐ซ
BUT, big messages can be larger than the Path MTU of the network path they travel across. when that happens, the messages are subject to fragmentation. fragmentation is generally considered harmful [FRAG], because among other problems, it makes the transfer of messages less reliable ๐ so an SNMP entity that sends a GetBulkRequest-PDU MUST take care to set its parameters accordingly, to reduce the risk of fragmentation ๐ in particular, under conditions of network stress, only small values SHOULD be used for max-repetitions ๐
2.4. Transport Mappings ๐
it's really important to note that exchanging SNMP messages only needs an unreliable datagram service, with every message fully and independently contained in a single transport datagram ๐ specific transport mappings and encoding rules are specified elsewhere [RFC3417]. however, the preferred mapping is using the User Datagram Protocol [RFC768] ๐
2.5. SMIv2 Data Type Mappings
okay so the SMIv2 [RFC2578] defines 11 base types (INTEGER, OCTET STRING, OBJECT IDENTIFIER, Integer32, IpAddress, Counter32, Gauge32, Unsigned32, TimeTicks, Opaque, Counter64) plus the BITS construct ๐ฆ each base type gets mapped to a matching selection type in the SimpleSyntax and ApplicationSyntax choices of the ASN.1 SNMP protocol definition. โจ
ngl the detail here is very specific ๐ INTEGER and Integer32 both land on the integer-value selection type of SimpleSyntax. Gauge32 and Unsigned32 both land on the unsigned-integer-value selection type of ApplicationSyntax. iykyk ๐
The BITS construct maps to the string-value selection type of SimpleSyntax ๐ธ A BITS value gets encoded as an OCTET STRING, and this part is giving puzzle energy ๐งฉ All the named bits in the bitstring definition get packed in order, starting with the first bit and ending with the last. The first bit goes into bit 8 (the high order bit) of the first octet, and the packing runs down to bit 1 (the low order bit). After that comes bits 8 to 1 of each following octet, then as many bits as needed in the final octet, starting again at bit 8. Any leftover bits in that final octet are set to zero when generating and ignored when receiving. ๐
3. Definitions
okay this is the ASN.1 section, and it is the source of truth for the PDU shapes ๐ The PDU syntax is defined using ASN.1 notation [ASN1].
SNMPv2-PDU DEFINITIONS ::= BEGIN
ObjectName ::= OBJECT IDENTIFIER
ObjectSyntax ::= CHOICE {
simple SimpleSyntax,
application-wide ApplicationSyntax }
SimpleSyntax ::= CHOICE {
integer-value INTEGER (-2147483648..2147483647),
string-value OCTET STRING (SIZE (0..65535)),
objectID-value OBJECT IDENTIFIER }
ApplicationSyntax ::= CHOICE {
ipAddress-value IpAddress,
counter-value Counter32,
timeticks-value TimeTicks,
arbitrary-value Opaque,
big-counter-value Counter64,
unsigned-integer-value Unsigned32 }
IpAddress ::= [APPLICATION 0] IMPLICIT OCTET STRING (SIZE (4))
Counter32 ::= [APPLICATION 1] IMPLICIT INTEGER (0..4294967295)
Unsigned32 ::= [APPLICATION 2] IMPLICIT INTEGER (0..4294967295)
Gauge32 ::= Unsigned32
TimeTicks ::= [APPLICATION 3] IMPLICIT INTEGER (0..4294967295)
Opaque ::= [APPLICATION 4] IMPLICIT OCTET STRING
Counter64 ::= [APPLICATION 6]
IMPLICIT INTEGER (0..18446744073709551615)
-- protocol data units
PDUs ::= CHOICE {
get-request GetRequest-PDU,
get-next-request GetNextRequest-PDU,
get-bulk-request GetBulkRequest-PDU,
response Response-PDU,
set-request SetRequest-PDU,
inform-request InformRequest-PDU,
snmpV2-trap SNMPv2-Trap-PDU,
report Report-PDU }
-- PDUs
GetRequest-PDU ::= [0] IMPLICIT PDU
GetNextRequest-PDU ::= [1] IMPLICIT PDU
Response-PDU ::= [2] IMPLICIT PDU
SetRequest-PDU ::= [3] IMPLICIT PDU
-- [4] is obsolete
GetBulkRequest-PDU ::= [5] IMPLICIT BulkPDU
InformRequest-PDU ::= [6] IMPLICIT PDU
SNMPv2-Trap-PDU ::= [7] IMPLICIT PDU
-- Usage and precise semantics of Report-PDU are not defined
-- in this document. Any SNMP administrative framework making
-- use of this PDU must define its usage and semantics.
Report-PDU ::= [8] IMPLICIT PDU
max-bindings INTEGER ::= 2147483647
PDU ::= SEQUENCE {
request-id INTEGER (-214783648..214783647),
error-status -- sometimes ignored
INTEGER {
noError(0),
tooBig(1),
noSuchName(2), -- for proxy compatibility
badValue(3), -- for proxy compatibility
readOnly(4), -- for proxy compatibility
genErr(5),
noAccess(6),
wrongType(7),
wrongLength(8),
wrongEncoding(9),
wrongValue(10),
noCreation(11),
inconsistentValue(12),
resourceUnavailable(13),
commitFailed(14),
undoFailed(15),
authorizationError(16),
notWritable(17),
inconsistentName(18)
},
error-index -- sometimes ignored
INTEGER (0..max-bindings),
variable-bindings -- values are sometimes ignored
VarBindList
}
BulkPDU ::= -- must be identical in
SEQUENCE { -- structure to PDU
request-id INTEGER (-214783648..214783647),
non-repeaters INTEGER (0..max-bindings),
max-repetitions INTEGER (0..max-bindings),
variable-bindings -- values are ignored
VarBindList
}
-- variable binding
VarBind ::= SEQUENCE {
name ObjectName,
CHOICE {
value ObjectSyntax,
unSpecified NULL, -- in retrieval requests
-- exceptions in responses
noSuchObject [0] IMPLICIT NULL,
noSuchInstance [1] IMPLICIT NULL,
endOfMibView [2] IMPLICIT NULL
}
}
-- variable-binding list
VarBindList ::= SEQUENCE (SIZE (0..max-bindings)) OF VarBind
END
4. Protocol Specification
4.1. Common Constructs
okay the request-id field is literally the key to everything ๐ A Response-PDU takes the request-id value from the request PDU it's answering. That's how an app can tell apart its (possibly many) outstanding requests and match each incoming response to the right one. ๐
If you're using an unreliable datagram service, request-id also helps spot messages the network duplicated ๐ Reusing the same request-id on a retransmission lets the response to either the original or the retransmission satisfy the request. BUT if you want to calculate the round trip time for a request-response transaction, the application needs to use a different request-id value on each retransmitted request. The latter strategy is recommended for use in the majority of situations. ๐ฆ
A non-zero error-status in a Response-PDU means an error happened and stopped the request from being processed ๐ When that happens, a non-zero error-index tells you which variable binding caused it. Each variable binding is identified by its index: the first one in a variable-binding list is index one, the second is index two, and so on. ๐
SNMP limits OBJECT IDENTIFIER values to a maximum of 128 sub-identifiers, where each sub-identifier has a maximum value of 2**32-1. ๐ง
4.2. PDU Processing
okay so in the procedures below, any PDU field that the relevant procedure doesn't reference gets ignored by the receiving SNMP entity ๐ BUT every component of a PDU, including the ignored ones, still has to have valid ASN.1 syntax and encoding. Bestie, no skipping the paperwork ๐ For example, some PDUs (like the GetRequest-PDU) only care about a variable's name and not its value. So the value portion of that variable binding is ignored by the receiver, and unSpecified is the value meant for exactly that kind of binding. ๐
When generating a management communication, the message "wrapper" that encapsulates the PDU gets built according to the "Elements of Procedure" of the administrative framework in use. The definition of "max-bindings" puts an upper bound on how many variable bindings there can be. In practice, the message size is also capped by the maximum message size constraints ๐ธ A compliant implementation must support as many variable bindings in a PDU or BulkPDU as fit into the overall maximum message size limit of the SNMP engine, but no more than 2147483647 variable bindings. โจ
When receiving a management communication, you follow the "Elements of Procedure" of the administrative framework in use. If those procedures say the operation in the message should be performed locally, then those same procedures also say which MIB view is visible to that operation ๐
4.2.1. The GetRequest-PDU
a GetRequest-PDU gets generated and transmitted whenever an application asks for it ๐ซถ
When a GetRequest-PDU comes in, the receiving SNMP entity processes each variable binding in the variable-binding list to produce a Response-PDU. All the fields of that Response-PDU have the same values as the matching fields of the received request, except for the ones noted below. Each variable binding is handled like this:
- If the variable binding's name exactly matches the name of a variable accessible by this request, the variable binding's value field gets set to the value of that named variable. ๐
- Otherwise, if the variable binding's name does not have an OBJECT IDENTIFIER prefix that exactly matches the OBJECT IDENTIFIER prefix of any (potential) variable accessible by this request, its value field gets set to
"noSuchObject". ๐ - Otherwise, the variable binding's value field gets set to
"noSuchInstance". ๐
If processing any variable binding fails for a reason that isn't listed above, the Response-PDU gets re-formatted. It keeps the same request-id and variable-bindings values as the received GetRequest-PDU, its error-status is set to "genErr", and its error-index is set to the index of the failed variable binding. ๐ญ
Otherwise, the Response-PDU's error-status is set to "noError" and its error-index is zero. ๐
The generated Response-PDU then gets encapsulated into a message. If that message's size is less than or equal to both a local constraint and the maximum message size of the originator, it gets sent back to the originator of the GetRequest-PDU. ๐ฆ
Otherwise, an alternate Response-PDU is generated. This one has the same request-id value as the received GetRequest-PDU, its error-status is set to "tooBig", its error-index is set to zero, and its variable-bindings field is empty. Then it gets encapsulated into a message. If that message's size is less than or equal to both a local constraint and the maximum message size of the originator, it gets sent to the originator of the GetRequest-PDU. Otherwise, the snmpSilentDrops [RFC3418] counter gets incremented and the resultant message is discarded. ๐
4.2.2. The GetNextRequest-PDU โจ
Okay so a GetNextRequest-PDU gets generated and sent whenever an application asks for one ๐ It's basically the "what comes next?" request, and it's giving main character energy.
Upon receipt of a GetNextRequest-PDU, the receiving SNMP entity processes each variable binding in the variable-binding list to produce a Response-PDU. All fields of the Response-PDU have the same values as the corresponding fields of the received request, except as indicated below. Each variable binding gets processed like this:
(1) The variable is located which is in the lexicographically ordered list of the names of all variables which are accessible by this request and whose name is the first lexicographic successor of the variable binding's name in the incoming GetNextRequest-PDU. The corresponding variable binding's name and value fields in the Response-PDU are set to the name and value of the located variable. ๐
(2) If the requested variable binding's name does not lexicographically precede the name of any variable accessible by this request, i.e., there is no lexicographic successor, then the corresponding variable binding produced in the Response-PDU has its value field set to endOfMibView, and its name field set to the variable binding's name in the request. ๐ That's the "end of the line" signal, bestie.
If the processing of any variable binding fails for a reason other than the ones listed above, then the Response-PDU is re-formatted with the same values in its request-id and variable-bindings fields as the received GetNextRequest-PDU, with the value of its error-status field set to genErr, and the value of its error-index field set to the index of the failed variable binding. ๐ Rough, but at least it tells you exactly which one broke.
Otherwise, the value of the Response-PDU's error-status field is set to noError, and the value of its error-index field is zero. Clean! ๐ซถ
The generated Response-PDU is then encapsulated into a message. If the size of the resultant message is less than or equal to both a local constraint and the maximum message size of the originator, it is transmitted to the originator of the GetNextRequest-PDU. ๐ฆ
Otherwise, an alternate Response-PDU is generated. This alternate Response-PDU is formatted with the same values in its request-id field as the received GetNextRequest-PDU, with the value of its error-status field set to tooBig, the value of its error-index field set to zero, and an empty variable-bindings field. This alternate Response-PDU is then encapsulated into a message. If the size of the resultant message is less than or equal to both a local constraint and the maximum message size of the originator, it is transmitted to the originator of the GetNextRequest-PDU. Otherwise, the snmpSilentDrops [RFC3418] counter is incremented and the resultant message is discarded. ๐ญ Oof, the message just gets ghosted.
4.2.2.1. Example of Table Traversal ๐ง
Okay this part is my favourite, no cap. The GetNextRequest-PDU is how you walk through conceptual tables of information inside a MIB. The semantics of this type of request, together with the way individual instances of objects get identified in the MIB, gives you access to related objects as if they were laid out in a table. It's so iconic ๐ญ
In the protocol exchange sketched below, an application retrieves the media-dependent physical address and the address-mapping type for each entry in the IP net-to-media Address Translation Table [RFC1213] of a particular network element. It also retrieves the value of sysUpTime [RFC3418], at which the mappings existed. Suppose that the command responder's IP net-to-media table has three entries:
Interface-Number Network-Address Physical-Address Type
1 10.0.0.51 00:00:10:01:23:45 static
1 9.2.3.4 00:00:10:54:32:10 dynamic
2 10.0.0.15 00:00:10:98:76:54 dynamic
The SNMP entity supporting a command generator application begins by sending a GetNextRequest-PDU containing the indicated OBJECT IDENTIFIER values as the requested variable names:
GetNextRequest ( sysUpTime,
ipNetToMediaPhysAddress,
ipNetToMediaType )
The SNMP entity supporting a command responder application responds with a Response-PDU:
Response (( sysUpTime.0 = "123456" ),
( ipNetToMediaPhysAddress.1.9.2.3.4 = "000010543210" ),
( ipNetToMediaType.1.9.2.3.4 = "dynamic" ))
The SNMP entity supporting the command generator application continues with:
GetNextRequest ( sysUpTime,
ipNetToMediaPhysAddress.1.9.2.3.4,
ipNetToMediaType.1.9.2.3.4 )
The SNMP entity supporting the command responder application responds with:
Response (( sysUpTime.0 = "123461" ),
( ipNetToMediaPhysAddress.1.10.0.0.51 = "000010012345" ),
( ipNetToMediaType.1.10.0.0.51 = "static" ))
The SNMP entity supporting the command generator application continues with:
GetNextRequest ( sysUpTime,
ipNetToMediaPhysAddress.1.10.0.0.51,
ipNetToMediaType.1.10.0.0.51 )
The SNMP entity supporting the command responder application responds with:
Response (( sysUpTime.0 = "123466" ),
( ipNetToMediaPhysAddress.2.10.0.0.15 = "000010987654" ),
( ipNetToMediaType.2.10.0.0.15 = "dynamic" ))
The SNMP entity supporting the command generator application continues with:
GetNextRequest ( sysUpTime,
ipNetToMediaPhysAddress.2.10.0.0.15,
ipNetToMediaType.2.10.0.0.15 )
As there are no further entries in the table, the SNMP entity supporting the command responder application responds with the variables that are next in the lexicographical ordering of the accessible object names, for example:
Response (( sysUpTime.0 = "123471" ),
( ipNetToMediaNetAddress.1.9.2.3.4 = "9.2.3.4" ),
( ipRoutingDiscards.0 = "2" ))
Note how, having reached the end of the column for ipNetToMediaPhysAddress, the second variable binding from the command responder application has now "wrapped" to the first row in the next column. Furthermore, note how, having reached the end of the ipNetToMediaTable for the third variable binding, the command responder application has responded with the next available object, which is outside that table. ๐ This response signals the end of the table to the command generator application, and that's the tea. ๐
4.2.3. The GetBulkRequest-PDU โจ
okay bestie, the GetBulkRequest-PDU is the one that's built for big data pulls ๐ An application generates it and sends it off to ask for a potentially huge amount of data. The whole point is to grab lots of stuff fast, especially when you need a big table, and that's literally the main character move here ๐ฆ
When a receiving SNMP entity gets a GetBulkRequest-PDU, it goes through every variable binding in the variable-binding list and builds a Response-PDU. The request-id in that response is the same value as the one in the request, so everything lines up ๐
Here's the tea ๐ซ For GetBulkRequest-PDUs, one successful variable binding in the request can produce zero or more variable bindings in the Response-PDU. So the one-to-one mapping you get with GetRequest-PDUs, GetNextRequest-PDUs, and SetRequest-PDUs just doesn't apply here. It's a totally different vibe ๐
The non-repeaters and max-repetitions fields in the request tell the responder how to process things. The first N variable bindings get one response variable binding each, and then each of the R remaining variable bindings gets M response variable bindings. So the total number of requested variable bindings is N + (M * R), where:
Nis the smaller of: a) the value of thenon-repeatersfield in the request, and b) the number of variable bindings in the request.Mis the value of themax-repetitionsfield in the request.Ris the larger of: a) the number of variable bindings in the request minusN, and b) zero.
The receiving SNMP entity makes a Response-PDU with up to that total number of requested variable bindings. The request-id has to be the same as the one in the received GetBulkRequest-PDU ๐ซถ
If N is greater than zero, the first through the N-th variable bindings in the Response-PDU each get made like this:
- Find the variable that's first in the lexicographically ordered list of the names of all variables accessible by this request, and whose name is the first lexicographic successor of the variable binding's name in the incoming GetBulkRequest-PDU. Then set the name and value fields of the corresponding variable binding in the Response-PDU to the name and value of that variable. ๐
- If the requested variable binding's name doesn't lexicographically precede any accessible variable's name (aka there's no lexicographic successor), then the variable binding in the Response-PDU gets its value field set to
"endOfMibView", and its name field set to the variable binding's name in the request. That's how it says "we're at the end, bestie" ๐
If M and R are non-zero, the (N + 1)-th and later variable bindings in the Response-PDU are made in a similar way. For each iteration i where i is greater than zero and less than or equal to M, and for each repeated variable r where r is greater than zero and less than or equal to R, the (N + ((i-1) * R) + r)-th variable binding in the Response-PDU gets made like this:
- The variable in the lexicographically ordered list of the names of all accessible variables, whose name is the
i-th lexicographic successor of the (N+r)-th variable binding's name in the incoming GetBulkRequest-PDU, is located. Its name and value fields get set to the variable's name and value. ๐ง - If there's no
i-th lexicographic successor, the variable binding in the Response-PDU gets its value field set to"endOfMibView". Its name field gets set to either the last lexicographic successor, or, if there are no lexicographic successors, to the (N+r)-th variable binding's name in the request. ๐
The max number of variable bindings in the Response-PDU is N + (M * R), but the response can come back with fewer (even zero!) for three reasons. Iykyk ๐
- If the message containing the Response-PDU with the requested number of variable bindings would be bigger than either a local constraint or the originator's maximum message size, the response gets generated with fewer variable bindings. The set gets trimmed from the end, so the message is roughly equal to, but not bigger than, the local constraint or the originator's max message size. Also, the number of variable bindings removed has no relationship to the values of
N,M, orR. Not my fault, the math is just like that ๐คทโโ๏ธ - The response can also have fewer variable bindings if, for some iteration
iwhereiis greater than zero and less than or equal toM, all of the generated variable bindings have their value field set to"endOfMibView". In that case, the variable bindings may be cut off after the (N+ (i*R))-th variable binding. - If processing a request with lots of repetitions takes way more time than a normal request, a command responder application may end the request early with fewer than the full number of repetitions. It has to finish at least one repetition though, so it doesn't just give up on everything ๐ฅบ
If processing any variable binding fails for a reason that isn't listed above, the Response-PDU gets re-formatted. It keeps the same request-id and variable-bindings fields as the received GetBulkRequest-PDU. Its error-status field gets set to "genErr", and its error-index field gets set to the index of the variable binding in the original request that matches the failed variable binding. Oof ๐ญ
Otherwise, the Response-PDU's error-status field is set to "noError", and its error-index field is set to zero. Clean ๐ซง
The generated Response-PDU (it might have an empty variable-bindings field, that's allowed) then gets wrapped up in a message. If that message is less than or equal to both a local constraint and the originator's maximum message size, it gets sent back to the originator of the GetBulkRequest-PDU. If not, the snmpSilentDrops [RFC3418] counter goes up by one, and the message is thrown away. Bye bye ๐
4.2.3.1. Another Example of Table Traversal
this example shows how the GetBulkRequest-PDU can be used as an alternative to the GetNextRequest-PDU. You get the same traversal of the IP net-to-media table as in Section 4.2.2.1, but with way fewer exchanges. Efficiency is so hot right now ๐ฅ
The SNMP entity running the command generator application starts off by sending a GetBulkRequest-PDU with a modest max-repetitions value of 2, and the OBJECT IDENTIFIER values it wants as requested variable names:
GetBulkRequest [ non-repeaters = 1, max-repetitions = 2 ]
( sysUpTime,
ipNetToMediaPhysAddress,
ipNetToMediaType )
The SNMP entity running the command responder application answers with a Response-PDU:
Response (( sysUpTime.0 = "123456" ),
( ipNetToMediaPhysAddress.1.9.2.3.4 = "000010543210" ),
( ipNetToMediaType.1.9.2.3.4 = "dynamic" ),
( ipNetToMediaPhysAddress.1.10.0.0.51 = "000010012345" ),
( ipNetToMediaType.1.10.0.0.51 = "static" ))
Then the SNMP entity running the command generator application keeps going with:
GetBulkRequest [ non-repeaters = 1, max-repetitions = 2 ]
( sysUpTime,
ipNetToMediaPhysAddress.1.10.0.0.51,
ipNetToMediaType.1.10.0.0.51 )
The SNMP entity running the command responder application responds with:
Response (( sysUpTime.0 = "123466" ),
( ipNetToMediaPhysAddress.2.10.0.0.15 = "000010987654" ),
( ipNetToMediaType.2.10.0.0.15 = "dynamic" ),
( ipNetToMediaNetAddress.1.9.2.3.4 = "9.2.3.4" ),
( ipRoutingDiscards.0 = "2" ))
Notice how, like in the first example, the variable bindings in the response show the table has ended. The fourth variable binding does it by returning info from the next available column. The fifth variable binding does it by returning info from the first available object lexicographically after the table. That response tells the command generator application it's reached the end of the table, and that's the end of the story ๐
4.2.4. The Response-PDU ๐
the Response-PDU only gets generated by an SNMP entity when it receives a GetRequest-PDU, GetNextRequest-PDU, GetBulkRequest-PDU, SetRequest-PDU, or InformRequest-PDU, like we talked about elsewhere in this document ๐ง
If the error-status field of the Response-PDU isn't zero, the value fields of the variable bindings in the variable binding list get ignored. Just skip them, bestie ๐ โโ๏ธ
If both the error-status field and the error-index field of the Response-PDU are non-zero, then the error-index value is the index of the variable binding (in the variable-binding list of the matching request) that caused the request to fail. The first variable binding in a request's variable-binding list is index one, the second is index two, and so on ๐ข
A compliant SNMP entity running a command generator application must be able to properly receive and handle a Response-PDU with an error-status field equal to "noSuchName", "badValue", or "readOnly". (See sections 1.3 and 4.3 of [RFC2576].) When a Response-PDU comes in, the receiving SNMP entity hands its contents to the application that made the request with the same request-id value. For more details, check [RFC3412] ๐
4.2.5. The SetRequest-PDU ๐
okay so a SetRequest-PDU gets generated and transmitted whenever an application asks for it ๐
When a SetRequest-PDU shows up, the receiving SNMP entity works out two things. First, how big a message would be if it wrapped up a Response-PDU with the same request-id and variable-bindings as the incoming request. Second, the biggest possible sizes for the error-status and error-index fields. If that message would be bigger than either a local constraint or the originator's maximum message size, the entity makes an alternate Response-PDU and sends it back to the originator. Then processing of the SetRequest-PDU stops right there ๐
That alternate Response-PDU has the same request-id as the request, error-status set to "tooBig", error-index set to zero, and an empty variable-bindings field. It gets wrapped in a message. If that message fits under both the local constraint and the originator's maximum message size, it goes back to the originator. If not, the snmpSilentDrops [RFC3418] counter goes up and the message gets discarded. Either way, processing of the SetRequest-PDU ends ๐
If the request passed that check, the entity handles each variable binding in the list to build a Response-PDU. Every field of the Response-PDU matches the matching field of the request, except for the changes spelled out below โจ
The variable bindings get processed in two conceptual phases. Phase one checks each binding. If every check passes, phase two actually changes each variable. Implementors are totally free to split up either phase, or both, into several implementation phases. Honestly, sometimes they have to, just to keep things consistent ๐งฉ
In phase one, the checks run on each variable binding until they all pass or one of them fails:
- If the binding's name points to a variable, existing or not, that this request is or would be denied access to because it is or would not be in the right MIB view, then the
Response-PDU'serror-statusis set to"noAccess"and itserror-indexis set to the index of the failed binding. ๐ - Otherwise, if no variables share the same OBJECT IDENTIFIER prefix as the binding's name and can be created or modified no matter what new value is given, then
error-statusis set to"notWritable"anderror-indexis set to the index of the failed binding. - Otherwise, if the binding's value field has, per ASN.1, a type that doesn't match what every variable sharing the same OBJECT IDENTIFIER prefix requires, then
error-statusis set to"wrongType"anderror-indexis set to the index of the failed binding. - Otherwise, if the binding's value field has, per ASN.1, a length that doesn't match what every variable sharing the same OBJECT IDENTIFIER prefix requires, then
error-statusis set to"wrongLength"anderror-indexis set to the index of the failed binding. - Otherwise, if the binding's value field has an ASN.1 encoding that doesn't match its ASN.1 tag, then
error-statusis set to"wrongEncoding"anderror-indexis set to the index of the failed binding. (Note that not all implementation strategies will generate this error.) - Otherwise, if the binding's value field specifies a value that could never be assigned to the variable under any circumstances, then
error-statusis set to"wrongValue"anderror-indexis set to the index of the failed binding. - Otherwise, if the binding's name points to a variable that doesn't exist and could never be created (even though other variables sharing the same OBJECT IDENTIFIER prefix might be creatable in some situations), then
error-statusis set to"noCreation"anderror-indexis set to the index of the failed binding. - Otherwise, if the binding's name points to a variable that doesn't exist and can't be created right now (even though it could be created in other circumstances), then
error-statusis set to"inconsistentName"anderror-indexis set to the index of the failed binding. - Otherwise, if the binding's name points to a variable that exists but can't be modified no matter what new value is given, then
error-statusis set to"notWritable"anderror-indexis set to the index of the failed binding. - Otherwise, if the binding's value field specifies a value that could be held by the variable under other circumstances, but is inconsistent right now or otherwise can't be assigned, then
error-statusis set to"inconsistentValue"anderror-indexis set to the index of the failed binding. - If, during the steps above, assigning the value to the variable needs a resource that isn't available right now, then
error-statusis set to"resourceUnavailable"anderror-indexis set to the index of the failed binding. - If processing the binding fails for any reason not listed above, then
error-statusis set to"genErr"anderror-indexis set to the index of the failed binding. - Otherwise, the validation of the binding succeeds.
Once phase one ends, if every binding passed, then error-status is set to "noError", error-index is set to zero, and processing moves on to phase two ๐
For phase two, each binding in the request gets its named variable created if needed, and the specified value is assigned to it. All of these assignments act as if they happen at the same time with respect to each other. But if the same variable is named more than once in one request with different values, which value actually gets assigned is implementation-specific ๐คทโโ๏ธ
If any assignment fails, even after all the earlier checks, then every other assignment gets undone. The Response-PDU is changed so error-status is "commitFailed" and error-index is the index of the failed binding ๐ฌ
If and only if it is not possible to undo all the assignments, the Response-PDU is changed so error-status is "undoFailed" and error-index is zero. Implementations are strongly encouraged to do everything they can to avoid "commitFailed" or "undoFailed". These two error codes are NOT a free pass to take the easy way out in an implementation ๐ซ
Finally, the generated Response-PDU gets wrapped into a message and sent to the originator of the SetRequest-PDU ๐ฆ
4.2.6. The SNMPv2-Trap-PDU ๐
An SNMPv2-Trap-PDU gets generated and transmitted by an SNMP entity on behalf of a notification originator application. It's super common for this one to notify a notification receiver application at a logically remote SNMP entity that something happened or that a condition is present. And there's no confirmation that the notification was delivered, so it's kind of a "send it and hope" situation ๐ธ
Where an SNMPv2-Trap-PDU goes is decided by the SNMP entity, in an implementation-dependent way. The first two variable bindings in an SNMPv2-Trap-PDU's variable binding list are sysUpTime.0 [RFC3418] and snmpTrapOID.0 [RFC3418], in that order. If the OBJECTS clause is present in the invocation of the corresponding NOTIFICATION-TYPE macro, then each corresponding variable, as instantiated by this notification, gets copied in order into the variable-bindings field. And if the generating SNMP entity wants to include any extra variables, each one gets copied into the variable-bindings field too ๐ง
4.2.7. The InformRequest-PDU โจ
Okay so, bestie, an InformRequest-PDU is generated and sent by an SNMP entity on behalf of a notification originator application ๐ฎ. It's usually how you tell a notification receiver application that something happened or that some condition is currently true ๐. It's a confirmed notification delivery mechanism, which is giving reliability vibes, although there is, of course, no guarantee of delivery ๐ฅบ.
The notification originator application decides where the InformRequest-PDU goes ๐บ๏ธ. The first two variable bindings in the variable binding list are sysUpTime.0 [RFC3418] and snmpTrapOID.0 [RFC3418], in that order ๐. If the OBJECTS clause is present in the invocation of the corresponding NOTIFICATION-TYPE macro, then each corresponding variable, as instantiated by this notification, gets copied in order into the variable-bindings field ๐ . And if the generating SNMP entity wants to include any extra variables, it can, and each one gets copied into the variable-bindings field too ๐.
Now the receiving side, which is so important ๐ญ. When an InformRequest-PDU comes in, the receiving SNMP entity figures out how big a message would be if it encapsulated a Response-PDU with the same values in its request-id, error-status, error-index and variable-bindings fields as the received InformRequest-PDU ๐. If that determined message size is greater than either a local constraint or the maximum message size of the originator, then an alternate Response-PDU gets generated and sent back to the originator, and processing of the InformRequest-PDU stops right there ๐. This alternate Response-PDU has the same request-id field as the received InformRequest-PDU, its error-status field is set to "tooBig", its error-index field is set to zero, and its variable-bindings field is empty ๐. That alternate Response-PDU then gets encapsulated into a message. If the size of that resultant message is less than or equal to both a local constraint and the maximum message size of the originator, it's sent to the originator of the InformRequest-PDU. Otherwise, the snmpSilentDrops [RFC3418] counter is incremented and the resultant message is discarded ๐. Either way, processing of the InformRequest-PDU terminates โจ.
Otherwise, the receiving SNMP entity does the following, in order ๐ฆ:
- presents its contents to the appropriate application ๐ฒ;
- generates a Response-PDU with the same values in its request-id and variable-bindings fields as the received InformRequest-PDU, with the error-status field set to
"noError"and the error-index field set to zero; and - transmits the generated Response-PDU to the originator of the InformRequest-PDU ๐.
5. Notice on Intellectual Property ๐
Okay, so the IETF doesn't take a position on whether any intellectual property or other rights that might be claimed to apply to the technology in this document are valid or in scope, and it doesn't say whether any license under those rights might or might not be available either ๐คทโโ๏ธ. It also doesn't claim it has tried to find any such rights ๐. Info about the IETF's procedures for rights in standards-track and standards-related documentation is in BCP-11 ๐. Copies of claims of rights that were made available for publication, plus any assurances of licenses that will be made available, or the result of an attempt to get a general license or permission for implementors or users of this spec to use proprietary rights, can be obtained from the IETF Secretariat ๐ฌ.
The IETF invites anyone interested to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that might cover technology required to practice this standard ๐ง. Please send that info to the IETF Executive Director ๐.
6. Acknowledgments ๐ซถ
This document is the product of the SNMPv3 Working Group ๐. Some special thanks go to these Working Group members, who are literally the reason this exists ๐:
- Randy Bush
- Jeffrey D. Case
- Mike Daniele
- Rob Frye
- Lauren Heintz
- Keith McCloghrie
- Russ Mundy
- David T. Perkins
- Randy Presuhn
- Aleksey Romanov
- Juergen Schoenwaelder
- Bert Wijnen
This version of the document, edited by Randy Presuhn, was initially based on the work of a design team whose members were ๐:
- Jeffrey D. Case
- Keith McCloghrie
- David T. Perkins
- Randy Presuhn
- Juergen Schoenwaelder
The previous versions of this document, edited by Keith McCloghrie, were the result of significant work by four major contributors ๐:
- Jeffrey D. Case
- Keith McCloghrie
- Marshall T. Rose
- Steven Waldbusser
The contributions of the SNMPv2 Working Group to the previous versions are also acknowledged ๐ธ. A special thanks goes to these contributors ๐ :
- Alexander I. Alten
- Dave Arneson
- Uri Blumenthal
- Doug Book
- Kim Curran
- Jim Galvin
- Maria Greene
- Iain Hanson
- Dave Harrington
- Nguyen Hien
- Jeff Johnson
- Michael Kornegay
- Deirdre Kostick
- David Levi
- Daniel Mahoney
- Bob Natale
- Brian O'Keefe
- Andrew Pearson
- Dave Perkins
- Randy Presuhn
- Aleksey Romanov
- Shawn Routhier
- Jon Saperia
- Juergen Schoenwaelder
- Bob Stewart
- Kaj Tesink
- Glenn Waters
- Bert Wijnen
7. Security Considerations ๐
โ ๏ธ The protocol defined in this document by itself does NOT provide a secure environment. Even if the network itself is secure (for example by using IPSec), there is NO control as to who on the secure network is allowed access to management information. Be warned, bestie ๐ญ.
It is recommended that implementors consider the security features provided by the SNMPv3 framework ๐. Specifically, the use of the User-based Security Model STD 62, RFC 3414 [RFC3414] and the View-based Access Control Model STD 62, RFC 3415 [RFC3415] is recommended ๐ก๏ธ.
It is then a customer/user responsibility to make sure the SNMP entity is properly configured so that:
- only those principals (users) having legitimate rights can access or modify the values of any MIB objects supported by that entity ๐ซ;
- the occurrence of particular events on the entity will be communicated appropriately ๐ฃ;
- the entity responds appropriately and with due credence to events and information that have been communicated to it ๐ง.
8. References ๐
8.1. Normative References
[RFC768] Postel, J., "User Datagram Protocol", STD 6, RFC 768,
August 1980.
[RFC2578] McCloghrie, K., Perkins, D., Schoenwaelder, J., Case, J.,
Rose, M. and S. Waldbusser, "Structure of Management
Information Version 2 (SMIv2)", STD 58, RFC 2578, April
1999.
[RFC2579] McCloghrie, K., Perkins, D., Schoenwaelder, J., Case, J.,
Rose, M. and S. Waldbusser, "Textual Conventions for
SMIv2", STD 58, RFC 2579, April 1999.
[RFC2580] McCloghrie, K., Perkins, D., Schoenwaelder, J., Case, J.,
Rose, M. and S. Waldbusser, "Conformance Statements for
SMIv2", STD 58, RFC 2580, April 1999.
[RFC3411] Harrington, D., Presuhn, R. and B. Wijnen, "An
Architecture for Describing Simple Network Management
Protocol (SNMP) Management Frameworks", STD 62, RFC 3411,
December 2002.
[RFC3412] Case, J., Harrington, D., Presuhn, R. and B. Wijnen,
"Message Processing and Dispatching for the Simple
Network Management Protocol (SNMP)", STD 62, RFC 3412,
December 2002.
[RFC3413] Levi, D., Meyer, P. and B. Stewart, "Simple Network
Management Protocol (SNMP) Applications", STD 62, RFC
3413, December 2002.
[RFC3414] Blumenthal, U. and B. Wijnen, "The User-Based Security
Model (USM) for Version 3 of the Simple Network
Management Protocol (SNMPv3)", STD 62, RFC 3414, December
2002.
[RFC3415] Wijnen, B., Presuhn, R. and K. McCloghrie, "View-based
Access Control Model (VACM) for the Simple Network
Management Protocol (SNMP)", STD 62, RFC 3415, December
2002.
[RFC3417] Presuhn, R., Case, J., McCloghrie, K., Rose, M. and S.
Waldbusser, "Transport Mappings for the Simple Network
Management Protocol", STD 62, RFC 3417, December 2002.
[RFC3418] Presuhn, R., Case, J., McCloghrie, K., Rose, M. and S.
Waldbusser, "Management Information Base (MIB) for the
Simple Network Management Protocol (SNMP)", STD 62, RFC
3418, December 2002.
[ASN1] Information processing systems - Open Systems
Interconnection - Specification of Abstract Syntax
Notation One (ASN.1), International Organization for
Standardization. International Standard 8824, December
1987.
8.2. Informative References
[FRAG] Kent, C. and J. Mogul, "Fragmentation Considered
Harmful," Proceedings, ACM SIGCOMM '87, Stowe, VT, August
1987.
[RFC1155] Rose, M. and K. McCloghrie, "Structure and Identification
of Management Information for TCP/IP-based Internets",
STD 16, RFC 1155, May 1990.
[RFC1157] Case, J., Fedor, M., Schoffstall, M. and J. Davin,
"Simple Network Management Protocol", STD 15, RFC 1157,
May 1990.
[RFC1212] Rose, M. and K. McCloghrie, "Concise MIB Definitions",
STD 16, RFC 1212, March 1991.
[RFC1213] McCloghrie, K. and M. Rose, Editors, "Management
Information Base for Network Management of TCP/IP-based
internets: MIB-II", STD 17, RFC 1213, March 1991.
[RFC1215] Rose, M., "A Convention for Defining Traps for use with
the SNMP", RFC 1215, March 1991.
[RFC1901] Case, J., McCloghrie, K., Rose, M. and S. Waldbusser,
"Introduction to Community-based SNMPv2", RFC 1901,
January 1996.
[RFC2576] Frye, R., Levi, D., Routhier, S. and B. Wijnen,
"Coexistence between Version 1, Version 2, and Version 3
of the Internet-Standard Network Management Framework",
RFC 2576, March 2000.
[RFC2863] McCloghrie, K. and F. Kastenholz, "The Interfaces Group
MIB", RFC 2863, June 2000.
[RFC2914] Floyd, S., "Congestion Control Principles", BCP 41, RFC
2914, September 2000.
[RFC3410] Case, J., Mundy, R., Partain, D. and B. Stewart,
"Introduction and Applicability Statements for Internet-
Standard Management Framework", RFC 3410, December 2002.
9. Changes from RFC 1905 โจ
okay bestie, this is the changelog for how RFC 1905 got its glow-up ๐ Some of these tweaks are cosmetic, some are real, and a few are just clarifications. The notes say which is which. Here's the full list:
- Corrected spelling error in copyright statement;
- Updated copyright date;
- Updated with new editor's name and contact information;
- Added notice on intellectual property;
- Cosmetic fixes to layout and typography;
- Added table of contents;
- Title changed;
- Updated document headers and footers;
- Deleted the old clause 2.3, entitled "Access to Management Information";
- Changed the way in which request-id was defined, though with the same ultimate syntax and semantics, to avoid coupling with SMI. This does not affect the protocol in any way;
- Replaced the word "exception" with the word "error" in the old clause 4.1. This does not affect the protocol in any way;
- Deleted the first two paragraphs of the old clause 4.2;
- Clarified the maximum number of variable bindings that an implementation must support in a PDU. This does not affect the protocol in any way;
- Replaced occurrences of "SNMPv2 application" with "application";
- Deleted three sentences in old clause 4.2.3 describing the handling of an impossible situation. This does not affect the protocol in any way;
- Clarified the use of the SNMPv2-Trap-Pdu in the old clause 4.2.6. This does not affect the protocol in any way;
- Aligned description of the use of the InformRequest-Pdu in old clause 4.2.7 with the architecture. This does not affect the protocol in any way;
- Updated references;
- Re-wrote introduction clause;
- Replaced manager/agent/SNMPv2 entity terminology with terminology from RFC 2571. This does not affect the protocol in any way;
- Eliminated IMPORTS from the SMI, replaced with equivalent in-line ASN.1. This does not affect the protocol in any way;
- Added notes calling attention to two different manifestations of reaching the end of a table in the table walk examples;
- Added content to security considerations clause;
- Updated ASN.1 comment on use of Report-PDU. This does not affect the protocol in any way;
- Updated acknowledgments section;
- Included information on handling of BITS;
- Deleted spurious comma in ASN.1 definition of PDUs;
- Added abstract;
- Made handling of additional variable bindings in informs consistent with that for traps. This was a correction of an editorial oversight, and reflects implementation practice;
- Added reference to RFC 2914.
10. Editor's Address ๐ฆ
this is where you find the editor, Randy Presuhn, at BMC Software, Inc. ๐ฌ
Randy Presuhn
BMC Software, Inc.
2141 North First Street
San Jose, CA 95131
USA
Phone: +1 408 546 1006
EMail: randy_presuhn@bmc.com
11. Full Copyright Statement ๐
Copyright (C) The Internet Society (2002). 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.
Acknowledgement ๐ซถ
Funding for the RFC Editor function is currently provided by the Internet Society.
๐ฆ where this page comes from
- ietf: rfc3416 2002-12
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms