Mailing List Archive

patch for ospfd - improved snmp functionality
Hi,

I presume that quagg-dev is the place to post patches, so here goes...

In an attempt to address a number of limitations in the snmp functionality
of the ospf demon I have produced this patch (against 0.96.2).

Specifically:
An 'snmpwalk' through the ospf mib fails to return any OIDs in the
ospfIfTable and the ospfIfMetricTable.
The metric returned for an interface is the default value, not the current
value, and it cannot be set.
Accessing data for a point-to-point interface, where quagga references the
destination address, appears impossible.

The patch below alters the behaviour of ospfIfLookup and ospfIfMetricLookup
on receipt of an inexact OID from smux. This is the case when the MIB is
walked using getnext. The change helps to ensure that interface tables in
the MIB are traversed correctly.
It also provides a write method for the interface metric and returns the
currently set metric.
Finally it enables access to point-to-point interface data by using the
(more conventional) local interface address value.

Comments welcome.

David

PS why does quagga/zebra use the destination address on point to point links
in the ospf network statement?

===================================================

diff -NaurbB quagga-0.96.2-clean/ospfd/ospf_snmp.c
quagga-0.96.2-mod/ospfd/ospf_snmp.c
--- quagga-0.96.2-clean/ospfd/ospf_snmp.c Thu Jun 19 02:21:07 2003
+++ quagga-0.96.2-mod/ospfd/ospf_snmp.c Wed Sep 17 09:56:31 2003
@@ -1440,9 +1440,6 @@
/* Lookup first IPv4 address entry. */
LIST_LOOP (ifp->connected, ifc, nn)
{
- if (ifc_pointopoint (ifc))
- p = ifc->destination;
- else
p = ifc->address;

if (p->family == AF_INET)
@@ -1585,21 +1582,30 @@
else
{
len = *length - v->namelen;
+
+ if (len < IN_ADDR_SIZE)
+ {
+ ifaddr_next = 1;
+ ifindex_next = 1;
+ }
+ // if len > internet address then truncate to the correct size
+ // and use the specified address.
if (len >= IN_ADDR_SIZE)
+ {
len = IN_ADDR_SIZE;
- if (len <= 0)
- ifaddr_next = 1;
-
+ // get the address if one exists
oid2in_addr (name + v->namelen, len, ifaddr);
-
+ // now check for an index
len = *length - v->namelen - IN_ADDR_SIZE;
if (len >= 1)
- len = 1;
+ {
+ *ifindex = name[v->namelen + IN_ADDR_SIZE];
+ }
else
+ {
ifindex_next = 1;
-
- if (len == 1)
- *ifindex = name[v->namelen + IN_ADDR_SIZE];
+ }
+ }

ifp = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next,
ifindex_next);
@@ -1623,7 +1629,7 @@
struct interface *ifp;
unsigned int ifindex;
struct in_addr ifaddr;
- struct ospf_interface *oi;
+ struct ospf_interface *oi = NULL;
struct ospf *ospf;

ifindex = 0;
@@ -1634,6 +1640,8 @@
if (ospf == NULL)
return NULL;

+ if (exact)
+ {
ifp = ospfIfLookup (v, name, length, &ifaddr, &ifindex, exact);
if (ifp == NULL)
return NULL;
@@ -1641,6 +1648,18 @@
oi = ospf_if_lookup_by_local_addr (ospf, ifp, ifaddr);
if (oi == NULL)
return NULL;
+ }
+ else
+ {
+ while (oi == NULL)
+ {
+ ifp = ospfIfLookup (v, name, length, &ifaddr, &ifindex, exact);
+ if (ifp == NULL)
+ return NULL;
+ else
+ oi = ospf_if_lookup_by_local_addr (ospf, ifp, ifaddr);
+ }
+ }

/* Return the current value of the variable */
switch (v->magic)
@@ -1755,21 +1774,30 @@
else
{
len = *length - v->namelen;
+
+ if (len < IN_ADDR_SIZE)
+ {
+ ifaddr_next = 1;
+ ifindex_next = 1;
+ }
+ // if len > internet address then truncate to the correct size
+ // and use the specified address.
if (len >= IN_ADDR_SIZE)
+ {
len = IN_ADDR_SIZE;
- else
- ifaddr_next = 1;
-
+ // get the address if one exists
oid2in_addr (name + v->namelen, len, ifaddr);
-
+ // now check for an index
len = *length - v->namelen - IN_ADDR_SIZE;
if (len >= 1)
- len = 1;
+ {
+ *ifindex = name[v->namelen + IN_ADDR_SIZE];
+ }
else
+ {
ifindex_next = 1;
-
- if (len == 1)
- *ifindex = name[v->namelen + IN_ADDR_SIZE];
+ }
+ }

ifp = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next,
ifindex_next);
@@ -1788,6 +1816,67 @@
return NULL;
}

+int
+ospfIfMetricWrite (int action, u_char *val, u_char val_type, size_t
var_len,
+ u_char *StatP, oid *name, size_t length, struct variable *v)
+
+{
+ struct interface *ifp;
+ unsigned int ifindex;
+ struct in_addr ifaddr;
+ struct ospf_interface *oi = NULL;
+ struct ospf_if_params *params;
+ struct ospf *ospf;
+
+ zlog_info ("Zebra:ospfIfWrite called");
+
+ /* Check OSPF instance. */
+ ospf = ospf_lookup ();
+ if (ospf == NULL)
+ return SNMP_ERR_RESOURCEUNAVAILABLE;
+
+ ifindex = 0;
+ memset (&ifaddr, 0, sizeof (struct in_addr));
+
+ ifp = ospfIfMetricLookup (v, name, &length, &ifaddr, &ifindex, 1);
+ if (ifp == NULL)
+ return SNMP_ERR_RESOURCEUNAVAILABLE;
+
+ oi = ospf_if_lookup_by_local_addr (ospf, ifp, ifaddr);
+ if (oi == NULL)
+ return SNMP_ERR_RESOURCEUNAVAILABLE;
+
+ params = IF_DEF_PARAMS (ifp);
+
+ if (val_type != ASN_INTEGER)
+ return SNMP_ERR_WRONGTYPE;
+
+ if (var_len != sizeof (long))
+ return SNMP_ERR_WRONGLENGTH;
+
+ if (action == COMMIT)
+ {
+ // go for write
+ u_long writeval = 0;
+ switch (v->magic)
+ {
+ case OSPFIFMETRICVALUE:
+ if (asn_parse_unsigned_int(val,&var_len,&val_type,&writeval,sizeof
(long)) == NULL)
+ return SNMP_ERR_WRONGENCODING;
+
+ SET_IF_PARAM (params, output_cost_cmd);
+ params->output_cost_cmd = writeval;
+ ospf_if_recalculate_output_cost (ifp);
+ break;
+ case OSPFIFMETRICSTATUS:
+ // No variable to write - so return
+ return SNMP_ERR_NOTWRITABLE;
+ break;
+ }
+ }
+ return SNMP_ERR_NOERROR;
+}
+
static u_char *
ospfIfMetricEntry (struct variable *v, oid *name, size_t *length, int
exact,
size_t *var_len, WriteMethod **write_method)
@@ -1796,7 +1885,7 @@
struct interface *ifp;
unsigned int ifindex;
struct in_addr ifaddr;
- struct ospf_interface *oi;
+ struct ospf_interface *oi = NULL;
struct ospf *ospf;

ifindex = 0;
@@ -1807,6 +1896,8 @@
if (ospf == NULL)
return NULL;

+ if (exact)
+ {
ifp = ospfIfMetricLookup (v, name, length, &ifaddr, &ifindex, exact);
if (ifp == NULL)
return NULL;
@@ -1814,6 +1904,18 @@
oi = ospf_if_lookup_by_local_addr (ospf, ifp, ifaddr);
if (oi == NULL)
return NULL;
+ }
+ else
+ {
+ while (oi == NULL)
+ {
+ ifp = ospfIfMetricLookup (v, name, length, &ifaddr, &ifindex, exact);
+ if (ifp == NULL)
+ return NULL;
+ else
+ oi = ospf_if_lookup_by_local_addr (ospf, ifp, ifaddr);
+ }
+ }

/* Return the current value of the variable */
switch (v->magic)
@@ -1828,9 +1930,11 @@
return SNMP_INTEGER (0);
break;
case OSPFIFMETRICVALUE:
- return SNMP_INTEGER (OSPF_SNMP_METRIC_VALUE);
+ *write_method = &ospfIfMetricWrite;
+ return SNMP_INTEGER (oi->output_cost);
break;
case OSPFIFMETRICSTATUS:
+ *write_method = &ospfIfMetricWrite;
return SNMP_INTEGER (1);
break;
default: