A quick note on embedding languages within languages

While I don't fully agree with this article [1] (link via ThoughtStorms [2], and more on this in a later entry) I do agree that our current methods of programming do fall short (design patterns being silly [3]). This was made plainly apparent today at The Office.

I have this program called ospfquery that not only retrieves OSPF (Open Shortest Path First) specific SNMP (Simple Network Management Protocol) 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 MIB (Management Information Base)s that ospfquery uses to retrieve the routing table. But by dumping the entire SNMP tree, I was able to find equivalents.

Table: Routing table SNMP MIBs for Cisco and Riverstone
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 (Florida Atlantic University) [4], I seem to dimly recall the ability to embed SQL (Structured Query Language) 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.

Upate on Thursday, July 22^nd, 2010

I found a way to do what I wanted [5] …

[1] http://www.onboard.jetbrains.com/is1/articles/04/10/lop/

[2] http://www.nooranch.com/synaesmedia/wiki/wiki.cgi?LanguageOrientedProgramming

[3] /boston/2007/01/15.2

[4] http://www.fau.edu/

[5] /boston/2010/07/22.1

Gemini Mention this post

Contact the author