MFD:ifTable:Get Data
MFD Tutorial | |
Contents
MFD : ifTable data GET
Once the correct table context has been found, the individual node get routines will be called. These are generated in the file ifTable_data_get.c.
Because we used the data context that is generated by default, we populated the data in the data structure during the data access phase and our MIB only has simple data types, the code which was generated for the get routines does not need much modification.
Implementing the get routines
There is, however, a case where the data format specified by the MIB does not match the data format we got from our datastore. The ifType enumerations need to be mapped from the Linux specific ARPHDR values. Here again, we haven't tried to provide a complete implementation, but enought to give you the an overview.
ifType mapping
The PhysAddr ioctl call provides us with an ARPHRD type for an interface. This type must be mapped to one of the valid IANAifType enumerated values. The file ifTable_enums.h contains macro definitions for all the allow values. It also contains a list of the same macros prefixed with 'INTERNAL_'. For the case where there is a one to one mapping between a MIB type and the implementation's type, this provides a way to map without having to update the code.
Unfortunately, the ifType isn't one of those cases. Only a small subset of the possible values are available in our implementation, and often there are several ARPHDR types that map to a single IANAifType. The first step is to whittle down the internal list to the ones with a direct mapping that we are going to support.
/* * TODO: * value mapping (see notes at top of file) */ #define INTERNAL_IANAIFTYPE_ETHERNETCSMACD ARPHRD_ETHER #define INTERNAL_IANAIFTYPE_FDDI ARPHRD_FDDI #define INTERNAL_IANAIFTYPE_PPP ARPHRD_PPP #define INTERNAL_IANAIFTYPE_SOFTWARELOOPBACK ARPHRD_LOOPBACK #define INTERNAL_IANAIFTYPE_SLIP ARPHRD_SLIP #define INTERNAL_IANAIFTYPE_ARCNET ARPHRD_ARCNET #ifdef ARPHRD_ATM #define INTERNAL_IANAIFTYPE_ATM ARPHRD_ATM #endif #define INTERNAL_IANAIFTYPE_LOCALTALK ARPHRD_LOCALTLK #ifdef ARPHRD_HIPPI #define INTERNAL_IANAIFTYPE_HIPPI ARPHRD_HIPPI #endif #define INTERNAL_IANAIFTYPE_TUNNEL ARPHRD_TUNNEL |
Then we update the implementation to remove all the extras, and use a default of 'other' for any unknown types.
int ifType_map(u_long * mib_ifType_val_ptr, u_long raw_ifType_val) { netsnmp_assert(NULL != mib_ifType_val_ptr); DEBUGMSGTL(("verbose:ifType_map", "called\n")); /* * TODO: * value mapping */ /** TODO: update INTERNAL_* macros defined in the header */ switch (raw_ifType_val) { case INTERNAL_IANAIFTYPE_ETHERNETCSMACD: (*mib_ifType_val_ptr) = IANAIFTYPE_ETHERNETCSMACD; break; case INTERNAL_IANAIFTYPE_TUNNEL: case ARPHRD_TUNNEL6: #ifdef ARPHRD_IPGRE case ARPHRD_IPGRE: #endif case ARPHRD_SIT: (*mib_ifType_val_ptr) = IANAIFTYPE_TUNNEL; break; /* tunnel */ case ARPHRD_CSLIP: case ARPHRD_SLIP6: case ARPHRD_CSLIP6: case INTERNAL_IANAIFTYPE_SLIP: (*mib_ifType_val_ptr) = IANAIFTYPE_SLIP; break; /* slip */ case INTERNAL_IANAIFTYPE_PPP: (*mib_ifType_val_ptr) = IANAIFTYPE_PPP; break; /* ppp */ case INTERNAL_IANAIFTYPE_SOFTWARELOOPBACK: (*mib_ifType_val_ptr) = IANAIFTYPE_SOFTWARELOOPBACK; break; /* softwareLoopback */ case INTERNAL_IANAIFTYPE_FDDI: (*mib_ifType_val_ptr) = IANAIFTYPE_FDDI; break; case INTERNAL_IANAIFTYPE_ARCNET: (*mib_ifType_val_ptr) = IANAIFTYPE_ARCNET; break; case INTERNAL_IANAIFTYPE_LOCALTALK: (*mib_ifType_val_ptr) = IANAIFTYPE_LOCALTALK; break; #ifdef INTERNAL_IANAIFTYPE_HIPPI case INTERNAL_IANAIFTYPE_HIPPI: (*mib_ifType_val_ptr) = IANAIFTYPE_HIPPI; break; #endif #ifdef INTERNAL_IANAIFTYPE_ATM case INTERNAL_IANAIFTYPE_ATM: (*mib_ifType_val_ptr) = IANAIFTYPE_ATM; break; #endif /* * XXX: more if_arp.h:ARPHDR_xxx to IANAifType mappings... */ default: snmp_log(LOG_ERR, "couldn't map value %d for ifType\n", raw_ifType_val); (*mib_ifType_val_ptr) = IANAIFTYPE_OTHER; } return MFD_SUCCESS; } |
Unimplemented columns
As mentioned before, we are leaving some colums unimplemented. There are several reasons a column might be left unimplemnted. The data may not be available, or a particular column might not make sense for an implementation.
We omitted some columns from the valid columns structure, because we don't want to provide data for those columns, ever. If you have columns that might have data, depending on the row, then those columns should be in the valid columns structure. When the column get routine is called for a row which had not data for the column, simply return MFD_SKIP from the object's get routine, and the agent will move on to the next object.
You should also consult your MIB to see if, for a particular column for which you don't have data, a special value is specified which should be returned when the data isn't available. For example, the ifPhysAddress object states: For interfaces which do not have such an address (e.g., a serial line), this object should contain an octet string of zero length.
Skipping ifMtu
Even though we've eliminated some columns from the valid columns, here is a simple example if skipping a column:
int ifMtu_get(ifTable_rowreq_ctx * rowreq_ctx, long *ifMtu_ptr) { /** we should have a non-NULL pointer */ netsnmp_assert(NULL != ifMtu_ptr); netsnmp_assert(NULL != rowreq_ctx); /* * TODO: * set (* ifMtu_ptr ) from rowreq_ctx->data. */ /* * TODO: * update, replace or delete, if needed. */ if (rowreq_ctx->data.ifMtu == 0) return MFD_SKIP; (*ifMtu_ptr) = rowreq_ctx->data.ifMtu; return MFD_SUCCESS; } |