Using dhcpctl to lookup/add/remove macs from subclasses on one connection

Aaron Logue alogue at
Mon Mar 14 17:48:14 UTC 2011

Hello Fellow DHCPers,

I'm running into some problems when using multiple dhcpctl calls to
operate on objects on the same connection or even in the same program
execution.  In some cases, dhcpctl_object_dereference() seems to leave
OMAPI in a state which prevents subsequent subclass lookups from
working correctly.  In other cases, the connection is dropped, such as
after a subclass add.  In both cases, re-issuing a dhcpctl_initialize()
and/or dhcpctl_connect() does not appear to put OMAPI back into a
working state; it seems to be necessary to exit and rerun the program
that's making the dhcpctl calls.

Has anyone run into that or come up with a workaround?

Here's the nitty-gritty...

It looks like dhcp_subclass_create() has been implemented, and will
add a MAC address to a subclass if it is passed in as 7 octets with a
name of "hashstring", in "dhcp-client-identifier" format.  Great!
In switching our hacks to use this new implementation however, I
found that I needed to change  cp -> flags = CLASS_DECL_DYNAMIC;
to cp -> flags = 0;  in order to prevent the dhcpd.leases file from
having dynamic subclass entries written to it that confpars.c
doesn't seem to be able to read, causing dhcpd to abort on load the
next time it is run.  We've got many thousands of MAC addresses,
and don't want them written out to dhcpd.leases anyway, so that's
no big deal.  The add seems to work, but the
dhcpctl_wait_for_completion() call returns ISC_R_CONNRESET.
Is that intentional?

It looks like dhcp_subclass_lookup() has been implemented to search
a subclass for a given MAC address if it's specified in the
abovementioned 7 octets named "hashstring" format.  To get it to
return ISC_R_SUCCESS after it found a match, I needed to remove the
"Don't return the object if the type is wrong" check from class_lookup().
Am I missing something there?  The main problem, however, is that it only
seems to work on the first open_object call, or as long as open_object
is returning a match.  As soon as open_object returns not found,
subsequent dhcp_subclass_lookup() calls fail, even if
dhcpctl_initialize() and dhcpctl_connect() are called again.

dhcp_subclass_remove() hasn't yet been implemented, but for anyone who
needs one, here is a kludge similar to one that I came up with for use
in older versions of omapi.c.  It piggybacks on dhcp_subclass_lookup()
and suffers from the same abovementioned failure modes (if you try to
remove something that's not there, subsequent lookups will fail, and
if you successfully remove, the wait call returns ISC_R_CONNRESET).

#define STRLEN 80
 * dhcp_subclass_lookup
 * After spending awhile trying to get object_remove to work (I think maybe
 * it winds up trying to use the wrong (subclass vs. parent class) hash
 * indexes or something..?) I reverted to a kludge of using subclass_lookup
 * to delete a subclass entry.  This removes a MAC from a subclass called
 * "modems" where macdata is pointing at 7 octets of a 0x01-prefixed MAC:
 *   dhcpctl_new_object (&subclass_handle, connection, "subclass");
 *   dhcpctl_set_string_value (subclass_handle, "modems", "name");
 *   dhcpctl_set_data_value (subclass_handle, (char *)macdata, 7, "hashstring");
 *   dhcpctl_set_string_value(object, "remove", "special");
 *   dhcpctl_open_object(object, connection, 0);
 *   dhcpctl_wait_for_completion (subclass_handle, &waitstatus);
isc_result_t dhcp_subclass_lookup (omapi_object_t **lp,
                                   omapi_object_t *id, omapi_object_t *ref)
 omapi_value_t *tv = (omapi_value_t *)0;
 isc_result_t status;
 struct class *class = (struct class *)0, *pc = (struct class *)0;
 char classname[STRLEN+1];
 int remove = 0;

   /* Check for a remove request */
   status = omapi_get_value_str (ref, id, "special", &tv);
   if (status == ISC_R_SUCCESS) {
      if (!strncmp((const char *)tv->value->u.buffer.value, "remove", tv->value->u.buffer.len)) {
         remove = 1;
      omapi_value_dereference (&tv, MDL);
   if (remove) {
      status = omapi_get_value_str (ref, id, "name", &tv);
      if (status == ISC_R_SUCCESS) {
         strncpy(classname, (const char *)tv->value->u.buffer.value, STRLEN);
         if (tv->value->u.buffer.len <= STRLEN) {
            classname[tv->value->u.buffer.len] = 0;
         } else {
            classname[STRLEN] = 0;
         omapi_value_dereference (&tv, MDL);
      find_class(&pc, classname, MDL);
      if (!pc) {
         /* we couldn't find the class containing the subclass */
         return ISC_R_NOTFOUND;
      } else {
         status = omapi_get_value_str (ref, id, "hashstring", &tv);
         if (status == ISC_R_SUCCESS) {
            class_hash_lookup(&class, pc->hash, (const char *)tv->value->u.buffer.value,
                                                tv->value->u.buffer.len, MDL);
            if (class) {
               class_hash_delete(pc->hash, (const char *)tv->value->u.buffer.value,
                                           tv->value->u.buffer.len, MDL);
               remove = 2;
            omapi_value_dereference (&tv, MDL);
         class_dereference(&pc, MDL);
      if (remove == 2) {
         return ISC_R_SUCCESS;
      return ISC_R_NOTFOUND;

        return class_lookup(lp, id, ref, dhcp_type_subclass);

Any insight or advice on where to look to solve the multiple-
lookups-per-connection problem is much appreciated.  Thanks,

Aaron Logue
Ygnition Networks

More information about the dhcp-users mailing list