[PATCH v2] irm: Revise naming API

  • From: Dimitri Staessens <dimitri@ouroboros.rocks>
  • To: ouroboros@xxxxxxxxxxxxx
  • Date: Sun, 8 Mar 2020 13:29:21 +0100

This revises the naming API to treat names (or reg_name in the source)
as first-class citizens of the architecture. This is more in line with
the way they are described in the article.

Operations have been added to create/destroy names independently of
registering. This was previously done only as part of register, and
there was no way to delete a name from the IRMd.  The create call now
allows specifying a policy for load-balancing incoming flows for a
name. The default is the new round-robin load-balancer, the previous
behaviour is still available as a spillover load-balancer.

The register calls will still create a name if it doesn't exist, with
the default round-robin load-balancer.

The tools now have a "name" section, so the format is now

irm name <operation> <name> ...

Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks>
---
 doc/man/ouroboros.8                           |  30 ++-
 include/ouroboros/errno.h                     |   1 +
 include/ouroboros/irm.h                       |  28 ++-
 include/ouroboros/sockets.h.in                |   1 +
 src/irmd/main.c                               | 183 ++++++++++++++----
 src/irmd/registry.c                           |  23 ++-
 src/irmd/registry.h                           |  11 +-
 src/lib/irm.c                                 | 125 +++++++++++-
 src/lib/irmd_messages.proto                   |  37 ++--
 src/tools/irm/CMakeLists.txt                  |   8 +-
 src/tools/irm/irm.c                           |   6 +-
 src/tools/irm/irm_ipcp_list.c                 |   4 +-
 src/tools/irm/irm_name.c                      |  98 ++++++++++
 src/tools/irm/irm_name_create.c               |  96 +++++++++
 src/tools/irm/irm_name_destroy.c              |  72 +++++++
 src/tools/irm/irm_name_list.c                 | 115 +++++++++++
 .../irm/{irm_register.c => irm_name_reg.c}    |  56 ++++--
 .../{irm_unregister.c => irm_name_unreg.c}    |  17 +-
 src/tools/irm/irm_ops.h                       |  16 +-
 19 files changed, 817 insertions(+), 110 deletions(-)
 create mode 100644 src/tools/irm/irm_name.c
 create mode 100644 src/tools/irm/irm_name_create.c
 create mode 100644 src/tools/irm/irm_name_destroy.c
 create mode 100644 src/tools/irm/irm_name_list.c
 rename src/tools/irm/{irm_register.c => irm_name_reg.c} (75%)
 rename src/tools/irm/{irm_unregister.c => irm_name_unreg.c} (91%)

diff --git a/doc/man/ouroboros.8 b/doc/man/ouroboros.8
index 4570505..f9aa745 100644
--- a/doc/man/ouroboros.8
+++ b/doc/man/ouroboros.8
@@ -313,7 +313,7 @@ lists IPCPs in the system. You can filter by type, by name 
or by layer.
 .RE
 .RE
 
-.SH IRM COMMANDS
+.SH IRM BIND COMMANDS
 .PP
 \fBirm bind\fR program \fiprogram\fR name \fIname\fR [[\fIauto\fR] -- \
 [\fIparam\fR] [\fIparam\fR] ... [\fIparam\fR]]
@@ -367,20 +367,44 @@ remove the binding between \fIipcp\fR and \fIname\fR. 
This IPCP will
 not accept future flow allocation requests for \fIname\fR.
 .RE
 
+.SH IRM NAME COMMANDS
 .PP
-\fBirm reg\fR name \fIname\fR \fIipcp\fR ipcp [\fIipcp\fR ...]
+\fBirm name create \fIname\fR \fIlb\fR policy
+.RS 4
+Create a name \fIname\fR with a load-balancing policy
+.br
+\fIpolicy\fR: round-robin, spillover
+.br
+.RE
+
+.PP
+\fBirm name destroy \fIname\fR
+.RS 4
+Destroy name \fIname\fR. This does not unregister or unbind it.
+.RE
+
+.PP
+\fBirm name register \fIname\fR \fIipcp\fR ipcp [\fIipcp\fR ...]
 layer [layer \fIlayer\fR ...]
 .RS 4
 Register name \fIname\fR in ipcps \fIipcp\fR ipcp and layers \fIlayer\fR.
 .RE
 
 .PP
-\fBirm unreg\fR name \fIname\fR \fIipcp\fR ipcp [\fIipcp\fR ...]
+\fBirm name unregister \fIname\fR \fIipcp\fR ipcp [\fIipcp\fR ...]
 layer [layer \fIlayer\fR ...]
 .RS 4
 Unregister name \fIname\fR in ipcps \fIipcp\fR ipcp and layers \fIlayer\fR.
 .RE
 
+.PP
+\fBirm name list \fIname\fR
+.RS 4
+List names in the system. \fIname\fR can be used as a prefix to filter
+the names.
+.RE
+
+
 .SH TERMINOLOGY
 Please see \fBouroboros-glossary\fR(7).
 
diff --git a/include/ouroboros/errno.h b/include/ouroboros/errno.h
index 560bcf0..e393e10 100644
--- a/include/ouroboros/errno.h
+++ b/include/ouroboros/errno.h
@@ -32,5 +32,6 @@
 #define EIPCPSTATE   1004 /* Target in wrong state           */
 #define EFLOWDOWN    1005 /* Flow is down                    */
 #define ECRYPT       1006 /* Encryption error                */
+#define ENAME        1007 /* Naming error                    */
 
 #endif /* OUROBOROS_ERRNO_H */
diff --git a/include/ouroboros/irm.h b/include/ouroboros/irm.h
index 69a23c4..2bb284b 100644
--- a/include/ouroboros/irm.h
+++ b/include/ouroboros/irm.h
@@ -39,11 +39,22 @@
 #define NAME_SIZE 256
 #define LAYER_SIZE LAYER_NAME_SIZE
 
+/* Load balancing policy for incoming flows. */
+enum pol_balance {
+        LB_RR = 0,
+        LB_SPILL
+};
+
 struct ipcp_info {
         pid_t          pid;
         enum ipcp_type type;
         char           name[NAME_SIZE];
-        char           layer[LAYER_SIZE];;
+        char           layer[LAYER_SIZE];
+};
+
+struct name_info {
+        char             name[NAME_SIZE];
+        enum pol_balance pol_lb;
 };
 
 __BEGIN_DECLS
@@ -85,11 +96,18 @@ int     irm_bind_process(pid_t        pid,
 int     irm_unbind_process(pid_t        pid,
                            const char * name);
 
-int     irm_reg(pid_t        pid,
-                const char * name);
+int     irm_create_name(const char *     name,
+                        enum pol_balance pol);
 
-int     irm_unreg(pid_t        pid,
-                  const char * name);
+int     irm_destroy_name(const char * name);
+
+ssize_t irm_list_names(struct name_info ** names);
+
+int     irm_reg_name(const char * name,
+                     pid_t        pid);
+
+int     irm_unreg_name(const char * name,
+                       pid_t        pid);
 
 __END_DECLS
 
diff --git a/include/ouroboros/sockets.h.in b/include/ouroboros/sockets.h.in
index 67d57ee..9ab2314 100644
--- a/include/ouroboros/sockets.h.in
+++ b/include/ouroboros/sockets.h.in
@@ -34,6 +34,7 @@ typedef LayerInfoMsg layer_info_msg_t;
 #include "irmd_messages.pb-c.h"
 typedef IrmMsg irm_msg_t;
 typedef IpcpInfoMsg ipcp_info_msg_t;
+typedef NameInfoMsg name_info_msg_t;
 
 #include "ipcpd_messages.pb-c.h"
 typedef IpcpMsg ipcp_msg_t;
diff --git a/src/irmd/main.c b/src/irmd/main.c
index 6535438..812b135 100644
--- a/src/irmd/main.c
+++ b/src/irmd/main.c
@@ -108,6 +108,7 @@ struct cmd {
 
 struct {
         struct list_head     registry;     /* registered names known     */
+        size_t               n_names;      /* number of names            */
 
         struct list_head     ipcps;        /* list of ipcps in system    */
         size_t               n_ipcps;      /* number of ipcps            */
@@ -918,7 +919,7 @@ static ssize_t list_ipcps(ipcp_info_msg_t *** ipcps,
         if (*ipcps == NULL) {
                 pthread_rwlock_unlock(&irmd.reg_lock);
                 *n_ipcps = 0;
-                return -1;
+                return -ENOMEM;
         }
 
         list_for_each(p, &irmd.ipcps) {
@@ -959,53 +960,140 @@ static ssize_t list_ipcps(ipcp_info_msg_t *** ipcps,
         return -ENOMEM;
 }
 
-static int irm_update_name(const char * name)
+static int name_create(const char *     name,
+                       enum pol_balance pol)
 {
+        struct reg_entry * re;
         struct list_head * p;
 
+        assert(name);
+
+        pthread_rwlock_wrlock(&irmd.reg_lock);
+
+        if (registry_has_name(&irmd.registry, name)) {
+                pthread_rwlock_unlock(&irmd.reg_lock);
+                log_err("Registry entry for %s already exists.", name);
+                return -ENAME;
+        }
+
+        re = registry_add_name(&irmd.registry, name);
+        if (re == NULL) {
+                pthread_rwlock_unlock(&irmd.reg_lock);
+                log_err("Failed creating registry entry for %s.", name);
+                return -ENOMEM;
+        }
+        ++irmd.n_names;
+        reg_entry_set_policy(re, pol);
+
+        /* check the tables for existing bindingse */
+        list_for_each(p, &irmd.proc_table) {
+                struct list_head * q;
+                struct proc_entry * e;
+                e = list_entry(p, struct proc_entry, next);
+                list_for_each(q, &e->names) {
+                        struct str_el * s;
+                        s = list_entry(q, struct str_el, next);
+                        if (!strcmp(s->str, name))
+                                reg_entry_add_pid(re, e->pid);
+                }
+        }
+
+        list_for_each(p, &irmd.prog_table) {
+                struct list_head * q;
+                struct prog_entry * e;
+                e = list_entry(p, struct prog_entry, next);
+                list_for_each(q, &e->names) {
+                        struct str_el * s;
+                        s = list_entry(q, struct str_el, next);
+                        if (!strcmp(s->str, name))
+                                reg_entry_add_prog(re, e);
+                }
+        }
+
+        pthread_rwlock_unlock(&irmd.reg_lock);
+
+        log_info("Created new name: %s.", name);
+
+        return 0;
+}
+
+static int name_destroy(const char * name)
+{
+        assert(name);
+
         pthread_rwlock_wrlock(&irmd.reg_lock);
 
         if (!registry_has_name(&irmd.registry, name)) {
-                struct reg_entry * re = registry_add_name(&irmd.registry, 
name);
-                if (re == NULL) {
-                        log_err("Failed creating registry entry for %s.", 
name);
-                        pthread_rwlock_unlock(&irmd.reg_lock);
-                        return -1;
-                }
+                pthread_rwlock_unlock(&irmd.reg_lock);
+                log_warn("Registry entry for %s does not exist.", name);
+                return -ENAME;
+        }
 
-                /* check the tables for client programs */
-                list_for_each(p, &irmd.proc_table) {
-                        struct list_head * q;
-                        struct proc_entry * e;
-                        e = list_entry(p, struct proc_entry, next);
-                        list_for_each(q, &e->names) {
-                                struct str_el * s;
-                                s = list_entry(q, struct str_el, next);
-                                if (!strcmp(s->str, name))
-                                        reg_entry_add_pid(re, e->pid);
-                        }
-                }
+        registry_del_name(&irmd.registry, name);
+        --irmd.n_names;
 
-                list_for_each(p, &irmd.prog_table) {
-                        struct list_head * q;
-                        struct prog_entry * e;
-                        e = list_entry(p, struct prog_entry, next);
-                        list_for_each(q, &e->names) {
-                                struct str_el * s;
-                                s = list_entry(q, struct str_el, next);
-                                if (!strcmp(s->str, name))
-                                        reg_entry_add_prog(re, e);
-                        }
-                }
+        pthread_rwlock_unlock(&irmd.reg_lock);
+
+        log_info("Destroyed name: %s.", name);
+
+        return 0;
+}
+
+static ssize_t list_names(name_info_msg_t *** names,
+                          size_t *            n_names)
+{
+        struct list_head * p;
+        int                i = 0;
+
+        pthread_rwlock_rdlock(&irmd.reg_lock);
+
+        *n_names = irmd.n_names;
+        if (*n_names == 0) {
+                pthread_rwlock_unlock(&irmd.reg_lock);
+                return 0;
+        }
+
+        *names = malloc(irmd.n_names * sizeof(**names));
+        if (*names == NULL) {
+                pthread_rwlock_unlock(&irmd.reg_lock);
+                *n_names = 0;
+                return -ENOMEM;
         }
 
+        list_for_each(p, &irmd.registry) {
+                struct reg_entry * e = list_entry(p, struct reg_entry, next);
+
+                (*names)[i] = malloc(sizeof(***names));
+                if ((*names)[i] == NULL) {
+                        --i;
+                        goto fail;
+                }
+
+                name_info_msg__init((*names)[i]);
+                (*names)[i]->name = strdup(e->name);
+                if ((*names)[i]->name == NULL)
+                        goto fail;
+
+                (*names)[i++]->pol_lb = e->pol_lb;
+       }
+
         pthread_rwlock_unlock(&irmd.reg_lock);
 
         return 0;
+
+ fail:
+        pthread_rwlock_unlock(&irmd.reg_lock);
+        while (i >= 0) {
+                free((*names)[i]->name);
+                free(*names[i--]);
+        }
+        free(*names);
+        *n_names = 0;
+        return -ENOMEM;
 }
 
-static int name_reg(pid_t         pid,
-                    const char *  name)
+static int name_reg(const char * name,
+                    pid_t        pid)
 {
         size_t              len;
         struct ipcp_entry * ipcp;
@@ -1016,6 +1104,11 @@ static int name_reg(pid_t         pid,
 
         pthread_rwlock_wrlock(&irmd.reg_lock);
 
+        if (!registry_has_name(&irmd.registry, name)) {
+                err = -ENAME;
+                goto fail;
+        }
+
         ipcp = get_ipcp_entry_by_pid(pid);
         if (ipcp == NULL) {
                 err = -EIPCP;
@@ -1045,8 +1138,6 @@ static int name_reg(pid_t         pid,
                 return -1;
         }
 
-        irm_update_name(name);
-
         log_info("Registered %s with IPCP %d as " HASH_FMT ".",
                  name, pid, HASH_VAL(hash));
 
@@ -1059,8 +1150,8 @@ fail:
         return err;
 }
 
-static int name_unreg(pid_t         pid,
-                      const char *  name)
+static int name_unreg(const char * name,
+                      pid_t        pid)
 {
         struct ipcp_entry * ipcp;
         int                 err;
@@ -2021,11 +2112,21 @@ static void * mainloop(void * o)
                 case IRM_MSG_CODE__IRM_LIST_IPCPS:
                         result = list_ipcps(&ret_msg->ipcps, 
&ret_msg->n_ipcps);
                         break;
-                case IRM_MSG_CODE__IRM_REG:
-                        result = name_reg(msg->pid, msg->name);
+                case IRM_MSG_CODE__IRM_CREATE_NAME:
+                        result = name_create(msg->names[0]->name,
+                                             msg->names[0]->pol_lb);
                         break;
-                case IRM_MSG_CODE__IRM_UNREG:
-                        result = name_unreg(msg->pid, msg->name);
+                case IRM_MSG_CODE__IRM_DESTROY_NAME:
+                        result = name_destroy(msg->name);
+                        break;
+                case IRM_MSG_CODE__IRM_LIST_NAMES:
+                        result = list_names(&ret_msg->names, 
&ret_msg->n_names);
+                        break;
+                case IRM_MSG_CODE__IRM_REG_NAME:
+                        result = name_reg(msg->name, msg->pid);
+                        break;
+                case IRM_MSG_CODE__IRM_UNREG_NAME:
+                        result = name_unreg(msg->name, msg->pid);
                         break;
                 case IRM_MSG_CODE__IRM_FLOW_ACCEPT:
                         assert(msg->pk.len > 0 ? msg->pk.data != NULL
diff --git a/src/irmd/registry.c b/src/irmd/registry.c
index ef0bc8c..66cc5af 100644
--- a/src/irmd/registry.c
+++ b/src/irmd/registry.c
@@ -32,7 +32,6 @@
 
 #include <ouroboros/errno.h>
 #include <ouroboros/logs.h>
-#include <ouroboros/irm.h>
 #include <ouroboros/time_utils.h>
 
 #include "registry.h"
@@ -72,7 +71,8 @@ static int reg_entry_init(struct reg_entry * e,
         list_head_init(&e->reg_progs);
         list_head_init(&e->reg_pids);
 
-        e->name = name;
+        e->name   = name;
+        e->pol_lb = 0;
 
         if (pthread_condattr_init(&cattr))
                 goto fail_cattr;
@@ -286,7 +286,17 @@ int reg_entry_add_pid(struct reg_entry * e,
 
         i->pid = pid;
 
-        list_add(&i->next, &e->reg_pids);
+        /* load balancing policy assigns queue order for this process. */
+        switch(e->pol_lb) {
+        case LB_RR:    /* Round robin policy. */
+                list_add_tail(&i->next, &e->reg_pids);
+                break;
+        case LB_SPILL: /* Keep accepting flows on the current process */
+                list_add(&i->next, &e->reg_pids);
+                break;
+        default:
+                assert(false);
+        };
 
         if (e->state == REG_NAME_IDLE ||
             e->state == REG_NAME_AUTO_ACCEPT ||
@@ -300,6 +310,13 @@ int reg_entry_add_pid(struct reg_entry * e,
         return 0;
 }
 
+void reg_entry_set_policy(struct reg_entry * e,
+                          enum pol_balance   p)
+{
+        e->pol_lb = p;
+}
+
+
 static void reg_entry_check_state(struct reg_entry * e)
 {
         assert(e);
diff --git a/src/irmd/registry.h b/src/irmd/registry.h
index 31c1b66..bc9aa23 100644
--- a/src/irmd/registry.h
+++ b/src/irmd/registry.h
@@ -26,6 +26,7 @@
 #include <ouroboros/hash.h>
 #include <ouroboros/ipcp.h>
 #include <ouroboros/list.h>
+#include <ouroboros/irm.h>
 
 #include "proc_table.h"
 #include "prog_table.h"
@@ -54,9 +55,11 @@ struct reg_entry {
         struct list_head    next;
         char *              name;
 
-        /* Programs that can be instantiated by the irmd */
+        /* Policies for this name. */
+        enum pol_balance    pol_lb;  /* Load balance incoming flows. */
+        /* Programs that can be instantiated by the irmd. */
         struct list_head    reg_progs;
-        /* Processes that are listening for this name */
+        /* Processes that are listening for this name. */
         struct list_head    reg_pids;
 
         enum reg_name_state state;
@@ -72,7 +75,6 @@ void                reg_entry_del_prog(struct reg_entry * e,
 
 char *              reg_entry_get_prog(struct reg_entry * e);
 
-
 int                 reg_entry_add_pid(struct reg_entry * e,
                                       pid_t              pid);
 
@@ -84,6 +86,9 @@ void                reg_entry_del_pid_el(struct reg_entry * e,
 
 pid_t               reg_entry_get_pid(struct reg_entry * e);
 
+void                reg_entry_set_policy(struct reg_entry * e,
+                                         enum pol_balance   p);
+
 enum reg_name_state reg_entry_get_state(struct reg_entry * e);
 
 int                 reg_entry_set_state(struct reg_entry *  e,
diff --git a/src/lib/irm.c b/src/lib/irm.c
index e4b39f2..dc50e8e 100644
--- a/src/lib/irm.c
+++ b/src/lib/irm.c
@@ -543,8 +543,43 @@ int irm_unbind_process(pid_t        pid,
         return ret;
 }
 
-int irm_reg(pid_t        pid,
-            const char * name)
+int irm_create_name(const char *     name,
+                    enum pol_balance pol)
+{
+        irm_msg_t       msg      = IRM_MSG__INIT;
+        name_info_msg_t ni_msg   = NAME_INFO_MSG__INIT;
+        irm_msg_t *     recv_msg;
+        int             ret;
+
+        if (name == NULL)
+                return -EINVAL;
+
+        msg.code      = IRM_MSG_CODE__IRM_CREATE_NAME;
+        ni_msg.name   = (char *) name;
+        ni_msg.pol_lb = pol;
+        msg.n_names   = 1;
+        msg.names = malloc(sizeof(*msg.names));
+        msg.names[0]  = &ni_msg;
+
+        recv_msg = send_recv_irm_msg(&msg);
+
+        free(msg.names);
+
+        if (recv_msg == NULL)
+                return -EIRMD;
+
+        if (!recv_msg->has_result) {
+                irm_msg__free_unpacked(recv_msg, NULL);
+                return -1;
+        }
+
+        ret = recv_msg->result;
+        irm_msg__free_unpacked(recv_msg, NULL);
+
+        return ret;
+}
+
+int irm_destroy_name(const char * name)
 {
         irm_msg_t   msg      = IRM_MSG__INIT;
         irm_msg_t * recv_msg = NULL;
@@ -553,7 +588,84 @@ int irm_reg(pid_t        pid,
         if (name == NULL)
                 return -EINVAL;
 
-        msg.code    = IRM_MSG_CODE__IRM_REG;
+        msg.code    = IRM_MSG_CODE__IRM_DESTROY_NAME;
+        msg.name    = (char *) name;
+
+        recv_msg = send_recv_irm_msg(&msg);
+        if (recv_msg == NULL)
+                return -EIRMD;
+
+        if (!recv_msg->has_result) {
+                irm_msg__free_unpacked(recv_msg, NULL);
+                return -1;
+        }
+
+        ret = recv_msg->result;
+        irm_msg__free_unpacked(recv_msg, NULL);
+
+        return ret;
+}
+
+ssize_t irm_list_names(struct name_info ** names)
+{
+        irm_msg_t   msg = IRM_MSG__INIT;
+        irm_msg_t * recv_msg;
+        size_t      nr;
+        size_t      i;
+
+        if (names == NULL)
+                return -EINVAL;
+
+        *names = NULL;
+
+        msg.code     = IRM_MSG_CODE__IRM_LIST_NAMES;
+
+        recv_msg = send_recv_irm_msg(&msg);
+        if (recv_msg == NULL)
+                return -EIRMD;
+
+        if (recv_msg->names == NULL) {
+                irm_msg__free_unpacked(recv_msg, NULL);
+                return 0;
+        }
+
+        nr = recv_msg->n_names;
+        if (nr == 0) {
+                irm_msg__free_unpacked(recv_msg, NULL);
+                return 0;
+        }
+
+        *names = malloc(nr * sizeof(**names));
+        if (*names == NULL) {
+                irm_msg__free_unpacked(recv_msg, NULL);
+                return -ENOMEM;
+        }
+
+        for (i = 0; i < nr; i++) {
+                (*names)[i].pol_lb = recv_msg->names[i]->pol_lb;
+                /* Truncate names > NAME_SIZE */
+                if (strlen(recv_msg->names[i]->name) >= NAME_SIZE)
+                    recv_msg->names[i]->name[NAME_SIZE - 1] = 0;
+
+                strcpy((*names)[i].name, recv_msg->names[i]->name);
+        }
+
+        irm_msg__free_unpacked(recv_msg, NULL);
+
+        return nr;
+}
+
+int irm_reg_name(const char * name,
+                 pid_t        pid)
+{
+        irm_msg_t   msg      = IRM_MSG__INIT;
+        irm_msg_t * recv_msg = NULL;
+        int         ret      = -1;
+
+        if (name == NULL)
+                return -EINVAL;
+
+        msg.code    = IRM_MSG_CODE__IRM_REG_NAME;
         msg.has_pid = true;
         msg.pid     = pid;
         msg.name    = (char *) name;
@@ -573,9 +685,8 @@ int irm_reg(pid_t        pid,
         return ret;
 }
 
-
-int irm_unreg(pid_t        pid,
-              const char * name)
+int irm_unreg_name(const char * name,
+                   pid_t        pid)
 {
         irm_msg_t   msg      = IRM_MSG__INIT;
         irm_msg_t * recv_msg = NULL;
@@ -584,7 +695,7 @@ int irm_unreg(pid_t        pid,
         if (name == NULL)
                 return -EINVAL;
 
-        msg.code    = IRM_MSG_CODE__IRM_UNREG;
+        msg.code    = IRM_MSG_CODE__IRM_UNREG_NAME;
         msg.has_pid = true;
         msg.pid     = pid;
         msg.name    = (char *) name;
diff --git a/src/lib/irmd_messages.proto b/src/lib/irmd_messages.proto
index c874969..5b23ee9 100644
--- a/src/lib/irmd_messages.proto
+++ b/src/lib/irmd_messages.proto
@@ -39,15 +39,18 @@ enum irm_msg_code {
         IRM_PROC_ANNOUNCE     = 11;
         IRM_BIND_PROCESS      = 12;
         IRM_UNBIND_PROCESS    = 13;
-        IRM_REG               = 14;
-        IRM_UNREG             = 15;
-        IRM_FLOW_ALLOC        = 16;
-        IRM_FLOW_ACCEPT       = 17;
-        IRM_FLOW_JOIN         = 18;
-        IRM_FLOW_DEALLOC      = 19;
-        IPCP_FLOW_REQ_ARR     = 20;
-        IPCP_FLOW_ALLOC_REPLY = 21;
-        IRM_REPLY             = 22;
+        IRM_CREATE_NAME       = 14;
+        IRM_DESTROY_NAME      = 15;
+        IRM_LIST_NAMES        = 16;
+        IRM_REG_NAME          = 17;
+        IRM_UNREG_NAME        = 18;
+        IRM_FLOW_ALLOC        = 19;
+        IRM_FLOW_ACCEPT       = 20;
+        IRM_FLOW_JOIN         = 21;
+        IRM_FLOW_DEALLOC      = 22;
+        IPCP_FLOW_REQ_ARR     = 23;
+        IPCP_FLOW_ALLOC_REPLY = 24;
+        IRM_REPLY             = 25;
 };
 
 message ipcp_info_msg {
@@ -57,6 +60,11 @@ message ipcp_info_msg {
         required string layer = 4;
 };
 
+message name_info_msg {
+        required string name   = 1;
+        required uint32 pol_lb = 2;
+};
+
 message irm_msg {
         required irm_msg_code code    =  1;
         optional string prog          =  2;
@@ -73,9 +81,10 @@ message irm_msg {
         optional ipcp_config_msg conf = 13;
         optional uint32 opts          = 14;
         repeated ipcp_info_msg ipcps  = 15;
-        optional uint32 timeo_sec     = 16;
-        optional uint32 timeo_nsec    = 17;
-        optional string comp          = 18;
-        optional bytes pk             = 19; /* piggyback */
-        optional sint32 result        = 20;
+        repeated name_info_msg names  = 16;
+        optional uint32 timeo_sec     = 17;
+        optional uint32 timeo_nsec    = 18;
+        optional string comp          = 19;
+        optional bytes pk             = 20; /* piggyback */
+        optional sint32 result        = 21;
 };
diff --git a/src/tools/irm/CMakeLists.txt b/src/tools/irm/CMakeLists.txt
index ca32e9c..e5e5c46 100644
--- a/src/tools/irm/CMakeLists.txt
+++ b/src/tools/irm/CMakeLists.txt
@@ -23,8 +23,12 @@ set(SOURCE_FILES
   irm_unbind.c
   irm_bind.c
   irm_ipcp.c
-  irm_register.c
-  irm_unregister.c
+  irm_name.c
+  irm_name_create.c
+  irm_name_destroy.c
+  irm_name_reg.c
+  irm_name_unreg.c
+  irm_name_list.c
   irm_utils.c
   )
 
diff --git a/src/tools/irm/irm.c b/src/tools/irm/irm.c
index fe382bb..2388bfd 100644
--- a/src/tools/irm/irm.c
+++ b/src/tools/irm/irm.c
@@ -49,8 +49,7 @@
 static void usage(void)
 {
         printf("Usage: irm [OPERATION]\n\n"
-               "where OPERATION = {ipcp bind unbind\n"
-               "                   register unregister}\n");
+               "where OPERATION = {ipcp bind unbind name}\n");
 }
 
 static int do_help(int    argc,
@@ -70,8 +69,7 @@ static const struct cmd {
         { "ipcp",       ipcp_cmd },
         { "bind",       bind_cmd },
         { "unbind",     unbind_cmd },
-        { "register",   do_register },
-        { "unregister", do_unregister },
+        { "name",       name_cmd },
         { "help",       do_help },
         { NULL,         NULL }
 };
diff --git a/src/tools/irm/irm_ipcp_list.c b/src/tools/irm/irm_ipcp_list.c
index 28a31d4..3b8612e 100644
--- a/src/tools/irm/irm_ipcp_list.c
+++ b/src/tools/irm/irm_ipcp_list.c
@@ -1,7 +1,7 @@
 /*
  * Ouroboros - Copyright (C) 2016 - 2020
  *
- * Create IPC Processes
+ * List IPC Processes
  *
  *    Dimitri Staessens <dimitri.staessens@xxxxxxxx>
  *    Sander Vrijders   <sander.vrijders@xxxxxxxx>
@@ -46,7 +46,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#define UNICAST  "unicast"
+#define UNICAST "unicast"
 #define UDP     "udp"
 #define ETH_LLC "eth-llc"
 #define ETH_DIX "eth-dix"
diff --git a/src/tools/irm/irm_name.c b/src/tools/irm/irm_name.c
new file mode 100644
index 0000000..3a615b0
--- /dev/null
+++ b/src/tools/irm/irm_name.c
@@ -0,0 +1,98 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2020
+ *
+ * A tool to instruct the IRM daemon
+ *
+ *    Dimitri Staessens <dimitri.staessens@xxxxxxxx>
+ *    Sander Vrijders   <sander.vrijders@xxxxxxxx>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+#include "irm_ops.h"
+#include "irm_utils.h"
+
+static void usage(void)
+{
+        printf("Usage: irm name [OPERATION]\n\n"
+               "where OPERATION = {create destroy\n"
+               "                   register unregister\n"
+               "                   list help}\n");
+}
+
+static int do_help(int argc, char **argv)
+{
+        (void) argc;
+        (void) argv;
+
+        usage();
+        return 0;
+}
+
+static const struct cmd {
+        const char * cmd;
+        int (* func)(int argc, char ** argv);
+} cmds[] = {
+        { "create",     do_create_name },
+        { "destroy",    do_destroy_name },
+        { "register",   do_reg_name },
+        { "unregister", do_unreg_name },
+        { "list",       do_list_name},
+        { "help",       do_help },
+        { NULL,         NULL }
+};
+
+static int do_cmd(const char * argv0,
+                  int          argc,
+                  char **      argv)
+{
+        const struct cmd * c;
+
+        for (c = cmds; c->cmd; ++c) {
+                if (matches(argv0, c->cmd) == 0)
+                        return c->func(argc - 1, argv + 1);
+        }
+
+        fprintf(stderr, "\"%s\" is unknown, try \"irm ipcp help\".\n", argv0);
+
+        return -1;
+}
+
+int name_cmd(int argc, char ** argv)
+{
+        if (argc < 1) {
+                usage();
+                return -1;
+        }
+
+        return do_cmd(argv[0], argc, argv);
+}
diff --git a/src/tools/irm/irm_name_create.c b/src/tools/irm/irm_name_create.c
new file mode 100644
index 0000000..9b7e6a3
--- /dev/null
+++ b/src/tools/irm/irm_name_create.c
@@ -0,0 +1,96 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2020
+ *
+ * Create IPC Processes
+ *
+ *    Dimitri Staessens <dimitri.staessens@xxxxxxxx>
+ *    Sander Vrijders   <sander.vrijders@xxxxxxxx>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ouroboros/irm.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "irm_ops.h"
+#include "irm_utils.h"
+
+#define RR    "round-robin"
+#define SPILL "spillover"
+
+static void usage(void)
+{
+        printf("Usage: irm name create\n"
+               "                <name>\n"
+               "                lb [LB_POLICY], default: %s\n\n"
+               "where LB_POLICY = {" RR " " SPILL "}\n", RR);
+}
+
+int do_create_name(int     argc,
+                   char ** argv)
+{
+        char * name             = NULL;
+        char * lb_pol           = RR;
+        enum pol_balance pol_lb = LB_RR;
+
+        name = *(argv++);
+        --argc;
+
+        while (argc > 0) {
+                if (matches(*argv, "lb") == 0) {
+                        lb_pol = *(argv + 1);
+                } else {
+                        printf("\"%s\" is unknown, try \"irm "
+                               "name create\".\n", *argv);
+                        return -1;
+                }
+
+                argc -= 2;
+                argv += 2;
+        }
+
+        if (name == NULL) {
+                usage();
+                return -1;
+        }
+
+        if (strcmp(lb_pol, RR) == 0)
+                pol_lb = LB_RR;
+        else if (strcmp(lb_pol, SPILL) == 0)
+                pol_lb = LB_SPILL;
+        else {
+                usage();
+                return -1;
+        }
+
+        return irm_create_name(name, pol_lb);
+}
diff --git a/src/tools/irm/irm_name_destroy.c b/src/tools/irm/irm_name_destroy.c
new file mode 100644
index 0000000..70f801b
--- /dev/null
+++ b/src/tools/irm/irm_name_destroy.c
@@ -0,0 +1,72 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2020
+ *
+ * Create IPC Processes
+ *
+ *    Dimitri Staessens <dimitri.staessens@xxxxxxxx>
+ *    Sander Vrijders   <sander.vrijders@xxxxxxxx>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ouroboros/irm.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "irm_ops.h"
+#include "irm_utils.h"
+
+static void usage(void)
+{
+        printf("Usage: irm name destroy <name>\n");
+}
+
+int do_destroy_name(int     argc,
+                    char ** argv)
+{
+        char * name             = NULL;
+
+        name = *(argv++);
+        --argc;
+
+        if (argc > 0) {
+                printf("\"%s\" is unknown, try \"irm "
+                       "name destroy\".\n", *argv);
+                return -1;
+        }
+
+        if (name == NULL) {
+                usage();
+                return -1;
+        }
+
+        return irm_destroy_name(name);
+}
diff --git a/src/tools/irm/irm_name_list.c b/src/tools/irm/irm_name_list.c
new file mode 100644
index 0000000..2e4c319
--- /dev/null
+++ b/src/tools/irm/irm_name_list.c
@@ -0,0 +1,115 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2020
+ *
+ * List names
+ *
+ *    Dimitri Staessens <dimitri.staessens@xxxxxxxx>
+ *    Sander Vrijders   <sander.vrijders@xxxxxxxx>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ouroboros/irm.h>
+#include <ouroboros/errno.h>
+
+#include "irm_ops.h"
+#include "irm_utils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define RR    "round-robin"
+#define SPILL "spillover"
+
+static char * str_pol(enum pol_balance p)
+{
+        switch(p) {
+        case LB_RR:
+                return RR;
+        case LB_SPILL:
+                return SPILL;
+        default:
+                return "UNKNOWN";
+        }
+};
+
+int do_list_name(int     argc,
+                 char ** argv)
+{
+        char *             name = NULL;
+        struct name_info * names;
+        ssize_t            len;
+        ssize_t            i;
+
+        while (argc > 0) {
+                if (matches(*argv, "list") == 0) {
+                        name = *(argv + 1);
+                } else {
+                        printf("\"%s\" is unknown, try \"irm "
+                               "name list.\n", *argv);
+                        return -1;
+                }
+
+                argc -= 2;
+                argv += 2;
+        }
+
+        len = irm_list_names(&names);
+        if (len == 0) {
+                printf("No names in system.\n\n");
+                return 0;
+        } else if (len == -EIRMD) {
+                printf("Failed to communicate with the "
+                       "Ouroboros IPC Resource Manager daemon.\n");
+                return -1;
+        } else if (len < 0)
+                return len;
+
+        printf("+----------------------------------------------------"
+               "+----------------------+\n");
+        printf("| %50s | %20s |\n", "name", "load-balance policy");
+        printf("+----------------------------------------------------"
+               "+----------------------+\n");
+
+        for (i = 0; i < len; i++) {
+                if (name != NULL && matches(names[i].name, name))
+                        continue;
+                printf("| %50s | %20s |\n",
+                       names[i].name,
+                       str_pol(names[i].pol_lb));
+        }
+        printf("+----------------------------------------------------"
+               "+----------------------+\n");
+
+        free(names);
+
+        return 0;
+}
diff --git a/src/tools/irm/irm_register.c b/src/tools/irm/irm_name_reg.c
similarity index 75%
rename from src/tools/irm/irm_register.c
rename to src/tools/irm/irm_name_reg.c
index f7b57b0..52bf911 100644
--- a/src/tools/irm/irm_register.c
+++ b/src/tools/irm/irm_name_reg.c
@@ -1,7 +1,7 @@
 /*
  * Ouroboros - Copyright (C) 2016 - 2020
  *
- * Register names in IPCPs
+ * Register names with IPCPs
  *
  *    Dimitri Staessens <dimitri.staessens@xxxxxxxx>
  *    Sander Vrijders   <sander.vrijders@xxxxxxxx>
@@ -38,7 +38,6 @@
 
 #include <ouroboros/irm.h>
 
-
 #include "irm_ops.h"
 #include "irm_utils.h"
 
@@ -51,8 +50,7 @@
 
 static void usage(void)
 {
-        printf("Usage: irm register\n"
-               "           name <name>\n"
+        printf("Usage: irm name register <name>\n"
                "           ipcp <ipcp to register with>\n"
                "           [ipcp <ipcp to register with>]\n"
                "           [... (maximum %d ipcps)]\n"
@@ -63,7 +61,7 @@ static void usage(void)
 }
 
 
-int do_register(int     argc,
+int do_reg_name(int     argc,
                 char ** argv)
 {
         char *             name       = NULL;
@@ -72,14 +70,17 @@ int do_register(int     argc,
         char *             ipcp[MAX_IPCPS];
         size_t             ipcp_len   = 0;
         struct ipcp_info * ipcps;
-        ssize_t            len;
+        ssize_t            ipcps_len;
+        struct name_info * names;
+        ssize_t            names_len;
+        bool               name_create = true;
         ssize_t            i;
 
+        name = *(argv++);
+        --argc;
 
         while (argc > 0) {
-                if (matches(*argv, "name") == 0) {
-                        name = *(argv + 1);
-                } else if (matches(*argv, "layer") == 0) {
+                if (matches(*argv, "layer") == 0) {
                         layers[layers_len++] = *(argv + 1);
                         if (layers_len > MAX_LAYERS) {
                                 printf("Too many layers specified.\n");
@@ -92,7 +93,7 @@ int do_register(int     argc,
                                 return -1;
                         }
                 } else {
-                        printf("\"%s\" is unknown, try \"irm "
+                        printf("\"%s\" is unknown, try \"irm name "
                                "register\".\n", *argv);
                         return -1;
                 }
@@ -106,24 +107,46 @@ int do_register(int     argc,
                 return -1;
         }
 
-        len = irm_list_ipcps(&ipcps);
-        if (len < 0)
-                return len;
+        ipcps_len = irm_list_ipcps(&ipcps);
+        if (ipcps_len < 0)
+                return ipcps_len;
 
-        for (i = 0; i < len; ++i) {
+        names_len = irm_list_names(&names);
+        if (names_len < 0) {
+                free(ipcps);
+                return names_len;
+        }
+
+        for (i = 0; i < names_len; ++i) {
+                if (strcmp(names[i].name, name) == 0) {
+                        name_create = false;
+                        break;
+                }
+        }
+
+        if (name_create && irm_create_name(name, LB_SPILL)) {
+                printf("Error creating name.");
+                free(ipcps);
+                free(name);
+                return -1;
+        }
+
+        for (i = 0; i < ipcps_len; ++i) {
                 size_t j;
                 for (j = 0; j < layers_len; j++) {
                         if (wildcard_match(layers[j], ipcps[i].layer) == 0) {
-                                if (irm_reg(ipcps[i].pid, name)) {
+                                if (irm_reg_name(name, ipcps[i].pid)) {
                                         free(ipcps);
+                                        free(names);
                                         return -1;
                                 }
                         }
                 }
                 for (j = 0; j < ipcp_len; j++) {
                         if (wildcard_match(ipcp[j], ipcps[i].name) == 0) {
-                                if (irm_reg(ipcps[i].pid, name)) {
+                                if (irm_reg_name(name, ipcps[i].pid)) {
                                         free(ipcps);
+                                        free(names);
                                         return -1;
                                 }
                         }
@@ -131,6 +154,7 @@ int do_register(int     argc,
         }
 
         free(ipcps);
+        free(names);
 
         return 0;
 }
diff --git a/src/tools/irm/irm_unregister.c b/src/tools/irm/irm_name_unreg.c
similarity index 91%
rename from src/tools/irm/irm_unregister.c
rename to src/tools/irm/irm_name_unreg.c
index 3ef2870..4825314 100644
--- a/src/tools/irm/irm_unregister.c
+++ b/src/tools/irm/irm_name_unreg.c
@@ -50,8 +50,7 @@
 
 static void usage(void)
 {
-        printf("Usage: irm unregister\n"
-               "           name <name>\n"
+        printf("Usage: irm name unregister <name>\n"
                "           ipcp <ipcp to register with>\n"
                "           [ipcp <ipcp to register with>]\n"
                "           [... (maximum %d ipcps)]\n"
@@ -61,7 +60,8 @@ static void usage(void)
                , MAX_IPCPS, MAX_LAYERS);
 }
 
-int do_unregister(int argc, char ** argv)
+int do_unreg_name(int     argc,
+                  char ** argv)
 {
         char *             name       = NULL;
         char *             layers[MAX_LAYERS];
@@ -72,10 +72,11 @@ int do_unregister(int argc, char ** argv)
         ssize_t            len;
         size_t             i;
 
+        name = *(argv++);
+        --argc;
+
         while (argc > 0) {
-                if (matches(*argv, "name") == 0) {
-                        name = *(argv + 1);
-                } else if (matches(*argv, "layer") == 0) {
+                if (matches(*argv, "layer") == 0) {
                         layers[layers_len++] = *(argv + 1);
                         if (layers_len > MAX_LAYERS) {
                                 printf("Too many layers specified.\n");
@@ -110,7 +111,7 @@ int do_unregister(int argc, char ** argv)
                 size_t j;
                 for (j = 0; j < layers_len; j++) {
                         if (wildcard_match(ipcps[i].layer, layers[j]) == 0) {
-                                if (irm_unreg(ipcps[i].pid, name)) {
+                                if (irm_unreg_name(name, ipcps[i].pid)) {
                                         free(ipcps);
                                         return -1;
                                 }
@@ -119,7 +120,7 @@ int do_unregister(int argc, char ** argv)
                 }
                 for (j = 0; j < ipcp_len; j++) {
                         if (wildcard_match(ipcps[i].name, ipcp[j]) == 0) {
-                                if (irm_unreg(ipcps[i].pid, name)) {
+                                if (irm_unreg_name(name, ipcps[i].pid)) {
                                         free(ipcps);
                                         return -1;
                                 }
diff --git a/src/tools/irm/irm_ops.h b/src/tools/irm/irm_ops.h
index a6530f6..7c1b1a8 100644
--- a/src/tools/irm/irm_ops.h
+++ b/src/tools/irm/irm_ops.h
@@ -84,8 +84,20 @@ int do_unbind_process(int     argc,
 int do_unbind_ipcp(int     argc,
                    char ** argv);
 
-int do_register(int     argc,
+int name_cmd(int     argc,
+             char ** argv);
+
+int do_create_name(int     argc,
+                   char ** argv);
+
+int do_destroy_name(int     argc,
+                    char ** argv);
+
+int do_reg_name(int     argc,
                 char ** argv);
 
-int do_unregister(int     argc,
+int do_unreg_name(int     argc,
                   char ** argv);
+
+int do_list_name(int     argc,
+                 char ** argv);
-- 
2.25.1



Other related posts: