Andy presents an IEEE 802.5 MAC-layer token-ring network-management application consisting of a Windows front end and a network-management agent on the back end. This tool lets you list active token-ring adapters on the ring, associate descriptive names with token-ring adapters, identify soft errors and the fault domain, monitor the network status, and more.
February 01, 1994
URL:http://www.drdobbs.com/architecture-and-design/your-own-token-ring-network-manager/184409182
Copyright © 1994, Dr. Dobb's Journal
Copyright © 1994, Dr. Dobb's Journal
Copyright © 1994, Dr. Dobb's Journal
Copyright © 1994, Dr. Dobb's Journal
Andy is a software engineer in Sydney, Australia and specializes in automation and system management. Andy can be reached through the DDJ offices.
When a local area network (LAN) has problems, the first troubleshooting tool you usually reach for is either Novell's LANalyzer or Network General's Sniffer. While both are useful for analyzing large networks interconnected with routers and gateways, there's a class of token-ring network problems that can be solved using the IEEE 802.5 built-in network-management functions. These functions include gathering the network-configuration data, detecting marginally operating token-ring cards and cabling systems, and contending with other physical network problems.
In this article, I present a token-ring network-management application consisting of a Windows front end called TRMGR and a network-management agent called TRAGN. Among other things, this tool lets you list all the active token-ring adapters on the ring, associate descriptive names with token-ring adapters, identify soft errors and the fault domain, monitor the network status, record the fault domain when a fault or hard error (beaconing) occurs, and remove a token-ring adapter from the ring. I've tested TRAGN and TRMGR on a 33-MHz 386 with the IBM 4/16 token-ring adapter, DXMA0MOD.SYS/DXMC0MOD.SYS drivers, and the Novell IPX/NETX LAN requester.
The IEEE 802.5 Token Ring Access Method Standard defines both the physical layer and the medium access control (MAC) layer. The physical layer defines physical properties such as data-symbol encoding, decoding, and timing. The MAC layer defines the control and mediation on ring access and station management.
The 802.5 standard defines a set of data collection and distribution points, called "servers," to collect reports from other network stations. You use these servers to manage the stations. The configuration-report server (CRS) collects information on station-configuration changes due to insertion or removal of stations, and removes stations on the ring according to the manager's request. The ring-error monitor (REM) gathers and analyzes both hard- and soft-error reports sent by stations on a ring and assists in fault isolation and correction. Finally, the ring-parameter server (RPS) provides a set of operating parameters to stations during the insertion process.
Any token-ring station can declare itself to be a CRS, REM, or RPS by setting the functional address, a set of locally administered group addresses; see Table 1(a). Functional addresses are analogous to TCP/IP sockets, in which a particular socket number identifies the application. A station can declare itself to be both a CRS and an REM simply by logically ORing their addresses together: X'00000018', for example.
Stations send reports to the servers via MAC frames; see Figure 1. The information field in a frame consists of a vector (the fundamental unit of information) that contains a length field, a function-identifier field, and zero or more subvectors. Only one vector is allowed in a MAC frame. Figure 2 shows the MAC information-field structure. There are 23 vectors and 21 subvectors defined by the IEEE 802.5 standard. Luckily, we only need the vectors and subvectors in Table 2 to implement the token-ring network manager.
The most-significant byte of the vector identifier contains the destination class (high nybble) and source class (low nybble). The least-significant byte contains the vector code. The class information provides a means to route the frame to the appropriate management function. Table 1(b) lists the function classes. For example, the report-error vector X'6029' means that the frame is sent by a ring station (source class X'0') to REM (destination class X'6'), and the vector code is X'29' (report error).
The BCN (beaconing) vector is sent by a station which detects a beaconing condition. It contains the UNA subvector and the BCN type subvector. The reporting station and its nearest active upstream neighbor (NAUN) constitute the fault domain.
The AMP, SMP, and Report SUA Change vectors all contain the UNA subvector, which can be used to find out which stations are active on the ring. The AMP MAC frame is normally generated every three seconds by the active monitor. SMP frames are then sent by standby monitors to complete the neighbor-notification process.
The report-error vector contains the isolating error count, nonisolating error count, and UNA subvectors. These subvectors provide information on the type and number of soft errors which have occurred on the ring. Together, the source address of the MAC frame and the UNA subvector define the fault domain.
The remove-ring-stations vector is used to remove a ring station from the ring. It doesn't contain subvectors.
TRMGR gets information about the network from TRAGN and presents it to you. TRMGR also requests the agent to carry out any action in the management of the network. The agent is simply a real-mode DOS program started before Windows that performs all the token-ring API calls for the Windows front end.
TRMGR and TRAGN communicate via a software interrupt in exactly the same way that DOS does with INT 21h. I arbitrarily chose an unused software interrupt, INT 78h, as the agent service interrupt. True, the Windows front end still requires the DPMI interface to invoke a real-mode interrupt, but this is easier than doing everything via DPMI.
TRMSG.H (Listing One, page 84) shows the message structure. There are ten messages--five requests and five data responses. TRMGR actively polls TRAGN by sending it any of the five supported request messages. Table 3 lists the request messages, while Table 4 lists the messages sent by TRAGN in response to TRMGR's MSG_REQUEST_MSG request.
TRMGR is written in C and C++. I used Zortech C++ 3.0 for development and Gpf (from GPF Systems, Moodus, CT) for the user interface. Gpf, a visual tool for generating GUI apps, functions much like Visual C++'s AppStudio and AppWizard except that it generates C, not C++, code. I used the OS/2-hosted Version 1.3 of Gpf, which has code generators for 16- and 32-bit OS/2 and 16-bit Windows.
I used the Gpf editor to design TRMGR's GUI and the Gpf code generator to generate a skeleton program which handles the Windows GUI. I actually use Gpf only as an event dispatcher, so that when certain events (double clicking, selecting a menu item, and the like) occur, it passes control to one of my functions. The events handled by my functions are shown in Table 5. TRMGR source files include TRMGR.H, TRMGR.C (Gpf-generated Windows GUI skeleton), TRMGR.EXT (Gpf-generated header file), TRMGR.IDS (Gpf-generated resource identifiers), TRMGR.RC (Gpf-generated resource file), TRFNS.H, TRFNS.C (functions to handle all Windows events that TRMGR is interested in), TRSMT.H, TRSMT.CPP (the only C++ module, which provides services to TRFNS.C and accesses TRAGN via TRMSG for LAN management), TRMSG.H, and TRMSG.C (message layer which interfaces to TRAGN via DPMI). All of these files, along with executables, are available electronically; see "Availability," page 3.
TRSMT and TRMSG constitute the network-management part of the GUI front end. TRSMT is written in C++ because I wanted to use the C++ hashed search-table classes zHashTable and zGHSearch that come with the Zortech compiler. A hash table is used to implement a database within TRSMT to record information about token-ring stations (adapters), soft errors, and faults. The information recorded (defined in the structure AdapterEntry in TRSMT.C) includes the adapter's address and symbolic name, soft-error counts, beacon type, and occurrence time of soft error and fault. The structure members pNaun and pNext link the information regarding adapters, soft errors, and faults into separate linked-list structures. Figures 3 and 4 show how these linked lists work. The entries in these figures are labeled Entry 1, 2, 3, and so on, to identify the entry in the discussion. They don't represent the relative position in the database because, in a hash-table implementation, the entries are bound to scatter within the hash table.
pRingHead always points to the TRMGR adapter entry. Only the pNaun fields of the entries are used to form a linked list. By going through this linked list, you can find out which stations are active on the ring. In Figure 3, the ring configuration in network order is: entry 1, 2, 5, 6, and 4. The adapter at entry 3 is not active on the ring.
The soft-error and fault linked lists are formed differently from the configuration linked list. In the soft-error list, pHead points to an entry in the database, say, entry 1. The pNext fields are used to link all the adapters which have reported errors. For each adapter, pNaun points to its NAUN. As you may recall, the reporting adapter, its NAUN, and the medium between them constitute the fault domain. The time at which the soft errors occurred can also be found in the adapter entry. In Figure 4, soft errors have occurred in fault domains which consist of adapters pairs (1, 2), (3, 4), (4, 5), and (5, 2).
A hash table is used because all reports or data messages have the adapter field set. Adapter addresses are unique, making them good keys for locating an item quickly in a database. Remember that each MSG_DATA_CONFIG message has information only on the reporting adapter and its NAUN, and it takes several reports to figure out who is on the ring. Since these reports are started by the AMP MAC frame every three seconds, we must locate the database entry for each adapter quickly. A hash table allows just that. Basically, TRSMT provides TRFNS access to this database for displaying the network information.
TRSMT also provides TRFNS with the Poll function, which is called whenever Windows is idle; that is, it is called within the PeekMessage loop, which replaces the standard Windows GetMessage loop in TRMGR.C. Poll keeps sending MSG_REQUEST_DATA to TRAGN to solicit network reports until either TRAGN says there isn't any more report (by returning a ERR_NO_DATA return code) or Poll has processed the maximum number of messages in a row. In either case, Poll returns control to PeekMessageLoop and gives up the CPU so that other Windows applications can run. If any report is returned from TRAGN, Poll processes it and updates the database.
All database information items, except for adapter addresses and their symbolic names saved in the text file TRMGR.CFG, are discarded when you terminate TRMGR. The TRMGR.CFG file is read by PeekMessageLoop at startup time such that names associated with adapters in a previous TRMGR session are maintained.
TRMSG.C is the module which interfaces between TRSMT and TRAGN. Since Windows is running in protected mode, TRMsg uses DPMI to invoke the TRAGN's functions. It passes the message identifier msg in the EAX register and simulates a real-mode interrupt using the Zortech dpmi_SimRealModeInterrupt function (INT 31h function 300h). The first time this function is called, it only passes msg to TRAGN and not the whole message. (MSG_REQUEST_ACTIVATE should always be the first message sent to TRAGN.) Upon returning from the interrupt, the address to a block of DOS memory which holds the message structure is returned in the EDX:EAX register pair. TRMsg converts the real-mode SEG:OFFSET address into a protected-mode SELECTOR:OFFSET pointer using dpmi_SegToDescriptor (INT 31h function 0002h) and saves it for all future use. From then on, all message exchanges use this memory block. If TRMGR were a real-mode app, I would have passed the message pointer from TRMGR to TRMSG, instead of the other way around. In Windows protected mode, however, I couldn't allocate DOS memory using DPMI. Hence, I let TRAGN provide the memory block for communication. When a MSG_REQUEST_INACTIVATE message is encountered, TRmsg frees the descriptor by calling dpmi_FreeDescriptor (INT 31h function 0001h).
The advantage of this message-based architecture is that I can go on to program the Windows front end before writing any code for the network-management agent. The UI can be tested simply by faking message exchanges. In this project, I wrote the entire UI before the agent. It is almost plug-and-play when the agent is ready. Under Windows, you can allocate DOS memory using the Windows GlobalDosAlloc, which returns both a DOS segment and a protected-mode selector. I chose not to use it because I wanted to isolate all Windows-related code to TRFNS.C. In retrospect, this isn't really necessary, and using GlobalDosAlloc may prove even more convenient.
To implement TRAGN, I started with the programs on the diskette that comes with IBM's Technical Reference: Token-ring Network PC Adapter manual, although I eventually wrote my own version of the API headers. Overall, the TRAGN program consists of: DLCCONST.H, DLCPTBLS.H (token-ring API constants and structures); TRAGN.C (source file for the network-management agent; TRUTL.H, TRUTL.C (a set of utility functions); TRDIR.H, TRDIR.C (a set of functions to access the token-ring API's direct interface); TRAPP.H, TRAPP.ASM (assembly program to setup API appendages); and TRMSG.H (message definitions). All of these files are available electronically.
TRAGN handles all message exchanges with TRMGR and carries out TRMGR's requests: activating the token-ring adapter, removing a station, reporting on soft errors and faults, and the like. It interfaces to the token-ring API via TRDIR.
When run, TRAGN first checks to see if token-ring API support has been installed. If not, TRAGN terminates with an error message. In general, all applications using the token-ring API should check for its availability by checking if the token-ring API support INT 5Ch interrupt vector has been set, and if so, whether it actually is the token-ring API support. TRAGN then installs an interrupt handler for INT 78h (chosen arbitrarily), which is used for message exchange with TRMGR, and sets up the data received and ring-status appendages by calling appinit in TRAPP.ASM. TRAGN then terminates and stays resident.
The Zortech compiler comes with a TSR package to facilitate writing TSRs. However, it's only available in the small memory model and programming the token-ring API is easier using the large model. The 8086 assembly-language module TRAPP.ASM installs interrupt handlers and handle appendages because the Zortech compiler doesn't support the interrupt keyword like the Microsoft compiler. Again, Zortech provides an interrupt package, but I couldn't get it to work in the large memory model.
When TRMGR requests activation of the token-ring adapter via INT 78H, TRAGN will go through the following steps:
When TRMGR requests deactivation of the token-ring interface, TRAGN simply calls receive_cancel to cancel the receive command. It does not actually close the adapter. When TRMGR requests the removal of an adapter, TRAGN builds a MAC frame and sends it via dir_transmit.
With the IEEE 802.5 network-management tool presented here, you can begin snooping around your LAN, discovering and fixing potential problems. However, you should be aware of some of this application's limitations. For instance, 802.5 MAC frames don't normally go through a bridge from one LAN segment to another. Consequently, TRMGR can only troubleshoot the LAN on which it is connected. Nor can TRMGR analyze the traffic load. (Use Sniffer or LANalyzer along with specially modified token-ring cards for this.)
TRMGR may be confused when the TRMGR adapter gets removed, but its token-ring adapter driver automatically resets it. For example, in the Novell environment where the IPX/NETX LAN requester has such a "feature," TRMGR works much more reliably if the LAN requester is not activated. Finally, although a station may use up to two token-ring adapters, TRMGR supports only the primary token-ring adapter.
(a) Functional Function Name Address ----------------------------------- Active Monitor X'00000001' CRS X'00000010' REM X'00000008' RPS X'00000002' (b) Function Class Value --------------------------- Ring Station X'0' CRS X'4' RPS X'5' REM X'6'
(a) Vector Vector Name Identifier -------------------------------------- BCN (beacon) X'0002' Active monitor present X'0005' Stand-by monitor present X'0006' Remove ring stations* X'0408' Report SUA change X'4026' Report error X'6029' (b) Subvector Subvector Subvector Subvector Name Identifier Length Value -------------------------------------------------------------------------- BCN Type X'01' 4 2-byte beacon type Upstream neighbor's X'02' 8 6-byte node address address Isolating error count X'2D' 8 Five 1-byte error counters and one byte reserved Nonisolating error X'2E' 8 Five 1-byte error counters count and one byte reserved
Message Description ------------------------------------------------------------------- MSG_REQUEST_ACTIVATE This is the first message the TRMGR sends to TRAGN. It requests TRAGN to prepare the token-ring adapter and establish itself as both REM and CRS so that it can receive management reports. No other parameter in the message structure is required. On return, the message member adapter contains the token-ring node address of the TRMGR station. MSG_REQUEST_MSG TRMGR uses this to get management reports from TRAGN. On return, the msg and information fields will be changed to the appropriate message type and report, respectively, if there is any report available. If no report is available, retcode will be set to ERR_NO_DATA. MSG_REQUEST_RESET TRMGR uses this to reset the adapter on which TRMGR is running. Necessary if TRMGR adapter gets removed automatically as a result of fault isolation or by another station running TRMGR or another network manager. MSG_REQUEST_REMOVE The only active network-management facility in TRMGR. The adapter field contains the address of the ring station to be removed. TRMGR uses this message to remove a station from the ring if the administrator has determined that a station is causing performance problem by generating many soft or hard errors. MSG_REQUEST_INACTIVATE TRMGR sends this to TRAGN before it terminates to tell TRAGN it can stop gathering management reports.
Message Description -------------------------------------------------------------------- MSG_DATA_ERROR Fields adapter and naun contain the fault domain. isoerr and noniso contain the soft-error counts. MSG_DATA_INDICATION Field ringstatus contains current status of the ring. Generated only when there is a change in ring status. MSG_DATA_CONFIG Field adapter contains reporting-station address; naun contains its neighbor's address. Collecting this report for all stations on the ring allows the ring's overall configuration to be determined. MSG_DATA_BEACON Fields adapter and naun make up the fault domain, and beacontype contains the beacon type. MSG_HOUSEKEEPING For TRAGN's internal use only. Used for release of MAC-layer buffers. Not included in original design--added later due to certain limitations of the DOS token-ring API.
Function Event Window/Control ------------------------------------------------------------ ChangeName BN_CLICKED Config/ChangeName button FillAdapters WM_INITDIALOG Config FillErrors WM_INITDIALOG Errors FillFaults WM_INITDIALOG Faults PaintMain WM_PAINT Main QuitTRMGR WM_CLOSE Main RecordAdapter LBN_DBCLK Config/Errors/Faults list box ResetAll BN_CLICKED Config/Reset button ResetErrors BN_CLICKED Errors/Clear button ResetFaults BN_CLICKED Faults/Clear button SelectAdapter LBN_SELCHANGE Config list box SetOption BN_CLICKED Display menu: dynamic, static ShowDetails LBN_DBCLK Config/Errors/Faults list box
------------------------------------------------------ | SD | AC | FC | DA | SA | RI | INFO | FCS | ED | FS | ------------------------------------------------------ SD Starting Delimiter (1 byte) AC Access Control (1 byte) FC Frame Control DA Destination Address (6 bytes) SA Source Address (6 bytes) RI Routing Information (0--18 bytes) INFO Information (0 or more bytes) FCS Frame Check Sequence (4 bytes) ED Ending Delimiter (1 byte) FS Frame Status (1 byte)
----------------------------------------------------- | VL | VI | SVL | SVI | SVV | ... | SVL | SVI | SVV | ----------------------------------------------------- VL Vector Length (2 bytes) VI Vector Identifier (2 bytes) SVL Subvector Length (1 byte) SVI Subvector Identifier (1 byte) SVV Subvector Value (n bytes)
#ifndef __TRMSG #define __TRMSG //#include "trdir.h" #ifndef DLCPTBLS typedef unsigned char BYTE; typedef unsigned int WORD; typedef unsigned long DWORD; typedef unsigned char *ADDRESS; #endif #define SERVINT 0x78 /* lower half to upper half messages */ #define MSG_HOUSEKEEPING 0 #define MSG_DATA_ERROR 1 #define MSG_DATA_INDICATION 2 #define MSG_DATA_BEACON 3 #define MSG_DATA_CONFIG 4 /* upper half to lower half messages */ #define MSG_REQUEST_MSG 5 #define MSG_REQUEST_RESET 6 #define MSG_REQUEST_REMOVE 7 #define MSG_REQUEST_ACTIVATE 8 #define MSG_REQUEST_INACTIVATE 9 #define MAXMSGS 9 /* error return codes */ #define ERR_OK 0 #define ERR_INVALID_MSG 1 #define ERR_FAILURE 2 #define ERR_NO_DATA 3 /* ring status constants */ #define STS_SIGNALLOSS 0x8000 #define STS_HARDERROR 0x4000 #define STS_SOFTERROR 0x2000 #define STS_XMITBEACON 0x1000 #define STS_WIREFAULT 0x0800 #define STS_REMOVAL1 0x0400 #define STS_REMOVERECVD 0x0100 #define STS_CNTOVERFLOWED 0x0080 #define STS_SINGLESTN 0x0040 #define STS_RECOVERY 0x0020 /* definition all all messages for communicating with the upper half */ typedef struct node{ struct node *next; //points to the next message ADDRESS buffer_one; //DLC buffer address WORD msg; //message type BYTE retcode; //return code BYTE dir_retcode; //direct interface return code BYTE more; //number of messages still queued BYTE beacontype; //becaon type WORD ringstatus; //ring status BYTE adapter[6]; //reporting adapter's address BYTE naun[6]; //and its neighbour BYTE isoerr[5]; //isolating error counts BYTE noniso[5]; //non-isolating error counts } Msgs; #if __cplusplus extern "C" { #endif int TRMsg(Msgs *msg); void TRPrintMsg(Msgs *msg); #if __cplusplus } #endif #endif End Listing
Copyright © 1994, Dr. Dobb's Journal
Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.