Friday, January 19, 2007
Don't think this'll happen any time in the near future.
Five years later and the weather hasn't changed as much as it has in 30 years.
Go figure.
A quick note on embedding languages within languages
While I don't fully agree with this article (link via ThoughtStorms, and more on this in a later entry) I do agree that our current methods of programming do fall short (design patterns being silly). This was made plainly apparent today at The Office.
I have this program called ospfquery
that not only retrieves
OSPF specific SNMP data, but can also
dump a routing table from a router.
Dest Mask NextHop Proto Metric Age ------------------------------------------------------------------------------- 169.254.0.0 255.255.0.0 XXXXXXXXXX.5 ospf 1 334866 172.16.0.0 255.240.0.0 XXXXXXXXXX.5 ospf 1 334866 192.0.2.0 255.255.255.0 XXXXXXXXXX.5 ospf 1 334866 192.168.0.0 255.255.0.0 XXXXXXXXXX.5 ospf 1 334866 198.18.0.0 255.254.0.0 XXXXXXXXXX.5 ospf 1 334866
But it doesn't quite work with Riverstones:
Dest Mask NextHop Proto Metric Age ------------------------------------------------------------------------------- 1.0.0.0 32.161.7.0 26.127.177.69 ??? 159791312426295
It's clear that the Riverstone doesn't support the right SNMP MIBs that
ospfquery
uses to retrieve the routing table. But by dumping
the entire SNMP tree, I was able to find equivalents.
Cisco | Riverstone |
---|---|
RFC1213-MIB::ipRouteDest | IP-MIB::ip.24.4.1.1 |
RFC1213-MIB::ipRouteMask | IP-MIB::ip.24.4.1.2 |
RFC1213-MIB::ipRouteNextHop | IP-MIB::ip.24.4.1.4 |
RFC1213-MIB::ipRouteProto | IP-MIB::ip.24.4.1.7 |
RFC1213-MIB::ipRouteAge | IP-MIB::ip.24.4.1.8 |
RFC1213-MIB::ipRouteMetric1 | IP-MIB::ip.24.4.1.11 |
RFC1213-MIB::ipRouteType | IP-MIB::ip.24.4.1.6 |
So, on to the code:
oid objid_ipRouteDest[] = {1, 3, 6, 1, 2, 1, 4, 21, 1, 1}; int length_ipRouteDest = sizeof(objid_ipRouteDest)/sizeof(oid); oid objid_ipRouteMetric1[] = {1, 3, 6, 1, 2, 1, 4, 21, 1, 3}; int length_ipRouteMetric1 = sizeof(objid_ipRouteMetric1)/sizeof(oid); oid objid_ipRouteNextHop[] = {1, 3, 6, 1, 2, 1, 4, 21, 1, 7}; int length_ipRouteNextHop = sizeof(objid_ipRouteNextHop)/sizeof(oid); oid objid_ipRouteType[] = {1, 3, 6, 1, 2, 1, 4, 21, 1, 8}; int length_ipRouteType = sizeof(objid_ipRouteType)/sizeof(oid); oid objid_ipRouteProto[] = {1, 3, 6, 1, 2, 1, 4, 21, 1, 9}; int length_ipRouteProto = sizeof(objid_ipRouteProto)/sizeof(oid); oid objid_ipRouteAge[] = {1, 3, 6, 1, 2, 1, 4, 21, 1, 10}; int length_ipRouteAge = sizeof(objid_ipRouteAge)/sizeof(oid); oid objid_ipRouteMask[] = {1, 3, 6, 1, 2, 1, 4, 21, 1, 11}; int length_ipRouteMask = sizeof(objid_ipRouteMask)/sizeof(oid); void collect_route_table(ss) struct snmp_session *ss; { struct ospfRT *cur; struct snmp_pdu *pdu, *response; struct variable_list *vars; int good_var, index; int status, count; pdu = snmp_pdu_create(GETNEXT_REQ_MSG); snmp_add_null_var(pdu, objid_ipRouteDest, length_ipRouteDest); snmp_add_null_var(pdu, objid_ipRouteMetric1, length_ipRouteMetric1); snmp_add_null_var(pdu, objid_ipRouteNextHop, length_ipRouteNextHop); snmp_add_null_var(pdu, objid_ipRouteType, length_ipRouteType); snmp_add_null_var(pdu, objid_ipRouteProto, length_ipRouteProto); snmp_add_null_var(pdu, objid_ipRouteAge, length_ipRouteAge); snmp_add_null_var(pdu, objid_ipRouteMask, length_ipRouteMask); good_var = 7; while(good_var == 7){ good_var = 0; status = snmp_synch_response(ss, pdu, &response); if (status == STAT_SUCCESS){ if (response->errstat == SNMP_ERR_NOERROR){ pdu = snmp_pdu_create(GETNEXT_REQ_MSG); index = 0; if (rtp == (struct ospfRT *) 0) { rtp = (struct ospfRT *) malloc(sizeof(struct ospfRT)); cur = rtp; cur->prev = (struct ospfRT *) 0; } else { cur->next = (struct ospfRT *) malloc(sizeof(struct ospfRT)); cur->next->prev = cur; cur = cur->next; } cur->next = (struct ospfRT *) 0; for(vars = response->variables; vars; vars = vars->next_variable) { if (index == 0 && vars->name_length >= length_ipRouteDest && !bcmp((char *)objid_ipRouteDest, (char *)vars->name, sizeof(objid_ipRouteDest))){ cur->ipRouteDest = *vars->val.integer; snmp_add_null_var(pdu, vars->name, vars->name_length); good_var++; } else if (index == 1 && vars->name_length >= length_ipRouteMetric1 && !bcmp((char *)objid_ipRouteMetric1, (char *)vars->name, sizeof(objid_ipRouteMetric1))){ cur->ipRouteMetric1 = *vars->val.integer; snmp_add_null_var(pdu, vars->name, vars->name_length); good_var++; } else if (index == 2 && vars->name_length >= length_ipRouteNextHop && !bcmp((char *)objid_ipRouteNextHop, (char *)vars->name, sizeof(objid_ipRouteNextHop))){ cur->ipRouteNextHop = *vars->val.integer; snmp_add_null_var(pdu, vars->name, vars->name_length); good_var++; } else if (index == 3 && vars->name_length >= length_ipRouteType && !bcmp((char *)objid_ipRouteType, (char *)vars->name, sizeof(objid_ipRouteType))){ cur->ipRouteType = *vars->val.integer; snmp_add_null_var(pdu, vars->name, vars->name_length); good_var++; } else if (index == 4 && vars->name_length >= length_ipRouteProto && !bcmp((char *)objid_ipRouteProto, (char *)vars->name, sizeof(objid_ipRouteProto))){ cur->ipRouteProto = *vars->val.integer; snmp_add_null_var(pdu, vars->name, vars->name_length); good_var++; } else if (index == 5 && vars->name_length >= length_ipRouteAge && !bcmp((char *)objid_ipRouteAge, (char *)vars->name, sizeof(objid_ipRouteAge))){ cur->ipRouteAge = *vars->val.integer; snmp_add_null_var(pdu, vars->name, vars->name_length); good_var++; } else if (index == 6 && vars->name_length >= length_ipRouteMask && !bcmp((char *)objid_ipRouteMask, (char *)vars->name, sizeof(objid_ipRouteMask))){ cur->ipRouteMask = *vars->val.integer; snmp_add_null_var(pdu, vars->name, vars->name_length); good_var++; } index++; } } else { printf("Error in packet.\nReason: %s\n", snmp_errstring(response->errstat)); if (response->errstat == SNMP_ERR_NOSUCHNAME){ printf("This name doesn't exist: "); for(count = 1, vars = response->variables; vars && count != response->errindex; vars = vars->next_variable, count++) ; if (vars) print_objid(vars->name, vars->name_length); printf("\n"); } } } else if (status == STAT_TIMEOUT){ printf("No Response from router\n"); exit(1); } else { /* status == STAT_ERROR */ printf("An error occurred, Quitting\n"); exit(2); } if (response) snmp_free_pdu(response); } /* get rid of last element that contains garbage. */ /* this loop is ugly and copied from CMU. It needs rewritten */ if (cur->prev) { cur->prev->next = (struct ospfRT *) 0; free(cur); } }
Um … yeah … (and that's before adding support for the other set of SNMP MIBs)
Ideally, I'd love do to something like:
OID sys = SNMPv2-MIB::sysObjectID.0; if (sys == SNMPv2-SMI::enterprises.5567.1.1) /* riverstone */ { IpAddress destination[] = IP-MIB::ip.24.4.1.1; IpAddress mask[] = IP-MIB::ip.24.4.1.2; IpAddress nexthop[] = IP-MIB::ip.24.4.1.4; int protocol[] = IP-MIB::ip.24.4.1.7; int age[] = IP-MIB::ip.24.4.1.8; int metric[] = IP-MIB::ip.24.4.1.11; int type[] = IP-MIB::ip.24.4.1.6; } else if (sys == SNMPv2-SMI::enterprises.9.1) /* cisco */ { IpAddress destination[] = RFC1213-MIB::ipRouteDest; IpAddress mask[] = RFC1213-MIB::ipRouteMask; IpAddress nexthop[] = RFC1213-MIB::ipRouteNextHop; int protocol[] = RFC1213-MIB::ipRouteProto; int age[] = RFC1213-MIB::ipRouteAge; int metric[] = RFC1213-MIB::ipRouteMetric1; int type[] = RFC1213-MIB::ipRouteType; } for (i = 0 ; i < destination.length; i++) { print( destination[i], mask[i], nexthop[i], snmp.protocol(protocol[i]), metric[i], age[i] ); }
I would love to make SNMP queries like this, but the ability to embed a secondary language within another language is difficult at best. I do recall in college, I seem to dimly recall the ability to embed SQL within C (or was is Pascal? It was on the VAX system). Something like:
int authenticate(char *user,char *password) { dbpass = ~~ SELECT password FROM g_database.users WHERE user="%user%" ~~; if (dbpass == NULL) return (FALSE); rc = (strcmp(dbpass,password) == 0); free(dbpass); return (rc); }
Much easier than building SQL strings and hoping you get the quoting right.
But alas, such tools and/or languages don't exist (or have ceased to exist) and I'm stuck patching this program to support an alternative set of SNMP MIBs to pull the routing table from Riverstones.