|
|
1.1 ! root 1: ! 2: ! 3: ! 4: ! 5: draft Exporting MIBs for BSD UNIX May 1990 ! 6: ! 7: ! 8: How to export a MIB module ! 9: from a BSD UNIX daemon ! 10: using the 4BSD/ISODE SMUX API ! 11: ! 12: Sun May 13 14:54:13 1990 ! 13: ! 14: ! 15: Marshall T. Rose ! 16: ! 17: Performance Systems International, Inc. ! 18: 11800 Sunrise Valley Drive ! 19: Suite 1100 ! 20: Reston, VA 22091 ! 21: ! 22: [email protected] ! 23: ! 24: ! 25: ! 26: ! 27: ! 28: ! 29: 1. Status of this Memo ! 30: ! 31: This document defines an API for UNIX daemons wishing to ! 32: implement a MIB module on a BSD UNIX system using the ! 33: 4BSD/ISODE SNMP software. This is a local mechanism. ! 34: ! 35: ! 36: ! 37: ! 38: ! 39: ! 40: ! 41: ! 42: ! 43: ! 44: ! 45: ! 46: ! 47: ! 48: ! 49: ! 50: ! 51: ! 52: ! 53: ! 54: ! 55: ! 56: ! 57: ! 58: M.T. Rose [Page 1] ! 59: ! 60: ! 61: ! 62: ! 63: ! 64: draft Exporting MIBs for BSD UNIX May 1990 ! 65: ! 66: ! 67: 2. The Environment ! 68: ! 69: This document gives an overview of how one modifies a UNIX ! 70: program to export a MIB module to the local SNMP agent. ! 71: ! 72: All of the files necessary to interface to the SNMP agent is ! 73: contained in the ISODE source tree, in the snmp/ directory. ! 74: Since this document avoids giving the actual C procedural ! 75: definitions, you should familiarize yourself with the lint ! 76: library, llib-lisnmp. ! 77: ! 78: For the purposes of example, throughout this document we will ! 79: reference a simple UNIX daemon, unixd, which implements a MIB ! 80: module for "mbuf statistics". ! 81: ! 82: ! 83: 2.1. The ISODE ! 84: ! 85: As you might have guessed, this document assumes that you're ! 86: running the ISODE on your system. You should read the READ-ME ! 87: file at the base of the source tree for instructions on how to ! 88: configure, generate, and install the ISODE. In the future, an ! 89: abbreviated set of instructions, for those interested in ! 90: running the only 4BSD/ISODE SNMP software, will be written. ! 91: ! 92: For now, follow the READ-ME, generate the base system and ! 93: SNMP, e.g., ! 94: ! 95: % ./make all all-snmp ! 96: ! 97: and then install only the 4BSD/ISODE SNMP software: ! 98: ! 99: # ./make inst-all inst-snmp ! 100: ! 101: However, be sure to read the entire READ-ME file, as there are ! 102: other steps involved in installing the SNMP software. ! 103: ! 104: ! 105: ! 106: ! 107: ! 108: ! 109: ! 110: ! 111: ! 112: ! 113: ! 114: ! 115: ! 116: ! 117: M.T. Rose [Page 2] ! 118: ! 119: ! 120: ! 121: ! 122: ! 123: draft Exporting MIBs for BSD UNIX May 1990 ! 124: ! 125: ! 126: 3. MIB Modules ! 127: ! 128: The first thing you need to do is to define the actual managed ! 129: objects which your program will implement. This is done by ! 130: writing a "MIB module". The syntax of the module is defined ! 131: in the Internet-standard SMI, RFC1155. It is not the purpose ! 132: of this document to describe the rules used for writing a MIB ! 133: module. However, here are the basics to speed you on your ! 134: way. ! 135: ! 136: The MIB module is defined in a file called module.my, e.g., ! 137: unix.my. In general, there are three kinds of MIB modules: ! 138: ! 139: (1) If you are defining a MIB module for something UNIX ! 140: specific, it should probably go under the BSD UNIX MIB ! 141: (contact Marshall Rose or Keith Sklower to get a number ! 142: under the UNIX enterprise tree). In this case, the ! 143: definition might start something like this: ! 144: ! 145: SendMail-MIB { iso org(3) dod(6) internet(1) private(4) ! 146: enterprises(1) unix (4) sendmail (99) } ! 147: ! 148: DEFINITIONS ::= BEGIN ! 149: ! 150: IMPORTS ! 151: unix --*, OBJECT-TYPE *-- ! 152: FROM RFC1155-SMI; ! 153: ! 154: sendMail OBJECT IDENTIFIER ::= { unix 99 } ! 155: ! 156: ! 157: (2) If you are defining a MIB module on a multilateral, ! 158: experimental basis, e.g., for a protocol like the NTP, ! 159: then you should contact the Internet Assigned Numbers ! 160: Authority ([email protected]) and ask for an experimental ! 161: number. In this case, the definition might start ! 162: something like this: ! 163: ! 164: FIZBIN-MIB DEFINITIONS ::= BEGIN ! 165: ! 166: IMPORTS ! 167: experimental, OBJECT-TYPE ! 168: FROM RFC1155-SMI; ! 169: ! 170: fizBin OBJECT IDENTIFIER ::= { experimental 99 } ! 171: ! 172: ! 173: ! 174: ! 175: ! 176: M.T. Rose [Page 3] ! 177: ! 178: ! 179: ! 180: ! 181: ! 182: draft Exporting MIBs for BSD UNIX May 1990 ! 183: ! 184: ! 185: (3) Otherwise, if you are defining a MIB module for something ! 186: specific to your enterprise, then you contact the ! 187: Internet Assigned Numbers Authority ([email protected]) and ! 188: ask for an enterprise number (assuming you don't already ! 189: have one). In this case, the definition might start ! 190: something like this: ! 191: ! 192: FIZZBIN-MIB DEFINITIONS ::= BEGIN ! 193: ! 194: IMPORTS ! 195: enterprises, OBJECT-TYPE ! 196: FROM RFC1155-SMI; ! 197: ! 198: cheetah OBJECT IDENTIFIER ::= { enterprises 9999 } ! 199: ! 200: fizBin OBJECT IDENTIFIER ::= { cheetah 1 } ! 201: ! 202: ! 203: Regardless of the kind of MIB module, this last OBJECT ! 204: IDENTIFIER points to the root of the tree which your agent is ! 205: going to export. ! 206: ! 207: Following this start, you have the actual definitions of the ! 208: MIB objects, followed by ! 209: ! 210: END ! 211: ! 212: ! 213: ! 214: 3.1. Compiling MIB modules ! 215: ! 216: The next step is to compile the MIB module into a form that ! 217: your program can read. This is done using the mosy program: ! 218: ! 219: % others/mosy/xmosy module.my ! 220: ! 221: which will create the file module.defs. In most cases you ! 222: will need to prefix this file with definitions from the root ! 223: of the OBJECT IDENTIFIER tree, e.g., ! 224: ! 225: % cat $(INCDIR)isode/snmp/smi.defs module.defs > daemon.defs ! 226: ! 227: where the daemon.defs file will be the one which you install ! 228: with your program binary. ! 229: ! 230: ! 231: ! 232: ! 233: ! 234: ! 235: M.T. Rose [Page 4] ! 236: ! 237: ! 238: ! 239: ! 240: ! 241: draft Exporting MIBs for BSD UNIX May 1990 ! 242: ! 243: ! 244: 3.1.1. The Syntax of compiled MIB modules ! 245: ! 246: The syntax is pretty simple: ! 247: ! 248: (1) Comments start with "--" or "#" at the beginning of a ! 249: line. ! 250: ! 251: (2) Object identifiers are defined like this: ! 252: ! 253: name value ! 254: ! 255: e.g., ! 256: ! 257: internet iso.3.6.1 ! 258: ! 259: ! 260: (3) Object types are defined like this: ! 261: ! 262: name oid syntax access status ! 263: ! 264: e.g., ! 265: ! 266: sysDescr system.1 DisplayString read-only mandatory ! 267: ! 268: where "name" and "oid" are fairly obvious. For the rest: ! 269: ! 270: "syntax" is the name of a defined syntax; ! 271: ! 272: "access" is one of read-only, read-write", or none; ! 273: and, ! 274: ! 275: "status" is one of mandatory, optional, ! 276: deprecated, or obsolete. ! 277: ! 278: Names of objects are always case-sensitive. ! 279: ! 280: ! 281: ! 282: ! 283: ! 284: ! 285: ! 286: ! 287: ! 288: ! 289: ! 290: ! 291: ! 292: ! 293: ! 294: M.T. Rose [Page 5] ! 295: ! 296: ! 297: ! 298: ! 299: ! 300: draft Exporting MIBs for BSD UNIX May 1990 ! 301: ! 302: ! 303: 4. SMUX Peers ! 304: ! 305: A program which exports a MIB module is termed a "SMUX peer" ! 306: (SMUX is the name of the protocol used by these programs to ! 307: communicate with an SNMP agent.) ! 308: ! 309: There is a textual database, $(ETCDIR)snmpd.peers, which ! 310: defines the SMUX peers known to the local SNMP agent. The ! 311: syntax of this file is pretty simple: ! 312: ! 313: (1) Comments start with "#" at the beginning of a line. ! 314: ! 315: (2) Each peer is identified in a single line: ! 316: ! 317: name oid password [priority] ! 318: ! 319: where "name" and "oid" are fairly obvious. For the rest: ! 320: ! 321: "password" is a string which the agent will use to ! 322: authenticate the SMUX peer; ! 323: and, ! 324: ! 325: "priority", ! 326: if present, ! 327: is the highest priority with which the SMUX peer can register subtrees. ! 328: ! 329: The name/oid pairs are assigned by the authority for the ! 330: BSD UNIX MIB (contact Marshall Rose or Keith Sklower to ! 331: register the name of your program and get an for your ! 332: program). ! 333: ! 334: Note that this file contains things resembling passwords in ! 335: the clear. As such, it should be protected mode 0600 and ! 336: owned by root. ! 337: ! 338: ! 339: ! 340: ! 341: ! 342: ! 343: ! 344: ! 345: ! 346: ! 347: ! 348: ! 349: ! 350: ! 351: ! 352: ! 353: M.T. Rose [Page 6] ! 354: ! 355: ! 356: ! 357: ! 358: ! 359: draft Exporting MIBs for BSD UNIX May 1990 ! 360: ! 361: ! 362: 5. Daemon Skeleton ! 363: ! 364: Now it's time to modify your daemon to export the MIB. Your ! 365: source code should include these lines: ! 366: ! 367: #include <isode/snmp/smux.h> ! 368: #include <isode/snmp/objects.h> ! 369: #include <isode/tailor.h> ! 370: ! 371: which will include the definitions for: talking to the SNMP ! 372: agent via the SMUX protocol, the object management package, ! 373: and the ISODE tailoring subsystem. ! 374: ! 375: When loading your daemon, you should add this to the end of ! 376: your command to the loader: ! 377: ! 378: -lisnmp -lisode ! 379: ! 380: which includes the 4BSD/SNMP and ISODE libraries. ! 381: ! 382: You should decide if you want to use the ISODE logging ! 383: subsystem. This is a convenient mechanism for using a unified ! 384: logging system. If you are modifying an already existing ! 385: daemon, you probably have your own logging package. ! 386: Otherwise, you should consider using the ISODE subsystem. ! 387: ! 388: ! 389: 5.1. Declarations ! 390: ! 391: There are some global variables that your program will have to ! 392: declare: ! 393: ! 394: int debug = 0; ! 395: static char *myname = "unixd"; ! 396: ! 397: static LLog _pgm_log = { ! 398: "unixd.log", NULLCP, NULLCP, ! 399: LLOG_FATAL | LLOG_EXCEPTIONS | LLOG_NOTICE, ! 400: LLOG_FATAL, -1, LLOGCLS | LLOGCRT | LLOGZER, NOTOK ! 401: }; ! 402: static LLog *pgm_log = &_pgm_log; ! 403: ! 404: static OID subtree = NULLOID; ! 405: static struct smuxEntry *se = NULL; ! 406: ! 407: ! 408: ! 409: ! 410: ! 411: ! 412: M.T. Rose [Page 7] ! 413: ! 414: ! 415: ! 416: ! 417: ! 418: draft Exporting MIBs for BSD UNIX May 1990 ! 419: ! 420: ! 421: static int smux_fd = NOTOK; ! 422: static int rock_and_roll = 0; ! 423: static int dont_bother_anymore = 0; ! 424: ! 425: static int quantum = 0; ! 426: ! 427: You only need the definition of _pgm_log and pgm_log if you ! 428: will be using the ISODE logging subsystem. ! 429: ! 430: ! 431: 5.2. Initialization ! 432: ! 433: When your program initializes itself, it should contain some ! 434: code like this: ! 435: ! 436: if (myname = rindex (argv[0], '/')) ! 437: myname++; ! 438: if (myname == NULL || *myname == NULL) ! 439: myname = argv[0]; ! 440: ! 441: isodetailor (myname, 0); ! 442: ll_hdinit (pgm_log, myname); ! 443: ! 444: /* scan argv, set debug if need be... */ ! 445: ! 446: if (debug) ! 447: ll_dbinit (pgm_log, myname); ! 448: ! 449: Of course, if you're not using the ISODE logging subsystem, ! 450: you don't have the calls to ll_hdinit or ll_dbinit. ! 451: ! 452: After cracking argv, your program should do the usual ! 453: detaching actions. Usually at this point, your program reads ! 454: the compiled MIB module definitions and starts talking to the ! 455: SNMP agent. ! 456: ! 457: ! 458: 5.3. Reading the compiled MIB module ! 459: ! 460: You program should call the readobjects routine to read the ! 461: module, look-up the subtree which it will export to the SNMP ! 462: agent, and call the getsmuxEntrybyname routine to find its ! 463: entry in the snmpd.peers database. Finally, it should call a ! 464: routine you define, e.g., init_mib, to initialize it's ! 465: internal MIB structures. (We'll look at this routine in ! 466: ! 467: ! 468: ! 469: ! 470: ! 471: M.T. Rose [Page 8] ! 472: ! 473: ! 474: ! 475: ! 476: ! 477: draft Exporting MIBs for BSD UNIX May 1990 ! 478: ! 479: ! 480: greater detail later on.) ! 481: ! 482: OT ot; ! 483: ! 484: if (readobjects ("unixd.defs") == NOTOK) ! 485: error ("readobjects: %s", PY_pepy); ! 486: ! 487: if ((ot = text2obj ("mbuf")) == NULL) ! 488: error ("object ! 489: subtree = ot -> ot_name; ! 490: ! 491: if (se = getsmuxEntrybyname ("unixd")) == NULL) ! 492: error ("no SMUX entry for ! 493: ! 494: init_mib (); ! 495: ! 496: If any of these routines fail, then don't bother trying to ! 497: export the MIB module. ! 498: ! 499: ! 500: 5.4. Talking to the SNMP agent ! 501: ! 502: All of the SMUX routines return NOTOK on failure. Unless ! 503: otherwise noted, these routines also return OK on success. On ! 504: failure, the variable ! 505: ! 506: extern int smux_errno; ! 507: ! 508: is set to a symbolic value defined in smux.h, one of: ! 509: ! 510: invalidOperation ! 511: parameterMissing ! 512: systemError ! 513: youLoseBig ! 514: congestion ! 515: inProgress ! 516: ! 517: In addition, the variable ! 518: ! 519: extern char smux_info[BUFSIZ]; ! 520: ! 521: contains a printable explanation of what happened on failure. ! 522: ! 523: All errors are FATAL except for inProgress. This means retry ! 524: your operation later on. ! 525: ! 526: ! 527: ! 528: ! 529: ! 530: M.T. Rose [Page 9] ! 531: ! 532: ! 533: ! 534: ! 535: ! 536: draft Exporting MIBs for BSD UNIX May 1990 ! 537: ! 538: ! 539: 5.4.1. Initialization ! 540: ! 541: You program should call the routine smux_init, which ! 542: initializes a SMUX connection to the local SNMP agent. This ! 543: starts a TCP connection, but most likely does not complete it. ! 544: You program will need to call an open routine (there is only ! 545: one at present) to finish the connect and establish the SMUX ! 546: association. ! 547: ! 548: If successful, the return value is a file-descriptor, suitable ! 549: for use with select, etc. ! 550: ! 551: On failure, smux_errno will be set to one of congestion, ! 552: youLoseBig, or systemError. In this case, you should probably ! 553: have your program retry the operation every 5 minutes or so. ! 554: ! 555: if ((smux_fd = smux_init (debug)) == NOTOK) ! 556: error ("smux_init: %s [%s]", ! 557: smux_error (smux_errno), smux_info); ! 558: else ! 559: rock_and_roll = 0; ! 560: ! 561: ! 562: ! 563: 5.4.2. Opening ! 564: ! 565: Once smux_init returns OK, you should start selecting for ! 566: writability on the file-descriptor returned. Once select says ! 567: your program can write to the fd, your program should call the ! 568: routine smux_simple_open, which establishes the SMUX ! 569: association. ! 570: ! 571: On failure, smux_error will be set to one of parameterMissing, ! 572: invalidOperation, inProgress, systemError, congestion, or ! 573: youLoseBig. If the error code is inProgress, then your ! 574: program should continue retrying the fd for writability, and ! 575: then call smux_simple_open again. Otherwise, your program ! 576: should take the appropriate action based on the error code ! 577: returned. ! 578: ! 579: if (smux_simple_open (&se -> se_identity, ! 580: "SMUX UNIX daemon", ! 581: se -> se_password, ! 582: strlen (se -> se_password)) ! 583: == NOTOK) { ! 584: ! 585: ! 586: ! 587: ! 588: ! 589: M.T. Rose [Page 10] ! 590: ! 591: ! 592: ! 593: ! 594: ! 595: draft Exporting MIBs for BSD UNIX May 1990 ! 596: ! 597: ! 598: if (smux_errno == inProgress) ! 599: return; ! 600: ! 601: error ("smux_simple_open: %s [%s]", ! 602: smux_error (smux_errno), smux_info); ! 603: smux_fd = NOTOK; ! 604: } ! 605: else ! 606: rock_and_roll = 1; ! 607: ! 608: ! 609: ! 610: 5.4.3. Closing ! 611: ! 612: If, for some reason, your program wishes to close the SMUX ! 613: association. There are several reasons that are allowed: ! 614: ! 615: goingDown ! 616: unsupportedVersion ! 617: packetFormat ! 618: protocolError ! 619: internalError ! 620: authenticationFailure ! 621: ! 622: On failure, smux_error will be set to one of invalidOperation, ! 623: congestion, or youLoseBig. ! 624: ! 625: ! 626: 5.4.4. Registering Subtrees ! 627: ! 628: Once smux_simple_open returns OK, your program should register ! 629: the MIB module that your daemon will export by calling ! 630: smux_register. A subtree can be registered in one of three ! 631: modes: ! 632: ! 633: readOnly ! 634: readWrite ! 635: delete ! 636: ! 637: which are all fairly obvious. ! 638: ! 639: Note that a return value of OK from smux_register means only ! 640: that the registration request was queued for the SNMP agent ! 641: via the SMUX protocol. Some time later the SNMP agent's ! 642: response will be forthcoming. ! 643: ! 644: ! 645: ! 646: ! 647: ! 648: M.T. Rose [Page 11] ! 649: ! 650: ! 651: ! 652: ! 653: ! 654: draft Exporting MIBs for BSD UNIX May 1990 ! 655: ! 656: ! 657: On failure, smux_error will be set to one of parameterMissing, ! 658: invalidOperation, congestion, or youLoseBig. Your program ! 659: should take the appropriate action based on the error code ! 660: returned. ! 661: ! 662: if (smux_register (subtree, -1, readOnly) == NOTOK) { ! 663: error ("smux_register: %s [%s]", ! 664: smux_error (smux_errno), smux_info); ! 665: smux_fd = NOTOK; ! 666: } ! 667: ! 668: ! 669: ! 670: 5.4.5. Main Loop ! 671: ! 672: At this point, your program is more or less in it's main loop ! 673: (actually, it probably entered the main loop after the very ! 674: first call to smux_init). ! 675: ! 676: int nfds; /* these are set for other fd's... */ ! 677: ! 678: fd_set ifds; ! 679: fd_set ofds; ! 680: ! 681: for (;;) { ! 682: int n, ! 683: secs; ! 684: fd_set rfds, ! 685: wfds; ! 686: ! 687: secs = NOTOK; ! 688: ! 689: rfds = ifds; /* struct copy */ ! 690: wfds = ofds; /* .. */ ! 691: ! 692: if (smux_fd == NOTOK && !dont_bother_anymore) ! 693: secs = 5 * 60L; ! 694: else ! 695: if (rock_and_roll) ! 696: FD_SET (smux_fd, &rfds); ! 697: else ! 698: FD_SET (smux_fd, &wfds); ! 699: if (smux_fd >= nfds) ! 700: nfds = smux_fd + 1; ! 701: ! 702: ! 703: ! 704: ! 705: ! 706: ! 707: M.T. Rose [Page 12] ! 708: ! 709: ! 710: ! 711: ! 712: ! 713: draft Exporting MIBs for BSD UNIX May 1990 ! 714: ! 715: ! 716: if ((n = xselect (nfds, &rfds, &wfds, NULLFD, secs)) ! 717: == NOTOK) { ! 718: error ("xselect failed"); ! 719: ... ! 720: } ! 721: ! 722: /* check fd's for other purposes here... */ ! 723: ! 724: if (smux_fd == NOTOK && !dont_bother_anymore) { ! 725: if (n == 0) { ! 726: if ((smux_fd = smux_init (debug)) == NOTOK) ! 727: error ("smux_init: %s [%s]", ! 728: smux_error (smux_errno), ! 729: smux_info); ! 730: else ! 731: rock_and_roll = 0; ! 732: } ! 733: } ! 734: else ! 735: if (rock_and_roll) { ! 736: if (FD_ISSET (smux_fd, &rfds)) ! 737: doit_smux (); ! 738: } ! 739: else ! 740: if (FD_ISSET (smux_fd, &wfds)) { ! 741: if (smux_simple_open (&se -> se_identity, ! 742: "SMUX UNIX daemon", ! 743: se -> se_password, ! 744: strlen (se -> se_password)) ! 745: == NOTOK) { ! 746: if (smux_errno != inProgress) { ! 747: error ("smux_simple_open: %s [%s]", ! 748: smux_error (smux_errno), ! 749: smux_info); ! 750: smux_fd = NOTOK; ! 751: } ! 752: } ! 753: else { ! 754: rock_and_roll = 1; ! 755: ! 756: if (smux_register (subtree, -1, ! 757: readOnly) == NOTOK) { ! 758: error ("smux_register: %s [%s]", ! 759: smux_error (smux_errno), ! 760: smux_info); ! 761: ! 762: ! 763: ! 764: ! 765: ! 766: M.T. Rose [Page 13] ! 767: ! 768: ! 769: ! 770: ! 771: ! 772: draft Exporting MIBs for BSD UNIX May 1990 ! 773: ! 774: ! 775: smux_fd = NOTOK; ! 776: } ! 777: } ! 778: } ! 779: ! 780: So, all that remains is to take a look at the routine ! 781: doit_smux mentioned above. This is called when select ! 782: indicates the SMUX file-descriptor is ready for reading. ! 783: ! 784: ! 785: 5.4.6. Events ! 786: ! 787: When select indicates the SMUX file-descriptor is ready for ! 788: reading, your program calls the routine smux_wait to return ! 789: the next event from the SNMP agent. ! 790: ! 791: Note that the event is filled-in from a static area. On the ! 792: next call to smux_init, smux_close, or smux_wait, the value ! 793: will be overwritten. As such, do not free this structure ! 794: yourself. ! 795: ! 796: On failure, smux_error will be set to one of parameterMissing, ! 797: invalidOperation, inProgress, or youLoseBig. Your program ! 798: should take the appropriate action based on the error code ! 799: returned. ! 800: ! 801: struct type_SNMP_SMUX__PDUs *event; ! 802: ! 803: if (smux_wait (&event, NOTOK) == NOTOK) { ! 804: if (smux_errno == inProgress) ! 805: return; ! 806: ! 807: error ("smux_wait: %s [%s]", ! 808: smux_error (smux_errno), smux_info); ! 809: losing: ; ! 810: smux_fd = NOTOK; ! 811: return; ! 812: } ! 813: ! 814: Next, your program should switch based on the actual event ! 815: returned: ! 816: ! 817: type_SNMP_SMUX__PDUs_registerResponse ! 818: type_SNMP_SMUX__PDUs_get_request ! 819: type_SNMP_SMUX__PDUs_get__next__request ! 820: ! 821: ! 822: ! 823: ! 824: ! 825: M.T. Rose [Page 14] ! 826: ! 827: ! 828: ! 829: ! 830: ! 831: draft Exporting MIBs for BSD UNIX May 1990 ! 832: ! 833: ! 834: type_SNMP_SMUX__PDUs_close ! 835: ! 836: The actual code is fairly straight-forward: ! 837: ! 838: switch (event -> offset) { ! 839: case type_SNMP_SMUX__PDUs_registerResponse: ! 840: { ! 841: struct type_SNMP_RRspPDU *rsp = ! 842: event -> un.registerResponse; ! 843: ! 844: if (rsp -> parm == int_SNMP_RRspPDU_failure) { ! 845: error ("SMUX registration of %s failed", ! 846: oid2ode (subtree)); ! 847: dont_bother_anymore = 1; ! 848: (void) smux_close (goingDown); ! 849: break; ! 850: } ! 851: } ! 852: if (smux_trap (int_SNMP_generic__trap_coldStart, ! 853: 0, (struct type_SNMP_VarBindList *) 0) ! 854: == NOTOK) { ! 855: error ("smux_trap: %s [%s]", ! 856: smux_error (smux_errno), smux_info); ! 857: break; ! 858: } ! 859: return; ! 860: ! 861: case type_SNMP_SMUX__PDUs_get_request: ! 862: case type_SNMP_SMUX__PDUs_get__next__request: ! 863: get_smux (event -> un.get__request, event -> offset); ! 864: return; ! 865: ! 866: case type_SNMP_SMUX__PDUs_close: ! 867: notice ("SMUX close: %s", ! 868: smux_error (event -> un.close -> parm)); ! 869: break; ! 870: ! 871: default: ! 872: error ("bad SMUX operation: %d", event -> offset); ! 873: (void) smux_close (protocolError); ! 874: break; ! 875: } ! 876: smux_fd = NOTOK; ! 877: ! 878: Note the use of the smux_trap routine to send a coldStart trap ! 879: ! 880: ! 881: ! 882: ! 883: ! 884: M.T. Rose [Page 15] ! 885: ! 886: ! 887: ! 888: ! 889: ! 890: draft Exporting MIBs for BSD UNIX May 1990 ! 891: ! 892: ! 893: once the daemon has successful registered the MIB module it is ! 894: exporting. The trap codes are: ! 895: ! 896: int_SNMP_generic__trap_coldStart ! 897: int_SNMP_generic__trap_warmStart ! 898: int_SNMP_generic__trap_linkDown ! 899: int_SNMP_generic__trap_linkUp ! 900: int_SNMP_generic__trap_authenticationFailure ! 901: int_SNMP_generic__trap_egpNeighborLoss ! 902: int_SNMP_generic__trap_enterpriseSpecific ! 903: ! 904: If this routine fails, smux_errno will be set to one of ! 905: invalidOperation, congestion, or youLoseBig. ! 906: ! 907: So, all that remains is to take a look at the routine get_smux ! 908: which implements the SNMP get and powerful get-next operators. ! 909: We will return to this routine once the structures and ! 910: routines which implement the managed object abstraction are ! 911: explained. ! 912: ! 913: ! 914: ! 915: ! 916: ! 917: ! 918: ! 919: ! 920: ! 921: ! 922: ! 923: ! 924: ! 925: ! 926: ! 927: ! 928: ! 929: ! 930: ! 931: ! 932: ! 933: ! 934: ! 935: ! 936: ! 937: ! 938: ! 939: ! 940: ! 941: ! 942: ! 943: M.T. Rose [Page 16] ! 944: ! 945: ! 946: ! 947: ! 948: ! 949: draft Exporting MIBs for BSD UNIX May 1990 ! 950: ! 951: ! 952: 6. Managed Objects ! 953: ! 954: A managed object is an abstraction with a syntax and a ! 955: semantics. The syntax defines what instances of the object ! 956: look like on the network. The semantics define what the ! 957: object actually is. ! 958: ! 959: ! 960: 6.1. Syntax ! 961: ! 962: The syntax of MIB objects is modeled by the OS structure: ! 963: ! 964: typedef struct object_syntax { ! 965: char *os_name; /* syntax name */ ! 966: ! 967: IFP os_encode; /* data -> PE */ ! 968: IFP os_decode; /* PE -> data */ ! 969: IFP os_free; /* free data */ ! 970: ! 971: IFP os_parse; /* str -> data */ ! 972: IFP os_print; /* data -> tty */ ! 973: ! 974: ... ! 975: } object_syntax, *OS; ! 976: #define NULLOS ((OS) 0) ! 977: ! 978: The syntaxes defined by the Internet-standard MIB are already ! 979: implemented: ! 980: ! 981: syntax structure ! 982: INTEGER integer ! 983: OctetString struct qbuf (OCTET STRING) ! 984: ObjectID struct OIDentifier (OBJECT IDENTIFIER) ! 985: NULL char ! 986: DisplayString struct qbuf ! 987: IpAddress struct sockaddr_in ! 988: NetworkAddress struct sockaddr_in ! 989: Counter integer ! 990: Gauge integer ! 991: TimeTicks integer ! 992: ClnpAddress struct sockaddr_iso ! 993: ! 994: where "syntax" is the name appearing in a compiled MIB module, ! 995: and "structure" is the C language data type corresponding to ! 996: the object's syntax. ! 997: ! 998: ! 999: ! 1000: ! 1001: ! 1002: M.T. Rose [Page 17] ! 1003: ! 1004: ! 1005: ! 1006: ! 1007: ! 1008: draft Exporting MIBs for BSD UNIX May 1990 ! 1009: ! 1010: ! 1011: To take a syntax name and get back the structure, use the ! 1012: routine text2syn. ! 1013: ! 1014: ! 1015: 6.1.1. Abstractions for Standard Syntaxes ! 1016: ! 1017: Here are the structures and routine used to implement the ! 1018: low-level MIB abstractions. ! 1019: ! 1020: ! 1021: 6.1.1.1. integer ! 1022: ! 1023: This is used for the INTEGER, Counter, Gauge, and TimeTicks ! 1024: syntax. ! 1025: ! 1026: The definition is: ! 1027: ! 1028: typedef int integer; ! 1029: ! 1030: which is hardly surprising. ! 1031: ! 1032: ! 1033: 6.1.1.2. struct qbuf ! 1034: ! 1035: This is used for the OctetString (OBJECT IDENTIFIER) and ! 1036: DisplayString syntaxes. ! 1037: ! 1038: The definition is: ! 1039: ! 1040: struct qbuf { ! 1041: struct qbuf *qb_forw; /* doubly-linked list */ ! 1042: struct qbuf *qb_back; /* .. */ ! 1043: ! 1044: int qb_len; /* length of data */ ! 1045: char *qb_data; /* current pointer into data */ ! 1046: char qb_base[1]; /* extensible... */ ! 1047: }; ! 1048: ! 1049: The macro QBFREE is used to traverse qb_forw to free all qbufs ! 1050: in the ring: ! 1051: ! 1052: QBFREE (qb) ! 1053: struct qbuf *qb; ! 1054: ! 1055: To allocate a new string from the qbuf use: ! 1056: ! 1057: ! 1058: ! 1059: ! 1060: ! 1061: M.T. Rose [Page 18] ! 1062: ! 1063: ! 1064: ! 1065: ! 1066: ! 1067: draft Exporting MIBs for BSD UNIX May 1990 ! 1068: ! 1069: ! 1070: char *qb2str (q) ! 1071: struct qbuf *q ! 1072: ! 1073: The string is NULL-terminated, but there may be other NULLs in ! 1074: the string to foil things like strlen. ! 1075: ! 1076: To allocate a new qbuf of len octets from string s, use: ! 1077: ! 1078: struct qbuf str2qb (s, len, head) ! 1079: char *s; ! 1080: int len, ! 1081: head; ! 1082: ! 1083: (head should always be 1). ! 1084: ! 1085: To free an allocated qbuf, use qb_free which calls QBFREE and ! 1086: then free on its argument. ! 1087: ! 1088: ! 1089: 6.1.1.3. struct OIDentifier ! 1090: ! 1091: This is used for the ObjectID (OBJECT IDENTIFIER) syntax. The ! 1092: definition is: ! 1093: ! 1094: typedef struct OIDentifier { ! 1095: int oid_nelem; /* number of sub-identifiers */ ! 1096: ! 1097: unsigned int *oid_elements; ! 1098: /* the (ordered) list of sub-identifiers */ ! 1099: } OIDentifier, *OID; ! 1100: #define NULLOID ((OID) 0) ! 1101: ! 1102: To compare two OIDs, use ! 1103: ! 1104: int oid_cmp (p, q) ! 1105: OID p, ! 1106: q; ! 1107: ! 1108: which returns -1 if p<q, 1 if p>q, 0 otherwise. ! 1109: ! 1110: To allocate a new OID and copy it from another, use oid_cpy. ! 1111: ! 1112: To free an allocated OID, use oid_free. ! 1113: ! 1114: ! 1115: ! 1116: ! 1117: ! 1118: ! 1119: ! 1120: M.T. Rose [Page 19] ! 1121: ! 1122: ! 1123: ! 1124: ! 1125: ! 1126: draft Exporting MIBs for BSD UNIX May 1990 ! 1127: ! 1128: ! 1129: To take an OID and produce a string in numeric form use ! 1130: ! 1131: char *sprintoid (oid) ! 1132: OID oid; ! 1133: ! 1134: The result is returned in a static area. The inverse routine ! 1135: is: ! 1136: ! 1137: OID str2oid (s) ! 1138: char *s; ! 1139: ! 1140: which returns an OID from a static area ! 1141: ! 1142: ! 1143: 6.1.1.4. struct sockaddr_in ! 1144: ! 1145: This is used for the IpAddress and NetworkAddress syntaxes. ! 1146: Presumably you are overly familiar with this structure. ! 1147: ! 1148: ! 1149: 6.1.1.5. struct sockaddr_iso ! 1150: ! 1151: This is used for the ClnpAddress syntax. If your are not ! 1152: running a BSD/OSI system, don't worry about this. ! 1153: ! 1154: ! 1155: 6.1.2. Defining a new Syntax ! 1156: ! 1157: The routine add_syntax is used to define a new syntax. (if ! 1158: this routine returns NOTOK, then the internal syntax table has ! 1159: overflowed; adjust the constant MAXSYN in the file syntax.c). ! 1160: The first argument is the name of the syntax. The other five ! 1161: are pointers to integer-valued routines that are called to ! 1162: operate on an opaque pointer: ! 1163: ! 1164: /* returns OK if x is encoded into pe (allocates pe), ! 1165: NOTOK otherwise */ ! 1166: ! 1167: f_encode (x, pe) ! 1168: pointer *x; ! 1169: PE *pe; ! 1170: ! 1171: ! 1172: /* returns OK if pe is decoded into x (allocates x), ! 1173: NOTOK otherwise */ ! 1174: ! 1175: ! 1176: ! 1177: ! 1178: ! 1179: M.T. Rose [Page 20] ! 1180: ! 1181: ! 1182: ! 1183: ! 1184: ! 1185: draft Exporting MIBs for BSD UNIX May 1990 ! 1186: ! 1187: ! 1188: f_decode (x, pe) ! 1189: pointer **x; ! 1190: PE pe; ! 1191: ! 1192: ! 1193: /* free's an allocated x (from f_decode or f_parse) */ ! 1194: ! 1195: f_free (x) ! 1196: pointer *x; ! 1197: ! 1198: ! 1199: /* returns OK if s is decoded into x (allocates x), ! 1200: NOTOK otherwise */ ! 1201: ! 1202: f_parse (x, s) ! 1203: pointer **x; ! 1204: char *s; ! 1205: ! 1206: ! 1207: /* prints x on the user's tty */ ! 1208: ! 1209: f_print (x, os) ! 1210: pointer *x; ! 1211: OS os; ! 1212: ! 1213: Presentation elements (PEs) are discussed later on. ! 1214: ! 1215: ! 1216: 6.2. Objects ! 1217: ! 1218: MIB objects are modeled by the OT structure: ! 1219: ! 1220: typedef struct object_type { ! 1221: char *ot_text; /* OBJECT DESCRIPTOR */ ! 1222: char *ot_id; /* OBJECT IDENTIFIER */ ! 1223: OID ot_name; /* .. */ ! 1224: ! 1225: OS ot_syntax; /* SYNTAX */ ! 1226: ! 1227: int ot_access; /* ACCESS */ ! 1228: #define OT_NONE 0x00 ! 1229: #define OT_RDONLY 0x01 ! 1230: #define OT_RDWRITE 0x02 ! 1231: ! 1232: int ot_status; /* STATUS */ ! 1233: ! 1234: ! 1235: ! 1236: ! 1237: ! 1238: M.T. Rose [Page 21] ! 1239: ! 1240: ! 1241: ! 1242: ! 1243: ! 1244: draft Exporting MIBs for BSD UNIX May 1990 ! 1245: ! 1246: ! 1247: #define OT_OBSOLETE 0x00 ! 1248: #define OT_MANDATORY 0x01 ! 1249: #define OT_OPTIONAL 0x02 ! 1250: #define OT_DEPRECATED 0x03 ! 1251: ! 1252: ... ! 1253: } object_type, *OT; ! 1254: #define NULLOT ((OT) 0) ! 1255: ! 1256: There are lots of routines to manipulate MIB objects. ! 1257: ! 1258: The routine name2obj takes an object identifier and returns ! 1259: the object type, either exact or prefix, e.g., ! 1260: ! 1261: name2obj ( OID { ipRouteDest.0.0.0.0 } ) ! 1262: ! 1263: returns the object type for "ipRouteDest" ! 1264: ! 1265: The routine text2obj takes a string and returns the exact ! 1266: object type, e.g., ! 1267: ! 1268: text2obj ("ipRouteDest") ! 1269: ! 1270: will succeed, but ! 1271: ! 1272: text2obj ("ipRouteDest.0.0.0.0") ! 1273: ! 1274: will fail. ! 1275: ! 1276: The routine text2oid takes a string and returns the object ! 1277: identifier associated with the corresponding object. The ! 1278: string can be numeric (e.g., "1.3.6.1"), symbolic (e.g., ! 1279: "internet"), or symbolic.numeric (e.g., "iso.3.6.1"). ! 1280: ! 1281: The routine oid2ode takes an OID and returns a string suitable ! 1282: for pretty-printing, in the form symbolic or symbolic.numeric. ! 1283: ! 1284: ! 1285: 6.3. Instances ! 1286: ! 1287: MIB instances are modeled by the OI structure: ! 1288: ! 1289: typedef struct object_instance { ! 1290: OID oi_name; /* instance OID */ ! 1291: ! 1292: ! 1293: ! 1294: ! 1295: ! 1296: ! 1297: M.T. Rose [Page 22] ! 1298: ! 1299: ! 1300: ! 1301: ! 1302: ! 1303: draft Exporting MIBs for BSD UNIX May 1990 ! 1304: ! 1305: ! 1306: OT oi_type; /* prototype */ ! 1307: } object_instance, *OI; ! 1308: #define NULLOI ((OI) 0) ! 1309: ! 1310: There are lots of routines to manipulate MIB instances. ! 1311: ! 1312: The routine name2inst takes a variable name and returns the ! 1313: corresponding instance, e.g., ! 1314: ! 1315: name2inst ( OID { ipRouteDest.0.0.0.0 } ) ! 1316: ! 1317: will return an OI with oi_name set to its argument and oi_type ! 1318: set to the object type for "ipRouteDest". ! 1319: ! 1320: The routine next2inst finds the closest object type before the ! 1321: variable name and returns an OI corresponding to that object ! 1322: type. ! 1323: ! 1324: The routine text2inst first calls text2oid to get the OID ! 1325: corresponding to the argument, then calls name2obj to get the ! 1326: type associated with that OID. ! 1327: ! 1328: ! 1329: ! 1330: ! 1331: ! 1332: ! 1333: ! 1334: ! 1335: ! 1336: ! 1337: ! 1338: ! 1339: ! 1340: ! 1341: ! 1342: ! 1343: ! 1344: ! 1345: ! 1346: ! 1347: ! 1348: ! 1349: ! 1350: ! 1351: ! 1352: ! 1353: ! 1354: ! 1355: ! 1356: M.T. Rose [Page 23] ! 1357: ! 1358: ! 1359: ! 1360: ! 1361: ! 1362: draft Exporting MIBs for BSD UNIX May 1990 ! 1363: ! 1364: ! 1365: 7. Linkage ! 1366: ! 1367: It is now time to tie up all the loose ends. When your ! 1368: program starts, it needs to establish some linkage between the ! 1369: objects defined in the compiled MIB module and the data ! 1370: structures in your program. Further, when the SNMP agent asks ! 1371: to manipulate the object instances in the MIB module your ! 1372: program exported (e.g., using the powerful SNMP get-next ! 1373: operator), you need to have a small protocol engine to field ! 1374: these requests. ! 1375: ! 1376: The way the linkage is established is to associate a C routine ! 1377: with each of the leaf objects defined in the compiled MIB ! 1378: module. When the protocol engine fields a request from the ! 1379: SNMP agent, it will invoke that routine to "do the right ! 1380: thing". Typically, for each table in the compiled MIB module, ! 1381: you define a C routine to handle requests for the leaf objects ! 1382: of that table. In addition, there is usually one more routine ! 1383: defined to handle those leaf objects not found under any one ! 1384: table. For each C routine you define, you define a group of ! 1385: constant integer symbols which identify a leaf object that is ! 1386: handled by that routine (e.g., for each routine, you start ! 1387: numbering the symbols starting at 0 and going up). By ! 1388: convention, these symbols have the same name as the leaf ! 1389: objects. ! 1390: ! 1391: ! 1392: 7.1. Initialization ! 1393: ! 1394: Earlier it was noted that your program will probably call a ! 1395: routine called init_mib which initializes it's internal MIB ! 1396: structures. The routine should look something like this: ! 1397: ! 1398: register OT ot; ! 1399: ! 1400: if (ot = text2obj ("mbufS")) ! 1401: ot -> ot_getfnx = o_mbuf, ! 1402: ot -> ot_info = (caddr_t) mbufS; ! 1403: ! 1404: ... ! 1405: ! 1406: if (ot = text2obj ("mbufType")) ! 1407: ot -> ot_getfnx = o_mbufType, ! 1408: ot -> ot_info = (caddr_t) mbufType; ! 1409: ! 1410: ! 1411: ! 1412: ! 1413: ! 1414: ! 1415: M.T. Rose [Page 24] ! 1416: ! 1417: ! 1418: ! 1419: ! 1420: ! 1421: draft Exporting MIBs for BSD UNIX May 1990 ! 1422: ! 1423: ! 1424: where we can imagine that o_mbuf and o_mbufType are routines ! 1425: that are defined in your program, and mbufS and mbufType are ! 1426: constant symbols defined with those routines. ! 1427: ! 1428: ! 1429: 7.2. Generic Event Handling ! 1430: ! 1431: Earlier it was noted that your program will probably call a ! 1432: routine called get_smux which implements the SNMP get and ! 1433: powerful get-next operators. The routine should look ! 1434: something like this: ! 1435: ! 1436: static get_smux (pdu, offset) ! 1437: register struct type_SNMP_GetRequest__PDU *pdu; ! 1438: int offset; ! 1439: { ! 1440: int idx, ! 1441: status; ! 1442: object_instance ois; ! 1443: register struct type_SNMP_VarBindList *vp; ! 1444: ! 1445: quantum = pdu -> request__id; ! 1446: idx = 0; ! 1447: for (vp = pdu -> variable__bindings; vp; vp = vp -> next) { ! 1448: register OI oi; ! 1449: register OT ot; ! 1450: register struct type_SNMP_VarBind *v = vp -> VarBind; ! 1451: ! 1452: idx++; ! 1453: ! 1454: if (offset == type_SNMP_SMUX__PDUs_get__next__request) { ! 1455: if ((oi = name2inst (v -> name)) == NULLOI ! 1456: && (oi = next2inst (v -> name)) == NULLOI) ! 1457: goto no_name; ! 1458: ! 1459: if ((ot = oi -> oi_type) -> ot_getfnx == NULLIFP) ! 1460: goto get_next; ! 1461: } ! 1462: else ! 1463: if ((oi = name2inst (v -> name)) == NULLOI ! 1464: || (ot = oi -> oi_type) -> ot_getfnx ! 1465: == NULLIFP) { ! 1466: no_name: ; ! 1467: pdu -> error__status = ! 1468: int_SNMP_error__status_noSuchName; ! 1469: ! 1470: ! 1471: ! 1472: ! 1473: ! 1474: M.T. Rose [Page 25] ! 1475: ! 1476: ! 1477: ! 1478: ! 1479: ! 1480: draft Exporting MIBs for BSD UNIX May 1990 ! 1481: ! 1482: ! 1483: goto out; ! 1484: } ! 1485: ! 1486: try_again: ; ! 1487: switch (ot -> ot_access) { ! 1488: case OT_NONE: ! 1489: if (offset == ! 1490: type_SNMP_SMUX__PDUs_get__next__request) ! 1491: goto get_next; ! 1492: goto no_name; ! 1493: ! 1494: case OT_RDONLY: ! 1495: if (offset == ! 1496: type_SNMP_SMUX__PDUs_set__request) { ! 1497: pdu -> error__status = ! 1498: int_SNMP_error__status_readOnly; ! 1499: goto out; ! 1500: } ! 1501: break; ! 1502: ! 1503: case OT_RDWRITE: ! 1504: break; ! 1505: } ! 1506: ! 1507: switch (status = (*ot -> ot_getfnx) (oi, v, offset)) { ! 1508: case NOTOK: /* get-next wants a bump */ ! 1509: get_next: ; ! 1510: oi = &ois; ! 1511: for (;;) { ! 1512: if ((ot = ot -> ot_next) == NULLOT) { ! 1513: pdu -> error__status = ! 1514: int_SNMP_error__status_noSuchName; ! 1515: goto out; ! 1516: } ! 1517: oi -> oi_name = ! 1518: (oi -> oi_type = ot) -> ot_name; ! 1519: if (ot -> ot_getfnx) ! 1520: goto try_again; ! 1521: } ! 1522: ! 1523: case int_SNMP_error__status_noError: ! 1524: break; ! 1525: ! 1526: default: ! 1527: pdu -> error__status = status; ! 1528: ! 1529: ! 1530: ! 1531: ! 1532: ! 1533: M.T. Rose [Page 26] ! 1534: ! 1535: ! 1536: ! 1537: ! 1538: ! 1539: draft Exporting MIBs for BSD UNIX May 1990 ! 1540: ! 1541: ! 1542: goto out; ! 1543: } ! 1544: } ! 1545: idx = 0; ! 1546: ! 1547: out: ; ! 1548: pdu -> error__index = idx; ! 1549: ! 1550: if (smux_response (pdu) == NOTOK) { ! 1551: error ("smux_response: %s [%s]", ! 1552: smux_error (smux_errno), smux_info); ! 1553: smux_fd = NOTOK; ! 1554: } ! 1555: } ! 1556: ! 1557: The actual code is fairly straight-forward: First, the ! 1558: variable quantum is set to the request ID for this ! 1559: transaction. The SMUX protocol requires that this number ! 1560: change for each SNMP operation that the SNMP agent fields, so ! 1561: your program can use it as a cookie to see when it should re- ! 1562: read kernel variables. (A single SNMP operation received by ! 1563: the SNMP agent might result in multiple SMUX protocol ! 1564: transactions with your program.) ! 1565: ! 1566: Next, the code loops through the list of variables requested. ! 1567: The object instance is determined and loaded into oin and the ! 1568: corresponding object type is loaded into ot, and the access is ! 1569: checked. ! 1570: ! 1571: Finally, the user-defined routine is invoked. This routine ! 1572: returns one of these values: ! 1573: ! 1574: NOTOK ! 1575: int_SNMP_error__status_noError ! 1576: int_SNMP_error__status_tooBig ! 1577: int_SNMP_error__status_noSuchName ! 1578: int_SNMP_error__status_badValue ! 1579: int_SNMP_error__status_readOnly ! 1580: int_SNMP_error__status_genErr ! 1581: ! 1582: the first value is returned only if the powerful get-next ! 1583: operator is being invoked and the routine didn't have any more ! 1584: object instances for the object type in question. The ! 1585: remainder are all self-explanatory. ! 1586: ! 1587: ! 1588: ! 1589: ! 1590: ! 1591: ! 1592: M.T. Rose [Page 27] ! 1593: ! 1594: ! 1595: ! 1596: ! 1597: ! 1598: draft Exporting MIBs for BSD UNIX May 1990 ! 1599: ! 1600: ! 1601: Once an answer is returned, the loop either continues or is ! 1602: broken and a response is written back using the smux_response ! 1603: routine. On failure, smux_error will be set to one of ! 1604: parameterMissing, invalidOperation, or youLoseBig. ! 1605: ! 1606: ! 1607: 7.3. Specific Event Handling: Outside a table ! 1608: ! 1609: Now let's look at one of these user-defined routines, which ! 1610: handles leaf objects that are not part of a table: ! 1611: ! 1612: static int lastq = -1; ! 1613: static struct mbstat mbstat; ! 1614: ! 1615: ! 1616: #define mbufS 0 ! 1617: #define mbufClusters 1 ! 1618: ... ! 1619: #define mbufFrees 6 ! 1620: ! 1621: ! 1622: static int o_mbuf (oi, v, offset) ! 1623: OI oi; ! 1624: register struct type_SNMP_VarBind *v; ! 1625: int offset; ! 1626: { ! 1627: int ifvar; ! 1628: register struct mbstat *m = &mbstat; ! 1629: register OID oid = oi -> oi_name; ! 1630: register OT ot = oi -> oi_type; ! 1631: ! 1632: ifvar = (int) ot -> ot_info; ! 1633: switch (offset) { ! 1634: case type_SNMP_SMUX__PDUs_get__request: ! 1635: if (oid -> oid_nelem != ! 1636: ot -> ot_name -> oid_nelem + 1 ! 1637: || oid -> oid_elements[oid -> oid_nelem - 1] ! 1638: != 0) ! 1639: return int_SNMP_error__status_noSuchName; ! 1640: break; ! 1641: ! 1642: case type_SNMP_SMUX__PDUs_get__next__request: ! 1643: if (oid -> oid_nelem ! 1644: == ot -> ot_name -> oid_nelem) { ! 1645: OID new; ! 1646: ! 1647: ! 1648: ! 1649: ! 1650: ! 1651: M.T. Rose [Page 28] ! 1652: ! 1653: ! 1654: ! 1655: ! 1656: ! 1657: draft Exporting MIBs for BSD UNIX May 1990 ! 1658: ! 1659: ! 1660: if ((new = oid_extend (oid, 1)) == NULLOID) ! 1661: return int_SNMP_error__status_genErr; ! 1662: new -> oid_elements[new -> oid_nelem - 1] = 0; ! 1663: ! 1664: if (v -> name) ! 1665: free_SNMP_ObjectName (v -> name); ! 1666: v -> name = new; ! 1667: } ! 1668: else ! 1669: return NOTOK; ! 1670: break; ! 1671: ! 1672: default: ! 1673: return int_SNMP_error__status_genErr; ! 1674: } ! 1675: ! 1676: if (quantum != lastq) { ! 1677: lastq = quantum; ! 1678: ! 1679: if (getkmem (nl + N_MBSTAT, (caddr_t) m, sizeof *m) ! 1680: == NOTOK) ! 1681: return int_SNMP_error__status_genErr; ! 1682: } ! 1683: ! 1684: switch (ifvar) { ! 1685: case mbufS: ! 1686: return o_integer (oi, v, m -> m_mbufs); ! 1687: ! 1688: case mbufClusters: ! 1689: return o_integer (oi, v, m -> m_clusters); ! 1690: ! 1691: ... ! 1692: ! 1693: case mbufFrees: ! 1694: return o_integer (oi, v, m -> m_mbfree); ! 1695: ! 1696: default: ! 1697: return int_SNMP_error__status_noSuchName; ! 1698: } ! 1699: } ! 1700: ! 1701: The actual code is fairly straight-forward: First, the ! 1702: constant offsets are defined. Then, the o_mbuf routine is ! 1703: defined. ! 1704: ! 1705: ! 1706: ! 1707: ! 1708: ! 1709: ! 1710: M.T. Rose [Page 29] ! 1711: ! 1712: ! 1713: ! 1714: ! 1715: ! 1716: draft Exporting MIBs for BSD UNIX May 1990 ! 1717: ! 1718: ! 1719: The first action is to determine which leaf object is being ! 1720: referenced. This corresponding symbolic constant is placed in ! 1721: the variable ifvar. Then a switch is made based on the ! 1722: operation. ! 1723: ! 1724: (1) For the get operation, all instances are identified by ! 1725: the object type followed by ".0" (e.g., "mbufS.0"). So, ! 1726: the code checks to see if the OID associated with the ! 1727: object instance is exactly one longer than the OID ! 1728: associated with the object type, and that the extra sub- ! 1729: identifier has the value 0. ! 1730: ! 1731: (2) For the powerful get-next operation, there are really two ! 1732: cases, depending on whether some instance identifier is ! 1733: present. If some instance identifier is present, then ! 1734: for a non-tabular leaf object, the next variable belongs ! 1735: to some other object type, so the routine simply returns ! 1736: the value NOTOK, and the get_smux routine will find the ! 1737: next object accordingly. Otherwise, if no instance is ! 1738: identified, a new OID is constructed and initialized. ! 1739: The old OID is free'd and the new one inserted in its ! 1740: place. ! 1741: ! 1742: Now that the correct instance has been identified, a check is ! 1743: made to see if kmem should be consulted. (Obviously other ! 1744: programs might consult other data stores.) Finally, the ! 1745: instance value is encoded and the routine returns. ! 1746: ! 1747: ! 1748: 7.3.1. Instance handling ! 1749: ! 1750: Several routines are provided to encode instance values: ! 1751: ! 1752: The o_number routine encodes an integer value, such as an ! 1753: INTEGER, Counter, Guage, or TimeTick. The macro o_integer is ! 1754: simply a synonym for o_number. ! 1755: ! 1756: The o_string routine encodes a string value, such as an ! 1757: OctetString or DisplayString, e.g., ! 1758: ! 1759: o_string (oi, v, "lo0", strlen ("lo0")); ! 1760: ! 1761: or ! 1762: ! 1763: o_string (oi, v, ether_addr, sizeof ether_addr); ! 1764: ! 1765: ! 1766: ! 1767: ! 1768: ! 1769: M.T. Rose [Page 30] ! 1770: ! 1771: ! 1772: ! 1773: ! 1774: ! 1775: draft Exporting MIBs for BSD UNIX May 1990 ! 1776: ! 1777: ! 1778: The o_specific routine takes a structure corresponding to a ! 1779: syntax, such as an OID for ObjectID, and does the encoding, ! 1780: e.g., ! 1781: ! 1782: OID nullSpecific = ...; ! 1783: ! 1784: o_specific (oi, v, nullSpecific); ! 1785: ! 1786: ! 1787: ! 1788: 7.3.2. A special case ! 1789: ! 1790: A special user-defined routine is provided for those cases for ! 1791: leaf-objects containing information that is initialized on ! 1792: start-up, o_generic. For example: ! 1793: ! 1794: char buffer[BUFSIZ]; ! 1795: ! 1796: if (ot = text2obj ("sysName")) ! 1797: ot -> ot_getfnx = o_generic, ! 1798: ot -> ot_info = (caddr_t) sysName; ! 1799: ! 1800: (void) gethostname (buffer, sizeof buffer); ! 1801: (void) (*ot -> ot_syntax -> os_parse) ! 1802: ((struct qbuf **) &ot -> ot_info, buffer); ! 1803: ! 1804: The idea is that the ot_info field contains a pointer to a ! 1805: data structure corresponding to the syntax of the object. ! 1806: Since all of the structures are rather strange (except for ! 1807: integers), o_generic probably won't receive a lot of use. ! 1808: ! 1809: ! 1810: 7.4. Specific Event Handling: Inside a table ! 1811: ! 1812: Now let's look at one of these user-defined routines, which ! 1813: handles leaf objects that are part of a table: ! 1814: ! 1815: #define mbufType 0 ! 1816: #define mbufAllocates 1 ! 1817: ! 1818: ! 1819: static int o_mbufType (oi, v, offset) ! 1820: OI oi; ! 1821: register struct type_SNMP_VarBind *v; ! 1822: int offset; ! 1823: ! 1824: ! 1825: ! 1826: ! 1827: ! 1828: M.T. Rose [Page 31] ! 1829: ! 1830: ! 1831: ! 1832: ! 1833: ! 1834: draft Exporting MIBs for BSD UNIX May 1990 ! 1835: ! 1836: ! 1837: { ! 1838: int ifnum, ! 1839: ifvar; ! 1840: register struct mbstat *m = &mbstat; ! 1841: register OID oid = oi -> oi_name; ! 1842: register OT ot = oi -> oi_type; ! 1843: ! 1844: ifvar = (int) ot -> ot_info; ! 1845: switch (offset) { ! 1846: case type_SNMP_SMUX__PDUs_get__request: ! 1847: if (oid -> oid_nelem ! 1848: != ot -> ot_name -> oid_nelem + 1) ! 1849: return int_SNMP_error__status_noSuchName; ! 1850: ifnum = ! 1851: oid -> oid_elements[oid -> oid_nelem - 1]; ! 1852: if (ifvar >= sizeof m -> m_mtypes / ! 1853: sizeof m -> m_mtypes[0]) ! 1854: return int_SNMP_error__status_noSuchName; ! 1855: break; ! 1856: ! 1857: case type_SNMP_SMUX__PDUs_get__next__request: ! 1858: if (oid -> oid_nelem ! 1859: == ot -> ot_name -> oid_nelem) { ! 1860: OID new; ! 1861: ! 1862: ifnum = 0; ! 1863: ! 1864: if ((new = oid_extend (oid, 1)) == NULLOID) ! 1865: return int_SNMP_error__status_genErr; ! 1866: new -> oid_elements[new -> oid_nelem - 1] = ! 1867: ifnum; ! 1868: ! 1869: if (v -> name) ! 1870: free_SNMP_ObjectName (v -> name); ! 1871: v -> name = new; ! 1872: } ! 1873: else { ! 1874: int i = ot -> ot_name -> oid_nelem; ! 1875: ! 1876: ifnum = oid -> oid_elements[i] + 1; ! 1877: if (ifnum >= sizeof m -> m_mtypes / ! 1878: sizeof m -> m_mtypes[0]) ! 1879: return NOTOK; ! 1880: ! 1881: oid -> oid_elements[i] = ifnum; ! 1882: ! 1883: ! 1884: ! 1885: ! 1886: ! 1887: M.T. Rose [Page 32] ! 1888: ! 1889: ! 1890: ! 1891: ! 1892: ! 1893: draft Exporting MIBs for BSD UNIX May 1990 ! 1894: ! 1895: ! 1896: oid -> oid_nelem = i + 1; ! 1897: } ! 1898: break; ! 1899: ! 1900: default: ! 1901: return int_SNMP_error__status_genErr; ! 1902: } ! 1903: ! 1904: if (quantum != lastq) { ! 1905: lastq = quantum; ! 1906: ! 1907: if (getkmem (nl + N_MBSTAT, (caddr_t) m, sizeof *m) ! 1908: == NOTOK) ! 1909: return int_SNMP_error__status_genErr; ! 1910: } ! 1911: ! 1912: switch (ifvar) { ! 1913: case mbufType: ! 1914: return o_integer (oi, v, ifnum); ! 1915: ! 1916: case mbufAllocates: ! 1917: return o_integer (oi, v, ! 1918: m -> m_mtypes[ifnum]); ! 1919: ! 1920: default: ! 1921: return int_SNMP_error__status_noSuchName; ! 1922: } ! 1923: } ! 1924: ! 1925: The actual code is fairly straight-forward: First, the ! 1926: constant offsets are defined. Then, the o_mbufType routine is ! 1927: defined. ! 1928: ! 1929: The first action is to determine which leaf object is being ! 1930: referenced. This corresponding symbolic constant is placed in ! 1931: the variable ifvar. Then a switch is made based on the ! 1932: operation. Because these are tabular objects, the instance ! 1933: refers to a row in the table (and the leaf object refers to a ! 1934: column in the table, of course). ! 1935: ! 1936: (1) For the get operation, all instances are identified by ! 1937: the object type followed by ".rowno" (e.g., ! 1938: "mbufAllocates.10") refers to the value in the ! 1939: mbufAllocates column of the thenth row). So, the code ! 1940: checks to see if the OID associated with the object ! 1941: ! 1942: ! 1943: ! 1944: ! 1945: ! 1946: M.T. Rose [Page 33] ! 1947: ! 1948: ! 1949: ! 1950: ! 1951: ! 1952: draft Exporting MIBs for BSD UNIX May 1990 ! 1953: ! 1954: ! 1955: instance is exactly one longer than the OID associated ! 1956: with the object type, and that the extra sub-identifier ! 1957: is within the range 0..rowno-1. ! 1958: ! 1959: (2) For the powerful get-next operation, there are really two ! 1960: cases, depending on whether some instance identifier is ! 1961: present. If no instance is identified, a new OID is ! 1962: constructed and initialized for the first row (row 0) of ! 1963: the table. The old OID is free'd and the new one inserted ! 1964: in its place. Otherwise, if some instance identifier is ! 1965: present, then the corresponding row must be identified, ! 1966: the row number incremented, and a check made to see if ! 1967: this is still in range (if not, NOTOK is returned to ! 1968: signal that the next object type should be used). ! 1969: Otherwise, the OID is updated in place. ! 1970: ! 1971: Now that the correct instance has been identified, a check is ! 1972: made to see if kmem should be consulted. (Obviously other ! 1973: programs might consult other data stores.) Finally, the ! 1974: instance value is encoded and the routine returns. ! 1975: ! 1976: ! 1977: 7.4.1. The general case ! 1978: ! 1979: Obviously, this is a simple example of table handling. In ! 1980: general, the table will be implemented via linked lists, ! 1981: sorted according to object instance. In this case, there is ! 1982: usually a special routine that is called to get a particular ! 1983: instance or the next instance. Take a look at the routines ! 1984: get_tbent and o_smuxTree in the file snmpd.c. These implement ! 1985: the smuxTree table. ! 1986: ! 1987: ! 1988: ! 1989: ! 1990: ! 1991: ! 1992: ! 1993: ! 1994: ! 1995: ! 1996: ! 1997: ! 1998: ! 1999: ! 2000: ! 2001: ! 2002: ! 2003: ! 2004: ! 2005: M.T. Rose [Page 34] ! 2006: ! 2007: ! 2008: ! 2009: ! 2010: ! 2011: draft Exporting MIBs for BSD UNIX May 1990 ! 2012: ! 2013: ! 2014: Table of Contents ! 2015: ! 2016: ! 2017: 1 Status of this Memo ................................... 1 ! 2018: 2 The Environment ....................................... 2 ! 2019: 2.1 The ISODE ........................................... 2 ! 2020: 3 MIB Modules ........................................... 3 ! 2021: 3.1 Compiling MIB modules ............................... 4 ! 2022: 3.1.1 The Syntax of compiled MIB modules ................ 5 ! 2023: 4 SMUX Peers ............................................ 6 ! 2024: 5 Daemon Skeleton ....................................... 7 ! 2025: 5.1 Declarations ........................................ 7 ! 2026: 5.2 Initialization ...................................... 8 ! 2027: 5.3 Reading the compiled MIB module ..................... 8 ! 2028: 5.4 Talking to the SNMP agent ........................... 9 ! 2029: 5.4.1 Initialization .................................... 10 ! 2030: 5.4.2 Opening ........................................... 10 ! 2031: 5.4.3 Closing ........................................... 11 ! 2032: 5.4.4 Registering Subtrees .............................. 11 ! 2033: 5.4.5 Main Loop ......................................... 12 ! 2034: 5.4.6 Events ............................................ 14 ! 2035: 6 Managed Objects ....................................... 17 ! 2036: 6.1 Syntax .............................................. 17 ! 2037: 6.1.1 Abstractions for Standard Syntaxes ................ 18 ! 2038: 6.1.1.1 integer ......................................... 18 ! 2039: 6.1.1.2 struct qbuf ..................................... 18 ! 2040: 6.1.1.3 struct OIDentifier .............................. 19 ! 2041: 6.1.1.4 struct sockaddr_in .............................. 20 ! 2042: 6.1.1.5 struct sockaddr_iso ............................. 20 ! 2043: 6.1.2 Defining a new Syntax ............................. 20 ! 2044: 6.2 Objects ............................................. 21 ! 2045: 6.3 Instances ........................................... 22 ! 2046: 7 Linkage ............................................... 24 ! 2047: 7.1 Initialization ...................................... 24 ! 2048: 7.2 Generic Event Handling .............................. 25 ! 2049: 7.3 Specific Event Handling: Outside a table ............ 28 ! 2050: 7.3.1 Instance handling ................................. 30 ! 2051: 7.3.2 A special case .................................... 31 ! 2052: 7.4 Specific Event Handling: Inside a table ............. 31 ! 2053: 7.4.1 The general case .................................. 34 ! 2054: ! 2055: ! 2056: ! 2057: ! 2058: ! 2059: ! 2060: ! 2061: ! 2062: ! 2063: ! 2064: M.T. Rose [Page 35] ! 2065:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.