Adjacency Delegate updates 35/10635/2
authorNeale Ranns <neale.ranns@cisco.com>
Mon, 19 Feb 2018 10:36:19 +0000 (02:36 -0800)
committerDamjan Marion <dmarion.lists@gmail.com>
Mon, 19 Feb 2018 12:21:00 +0000 (12:21 +0000)
- Register new type (for use from puglins)
- Memory for delegate is provided by delegate provider

Change-Id: I5ece86b1fe84e3028a5c853871476c4ba015b2eb
Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
src/vnet/adj/adj.c
src/vnet/adj/adj.h
src/vnet/adj/adj_bfd.c
src/vnet/adj/adj_delegate.c
src/vnet/adj/adj_delegate.h
src/vnet/adj/adj_internal.h
src/vnet/fib/fib_node.h

index e1d7821..386070e 100644 (file)
@@ -129,18 +129,13 @@ format_ip_adjacency (u8 * s, va_list * args)
 
     if (fiaf & FORMAT_IP_ADJACENCY_DETAIL)
     {
-        adj_delegate_type_t adt;
-        adj_delegate_t *aed;
         vlib_counter_t counts;
 
         vlib_get_combined_counter(&adjacency_counters, adj_index, &counts);
         s = format (s, "\n counts:[%Ld:%Ld]", counts.packets, counts.bytes);
        s = format (s, "\n locks:%d", adj->ia_node.fn_locks);
        s = format(s, "\n delegates:\n  ");
-        FOR_EACH_ADJ_DELEGATE(adj, adt, aed,
-        {
-            s = format(s, "  %U\n", format_adj_delegate, aed);
-        });
+        adj_delegate_format(s, adj);
 
        s = format(s, "\n children:\n  ");
        s = fib_node_children_format(adj->ia_node.fn_children, s);
@@ -162,7 +157,7 @@ adj_last_lock_gone (ip_adjacency_t *adj)
     ASSERT(0 == fib_node_list_get_size(adj->ia_node.fn_children));
     ADJ_DBG(adj, "last-lock-gone");
 
-    adj_delegate_vft_lock_gone(adj);
+    adj_delegate_adj_deleted(adj);
 
     vlib_worker_thread_barrier_sync (vm);
 
@@ -430,24 +425,7 @@ adj_get_sw_if_index (adj_index_t ai)
 int
 adj_is_up (adj_index_t ai)
 {
-    const adj_delegate_t *aed;
-
-    aed = adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD);
-
-    if (NULL == aed)
-    {
-        /*
-         * no BFD tracking - resolved
-         */
-        return (!0);
-    }
-    else
-    {
-        /*
-         * defer to the state of the BFD tracking
-         */
-        return (ADJ_BFD_STATE_UP == aed->ad_bfd_state);
-    }
+    return (adj_bfd_is_up(ai));
 }
 
 /**
index bcf6c04..0434d7c 100644 (file)
@@ -273,7 +273,7 @@ typedef struct ip_adjacency_t_
   /**
    * A sorted vector of delegates
    */
-  struct adj_delegate_t_ *ia_delegates;
+  struct adj_delegate_t_ **ia_delegates;
 
 } ip_adjacency_t;
 
index 2d845ff..a4e7e27 100644 (file)
 #include <vnet/adj/adj_nbr.h>
 #include <vnet/fib/fib_walk.h>
 
+/**
+ * Distillation of the BFD session states into a go/no-go for using
+ * the associated tracked adjacency
+ */
+typedef enum adj_bfd_state_t_
+{
+    ADJ_BFD_STATE_DOWN,
+    ADJ_BFD_STATE_UP,
+} adj_bfd_state_t;
+
+/**
+ * BFD delegate daa
+ */
+typedef struct adj_bfd_delegate_t_
+{
+    /**
+     * Base class,linkage to the adjacency
+     */
+    adj_delegate_t abd_link;
+
+    /**
+     * BFD session state
+     */
+    adj_bfd_state_t abd_state;
+
+    /**
+     * BFD session index
+     */
+    u32 abd_index;
+} adj_bfd_delegate_t;
+
+/**
+ * Pool of delegates
+*/
+static adj_bfd_delegate_t *abd_pool;
+
+static inline adj_bfd_delegate_t*
+adj_bfd_from_base (adj_delegate_t *ad)
+{
+    if (NULL == ad)
+    {
+        return (NULL);
+    }
+    return ((adj_bfd_delegate_t*)((char*)ad -
+                                  STRUCT_OFFSET_OF(adj_bfd_delegate_t,
+                                                   abd_link)));
+}
+
+static inline const adj_bfd_delegate_t*
+adj_bfd_from_const_base (const adj_delegate_t *ad)
+{
+    if (NULL == ad)
+    {
+        return (NULL);
+    }
+    return ((adj_bfd_delegate_t*)((char*)ad -
+                                  STRUCT_OFFSET_OF(adj_bfd_delegate_t,
+                                                   abd_link)));
+}
+
 static adj_bfd_state_t
 adj_bfd_bfd_state_to_fib (bfd_state_e bstate)
 {
@@ -57,6 +117,7 @@ adj_bfd_notify (bfd_listen_event_e event,
                 const bfd_session_t *session)
 {
     const bfd_udp_key_t *key;
+    adj_bfd_delegate_t *abd;
     fib_protocol_t fproto;
     adj_delegate_t *aed;
     adj_index_t ai;
@@ -107,7 +168,10 @@ adj_bfd_notify (bfd_listen_event_e event,
              */
             adj_lock(ai);
 
-            aed = adj_delegate_find_or_add(adj_get(ai), ADJ_DELEGATE_BFD);
+            /*
+             * allocate and init a new delegate struct
+             */
+            pool_get(abd_pool, abd);
 
             /*
              * pretend the session is up and skip the walk.
@@ -116,8 +180,10 @@ adj_bfd_notify (bfd_listen_event_e event,
              * for the first BFD UP/DOWN before we let the session's state
              * influence forwarding.
              */
-            aed->ad_bfd_state = ADJ_BFD_STATE_UP;
-            aed->ad_bfd_index = session->bs_idx;
+            abd->abd_state = ADJ_BFD_STATE_UP;
+            abd->abd_index = session->bs_idx;
+
+            adj_delegate_add(adj_get(ai), ADJ_DELEGATE_BFD, &abd->abd_link);
         }
         break;
 
@@ -125,11 +191,11 @@ adj_bfd_notify (bfd_listen_event_e event,
         /*
          * state change up/dowm and
          */
-        aed = adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD);
+        abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
 
-        if (NULL != aed)
+        if (NULL != abd)
         {
-            aed->ad_bfd_state = adj_bfd_bfd_state_to_fib(session->local_state);
+            abd->abd_state = adj_bfd_bfd_state_to_fib(session->local_state);
             adj_bfd_update_walk(ai);
         }
         /*
@@ -142,15 +208,17 @@ adj_bfd_notify (bfd_listen_event_e event,
         /*
          * session has been removed.
          */
+        abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
 
-        if (adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD))
+        if (NULL != abd)
         {
             /*
              * has an associated BFD tracking delegate
              * remove the BFD tracking deletgate, update children, then
              * unlock the adj
              */
-            adj_delegate_remove(adj_get(ai), ADJ_DELEGATE_BFD);
+            adj_delegate_remove(ai, ADJ_DELEGATE_BFD);
+            pool_put(abd_pool, abd);
 
             adj_bfd_update_walk(ai);
             adj_unlock(ai);
@@ -168,15 +236,40 @@ adj_bfd_notify (bfd_listen_event_e event,
     adj_unlock(ai);
 }
 
+int
+adj_bfd_is_up (adj_index_t ai)
+{
+    const adj_bfd_delegate_t *abd;
+
+    abd = adj_bfd_from_base(adj_delegate_get(adj_get(ai), ADJ_DELEGATE_BFD));
+
+    if (NULL == abd)
+    {
+        /*
+         * no BFD tracking - resolved
+         */
+        return (!0);
+    }
+    else
+    {
+        /*
+         * defer to the state of the BFD tracking
+         */
+        return (ADJ_BFD_STATE_UP == abd->abd_state);
+    }
+}
+
 /**
  * Print a delegate that represents BFD tracking
  */
 static u8 *
 adj_delegate_fmt_bfd (const adj_delegate_t *aed, u8 *s)
 {
+    const adj_bfd_delegate_t *abd = adj_bfd_from_const_base(aed);
+
     s = format(s, "BFD:[state:%d index:%d]",
-               aed->ad_bfd_state,
-               aed->ad_bfd_index);
+               abd->abd_state,
+               abd->abd_index);
 
     return (s);
 }
index 0125c89..1cc7c4b 100644 (file)
  */
 static adj_delegate_vft_t *ad_vfts;
 
+/**
+ * The value of the last dynamically allocated delegeate value
+ */
+static adj_delegate_type_t ad_max_id = ADJ_DELEGATE_BFD;
+
 static adj_delegate_t *
 adj_delegate_find_i (const ip_adjacency_t *adj,
                      adj_delegate_type_t type,
                      u32 *index)
 {
-    adj_delegate_t *delegate;
+    adj_delegate_t **delegate;
     int ii;
 
     ii = 0;
     vec_foreach(delegate, adj->ia_delegates)
     {
-       if (delegate->ad_type == type)
+       if ((*delegate)->ad_type == type)
        {
             if (NULL != index)
                 *index = ii;
 
-           return (delegate);
+           return (*delegate);
        }
        else
        {
@@ -57,12 +62,14 @@ adj_delegate_get (const ip_adjacency_t *adj,
 }
 
 void
-adj_delegate_remove (ip_adjacency_t *adj,
+adj_delegate_remove (adj_index_t ai,
                      adj_delegate_type_t type)
 {
+    ip_adjacency_t *adj;
     adj_delegate_t *aed;
     u32 index = ~0;
 
+    adj = adj_get(ai);
     aed = adj_delegate_find_i(adj, type, &index);
 
     ASSERT(NULL != aed);
@@ -74,29 +81,29 @@ static int
 adj_delegate_cmp_for_sort (void * v1,
                            void * v2)
 {
-    adj_delegate_t *delegate1 = v1, *delegate2 = v2;
+    adj_delegate_t **delegate1 = v1, **delegate2 = v2;
 
-    return (delegate1->ad_type - delegate2->ad_type);
+    return ((*delegate1)->ad_type - (*delegate2)->ad_type);
 }
 
 static void
 adj_delegate_init (ip_adjacency_t *adj,
-                   adj_delegate_type_t type)
+                   adj_delegate_type_t adt,
+                   adj_delegate_t *aed)
 
 {
-    adj_delegate_t delegate = {
-       .ad_adj_index = adj_get_index(adj),
-       .ad_type = type,
-    };
+    aed->ad_adj_index = adj_get_index(adj);
+    aed->ad_type = adt;
 
-    vec_add1(adj->ia_delegates, delegate);
+    vec_add1(adj->ia_delegates, aed);
     vec_sort_with_function(adj->ia_delegates,
                           adj_delegate_cmp_for_sort);
 }
 
-adj_delegate_t *
-adj_delegate_find_or_add (ip_adjacency_t *adj,
-                          adj_delegate_type_t adt)
+int
+adj_delegate_add (ip_adjacency_t *adj,
+                  adj_delegate_type_t adt,
+                  adj_delegate_t *ad)
 {
     adj_delegate_t *delegate;
 
@@ -104,30 +111,52 @@ adj_delegate_find_or_add (ip_adjacency_t *adj,
 
     if (NULL == delegate)
     {
-       adj_delegate_init(adj, adt);
+       adj_delegate_init(adj, adt, ad);
+    }
+    else
+    {
+        return (-1);
     }
 
-    return (adj_delegate_get(adj, adt));
+    return (0);
 }
 
-void adj_delegate_vft_lock_gone (ip_adjacency_t *adj)
+void
+adj_delegate_adj_deleted (ip_adjacency_t *adj)
 {
-    adj_delegate_t *delegate;
-    vec_foreach(delegate, adj->ia_delegates) {
-      if (ad_vfts[delegate->ad_type].adv_last_lock)
-       ad_vfts[delegate->ad_type].adv_last_lock(adj, delegate);
+    adj_delegate_t **delegate;
+
+    vec_foreach(delegate, adj->ia_delegates)
+    {
+        if (ad_vfts[(*delegate)->ad_type].adv_adj_deleted)
+        {
+            ad_vfts[(*delegate)->ad_type].adv_adj_deleted(*delegate);
+        }
     }
+
+    vec_reset_length(adj->ia_delegates);
 }
 
-u8 *
-format_adj_delegate (u8 * s, va_list * args)
+u8*
+adj_delegate_format (u8* s, ip_adjacency_t *adj)
 {
-    adj_delegate_t *aed;
+    adj_delegate_t **aed;
 
-    aed = va_arg (*args, adj_delegate_t *);
-    if (ad_vfts[aed->ad_type].adv_format)
-      return ad_vfts[aed->ad_type].adv_format(aed, s);
-    return format(s, "unknown delegate");
+    vec_foreach(aed, adj->ia_delegates)
+    {
+        if (ad_vfts[(*aed)->ad_type].adv_format)
+        {
+            s = format(s, "{");
+            s = ad_vfts[(*aed)->ad_type].adv_format(*aed, s);
+            s = format(s, "}");
+        }
+        else
+        {
+            s = format(s, "{unknown delegate}");
+        }
+    }
+
+    return (s);
 }
 
 /**
@@ -135,17 +164,34 @@ format_adj_delegate (u8 * s, va_list * args)
  *
  * Register the function table for a given type
  */
-
 void
 adj_delegate_register_type (adj_delegate_type_t type,
                            const adj_delegate_vft_t *vft)
 {
-  /*
-   * assert that one only registration is made per-node type
-   */
-  if (vec_len(ad_vfts) > type)
-    ASSERT(NULL == ad_vfts[type].adv_last_lock);
-
-  vec_validate(ad_vfts, type);
-  ad_vfts[type] = *vft;
+    /*
+     * assert that one only registration is made per-node type
+     */
+    if (vec_len(ad_vfts) > type)
+        ASSERT(NULL == ad_vfts[type].adv_adj_deleted);
+
+    vec_validate(ad_vfts, type);
+    ad_vfts[type] = *vft;
+}
+
+/**
+ * adj_delegate_register_new_type
+ *
+ * Register the function table for a new type
+ */
+adj_delegate_type_t
+adj_delegate_register_new_type (const adj_delegate_vft_t *vft)
+{
+    adj_delegate_type_t type;
+
+    type = ++ad_max_id;
+
+    vec_validate(ad_vfts, type);
+    ad_vfts[type] = *vft;
+
+    return (type);
 }
index 9f7d8c6..b57900b 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+/**
+ * A Delagate is a means to implement the Delagation design pattern;
+ * the extension of an object's functionality through the composition of,
+ * and delgation to, other objects.
+ * These 'other' objects are delegates. Delagates are thus attached to
+ * ADJ objects to extend their functionality.
+ */
 
 #ifndef __ADJ_DELEGATE_T__
 #define __ADJ_DELEGATE_T__
 #include <vnet/adj/adj.h>
 
 /**
- * Delegate types
+ * Built-in delegate types.
+ * When adding new types, if your code is within the vnet subsystem, then add a
+ * new  type here. If not then use the adj_delegate_register_new_type API to
+ * register a new type.
  */
 typedef enum adj_delegate_type_t_ {
     /**
@@ -28,35 +38,12 @@ typedef enum adj_delegate_type_t_ {
     ADJ_DELEGATE_BFD,
 } adj_delegate_type_t;
 
-#define FOR_EACH_ADJ_DELEGATE(_adj, _adt, _aed, _body)        \
-{                                                             \
-    for (_adt = ADJ_DELEGATE_BFD;                             \
-         _adt <= ADJ_DELEGATE_BFD;                            \
-         _adt++)                                              \
-    {                                                         \
-        _aed = adj_delegate_get(_adj, _adt);                  \
-        if (NULL != _aed) {                                   \
-            _body;                                            \
-        }                                                     \
-    }                                                         \
-}
-
-/**
- * Distillation of the BFD session states into a go/no-go for using
- * the associated tracked adjacency
- */
-typedef enum adj_bfd_state_t_
-{
-    ADJ_BFD_STATE_DOWN,
-    ADJ_BFD_STATE_UP,
-} adj_bfd_state_t;
-
 /**
- * A Delagate is a means to implement the Delagation design pattern;
- * the extension of an object's functionality through the composition of,
- * and delgation to, other objects.
- * These 'other' objects are delegates. Delagates are thus attached to
- * ADJ objects to extend their functionality.
+ * Adj delegate. This object should be contained within all type specific
+ * delegates.  i.e. this is the base class to all type specific derived classes.
+ * With this model the delegate provider is free to manage the memory of the
+ * delegate in the way it chooses. Specifically it can assign them from its own
+ * pools and thus, for example, add the delegates to the FIB node graph.
  */
 typedef struct adj_delegate_t_
 {
@@ -69,47 +56,69 @@ typedef struct adj_delegate_t_
      * The delagate type
      */
     adj_delegate_type_t ad_type;
-
-    /**
-     * A union of data for the different delegate types
-     */
-    union
-    {
-        /**
-         * BFD delegate daa
-         */
-        struct {
-            /**
-             * BFD session state
-             */
-            adj_bfd_state_t ad_bfd_state;
-            /**
-             * BFD session index
-             */
-            u32 ad_bfd_index;
-        };
-    };
 } adj_delegate_t;
 
 /**
- * An ADJ delegate virtual function table
+ * Indication that the adjacency has been deleted. The delegate provider should free
+ * the delegate.
+ */
+typedef void (*adj_delegate_adj_deleted_t)(adj_delegate_t *aed);
+
+/**
+ * Format function for the delegate
  */
-typedef void (*adj_delegate_last_lock_gone_t)(ip_adjacency_t *adj, adj_delegate_t *aed);
 typedef u8 * (*adj_delegate_format_t)(const adj_delegate_t *aed, u8 *s);
+
+/**
+ * An ADJ delegate virtual function table
+ */
 typedef struct adj_delegate_vft_t_ {
-  adj_delegate_format_t adv_format;
-  adj_delegate_last_lock_gone_t adv_last_lock;
+    adj_delegate_format_t adv_format;
+    adj_delegate_adj_deleted_t adv_adj_deleted;
 } adj_delegate_vft_t;
 
-extern void adj_delegate_remove(ip_adjacency_t *adj,
+/**
+ * @brief Remove a delegate from an adjacency
+ *
+ * @param ai The adjacency to remove the delegate from
+ * @param type The type of delegate being removed
+ */
+extern void adj_delegate_remove(adj_index_t ai,
                                 adj_delegate_type_t type);
 
-extern adj_delegate_t *adj_delegate_find_or_add(ip_adjacency_t *adj,
-                                                adj_delegate_type_t fdt);
+/**
+ * @brief Add a delegate to an adjacency
+ *
+ * @param ai The adjacency to add the delegate to
+ * @param type The type of delegate being added
+ * @param ad The delegate. The provider should allocate memory for this object
+ *                         Typically this is a 'derived' class with the
+ *                         adj_delegate_t struct embedded within.
+ */
+extern int adj_delegate_add(ip_adjacency_t *adj,
+                            adj_delegate_type_t fdt,
+                            adj_delegate_t *ad);
+
+
+/**
+ * @brief Get a delegate from an adjacency
+ *
+ * @param ai The adjacency to get the delegate from
+ * @param type The type of delegate being sought
+ */
 extern adj_delegate_t *adj_delegate_get(const ip_adjacency_t *adj,
                                         adj_delegate_type_t type);
 
-extern u8 *format_adj_delegate(u8 * s, va_list * args);
-extern void adj_delegate_register_type(adj_delegate_type_t type, const adj_delegate_vft_t *vft);
+/**
+ * @brief Register a VFT for one of the built-in types
+ */
+extern void adj_delegate_register_type(adj_delegate_type_t type,
+                                       const adj_delegate_vft_t *vft);
+
+/**
+ * @brief create a new delegate type and register a new VFT
+ */
+extern adj_delegate_type_t adj_delegate_register_new_type(
+    const adj_delegate_vft_t *vft);
 
 #endif
index 55afe55..efaa11d 100644 (file)
@@ -126,6 +126,16 @@ extern void adj_mcast_remove(fib_protocol_t proto,
                             u32 sw_if_index);
 
 extern u32 adj_dpo_get_urpf(const dpo_id_t *dpo);
-extern void adj_delegate_vft_lock_gone(ip_adjacency_t *adj);
+
+/*
+ * Adj BFD
+ */
+extern int adj_bfd_is_up (adj_index_t ai);
+
+/*
+ * Adj delegates
+ */ 
+extern void adj_delegate_adj_deleted(ip_adjacency_t *adj);
+extern u8* adj_delegate_format(u8* s, ip_adjacency_t *adj);
 
 #endif
index 532efd5..ec3b542 100644 (file)
@@ -56,24 +56,24 @@ typedef enum fib_node_type_t_ {
 
 #define FIB_NODE_TYPE_MAX (FIB_NODE_TYPE_LAST + 1)
 
-#define FIB_NODE_TYPES {                          \
-    [FIB_NODE_TYPE_ENTRY]     = "entry",          \
-    [FIB_NODE_TYPE_MFIB_ENTRY] = "mfib-entry",    \
-    [FIB_NODE_TYPE_WALK]      = "walk",           \
-    [FIB_NODE_TYPE_PATH_LIST] = "path-list",      \
-    [FIB_NODE_TYPE_PATH]      = "path",           \
-    [FIB_NODE_TYPE_MPLS_ENTRY] = "mpls-entry",    \
-    [FIB_NODE_TYPE_MPLS_TUNNEL] = "mpls-tunnel",  \
-    [FIB_NODE_TYPE_ADJ] = "adj",                  \
-    [FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY] = "lisp-gpe-fwd-entry", \
-    [FIB_NODE_TYPE_LISP_ADJ] = "lisp-adj", \
-    [FIB_NODE_TYPE_GRE_TUNNEL] = "gre-tunnel", \
-    [FIB_NODE_TYPE_VXLAN_TUNNEL] = "vxlan-tunnel", \
-    [FIB_NODE_TYPE_MAP_E] = "map-e", \
-    [FIB_NODE_TYPE_VXLAN_GPE_TUNNEL] = "vxlan-gpe-tunnel", \
-    [FIB_NODE_TYPE_UDP_ENCAP] = "udp-encap", \
-    [FIB_NODE_TYPE_BIER_FMASK] = "bier-fmask", \
-    [FIB_NODE_TYPE_BIER_ENTRY] = "bier-entry", \
+#define FIB_NODE_TYPES {                                       \
+    [FIB_NODE_TYPE_ENTRY]     = "entry",                       \
+    [FIB_NODE_TYPE_MFIB_ENTRY] = "mfib-entry",                 \
+    [FIB_NODE_TYPE_WALK]      = "walk",                                \
+    [FIB_NODE_TYPE_PATH_LIST] = "path-list",                   \
+    [FIB_NODE_TYPE_PATH]      = "path",                                \
+    [FIB_NODE_TYPE_MPLS_ENTRY] = "mpls-entry",                 \
+    [FIB_NODE_TYPE_MPLS_TUNNEL] = "mpls-tunnel",               \
+    [FIB_NODE_TYPE_ADJ] = "adj",                               \
+    [FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY] = "lisp-gpe-fwd-entry", \
+    [FIB_NODE_TYPE_LISP_ADJ] = "lisp-adj",                     \
+    [FIB_NODE_TYPE_GRE_TUNNEL] = "gre-tunnel",                 \
+    [FIB_NODE_TYPE_VXLAN_TUNNEL] = "vxlan-tunnel",             \
+    [FIB_NODE_TYPE_MAP_E] = "map-e",                           \
+    [FIB_NODE_TYPE_VXLAN_GPE_TUNNEL] = "vxlan-gpe-tunnel",     \
+    [FIB_NODE_TYPE_UDP_ENCAP] = "udp-encap",                   \
+    [FIB_NODE_TYPE_BIER_FMASK] = "bier-fmask",                 \
+    [FIB_NODE_TYPE_BIER_ENTRY] = "bier-entry",                 \
 }
 
 /**
@@ -293,12 +293,6 @@ typedef struct fib_node_t_ {
      * Some pad space the concrete/derived type is free to use
      */
     u16 fn_pad;
-    /**
-     * The node's VFT.
-     * we could store the type here instead, and lookup the VFT using that. But
-     * I like this better,
-     */
-//    const fib_node_vft_t *fn_vft;
 
     /**
      * Vector of nodes that depend upon/use/share this node