跳到主要内容

4. 协议规范

网络管理协议是一种应用协议,通过它可以查看或修改代理 MIB 的变量。

协议实体之间的通信通过消息交换来完成,每条消息都使用 ASN.1 的基本编码规则(如第 3.2.2 节所讨论的)完整且独立地表示在单个 UDP 数据报中。一条消息由版本标识符、SNMP 团体名和协议数据单元(PDU)组成。对于除报告 trap 的消息之外的所有消息(即,除包含 Trap-PDU 的消息之外的所有消息),协议实体在其所关联主机的 UDP 端口 161 上接收。报告 trap 的消息应当在 UDP 端口 162 上接收以进一步处理。本协议的实现不必接受长度超过 484 个八位位组的消息。但是,建议实现在可行时支持更大的数据报。

SNMP 的所有实现都必须支持五种 PDU:GetRequest-PDU、GetNextRequest-PDU、GetResponse-PDU、SetRequest-PDU 和 Trap-PDU。

 RFC1157-SNMP DEFINITIONS ::= BEGIN

IMPORTS
ObjectName, ObjectSyntax, NetworkAddress, IpAddress, TimeTicks
FROM RFC1155-SMI;

-- top-level message

Message ::=
SEQUENCE {
version -- version-1 for this RFC
INTEGER {
version-1(0)
},

community -- community name
OCTET STRING,

data -- e.g., PDUs if trivial
ANY -- authentication is being used
}
-- protocol data units

PDUs ::=
CHOICE {
get-request
GetRequest-PDU,

get-next-request
GetNextRequest-PDU,

get-response
GetResponse-PDU,

set-request
SetRequest-PDU,

trap
Trap-PDU
}

-- the individual PDUs and commonly used
-- data types will be defined later

END

4.1. 过程要素​

本节描述实现 SNMP 的协议实体的动作。但请注意,它无意约束任何一致性实现的内部体系结构。

在下文中会使用传输地址这一术语。就 UDP 而言,一个传输地址由一个 IP 地址和一个 UDP 端口组成。也可以使用其他传输服务来支持 SNMP。在这些情况下,应当相应地给出传输地址的定义。

生成消息的协议实体的顶层动作如下:

  1. 它首先构造适当的 PDU(例如 GetRequest-PDU)作为一个 ASN.1 对象。

  2. 然后,它把这个 ASN.1 对象连同团体名、其源传输地址和目的传输地址一起,传递给实现所需鉴别方案的服务。该鉴别服务返回另一个 ASN.1 对象。

  3. 接着,协议实体使用该团体名和所得的 ASN.1 对象构造一个 ASN.1 Message 对象。

  4. 然后使用 ASN.1 的基本编码规则将这个新的 ASN.1 对象序列化,再使用传输服务发送给对等协议实体。

类似地,接收消息的协议实体的顶层动作如下:

  1. 它对传入的数据报执行初步解析,以构建一个对应于 ASN.1 Message 对象的 ASN.1 对象。如果解析失败,它丢弃该数据报,不再执行进一步的动作。

  2. 然后它校验该 SNMP 消息的版本号。如果不匹配,它丢弃该数据报,不再执行进一步的动作。

  3. 接着,协议实体把在 ASN.1 Message 对象中找到的团体名和用户数据,连同该数据报的源传输地址和目的传输地址,传递给实现所需鉴别方案的服务。该实体返回另一个 ASN.1 对象,或发出鉴别失败信号。在后一种情况下,协议实体记录这一失败,(可能)生成一个 trap,并丢弃该数据报,不再执行进一步的动作。

  4. 然后,协议实体对鉴别服务返回的 ASN.1 对象执行初步解析,以构建一个对应于 ASN.1 PDUs 对象的 ASN.1 对象。如果解析失败,它丢弃该数据报,不再执行进一步的动作。否则,使用所命名的 SNMP 团体选择适当的配置文件,并相应地处理该 PDU。如果这一处理的结果是返回一条消息,那么发送该响应消息所用的源传输地址,应当与原始请求消息所发送到的目的传输地址相同。

4.1.1. 公共构造​

在介绍该协议的六种 PDU 类型之前,先来考虑一些经常使用的 ASN.1 构造是合适的:

               -- request/response information

RequestID ::=
INTEGER

ErrorStatus ::=
INTEGER {
noError(0),
tooBig(1),
noSuchName(2),
badValue(3),
readOnly(4)
genErr(5)
}

ErrorIndex ::=
INTEGER

-- variable bindings

VarBind ::=
SEQUENCE {
name
ObjectName,

value
ObjectSyntax
}

VarBindList ::=
SEQUENCE OF
VarBind

RequestID 用于区分尚未完成的请求。通过使用 RequestID,SNMP 应用实体可以把传入的响应与尚未完成的请求关联起来。在使用不可靠数据报服务的情况下,RequestID 还提供了一种识别被网络复制的消息的简单手段。

ErrorStatus 的非零实例用于指示处理请求时发生了异常。在这些情况下,ErrorIndex 可以通过指出列表中的哪个变量导致了该异常来提供附加信息。

术语"变量"指的是被管对象的一个实例。变量绑定(或称 VarBind)指的是变量名称与该变量值的配对。VarBindList 是变量名称及对应值的简单列表。有些 PDU 只关心变量的名称而不关心它的值(例如 GetRequest-PDU)。在这种情况下,协议实体忽略绑定中的值部分。但是,值部分仍然必须具有有效的 ASN.1 语法和编码。建议对此类绑定的值部分使用 ASN.1 值 NULL。

4.1.2. GetRequest-PDU​

GetRequest-PDU 的形式为:

          The form of the GetRequest-PDU is:
GetRequest-PDU ::=
[0]
IMPLICIT SEQUENCE {
request-id
RequestID,

error-status -- always 0
ErrorStatus,

error-index -- always 0
ErrorIndex,

variable-bindings
VarBindList
}

GetRequest-PDU 仅在其 SNMP 应用实体的请求下才由协议实体生成。

收到 GetRequest-PDU 后,接收协议实体根据下列列表中任何适用的规则进行响应:

  1. 如果在 variable-bindings 字段中命名的任何对象,其名称与相关 MIB 视图中可用于 get 操作的某个对象的名称不完全匹配,那么接收实体向所收到消息的发起方发送形式相同的 GetResponse-PDU,只是 error-status 字段的值为 noSuchName,error-index 字段的值为所收到消息中该对象名称分量的索引。

  2. 如果在 variable-bindings 字段中命名的任何对象属于聚合类型(如 SMI 中所定义),那么接收实体向所收到消息的发起方发送形式相同的 GetResponse-PDU,只是 error-status 字段的值为 noSuchName,error-index 字段的值为所收到消息中该对象名称分量的索引。

  3. 如果按下文所述生成的 GetResponse-PDU 的大小会超出本地限制,那么接收实体向所收到消息的发起方发送形式相同的 GetResponse-PDU,只是 error-status 字段的值为 tooBig,error-index 字段的值为零。

  4. 如果在 variable-bindings 字段中命名的任何对象,其值因上述任何规则均未涵盖的原因而无法检索,那么接收实体向所收到消息的发起方发送形式相同的 GetResponse-PDU,只是 error-status 字段的值为 genErr,error-index 字段的值为所收到消息中该对象名称分量的索引。

如果上述规则均不适用,那么接收协议实体向所收到消息的发起方发送这样的 GetResponse-PDU:对于所收到消息的 variable-bindings 字段中命名的每个对象,GetResponse-PDU 的对应分量表示该变量的名称和值。该 GetResponse-PDU 的 error-status 字段的值为 noError,error-index 字段的值为零。该 GetResponse-PDU 的 request-id 字段的值为所收到消息的值。

4.1.3. GetNextRequest-PDU​

GetNextRequest-PDU 的形式与 GetRequest-PDU 的相同,只是 PDU 类型的指示不同。用 ASN.1 语言表示:

               GetNextRequest-PDU ::=
[1]
IMPLICIT SEQUENCE {
request-id
RequestID,
error-status -- always 0
ErrorStatus,

error-index -- always 0
ErrorIndex,

variable-bindings
VarBindList
}

GetNextRequest-PDU 仅在其 SNMP 应用实体的请求下才由协议实体生成。

收到 GetNextRequest-PDU 后,接收协议实体根据下列列表中任何适用的规则进行响应:

  1. 如果在 variable-bindings 字段中的任何对象名,在字典序上不先于相关 MIB 视图中可用于 get 操作的某个对象的名称,那么接收实体向所收到消息的发起方发送形式相同的 GetResponse-PDU,只是 error-status 字段的值为 noSuchName,error-index 字段的值为所收到消息中该对象名称分量的索引。

  2. 如果按下文所述生成的 GetResponse-PDU 的大小会超出本地限制,那么接收实体向所收到消息的发起方发送形式相同的 GetResponse-PDU,只是 error-status 字段的值为 tooBig,error-index 字段的值为零。

  3. 如果在 variable-bindings 字段中命名的任何对象,其字典序后继者的值因上述任何规则均未涵盖的原因而无法检索,那么接收实体向所收到消息的发起方发送形式相同的 GetResponse-PDU,只是 error-status 字段的值为 genErr,error-index 字段的值为所收到消息中该对象名称分量的索引。

如果上述规则均不适用,那么接收协议实体向所收到消息的发起方发送这样的 GetResponse-PDU:对于所收到消息的 variable-bindings 字段中的每个名称,GetResponse-PDU 的对应分量表示这样一个对象的名称和值——在相关 MIB 视图中可用于 get 操作的所有对象名称的字典序中,该对象的名称紧接在给定分量的名称字段的值之后。该 GetResponse-PDU 的 error-status 字段的值为 noError,errorindex 字段的值为零。该 GetResponse-PDU 的 request-id 字段的值为所收到消息的值。

4.1.3.1. 表遍历示例​

GetNextRequest-PDU 的一个重要用途是遍历 MIB 内的概念信息表。这类 SNMP 消息的语义,连同用于标识 MIB 中对象类型各个实例的协议特定机制,使得可以访问 MIB 中的相关对象,就好像它们具有表格化的组织一样。

通过下面概述的 SNMP 交换,SNMP 应用实体可以提取某个特定网络元素路由表中每个条目的目的地址和下一跳网关。假设该路由表有三个条目:

      Destination                     NextHop         Metric

10.0.0.99 89.1.1.42 5
9.1.2.3 99.0.0.3 3
10.0.0.51 89.1.1.42 5

管理站向 SNMP 代理发送一个 GetNextRequest-PDU,其中包含作为所请求变量名的指定 OBJECT IDENTIFIER 值:

GetNextRequest ( ipRouteDest, ipRouteNextHop, ipRouteMetric1 )

SNMP 代理以一个 GetResponse-PDU 作为响应:

              GetResponse (( ipRouteDest.9.1.2.3 =  "9.1.2.3" ),
( ipRouteNextHop.9.1.2.3 = "99.0.0.3" ),
( ipRouteMetric1.9.1.2.3 = 3 ))

管理站继续:

              GetNextRequest ( ipRouteDest.9.1.2.3,
ipRouteNextHop.9.1.2.3,
ipRouteMetric1.9.1.2.3 )

SNMP 代理响应:

              GetResponse (( ipRouteDest.10.0.0.51 = "10.0.0.51" ),
( ipRouteNextHop.10.0.0.51 = "89.1.1.42" ),
( ipRouteMetric1.10.0.0.51 = 5 ))

管理站继续:

              GetNextRequest ( ipRouteDest.10.0.0.51,
ipRouteNextHop.10.0.0.51,
ipRouteMetric1.10.0.0.51 )

SNMP 代理响应:

              GetResponse (( ipRouteDest.10.0.0.99 = "10.0.0.99" ),
( ipRouteNextHop.10.0.0.99 = "89.1.1.42" ),
( ipRouteMetric1.10.0.0.99 = 5 ))

管理站继续:

              GetNextRequest ( ipRouteDest.10.0.0.99,
ipRouteNextHop.10.0.0.99,
ipRouteMetric1.10.0.0.99 )

由于表中已没有更多条目,SNMP 代理返回已知对象名字典序中的下一些对象。这一响应向管理站表明路由表已结束。

4.1.4. GetResponse-PDU​

GetResponse-PDU 的形式与 GetRequest-PDU 的相同,只是 PDU 类型的指示不同。用 ASN.1 语言表示:

               GetResponse-PDU ::=
[2]
IMPLICIT SEQUENCE {
request-id
RequestID,
error-status
ErrorStatus,

error-index
ErrorIndex,

variable-bindings
VarBindList
}

GetResponse-PDU 仅在收到 GetRequest-PDU、GetNextRequest-PDU 或 SetRequest-PDU 时由协议实体生成,如本文档其他地方所述。

收到 GetResponse-PDU 后,接收协议实体将其内容呈现给其 SNMP 应用实体。

4.1.5. SetRequest-PDU​

SetRequest-PDU 的形式与 GetRequest-PDU 的相同,只是 PDU 类型的指示不同。用 ASN.1 语言表示:

               SetRequest-PDU ::=
[3]
IMPLICIT SEQUENCE {
request-id
RequestID,

error-status -- always 0
ErrorStatus,

error-index -- always 0
ErrorIndex,

variable-bindings
VarBindList
}

SetRequest-PDU 仅在其 SNMP 应用实体的请求下才由协议实体生成。

收到 SetRequest-PDU 后,接收实体根据下列列表中任何适用的规则进行响应:

  1. 如果在 variable-bindings 字段中命名的任何对象,在相关 MIB 视图中不可用于 set 操作,那么接收实体向所收到消息的发起方发送形式相同的 GetResponse-PDU,只是 error-status 字段的值为 noSuchName,error-index 字段的值为所收到消息中该对象名称分量的索引。

  2. 如果在 variable-bindings 字段中命名的任何对象,其 value 字段的内容按照 ASN.1 语言并未体现出与该变量所要求一致的类型、长度和值,那么接收实体向所收到消息的发起方发送形式相同的 GetResponse-PDU,只是 error-status 字段的值为 badValue,error-index 字段的值为所收到消息中该对象名称的索引。

  3. 如果按下文所述生成的 Get Response 类型消息的大小会超出本地限制,那么接收实体向所收到消息的发起方发送形式相同的 GetResponse-PDU,只是 error-status 字段的值为 tooBig,error-index 字段的值为零。

  4. 如果在 variable-bindings 字段中命名的任何对象,其值因上述任何规则均未涵盖的原因而无法修改,那么接收实体向所收到消息的发起方发送形式相同的 GetResponse-PDU,只是 error-status 字段的值为 genErr,error-index 字段的值为所收到消息中该对象名称分量的索引。

如果上述规则均不适用,那么对于所收到消息的 variable-bindings 字段中命名的每个对象,将对应的值赋给该变量。SetRequest-PDU 所指定的每个变量赋值,应当如同与同一消息中指定的所有其他赋值同时设置那样生效。

然后,接收实体向所收到消息的发起方发送形式相同的 GetResponse-PDU,只是所生成消息的 error-status 字段的值为 noError,error-index 字段的值为零。

4.1.6. Trap-PDU​

Trap-PDU 的形式为:

  Trap-PDU ::=
[4]

IMPLICIT SEQUENCE {
enterprise -- type of object generating
-- trap, see sysObjectID in [5]
OBJECT IDENTIFIER,

agent-addr -- address of object generating
NetworkAddress, -- trap

generic-trap -- generic trap type
INTEGER {
coldStart(0),
warmStart(1),
linkDown(2),
linkUp(3),
authenticationFailure(4),
egpNeighborLoss(5),
enterpriseSpecific(6)
},

specific-trap -- specific code, present even
INTEGER, -- if generic-trap is not
-- enterpriseSpecific

time-stamp -- time elapsed between the last
TimeTicks, -- (re)initialization of the network
-- entity and the generation of the
trap

variable-bindings -- "interesting" information
VarBindList
}

Trap-PDU 仅在 SNMP 应用实体的请求下才由协议实体生成。SNMP 应用实体选择 SNMP 应用实体目的地址的方式是特定于实现的。

收到 Trap-PDU 后,接收协议实体将其内容呈现给其 SNMP 应用实体。

Trap-PDU 的 variable-bindings 分量的意义是特定于实现的。

对 generic-trap 字段值的解释如下:

4.1.6.1. coldStart Trap​

coldStart(0) trap 表示发送协议实体正在重新初始化自身,以致代理的配置或协议实体实现可能被改变。

4.1.6.2. warmStart Trap​

warmStart(1) trap 表示发送协议实体正在重新初始化自身,且代理配置和协议实体实现都不会被改变。

4.1.6.3. linkDown Trap​

linkDown(2) trap 表示发送协议实体察觉到代理配置中所表示的某条通信链路出现故障。

linkDown 类型的 Trap-PDU 在其 variable-bindings 的第一个元素中包含受影响接口的 ifIndex 实例的名称和值。

4.1.6.4. linkUp Trap​

linkUp(3) trap 表示发送协议实体察觉到代理配置中所表示的某条通信链路已经恢复运行。

linkUp 类型的 Trap-PDU 在其 variable-bindings 的第一个元素中包含受影响接口的 ifIndex 实例的名称和值。

4.1.6.5. authenticationFailure Trap​

authenticationFailure(4) trap 表示发送协议实体是一条未经正确鉴别的协议消息的收件方。虽然 SNMP 的实现必须能够生成这一 trap,但它们也必须能够通过特定于实现的机制抑制此类 trap 的发出。

4.1.6.6. egpNeighborLoss Trap​

egpNeighborLoss(5) trap 表示发送协议实体曾作为其 EGP 对等方的一个 EGP 邻居已被标记为不可用,且对等关系不再存在。

egpNeighborLoss 类型的 Trap-PDU 在其 variable-bindings 的第一个元素中包含受影响邻居的 egpNeighAddr 实例的名称和值。

4.1.6.7. enterpriseSpecific Trap​

enterpriseSpecific(6) trap 表示发送协议实体察觉到发生了某个企业特定事件。specific-trap 字段标识所发生的那个特定 trap。