]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #1025 from qlyoung/no-ospf
authorDavid Lamparter <equinox@diac24.net>
Tue, 22 Aug 2017 15:55:01 +0000 (17:55 +0200)
committerGitHub <noreply@github.com>
Tue, 22 Aug 2017 15:55:01 +0000 (17:55 +0200)
ospfd, ospf6d: cleanup some `no` commands

86 files changed:
babeld/babel_interface.c
babeld/babel_zebra.c
bgpd/bgp_debug.c
bgpd/bgp_main.c
bgpd/bgp_route.c
bgpd/bgp_table.h
bgpd/bgp_vty.c
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/rfapi_import.c
bgpd/rfapi/vnc_debug.c
configure.ac
doc/code/.gitignore [new file with mode: 0644]
doc/code/Makefile [new file with mode: 0644]
doc/code/conf.py [new file with mode: 0644]
doc/code/hooks.rst [new file with mode: 0644]
doc/code/index.rst [new file with mode: 0644]
doc/code/library.rst [new file with mode: 0644]
doc/code/memtypes.rst [new file with mode: 0644]
eigrpd/eigrp_dump.c
eigrpd/eigrp_hello.c
eigrpd/eigrp_interface.c
eigrpd/eigrp_main.c
eigrpd/eigrp_packet.c
eigrpd/eigrp_packet.h
isisd/isis_circuit.c
isisd/isis_vty.c
isisd/isisd.c
ldpd/control.h
ldpd/lde.h
ldpd/ldp_vty_cmds.c
ldpd/ldpd.c
ldpd/ldpd.h
ldpd/ldpe.h
lib/freebsd-queue.h [new file with mode: 0644]
lib/hash.c
lib/hook.c
lib/hook.h
lib/if.c
lib/if.h
lib/imsg-buffer.c
lib/imsg.c
lib/libfrr.c
lib/libfrr.h
lib/prefix.c
lib/prefix.h
lib/privs.c
lib/queue.h
lib/subdir.am
lib/table.c
lib/table.h
lib/workqueue.c
lib/workqueue.h
nhrpd/nhrp_interface.c
nhrpd/nhrp_main.c
nhrpd/nhrp_vty.c
ospf6d/ospf6_main.c
ospf6d/ospf6d.c
ospfd/ospf_dump.c
ospfd/ospf_interface.c
ospfd/ospf_packet.c
pimd/pim_cmd.c
redhat/frr.spec.in
ripd/rip_debug.c
ripd/rip_interface.c
ripngd/ripng_debug.c
ripngd/ripng_interface.c
tools/frr
tools/frr-reload.py
vtysh/vtysh.c
zebra/debug.c
zebra/interface.c
zebra/interface.h
zebra/irdp.h
zebra/irdp_interface.c
zebra/irdp_main.c
zebra/irdp_packet.c
zebra/main.c
zebra/redistribute.c
zebra/rtadv.c
zebra/rtadv.h
zebra/subdir.am
zebra/zebra_pw.c
zebra/zebra_rib.c
zebra/zebra_static.c
zebra/zebra_vty.c

index 1ae33b3a27af7a6b49f077ca8f913e29de7ca5d5..9fa32ee6fa6f8acf2b1e03d24e744e9f0b391f03 100644 (file)
@@ -1256,8 +1256,8 @@ void
 babel_if_init ()
 {
     /* initialize interface list */
-    if_add_hook (IF_NEW_HOOK,    babel_if_new_hook);
-    if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook);
+    hook_register_prio(if_add, 0, babel_if_new_hook);
+    hook_register_prio(if_del, 0, babel_if_delete_hook);
 
     babel_enable_if = vector_init (1);
 
index 11b9c5956c24cb1666bc3ac990e544e037028403..2ec5c3d7c3d2d84e3a319c8a7fee2e6805de3a29 100644 (file)
@@ -310,6 +310,20 @@ debug_babel_config_write (struct vty * vty)
 #endif /* NO_DEBUG */
 }
 
+DEFUN_NOSH (show_debugging_babel,
+           show_debugging_babel_cmd,
+           "show debugging [babel]",
+           SHOW_STR
+           DEBUG_STR
+           "Babel")
+{
+       vty_out(vty, "BABEL debugging status\n");
+
+       debug_babel_config_write(vty);
+
+       return CMD_SUCCESS;
+}
+
 static void
 babel_zebra_connected (struct zclient *zclient)
 {
@@ -339,6 +353,8 @@ void babelz_zebra_init(void)
     install_element(ENABLE_NODE, &no_debug_babel_cmd);
     install_element(CONFIG_NODE, &debug_babel_cmd);
     install_element(CONFIG_NODE, &no_debug_babel_cmd);
+
+    install_element(VIEW_NODE, &show_debugging_babel_cmd);
 }
 
 static int
index bcb3c5fc1860f1ae7761eea93dd7f217cbc373d5..c1c4f2b39cda7ffe1ed3e291543a427ac8f1eb50 100644 (file)
@@ -1615,12 +1615,12 @@ DEFUN (no_debug_bgp,
        return CMD_SUCCESS;
 }
 
-DEFUN (show_debugging_bgp,
-       show_debugging_bgp_cmd,
-       "show debugging bgp",
-       SHOW_STR
-       DEBUG_STR
-       BGP_STR)
+DEFUN_NOSH (show_debugging_bgp,
+           show_debugging_bgp_cmd,
+           "show debugging [bgp]",
+           SHOW_STR
+           DEBUG_STR
+           BGP_STR)
 {
        vty_out(vty, "BGP debugging status:\n");
 
index 25a562ed68f9c944a4d25e3db77dd770e83210e8..3bf9ea02d501e7793e40d24b57ca10e88b37e17b 100644 (file)
@@ -140,11 +140,8 @@ __attribute__((__noreturn__)) void sigint(void)
 {
        zlog_notice("Terminating on signal");
 
-       if (!retain_mode) {
+       if (!retain_mode)
                bgp_terminate();
-               if (bgpd_privs.user) /* NULL if skip_runas flag set */
-                       zprivs_terminate(&bgpd_privs);
-       }
 
        bgp_exit(0);
 
@@ -172,13 +169,12 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
        /* it only makes sense for this to be called on a clean exit */
        assert(status == 0);
 
+       frr_early_fini();
+
        bfd_gbl_exit();
 
        bgp_close();
 
-       if (retain_mode)
-               if_add_hook(IF_DELETE_HOOK, NULL);
-
        /* reverse bgp_master_init */
        for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
                bgp_delete(bgp);
@@ -214,22 +210,16 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
        community_list_terminate(bgp_clist);
 
        bgp_vrf_terminate();
-       cmd_terminate();
-       vty_terminate();
 #if ENABLE_BGP_VNC
        vnc_zebra_destroy();
 #endif
        bgp_zebra_destroy();
 
-       /* reverse bgp_master_init */
-       if (bm->master)
-               thread_master_free(bm->master);
-
-       closezlog();
-
        list_delete(bm->bgp);
        memset(bm, 0, sizeof(*bm));
 
+       frr_fini();
+
        if (bgp_debug_count())
                log_memstats_stderr("bgpd");
        exit(status);
index 35f793f8612b61a24dee0699fde8afceef0e54d2..bb204b01f1265784e4d3ecee1a46ad98a10a7b98 100644 (file)
@@ -2001,18 +2001,15 @@ int bgp_zebra_has_route_changed(struct bgp_node *rn, struct bgp_info *selected)
 
 struct bgp_process_queue {
        struct bgp *bgp;
-       struct bgp_node *rn;
-       afi_t afi;
-       safi_t safi;
+       STAILQ_HEAD(, bgp_node)pqueue;
+#define BGP_PROCESS_QUEUE_EOIU_MARKER          (1 << 0)
+       unsigned int flags;
+       unsigned int queued;
 };
 
-static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
+static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
+                                afi_t afi, safi_t safi)
 {
-       struct bgp_process_queue *pq = data;
-       struct bgp *bgp = pq->bgp;
-       struct bgp_node *rn = pq->rn;
-       afi_t afi = pq->afi;
-       safi_t safi = pq->safi;
        struct prefix *p = &rn->p;
        struct bgp_info *new_select;
        struct bgp_info *old_select;
@@ -2033,7 +2030,7 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
                bgp->main_peers_update_hold = 0;
 
                bgp_start_routeadv(bgp);
-               return WQ_SUCCESS;
+               return;
        }
 
        /* Best path selection. */
@@ -2114,7 +2111,7 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
                }
 
                UNSET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED);
-               return WQ_SUCCESS;
+               return;
        }
 
        /* If the user did "clear ip bgp prefix x.x.x.x" this flag will be set
@@ -2192,21 +2189,42 @@ static wq_item_status bgp_process_main(struct work_queue *wq, void *data)
                bgp_info_reap(rn, old_select);
 
        UNSET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED);
-       return WQ_SUCCESS;
+       return;
 }
 
-static void bgp_processq_del(struct work_queue *wq, void *data)
+static wq_item_status bgp_process_wq(struct work_queue *wq, void *data)
 {
-       struct bgp_process_queue *pq = data;
+       struct bgp_process_queue *pqnode = data;
+       struct bgp *bgp = pqnode->bgp;
        struct bgp_table *table;
+       struct bgp_node *rn, *nrn;
+
+       /* eoiu marker */
+       if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER)) {
+               bgp_process_main_one(bgp, NULL, 0, 0);
 
-       bgp_unlock(pq->bgp);
-       if (pq->rn) {
-               table = bgp_node_table(pq->rn);
-               bgp_unlock_node(pq->rn);
+               return WQ_SUCCESS;
+       }
+
+       STAILQ_FOREACH_SAFE(rn, &pqnode->pqueue, pq, nrn) {
+               table = bgp_node_table(rn);
+
+               bgp_process_main_one(bgp, rn, table->afi, table->safi);
+
+               bgp_unlock_node(rn);
                bgp_table_unlock(table);
        }
-       XFREE(MTYPE_BGP_PROCESS_QUEUE, pq);
+
+       return WQ_SUCCESS;
+}
+
+static void bgp_processq_del(struct work_queue *wq, void *data)
+{
+       struct bgp_process_queue *pqnode = data;
+
+       bgp_unlock(pqnode->bgp);
+
+       XFREE(MTYPE_BGP_PROCESS_QUEUE, pqnode);
 }
 
 void bgp_process_queue_init(void)
@@ -2221,7 +2239,7 @@ void bgp_process_queue_init(void)
                }
        }
 
-       bm->process_main_queue->spec.workfunc = &bgp_process_main;
+       bm->process_main_queue->spec.workfunc = &bgp_process_wq;
        bm->process_main_queue->spec.del_item_data = &bgp_processq_del;
        bm->process_main_queue->spec.max_retries = 0;
        bm->process_main_queue->spec.hold = 50;
@@ -2229,31 +2247,56 @@ void bgp_process_queue_init(void)
        bm->process_main_queue->spec.yield = 50 * 1000L;
 }
 
+static struct bgp_process_queue *bgp_process_queue_work(struct work_queue *wq,
+                                                       struct bgp *bgp)
+{
+       struct bgp_process_queue *pqnode;
+
+       pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE, sizeof(struct bgp_process_queue));
+
+       /* unlocked in bgp_processq_del */
+       pqnode->bgp = bgp_lock(bgp);
+       STAILQ_INIT(&pqnode->pqueue);
+
+       work_queue_add(wq, pqnode);
+
+       return pqnode;
+}
+
 void bgp_process(struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
 {
+#define ARBITRARY_PROCESS_QLEN         10000
+       struct work_queue *wq = bm->process_main_queue;
        struct bgp_process_queue *pqnode;
 
        /* already scheduled for processing? */
        if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED))
                return;
 
-       if (bm->process_main_queue == NULL)
+       if (wq == NULL)
                return;
 
-       pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE,
-                        sizeof(struct bgp_process_queue));
-       if (!pqnode)
-               return;
+       /* Add route nodes to an existing work queue item until reaching the
+          limit only if is from the same BGP view and it's not an EOIU marker */
+       if (work_queue_item_count(wq)) {
+               struct work_queue_item *item = work_queue_last_item(wq);
+               pqnode = item->data;
+
+               if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) ||
+                   pqnode->bgp != bgp || pqnode->queued >= ARBITRARY_PROCESS_QLEN)
+                       pqnode = bgp_process_queue_work(wq, bgp);
+       } else
+               pqnode = bgp_process_queue_work(wq, bgp);
 
-       /* all unlocked in bgp_processq_del */
+       /* all unlocked in bgp_process_wq */
        bgp_table_lock(bgp_node_table(rn));
-       pqnode->rn = bgp_lock_node(rn);
-       pqnode->bgp = bgp;
-       bgp_lock(bgp);
-       pqnode->afi = afi;
-       pqnode->safi = safi;
-       work_queue_add(bm->process_main_queue, pqnode);
+
        SET_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED);
+       bgp_lock_node(rn);
+
+       STAILQ_INSERT_TAIL(&pqnode->pqueue, rn, pq);
+       pqnode->queued++;
+
        return;
 }
 
@@ -2264,15 +2307,9 @@ void bgp_add_eoiu_mark(struct bgp *bgp)
        if (bm->process_main_queue == NULL)
                return;
 
-       pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE,
-                        sizeof(struct bgp_process_queue));
-       if (!pqnode)
-               return;
+       pqnode = bgp_process_queue_work(bm->process_main_queue, bgp);
 
-       pqnode->rn = NULL;
-       pqnode->bgp = bgp;
-       bgp_lock(bgp);
-       work_queue_add(bm->process_main_queue, pqnode);
+       SET_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER);
 }
 
 static int bgp_maximum_prefix_restart_timer(struct thread *thread)
index 0d5706f7cb60fc34cf7e4c741aea52797d9fa7bc..a4f3b604c24c9effb4eda5a327bbde952add81be 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "mpls.h"
 #include "table.h"
+#include "queue.h"
 
 struct bgp_table {
        /* afi/safi of this table */
@@ -52,6 +53,8 @@ struct bgp_node {
 
        struct bgp_node *prn;
 
+       STAILQ_ENTRY(bgp_node) pq;
+
        mpls_label_t local_label;
 
        uint64_t version;
index 01c27920f5bab3fe863825213d629f49e913b7ba..2e18a6d44fb5605d1baf51ab376a3698e6ac233a 100644 (file)
@@ -6145,6 +6145,8 @@ DEFUN (clear_ip_bgp_all,
        IP_STR
        BGP_STR
        BGP_INSTANCE_HELP_STR
+       BGP_AFI_HELP_STR
+       BGP_SAFI_WITH_LABEL_HELP_STR
        "Clear all peers\n"
        "BGP neighbor address to clear\n"
        "BGP IPv6 neighbor to clear\n"
@@ -6153,8 +6155,6 @@ DEFUN (clear_ip_bgp_all,
        "Clear all external peers\n"
        "Clear all members of peer-group\n"
        "BGP peer-group name\n"
-       BGP_AFI_HELP_STR
-       BGP_SAFI_WITH_LABEL_HELP_STR
        BGP_SOFT_STR
        BGP_SOFT_IN_STR
        BGP_SOFT_OUT_STR
index d7733fbacd3db1a70602abb44f36b811445ab186..9d7c38c8716d498b65b1645a90189a1d626698f9 100644 (file)
@@ -1116,9 +1116,8 @@ struct peer *peer_new(struct bgp *bgp)
        peer->status = Idle;
        peer->ostatus = Idle;
        peer->cur_event = peer->last_event = peer->last_major_event = 0;
-       peer->bgp = bgp;
+       peer->bgp = bgp_lock(bgp);
        peer = peer_lock(peer); /* initial reference */
-       bgp_lock(bgp);
        peer->password = NULL;
 
        /* Set default flags.  */
@@ -3106,21 +3105,7 @@ int bgp_delete(struct bgp *bgp)
        return 0;
 }
 
-static void bgp_free(struct bgp *);
-
-void bgp_lock(struct bgp *bgp)
-{
-       ++bgp->lock;
-}
-
-void bgp_unlock(struct bgp *bgp)
-{
-       assert(bgp->lock > 0);
-       if (--bgp->lock == 0)
-               bgp_free(bgp);
-}
-
-static void bgp_free(struct bgp *bgp)
+void bgp_free(struct bgp *bgp)
 {
        afi_t afi;
        safi_t safi;
index bfdddc69b1e93bb901bbcbfa48cc4a65c943aa93..f6e7b2277f9501636a9ef31f198e87ab30c030b8 100644 (file)
@@ -1252,9 +1252,6 @@ extern int bgp_flag_set(struct bgp *, int);
 extern int bgp_flag_unset(struct bgp *, int);
 extern int bgp_flag_check(struct bgp *, int);
 
-extern void bgp_lock(struct bgp *);
-extern void bgp_unlock(struct bgp *);
-
 extern void bgp_router_id_zebra_bump(vrf_id_t, const struct prefix *);
 extern int bgp_router_id_static_set(struct bgp *, struct in_addr);
 
@@ -1395,6 +1392,20 @@ extern struct peer_af *peer_af_find(struct peer *, afi_t, safi_t);
 extern int peer_af_delete(struct peer *, afi_t, safi_t);
 
 extern void bgp_close(void);
+extern void bgp_free(struct bgp *);
+
+static inline struct bgp *bgp_lock(struct bgp *bgp)
+{
+       bgp->lock++;
+       return bgp;
+}
+
+static inline void bgp_unlock(struct bgp *bgp)
+{
+       assert(bgp->lock > 0);
+       if (--bgp->lock == 0)
+               bgp_free(bgp);
+}
 
 static inline int afindex(afi_t afi, safi_t safi)
 {
@@ -1540,10 +1551,8 @@ static inline struct vrf *bgp_vrf_lookup_by_instance_type(struct bgp *bgp)
 static inline void bgp_vrf_link(struct bgp *bgp, struct vrf *vrf)
 {
        bgp->vrf_id = vrf->vrf_id;
-       if (vrf->info != (void *)bgp) {
-               bgp_lock(bgp);
-               vrf->info = (void *)bgp;
-       }
+       if (vrf->info != (void *)bgp)
+               vrf->info = (void *)bgp_lock(bgp);
 }
 
 /* Unlink BGP instance from VRF. */
index 7e0ed9150bb8f04b2a4d75d3c8d0fe30d677677e..d63975a22bff02105ede300fb0d467b0dbfd905f 100644 (file)
@@ -1224,8 +1224,8 @@ static int rfapiVpnBiSamePtUn(struct bgp_info *bi1, struct bgp_info *bi2)
 
        switch (pfx_un1.family) {
        case AF_INET:
-               if (!IPV4_ADDR_SAME(&pfx_un1.u.prefix4.s_addr,
-                                   &pfx_un2.u.prefix4.s_addr))
+               if (!IPV4_ADDR_SAME(&pfx_un1.u.prefix4,
+                                   &pfx_un2.u.prefix4))
                        return 0;
                break;
        case AF_INET6:
index d4ff9451c373edc536c9a53f73ce22cc8a625f58..3e9b5ed6b97aff27ac3089897499ce3d8ae6c39b 100644 (file)
@@ -142,13 +142,13 @@ DEFUN (no_debug_bgp_vnc_all,
  *     show/save
  ***********************************************************************/
 
-DEFUN (show_debugging_bgp_vnc,
-       show_debugging_bgp_vnc_cmd,
-       "show debugging bgp vnc",
-       SHOW_STR
-       DEBUG_STR
-       BGP_STR
-       VNC_STR)
+DEFUN_NOSH (show_debugging_bgp_vnc,
+           show_debugging_bgp_vnc_cmd,
+           "show debugging bgp vnc",
+           SHOW_STR
+           DEBUG_STR
+           BGP_STR
+           VNC_STR)
 {
        size_t i;
 
index 574992342fd1f0ce45fd9d0f71fa3bb2f2eedcda..bf66e00f9fbcb9b0e3220d08816a87eb011cc2bd 100755 (executable)
@@ -344,7 +344,7 @@ AC_ARG_ENABLE(shell_access,
 AC_ARG_ENABLE(rtadv,
   AS_HELP_STRING([--disable-rtadv], [disable IPV6 router advertisement feature]))
 AC_ARG_ENABLE(irdp,
-  AS_HELP_STRING([--enable-irdp], [enable IRDP server support in zebra]))
+  AS_HELP_STRING([--disable-irdp], [enable IRDP server support in zebra (default if supported)]))
 AC_ARG_ENABLE(capabilities,
   AS_HELP_STRING([--disable-capabilities], [disable using POSIX capabilities]))
 AC_ARG_ENABLE(rusage,
@@ -570,10 +570,6 @@ else
   AC_MSG_RESULT(no)
 fi
 
-if test "${enable_irdp}" = "yes"; then
-  AC_DEFINE(HAVE_IRDP,, IRDP )
-fi
-
 if test x"${enable_user}" = x"no"; then
   enable_user=""
 else
@@ -1370,7 +1366,7 @@ fi
 dnl ------------------
 dnl check Net-SNMP library
 dnl ------------------
-if test "${enable_snmp}" != ""; then
+if test "${enable_snmp}" != "" -a "${enable_snmp}" != "no"; then
    AC_PATH_TOOL([NETSNMP_CONFIG], [net-snmp-config], [no])
    if test x"$NETSNMP_CONFIG" = x"no"; then
       AC_MSG_ERROR([--enable-snmp given but unable to find net-snmp-config])
@@ -1479,17 +1475,27 @@ AC_CHECK_MEMBERS([struct sockaddr.sa_len,
 dnl ---------------------------
 dnl IRDP/pktinfo/icmphdr checks
 dnl ---------------------------
-AC_CHECK_TYPES([struct in_pktinfo], 
- [AC_CHECK_TYPES([struct icmphdr],
-   [if test "${enable_irdp}" != "no"; then
-      AC_DEFINE(HAVE_IRDP,, IRDP)
-    fi],
-   [if test "${enable_irdp}" = "yes"; then
-      AC_MSG_ERROR(['IRDP requires in_pktinfo at the moment!'])
-    fi], [FRR_INCLUDES])],
- [if test "${enable_irdp}" = "yes"; then
-    AC_MSG_ERROR(['IRDP requires in_pktinfo at the moment!'])
-  fi], [FRR_INCLUDES])
+
+AC_CHECK_TYPES([struct in_pktinfo], [
+  AC_CHECK_TYPES([struct icmphdr], [
+    IRDP=true
+  ], [
+    IRDP=false
+  ], [FRR_INCLUDES])
+], [
+  IRDP=false
+], [FRR_INCLUDES])
+
+case "${enable_irdp}" in
+yes)
+  $IRDP || AC_MSG_ERROR(['IRDP requires in_pktinfo at the moment!'])
+  ;;
+no)
+  IRDP=false
+  ;;
+esac
+
+AM_CONDITIONAL(IRDP, $IRDP)
 
 dnl -----------------------
 dnl checking for IP_PKTINFO
diff --git a/doc/code/.gitignore b/doc/code/.gitignore
new file mode 100644 (file)
index 0000000..0505537
--- /dev/null
@@ -0,0 +1,3 @@
+/_templates
+/_build
+!/Makefile
diff --git a/doc/code/Makefile b/doc/code/Makefile
new file mode 100644 (file)
index 0000000..056b78e
--- /dev/null
@@ -0,0 +1,216 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# User-friendly check for sphinx-build
+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
+endif
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help
+help:
+       @echo "Please use \`make <target>' where <target> is one of"
+       @echo "  html       to make standalone HTML files"
+       @echo "  dirhtml    to make HTML files named index.html in directories"
+       @echo "  singlehtml to make a single large HTML file"
+       @echo "  pickle     to make pickle files"
+       @echo "  json       to make JSON files"
+       @echo "  htmlhelp   to make HTML files and a HTML help project"
+       @echo "  qthelp     to make HTML files and a qthelp project"
+       @echo "  applehelp  to make an Apple Help Book"
+       @echo "  devhelp    to make HTML files and a Devhelp project"
+       @echo "  epub       to make an epub"
+       @echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+       @echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+       @echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+       @echo "  text       to make text files"
+       @echo "  man        to make manual pages"
+       @echo "  texinfo    to make Texinfo files"
+       @echo "  info       to make Texinfo files and run them through makeinfo"
+       @echo "  gettext    to make PO message catalogs"
+       @echo "  changes    to make an overview of all changed/added/deprecated items"
+       @echo "  xml        to make Docutils-native XML files"
+       @echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
+       @echo "  linkcheck  to check all external links for integrity"
+       @echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+       @echo "  coverage   to run coverage check of the documentation (if enabled)"
+
+.PHONY: clean
+clean:
+       rm -rf $(BUILDDIR)/*
+
+.PHONY: html
+html:
+       $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+.PHONY: dirhtml
+dirhtml:
+       $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+.PHONY: singlehtml
+singlehtml:
+       $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+       @echo
+       @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+.PHONY: pickle
+pickle:
+       $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+       @echo
+       @echo "Build finished; now you can process the pickle files."
+
+.PHONY: json
+json:
+       $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+       @echo
+       @echo "Build finished; now you can process the JSON files."
+
+.PHONY: htmlhelp
+htmlhelp:
+       $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+       @echo
+       @echo "Build finished; now you can run HTML Help Workshop with the" \
+             ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+.PHONY: qthelp
+qthelp:
+       $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+       @echo
+       @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+             ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+       @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/FRR.qhcp"
+       @echo "To view the help file:"
+       @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/FRR.qhc"
+
+.PHONY: applehelp
+applehelp:
+       $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
+       @echo
+       @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
+       @echo "N.B. You won't be able to view it unless you put it in" \
+             "~/Library/Documentation/Help or install it in your application" \
+             "bundle."
+
+.PHONY: devhelp
+devhelp:
+       $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+       @echo
+       @echo "Build finished."
+       @echo "To view the help file:"
+       @echo "# mkdir -p $$HOME/.local/share/devhelp/FRR"
+       @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/FRR"
+       @echo "# devhelp"
+
+.PHONY: epub
+epub:
+       $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+       @echo
+       @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+.PHONY: latex
+latex:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo
+       @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+       @echo "Run \`make' in that directory to run these through (pdf)latex" \
+             "(use \`make latexpdf' here to do that automatically)."
+
+.PHONY: latexpdf
+latexpdf:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through pdflatex..."
+       $(MAKE) -C $(BUILDDIR)/latex all-pdf
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: latexpdfja
+latexpdfja:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through platex and dvipdfmx..."
+       $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: text
+text:
+       $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+       @echo
+       @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+.PHONY: man
+man:
+       $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+       @echo
+       @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+.PHONY: texinfo
+texinfo:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo
+       @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+       @echo "Run \`make' in that directory to run these through makeinfo" \
+             "(use \`make info' here to do that automatically)."
+
+.PHONY: info
+info:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo "Running Texinfo files through makeinfo..."
+       make -C $(BUILDDIR)/texinfo info
+       @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+.PHONY: gettext
+gettext:
+       $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+       @echo
+       @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+.PHONY: changes
+changes:
+       $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+       @echo
+       @echo "The overview file is in $(BUILDDIR)/changes."
+
+.PHONY: linkcheck
+linkcheck:
+       $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+       @echo
+       @echo "Link check complete; look for any errors in the above output " \
+             "or in $(BUILDDIR)/linkcheck/output.txt."
+
+.PHONY: doctest
+doctest:
+       $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+       @echo "Testing of doctests in the sources finished, look at the " \
+             "results in $(BUILDDIR)/doctest/output.txt."
+
+.PHONY: coverage
+coverage:
+       $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
+       @echo "Testing of coverage in the sources finished, look at the " \
+             "results in $(BUILDDIR)/coverage/python.txt."
+
+.PHONY: xml
+xml:
+       $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+       @echo
+       @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+.PHONY: pseudoxml
+pseudoxml:
+       $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+       @echo
+       @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
diff --git a/doc/code/conf.py b/doc/code/conf.py
new file mode 100644 (file)
index 0000000..38be7f2
--- /dev/null
@@ -0,0 +1,293 @@
+# -*- coding: utf-8 -*-
+#
+# FRR documentation build configuration file, created by
+# sphinx-quickstart on Tue Jan 31 16:00:52 2017.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys
+import os
+import re
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ['sphinx.ext.todo']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'FRR'
+copyright = u'2017, FRR'
+author = u'FRR'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+
+# The short X.Y version.
+version = u'?.?'
+# The full version, including alpha/beta/rc tags.
+release = u'?.?-?'
+
+val = re.compile('^S\["([^"]+)"\]="(.*)"$')
+with open('../../config.status', 'r') as cfgstatus:
+    for ln in cfgstatus.readlines():
+        m = val.match(ln)
+        if m is None: continue
+        if m.group(1) == 'PACKAGE_VERSION':
+            release = m.group(2)
+            version = release.split('-')[0]
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = True
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'sphinx_rtd_theme'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Language to be used for generating the HTML full-text search index.
+# Sphinx supports the following languages:
+#   'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
+#   'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
+#html_search_language = 'en'
+
+# A dictionary with options for the search language support, empty by default.
+# Now only 'ja' uses this config value
+#html_search_options = {'type': 'default'}
+
+# The name of a javascript file (relative to the configuration directory) that
+# implements a search results scorer. If empty, the default will be used.
+#html_search_scorer = 'scorer.js'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'FRRdoc'
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+
+# Latex figure (float) alignment
+#'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+#  author, documentclass [howto, manual, or own class]).
+latex_documents = [
+    (master_doc, 'FRR.tex', u'FRR Documentation',
+     u'FRR', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    (master_doc, 'frr', u'FRR Documentation',
+     [author], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+    (master_doc, 'FRR', u'FRR Documentation',
+     author, 'FRR', 'One line description of project.',
+     'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
diff --git a/doc/code/hooks.rst b/doc/code/hooks.rst
new file mode 100644 (file)
index 0000000..0afa297
--- /dev/null
@@ -0,0 +1,171 @@
+.. highlight:: c
+
+Hooks
+=====
+
+Libfrr provides type-safe subscribable hook points where other pieces of
+code can add one or more callback functions.  "type-safe" in this case
+applies to the function pointers used for subscriptions.  The
+implementations checks (at compile-time) wheter a callback to be added has
+the appropriate function signature (parameters) for the hook.
+
+Example:
+
+.. code-block:: c
+     :caption: mydaemon.h
+
+     #include "hook.h"
+     DECLARE_HOOK(some_update_event, (struct eventinfo *info), (info))
+
+.. code-block:: c
+     :caption: mydaemon.c
+
+     #include "mydaemon.h"
+     DEFINE_HOOK(some_update_event, (struct eventinfo *info), (info))
+     ...
+     hook_call(some_update_event, info);
+
+.. code-block:: c
+     :caption: mymodule.c
+
+     #include "mydaemon.h"
+     static int event_handler(struct eventinfo *info);
+     ...
+     hook_register(some_update_event, event_handler);
+
+Do not use parameter names starting with "hook", these can collide with
+names used by the hook code itself.
+
+
+Return values
+-------------
+
+Callbacks to be placed on hooks always return "int" for now;  hook_call will
+sum up the return values from each called function.  (The default is 0 if no
+callbacks are registered.)
+
+There are no pre-defined semantics for the value, in most cases it is
+ignored.  For success/failure indication, 0 should be success, and
+handlers should make sure to only return 0 or 1 (not -1 or other values).
+
+There is no built-in way to abort executing a chain after a failure of one
+of the callbacks.  If this is needed, the hook can use an extra
+``bool *aborted`` argument.
+
+
+Priorities
+----------
+
+Hooks support a "priority" value for ordering registered calls
+relative to each other.  The priority is a signed integer where lower
+values are called earlier.  There are also "Koohs", which is hooks with
+reverse priority ordering (for cleanup/deinit hooks, so you can use the
+same priority value).
+
+Recommended priority value ranges are:
+
+======================== ===================================================
+Range                    Usage
+------------------------ ---------------------------------------------------
+ -999 ...     0 ...  999 main executable / daemon, or library
+
+-1999 ... -1000          modules registering calls that should run before
+                         the daemon's bits
+
+1000 ... 1999            modules' calls that should run after daemon's
+                         (includes default value: 1000)
+======================== ===================================================
+
+Note: the default value is 1000, based on the following 2 expectations:
+
+- most hook_register() usage will be in loadable modules
+- usage of hook_register() in the daemon itself may need relative ordering
+  to itself, making an explicit value the expected case
+
+The priority value is passed as extra argument on hook_register_prio() /
+hook_register_arg_prio().  Whether a hook runs in reverse is determined
+solely by the code defining / calling the hook.  (DECLARE_KOOH is actually
+the same thing as DECLARE_HOOK, it's just there to make it obvious.)
+
+
+Definition
+----------
+
+.. c:macro:: DECLARE_HOOK(name, arglist, passlist)
+.. c:macro:: DECLARE_KOOH(name, arglist, passlist)
+
+   :param name: Name of the hook to be defined
+   :param arglist: Function definition style parameter list in braces.
+   :param passlist: List of the same parameters without their types.
+
+   Note:  the second and third macro args must be the hook function's
+   parameter list, with the same names for each parameter.  The second
+   macro arg is with types (used for defining things), the third arg is
+   just the names (used for passing along parameters).
+
+   This macro must be placed in a header file;  this header file must be
+   included to register a callback on the hook.
+
+   Examples:
+
+   .. code-block:: c
+
+      DECLARE_HOOK(foo, (), ())
+      DECLARE_HOOK(bar, (int arg), (arg))
+      DECLARE_HOOK(baz, (const void *x, in_addr_t y), (x, y))
+
+.. c:macro:: DEFINE_HOOK(name, arglist, passlist)
+
+   Implements an hook.  Each ``DECLARE_HOOK`` must have be accompanied by
+   exactly one ``DEFINE_HOOK``, which needs to be placed in a source file.
+   **The hook can only be called from this source file.**  This is intentional
+   to avoid overloading and/or misusing hooks for distinct purposes.
+
+   The compiled source file will include a global symbol with the name of the
+   hook prefixed by `_hook_`.  Trying to register a callback for a hook that
+   doesn't exist will therefore result in a linker error, or a module
+   load-time error for dynamic modules.
+
+.. c:macro:: DEFINE_KOOH(name, arglist, passlist)
+
+   Same as ``DEFINE_HOOK``, but the sense of priorities / order of callbacks
+   is reversed.  This should be used for cleanup hooks.
+
+.. c:function:: int hook_call(name, ...)
+
+   Calls the specified named hook.  Parameters to the hook are passed right
+   after the hook name, e.g.:
+
+   .. code-block:: c
+
+      hook_call(foo);
+      hook_call(bar, 0);
+      hook_call(baz, NULL, INADDR_ANY);
+
+   Returns the sum of return values from all callbacks.  The ``DEFINE_HOOK``
+   statement for the hook must be placed in the file before any ``hook_call``
+   use of the hook.
+
+
+Callback registration
+---------------------
+
+.. c:function:: void hook_register(name, int (*callback)(...))
+.. c:function:: void hook_register_prio(name, int priority, int (*callback)(...))
+.. c:function:: void hook_register_arg(name, int (*callback)(void *arg, ...), void *arg)
+.. c:function:: void hook_register_arg_prio(name, int priority, int (*callback)(void *arg, ...), void *arg)
+
+   Register a callback with an hook.  If the caller needs to pass an extra
+   argument to the callback, the _arg variant can be used and the extra
+   parameter will be passed as first argument to the callback.  There is no
+   typechecking for this argument.
+
+   The priority value is used as described above.  The variants without a
+   priority parameter use 1000 as priority value.
+
+.. c:function:: void hook_unregister(name, int (*callback)(...))
+.. c:function:: void hook_unregister_arg(name, int (*callback)(void *arg, ...), void *arg)
+
+   Removes a previously registered callback from a hook.  Note that there
+   is no _prio variant of these calls.  The priority value is only used during
+   registration.
diff --git a/doc/code/index.rst b/doc/code/index.rst
new file mode 100644 (file)
index 0000000..79647d0
--- /dev/null
@@ -0,0 +1,18 @@
+Welcome to FRR's documentation!
+===============================
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   library
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/doc/code/library.rst b/doc/code/library.rst
new file mode 100644 (file)
index 0000000..dd46021
--- /dev/null
@@ -0,0 +1,10 @@
+libfrr library facilities
+=========================
+
+.. toctree::
+   :maxdepth: 2
+
+   memtypes
+   hooks
+
+
diff --git a/doc/code/memtypes.rst b/doc/code/memtypes.rst
new file mode 100644 (file)
index 0000000..62d211e
--- /dev/null
@@ -0,0 +1,117 @@
+.. highlight:: c
+
+Memtypes
+========
+
+FRR includes wrappers arround ``malloc()`` and ``free()`` that count the number
+of objects currently allocated, for each of a defined ``MTYPE``.
+
+To this extent, there are `memory groups` and `memory types`.  Each memory
+type must belong to a memory group, this is used just to provide some basic
+structure.
+
+Example:
+
+.. code-block:: c
+     :caption: mydaemon.h
+
+     DECLARE_MGROUP(MYDAEMON)
+     DECLARE_MTYPE(MYNEIGHBOR)
+
+.. code-block:: c
+     :caption: mydaemon.c
+
+     DEFINE_MGROUP(      MYDAEMON, "My daemon's memory")
+     DEFINE_MTYPE(       MYDAEMON, MYNEIGHBOR,     "Neighbor entry")
+     DEFINE_MTYPE_STATIC(MYDAEMON, MYNEIGHBORNAME, "Neighbor name")
+
+     struct neigh *neighbor_new(const char *name)
+     {
+        struct neigh *n = XMALLOC(MYNEIGHBOR, sizeof(*n));
+        n->name = XSTRDUP(MYNEIGHBORNAME, name);
+        return n;
+     }
+
+     void neighbor_free(struct neigh *n)
+     {
+        XFREE(MYNEIGHBORNAME, n->name);
+        XFREE(MYNEIGHBOR, n);
+     }
+
+
+Definition
+----------
+
+.. c:macro:: DECLARE_MGROUP(name)
+
+   This macro forward-declares a memory group and should be placed in a
+   ``.h`` file.  It expands to an ``extern struct memgroup`` statement.
+
+.. c:macro:: DEFINE_MGROUP(mname, description)
+
+   Defines/implements a memory group.  Must be placed into exactly one ``.c``
+   file (multiple inclusion will result in a link-time symbol conflict).
+
+   Contains additional logic (constructor and destructor) to register the
+   memory group in a global list.
+
+.. c:macro:: DECLARE_MTYPE(name)
+
+   Forward-declares a memory type and makes ``MTYPE_name`` available for use.
+   Note that the ``MTYPE_`` prefix must not be included in the name, it is
+   automatically prefixed.
+
+   ``MTYPE_name`` is created as a `static const` symbol, i.e. a compile-time
+   constant.  It refers to an ``extern struct memtype _mt_name``, where `name`
+   is replaced with the actual name.
+
+.. c:macro:: DEFINE_MTYPE(group, name, description)
+
+   Define/implement a memory type, must be placed into exactly one ``.c``
+   file (multiple inclusion will result in a link-time symbol conflict).
+
+   Like ``DEFINE_MGROUP``, this contains actual code to register the MTYPE
+   under its group.
+
+.. c:macro:: DEFINE_MTYPE_STATIC(group, name, description)
+
+   Same as ``DEFINE_MTYPE``, but the ``DEFINE_MTYPE_STATIC`` variant places
+   the C ``static`` keyword on the definition, restricting the MTYPE's
+   availability to the current source file.  This should be appropriate in
+   >80% of cases.
+
+   .. todo::
+   
+      Daemons currently have ``daemon_memory.[ch]`` files listing all of
+      their MTYPEs.  This is not how it should be, most of these types
+      should be moved into the appropriate files where they are used.
+      Only a few MTYPEs should remain non-static after that.
+
+
+Usage
+-----
+
+.. c:function:: void *XMALLOC(struct memtype *mtype, size_t size)
+
+.. c:function:: void *XCALLOC(struct memtype *mtype, size_t size)
+
+.. c:function:: void *XSTRDUP(struct memtype *mtype, size_t size)
+
+   Allocation wrappers for malloc/calloc/realloc/strdup, taking an extra
+   mtype parameter.
+
+.. c:function:: void *XREALLOC(struct memtype *mtype, void *ptr, size_t size)
+
+   Wrapper around realloc() with MTYPE tracking.  Note that ``ptr`` may
+   be NULL, in which case the function does the same as XMALLOC (regardless
+   of whether the system realloc() supports this.)
+
+.. c:function:: void XFREE(struct memtype *mtype, void *ptr)
+
+   Wrapper around free(), again taking an extra mtype parameter.  This is
+   actually a macro, with the following additional properties:
+
+   - the macro contains ``ptr = NULL``
+   - if ptr is NULL, no operation is performed (as is guaranteed by system
+     implementations.)  Do not surround XFREE with ``if (ptr != NULL)``
+     checks.
index aca6e5981601ab50f7aa83253403c1b8def48d88..0cb1ee5876049e6e4c65ccbe3980283d1edf1eec 100644 (file)
@@ -323,12 +323,12 @@ void show_ip_eigrp_neighbor_entry(struct vty *vty, struct eigrp *eigrp,
 }
 
 
-DEFUN (show_debugging_eigrp,
-       show_debugging_eigrp_cmd,
-       "show debugging eigrp",
-       SHOW_STR
-       DEBUG_STR
-       EIGRP_STR)
+DEFUN_NOSH (show_debugging_eigrp,
+           show_debugging_eigrp_cmd,
+           "show debugging [eigrp]",
+           SHOW_STR
+           DEBUG_STR
+           EIGRP_STR)
 {
        int i;
 
index d56767fafc767c59b416579c57b52445069d1bea..ef10ebf54c7f59ea57b111470ed13fa84ac67252 100644 (file)
@@ -405,6 +405,20 @@ void eigrp_hello_receive(struct eigrp *eigrp, struct ip *iph,
                           inet_ntoa(nbr->src));
 }
 
+u_int32_t FRR_MAJOR;
+u_int32_t FRR_MINOR;
+
+void eigrp_sw_version_initialize(void)
+{
+       char ver_string[] = VERSION;
+       char *dash = strstr(ver_string, "-");
+
+       if (dash)
+               dash[0] = '\0';
+
+       sscanf(ver_string, "%d.%d", &FRR_MAJOR, &FRR_MINOR);
+}
+
 /**
  * @fn eigrp_sw_version_encode
  *
@@ -425,10 +439,8 @@ static u_int16_t eigrp_sw_version_encode(struct stream *s)
        stream_putw(s, EIGRP_TLV_SW_VERSION);
        stream_putw(s, length);
 
-       // encode the version of quagga we're running
-       // DVS: need to figure out a cleaner way to do this
-       stream_putc(s, 0);  //!< major os version
-       stream_putc(s, 99); //!< minor os version
+       stream_putc(s, FRR_MAJOR);  //!< major os version
+       stream_putc(s, FRR_MINOR); //!< minor os version
 
        /* and the core eigrp version */
        stream_putc(s, EIGRP_MAJOR_VERSION);
index 7f05e147038c17778d1dd79b32a51e70e2aa6a2a..22b6fa394f8a43070fad0b0115dbb93b69c895cb 100644 (file)
@@ -150,8 +150,8 @@ struct list *eigrp_iflist;
 void eigrp_if_init()
 {
        /* Initialize Zebra interface data structure. */
-       if_add_hook(IF_NEW_HOOK, eigrp_if_new_hook);
-       if_add_hook(IF_DELETE_HOOK, eigrp_if_delete_hook);
+       hook_register_prio(if_add, 0, eigrp_if_new_hook);
+       hook_register_prio(if_del, 0, eigrp_if_delete_hook);
 }
 
 int eigrp_if_new_hook(struct interface *ifp)
index 4c99821d3c4b98ab8a5aca3e2c7820218621c785..705e04b34dda793d001c199fe0ed62da06664710 100644 (file)
@@ -159,6 +159,8 @@ int main(int argc, char **argv, char **envp)
                }
        }
 
+       eigrp_sw_version_initialize();
+
        /* EIGRP master init. */
        eigrp_master_init();
        eigrp_om->master = frr_init();
index 3b4a57ed54a91ee6fdbe03b3cd522bc43483958d..72aaef1b37de27d1b4a4f69bf78ff4ba714d2b33 100644 (file)
@@ -527,7 +527,7 @@ int eigrp_read(struct thread *thread)
 
        /* Self-originated packet should be discarded silently. */
        if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src)
-           || (IPV4_ADDR_SAME(&iph->ip_src.s_addr, &ei->address->u.prefix4))) {
+           || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address->u.prefix4))) {
                if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
                        zlog_debug(
                                "eigrp_read[%s]: Dropping self-originated packet",
index 03fe412f1f84e79f016d1c247310281fa9a5ac06..e72048ecc39572c963d8653f380cf8bc1093a3d3 100644 (file)
@@ -71,6 +71,7 @@ extern int eigrp_unack_multicast_packet_retrans(struct thread *);
  * untill there is reason to have their own header, these externs are found in
  * eigrp_hello.c
  */
+extern void eigrp_sw_version_initialize(void);
 extern void eigrp_hello_send(struct eigrp_interface *, u_char,
                             struct in_addr *);
 extern void eigrp_hello_send_ack(struct eigrp_neighbor *);
index 9622dcdbc4e480c424a7f20fb231920385cfe35d..a1aa87e396d15ecbfc7333a90eca2c6c12304a4a 100644 (file)
@@ -1336,8 +1336,8 @@ int isis_if_delete_hook(struct interface *ifp)
 void isis_circuit_init()
 {
        /* Initialize Zebra interface data structure */
-       if_add_hook(IF_NEW_HOOK, isis_if_new_hook);
-       if_add_hook(IF_DELETE_HOOK, isis_if_delete_hook);
+       hook_register_prio(if_add, 0, isis_if_new_hook);
+       hook_register_prio(if_del, 0, isis_if_delete_hook);
 
        /* Install interface node */
        install_node(&interface_node, isis_interface_config_write);
index 2a19465a01feafa4e269060d477699efc249961d..17d8ad3c0b887924c148fa49395789ee65896083 100644 (file)
@@ -181,7 +181,7 @@ DEFUN (no_isis_passive,
 
        if (if_is_loopback(circuit->interface)) {
                vty_out(vty, "Can't set no passive for loopback interface\n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        isis_circuit_passive_set(circuit, 0);
@@ -206,7 +206,7 @@ DEFUN (isis_circuit_type,
        is_type = string2circuit_t(argv[idx_level]->arg);
        if (!is_type) {
                vty_out(vty, "Unknown circuit-type \n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        if (circuit->state == C_STATE_UP
@@ -214,7 +214,7 @@ DEFUN (isis_circuit_type,
            && circuit->area->is_type != is_type) {
                vty_out(vty, "Invalid circuit level for area %s.\n",
                        circuit->area->area_tag);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
        isis_circuit_is_type_set(circuit, is_type);
 
@@ -262,7 +262,7 @@ DEFUN (isis_network,
        if (isis_circuit_circ_type_set(circuit, CIRCUIT_T_P2P)) {
                vty_out(vty,
                        "isis network point-to-point is valid only on broadcast interfaces\n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        return CMD_SUCCESS;
@@ -283,7 +283,7 @@ DEFUN (no_isis_network,
        if (isis_circuit_circ_type_set(circuit, CIRCUIT_T_BROADCAST)) {
                vty_out(vty,
                        "isis network point-to-point is valid only on broadcast interfaces\n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        return CMD_SUCCESS;
@@ -313,7 +313,7 @@ DEFUN (isis_passwd,
                                                       argv[idx_word]->arg);
        if (rv) {
                vty_out(vty, "Too long circuit password (>254)\n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        return CMD_SUCCESS;
@@ -355,7 +355,7 @@ DEFUN (isis_priority,
        prio = atoi(argv[idx_number]->arg);
        if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) {
                vty_out(vty, "Invalid priority %d - should be <0-127>\n", prio);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->priority[0] = prio;
@@ -400,7 +400,7 @@ DEFUN (isis_priority_l1,
        prio = atoi(argv[idx_number]->arg);
        if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) {
                vty_out(vty, "Invalid priority %d - should be <0-127>\n", prio);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->priority[0] = prio;
@@ -444,7 +444,7 @@ DEFUN (isis_priority_l2,
        prio = atoi(argv[idx_number]->arg);
        if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) {
                vty_out(vty, "Invalid priority %d - should be <0-127>\n", prio);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->priority[1] = prio;
@@ -494,7 +494,7 @@ DEFUN (isis_metric,
                        "Invalid metric %d - should be <0-63> "
                        "when narrow metric type enabled\n",
                        met);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        /* RFC4444 */
@@ -504,7 +504,7 @@ DEFUN (isis_metric,
                        "Invalid metric %d - should be <0-16777215> "
                        "when wide metric type enabled\n",
                        met);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        isis_circuit_metric_set(circuit, IS_LEVEL_1, met);
@@ -554,7 +554,7 @@ DEFUN (isis_metric_l1,
                        "Invalid metric %d - should be <0-63> "
                        "when narrow metric type enabled\n",
                        met);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        /* RFC4444 */
@@ -564,7 +564,7 @@ DEFUN (isis_metric_l1,
                        "Invalid metric %d - should be <0-16777215> "
                        "when wide metric type enabled\n",
                        met);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        isis_circuit_metric_set(circuit, IS_LEVEL_1, met);
@@ -613,7 +613,7 @@ DEFUN (isis_metric_l2,
                        "Invalid metric %d - should be <0-63> "
                        "when narrow metric type enabled\n",
                        met);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        /* RFC4444 */
@@ -623,7 +623,7 @@ DEFUN (isis_metric_l2,
                        "Invalid metric %d - should be <0-16777215> "
                        "when wide metric type enabled\n",
                        met);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        isis_circuit_metric_set(circuit, IS_LEVEL_2, met);
@@ -667,7 +667,7 @@ DEFUN (isis_hello_interval,
        if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) {
                vty_out(vty, "Invalid hello-interval %d - should be <1-600>\n",
                        interval);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->hello_interval[0] = (u_int16_t)interval;
@@ -714,7 +714,7 @@ DEFUN (isis_hello_interval_l1,
        if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) {
                vty_out(vty, "Invalid hello-interval %ld - should be <1-600>\n",
                        interval);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->hello_interval[0] = (u_int16_t)interval;
@@ -760,7 +760,7 @@ DEFUN (isis_hello_interval_l2,
        if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) {
                vty_out(vty, "Invalid hello-interval %ld - should be <1-600>\n",
                        interval);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->hello_interval[1] = (u_int16_t)interval;
@@ -806,7 +806,7 @@ DEFUN (isis_hello_multiplier,
                vty_out(vty,
                        "Invalid hello-multiplier %d - should be <2-100>\n",
                        mult);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->hello_multiplier[0] = (u_int16_t)mult;
@@ -854,7 +854,7 @@ DEFUN (isis_hello_multiplier_l1,
                vty_out(vty,
                        "Invalid hello-multiplier %d - should be <2-100>\n",
                        mult);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->hello_multiplier[0] = (u_int16_t)mult;
@@ -901,7 +901,7 @@ DEFUN (isis_hello_multiplier_l2,
                vty_out(vty,
                        "Invalid hello-multiplier %d - should be <2-100>\n",
                        mult);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->hello_multiplier[1] = (u_int16_t)mult;
@@ -979,7 +979,7 @@ DEFUN (csnp_interval,
        if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) {
                vty_out(vty, "Invalid csnp-interval %lu - should be <1-600>\n",
                        interval);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->csnp_interval[0] = (u_int16_t)interval;
@@ -1026,7 +1026,7 @@ DEFUN (csnp_interval_l1,
        if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) {
                vty_out(vty, "Invalid csnp-interval %lu - should be <1-600>\n",
                        interval);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->csnp_interval[0] = (u_int16_t)interval;
@@ -1072,7 +1072,7 @@ DEFUN (csnp_interval_l2,
        if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) {
                vty_out(vty, "Invalid csnp-interval %lu - should be <1-600>\n",
                        interval);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->csnp_interval[1] = (u_int16_t)interval;
@@ -1117,7 +1117,7 @@ DEFUN (psnp_interval,
        if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) {
                vty_out(vty, "Invalid psnp-interval %lu - should be <1-120>\n",
                        interval);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->psnp_interval[0] = (u_int16_t)interval;
@@ -1164,7 +1164,7 @@ DEFUN (psnp_interval_l1,
        if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) {
                vty_out(vty, "Invalid psnp-interval %lu - should be <1-120>\n",
                        interval);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->psnp_interval[0] = (u_int16_t)interval;
@@ -1210,7 +1210,7 @@ DEFUN (psnp_interval_l2,
        if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) {
                vty_out(vty, "Invalid psnp-interval %lu - should be <1-120>\n",
                        interval);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        circuit->psnp_interval[1] = (u_int16_t)interval;
@@ -1253,12 +1253,12 @@ DEFUN (circuit_topology,
        if (circuit->area && circuit->area->oldmetric) {
                vty_out(vty,
                        "Multi topology IS-IS can only be used with wide metrics\n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        if (mtid == (uint16_t)-1) {
                vty_out(vty, "Don't know topology '%s'\n", arg);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        return isis_circuit_mt_enabled_set(circuit, mtid, true);
@@ -1281,12 +1281,12 @@ DEFUN (no_circuit_topology,
        if (circuit->area && circuit->area->oldmetric) {
                vty_out(vty,
                        "Multi topology IS-IS can only be used with wide metrics\n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        if (mtid == (uint16_t)-1) {
                vty_out(vty, "Don't know topology '%s'\n", arg);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        return isis_circuit_mt_enabled_set(circuit, mtid, false);
@@ -1298,11 +1298,11 @@ static int validate_metric_style_narrow(struct vty *vty, struct isis_area *area)
        struct listnode *node;
 
        if (!vty)
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
 
        if (!area) {
                vty_out(vty, "ISIS area is invalid\n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
@@ -1311,14 +1311,14 @@ static int validate_metric_style_narrow(struct vty *vty, struct isis_area *area)
                    && (circuit->te_metric[0] > MAX_NARROW_LINK_METRIC)) {
                        vty_out(vty, "ISIS circuit %s metric is invalid\n",
                                circuit->interface->name);
-                       return CMD_ERR_AMBIGUOUS;
+                       return CMD_WARNING_CONFIG_FAILED;
                }
                if ((area->is_type & IS_LEVEL_2)
                    && (circuit->is_type & IS_LEVEL_2)
                    && (circuit->te_metric[1] > MAX_NARROW_LINK_METRIC)) {
                        vty_out(vty, "ISIS circuit %s metric is invalid\n",
                                circuit->interface->name);
-                       return CMD_ERR_AMBIGUOUS;
+                       return CMD_WARNING_CONFIG_FAILED;
                }
        }
 
@@ -1345,7 +1345,7 @@ DEFUN (metric_style,
        if (area_is_mt(area)) {
                vty_out(vty,
                        "Narrow metrics cannot be used while multi topology IS-IS is active\n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        ret = validate_metric_style_narrow(vty, area);
@@ -1373,7 +1373,7 @@ DEFUN (no_metric_style,
        if (area_is_mt(area)) {
                vty_out(vty,
                        "Narrow metrics cannot be used while multi topology IS-IS is active\n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        ret = validate_metric_style_narrow(vty, area);
@@ -1470,7 +1470,7 @@ static int area_lsp_mtu_set(struct vty *vty, unsigned int lsp_mtu)
                                "ISIS area contains circuit %s, which has a maximum PDU size of %zu.\n",
                                circuit->interface->name,
                                isis_circuit_pdu_size(circuit));
-                       return CMD_ERR_AMBIGUOUS;
+                       return CMD_WARNING_CONFIG_FAILED;
                }
        }
 
@@ -1568,7 +1568,7 @@ static int set_lsp_gen_interval(struct vty *vty, struct isis_area *area,
                                "LSP gen interval %us must be less than "
                                "the LSP refresh interval %us\n",
                                interval, area->lsp_refresh[lvl - 1]);
-                       return CMD_ERR_AMBIGUOUS;
+                       return CMD_WARNING_CONFIG_FAILED;
                }
        }
 
@@ -1817,7 +1817,7 @@ static int area_max_lsp_lifetime_set(struct vty *vty, int level,
                                        "the configured LSP gen interval %us\n",
                                        refresh_interval,
                                        area->lsp_gen_interval[lvl - 1]);
-                               return CMD_ERR_AMBIGUOUS;
+                               return CMD_WARNING_CONFIG_FAILED;
                        }
                }
        }
@@ -1890,14 +1890,14 @@ static int area_lsp_refresh_interval_set(struct vty *vty, int level,
                                "LSP refresh interval %us must be greater than "
                                "the configured LSP gen interval %us\n",
                                interval, area->lsp_gen_interval[lvl - 1]);
-                       return CMD_ERR_AMBIGUOUS;
+                       return CMD_WARNING_CONFIG_FAILED;
                }
                if (interval > (area->max_lsp_lifetime[lvl - 1] - 300)) {
                        vty_out(vty,
                                "LSP refresh interval %us must be less than "
                                "the configured LSP lifetime %us less 300\n",
                                interval, area->max_lsp_lifetime[lvl - 1]);
-                       return CMD_ERR_AMBIGUOUS;
+                       return CMD_WARNING_CONFIG_FAILED;
                }
        }
 
@@ -1961,7 +1961,7 @@ static int area_passwd_set(struct vty *vty, int level,
 
        if (passwd && strlen(passwd) > 254) {
                vty_out(vty, "Too long area password (>254)\n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        type_set(area, level, passwd, snp_auth);
index 60b9367da9907baf0cb3dedd82cc19d232e21c63..f8a9df45c735a32c1a04eebc8936a4ff1e9982ec 100644 (file)
@@ -347,14 +347,14 @@ int area_net_title(struct vty *vty, const char *net_title)
                        "area address must be at least 8..20 octets long (%d)\n",
                        addr->addr_len);
                XFREE(MTYPE_ISIS_AREA_ADDR, addr);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        if (addr->area_addr[addr->addr_len - 1] != 0) {
                vty_out(vty,
                        "nsel byte (last byte) in area address must be 0\n");
                XFREE(MTYPE_ISIS_AREA_ADDR, addr);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        if (isis->sysid_set == 0) {
@@ -374,7 +374,7 @@ int area_net_title(struct vty *vty, const char *net_title)
                        vty_out(vty,
                                "System ID must not change when defining additional area addresses\n");
                        XFREE(MTYPE_ISIS_AREA_ADDR, addr);
-                       return CMD_ERR_AMBIGUOUS;
+                       return CMD_WARNING_CONFIG_FAILED;
                }
 
                /* now we see that we don't already have this address */
@@ -419,7 +419,7 @@ int area_clear_net_title(struct vty *vty, const char *net_title)
                vty_out(vty,
                        "Unsupported area address length %d, should be 8...20 \n",
                        addr.addr_len);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        memcpy(addr.area_addr, buff, (int)addr.addr_len);
@@ -758,17 +758,18 @@ void print_debug(struct vty *vty, int flags, int onoff)
                vty_out(vty, "IS-IS LSP scheduling debugging is %s\n", onoffs);
 }
 
-DEFUN (show_debugging,
-       show_debugging_isis_cmd,
-       "show debugging isis",
-       SHOW_STR
-       "State of each debugging option\n"
-       ISIS_STR)
+DEFUN_NOSH (show_debugging,
+           show_debugging_isis_cmd,
+           "show debugging [isis]",
+           SHOW_STR
+           "State of each debugging option\n"
+           ISIS_STR)
 {
-       if (isis->debugs) {
-               vty_out(vty, "IS-IS:\n");
+       vty_out (vty, "IS-IS debugging status:\n");
+
+       if (isis->debugs)
                print_debug(vty, isis->debugs, 1);
-       }
+
        return CMD_SUCCESS;
 }
 
@@ -1404,7 +1405,7 @@ static int show_isis_database(struct vty *vty, const char *argv, int ui_level)
                                (u_char)strtol((char *)number, NULL, 16);
                        pos -= 4;
                        if (strncmp(pos, ".", 1) != 0)
-                               return CMD_ERR_AMBIGUOUS;
+                               return CMD_WARNING;
                }
                if (strncmp(pos, ".", 1) == 0) {
                        memcpy(number, ++pos, 2);
@@ -1569,16 +1570,16 @@ DEFUN (isis_topology,
        if (area->oldmetric) {
                vty_out(vty,
                        "Multi topology IS-IS can only be used with wide metrics\n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        if (mtid == (uint16_t)-1) {
                vty_out(vty, "Don't know topology '%s'\n", arg);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
        if (mtid == ISIS_MT_IPV4_UNICAST) {
                vty_out(vty, "Cannot configure IPv4 unicast topology\n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        area_set_mt_enabled(area, mtid, true);
@@ -1602,16 +1603,16 @@ DEFUN (no_isis_topology,
        if (area->oldmetric) {
                vty_out(vty,
                        "Multi topology IS-IS can only be used with wide metrics\n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        if (mtid == (uint16_t)-1) {
                vty_out(vty, "Don't know topology '%s'\n", arg);
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
        if (mtid == ISIS_MT_IPV4_UNICAST) {
                vty_out(vty, "Cannot configure IPv4 unicast topology\n");
-               return CMD_ERR_AMBIGUOUS;
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
        area_set_mt_enabled(area, mtid, false);
index 0e66a1636aa88354fd83db989b961856cf05aa4f..23edb5f24d9360772166ff9e92365fa592e69d06 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef _CONTROL_H_
 #define        _CONTROL_H_
 
-#include "openbsd-queue.h"
+#include "queue.h"
 
 struct ctl_conn {
        TAILQ_ENTRY(ctl_conn)   entry;
index 43f1d36481767029d997a91d2c221f6b96a821b8..94077d16316be8b948d2a2881e4ab3fab01c0638 100644 (file)
@@ -21,7 +21,7 @@
 #ifndef _LDE_H_
 #define _LDE_H_
 
-#include "openbsd-queue.h"
+#include "queue.h"
 #include "openbsd-tree.h"
 #include "if.h"
 
index db92b936287f9caab164e9f288c3cc37d26aa3c2..be473063cdabc68d325c17fc3a6ead2122574db5 100644 (file)
@@ -684,13 +684,13 @@ DEFPY  (ldp_show_l2vpn_atom_vc,
        return (ldp_vty_show_atom_vc(vty, json));
 }
 
-DEFPY  (ldp_show_debugging_mpls_ldp,
-       ldp_show_debugging_mpls_ldp_cmd,
-       "show debugging mpls ldp",
-       "Show running system information\n"
-       "Debugging functions\n"
-       "MPLS information\n"
-       "Label Distribution Protocol\n")
+DEFUN_NOSH (ldp_show_debugging_mpls_ldp,
+           ldp_show_debugging_mpls_ldp_cmd,
+           "show debugging [mpls ldp]",
+           "Show running system information\n"
+           "Debugging functions\n"
+           "MPLS information\n"
+           "Label Distribution Protocol\n")
 {
        return (ldp_vty_show_debugging(vty));
 }
index 80af2b14e5da6accde082303f01eae3427835f10..0a586ec1c5b123671954ca019712d50e859bb0b3 100644 (file)
@@ -392,6 +392,8 @@ ldpd_shutdown(void)
        pid_t            pid;
        int              status;
 
+       frr_early_fini();
+
        /* close pipes */
        msgbuf_clear(&iev_ldpe->ibuf.w);
        close(iev_ldpe->ibuf.fd);
@@ -423,13 +425,9 @@ ldpd_shutdown(void)
 
        vrf_terminate();
        access_list_reset();
-       cmd_terminate();
-       vty_terminate();
        ldp_zebra_destroy();
-       zprivs_terminate(&ldpd_privs);
-       thread_master_free(master);
-       closezlog();
 
+       frr_fini();
        exit(0);
 }
 
index 31d0bc69b159b7c586a4ef8f6b3cfeafadb00546..5580ea5d676db10a160a7b0cf9dd60c735718ee7 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef _LDPD_H_
 #define _LDPD_H_
 
-#include "openbsd-queue.h"
+#include "queue.h"
 #include "openbsd-tree.h"
 #include "imsg.h"
 #include "thread.h"
index 74f6b852b0cda4824e89c58f755fa397aebd3d7c..ccff1e803d354f890e528b6e72c1245fca668561 100644 (file)
@@ -21,7 +21,7 @@
 #ifndef _LDPE_H_
 #define _LDPE_H_
 
-#include "openbsd-queue.h"
+#include "queue.h"
 #include "openbsd-tree.h"
 #ifdef __OpenBSD__
 #include <net/pfkeyv2.h>
diff --git a/lib/freebsd-queue.h b/lib/freebsd-queue.h
new file mode 100644 (file)
index 0000000..d198f56
--- /dev/null
@@ -0,0 +1,679 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * 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.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ *     @(#)queue.h     8.5 (Berkeley) 8/20/94
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define        _SYS_QUEUE_H_
+
+/*
+ * This file defines four types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists and tail queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ *                             SLIST   LIST    STAILQ  TAILQ
+ * _HEAD                       +       +       +       +
+ * _HEAD_INITIALIZER           +       +       +       +
+ * _ENTRY                      +       +       +       +
+ * _INIT                       +       +       +       +
+ * _EMPTY                      +       +       +       +
+ * _FIRST                      +       +       +       +
+ * _NEXT                       +       +       +       +
+ * _PREV                       -       -       -       +
+ * _LAST                       -       -       +       +
+ * _FOREACH                    +       +       +       +
+ * _FOREACH_SAFE               +       +       +       +
+ * _FOREACH_REVERSE            -       -       -       +
+ * _FOREACH_REVERSE_SAFE       -       -       -       +
+ * _INSERT_HEAD                        +       +       +       +
+ * _INSERT_BEFORE              -       +       -       +
+ * _INSERT_AFTER               +       +       +       +
+ * _INSERT_TAIL                        -       -       +       +
+ * _CONCAT                     -       -       +       +
+ * _REMOVE_AFTER               +       -       +       -
+ * _REMOVE_HEAD                        +       -       +       -
+ * _REMOVE                     +       +       +       +
+ * _SWAP                       +       +       +       +
+ *
+ */
+#ifdef QUEUE_MACRO_DEBUG
+/* Store the last 2 places the queue element or head was altered */
+struct qm_trace {
+       char *lastfile;
+       int lastline;
+       char *prevfile;
+       int prevline;
+};
+
+#define        TRACEBUF        struct qm_trace trace;
+#define        TRASHIT(x)      do {(x) = (void *)-1;} while (0)
+#define        QMD_SAVELINK(name, link)        void **name = (void *)&(link)
+
+#define QMD_TRACE_HEAD(head)                                                   \
+       do {                                                                   \
+               (head)->trace.prevline = (head)->trace.lastline;               \
+               (head)->trace.prevfile = (head)->trace.lastfile;               \
+               (head)->trace.lastline = __LINE__;                             \
+               (head)->trace.lastfile = __FILE__;                             \
+       } while (0)
+
+#define QMD_TRACE_ELEM(elem)                                                   \
+       do {                                                                   \
+               (elem)->trace.prevline = (elem)->trace.lastline;               \
+               (elem)->trace.prevfile = (elem)->trace.lastfile;               \
+               (elem)->trace.lastline = __LINE__;                             \
+               (elem)->trace.lastfile = __FILE__;                             \
+       } while (0)
+
+#else
+#define        QMD_TRACE_ELEM(elem)
+#define        QMD_TRACE_HEAD(head)
+#define        QMD_SAVELINK(name, link)
+#define        TRACEBUF
+#define        TRASHIT(x)
+#endif /* QUEUE_MACRO_DEBUG */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define SLIST_HEAD(name, type)                                                 \
+       struct name {                                                          \
+               struct type *slh_first; /* first element */                    \
+       }
+
+#define SLIST_HEAD_INITIALIZER(head)                                           \
+       {                                                                      \
+               NULL                                                           \
+       }
+
+#define SLIST_ENTRY(type)                                                      \
+       struct {                                                               \
+               struct type *sle_next; /* next element */                      \
+       }
+
+/*
+ * Singly-linked List functions.
+ */
+#define        SLIST_EMPTY(head)       ((head)->slh_first == NULL)
+
+#define        SLIST_FIRST(head)       ((head)->slh_first)
+
+#define SLIST_FOREACH(var, head, field)                                        \
+       for ((var) = SLIST_FIRST((head)); (var);                               \
+            (var) = SLIST_NEXT((var), field))
+
+#define SLIST_FOREACH_SAFE(var, head, field, tvar)                             \
+       for ((var) = SLIST_FIRST((head));                                      \
+            (var) && ((tvar) = SLIST_NEXT((var), field), 1); (var) = (tvar))
+
+#define SLIST_FOREACH_PREVPTR(var, varp, head, field)                          \
+       for ((varp) = &SLIST_FIRST((head)); ((var) = *(varp)) != NULL;         \
+            (varp) = &SLIST_NEXT((var), field))
+
+#define SLIST_INIT(head)                                                       \
+       do {                                                                   \
+               SLIST_FIRST((head)) = NULL;                                    \
+       } while (0)
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field)                               \
+       do {                                                                   \
+               SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field);      \
+               SLIST_NEXT((slistelm), field) = (elm);                         \
+       } while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field)                                    \
+       do {                                                                   \
+               SLIST_NEXT((elm), field) = SLIST_FIRST((head));                \
+               SLIST_FIRST((head)) = (elm);                                   \
+       } while (0)
+
+#define        SLIST_NEXT(elm, field)  ((elm)->field.sle_next)
+
+#define SLIST_REMOVE(head, elm, type, field)                                   \
+       do {                                                                   \
+               QMD_SAVELINK(oldnext, (elm)->field.sle_next);                  \
+               if (SLIST_FIRST((head)) == (elm)) {                            \
+                       SLIST_REMOVE_HEAD((head), field);                      \
+               } else {                                                       \
+                       struct type *curelm = SLIST_FIRST((head));             \
+                       while (SLIST_NEXT(curelm, field) != (elm))             \
+                               curelm = SLIST_NEXT(curelm, field);            \
+                       SLIST_REMOVE_AFTER(curelm, field);                     \
+               }                                                              \
+               TRASHIT(*oldnext);                                             \
+       } while (0)
+
+#define SLIST_REMOVE_AFTER(elm, field)                                         \
+       do {                                                                   \
+               SLIST_NEXT(elm, field) =                                       \
+                       SLIST_NEXT(SLIST_NEXT(elm, field), field);             \
+       } while (0)
+
+#define SLIST_REMOVE_HEAD(head, field)                                         \
+       do {                                                                   \
+               SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);  \
+       } while (0)
+
+#define SLIST_SWAP(head1, head2, type)                                         \
+       do {                                                                   \
+               struct type *swap_first = SLIST_FIRST(head1);                  \
+               SLIST_FIRST(head1) = SLIST_FIRST(head2);                       \
+               SLIST_FIRST(head2) = swap_first;                               \
+       } while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define STAILQ_HEAD(name, type)                                                \
+       struct name {                                                          \
+               struct type *stqh_first; /* first element */                   \
+               struct type **stqh_last; /* addr of last next element */       \
+       }
+
+#define STAILQ_HEAD_INITIALIZER(head)                                          \
+       {                                                                      \
+               NULL, &(head).stqh_first                                       \
+       }
+
+#define STAILQ_ENTRY(type)                                                     \
+       struct {                                                               \
+               struct type *stqe_next; /* next element */                     \
+       }
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define STAILQ_CONCAT(head1, head2)                                            \
+       do {                                                                   \
+               if (!STAILQ_EMPTY((head2))) {                                  \
+                       *(head1)->stqh_last = (head2)->stqh_first;             \
+                       (head1)->stqh_last = (head2)->stqh_last;               \
+                       STAILQ_INIT((head2));                                  \
+               }                                                              \
+       } while (0)
+
+#define        STAILQ_EMPTY(head)      ((head)->stqh_first == NULL)
+
+#define        STAILQ_FIRST(head)      ((head)->stqh_first)
+
+#define STAILQ_FOREACH(var, head, field)                                       \
+       for ((var) = STAILQ_FIRST((head)); (var);                              \
+            (var) = STAILQ_NEXT((var), field))
+
+
+#define STAILQ_FOREACH_SAFE(var, head, field, tvar)                            \
+       for ((var) = STAILQ_FIRST((head));                                     \
+            (var) && ((tvar) = STAILQ_NEXT((var), field), 1); (var) = (tvar))
+
+#define STAILQ_INIT(head)                                                      \
+       do {                                                                   \
+               STAILQ_FIRST((head)) = NULL;                                   \
+               (head)->stqh_last = &STAILQ_FIRST((head));                     \
+       } while (0)
+
+#define STAILQ_INSERT_AFTER(head, tqelm, elm, field)                           \
+       do {                                                                   \
+               if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field))  \
+                   == NULL)                                                   \
+                       (head)->stqh_last = &STAILQ_NEXT((elm), field);        \
+               STAILQ_NEXT((tqelm), field) = (elm);                           \
+       } while (0)
+
+#define STAILQ_INSERT_HEAD(head, elm, field)                                   \
+       do {                                                                   \
+               if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head)))         \
+                   == NULL)                                                   \
+                       (head)->stqh_last = &STAILQ_NEXT((elm), field);        \
+               STAILQ_FIRST((head)) = (elm);                                  \
+       } while (0)
+
+#define STAILQ_INSERT_TAIL(head, elm, field)                                   \
+       do {                                                                   \
+               STAILQ_NEXT((elm), field) = NULL;                              \
+               *(head)->stqh_last = (elm);                                    \
+               (head)->stqh_last = &STAILQ_NEXT((elm), field);                \
+       } while (0)
+
+#define STAILQ_LAST(head, type, field)                                         \
+       (STAILQ_EMPTY((head))                                                  \
+                ? NULL                                                        \
+                : ((struct type *)(void *)((char *)((head)->stqh_last)        \
+                                           - offsetof(struct type,            \
+                                                        field))))
+
+#define        STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
+
+#define STAILQ_REMOVE(head, elm, type, field)                                  \
+       do {                                                                   \
+               QMD_SAVELINK(oldnext, (elm)->field.stqe_next);                 \
+               if (STAILQ_FIRST((head)) == (elm)) {                           \
+                       STAILQ_REMOVE_HEAD((head), field);                     \
+               } else {                                                       \
+                       struct type *curelm = STAILQ_FIRST((head));            \
+                       while (STAILQ_NEXT(curelm, field) != (elm))            \
+                               curelm = STAILQ_NEXT(curelm, field);           \
+                       STAILQ_REMOVE_AFTER(head, curelm, field);              \
+               }                                                              \
+               TRASHIT(*oldnext);                                             \
+       } while (0)
+
+#define STAILQ_REMOVE_AFTER(head, elm, field)                                  \
+       do {                                                                   \
+               if ((STAILQ_NEXT(elm, field) =                                 \
+                            STAILQ_NEXT(STAILQ_NEXT(elm, field), field))      \
+                   == NULL)                                                   \
+                       (head)->stqh_last = &STAILQ_NEXT((elm), field);        \
+       } while (0)
+
+#define STAILQ_REMOVE_HEAD(head, field)                                        \
+       do {                                                                   \
+               if ((STAILQ_FIRST((head)) =                                    \
+                            STAILQ_NEXT(STAILQ_FIRST((head)), field))         \
+                   == NULL)                                                   \
+                       (head)->stqh_last = &STAILQ_FIRST((head));             \
+       } while (0)
+
+#define STAILQ_SWAP(head1, head2, type)                                        \
+       do {                                                                   \
+               struct type *swap_first = STAILQ_FIRST(head1);                 \
+               struct type **swap_last = (head1)->stqh_last;                  \
+               STAILQ_FIRST(head1) = STAILQ_FIRST(head2);                     \
+               (head1)->stqh_last = (head2)->stqh_last;                       \
+               STAILQ_FIRST(head2) = swap_first;                              \
+               (head2)->stqh_last = swap_last;                                \
+               if (STAILQ_EMPTY(head1))                                       \
+                       (head1)->stqh_last = &STAILQ_FIRST(head1);             \
+               if (STAILQ_EMPTY(head2))                                       \
+                       (head2)->stqh_last = &STAILQ_FIRST(head2);             \
+       } while (0)
+
+
+/*
+ * List declarations.
+ */
+#define LIST_HEAD(name, type)                                                  \
+       struct name {                                                          \
+               struct type *lh_first; /* first element */                     \
+       }
+
+#define LIST_HEAD_INITIALIZER(head)                                            \
+       {                                                                      \
+               NULL                                                           \
+       }
+
+#define LIST_ENTRY(type)                                                       \
+       struct {                                                               \
+               struct type *le_next;  /* next element */                      \
+               struct type **le_prev; /* address of previous next element */  \
+       }
+
+/*
+ * List functions.
+ */
+
+#if (defined(_KERNEL) && defined(INVARIANTS))
+#define QMD_LIST_CHECK_HEAD(head, field)                                       \
+       do {                                                                   \
+               if (LIST_FIRST((head)) != NULL                                 \
+                   && LIST_FIRST((head))->field.le_prev                       \
+                              != &LIST_FIRST((head)))                         \
+                       panic("Bad list head %p first->prev != head", (head)); \
+       } while (0)
+
+#define QMD_LIST_CHECK_NEXT(elm, field)                                        \
+       do {                                                                   \
+               if (LIST_NEXT((elm), field) != NULL                            \
+                   && LIST_NEXT((elm), field)->field.le_prev                  \
+                              != &((elm)->field.le_next))                     \
+                       panic("Bad link elm %p next->prev != elm", (elm));     \
+       } while (0)
+
+#define QMD_LIST_CHECK_PREV(elm, field)                                        \
+       do {                                                                   \
+               if (*(elm)->field.le_prev != (elm))                            \
+                       panic("Bad link elm %p prev->next != elm", (elm));     \
+       } while (0)
+#else
+#define        QMD_LIST_CHECK_HEAD(head, field)
+#define        QMD_LIST_CHECK_NEXT(elm, field)
+#define        QMD_LIST_CHECK_PREV(elm, field)
+#endif /* (_KERNEL && INVARIANTS) */
+
+#define        LIST_EMPTY(head)        ((head)->lh_first == NULL)
+
+#define        LIST_FIRST(head)        ((head)->lh_first)
+
+#define LIST_FOREACH(var, head, field)                                         \
+       for ((var) = LIST_FIRST((head)); (var); (var) = LIST_NEXT((var), field))
+
+#define LIST_FOREACH_SAFE(var, head, field, tvar)                              \
+       for ((var) = LIST_FIRST((head));                                       \
+            (var) && ((tvar) = LIST_NEXT((var), field), 1); (var) = (tvar))
+
+#define LIST_INIT(head)                                                        \
+       do {                                                                   \
+               LIST_FIRST((head)) = NULL;                                     \
+       } while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field)                                 \
+       do {                                                                   \
+               QMD_LIST_CHECK_NEXT(listelm, field);                           \
+               if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field))    \
+                   != NULL)                                                   \
+                       LIST_NEXT((listelm), field)->field.le_prev =           \
+                               &LIST_NEXT((elm), field);                      \
+               LIST_NEXT((listelm), field) = (elm);                           \
+               (elm)->field.le_prev = &LIST_NEXT((listelm), field);           \
+       } while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field)                                \
+       do {                                                                   \
+               QMD_LIST_CHECK_PREV(listelm, field);                           \
+               (elm)->field.le_prev = (listelm)->field.le_prev;               \
+               LIST_NEXT((elm), field) = (listelm);                           \
+               *(listelm)->field.le_prev = (elm);                             \
+               (listelm)->field.le_prev = &LIST_NEXT((elm), field);           \
+       } while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field)                                     \
+       do {                                                                   \
+               QMD_LIST_CHECK_HEAD((head), field);                            \
+               if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)    \
+                       LIST_FIRST((head))->field.le_prev =                    \
+                               &LIST_NEXT((elm), field);                      \
+               LIST_FIRST((head)) = (elm);                                    \
+               (elm)->field.le_prev = &LIST_FIRST((head));                    \
+       } while (0)
+
+#define        LIST_NEXT(elm, field)   ((elm)->field.le_next)
+
+#define LIST_REMOVE(elm, field)                                                \
+       do {                                                                   \
+               QMD_SAVELINK(oldnext, (elm)->field.le_next);                   \
+               QMD_SAVELINK(oldprev, (elm)->field.le_prev);                   \
+               QMD_LIST_CHECK_NEXT(elm, field);                               \
+               QMD_LIST_CHECK_PREV(elm, field);                               \
+               if (LIST_NEXT((elm), field) != NULL)                           \
+                       LIST_NEXT((elm), field)->field.le_prev =               \
+                               (elm)->field.le_prev;                          \
+               *(elm)->field.le_prev = LIST_NEXT((elm), field);               \
+               TRASHIT(*oldnext);                                             \
+               TRASHIT(*oldprev);                                             \
+       } while (0)
+
+#define LIST_SWAP(head1, head2, type, field)                                   \
+       do {                                                                   \
+               struct type *swap_tmp = LIST_FIRST((head1));                   \
+               LIST_FIRST((head1)) = LIST_FIRST((head2));                     \
+               LIST_FIRST((head2)) = swap_tmp;                                \
+               if ((swap_tmp = LIST_FIRST((head1))) != NULL)                  \
+                       swap_tmp->field.le_prev = &LIST_FIRST((head1));        \
+               if ((swap_tmp = LIST_FIRST((head2))) != NULL)                  \
+                       swap_tmp->field.le_prev = &LIST_FIRST((head2));        \
+       } while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define TAILQ_HEAD(name, type)                                                 \
+       struct name {                                                          \
+               struct type *tqh_first; /* first element */                    \
+               struct type **tqh_last; /* addr of last next element */        \
+               TRACEBUF                                                       \
+       }
+
+#define TAILQ_HEAD_INITIALIZER(head)                                           \
+       {                                                                      \
+               NULL, &(head).tqh_first                                        \
+       }
+
+#define TAILQ_ENTRY(type)                                                      \
+       struct {                                                               \
+               struct type *tqe_next;  /* next element */                     \
+               struct type **tqe_prev; /* address of previous next element */ \
+               TRACEBUF                                                       \
+       }
+
+/*
+ * Tail queue functions.
+ */
+#if (defined(_KERNEL) && defined(INVARIANTS))
+#define QMD_TAILQ_CHECK_HEAD(head, field)                                      \
+       do {                                                                   \
+               if (!TAILQ_EMPTY(head)                                         \
+                   && TAILQ_FIRST((head))->field.tqe_prev                     \
+                              != &TAILQ_FIRST((head)))                        \
+                       panic("Bad tailq head %p first->prev != head",         \
+                             (head));                                         \
+       } while (0)
+
+#define QMD_TAILQ_CHECK_TAIL(head, field)                                      \
+       do {                                                                   \
+               if (*(head)->tqh_last != NULL)                                 \
+                       panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
+       } while (0)
+
+#define QMD_TAILQ_CHECK_NEXT(elm, field)                                       \
+       do {                                                                   \
+               if (TAILQ_NEXT((elm), field) != NULL                           \
+                   && TAILQ_NEXT((elm), field)->field.tqe_prev                \
+                              != &((elm)->field.tqe_next))                    \
+                       panic("Bad link elm %p next->prev != elm", (elm));     \
+       } while (0)
+
+#define QMD_TAILQ_CHECK_PREV(elm, field)                                       \
+       do {                                                                   \
+               if (*(elm)->field.tqe_prev != (elm))                           \
+                       panic("Bad link elm %p prev->next != elm", (elm));     \
+       } while (0)
+#else
+#define        QMD_TAILQ_CHECK_HEAD(head, field)
+#define        QMD_TAILQ_CHECK_TAIL(head, headname)
+#define        QMD_TAILQ_CHECK_NEXT(elm, field)
+#define        QMD_TAILQ_CHECK_PREV(elm, field)
+#endif /* (_KERNEL && INVARIANTS) */
+
+#define TAILQ_CONCAT(head1, head2, field)                                      \
+       do {                                                                   \
+               if (!TAILQ_EMPTY(head2)) {                                     \
+                       *(head1)->tqh_last = (head2)->tqh_first;               \
+                       (head2)->tqh_first->field.tqe_prev =                   \
+                               (head1)->tqh_last;                             \
+                       (head1)->tqh_last = (head2)->tqh_last;                 \
+                       TAILQ_INIT((head2));                                   \
+                       QMD_TRACE_HEAD(head1);                                 \
+                       QMD_TRACE_HEAD(head2);                                 \
+               }                                                              \
+       } while (0)
+
+#define        TAILQ_EMPTY(head)       ((head)->tqh_first == NULL)
+
+#define        TAILQ_FIRST(head)       ((head)->tqh_first)
+
+#define TAILQ_FOREACH(var, head, field)                                        \
+       for ((var) = TAILQ_FIRST((head)); (var);                               \
+            (var) = TAILQ_NEXT((var), field))
+
+#define TAILQ_FOREACH_SAFE(var, head, field, tvar)                             \
+       for ((var) = TAILQ_FIRST((head));                                      \
+            (var) && ((tvar) = TAILQ_NEXT((var), field), 1); (var) = (tvar))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field)                      \
+       for ((var) = TAILQ_LAST((head), headname); (var);                      \
+            (var) = TAILQ_PREV((var), headname, field))
+
+#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)           \
+       for ((var) = TAILQ_LAST((head), headname);                             \
+            (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1);        \
+            (var) = (tvar))
+
+#define TAILQ_INIT(head)                                                       \
+       do {                                                                   \
+               TAILQ_FIRST((head)) = NULL;                                    \
+               (head)->tqh_last = &TAILQ_FIRST((head));                       \
+               QMD_TRACE_HEAD(head);                                          \
+       } while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field)                          \
+       do {                                                                   \
+               QMD_TAILQ_CHECK_NEXT(listelm, field);                          \
+               if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field))  \
+                   != NULL)                                                   \
+                       TAILQ_NEXT((elm), field)->field.tqe_prev =             \
+                               &TAILQ_NEXT((elm), field);                     \
+               else {                                                         \
+                       (head)->tqh_last = &TAILQ_NEXT((elm), field);          \
+                       QMD_TRACE_HEAD(head);                                  \
+               }                                                              \
+               TAILQ_NEXT((listelm), field) = (elm);                          \
+               (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field);         \
+               QMD_TRACE_ELEM(&(elm)->field);                                 \
+               QMD_TRACE_ELEM(&listelm->field);                               \
+       } while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field)                               \
+       do {                                                                   \
+               QMD_TAILQ_CHECK_PREV(listelm, field);                          \
+               (elm)->field.tqe_prev = (listelm)->field.tqe_prev;             \
+               TAILQ_NEXT((elm), field) = (listelm);                          \
+               *(listelm)->field.tqe_prev = (elm);                            \
+               (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field);         \
+               QMD_TRACE_ELEM(&(elm)->field);                                 \
+               QMD_TRACE_ELEM(&listelm->field);                               \
+       } while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field)                                    \
+       do {                                                                   \
+               QMD_TAILQ_CHECK_HEAD(head, field);                             \
+               if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)  \
+                       TAILQ_FIRST((head))->field.tqe_prev =                  \
+                               &TAILQ_NEXT((elm), field);                     \
+               else                                                           \
+                       (head)->tqh_last = &TAILQ_NEXT((elm), field);          \
+               TAILQ_FIRST((head)) = (elm);                                   \
+               (elm)->field.tqe_prev = &TAILQ_FIRST((head));                  \
+               QMD_TRACE_HEAD(head);                                          \
+               QMD_TRACE_ELEM(&(elm)->field);                                 \
+       } while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field)                                    \
+       do {                                                                   \
+               QMD_TAILQ_CHECK_TAIL(head, field);                             \
+               TAILQ_NEXT((elm), field) = NULL;                               \
+               (elm)->field.tqe_prev = (head)->tqh_last;                      \
+               *(head)->tqh_last = (elm);                                     \
+               (head)->tqh_last = &TAILQ_NEXT((elm), field);                  \
+               QMD_TRACE_HEAD(head);                                          \
+               QMD_TRACE_ELEM(&(elm)->field);                                 \
+       } while (0)
+
+#define TAILQ_LAST(head, headname)                                             \
+       (*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define        TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define TAILQ_PREV(elm, headname, field)                                       \
+       (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define TAILQ_REMOVE(head, elm, field)                                         \
+       do {                                                                   \
+               QMD_SAVELINK(oldnext, (elm)->field.tqe_next);                  \
+               QMD_SAVELINK(oldprev, (elm)->field.tqe_prev);                  \
+               QMD_TAILQ_CHECK_NEXT(elm, field);                              \
+               QMD_TAILQ_CHECK_PREV(elm, field);                              \
+               if ((TAILQ_NEXT((elm), field)) != NULL)                        \
+                       TAILQ_NEXT((elm), field)->field.tqe_prev =             \
+                               (elm)->field.tqe_prev;                         \
+               else {                                                         \
+                       (head)->tqh_last = (elm)->field.tqe_prev;              \
+                       QMD_TRACE_HEAD(head);                                  \
+               }                                                              \
+               *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);             \
+               TRASHIT(*oldnext);                                             \
+               TRASHIT(*oldprev);                                             \
+               QMD_TRACE_ELEM(&(elm)->field);                                 \
+       } while (0)
+
+#define TAILQ_SWAP(head1, head2, type, field)                                  \
+       do {                                                                   \
+               struct type *swap_first = (head1)->tqh_first;                  \
+               struct type **swap_last = (head1)->tqh_last;                   \
+               (head1)->tqh_first = (head2)->tqh_first;                       \
+               (head1)->tqh_last = (head2)->tqh_last;                         \
+               (head2)->tqh_first = swap_first;                               \
+               (head2)->tqh_last = swap_last;                                 \
+               if ((swap_first = (head1)->tqh_first) != NULL)                 \
+                       swap_first->field.tqe_prev = &(head1)->tqh_first;      \
+               else                                                           \
+                       (head1)->tqh_last = &(head1)->tqh_first;               \
+               if ((swap_first = (head2)->tqh_first) != NULL)                 \
+                       swap_first->field.tqe_prev = &(head2)->tqh_first;      \
+               else                                                           \
+                       (head2)->tqh_last = &(head2)->tqh_first;               \
+       } while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
index 66341cf2f1af68e9258225d28140aecc66417460..243521bef7cc7201efda7a1b4bd06d3174eeae9d 100644 (file)
@@ -335,12 +335,13 @@ void hash_free(struct hash *hash)
 
 /* CLI commands ------------------------------------------------------------ */
 
-DEFUN(show_hash_stats,
-      show_hash_stats_cmd,
-      "show hashtable [statistics]",
-      SHOW_STR
-      "Statistics about hash tables\n"
-      "Statistics about hash tables\n")
+DEFUN_NOSH(show_hash_stats,
+           show_hash_stats_cmd,
+           "show debugging hashtable [statistics]",
+           SHOW_STR
+           DEBUG_STR
+           "Statistics about hash tables\n"
+           "Statistics about hash tables\n")
 {
        struct hash *h;
        struct listnode *ln;
index 2c877cbf451e64402644088c26ee58268e4b213c..1468c4d3291f15ca00769d0eaab2eb7fb6a6ee91 100644 (file)
 DEFINE_MTYPE_STATIC(LIB, HOOK_ENTRY, "Hook entry")
 
 void _hook_register(struct hook *hook, void *funcptr, void *arg, bool has_arg,
-                   struct frrmod_runtime *module, const char *funcname)
+                   struct frrmod_runtime *module, const char *funcname,
+                   int priority)
 {
-       struct hookent *he = XCALLOC(MTYPE_HOOK_ENTRY, sizeof(*he));
+       struct hookent *he = XCALLOC(MTYPE_HOOK_ENTRY, sizeof(*he)), **pos;
        he->hookfn = funcptr;
        he->hookarg = arg;
        he->has_arg = has_arg;
        he->module = module;
        he->fnname = funcname;
+       he->priority = priority;
 
-       he->next = hook->entries;
-       hook->entries = he;
+       for (pos = &hook->entries; *pos; pos = &(*pos)->next)
+               if (hook->reverse
+                   ? (*pos)->priority < priority
+                   : (*pos)->priority >= priority)
+                       break;
+
+       he->next = *pos;
+       *pos = he;
 }
 
 void _hook_unregister(struct hook *hook, void *funcptr, void *arg, bool has_arg)
index 4a5cee2fd394ea1783cfc0c5f33c6869101ba2e9..5f45e113e75cbca264159b7d023c3d51735190e3 100644 (file)
  *     hook_register_arg (some_update_event, event_handler, addonptr);
  *
  *   (addonptr isn't typesafe, but that should be manageable.)
+ *
+ * Hooks also support a "priority" value for ordering registered calls
+ * relative to each other.  The priority is a signed integer where lower
+ * values are called earlier.  There is also "Koohs", which is hooks with
+ * reverse priority ordering (for cleanup/deinit hooks, so you can use the
+ * same priority value).
+ *
+ * Recommended priority value ranges are:
+ *
+ *  -999 ...     0 ...  999 - main executable / daemon, or library
+ * -1999 ... -1000          - modules registering calls that should run before
+ *                            the daemon's bits
+ *            1000 ... 1999 - modules calls that should run after daemon's
+ *
+ * Note: the default value is 1000, based on the following 2 expectations:
+ * - most hook_register() usage will be in loadable modules
+ * - usage of hook_register() in the daemon itself may need relative ordering
+ *   to itself, making an explicit value the expected case
+ *
+ * The priority value is passed as extra argument on hook_register_prio() /
+ * hook_register_arg_prio().  Whether a hook runs in reverse is determined
+ * solely by the code defining / calling the hook.  (DECLARE_KOOH is actually
+ * the same thing as DECLARE_HOOK, it's just there to make it obvious.)
  */
 
 /* TODO:
@@ -94,6 +117,7 @@ struct hookent {
        void *hookfn; /* actually a function pointer */
        void *hookarg;
        bool has_arg;
+       int priority;
        struct frrmod_runtime *module;
        const char *fnname;
 };
@@ -101,8 +125,11 @@ struct hookent {
 struct hook {
        const char *name;
        struct hookent *entries;
+       bool reverse;
 };
 
+#define HOOK_DEFAULT_PRIORITY 1000
+
 /* subscribe/add callback function to a hook
  *
  * always use hook_register(), which uses the static inline helper from
@@ -110,14 +137,21 @@ struct hook {
  */
 extern void _hook_register(struct hook *hook, void *funcptr, void *arg,
                           bool has_arg, struct frrmod_runtime *module,
-                          const char *funcname);
+                          const char *funcname, int priority);
 #define hook_register(hookname, func)                                          \
        _hook_register(&_hook_##hookname, _hook_typecheck_##hookname(func),    \
-                      NULL, false, THIS_MODULE, #func)
+                      NULL, false, THIS_MODULE, #func, HOOK_DEFAULT_PRIORITY)
 #define hook_register_arg(hookname, func, arg)                                 \
        _hook_register(&_hook_##hookname,                                      \
                       _hook_typecheck_arg_##hookname(func), arg, true,        \
-                      THIS_MODULE, #func)
+                      THIS_MODULE, #func, HOOK_DEFAULT_PRIORITY)
+#define hook_register_prio(hookname, prio, func)                               \
+       _hook_register(&_hook_##hookname, _hook_typecheck_##hookname(func),    \
+                      NULL, false, THIS_MODULE, #func, prio)
+#define hook_register_arg_prio(hookname, prio, func, arg)                      \
+       _hook_register(&_hook_##hookname,                                      \
+                      _hook_typecheck_arg_##hookname(func),                   \
+                      arg, true, THIS_MODULE, #func, prio)
 
 extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
                             bool has_arg);
@@ -156,12 +190,14 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
        {                                                                      \
                return (void *)funcptr;                                        \
        }
+#define DECLARE_KOOH(hookname, arglist, passlist) \
+       DECLARE_HOOK(hookname, arglist, passlist)
 
 /* use in source file - contains hook-related definitions.
  */
-#define DEFINE_HOOK(hookname, arglist, passlist)                               \
+#define DEFINE_HOOK_INT(hookname, arglist, passlist, rev)                      \
        struct hook _hook_##hookname = {                                       \
-               .name = #hookname, .entries = NULL,                            \
+               .name = #hookname, .entries = NULL, .reverse = rev,            \
        };                                                                     \
        static int hook_call_##hookname arglist                                \
        {                                                                      \
@@ -184,4 +220,9 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
                return hooksum;                                                \
        }
 
+#define DEFINE_HOOK(hookname, arglist, passlist) \
+       DEFINE_HOOK_INT(hookname, arglist, passlist, false)
+#define DEFINE_KOOH(hookname, arglist, passlist) \
+       DEFINE_HOOK_INT(hookname, arglist, passlist, true)
+
 #endif /* _FRR_HOOK_H */
index 4e4534851cccd28d31c5c54d5c52c2f6d7de325f..43c382beaaa4cb7107720553d5a19b3acc066463 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -42,17 +42,12 @@ DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters")
 
 DEFINE_QOBJ_TYPE(interface)
 
+DEFINE_HOOK(if_add, (struct interface *ifp), (ifp))
+DEFINE_KOOH(if_del, (struct interface *ifp), (ifp))
+
 /* List of interfaces in only the default VRF */
 int ptm_enable = 0;
 
-/* One for each program.  This structure is needed to store hooks. */
-struct if_master {
-       int (*if_new_hook)(struct interface *);
-       int (*if_delete_hook)(struct interface *);
-} if_master = {
-       0,
-};
-
 /* Compare interface names, returning an integer greater than, equal to, or
  * less than 0, (following the strcmp convention), according to the
  * relationship between ifp1 and ifp2.  Interface names consist of an
@@ -150,10 +145,7 @@ struct interface *if_create(const char *name, int namelen, vrf_id_t vrf_id)
        SET_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION);
 
        QOBJ_REG(ifp, interface);
-
-       if (if_master.if_new_hook)
-               (*if_master.if_new_hook)(ifp);
-
+        hook_call(if_add, ifp);
        return ifp;
 }
 
@@ -182,9 +174,7 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
 /* Delete interface structure. */
 void if_delete_retain(struct interface *ifp)
 {
-       if (if_master.if_delete_hook)
-               (*if_master.if_delete_hook)(ifp);
-
+        hook_call(if_del, ifp);
        QOBJ_UNREG(ifp);
 
        /* Free connected address list */
@@ -209,21 +199,6 @@ void if_delete(struct interface *ifp)
        XFREE(MTYPE_IF, ifp);
 }
 
-/* Add hook to interface master. */
-void if_add_hook(int type, int (*func)(struct interface *ifp))
-{
-       switch (type) {
-       case IF_NEW_HOOK:
-               if_master.if_new_hook = func;
-               break;
-       case IF_DELETE_HOOK:
-               if_master.if_delete_hook = func;
-               break;
-       default:
-               break;
-       }
-}
-
 /* Interface existance check by index. */
 struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id)
 {
index f80ac19179527e2bf57da2d165cd6c1d90f2a06d..a592e0ff857d25ebfd34b6f8c655ecf4fe7919b0 100644 (file)
--- a/lib/if.h
+++ b/lib/if.h
@@ -25,6 +25,7 @@
 #include "linklist.h"
 #include "memory.h"
 #include "qobj.h"
+#include "hook.h"
 
 DECLARE_MTYPE(IF)
 DECLARE_MTYPE(CONNECTED_LABEL)
@@ -283,6 +284,17 @@ struct interface {
 };
 DECLARE_QOBJ_TYPE(interface)
 
+/* called from the library code whenever interfaces are created/deleted
+ * note: interfaces may not be fully realized at that point; also they
+ * may not exist in the system (ifindex = IFINDEX_INTERNAL)
+ *
+ * priority values are important here, daemons should be at 0 while modules
+ * can use 1000+ so they run after the daemon has initialised daemon-specific
+ * interface data
+ */
+DECLARE_HOOK(if_add, (struct interface *ifp), (ifp))
+DECLARE_KOOH(if_del, (struct interface *ifp), (ifp))
+
 /* Connected address structure. */
 struct connected {
        /* Attached interface. */
@@ -355,10 +367,6 @@ struct nbr_connected {
                 ? (C)->destination                                            \
                 : (C)->address)
 
-/* Interface hook sort. */
-#define IF_NEW_HOOK   0
-#define IF_DELETE_HOOK 1
-
 /* There are some interface flags which are only supported by some
    operating system. */
 
@@ -442,7 +450,6 @@ extern int if_is_loopback(struct interface *);
 extern int if_is_broadcast(struct interface *);
 extern int if_is_pointopoint(struct interface *);
 extern int if_is_multicast(struct interface *);
-extern void if_add_hook(int, int (*)(struct interface *));
 extern void if_init(struct list **);
 extern void if_cmd_init(void);
 extern void if_terminate(struct list **);
index a486fc17c18d35329eb245ca2d4a051ba3e3fb03..ae660504e41ddc3e8c0552962ca088100fc0428a 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <zebra.h>
 
-#include "openbsd-queue.h"
+#include "queue.h"
 #include "imsg.h"
 
 int    ibuf_realloc(struct ibuf *, size_t);
index fc62c13734a8bbf036580cdc84f75b108f6d770e..999ab679b8a29cd945b20e3e902574bdd4b1f2e0 100644 (file)
@@ -18,7 +18,7 @@
 
 #include <zebra.h>
 
-#include "openbsd-queue.h"
+#include "queue.h"
 #include "imsg.h"
 
 int     imsg_fd_overhead = 0;
index a5c87e6edc6d6d5f003ed2731108ca9491f542f0..255f91ec71f85564ded01ec90b29d054c7fdd783 100644 (file)
@@ -37,6 +37,8 @@
 #include "network.h"
 
 DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
+DEFINE_KOOH(frr_early_fini, (), ())
+DEFINE_KOOH(frr_fini, (), ())
 
 const char frr_sysconfdir[] = SYSCONFDIR;
 const char frr_vtydir[] = DAEMON_VTY_DIR;
@@ -831,3 +833,22 @@ void frr_run(struct thread_master *master)
        while (thread_fetch(master, &thread))
                thread_call(&thread);
 }
+
+void frr_early_fini(void)
+{
+       hook_call(frr_early_fini);
+}
+
+void frr_fini(void)
+{
+       hook_call(frr_fini);
+
+       /* memory_init -> nothing needed */
+       vty_terminate();
+       cmd_terminate();
+       zprivs_terminate(di->privs);
+       /* signal_init -> nothing needed */
+       thread_master_free(master);
+       closezlog();
+       /* frrmod_init -> nothing needed / hooks */
+}
index 1710fc9a846ea0a69e4fa42355f84f6a37a55ac3..8a15d168a1722290d39693b54798833036bca57d 100644 (file)
@@ -104,6 +104,14 @@ extern void frr_run(struct thread_master *master);
 extern bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len,
                             const char *path);
 
+/* these two are before the protocol daemon does its own shutdown
+ * it's named this way being the counterpart to frr_late_init */
+DECLARE_KOOH(frr_early_fini, (), ())
+extern void frr_early_fini(void);
+/* and these two are after the daemon did its own cleanup */
+DECLARE_KOOH(frr_fini, (), ())
+extern void frr_fini(void);
+
 extern char config_default[256];
 extern char frr_zclientpath[256];
 extern const char frr_sysconfdir[];
index de521b2e3e0949ec7a0e5f4f91a1508f2e86c8fd..2f61eb6e8b0f04874225e0c34dd88a268bb74635 100644 (file)
@@ -497,8 +497,7 @@ int prefix_same(const struct prefix *p1, const struct prefix *p2)
 
        if (p1->family == p2->family && p1->prefixlen == p2->prefixlen) {
                if (p1->family == AF_INET)
-                       if (IPV4_ADDR_SAME(&p1->u.prefix4.s_addr,
-                                          &p2->u.prefix4.s_addr))
+                       if (IPV4_ADDR_SAME(&p1->u.prefix4, &p2->u.prefix4))
                                return 1;
                if (p1->family == AF_INET6)
                        if (IPV6_ADDR_SAME(&p1->u.prefix6.s6_addr,
index f0644ea88e9dbb238e4900dc012ffe938b464603..bc4abb492a0cca31e59c61838ecb3901eed35d20 100644 (file)
@@ -241,8 +241,20 @@ union prefixconstptr {
 #define IPV4_MAX_BITLEN    32
 #define IPV4_MAX_PREFIXLEN 32
 #define IPV4_ADDR_CMP(D,S)   memcmp ((D), (S), IPV4_MAX_BYTELEN)
-#define IPV4_ADDR_SAME(D,S)  (memcmp ((D), (S), IPV4_MAX_BYTELEN) == 0)
-#define IPV4_ADDR_COPY(D,S)  memcpy ((D), (S), IPV4_MAX_BYTELEN)
+
+static inline bool ipv4_addr_same(const struct in_addr *a,
+                                 const struct in_addr *b)
+{
+       return (a->s_addr == b->s_addr);
+}
+#define IPV4_ADDR_SAME(A,B)  ipv4_addr_same((A), (B))
+
+static inline void ipv4_addr_copy(struct in_addr *dst,
+                                 const struct in_addr *src)
+{
+       dst->s_addr = src->s_addr;
+}
+#define IPV4_ADDR_COPY(D,S)  ipv4_addr_copy((D), (S))
 
 #define IPV4_NET0(a)    ((((u_int32_t) (a)) & 0xff000000) == 0x00000000)
 #define IPV4_NET127(a)  ((((u_int32_t) (a)) & 0xff000000) == 0x7f000000)
index eda3fb02d4c0b72a7ea33b6504210107e256b9ea..cfe7d6d6f81bdf802191e2559f1438ab7c985e98 100644 (file)
@@ -856,7 +856,9 @@ void zprivs_terminate(struct zebra_privs_t *zprivs)
        }
 
 #ifdef HAVE_CAPABILITIES
-       zprivs_caps_terminate();
+       if (zprivs->user || zprivs->group || zprivs->cap_num_p
+           || zprivs->cap_num_i)
+               zprivs_caps_terminate();
 #else  /* !HAVE_CAPABILITIES */
        /* only change uid if we don't have the correct one */
        if ((zprivs_state.zuid) && (zprivs_state.zsuid != zprivs_state.zuid)) {
index 658b602ba3f740d4a2672f6c633dc0e36ac9e746..29b67a26e65639b993757e84983a2aadc8c66278 100644 (file)
-/*-
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * 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.
- * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- *
- *     @(#)queue.h     8.5 (Berkeley) 8/20/94
- * $FreeBSD$
- */
-
-#ifndef _SYS_QUEUE_H_
-#define        _SYS_QUEUE_H_
-
 /*
- * This file defines four types of data structures: singly-linked lists,
- * singly-linked tail queues, lists and tail queues.
+ * lists and queues implementations
  *
- * A singly-linked list is headed by a single forward pointer. The elements
- * are singly linked for minimum space and pointer manipulation overhead at
- * the expense of O(n) removal for arbitrary elements. New elements can be
- * added to the list after an existing element or at the head of the list.
- * Elements being removed from the head of the list should use the explicit
- * macro for this purpose for optimum efficiency. A singly-linked list may
- * only be traversed in the forward direction.  Singly-linked lists are ideal
- * for applications with large datasets and few or no removals or for
- * implementing a LIFO queue.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
  *
- * A singly-linked tail queue is headed by a pair of pointers, one to the
- * head of the list and the other to the tail of the list. The elements are
- * singly linked for minimum space and pointer manipulation overhead at the
- * expense of O(n) removal for arbitrary elements. New elements can be added
- * to the list after an existing element, at the head of the list, or at the
- * end of the list. Elements being removed from the head of the tail queue
- * should use the explicit macro for this purpose for optimum efficiency.
- * A singly-linked tail queue may only be traversed in the forward direction.
- * Singly-linked tail queues are ideal for applications with large datasets
- * and few or no removals or for implementing a FIFO queue.
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
  *
- * A list is headed by a single forward pointer (or an array of forward
- * pointers for a hash table header). The elements are doubly linked
- * so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before
- * or after an existing element or at the head of the list. A list
- * may only be traversed in the forward direction.
- *
- * A tail queue is headed by a pair of pointers, one to the head of the
- * list and the other to the tail of the list. The elements are doubly
- * linked so that an arbitrary element can be removed without a need to
- * traverse the list. New elements can be added to the list before or
- * after an existing element, at the head of the list, or at the end of
- * the list. A tail queue may be traversed in either direction.
- *
- * For details on the use of these macros, see the queue(3) manual page.
- *
- *
- *                             SLIST   LIST    STAILQ  TAILQ
- * _HEAD                       +       +       +       +
- * _HEAD_INITIALIZER           +       +       +       +
- * _ENTRY                      +       +       +       +
- * _INIT                       +       +       +       +
- * _EMPTY                      +       +       +       +
- * _FIRST                      +       +       +       +
- * _NEXT                       +       +       +       +
- * _PREV                       -       -       -       +
- * _LAST                       -       -       +       +
- * _FOREACH                    +       +       +       +
- * _FOREACH_SAFE               +       +       +       +
- * _FOREACH_REVERSE            -       -       -       +
- * _FOREACH_REVERSE_SAFE       -       -       -       +
- * _INSERT_HEAD                        +       +       +       +
- * _INSERT_BEFORE              -       +       -       +
- * _INSERT_AFTER               +       +       +       +
- * _INSERT_TAIL                        -       -       +       +
- * _CONCAT                     -       -       +       +
- * _REMOVE_AFTER               +       -       +       -
- * _REMOVE_HEAD                        +       -       +       -
- * _REMOVE                     +       +       +       +
- * _SWAP                       +       +       +       +
- *
- */
-#ifdef QUEUE_MACRO_DEBUG
-/* Store the last 2 places the queue element or head was altered */
-struct qm_trace {
-       char *lastfile;
-       int lastline;
-       char *prevfile;
-       int prevline;
-};
-
-#define        TRACEBUF        struct qm_trace trace;
-#define        TRASHIT(x)      do {(x) = (void *)-1;} while (0)
-#define        QMD_SAVELINK(name, link)        void **name = (void *)&(link)
-
-#define QMD_TRACE_HEAD(head)                                                   \
-       do {                                                                   \
-               (head)->trace.prevline = (head)->trace.lastline;               \
-               (head)->trace.prevfile = (head)->trace.lastfile;               \
-               (head)->trace.lastline = __LINE__;                             \
-               (head)->trace.lastfile = __FILE__;                             \
-       } while (0)
-
-#define QMD_TRACE_ELEM(elem)                                                   \
-       do {                                                                   \
-               (elem)->trace.prevline = (elem)->trace.lastline;               \
-               (elem)->trace.prevfile = (elem)->trace.lastfile;               \
-               (elem)->trace.lastline = __LINE__;                             \
-               (elem)->trace.lastfile = __FILE__;                             \
-       } while (0)
-
-#else
-#define        QMD_TRACE_ELEM(elem)
-#define        QMD_TRACE_HEAD(head)
-#define        QMD_SAVELINK(name, link)
-#define        TRACEBUF
-#define        TRASHIT(x)
-#endif /* QUEUE_MACRO_DEBUG */
-
-/*
- * Singly-linked List declarations.
- */
-#define SLIST_HEAD(name, type)                                                 \
-       struct name {                                                          \
-               struct type *slh_first; /* first element */                    \
-       }
-
-#define SLIST_HEAD_INITIALIZER(head)                                           \
-       {                                                                      \
-               NULL                                                           \
-       }
-
-#define SLIST_ENTRY(type)                                                      \
-       struct {                                                               \
-               struct type *sle_next; /* next element */                      \
-       }
-
-/*
- * Singly-linked List functions.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
-#define        SLIST_EMPTY(head)       ((head)->slh_first == NULL)
-
-#define        SLIST_FIRST(head)       ((head)->slh_first)
-
-#define SLIST_FOREACH(var, head, field)                                        \
-       for ((var) = SLIST_FIRST((head)); (var);                               \
-            (var) = SLIST_NEXT((var), field))
-
-#define SLIST_FOREACH_SAFE(var, head, field, tvar)                             \
-       for ((var) = SLIST_FIRST((head));                                      \
-            (var) && ((tvar) = SLIST_NEXT((var), field), 1); (var) = (tvar))
-
-#define SLIST_FOREACH_PREVPTR(var, varp, head, field)                          \
-       for ((varp) = &SLIST_FIRST((head)); ((var) = *(varp)) != NULL;         \
-            (varp) = &SLIST_NEXT((var), field))
-
-#define SLIST_INIT(head)                                                       \
-       do {                                                                   \
-               SLIST_FIRST((head)) = NULL;                                    \
-       } while (0)
-
-#define SLIST_INSERT_AFTER(slistelm, elm, field)                               \
-       do {                                                                   \
-               SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field);      \
-               SLIST_NEXT((slistelm), field) = (elm);                         \
-       } while (0)
-
-#define SLIST_INSERT_HEAD(head, elm, field)                                    \
-       do {                                                                   \
-               SLIST_NEXT((elm), field) = SLIST_FIRST((head));                \
-               SLIST_FIRST((head)) = (elm);                                   \
-       } while (0)
-
-#define        SLIST_NEXT(elm, field)  ((elm)->field.sle_next)
-
-#define SLIST_REMOVE(head, elm, type, field)                                   \
-       do {                                                                   \
-               QMD_SAVELINK(oldnext, (elm)->field.sle_next);                  \
-               if (SLIST_FIRST((head)) == (elm)) {                            \
-                       SLIST_REMOVE_HEAD((head), field);                      \
-               } else {                                                       \
-                       struct type *curelm = SLIST_FIRST((head));             \
-                       while (SLIST_NEXT(curelm, field) != (elm))             \
-                               curelm = SLIST_NEXT(curelm, field);            \
-                       SLIST_REMOVE_AFTER(curelm, field);                     \
-               }                                                              \
-               TRASHIT(*oldnext);                                             \
-       } while (0)
-
-#define SLIST_REMOVE_AFTER(elm, field)                                         \
-       do {                                                                   \
-               SLIST_NEXT(elm, field) =                                       \
-                       SLIST_NEXT(SLIST_NEXT(elm, field), field);             \
-       } while (0)
-
-#define SLIST_REMOVE_HEAD(head, field)                                         \
-       do {                                                                   \
-               SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);  \
-       } while (0)
-
-#define SLIST_SWAP(head1, head2, type)                                         \
-       do {                                                                   \
-               struct type *swap_first = SLIST_FIRST(head1);                  \
-               SLIST_FIRST(head1) = SLIST_FIRST(head2);                       \
-               SLIST_FIRST(head2) = swap_first;                               \
-       } while (0)
-
-/*
- * Singly-linked Tail queue declarations.
- */
-#define STAILQ_HEAD(name, type)                                                \
-       struct name {                                                          \
-               struct type *stqh_first; /* first element */                   \
-               struct type **stqh_last; /* addr of last next element */       \
-       }
-
-#define STAILQ_HEAD_INITIALIZER(head)                                          \
-       {                                                                      \
-               NULL, &(head).stqh_first                                       \
-       }
-
-#define STAILQ_ENTRY(type)                                                     \
-       struct {                                                               \
-               struct type *stqe_next; /* next element */                     \
-       }
-
-/*
- * Singly-linked Tail queue functions.
- */
-#define STAILQ_CONCAT(head1, head2)                                            \
-       do {                                                                   \
-               if (!STAILQ_EMPTY((head2))) {                                  \
-                       *(head1)->stqh_last = (head2)->stqh_first;             \
-                       (head1)->stqh_last = (head2)->stqh_last;               \
-                       STAILQ_INIT((head2));                                  \
-               }                                                              \
-       } while (0)
-
-#define        STAILQ_EMPTY(head)      ((head)->stqh_first == NULL)
-
-#define        STAILQ_FIRST(head)      ((head)->stqh_first)
-
-#define STAILQ_FOREACH(var, head, field)                                       \
-       for ((var) = STAILQ_FIRST((head)); (var);                              \
-            (var) = STAILQ_NEXT((var), field))
-
-
-#define STAILQ_FOREACH_SAFE(var, head, field, tvar)                            \
-       for ((var) = STAILQ_FIRST((head));                                     \
-            (var) && ((tvar) = STAILQ_NEXT((var), field), 1); (var) = (tvar))
-
-#define STAILQ_INIT(head)                                                      \
-       do {                                                                   \
-               STAILQ_FIRST((head)) = NULL;                                   \
-               (head)->stqh_last = &STAILQ_FIRST((head));                     \
-       } while (0)
-
-#define STAILQ_INSERT_AFTER(head, tqelm, elm, field)                           \
-       do {                                                                   \
-               if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field))  \
-                   == NULL)                                                   \
-                       (head)->stqh_last = &STAILQ_NEXT((elm), field);        \
-               STAILQ_NEXT((tqelm), field) = (elm);                           \
-       } while (0)
-
-#define STAILQ_INSERT_HEAD(head, elm, field)                                   \
-       do {                                                                   \
-               if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head)))         \
-                   == NULL)                                                   \
-                       (head)->stqh_last = &STAILQ_NEXT((elm), field);        \
-               STAILQ_FIRST((head)) = (elm);                                  \
-       } while (0)
-
-#define STAILQ_INSERT_TAIL(head, elm, field)                                   \
-       do {                                                                   \
-               STAILQ_NEXT((elm), field) = NULL;                              \
-               *(head)->stqh_last = (elm);                                    \
-               (head)->stqh_last = &STAILQ_NEXT((elm), field);                \
-       } while (0)
 
+#ifndef _FRR_QUEUE_H
+#define _FRR_QUEUE_H
+
+#if defined(__OpenBSD__) && !defined(STAILQ_HEAD)
+#include "openbsd-queue.h"
+
+/* Try to map FreeBSD implementation to OpenBSD one. */
+#define STAILQ_HEAD(name, type)                                SIMPLEQ_HEAD(name, type)
+#define STAILQ_HEAD_INITIALIZER(head)                  SIMPLEQ_HEAD_INITIALIZER(head)
+#define STAILQ_ENTRY(entry)                            SIMPLEQ_ENTRY(entry)
+
+#define STAILQ_CONCAT(head1, head2)                    SIMPLEQ_CONCAT(head1, head2)
+#define STAILQ_EMPTY(head)                             SIMPLEQ_EMPTY(head)
+#define STAILQ_FIRST(head)                             SIMPLEQ_FIRST(head)
+#define STAILQ_FOREACH(var, head, field)               SIMPLEQ_FOREACH(var, head, field)
+#define STAILQ_FOREACH_SAFE(var, head, field, tvar)    SIMPLEQ_FOREACH_SAFE(var, head, field, tvar)
+#define STAILQ_INIT(head)                              SIMPLEQ_INIT(head)
+#define STAILQ_INSERT_AFTER(head, tqelm, elm, field)   SIMPLEQ_INSERT_AFTER(head, tqelm, elm, field)
+#define STAILQ_INSERT_HEAD(head, elm, field)           SIMPLEQ_INSERT_HEAD(head, elm, field)
+#define STAILQ_INSERT_TAIL(head, elm, field)           SIMPLEQ_INSERT_TAIL(head, elm, field)
 #define STAILQ_LAST(head, type, field)                                         \
-       (STAILQ_EMPTY((head))                                                  \
+       (SIMPLEQ_EMPTY((head))                                                 \
                 ? NULL                                                        \
-                : ((struct type *)(void *)((char *)((head)->stqh_last)        \
-                                           - __offsetof(struct type,          \
+                : ((struct type *)(void *)((char *)((head)->sqh_last)         \
+                                           - offsetof(struct type,            \
                                                         field))))
-
-#define        STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
-
+#define STAILQ_NEXT(elm, field)                                SIMPLEQ_NEXT(elm, field)
 #define STAILQ_REMOVE(head, elm, type, field)                                  \
        do {                                                                   \
-               QMD_SAVELINK(oldnext, (elm)->field.stqe_next);                 \
-               if (STAILQ_FIRST((head)) == (elm)) {                           \
-                       STAILQ_REMOVE_HEAD((head), field);                     \
+               if (SIMPLEQ_FIRST((head)) == (elm)) {                          \
+                       SIMPLEQ_REMOVE_HEAD((head), field);                    \
                } else {                                                       \
-                       struct type *curelm = STAILQ_FIRST((head));            \
-                       while (STAILQ_NEXT(curelm, field) != (elm))            \
-                               curelm = STAILQ_NEXT(curelm, field);           \
-                       STAILQ_REMOVE_AFTER(head, curelm, field);              \
+                       struct type *curelm = SIMPLEQ_FIRST((head));           \
+                       while (SIMPLEQ_NEXT(curelm, field) != (elm))           \
+                               curelm = SIMPLEQ_NEXT(curelm, field);          \
+                       SIMPLEQ_REMOVE_AFTER(head, curelm, field);             \
                }                                                              \
-               TRASHIT(*oldnext);                                             \
-       } while (0)
-
-#define STAILQ_REMOVE_AFTER(head, elm, field)                                  \
-       do {                                                                   \
-               if ((STAILQ_NEXT(elm, field) =                                 \
-                            STAILQ_NEXT(STAILQ_NEXT(elm, field), field))      \
-                   == NULL)                                                   \
-                       (head)->stqh_last = &STAILQ_NEXT((elm), field);        \
        } while (0)
-
-#define STAILQ_REMOVE_HEAD(head, field)                                        \
-       do {                                                                   \
-               if ((STAILQ_FIRST((head)) =                                    \
-                            STAILQ_NEXT(STAILQ_FIRST((head)), field))         \
-                   == NULL)                                                   \
-                       (head)->stqh_last = &STAILQ_FIRST((head));             \
-       } while (0)
-
+#define STAILQ_REMOVE_AFTER(head, elm, field)          SIMPLEQ_REMOVE_AFTER(head, elm, field)
+#define STAILQ_REMOVE_HEAD(head, field)                        SIMPLEQ_REMOVE_HEAD(head, field)
 #define STAILQ_SWAP(head1, head2, type)                                        \
        do {                                                                   \
                struct type *swap_first = STAILQ_FIRST(head1);                 \
-               struct type **swap_last = (head1)->stqh_last;                  \
+               struct type **swap_last = (head1)->sqh_last;                   \
                STAILQ_FIRST(head1) = STAILQ_FIRST(head2);                     \
-               (head1)->stqh_last = (head2)->stqh_last;                       \
+               (head1)->sqh_last = (head2)->sqh_last;                         \
                STAILQ_FIRST(head2) = swap_first;                              \
-               (head2)->stqh_last = swap_last;                                \
+               (head2)->sqh_last = swap_last;                                 \
                if (STAILQ_EMPTY(head1))                                       \
-                       (head1)->stqh_last = &STAILQ_FIRST(head1);             \
+                       (head1)->sqh_last = &STAILQ_FIRST(head1);              \
                if (STAILQ_EMPTY(head2))                                       \
-                       (head2)->stqh_last = &STAILQ_FIRST(head2);             \
-       } while (0)
-
-
-/*
- * List declarations.
- */
-#define LIST_HEAD(name, type)                                                  \
-       struct name {                                                          \
-               struct type *lh_first; /* first element */                     \
-       }
-
-#define LIST_HEAD_INITIALIZER(head)                                            \
-       {                                                                      \
-               NULL                                                           \
-       }
-
-#define LIST_ENTRY(type)                                                       \
-       struct {                                                               \
-               struct type *le_next;  /* next element */                      \
-               struct type **le_prev; /* address of previous next element */  \
-       }
-
-/*
- * List functions.
- */
-
-#if (defined(_KERNEL) && defined(INVARIANTS))
-#define QMD_LIST_CHECK_HEAD(head, field)                                       \
-       do {                                                                   \
-               if (LIST_FIRST((head)) != NULL                                 \
-                   && LIST_FIRST((head))->field.le_prev                       \
-                              != &LIST_FIRST((head)))                         \
-                       panic("Bad list head %p first->prev != head", (head)); \
-       } while (0)
-
-#define QMD_LIST_CHECK_NEXT(elm, field)                                        \
-       do {                                                                   \
-               if (LIST_NEXT((elm), field) != NULL                            \
-                   && LIST_NEXT((elm), field)->field.le_prev                  \
-                              != &((elm)->field.le_next))                     \
-                       panic("Bad link elm %p next->prev != elm", (elm));     \
-       } while (0)
-
-#define QMD_LIST_CHECK_PREV(elm, field)                                        \
-       do {                                                                   \
-               if (*(elm)->field.le_prev != (elm))                            \
-                       panic("Bad link elm %p prev->next != elm", (elm));     \
+                       (head2)->sqh_last = &STAILQ_FIRST(head2);              \
        } while (0)
 #else
-#define        QMD_LIST_CHECK_HEAD(head, field)
-#define        QMD_LIST_CHECK_NEXT(elm, field)
-#define        QMD_LIST_CHECK_PREV(elm, field)
-#endif /* (_KERNEL && INVARIANTS) */
-
-#define        LIST_EMPTY(head)        ((head)->lh_first == NULL)
-
-#define        LIST_FIRST(head)        ((head)->lh_first)
-
-#define LIST_FOREACH(var, head, field)                                         \
-       for ((var) = LIST_FIRST((head)); (var); (var) = LIST_NEXT((var), field))
-
-#define LIST_FOREACH_SAFE(var, head, field, tvar)                              \
-       for ((var) = LIST_FIRST((head));                                       \
-            (var) && ((tvar) = LIST_NEXT((var), field), 1); (var) = (tvar))
-
-#define LIST_INIT(head)                                                        \
-       do {                                                                   \
-               LIST_FIRST((head)) = NULL;                                     \
-       } while (0)
-
-#define LIST_INSERT_AFTER(listelm, elm, field)                                 \
-       do {                                                                   \
-               QMD_LIST_CHECK_NEXT(listelm, field);                           \
-               if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field))    \
-                   != NULL)                                                   \
-                       LIST_NEXT((listelm), field)->field.le_prev =           \
-                               &LIST_NEXT((elm), field);                      \
-               LIST_NEXT((listelm), field) = (elm);                           \
-               (elm)->field.le_prev = &LIST_NEXT((listelm), field);           \
-       } while (0)
-
-#define LIST_INSERT_BEFORE(listelm, elm, field)                                \
-       do {                                                                   \
-               QMD_LIST_CHECK_PREV(listelm, field);                           \
-               (elm)->field.le_prev = (listelm)->field.le_prev;               \
-               LIST_NEXT((elm), field) = (listelm);                           \
-               *(listelm)->field.le_prev = (elm);                             \
-               (listelm)->field.le_prev = &LIST_NEXT((elm), field);           \
-       } while (0)
-
-#define LIST_INSERT_HEAD(head, elm, field)                                     \
-       do {                                                                   \
-               QMD_LIST_CHECK_HEAD((head), field);                            \
-               if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)    \
-                       LIST_FIRST((head))->field.le_prev =                    \
-                               &LIST_NEXT((elm), field);                      \
-               LIST_FIRST((head)) = (elm);                                    \
-               (elm)->field.le_prev = &LIST_FIRST((head));                    \
-       } while (0)
-
-#define        LIST_NEXT(elm, field)   ((elm)->field.le_next)
-
-#define LIST_REMOVE(elm, field)                                                \
-       do {                                                                   \
-               QMD_SAVELINK(oldnext, (elm)->field.le_next);                   \
-               QMD_SAVELINK(oldprev, (elm)->field.le_prev);                   \
-               QMD_LIST_CHECK_NEXT(elm, field);                               \
-               QMD_LIST_CHECK_PREV(elm, field);                               \
-               if (LIST_NEXT((elm), field) != NULL)                           \
-                       LIST_NEXT((elm), field)->field.le_prev =               \
-                               (elm)->field.le_prev;                          \
-               *(elm)->field.le_prev = LIST_NEXT((elm), field);               \
-               TRASHIT(*oldnext);                                             \
-               TRASHIT(*oldprev);                                             \
-       } while (0)
-
-#define LIST_SWAP(head1, head2, type, field)                                   \
-       do {                                                                   \
-               struct type *swap_tmp = LIST_FIRST((head1));                   \
-               LIST_FIRST((head1)) = LIST_FIRST((head2));                     \
-               LIST_FIRST((head2)) = swap_tmp;                                \
-               if ((swap_tmp = LIST_FIRST((head1))) != NULL)                  \
-                       swap_tmp->field.le_prev = &LIST_FIRST((head1));        \
-               if ((swap_tmp = LIST_FIRST((head2))) != NULL)                  \
-                       swap_tmp->field.le_prev = &LIST_FIRST((head2));        \
-       } while (0)
-
-/*
- * Tail queue declarations.
- */
-#define TAILQ_HEAD(name, type)                                                 \
-       struct name {                                                          \
-               struct type *tqh_first; /* first element */                    \
-               struct type **tqh_last; /* addr of last next element */        \
-               TRACEBUF                                                       \
-       }
-
-#define TAILQ_HEAD_INITIALIZER(head)                                           \
-       {                                                                      \
-               NULL, &(head).tqh_first                                        \
-       }
-
-#define TAILQ_ENTRY(type)                                                      \
-       struct {                                                               \
-               struct type *tqe_next;  /* next element */                     \
-               struct type **tqe_prev; /* address of previous next element */ \
-               TRACEBUF                                                       \
-       }
-
-/*
- * Tail queue functions.
- */
-#if (defined(_KERNEL) && defined(INVARIANTS))
-#define QMD_TAILQ_CHECK_HEAD(head, field)                                      \
-       do {                                                                   \
-               if (!TAILQ_EMPTY(head)                                         \
-                   && TAILQ_FIRST((head))->field.tqe_prev                     \
-                              != &TAILQ_FIRST((head)))                        \
-                       panic("Bad tailq head %p first->prev != head",         \
-                             (head));                                         \
-       } while (0)
-
-#define QMD_TAILQ_CHECK_TAIL(head, field)                                      \
-       do {                                                                   \
-               if (*(head)->tqh_last != NULL)                                 \
-                       panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
-       } while (0)
-
-#define QMD_TAILQ_CHECK_NEXT(elm, field)                                       \
-       do {                                                                   \
-               if (TAILQ_NEXT((elm), field) != NULL                           \
-                   && TAILQ_NEXT((elm), field)->field.tqe_prev                \
-                              != &((elm)->field.tqe_next))                    \
-                       panic("Bad link elm %p next->prev != elm", (elm));     \
-       } while (0)
-
-#define QMD_TAILQ_CHECK_PREV(elm, field)                                       \
-       do {                                                                   \
-               if (*(elm)->field.tqe_prev != (elm))                           \
-                       panic("Bad link elm %p prev->next != elm", (elm));     \
-       } while (0)
-#else
-#define        QMD_TAILQ_CHECK_HEAD(head, field)
-#define        QMD_TAILQ_CHECK_TAIL(head, headname)
-#define        QMD_TAILQ_CHECK_NEXT(elm, field)
-#define        QMD_TAILQ_CHECK_PREV(elm, field)
-#endif /* (_KERNEL && INVARIANTS) */
-
-#define TAILQ_CONCAT(head1, head2, field)                                      \
-       do {                                                                   \
-               if (!TAILQ_EMPTY(head2)) {                                     \
-                       *(head1)->tqh_last = (head2)->tqh_first;               \
-                       (head2)->tqh_first->field.tqe_prev =                   \
-                               (head1)->tqh_last;                             \
-                       (head1)->tqh_last = (head2)->tqh_last;                 \
-                       TAILQ_INIT((head2));                                   \
-                       QMD_TRACE_HEAD(head1);                                 \
-                       QMD_TRACE_HEAD(head2);                                 \
-               }                                                              \
-       } while (0)
-
-#define        TAILQ_EMPTY(head)       ((head)->tqh_first == NULL)
-
-#define        TAILQ_FIRST(head)       ((head)->tqh_first)
-
-#define TAILQ_FOREACH(var, head, field)                                        \
-       for ((var) = TAILQ_FIRST((head)); (var);                               \
-            (var) = TAILQ_NEXT((var), field))
-
-#define TAILQ_FOREACH_SAFE(var, head, field, tvar)                             \
-       for ((var) = TAILQ_FIRST((head));                                      \
-            (var) && ((tvar) = TAILQ_NEXT((var), field), 1); (var) = (tvar))
-
-#define TAILQ_FOREACH_REVERSE(var, head, headname, field)                      \
-       for ((var) = TAILQ_LAST((head), headname); (var);                      \
-            (var) = TAILQ_PREV((var), headname, field))
-
-#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)           \
-       for ((var) = TAILQ_LAST((head), headname);                             \
-            (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1);        \
-            (var) = (tvar))
-
-#define TAILQ_INIT(head)                                                       \
-       do {                                                                   \
-               TAILQ_FIRST((head)) = NULL;                                    \
-               (head)->tqh_last = &TAILQ_FIRST((head));                       \
-               QMD_TRACE_HEAD(head);                                          \
-       } while (0)
-
-#define TAILQ_INSERT_AFTER(head, listelm, elm, field)                          \
-       do {                                                                   \
-               QMD_TAILQ_CHECK_NEXT(listelm, field);                          \
-               if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field))  \
-                   != NULL)                                                   \
-                       TAILQ_NEXT((elm), field)->field.tqe_prev =             \
-                               &TAILQ_NEXT((elm), field);                     \
-               else {                                                         \
-                       (head)->tqh_last = &TAILQ_NEXT((elm), field);          \
-                       QMD_TRACE_HEAD(head);                                  \
-               }                                                              \
-               TAILQ_NEXT((listelm), field) = (elm);                          \
-               (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field);         \
-               QMD_TRACE_ELEM(&(elm)->field);                                 \
-               QMD_TRACE_ELEM(&listelm->field);                               \
-       } while (0)
-
-#define TAILQ_INSERT_BEFORE(listelm, elm, field)                               \
-       do {                                                                   \
-               QMD_TAILQ_CHECK_PREV(listelm, field);                          \
-               (elm)->field.tqe_prev = (listelm)->field.tqe_prev;             \
-               TAILQ_NEXT((elm), field) = (listelm);                          \
-               *(listelm)->field.tqe_prev = (elm);                            \
-               (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field);         \
-               QMD_TRACE_ELEM(&(elm)->field);                                 \
-               QMD_TRACE_ELEM(&listelm->field);                               \
-       } while (0)
-
-#define TAILQ_INSERT_HEAD(head, elm, field)                                    \
-       do {                                                                   \
-               QMD_TAILQ_CHECK_HEAD(head, field);                             \
-               if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)  \
-                       TAILQ_FIRST((head))->field.tqe_prev =                  \
-                               &TAILQ_NEXT((elm), field);                     \
-               else                                                           \
-                       (head)->tqh_last = &TAILQ_NEXT((elm), field);          \
-               TAILQ_FIRST((head)) = (elm);                                   \
-               (elm)->field.tqe_prev = &TAILQ_FIRST((head));                  \
-               QMD_TRACE_HEAD(head);                                          \
-               QMD_TRACE_ELEM(&(elm)->field);                                 \
-       } while (0)
-
-#define TAILQ_INSERT_TAIL(head, elm, field)                                    \
-       do {                                                                   \
-               QMD_TAILQ_CHECK_TAIL(head, field);                             \
-               TAILQ_NEXT((elm), field) = NULL;                               \
-               (elm)->field.tqe_prev = (head)->tqh_last;                      \
-               *(head)->tqh_last = (elm);                                     \
-               (head)->tqh_last = &TAILQ_NEXT((elm), field);                  \
-               QMD_TRACE_HEAD(head);                                          \
-               QMD_TRACE_ELEM(&(elm)->field);                                 \
-       } while (0)
-
-#define TAILQ_LAST(head, headname)                                             \
-       (*(((struct headname *)((head)->tqh_last))->tqh_last))
-
-#define        TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
-
-#define TAILQ_PREV(elm, headname, field)                                       \
-       (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
-
-#define TAILQ_REMOVE(head, elm, field)                                         \
-       do {                                                                   \
-               QMD_SAVELINK(oldnext, (elm)->field.tqe_next);                  \
-               QMD_SAVELINK(oldprev, (elm)->field.tqe_prev);                  \
-               QMD_TAILQ_CHECK_NEXT(elm, field);                              \
-               QMD_TAILQ_CHECK_PREV(elm, field);                              \
-               if ((TAILQ_NEXT((elm), field)) != NULL)                        \
-                       TAILQ_NEXT((elm), field)->field.tqe_prev =             \
-                               (elm)->field.tqe_prev;                         \
-               else {                                                         \
-                       (head)->tqh_last = (elm)->field.tqe_prev;              \
-                       QMD_TRACE_HEAD(head);                                  \
-               }                                                              \
-               *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);             \
-               TRASHIT(*oldnext);                                             \
-               TRASHIT(*oldprev);                                             \
-               QMD_TRACE_ELEM(&(elm)->field);                                 \
-       } while (0)
-
-#define TAILQ_SWAP(head1, head2, type, field)                                  \
-       do {                                                                   \
-               struct type *swap_first = (head1)->tqh_first;                  \
-               struct type **swap_last = (head1)->tqh_last;                   \
-               (head1)->tqh_first = (head2)->tqh_first;                       \
-               (head1)->tqh_last = (head2)->tqh_last;                         \
-               (head2)->tqh_first = swap_first;                               \
-               (head2)->tqh_last = swap_last;                                 \
-               if ((swap_first = (head1)->tqh_first) != NULL)                 \
-                       swap_first->field.tqe_prev = &(head1)->tqh_first;      \
-               else                                                           \
-                       (head1)->tqh_last = &(head1)->tqh_first;               \
-               if ((swap_first = (head2)->tqh_first) != NULL)                 \
-                       swap_first->field.tqe_prev = &(head2)->tqh_first;      \
-               else                                                           \
-                       (head2)->tqh_last = &(head2)->tqh_first;               \
-       } while (0)
+#include "freebsd-queue.h"
+#endif /* defined(__OpenBSD__) && !defined(STAILQ_HEAD) */
 
-#endif /* !_SYS_QUEUE_H_ */
+#endif /* _FRR_QUEUE_H */
index 6a62cbb67856b2d823051a144b5332feef0f0f2f..85451842286f00484df104c1967b07a1299d6020 100644 (file)
@@ -90,6 +90,7 @@ pkginclude_HEADERS += \
        lib/event_counter.h \
        lib/fifo.h \
        lib/filter.h \
+       lib/freebsd-queue.h \
        lib/frr_pthread.h \
        lib/frratomic.h \
        lib/getopt.h \
@@ -125,6 +126,7 @@ pkginclude_HEADERS += \
        lib/ptm_lib.h \
        lib/pw.h \
        lib/qobj.h \
+       lib/queue.h \
        lib/routemap.h \
        lib/sbuf.h \
        lib/sha256.h \
@@ -222,7 +224,6 @@ EXTRA_DIST += \
        lib/command_lex.h \
        lib/command_parse.h \
        lib/gitversion.pl \
-       lib/queue.h \
        lib/route_types.pl \
        lib/route_types.txt \
        # end
index 833adb9a3702de80abf67d53b6caef039d101066..67cf6aeec3481b7fcac2d1e49d2589b8777bcae1 100644 (file)
@@ -31,7 +31,6 @@
 DEFINE_MTYPE(LIB, ROUTE_TABLE, "Route table")
 DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node")
 
-static void route_node_delete(struct route_node *);
 static void route_table_free(struct route_table *);
 
 static int route_table_hash_cmp(const void *a, const void *b)
@@ -187,23 +186,6 @@ static void set_link(struct route_node *node, struct route_node *new)
        new->parent = node;
 }
 
-/* Lock node. */
-struct route_node *route_lock_node(struct route_node *node)
-{
-       node->lock++;
-       return node;
-}
-
-/* Unlock node. */
-void route_unlock_node(struct route_node *node)
-{
-       assert(node->lock > 0);
-       node->lock--;
-
-       if (node->lock == 0)
-               route_node_delete(node);
-}
-
 /* Find matched prefix. */
 struct route_node *route_node_match(const struct route_table *table,
                                    union prefixconstptr pu)
@@ -348,7 +330,7 @@ struct route_node *route_node_get(struct route_table *const table,
 }
 
 /* Delete node from the routing table. */
-static void route_node_delete(struct route_node *node)
+void route_node_delete(struct route_node *node)
 {
        struct route_node *child;
        struct route_node *parent;
index b7b402a5914135a99a42b03a955b2d3d2d42dc31..9637fec1499ccb2e07a916cbab5e870adeaf0ded 100644 (file)
@@ -182,7 +182,6 @@ route_table_init_with_delegate(route_table_delegate_t *);
 extern route_table_delegate_t *route_table_get_default_delegate(void);
 
 extern void route_table_finish(struct route_table *);
-extern void route_unlock_node(struct route_node *node);
 extern struct route_node *route_top(struct route_table *);
 extern struct route_node *route_next(struct route_node *);
 extern struct route_node *route_next_until(struct route_node *,
@@ -193,7 +192,6 @@ extern struct route_node *route_node_lookup(const struct route_table *,
                                            union prefixconstptr);
 extern struct route_node *route_node_lookup_maynull(const struct route_table *,
                                                    union prefixconstptr);
-extern struct route_node *route_lock_node(struct route_node *node);
 extern struct route_node *route_node_match(const struct route_table *,
                                           union prefixconstptr);
 extern struct route_node *route_node_match_ipv4(const struct route_table *,
@@ -205,6 +203,7 @@ extern unsigned long route_table_count(const struct route_table *);
 
 extern struct route_node *route_node_create(route_table_delegate_t *,
                                            struct route_table *);
+extern void route_node_delete(struct route_node *);
 extern void route_node_destroy(route_table_delegate_t *, struct route_table *,
                               struct route_node *);
 
@@ -225,6 +224,23 @@ extern void route_table_iter_cleanup(route_table_iter_t *iter);
  * Inline functions.
  */
 
+/* Lock node. */
+static inline struct route_node *route_lock_node(struct route_node *node)
+{
+       (*(unsigned *)&node->lock)++;
+       return node;
+}
+
+/* Unlock node. */
+static inline void route_unlock_node(struct route_node *node)
+{
+       assert(node->lock > 0);
+       (*(unsigned *)&node->lock)--;
+
+       if (node->lock == 0)
+               route_node_delete(node);
+}
+
 /*
  * route_table_iter_next
  *
index 612421c80b5fd723696fcdbf5d67d0f9956222f0..b76b73b367b5484379f0be7fa4b60fa53f576b01 100644 (file)
@@ -72,14 +72,7 @@ struct work_queue *work_queue_new(struct thread_master *m,
        new->master = m;
        SET_FLAG(new->flags, WQ_UNPLUGGED);
 
-       if ((new->items = list_new()) == NULL) {
-               XFREE(MTYPE_WORK_QUEUE_NAME, new->name);
-               XFREE(MTYPE_WORK_QUEUE, new);
-
-               return NULL;
-       }
-
-       new->items->del = (void (*)(void *))work_queue_item_free;
+       STAILQ_INIT(&new->items);
 
        listnode_add(work_queues, new);
 
@@ -97,8 +90,6 @@ void work_queue_free(struct work_queue *wq)
        if (wq->thread != NULL)
                thread_cancel(wq->thread);
 
-       /* list_delete frees items via callback */
-       list_delete(wq->items);
        listnode_delete(work_queues, wq);
 
        XFREE(MTYPE_WORK_QUEUE_NAME, wq->name);
@@ -114,8 +105,8 @@ bool work_queue_is_scheduled(struct work_queue *wq)
 static int work_queue_schedule(struct work_queue *wq, unsigned int delay)
 {
        /* if appropriate, schedule work queue thread */
-       if (CHECK_FLAG(wq->flags, WQ_UNPLUGGED) && (wq->thread == NULL)
-           && (listcount(wq->items) > 0)) {
+       if (CHECK_FLAG(wq->flags, WQ_UNPLUGGED) && (wq->thread == NULL) &&
+           !work_queue_empty(wq)) {
                wq->thread = NULL;
                thread_add_timer_msec(wq->master, work_queue_run, wq, delay,
                                      &wq->thread);
@@ -139,33 +130,35 @@ void work_queue_add(struct work_queue *wq, void *data)
        }
 
        item->data = data;
-       listnode_add(wq->items, item);
+       work_queue_item_enqueue(wq, item);
 
        work_queue_schedule(wq, wq->spec.hold);
 
        return;
 }
 
-static void work_queue_item_remove(struct work_queue *wq, struct listnode *ln)
+static void work_queue_item_remove(struct work_queue *wq,
+                                  struct work_queue_item *item)
 {
-       struct work_queue_item *item = listgetdata(ln);
-
        assert(item && item->data);
 
        /* call private data deletion callback if needed */
        if (wq->spec.del_item_data)
                wq->spec.del_item_data(wq, item->data);
 
-       list_delete_node(wq->items, ln);
+       work_queue_item_dequeue(wq, item);
+
        work_queue_item_free(item);
 
        return;
 }
 
-static void work_queue_item_requeue(struct work_queue *wq, struct listnode *ln)
+static void work_queue_item_requeue(struct work_queue *wq, struct work_queue_item *item)
 {
-       LISTNODE_DETACH(wq->items, ln);
-       LISTNODE_ATTACH(wq->items, ln); /* attach to end of list */
+       work_queue_item_dequeue(wq, item);
+
+       /* attach to end of list */
+       work_queue_item_enqueue(wq, item);
 }
 
 DEFUN (show_work_queues,
@@ -186,7 +179,7 @@ DEFUN (show_work_queues,
        for (ALL_LIST_ELEMENTS_RO(work_queues, node, wq)) {
                vty_out(vty, "%c %8d %5d %8ld %8ld %7d %6d %8ld %6u %s\n",
                        (CHECK_FLAG(wq->flags, WQ_UNPLUGGED) ? ' ' : 'P'),
-                       listcount(wq->items), wq->spec.hold, wq->runs,
+                       work_queue_item_count(wq), wq->spec.hold, wq->runs,
                        wq->yields, wq->cycles.best, wq->cycles.granularity,
                        wq->cycles.total,
                        (wq->runs) ? (unsigned int)(wq->cycles.total / wq->runs)
@@ -233,16 +226,15 @@ void work_queue_unplug(struct work_queue *wq)
 int work_queue_run(struct thread *thread)
 {
        struct work_queue *wq;
-       struct work_queue_item *item;
+       struct work_queue_item *item, *titem;
        wq_item_status ret;
        unsigned int cycles = 0;
-       struct listnode *node, *nnode;
        char yielded = 0;
 
        wq = THREAD_ARG(thread);
        wq->thread = NULL;
 
-       assert(wq && wq->items);
+       assert(wq);
 
        /* calculate cycle granularity:
         * list iteration == 1 run
@@ -266,7 +258,7 @@ int work_queue_run(struct thread *thread)
        if (wq->cycles.granularity == 0)
                wq->cycles.granularity = WORK_QUEUE_MIN_GRANULARITY;
 
-       for (ALL_LIST_ELEMENTS(wq->items, node, nnode, item)) {
+       STAILQ_FOREACH_SAFE(item, &wq->items, wq, titem) {
                assert(item && item->data);
 
                /* dont run items which are past their allowed retries */
@@ -274,7 +266,7 @@ int work_queue_run(struct thread *thread)
                        /* run error handler, if any */
                        if (wq->spec.errorfunc)
                                wq->spec.errorfunc(wq, item->data);
-                       work_queue_item_remove(wq, node);
+                       work_queue_item_remove(wq, item);
                        continue;
                }
 
@@ -298,7 +290,7 @@ int work_queue_run(struct thread *thread)
                }
                case WQ_REQUEUE: {
                        item->ran--;
-                       work_queue_item_requeue(wq, node);
+                       work_queue_item_requeue(wq, item);
                        /* If a single node is being used with a meta-queue
                         * (e.g., zebra),
                         * update the next node as we don't want to exit the
@@ -309,8 +301,8 @@ int work_queue_run(struct thread *thread)
                         * will kick in
                         * to terminate the thread when time has exceeded.
                         */
-                       if (nnode == NULL)
-                               nnode = node;
+                       if (titem == NULL)
+                               titem = item;
                        break;
                }
                case WQ_RETRY_NOW:
@@ -323,7 +315,7 @@ int work_queue_run(struct thread *thread)
                /* fallthru */
                case WQ_SUCCESS:
                default: {
-                       work_queue_item_remove(wq, node);
+                       work_queue_item_remove(wq, item);
                        break;
                }
                }
@@ -376,7 +368,7 @@ stats:
 #endif
 
        /* Is the queue done yet? If it is, call the completion callback. */
-       if (listcount(wq->items) > 0)
+       if (!work_queue_empty(wq))
                work_queue_schedule(wq, 0);
        else if (wq->spec.completion_func)
                wq->spec.completion_func(wq);
index ff7f57690dd93721be68b5964fbe149508e0d1a1..df35d44fbcb9a67d48c33c9cf01e77992e8afbb0 100644 (file)
@@ -24,6 +24,7 @@
 #define _QUAGGA_WORK_QUEUE_H
 
 #include "memory.h"
+#include "queue.h"
 DECLARE_MTYPE(WORK_QUEUE)
 
 /* Hold time for the initial schedule of a queue run, in  millisec */
@@ -43,6 +44,7 @@ typedef enum {
 
 /* A single work queue item, unsurprisingly */
 struct work_queue_item {
+       STAILQ_ENTRY(work_queue_item) wq;
        void *data;      /* opaque data */
        unsigned short ran; /* # of times item has been run */
 };
@@ -91,7 +93,8 @@ struct work_queue {
        } spec;
 
        /* remaining fields should be opaque to users */
-       struct list *items;   /* queue item list */
+       STAILQ_HEAD(work_queue_items, work_queue_item) items; /* queue item list */
+       int item_count; /* queued items */
        unsigned long runs;   /* runs count */
        unsigned long yields; /* yields count */
 
@@ -107,6 +110,37 @@ struct work_queue {
 
 /* User API */
 
+static inline int work_queue_item_count(struct work_queue *wq)
+{
+       return wq->item_count;
+}
+
+static inline bool work_queue_empty(struct work_queue *wq)
+{
+       return (wq->item_count == 0) ? true : false;
+}
+
+static inline struct work_queue_item *work_queue_last_item(struct work_queue *wq)
+{
+       return STAILQ_LAST(&wq->items, work_queue_item, wq);
+}
+
+static inline void work_queue_item_enqueue(struct work_queue *wq,
+                                          struct work_queue_item *item)
+{
+       STAILQ_INSERT_TAIL(&wq->items, item, wq);
+       wq->item_count++;
+}
+
+static inline void work_queue_item_dequeue(struct work_queue *wq,
+                                          struct work_queue_item *item)
+{
+       assert(wq->item_count > 0);
+
+       wq->item_count--;
+       STAILQ_REMOVE(&wq->items, item, work_queue_item, wq);
+}
+
 /* create a new work queue, of given name.
  * user must fill in the spec of the returned work queue before adding
  * anything to it
index 58ad1675498da2c1af91be0fb8d0b584ea17eb3b..a46962c91af37a41e073e3e91d2eab1fe344ad49 100644 (file)
@@ -48,8 +48,8 @@ static int nhrp_if_delete_hook(struct interface *ifp)
 
 void nhrp_interface_init(void)
 {
-       if_add_hook(IF_NEW_HOOK,    nhrp_if_new_hook);
-       if_add_hook(IF_DELETE_HOOK, nhrp_if_delete_hook);
+       hook_register_prio(if_add, 0, nhrp_if_new_hook);
+       hook_register_prio(if_del, 0, nhrp_if_delete_hook);
 }
 
 void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi)
index 012d5cd87c0d143a10a9615f2b9fb2a4217634f3..3a7186c1d799dfcce0d315d258d11087c8be530f 100644 (file)
@@ -81,6 +81,7 @@ static void nhrp_sigusr1(void)
 static void nhrp_request_stop(void)
 {
        debugf(NHRP_DEBUG_COMMON, "Exiting...");
+       frr_early_fini();
 
        nhrp_shortcut_terminate();
        nhrp_nhs_terminate();
@@ -89,15 +90,9 @@ static void nhrp_request_stop(void)
        evmgr_terminate();
        nhrp_vc_terminate();
        vrf_terminate();
-       /* memory_terminate(); */
-       /* vty_terminate(); */
-       cmd_terminate();
-       /* signal_terminate(); */
-       zprivs_terminate(&nhrpd_privs);
 
        debugf(NHRP_DEBUG_COMMON, "Done.");
-
-       closezlog();
+       frr_fini();
 
        exit(0);
 }
index 20ef17de00bfb9993e8653e7b1f791e58c076411..6d78fc1d2b25f37cc52dda164251a8f4dca79491 100644 (file)
@@ -110,11 +110,11 @@ static int toggle_flag(
 
 #ifndef NO_DEBUG
 
-DEFUN(show_debugging_nhrp, show_debugging_nhrp_cmd,
-       "show debugging nhrp",
-       SHOW_STR
-       "Debugging information\n"
-       "NHRP configuration\n")
+DEFUN_NOSH(show_debugging_nhrp, show_debugging_nhrp_cmd,
+          "show debugging [nhrp]",
+          SHOW_STR
+          "Debugging information\n"
+          "NHRP configuration\n")
 {
        int i;
 
index 28bb956c403d819328bbd03b27fd2931249c6495..e582737f940e9f16c1ca2a2b702b72e7352cf5f0 100644 (file)
@@ -82,6 +82,8 @@ static void __attribute__((noreturn)) ospf6_exit(int status)
        struct listnode *node;
        struct interface *ifp;
 
+       frr_early_fini();
+
        if (ospf6)
                ospf6_delete(ospf6);
 
@@ -96,19 +98,13 @@ static void __attribute__((noreturn)) ospf6_exit(int status)
        ospf6_lsa_terminate();
 
        vrf_terminate();
-       vty_terminate();
-       cmd_terminate();
 
        if (zclient) {
                zclient_stop(zclient);
                zclient_free(zclient);
        }
 
-       if (master)
-               thread_master_free(master);
-
-       closezlog();
-
+       frr_fini();
        exit(status);
 }
 
index 48c34b79751d18e3abfeeb6296a477e5614fba3a..f6b9e0ec140ed116c1ce49370ea4949b6f7ad75c 100644 (file)
@@ -85,10 +85,24 @@ static int config_write_ospf6_debug(struct vty *vty)
        config_write_ospf6_debug_asbr(vty);
        config_write_ospf6_debug_abr(vty);
        config_write_ospf6_debug_flood(vty);
-       vty_out(vty, "!\n");
+
        return 0;
 }
 
+DEFUN_NOSH (show_debugging_ospf6,
+           show_debugging_ospf6_cmd,
+           "show debugging [ospf6]",
+           SHOW_STR
+           DEBUG_STR
+           OSPF6_STR)
+{
+       vty_out(vty, "OSPF6 debugging status:");
+
+       config_write_ospf6_debug(vty);
+
+       return CMD_SUCCESS;
+}
+
 #define AREA_LSDB_TITLE_FORMAT                                                 \
        "\n        Area Scoped Link State Database (Area %s)\n\n"
 #define IF_LSDB_TITLE_FORMAT                                                   \
@@ -1157,6 +1171,8 @@ void ospf6_init(void)
 
        install_element_ospf6_clear_interface();
 
+       install_element(VIEW_NODE, &show_debugging_ospf6_cmd);
+
        install_element(VIEW_NODE, &show_ipv6_ospf6_border_routers_cmd);
 
        install_element(VIEW_NODE, &show_ipv6_ospf6_linkstate_cmd);
index d3d1ffed5ec3f19b631d4ef0a03a2330e305b49e..619bd4e5f529d9b7546a49b09a1072103a0d5dea 100644 (file)
@@ -1597,12 +1597,12 @@ static int show_debugging_ospf_common(struct vty *vty, struct ospf *ospf)
        return CMD_SUCCESS;
 }
 
-DEFUN (show_debugging_ospf,
-       show_debugging_ospf_cmd,
-       "show debugging ospf",
-       SHOW_STR
-       DEBUG_STR
-       OSPF_STR)
+DEFUN_NOSH (show_debugging_ospf,
+           show_debugging_ospf_cmd,
+           "show debugging [ospf]",
+           SHOW_STR
+           DEBUG_STR
+           OSPF_STR)
 {
        struct ospf *ospf;
 
@@ -1612,13 +1612,13 @@ DEFUN (show_debugging_ospf,
        return show_debugging_ospf_common(vty, ospf);
 }
 
-DEFUN (show_debugging_ospf_instance,
-       show_debugging_ospf_instance_cmd,
-       "show debugging ospf (1-65535)",
-       SHOW_STR
-       DEBUG_STR
-       OSPF_STR
-       "Instance ID\n")
+DEFUN_NOSH (show_debugging_ospf_instance,
+           show_debugging_ospf_instance_cmd,
+           "show debugging ospf (1-65535)",
+           SHOW_STR
+           DEBUG_STR
+           OSPF_STR
+           "Instance ID\n")
 {
        int idx_number = 3;
        struct ospf *ospf;
index 4ea8ec26f2acf892d923a212e60f361484b6007a..54639afd6c852cf4cf2bb52f8ddc6f14eec7d3d0 100644 (file)
@@ -1163,6 +1163,6 @@ void ospf_if_init()
 {
        /* Initialize Zebra interface data structure. */
        om->iflist = vrf_iflist(VRF_DEFAULT);
-       if_add_hook(IF_NEW_HOOK, ospf_if_new_hook);
-       if_add_hook(IF_DELETE_HOOK, ospf_if_delete_hook);
+       hook_register_prio(if_add, 0, ospf_if_new_hook);
+       hook_register_prio(if_del, 0, ospf_if_delete_hook);
 }
index ac2406ec2d363f5733d495e2b73359606ac6f10c..36f9a6757a1d4bb34bca4ff3deb5685157a87e9a 100644 (file)
@@ -3938,7 +3938,7 @@ void ospf_ls_upd_send(struct ospf_neighbor *nbr, struct list *update, int flag)
                if (flag == OSPF_SEND_PACKET_INDIRECT)
                        zlog_warn(
                                "* LS-Update is directly sent on NBMA network.");
-               if (IPV4_ADDR_SAME(&oi->address->u.prefix4, &p.prefix.s_addr))
+               if (IPV4_ADDR_SAME(&oi->address->u.prefix4, &p.prefix))
                        zlog_warn("* LS-Update is sent to myself.");
        }
 
index 3bffaf855b893c5f3726d28d9b29e0ce18ee8440..9c79fd87e2980e4dcfc26f51c6767a6a91098115 100644 (file)
@@ -7254,14 +7254,17 @@ DEFUN (no_debug_msdp_packets,
 ALIAS(no_debug_msdp_packets, undebug_msdp_packets_cmd, "undebug msdp packets",
       UNDEBUG_STR DEBUG_MSDP_STR DEBUG_MSDP_PACKETS_STR)
 
-DEFUN (show_debugging_pim,
-       show_debugging_pim_cmd,
-       "show debugging pim",
-       SHOW_STR
-       DEBUG_STR
-       PIM_STR)
+DEFUN_NOSH (show_debugging_pim,
+           show_debugging_pim_cmd,
+           "show debugging [pim]",
+           SHOW_STR
+           DEBUG_STR
+           PIM_STR)
 {
+       vty_out(vty, "PIM debugging status\n");
+
        pim_debug_config_write(vty);
+
        return CMD_SUCCESS;
 }
 
index 12cdcf04fe699df78a59df5df05baabeebe9d529..cc0632b56252035f42cfab193f0ba3e88e506ad2 100644 (file)
@@ -13,7 +13,6 @@
 %{!?with_pam:           %global  with_pam           0 }
 %{!?with_ospfclient:    %global  with_ospfclient    1 }
 %{!?with_ospfapi:       %global  with_ospfapi       1 }
-%{!?with_irdp:          %global  with_irdp          1 }
 %{!?with_rtadv:         %global  with_rtadv         1 }
 %{!?with_ldpd:          %global  with_ldpd          1 }
 %{!?with_nhrpd:         %global  with_nhrpd         1 }
@@ -221,6 +220,7 @@ developing OSPF-API and frr applications.
     --libexecdir=%{_libexecdir} \
     --localstatedir=%{_localstatedir} \
     --disable-werror \
+    --enable-irdp \
 %if !%{with_shared}
     --disable-shared \
 %endif
@@ -238,11 +238,6 @@ developing OSPF-API and frr applications.
 %else
     --enable-ospfapi=no \
 %endif
-%if %{with_irdp}
-    --enable-irdp=yes \
-%else
-    --enable-irdp=no \
-%endif
 %if %{with_rtadv}
     --enable-rtadv=yes \
 %else
@@ -325,6 +320,9 @@ rm -rf %{buildroot}/usr/share/info/dir
 # Remove debian init script if it was installed
 rm -f %{buildroot}%{_sbindir}/frr
 
+# kill bogus libtool files for modules
+rm -f %{buildroot}%{_libdir}/frr/modules/*.la
+
 # install /etc sources
 %if "%{initsystem}" == "systemd"
 mkdir -p %{buildroot}%{_unitdir}
@@ -554,6 +552,7 @@ rm -rf %{buildroot}
 %{_libdir}/lib*.so.0
 %attr(755,root,root) %{_libdir}/lib*.so.0.*
 %endif
+%attr(755,root,root) %{_libdir}/frr/modules/zebra_irdp.so
 %{_bindir}/*
 %config(noreplace) /etc/frr/[!v]*.conf*
 %config(noreplace) %attr(750,%frr_user,%frr_user) /etc/frr/daemons
index 492d036991b9ece51d21a6cda35b7d34b9e0d39f..56ba8e7f3e75426845dfa94d802730d24dee2996 100644 (file)
@@ -27,12 +27,12 @@ unsigned long rip_debug_event = 0;
 unsigned long rip_debug_packet = 0;
 unsigned long rip_debug_zebra = 0;
 
-DEFUN (show_debugging_rip,
-       show_debugging_rip_cmd,
-       "show debugging rip",
-       SHOW_STR
-       DEBUG_STR
-       RIP_STR)
+DEFUN_NOSH (show_debugging_rip,
+           show_debugging_rip_cmd,
+           "show debugging [rip]",
+           SHOW_STR
+           DEBUG_STR
+           RIP_STR)
 {
        vty_out(vty, "RIP debugging status:\n");
 
index a1704711230dc01b31b5b7ed1e9fa7f7cece36a7..00b6d1cadd2aaafc3ed15d9e7b523fc2583eaf3c 100644 (file)
@@ -1877,8 +1877,8 @@ static int rip_interface_delete_hook(struct interface *ifp)
 void rip_if_init(void)
 {
        /* Default initial size of interface vector. */
-       if_add_hook(IF_NEW_HOOK, rip_interface_new_hook);
-       if_add_hook(IF_DELETE_HOOK, rip_interface_delete_hook);
+       hook_register_prio(if_add, 0, rip_interface_new_hook);
+       hook_register_prio(if_del, 0, rip_interface_delete_hook);
 
        /* RIP network init. */
        rip_enable_interface = vector_init(1);
index d56161d39e19aff0f88f3ecef78280f9637ee7a0..9ebc302b1b32e9be2d72edda4ca0923828535c3e 100644 (file)
@@ -28,12 +28,12 @@ unsigned long ripng_debug_event = 0;
 unsigned long ripng_debug_packet = 0;
 unsigned long ripng_debug_zebra = 0;
 
-DEFUN (show_debugging_ripng,
-       show_debugging_ripng_cmd,
-       "show debugging ripng",
-       SHOW_STR
-       DEBUG_STR
-       "RIPng configuration\n")
+DEFUN_NOSH (show_debugging_ripng,
+           show_debugging_ripng_cmd,
+           "show debugging [ripng]",
+           SHOW_STR
+           DEBUG_STR
+           "RIPng configuration\n")
 {
        vty_out(vty, "RIPng debugging status:\n");
 
index c762d8ace729cadee9c7eb2c3105101352bea045..02fab6825483b48a77449e905063ec0e7c9ee78a 100644 (file)
@@ -1121,8 +1121,8 @@ static struct cmd_node interface_node = {
 void ripng_if_init()
 {
        /* Interface initialize. */
-       if_add_hook(IF_NEW_HOOK, ripng_if_new_hook);
-       if_add_hook(IF_DELETE_HOOK, ripng_if_delete_hook);
+       hook_register_prio(if_add, 0, ripng_if_new_hook);
+       hook_register_prio(if_del, 0, ripng_if_delete_hook);
 
        /* RIPng enable network init. */
        ripng_enable_network = route_table_init();
index 0bea3ee81d089a5d8b28f8b2dd5eb94327a127c5..4eb4a5c28c7c05fde305f14dcf8e7e3a1d3694ac 100755 (executable)
--- a/tools/frr
+++ b/tools/frr
@@ -72,6 +72,11 @@ vtysh_b ()
 # returns:      0=ok, 1=error
 check_daemon()
 {
+        if [ $1 != "watchfrr" -a $1 != "vtysh_enable" ]; then
+          # check for daemon binary
+          if [ ! -x "$D_PATH/$1" ]; then return 1; fi
+        fi
+
         # If the integrated config file is used the others are not checked.
         if [ -r "$C_PATH/frr.conf" ]; then
           return 0
@@ -80,9 +85,6 @@ check_daemon()
         # vtysh_enable has no config file nor binary so skip check.
         # (Not sure why vtysh_enable is in this list but does not hurt)
         if [ $1 != "watchfrr" -a $1 != "vtysh_enable" ]; then
-          # check for daemon binary
-          if [ ! -x "$D_PATH/$1" ]; then return 1; fi
-
           # check for config file
           if [ -n "$2" ]; then
            if [ ! -r "$C_PATH/$1-$2.conf" ]; then
index 43496d4cbfebc64610d0beddb1c8b74dba370809..8556f0b46e4858273dae854945ea8c62982750a5 100755 (executable)
@@ -1162,19 +1162,11 @@ if __name__ == '__main__':
                         for line in lines_to_configure:
                             fh.write(line + '\n')
 
-                    output = subprocess.check_output(['/usr/bin/vtysh', '-f', filename])
-
-                    # exit non-zero if we see these errors
-                    for x in ('BGP instance name and AS number mismatch',
-                              'BGP instance is already running',
-                              '% not a local address'):
-                        for line in output.splitlines():
-                            if x in line:
-                                msg = "ERROR: %s" % x
-                                log.error(msg)
-                                print msg
-                                reload_ok = False
-
+                    try:
+                        subprocess.check_output(['/usr/bin/vtysh', '-f', filename])
+                    except subprocess.CalledProcessError as e:
+                        log.warning("frr-reload.py failed due to\n%s" % e.output)
+                        reload_ok = False
                     os.unlink(filename)
 
         # Make these changes persistent
index f971c171bc328afcc5dfbab5b8bc2c033cf98570..85cbcae4dfa4db8b10b84e980a8c4e2b0cca1513 100644 (file)
@@ -752,6 +752,7 @@ int vtysh_config_from_file(struct vty *vty, FILE *fp)
                                                        lineno, cmd_stat,
                                                        vtysh_client[i].name,
                                                        vty->buf);
+                                               retcode = cmd_stat;
                                                break;
                                        }
                                }
@@ -1914,6 +1915,28 @@ static int show_per_daemon(const char *line, const char *headline)
        return ret;
 }
 
+DEFUN (vtysh_show_debugging,
+       vtysh_show_debugging_cmd,
+       "show debugging",
+       SHOW_STR
+       DEBUG_STR)
+{
+       return show_per_daemon("do show debugging\n",
+                              "Debugging Information for %s:\n");
+}
+
+DEFUN (vtysh_show_debugging_hashtable,
+       vtysh_show_debugging_hashtable_cmd,
+       "show debugging hashtable [statistics]",
+       SHOW_STR
+       DEBUG_STR
+       "Statistics about hash tables\n"
+       "Statistics about hash tables\n")
+{
+       return show_per_daemon("do show debugging hashtable\n",
+                              "Hashtable statistics for %s:\n");
+}
+
 /* Memory */
 DEFUN (vtysh_show_memory,
        vtysh_show_memory_cmd,
@@ -1921,7 +1944,8 @@ DEFUN (vtysh_show_memory,
        SHOW_STR
        "Memory statistics\n")
 {
-       return show_per_daemon("show memory\n", "Memory statistics for %s:\n");
+       return show_per_daemon("show memory\n",
+                              "Memory statistics for %s:\n");
 }
 
 DEFUN (vtysh_show_modules,
@@ -1941,20 +1965,8 @@ DEFUN (vtysh_show_logging,
        SHOW_STR
        "Show current logging configuration\n")
 {
-       unsigned int i;
-       int ret = CMD_SUCCESS;
-       char line[] = "do show logging\n";
-
-       for (i = 0; i < array_size(vtysh_client); i++)
-               if (vtysh_client[i].fd >= 0) {
-                       fprintf(stdout, "Logging configuration for %s:\n",
-                               vtysh_client[i].name);
-                       ret = vtysh_client_execute(&vtysh_client[i], line,
-                                                  stdout);
-                       fprintf(stdout, "\n");
-               }
-
-       return ret;
+       return show_per_daemon("do show logging\n",
+                              "Logging configuration for %s:\n");
 }
 
 DEFUNSH(VTYSH_ALL, vtysh_log_stdout, vtysh_log_stdout_cmd, "log stdout",
@@ -3232,6 +3244,8 @@ void vtysh_init_vty(void)
        install_element(ENABLE_NODE, &vtysh_start_zsh_cmd);
 #endif
 
+       install_element(VIEW_NODE, &vtysh_show_debugging_cmd);
+       install_element(VIEW_NODE, &vtysh_show_debugging_hashtable_cmd);
        install_element(VIEW_NODE, &vtysh_show_memory_cmd);
        install_element(VIEW_NODE, &vtysh_show_modules_cmd);
 
index 25f47bc51a8fa85e9068c0ce18a036f79699f496..afeba1c6dea19f090e136b0096e156a5123e07ee 100644 (file)
@@ -34,12 +34,12 @@ unsigned long zebra_debug_mpls;
 unsigned long zebra_debug_vxlan;
 unsigned long zebra_debug_pw;
 
-DEFUN (show_debugging_zebra,
-       show_debugging_zebra_cmd,
-       "show debugging zebra",
-       SHOW_STR
-       "Debugging information\n"
-       "Zebra configuration\n")
+DEFUN_NOSH (show_debugging_zebra,
+           show_debugging_zebra_cmd,
+           "show debugging [zebra]",
+           SHOW_STR
+           "Debugging information\n"
+           "Zebra configuration\n")
 {
        vty_out(vty, "Zebra debugging status:\n");
 
index c4d0363994f51c5169f06bd45fe789259edd3c67..c17e408ea0e062903fb19ec91a3969228f57854d 100644 (file)
 
 #define ZEBRA_PTM_SUPPORT
 
-#if defined(HAVE_RTADV)
-/* Order is intentional.  Matches RFC4191.  This array is also used for
-   command matching, so only modify with care. */
-const char *rtadv_pref_strs[] = {"medium", "high", "INVALID", "low", 0};
-#endif /* HAVE_RTADV */
+DEFINE_HOOK(zebra_if_extra_info, (struct vty *vty, struct interface *ifp),
+                                (vty, ifp))
+DEFINE_HOOK(zebra_if_config_wr, (struct vty *vty, struct interface *ifp),
+                               (vty, ifp))
 
 static void if_down_del_nbr_connected(struct interface *ifp);
 
@@ -996,74 +995,6 @@ static void nbr_connected_dump_vty(struct vty *vty,
        vty_out(vty, "\n");
 }
 
-#if defined(HAVE_RTADV)
-/* Dump interface ND information to vty. */
-static void nd_dump_vty(struct vty *vty, struct interface *ifp)
-{
-       struct zebra_if *zif;
-       struct rtadvconf *rtadv;
-       int interval;
-
-       zif = (struct zebra_if *)ifp->info;
-       rtadv = &zif->rtadv;
-
-       if (rtadv->AdvSendAdvertisements) {
-               vty_out(vty,
-                       "  ND advertised reachable time is %d milliseconds\n",
-                       rtadv->AdvReachableTime);
-               vty_out(vty,
-                       "  ND advertised retransmit interval is %d milliseconds\n",
-                       rtadv->AdvRetransTimer);
-               vty_out(vty, "  ND router advertisements sent: %d rcvd: %d\n",
-                       zif->ra_sent, zif->ra_rcvd);
-               interval = rtadv->MaxRtrAdvInterval;
-               if (interval % 1000)
-                       vty_out(vty,
-                               "  ND router advertisements are sent every "
-                               "%d milliseconds\n",
-                               interval);
-               else
-                       vty_out(vty,
-                               "  ND router advertisements are sent every "
-                               "%d seconds\n",
-                               interval / 1000);
-               if (rtadv->AdvDefaultLifetime != -1)
-                       vty_out(vty,
-                               "  ND router advertisements live for %d seconds\n",
-                               rtadv->AdvDefaultLifetime);
-               else
-                       vty_out(vty,
-                               "  ND router advertisements lifetime tracks ra-interval\n");
-               vty_out(vty,
-                       "  ND router advertisement default router preference is "
-                       "%s\n",
-                       rtadv_pref_strs[rtadv->DefaultPreference]);
-               if (rtadv->AdvManagedFlag)
-                       vty_out(vty,
-                               "  Hosts use DHCP to obtain routable addresses.\n");
-               else
-                       vty_out(vty,
-                               "  Hosts use stateless autoconfig for addresses.\n");
-               if (rtadv->AdvHomeAgentFlag) {
-                       vty_out(vty,
-                               "  ND router advertisements with Home Agent flag bit set.\n");
-                       if (rtadv->HomeAgentLifetime != -1)
-                               vty_out(vty,
-                                       "  Home Agent lifetime is %u seconds\n",
-                                       rtadv->HomeAgentLifetime);
-                       else
-                               vty_out(vty,
-                                       "  Home Agent lifetime tracks ra-lifetime\n");
-                       vty_out(vty, "  Home Agent preference is %u\n",
-                               rtadv->HomeAgentPreference);
-               }
-               if (rtadv->AdvIntervalOption)
-                       vty_out(vty,
-                               "  ND router advertisements with Adv. Interval option.\n");
-       }
-}
-#endif /* HAVE_RTADV */
-
 static const char *zebra_ziftype_2str(zebra_iftype_t zif_type)
 {
        switch (zif_type) {
@@ -1277,12 +1208,8 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
                                inet_ntoa(iflp->rmt_ip), iflp->rmt_as);
        }
 
-#ifdef RTADV
-       nd_dump_vty(vty, ifp);
-#endif /* RTADV */
-#if defined(HAVE_RTADV)
-       nd_dump_vty(vty, ifp);
-#endif /* HAVE_RTADV */
+       hook_call(zebra_if_extra_info, vty, ifp);
+
        if (listhead(ifp->nbr_connected))
                vty_out(vty, "  Neighbor address(s):\n");
        for (ALL_LIST_ELEMENTS_RO(ifp->nbr_connected, node, nbr_connected))
@@ -2911,13 +2838,7 @@ static int if_config_write(struct vty *vty)
                                                : "no ");
                }
 
-#if defined(HAVE_RTADV)
-               rtadv_config_write(vty, ifp);
-#endif /* HAVE_RTADV */
-
-#ifdef HAVE_IRDP
-               irdp_config_write(vty, ifp);
-#endif /* IRDP */
+               hook_call(zebra_if_config_wr, vty, ifp);
 
                link_params_config_write(vty, ifp);
 
@@ -2930,8 +2851,8 @@ static int if_config_write(struct vty *vty)
 void zebra_if_init(void)
 {
        /* Initialize interface and new hook. */
-       if_add_hook(IF_NEW_HOOK, if_zebra_new_hook);
-       if_add_hook(IF_DELETE_HOOK, if_zebra_delete_hook);
+       hook_register_prio(if_add, 0, if_zebra_new_hook);
+       hook_register_prio(if_del, 0, if_zebra_delete_hook);
 
        /* Install configuration write function. */
        install_node(&interface_node, if_config_write);
index 970c3c52927b78fe5d67883cb245ba679628273c..7b56dcd4a40c7263f1b1ba1052963153df1fc4d3 100644 (file)
 
 #include "redistribute.h"
 #include "vrf.h"
-
-#ifdef HAVE_IRDP
-#include "zebra/irdp.h"
-#endif
+#include "hook.h"
 
 #include "zebra/zebra_l2.h"
 
@@ -202,6 +199,8 @@ typedef enum {
        ZEBRA_IF_SLAVE_OTHER,  /* Something else - e.g., bond slave */
 } zebra_slave_iftype_t;
 
+struct irdp_interface;
+
 /* `zebra' daemon local interface structure. */
 struct zebra_if {
        /* Shutdown configuration. */
@@ -227,9 +226,7 @@ struct zebra_if {
        unsigned int ra_sent, ra_rcvd;
 #endif /* HAVE_RTADV */
 
-#ifdef HAVE_IRDP
-       struct irdp_interface irdp;
-#endif
+       struct irdp_interface *irdp;
 
 #ifdef HAVE_STRUCT_SOCKADDR_DL
        union {
@@ -273,6 +270,11 @@ struct zebra_if {
        struct interface *link;
 };
 
+DECLARE_HOOK(zebra_if_extra_info, (struct vty *vty, struct interface *ifp),
+                                 (vty, ifp))
+DECLARE_HOOK(zebra_if_config_wr, (struct vty *vty, struct interface *ifp),
+                                (vty, ifp))
+
 static inline void zebra_if_set_ziftype(struct interface *ifp,
                                        zebra_iftype_t zif_type,
                                        zebra_slave_iftype_t zif_slave_type)
index 01308b915b3f4a316e142a771d465fb42b3fd6c5..ea190b574df0896af22df60ae7f05f7b2e74fcfc 100644 (file)
@@ -138,10 +138,9 @@ struct Adv {
        int pref;
 };
 
-extern void irdp_init(void);
+extern void irdp_if_init(void);
 extern int irdp_sock_init(void);
-extern void irdp_finish(void);
-extern void irdp_config_write(struct vty *, struct interface *);
+extern int irdp_config_write(struct vty *, struct interface *);
 extern int irdp_send_thread(struct thread *t_advert);
 extern void irdp_advert_off(struct interface *ifp);
 extern void process_solicit(struct interface *ifp);
index 5682e12e6f51385e07095b67e35b16fed835b4ef..34c78e2a482002ea7182f2a1fb25c6c0ebf454e9 100644 (file)
@@ -35,8 +35,6 @@
 
 #include <zebra.h>
 
-#ifdef HAVE_IRDP
-
 #include "if.h"
 #include "vty.h"
 #include "sockunion.h"
 
 extern int irdp_sock;
 
+DEFINE_MTYPE_STATIC(ZEBRA, IRDP_IF, "IRDP interface data")
+
+static struct irdp_interface *irdp_if_get(struct interface *ifp)
+{
+       struct zebra_if *zi = ifp->info;
+       if (!zi->irdp)
+               zi->irdp = XCALLOC(MTYPE_IRDP_IF, sizeof(*zi->irdp));
+       return zi->irdp;
+}
+
+static int irdp_if_delete(struct interface *ifp)
+{
+       struct zebra_if *zi = ifp->info;
+       if (!zi)
+               return 0;
+       XFREE(MTYPE_IRDP_IF, zi->irdp);
+       return 0;
+}
+
 static const char *inet_2a(u_int32_t a, char *b)
 {
        sprintf(b, "%u.%u.%u.%u", (a)&0xFF, (a >> 8) & 0xFF, (a >> 16) & 0xFF,
@@ -117,10 +134,13 @@ static int if_group(struct interface *ifp, int sock, u_int32_t group,
 static int if_add_group(struct interface *ifp)
 {
        struct zebra_if *zi = ifp->info;
-       struct irdp_interface *irdp = &zi->irdp;
+       struct irdp_interface *irdp = zi->irdp;
        int ret;
        char b1[INET_ADDRSTRLEN];
 
+       if (!irdp)
+               return -1;
+
        ret = if_group(ifp, irdp_sock, INADDR_ALLRTRS_GROUP, IP_ADD_MEMBERSHIP);
        if (ret < 0) {
                return ret;
@@ -135,10 +155,13 @@ static int if_add_group(struct interface *ifp)
 static int if_drop_group(struct interface *ifp)
 {
        struct zebra_if *zi = ifp->info;
-       struct irdp_interface *irdp = &zi->irdp;
+       struct irdp_interface *irdp = zi->irdp;
        int ret;
        char b1[INET_ADDRSTRLEN];
 
+       if (!irdp)
+               return -1;
+
        ret = if_group(ifp, irdp_sock, INADDR_ALLRTRS_GROUP,
                       IP_DROP_MEMBERSHIP);
        if (ret < 0)
@@ -150,11 +173,8 @@ static int if_drop_group(struct interface *ifp)
        return 0;
 }
 
-static void if_set_defaults(struct interface *ifp)
+static void if_set_defaults(struct irdp_interface *irdp)
 {
-       struct zebra_if *zi = ifp->info;
-       struct irdp_interface *irdp = &zi->irdp;
-
        irdp->MaxAdvertInterval = IRDP_MAXADVERTINTERVAL;
        irdp->MinAdvertInterval = IRDP_MINADVERTINTERVAL;
        irdp->Preference = IRDP_PREFERENCE;
@@ -176,11 +196,13 @@ static void irdp_if_start(struct interface *ifp, int multicast,
                          int set_defaults)
 {
        struct zebra_if *zi = ifp->info;
-       struct irdp_interface *irdp = &zi->irdp;
+       struct irdp_interface *irdp = zi->irdp;
        struct listnode *node;
        struct connected *ifc;
        u_int32_t timer, seed;
 
+       assert(irdp);
+
        if (irdp->flags & IF_ACTIVE) {
                zlog_warn("IRDP: Interface is already active %s", ifp->name);
                return;
@@ -215,7 +237,7 @@ static void irdp_if_start(struct interface *ifp, int multicast,
        }
 
        if (set_defaults)
-               if_set_defaults(ifp);
+               if_set_defaults(irdp);
 
        irdp->irdp_sent = 0;
 
@@ -254,7 +276,7 @@ static void irdp_if_start(struct interface *ifp, int multicast,
 static void irdp_if_stop(struct interface *ifp)
 {
        struct zebra_if *zi = ifp->info;
-       struct irdp_interface *irdp = &zi->irdp;
+       struct irdp_interface *irdp = zi->irdp;
 
        if (irdp == NULL) {
                zlog_warn("Interface %s structure is NULL", ifp->name);
@@ -281,8 +303,10 @@ static void irdp_if_stop(struct interface *ifp)
 static void irdp_if_shutdown(struct interface *ifp)
 {
        struct zebra_if *zi = ifp->info;
-       struct irdp_interface *irdp = &zi->irdp;
+       struct irdp_interface *irdp = zi->irdp;
 
+       if (!irdp)
+               return;
        if (irdp->flags & IF_SHUTDOWN) {
                zlog_warn("IRDP: Interface is already shutdown %s", ifp->name);
                return;
@@ -300,8 +324,7 @@ static void irdp_if_shutdown(struct interface *ifp)
 
 static void irdp_if_no_shutdown(struct interface *ifp)
 {
-       struct zebra_if *zi = ifp->info;
-       struct irdp_interface *irdp = &zi->irdp;
+       struct irdp_interface *irdp = irdp_if_get(ifp);
 
        if (!(irdp->flags & IF_SHUTDOWN)) {
                zlog_warn("IRDP: Interface is not shutdown %s", ifp->name);
@@ -316,14 +339,17 @@ static void irdp_if_no_shutdown(struct interface *ifp)
 
 /* Write configuration to user */
 
-void irdp_config_write(struct vty *vty, struct interface *ifp)
+int irdp_config_write(struct vty *vty, struct interface *ifp)
 {
        struct zebra_if *zi = ifp->info;
-       struct irdp_interface *irdp = &zi->irdp;
+       struct irdp_interface *irdp = zi->irdp;
        struct Adv *adv;
        struct listnode *node;
        char b1[INET_ADDRSTRLEN];
 
+       if (!irdp)
+               return 0;
+
        if (irdp->flags & IF_ACTIVE || irdp->flags & IF_SHUTDOWN) {
 
                if (irdp->flags & IF_SHUTDOWN)
@@ -348,6 +374,7 @@ void irdp_config_write(struct vty *vty, struct interface *ifp)
                vty_out(vty, " ip irdp maxadvertinterval %ld\n",
                        irdp->MaxAdvertInterval);
        }
+       return 0;
 }
 
 
@@ -359,6 +386,7 @@ DEFUN (ip_irdp_multicast,
        "Use multicast mode\n")
 {
        VTY_DECLVAR_CONTEXT(interface, ifp);
+       irdp_if_get(ifp);
 
        irdp_if_start(ifp, TRUE, TRUE);
        return CMD_SUCCESS;
@@ -372,6 +400,7 @@ DEFUN (ip_irdp_broadcast,
        "Use broadcast mode\n")
 {
        VTY_DECLVAR_CONTEXT(interface, ifp);
+       irdp_if_get(ifp);
 
        irdp_if_start(ifp, FALSE, TRUE);
        return CMD_SUCCESS;
@@ -427,11 +456,7 @@ DEFUN (ip_irdp_holdtime,
 {
        int idx_number = 3;
        VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct zebra_if *zi;
-       struct irdp_interface *irdp;
-
-       zi = ifp->info;
-       irdp = &zi->irdp;
+       struct irdp_interface *irdp = irdp_if_get(ifp);
 
        irdp->Lifetime = atoi(argv[idx_number]->arg);
        return CMD_SUCCESS;
@@ -447,11 +472,7 @@ DEFUN (ip_irdp_minadvertinterval,
 {
        int idx_number = 3;
        VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct zebra_if *zi;
-       struct irdp_interface *irdp;
-
-       zi = ifp->info;
-       irdp = &zi->irdp;
+       struct irdp_interface *irdp = irdp_if_get(ifp);
 
        if ((unsigned)atoi(argv[idx_number]->arg) <= irdp->MaxAdvertInterval) {
                irdp->MinAdvertInterval = atoi(argv[idx_number]->arg);
@@ -474,11 +495,7 @@ DEFUN (ip_irdp_maxadvertinterval,
 {
        int idx_number = 3;
        VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct zebra_if *zi;
-       struct irdp_interface *irdp;
-
-       zi = ifp->info;
-       irdp = &zi->irdp;
+       struct irdp_interface *irdp = irdp_if_get(ifp);
 
        if (irdp->MinAdvertInterval <= (unsigned)atoi(argv[idx_number]->arg)) {
                irdp->MaxAdvertInterval = atoi(argv[idx_number]->arg);
@@ -506,11 +523,7 @@ DEFUN (ip_irdp_preference,
 {
        int idx_number = 3;
        VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct zebra_if *zi;
-       struct irdp_interface *irdp;
-
-       zi = ifp->info;
-       irdp = &zi->irdp;
+       struct irdp_interface *irdp = irdp_if_get(ifp);
 
        irdp->Preference = atoi(argv[idx_number]->arg);
        return CMD_SUCCESS;
@@ -529,17 +542,13 @@ DEFUN (ip_irdp_address_preference,
        int idx_ipv4 = 3;
        int idx_number = 5;
        VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct irdp_interface *irdp = irdp_if_get(ifp);
        struct listnode *node;
        struct in_addr ip;
        int pref;
        int ret;
-       struct zebra_if *zi;
-       struct irdp_interface *irdp;
        struct Adv *adv;
 
-       zi = ifp->info;
-       irdp = &zi->irdp;
-
        ret = inet_aton(argv[idx_ipv4]->arg, &ip);
        if (!ret)
                return CMD_WARNING_CONFIG_FAILED;
@@ -571,16 +580,12 @@ DEFUN (no_ip_irdp_address_preference,
 {
        int idx_ipv4 = 4;
        VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct irdp_interface *irdp = irdp_if_get(ifp);
        struct listnode *node, *nnode;
        struct in_addr ip;
        int ret;
-       struct zebra_if *zi;
-       struct irdp_interface *irdp;
        struct Adv *adv;
 
-       zi = ifp->info;
-       irdp = &zi->irdp;
-
        ret = inet_aton(argv[idx_ipv4]->arg, &ip);
        if (!ret)
                return CMD_WARNING_CONFIG_FAILED;
@@ -604,11 +609,7 @@ DEFUN (ip_irdp_debug_messages,
        "Enable debugging for IRDP messages\n")
 {
        VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct zebra_if *zi;
-       struct irdp_interface *irdp;
-
-       zi = ifp->info;
-       irdp = &zi->irdp;
+       struct irdp_interface *irdp = irdp_if_get(ifp);
 
        irdp->flags |= IF_DEBUG_MESSAGES;
 
@@ -624,11 +625,7 @@ DEFUN (ip_irdp_debug_misc,
        "Enable debugging for miscellaneous IRDP events\n")
 {
        VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct zebra_if *zi;
-       struct irdp_interface *irdp;
-
-       zi = ifp->info;
-       irdp = &zi->irdp;
+       struct irdp_interface *irdp = irdp_if_get(ifp);
 
        irdp->flags |= IF_DEBUG_MISC;
 
@@ -644,11 +641,7 @@ DEFUN (ip_irdp_debug_packet,
        "Enable debugging for IRDP packets\n")
 {
        VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct zebra_if *zi;
-       struct irdp_interface *irdp;
-
-       zi = ifp->info;
-       irdp = &zi->irdp;
+       struct irdp_interface *irdp = irdp_if_get(ifp);
 
        irdp->flags |= IF_DEBUG_PACKET;
 
@@ -665,11 +658,7 @@ DEFUN (ip_irdp_debug_disable,
        "Disable debugging for all IRDP events\n")
 {
        VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct zebra_if *zi;
-       struct irdp_interface *irdp;
-
-       zi = ifp->info;
-       irdp = &zi->irdp;
+       struct irdp_interface *irdp = irdp_if_get(ifp);
 
        irdp->flags &= ~IF_DEBUG_PACKET;
        irdp->flags &= ~IF_DEBUG_MESSAGES;
@@ -678,8 +667,11 @@ DEFUN (ip_irdp_debug_disable,
        return CMD_SUCCESS;
 }
 
-void irdp_init()
+void irdp_if_init()
 {
+       hook_register(zebra_if_config_wr, irdp_config_write);
+       hook_register(if_del, irdp_if_delete);
+
        install_element(INTERFACE_NODE, &ip_irdp_broadcast_cmd);
        install_element(INTERFACE_NODE, &ip_irdp_multicast_cmd);
        install_element(INTERFACE_NODE, &no_ip_irdp_cmd);
@@ -697,5 +689,3 @@ void irdp_init()
        install_element(INTERFACE_NODE, &ip_irdp_debug_packet_cmd);
        install_element(INTERFACE_NODE, &ip_irdp_debug_disable_cmd);
 }
-
-#endif /* HAVE_IRDP */
index 6220c9d81b1fda53083e053540568987058329f3..9dfa854725318a97a9849683d0ba798945cae6fd 100644 (file)
@@ -35,8 +35,6 @@
 
 #include <zebra.h>
 
-#ifdef HAVE_IRDP
-
 #include "if.h"
 #include "vty.h"
 #include "sockunion.h"
@@ -52,6 +50,8 @@
 #include "zclient.h"
 #include "thread.h"
 #include "privs.h"
+#include "libfrr.h"
+#include "version.h"
 #include "zebra/interface.h"
 #include "zebra/rtadv.h"
 #include "zebra/rib.h"
@@ -143,7 +143,7 @@ static int make_advertisement_packet(struct interface *ifp, struct prefix *p,
                                     struct stream *s)
 {
        struct zebra_if *zi = ifp->info;
-       struct irdp_interface *irdp = &zi->irdp;
+       struct irdp_interface *irdp = zi->irdp;
        int size;
        int pref;
        u_int16_t checksum;
@@ -175,11 +175,13 @@ static int make_advertisement_packet(struct interface *ifp, struct prefix *p,
 static void irdp_send(struct interface *ifp, struct prefix *p, struct stream *s)
 {
        struct zebra_if *zi = ifp->info;
-       struct irdp_interface *irdp = &zi->irdp;
+       struct irdp_interface *irdp = zi->irdp;
        char buf[PREFIX_STRLEN];
        u_int32_t dst;
        u_int32_t ttl = 1;
 
+       if (!irdp)
+               return;
        if (!(ifp->flags & IFF_UP))
                return;
 
@@ -211,11 +213,14 @@ int irdp_send_thread(struct thread *t_advert)
        u_int32_t timer, tmp;
        struct interface *ifp = THREAD_ARG(t_advert);
        struct zebra_if *zi = ifp->info;
-       struct irdp_interface *irdp = &zi->irdp;
+       struct irdp_interface *irdp = zi->irdp;
        struct prefix *p;
        struct listnode *node, *nnode;
        struct connected *ifc;
 
+       if (!irdp)
+               return 0;
+
        irdp->flags &= ~IF_SOLICIT;
 
        if (ifp->connected)
@@ -250,12 +255,15 @@ int irdp_send_thread(struct thread *t_advert)
 void irdp_advert_off(struct interface *ifp)
 {
        struct zebra_if *zi = ifp->info;
-       struct irdp_interface *irdp = &zi->irdp;
+       struct irdp_interface *irdp = zi->irdp;
        struct listnode *node, *nnode;
        int i;
        struct connected *ifc;
        struct prefix *p;
 
+       if (!irdp)
+               return;
+
        if (irdp->t_advertise)
                thread_cancel(irdp->t_advertise);
        irdp->t_advertise = NULL;
@@ -279,9 +287,12 @@ void irdp_advert_off(struct interface *ifp)
 void process_solicit(struct interface *ifp)
 {
        struct zebra_if *zi = ifp->info;
-       struct irdp_interface *irdp = &zi->irdp;
+       struct irdp_interface *irdp = zi->irdp;
        u_int32_t timer;
 
+       if (!irdp)
+               return;
+
        /* When SOLICIT is active we reject further incoming solicits
           this keeps down the answering rate so we don't have think
           about DoS attacks here. */
@@ -301,7 +312,7 @@ void process_solicit(struct interface *ifp)
                         &irdp->t_advertise);
 }
 
-void irdp_finish()
+static int irdp_finish(void)
 {
        struct vrf *vrf;
        struct listnode *node, *nnode;
@@ -317,7 +328,7 @@ void irdp_finish()
 
                if (!zi)
                        continue;
-               irdp = &zi->irdp;
+               irdp = zi->irdp;
                if (!irdp)
                        continue;
 
@@ -326,6 +337,26 @@ void irdp_finish()
                        irdp_advert_off(ifp);
                }
        }
+       return 0;
+}
+
+static int irdp_init(struct thread_master *master)
+{
+       irdp_if_init();
+
+       hook_register(frr_early_fini, irdp_finish);
+       return 0;
+}
+
+static int irdp_module_init(void)
+{
+       hook_register(frr_late_init, irdp_init);
+       return 0;
 }
 
-#endif /* HAVE_IRDP */
+FRR_MODULE_SETUP(
+       .name = "zebra_irdp",
+       .version = FRR_VERSION,
+       .description = "zebra IRDP module",
+       .init = irdp_module_init,
+)
index 3bd093d97bfb9ea85d11e2f00efcc034ffa4efbe..08322455368fde4b1e3104bceb48a898b5a88f97 100644 (file)
@@ -36,8 +36,6 @@
 #include <zebra.h>
 
 
-#ifdef HAVE_IRDP
-
 #include "if.h"
 #include "vty.h"
 #include "sockunion.h"
@@ -84,7 +82,7 @@ static void parse_irdp_packet(char *p, int len, struct interface *ifp)
        if (!zi)
                return;
 
-       irdp = &zi->irdp;
+       irdp = zi->irdp;
        if (!irdp)
                return;
 
@@ -240,7 +238,7 @@ int irdp_read_raw(struct thread *r)
        if (!zi)
                return ret;
 
-       irdp = &zi->irdp;
+       irdp = zi->irdp;
        if (!irdp)
                return ret;
 
@@ -353,6 +351,3 @@ void send_packet(struct interface *ifp, struct stream *s, u_int32_t dst,
        }
        /*   printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */
 }
-
-
-#endif /* HAVE_IRDP */
index 538c2f0663129ed7db8e1e5463bfeeceb5d578a4..bc7276817d560e5c08020979345e310553cece97 100644 (file)
@@ -125,9 +125,7 @@ static void sigint(void)
 
        zlog_notice("Terminating on signal");
 
-#ifdef HAVE_IRDP
-       irdp_finish();
-#endif
+       frr_early_fini();
 
        zebra_ptm_finish();
        list_delete_all_node(zebrad.client_list);
@@ -147,17 +145,14 @@ static void sigint(void)
        access_list_reset();
        prefix_list_reset();
        route_map_finish();
-       cmd_terminate();
-       vty_terminate();
-       zprivs_terminate(&zserv_privs);
+
        list_delete(zebrad.client_list);
        work_queue_free(zebrad.ribq);
        if (zebrad.lsp_process_q)
                work_queue_free(zebrad.lsp_process_q);
        meta_queue_free(zebrad.mq);
-       thread_master_free(zebrad.master);
-       closezlog();
 
+       frr_fini();
        exit(0);
 }
 
@@ -297,9 +292,6 @@ int main(int argc, char **argv)
 #if defined(HAVE_RTADV)
        rtadv_cmd_init();
 #endif
-#ifdef HAVE_IRDP
-       irdp_init();
-#endif
 /* PTM socket */
 #ifdef ZEBRA_PTM_SUPPORT
        zebra_ptm_init();
index ed27dc3e8344c11bfaa74419b28f5f93df3bdf8e..410ddcd4a00c783cb13726ef364d7a3af12f992c 100644 (file)
@@ -114,7 +114,7 @@ static void zebra_redistribute(struct zserv *client, int type, u_short instance,
        if (!table)
                return;
 
-       for (rn = route_top(table); rn; rn = route_next(rn))
+       for (rn = route_top(table); rn; rn = srcdest_route_next(rn))
                RNODE_FOREACH_RE(rn, newre)
                {
                        struct prefix *dst_p, *src_p;
index b8cf2d490afbe2a269c1e9969fb629c765a5bfe8..2182d6618ce4a33fa4a24c0b19a387424119cd1d 100644 (file)
@@ -62,6 +62,10 @@ extern struct zebra_privs_t zserv_privs;
 #define ALLNODE   "ff02::1"
 #define ALLROUTER "ff02::2"
 
+/* Order is intentional.  Matches RFC4191.  This array is also used for
+   command matching, so only modify with care. */
+const char *rtadv_pref_strs[] = {"medium", "high", "INVALID", "low", 0};
+
 enum rtadv_event {
        RTADV_START,
        RTADV_STOP,
@@ -1456,9 +1460,76 @@ DEFUN (no_ipv6_nd_mtu,
        return CMD_SUCCESS;
 }
 
+/* Dump interface ND information to vty. */
+static int nd_dump_vty(struct vty *vty, struct interface *ifp)
+{
+       struct zebra_if *zif;
+       struct rtadvconf *rtadv;
+       int interval;
+
+       zif = (struct zebra_if *)ifp->info;
+       rtadv = &zif->rtadv;
+
+       if (rtadv->AdvSendAdvertisements) {
+               vty_out(vty,
+                       "  ND advertised reachable time is %d milliseconds\n",
+                       rtadv->AdvReachableTime);
+               vty_out(vty,
+                       "  ND advertised retransmit interval is %d milliseconds\n",
+                       rtadv->AdvRetransTimer);
+               vty_out(vty, "  ND router advertisements sent: %d rcvd: %d\n",
+                       zif->ra_sent, zif->ra_rcvd);
+               interval = rtadv->MaxRtrAdvInterval;
+               if (interval % 1000)
+                       vty_out(vty,
+                               "  ND router advertisements are sent every "
+                               "%d milliseconds\n",
+                               interval);
+               else
+                       vty_out(vty,
+                               "  ND router advertisements are sent every "
+                               "%d seconds\n",
+                               interval / 1000);
+               if (rtadv->AdvDefaultLifetime != -1)
+                       vty_out(vty,
+                               "  ND router advertisements live for %d seconds\n",
+                               rtadv->AdvDefaultLifetime);
+               else
+                       vty_out(vty,
+                               "  ND router advertisements lifetime tracks ra-interval\n");
+               vty_out(vty,
+                       "  ND router advertisement default router preference is "
+                       "%s\n",
+                       rtadv_pref_strs[rtadv->DefaultPreference]);
+               if (rtadv->AdvManagedFlag)
+                       vty_out(vty,
+                               "  Hosts use DHCP to obtain routable addresses.\n");
+               else
+                       vty_out(vty,
+                               "  Hosts use stateless autoconfig for addresses.\n");
+               if (rtadv->AdvHomeAgentFlag) {
+                       vty_out(vty,
+                               "  ND router advertisements with Home Agent flag bit set.\n");
+                       if (rtadv->HomeAgentLifetime != -1)
+                               vty_out(vty,
+                                       "  Home Agent lifetime is %u seconds\n",
+                                       rtadv->HomeAgentLifetime);
+                       else
+                               vty_out(vty,
+                                       "  Home Agent lifetime tracks ra-lifetime\n");
+                       vty_out(vty, "  Home Agent preference is %u\n",
+                               rtadv->HomeAgentPreference);
+               }
+               if (rtadv->AdvIntervalOption)
+                       vty_out(vty,
+                               "  ND router advertisements with Adv. Interval option.\n");
+       }
+       return 0;
+}
+
 
 /* Write configuration about router advertisement. */
-void rtadv_config_write(struct vty *vty, struct interface *ifp)
+static int rtadv_config_write(struct vty *vty, struct interface *ifp)
 {
        struct zebra_if *zif;
        struct listnode *node;
@@ -1539,6 +1610,7 @@ void rtadv_config_write(struct vty *vty, struct interface *ifp)
                        vty_out(vty, " router-address");
                vty_out(vty, "\n");
        }
+       return 0;
 }
 
 
@@ -1600,6 +1672,9 @@ void rtadv_terminate(struct zebra_ns *zns)
 
 void rtadv_cmd_init(void)
 {
+       hook_register(zebra_if_extra_info, nd_dump_vty);
+       hook_register(zebra_if_config_wr, rtadv_config_write);
+
        install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
        install_element(INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
        install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
index 029c97cddc50687dbeba2d5850bc736ee3d9ef60..dcaeb3ed28bf1e359add90fc355f670f10ec645a 100644 (file)
@@ -55,8 +55,6 @@ struct rtadv_prefix {
 #endif
 };
 
-extern void rtadv_config_write(struct vty *, struct interface *);
-
 /* RFC4584 Extension to Sockets API for Mobile IPv6 */
 
 #ifndef ND_OPT_ADV_INTERVAL
index 0391cab9fde750aed0eee3ce03bfc87f0bb94b1b..347482362341bfc4c58ba32549e6f19ae976668d 100644 (file)
@@ -6,6 +6,9 @@ if ZEBRA
 sbin_PROGRAMS += zebra/zebra
 dist_examples_DATA += zebra/zebra.conf.sample
 
+if IRDP
+module_LTLIBRARIES += zebra/zebra_irdp.la
+endif
 if SNMP
 module_LTLIBRARIES += zebra/zebra_snmp.la
 endif
@@ -30,9 +33,6 @@ zebra_zebra_SOURCES = \
        zebra/ipforward_proc.c \
        zebra/ipforward_solaris.c \
        zebra/ipforward_sysctl.c \
-       zebra/irdp_interface.c \
-       zebra/irdp_main.c \
-       zebra/irdp_packet.c \
        zebra/kernel_netlink.c \
        zebra/kernel_socket.c \
        zebra/label_manager.c \
@@ -106,6 +106,13 @@ noinst_HEADERS += \
        zebra/zserv.h \
        # end
 
+zebra_zebra_irdp_la_SOURCES = \
+       zebra/irdp_interface.c \
+       zebra/irdp_main.c \
+       zebra/irdp_packet.c \
+       # end
+zebra_zebra_irdp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
+
 zebra_zebra_snmp_la_SOURCES = zebra/zebra_snmp.c
 zebra_zebra_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS)
 zebra_zebra_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
index 4f1d8b0915c2d9e14eae021d02c3d2c30120d4fe..0b6263fac5241b2ce4b82f3d16fd493f060568d2 100644 (file)
@@ -434,8 +434,9 @@ DEFUN (pseudowire_control_word,
 
 DEFUN (show_pseudowires,
        show_pseudowires_cmd,
-       "show pseudowires",
+       "show mpls pseudowires",
        SHOW_STR
+       MPLS_STR
        "Pseudowires")
 {
        struct zebra_vrf *zvrf;
index ed5355426524bdb528654c5bca083d8f061f5137..dc61ea5e40c14a3211c89af7b8ba7393071af4e0 100644 (file)
@@ -1820,7 +1820,7 @@ void rib_queue_add(struct route_node *rn)
         * holder, if necessary, then push the work into it in any case.
         * This semantics was introduced after 0.99.9 release.
         */
-       if (!zebrad.ribq->items->count)
+       if (work_queue_empty(zebrad.ribq))
                work_queue_add(zebrad.ribq, zebrad.mq);
 
        rib_meta_queue_add(zebrad.mq, rn);
@@ -2352,7 +2352,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
                                break;
                        }
                        for (ALL_NEXTHOPS(re->nexthop, nexthop))
-                               if (IPV4_ADDR_SAME(&nexthop->gate.ipv4, gate)
+                               if (IPV4_ADDR_SAME(&nexthop->gate.ipv4, &gate->ipv4)
                                    || IPV6_ADDR_SAME(&nexthop->gate.ipv6,
                                                      gate)) {
                                        same = re;
index dba228ea350df68c7d0ba04840a54dc8d95305c9..6815916faf8d08b91e232f6b0d80be2b30e8d51f 100644 (file)
@@ -398,7 +398,7 @@ int static_add_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
        for (si = rn->info; si; si = si->next) {
                if (type == si->type
                    && (!gate || ((afi == AFI_IP
-                                  && IPV4_ADDR_SAME(gate, &si->addr.ipv4))
+                                  && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4))
                                  || (afi == AFI_IP6
                                      && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
                    && (!strcmp (ifname ? ifname : "", si->ifname))) {
@@ -515,7 +515,7 @@ int static_delete_route(afi_t afi, safi_t safi, u_char type, struct prefix *p,
        for (si = rn->info; si; si = si->next)
                if (type == si->type
                    && (!gate || ((afi == AFI_IP
-                                  && IPV4_ADDR_SAME(gate, &si->addr.ipv4))
+                                  && IPV4_ADDR_SAME(&gate->ipv4, &si->addr.ipv4))
                                  || (afi == AFI_IP6
                                      && IPV6_ADDR_SAME(gate, &si->addr.ipv6))))
                    && (!strcmp(ifname ? ifname : "", si->ifname))
index f01f037ed5f3dc0b8676742958ae5f8ecb2de831..9f887e840189428045cfb4d16fd7cd34a3556571 100644 (file)
@@ -1705,16 +1705,14 @@ static int static_config(struct vty *vty, afi_t afi, safi_t safi,
                                                inet_ntop(AF_INET,
                                                          &si->addr.ipv4, buf,
                                                          sizeof buf),
-                                               ifindex2ifname(si->ifindex,
-                                                              si->vrf_id));
+                                               si->ifname);
                                        break;
                                case STATIC_IPV6_GATEWAY_IFNAME:
                                        vty_out(vty, " %s %s",
                                                inet_ntop(AF_INET6,
                                                          &si->addr.ipv6, buf,
                                                          sizeof buf),
-                                               ifindex2ifname(si->ifindex,
-                                                              si->vrf_id));
+                                               si->ifname);
                                        break;
                                }