Friday, January 19, 2007
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.