《精通SNMP》——2.7 宏定义

    xiaoxiao2023-06-14  170

    本节书摘来自异步社区《精通SNMP》一书中的第2章,第2.7节,作者: 武孟军 更多章节内容可以访问云栖社区“异步社区”公众号查看。

    2.7 宏定义

    前面已经提到,ASN.1提供了一些简单类型和结构类型。使用这些内置类型,用户可定义新的简单类型和结构类型。用户定义的结构类型无论多复杂,最终的基础类型必然可以归结到ASN.1的简单类型上。另外,用户定义的类型,实质上是为原有类型定义的一个“别名”,并没有真正的新类型产生,虽然新类型的Tag可以和原有类型的不同。

    ASN.1为用户提供了一种直接扩展BNF语法的手段,也就是定义真正意义上的新ASN.1数据类型,即定义ASN.1宏(macro)。

    在2.3节中介绍简单类型的BNF语法,我们可以知道每种类型有类型符号和值符号两类BNF产生式。只要这两类BNF产生式确定了,类型也就确定了。宏定义,实际上是使用一个固定的格式,用户可以在这个格式中填写类型符号和值符号的产生式,创造新的类型。

    需要注意的是,大部分宏定义确定的类型,取值一般是已有的ASN.1类型值。因此,这样的宏定义,实质上是为已有的类型定义出一种复杂的类型符号,借助类型符号的多变来包含更多的语义。而值符号和值传输编码,仍使用原有的类型值符号和编码。

    宏定义虽然功能强大而且灵活,但也给ASN.1的编译带来了不少麻烦,因此新版本的ASN.1已经不再允许使用宏。宏被认为是ASN.1的一处“败笔”,很多ASN.1书籍中已不再介绍宏的概念,但对于SNMP来说,宏仍然被广泛使用,因此本节专门对宏进行详细介绍。

    2.7.1 宏定义定义宏有两部分内容,类型的语法符号书写规则和该类型的值符号规则,即类型和值的符号如何书写。

    宏定义语法格式如下:

    < 宏名字 > MACRO ::= BEGIN TYPE NOTATION ::=     -- 类型语法规则; VALUE NOTATION ::=    -- 值语法规则; -- 定义类型和值语法所需要的语法产生式; END

    因此,完整的宏定义必须包括类型符号语法定义、属于该类型的值的符号语法定义以及所需要的语法产生式,其中MACRO、BEGIN、END、TYPE NOTATION 、VALUE NOTATION 是定义宏的关键字。

    宏定义的重点是类型语法规则和值语法规则定义部分,它限定了新类型(值)的符号形式。通俗地讲,就是新类型(值)“看上去是什么样子”。

    使用宏定义的类型,必须以宏名字作为前导,即将“宏名字+类型符号”作为完整的类型符号使用。下面是一个简单的宏定义例子。

    ERROR MACRO ::=    BEGIN     TYPE NOTATION ::= Parameter         VALUE NOTATION::= value (VALUE CHOICE                     {                     localValue  INTEGER,                     globalValue OBJECT IDENTIFIER                     })     Parameter ::= '' PARAMETER'' NamedType | empty     NamedType ::= identifier type | type    END

    宏名字为ERROR,类型符号由TYPE NOTATION、Parameter和NamedType产生式限定。可以这样理解:新类型符号被定义为Parameter,Parameter可以为空,也可以是符号“PARAMETER”+空格+ NamedType,而NamedType可以是ASN.1类型符号或是类型标识符。因此,下面的符号可作为宏定义的新类型形式:

    ERROR           PARAMETER QueueName           --- QueueName为别处定义的类型标识符; 值符号由产生式中定义的CHOICE类型确定,既可以是整数值,也可以是类型标识符。下面是使用新类型的例子: E ::= ERROR    PARAMETER  QueueName     --类型E被定义为新类型 badQueueName E ::= 0        --属于新类型的一个值,值名为badQueueName; 注意:

    严格地说,宏名字不是新类型的类型符号的一部分。但由于新类型不是ASN.1的内置类型,因此,为了能够确定新类型由哪个宏产生,在模块中使用新类型时,必须将宏名字作为新类型符号的前缀。2.7.2 宏的产生式上小节简单介绍了宏的定义和使用方法,本小节介绍宏的产生式。在学习SNMP的过程中,会遇到许许多多宏定义,不了解宏的产生式是很难理解它们的。

    为定义宏,ASN .1新增加了如下关键字和基本单词。这些符号,有的不常见,有的根据名字就可以猜测出其含意,这里不再对它们一一进行详细讲解,以后用到时再具体解释。

    新增加的基本单词如下:

    macroreference  "number" productionreference  "empty" localtypereference MACRO localvaluereference TYPE  "|" NOTATION >  VALUE astring  value  "string"  type  "identifier"

    注意:

    基本单词中有一些带有双引号,双引号是基本单词的组成部分,注意它们和产生式中终结符的区别。下面是具体的巴柯斯范式,为方便解释,每条产生式前面增加了一个标识序号。

    (1) MacroDefinition ::=macroreference MACRO "::=" MacroSubstance (2) MacroSubstance ::=BEGIN MacroBody END | macroreference | Externalmacroreference (3) MacroBody ::= TypeProduction          ValueProduction         SupportingProductions (4) TypeProduction ::= TYPE NOTATION "::=" MacroAlternativeList (5) ValueProduction ::=VALUE NOTATION "::=" MacroAlternativeList (6) SupportingProductions ::= ProductionList | empty (7) ProductionList ::= Production | ProductionList Production (8) Production ::=productionreference "::=" MacroAlternativeList (9) Externalmacroreference ::=modulereference . macroreference (10) MacroAlternativeList ::=MacroAlternative | MacroAlternativeList “|” MacroAlternative (11) MacroAlternative ::= SymbolList  (12) SymbolList ::= SymbolElement | SymbolList SymbolElement (13) SymbolElement ::= SymbolDefn | EmbeddedDefinitions (14) SymbolDefn ::= astring |        productionreference |        "string" |        "identifier" |        "number" |        "empty" |        type |        type(localtypereference) |        value(MacroType) |        value(localvaluereference MacroType) |        value(VALUE MacroType) (15) MacroType ::= localtypereference | Type (16) EmbeddedDefinitions ::= <EmbeddedDefinitionList> (17) EmbeddedDefinitionList ::=EmbeddedDefinition | EmbeddedDefinitionList EmbeddedDefinition (18) EmbeddedDefinition ::=LocalTypeassignment | LocalValueassignment (19) LocalTypeassignment ::=Localtypereference "::=" MacroType (20) LocalValueassignment ::=localvaluereference MacroType "::=" MacroValue (21) MacroValue ::= Value | localvaluereference

    产生式(1)和(2)定义了宏格式。即宏名字“macroreference”+关键字“MACRO”+被定义为符号“::=”+关键字“BEGIN”+宏块+关键字“END”(参见2.7.1小节的内容)。另外,BEGIN+宏块+END部分还可以被一个已定义的宏名字代替。如果引用宏在本模块中定义,直接使用宏名字,否则,遵循产生式(9)的规则,用模块名+符号“.”+宏名字格式。注意,产生式(9)中的符号“.”不是终结符,而是ASN .1中定义的基本符号(参见2.2.4小节)。

    产生式(3)定义了宏块的格式,即宏块由类型产生式、值产生式和其他产生式三部分组成。

    产生式(4)和(5)定义了类型、值产生式部分规则,而产生式(6)、(7)和(8)定义了其他产生式部分,意义直观。这几个产生式的右端均为 MacroAlternativeList。

    余下的产生式定义MacroAlternativeList。从产生式(10)~(13)可以看出,MacroAlternativeList其实是若干个SymbolDefn 或 EmbeddedDefinitions,如有多个,使用符号“|”分隔。

    产生式(15)和(21)定义了MacroType 和 MacroValue,这里可以理解为ASN .1内置类型(值)和已定义类型(值)。

    产生式(16)~(20)看起来眼花缭乱,实际上就是一个或多个普通ASN .1类型定义语句、赋值语句的列表。

    产生式(14)定义了类型产生式、值产生式部分可以出现的符号,表2-3列出了常见的符号意义。

    至此,读者已经有了足够的宏知识来分析一个宏实例了。

    2.7.3 宏实例分析宏MODULE-IDENTITY定义了一种新类型。在ASN.1模块中,使用该类型的赋值语句可以:

    表明模块的最后更新时间;表明模块所属的组织;作者的联系方式;模块内容的概括描述;模块的标识符。

    其中前面几项包含在类型的类型符号中,最后一项通过值符号确定。下面的例子摘自RFC 1902,定义如下:

    (1) MODULE-IDENTITY MACRO ::= (2) BEGIN (3)    TYPE NOTATION ::=                  --类型符号定义开始 (4)         "LAST-UPDATED" value(Update UTCTime) (5)         "ORGANIZATION" Text (6)         "CONTACT-INFO" Text (7)         "DESCRIPTION" Text (8)         RevisionPart               --类型符号定义结束 (9)  VALUE NOTATION ::= value(VALUE OBJECT IDENTIFIER)     --值符号定义 (10)  RevisionPart ::= Revisions | empty            --支持产生式定义开始 (11)  Revisions ::= Revision | Revisions Revision (12)  Revision ::= "REVISION" value(Update UTCTime) (13)       "DESCRIPTION" Text (14)  Text ::= """" string """"                --支持产生式结束 (15) END

    首先分析简单的部分,第1、2和15行为宏定义的固定格式。从第1行可以看到,宏名字为MODULE-IDENTITY;第9行为值符号定义部分,可以这样理解:宏定义的类型值符号、值范围,与类型OBJECT IDENTIFIER完全一致。

    第3~8行为类型符号定义部分,可根据该部分确定类型的符号形式。其中,第4~7行中用双引号引起来的几个终结符,照写即可。第4行终结符后的value(Update UTCTime)处是一个类型为UTCTime的值,第5~7行中三个终结符后紧跟由Text限定的字符,第8行是RevisionPart限定的符号。

    根据第10~13行的产生式定义,RevisionPart部分可以为空,也可以是多个Revision;而一个Revision形如下式:

    REVISION    "9505241811Z"  DESCRIPTION  "The latest version of this MIB module."

    第14行中的Text则是用双引号引起来的字符串。注意产生式右端,string两边各有4个双引号。最里面的一对双引号和字符串string一起,是基本单词,意义等同于基本单词string。前3个和最后3个双引号,分别在基本单词“string”两边限定了两个终结符——前双引号和后双引号。因此,Text的最终形式是两边带有双引号的字符串。

    这样,可以确定类型符号由两部分组成:终结符+ Value(Update UTCTime)+Text部分和RevisionPart部分。RevisionPart部分可以是空,也可以是多个Revision的排列。

    Value(Update UTCTime)是类型ASN.1内置类型UTCTime的实例值。

    下面是一个宏MODULE-IDENTITY的应用实例。

    fizbin MODULE-IDENTITY   LAST-UPDATED "9505241811Z"          --终结LAST-UPDATED + UTCTime值                           --"9505241811Z" 是类型UTCTime取值   ORGANIZATION "IETF SNMPv2 Working Group"  --终结符ORGANIZATION +Text   CONTACT-INFO       " Marshall T. Rose        Postal: Dover Beach Consulting, Inc.            420 Whisman Court            Mountain View, CA 94043-2186            US         Tel: +1 415 968 1052         Fax: +1 415 968 2510        E-mail: mrose@dbc.mtview.ca.us"    --终结符CONTACT-INFO +Text   DESCRIPTION  "The MIB module for entities implementing the xxxx protocol." --终结符DESCRIPTION +Text;   -- 下面开始是RevisionPart部分,共由两个Revision组成; REVISION   "9505241811Z"   DESCRIPTION "The latest version of this MIB module."   REVISION   "9210070433Z"   DESCRIPTION  "The initial version of this MIB module."   ::= { experimental 9 }

    斜体部分就是新类型的类型符号,跟在宏名字MODULE-IDENTITY后面,可以出现在一个ASN.1模块中任何一个ASN.1类型符号可以出现的地方。

    注意:

    上述宏类型符号定义中的Value(Update UTCTime)部分,笔者怀疑有误。根据宏定义的巴柯斯范式中关于SymbolDefn产生式的定义,这种形式应该适用选项value(localvaluereference MacroType),而Update应该是localvaluereference(本地值引用,类似valuereference,即一个值名)。但根据命名规则,值名应该以小写字母开始,因此,正确的形式应该是Value(update UTCTime)。

    相关资源:SNMP经典著作《精通SNMP》 高清pdf
    最新回复(0)