Support IETF routing Yang models (VPP-503).
[vpp.git] / vnet / vnet / fib / fib_entry_src.c
index 6107e3e..2cbdf18 100644 (file)
@@ -34,6 +34,21 @@ fib_entry_get_proto (const fib_entry_t * fib_entry)
     return (fib_entry->fe_prefix.fp_proto);
 }
 
+static dpo_proto_t
+fib_entry_get_payload_proto (const fib_entry_t * fib_entry)
+{
+    switch (fib_entry->fe_prefix.fp_proto)
+    {
+    case FIB_PROTOCOL_IP4:
+    case FIB_PROTOCOL_IP6:
+       return fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto);
+    case FIB_PROTOCOL_MPLS:
+       return fib_entry->fe_prefix.fp_payload_proto;
+    }
+
+    return (fib_proto_to_dpo(fib_entry->fe_prefix.fp_proto));
+}
+
 void
 fib_entry_src_register (fib_source_t source,
                        const fib_entry_src_vft_t *vft)
@@ -329,7 +344,7 @@ fib_entry_src_mk_lb (fib_entry_t *fib_entry,
         .fct = fct,
     };
 
-    lb_proto = fib_proto_to_dpo(fib_entry_get_proto(fib_entry));
+    lb_proto = fib_entry_get_payload_proto(fib_entry);
 
     fib_path_list_walk(esrc->fes_pl,
                        fib_entry_src_collect_forwarding,
@@ -369,6 +384,7 @@ fib_entry_src_mk_lb (fib_entry_t *fib_entry,
     load_balance_multipath_update(dpo_lb,
                                   ctx.next_hops,
                                   fib_entry_calc_lb_flags(&ctx));
+    vec_free(ctx.next_hops);
 
     /*
      * if this entry is sourced by the uRPF-exempt source then we
@@ -408,21 +424,33 @@ fib_entry_src_action_install (fib_entry_t *fib_entry,
      */
     fib_forward_chain_type_t fct;
     fib_entry_src_t *esrc;
+    int insert;
 
     fct = fib_entry_get_default_chain_type(fib_entry);
     esrc = fib_entry_src_find(fib_entry, source, NULL);
 
+    /*
+     * Every entry has its own load-balance object. All changes to the entry's
+     * forwarding result in an inplace modify of the load-balance. This means
+     * the load-balance object only needs to be added to the forwarding
+     * DB once, when it is created.
+     */
+    insert = !dpo_id_is_valid(&fib_entry->fe_lb[fct]);
+
     fib_entry_src_mk_lb(fib_entry, esrc, fct, &fib_entry->fe_lb[fct]);
 
-    FIB_ENTRY_DBG(fib_entry, "install: %d",
-                 fib_entry->fe_lb[fct]);
+    ASSERT(dpo_id_is_valid(&fib_entry->fe_lb[fct]));
+    FIB_ENTRY_DBG(fib_entry, "install: %d", fib_entry->fe_lb[fct]);
 
     /*
      * insert the adj into the data-plane forwarding trie
      */
-    fib_table_fwding_dpo_update(fib_entry->fe_fib_index,
-                               &fib_entry->fe_prefix,
-                               &fib_entry->fe_lb[fct]);
+    if (insert)
+    {
+       fib_table_fwding_dpo_update(fib_entry->fe_fib_index,
+                                   &fib_entry->fe_prefix,
+                                   &fib_entry->fe_lb[fct]);
+    }
 
     if (FIB_FORW_CHAIN_TYPE_UNICAST_IP4 == fct ||
        FIB_FORW_CHAIN_TYPE_UNICAST_IP6 == fct)
@@ -717,6 +745,56 @@ fib_entry_src_action_add (fib_entry_t *fib_entry,
     return (fib_entry);
 }
 
+/*
+ * fib_entry_src_action_update
+ *
+ * Adding a source can result in a new fib_entry being created, which
+ * can inturn mean the pool is realloc'd and thus the entry passed as
+ * an argument it also realloc'd
+ * @return the original entry
+ */
+fib_entry_t *
+fib_entry_src_action_update (fib_entry_t *fib_entry,
+                            fib_source_t source,
+                            fib_entry_flag_t flags,
+                            const dpo_id_t *dpo)
+{
+    fib_node_index_t fib_entry_index, old_path_list_index;
+    fib_entry_src_t *esrc;
+
+    esrc = fib_entry_src_find_or_create(fib_entry, source, NULL);
+
+    if (NULL == esrc)
+       return (fib_entry_src_action_add(fib_entry, source, flags, dpo));
+
+    old_path_list_index = esrc->fes_pl;
+    esrc->fes_entry_flags = flags;
+
+    /*
+     * save variable so we can recover from a fib_entry realloc.
+     */
+    fib_entry_index = fib_entry_get_index(fib_entry);
+
+    if (NULL != fib_entry_src_vft[source].fesv_add)
+    {
+       fib_entry_src_vft[source].fesv_add(esrc,
+                                          fib_entry,
+                                          flags,
+                                          fib_entry_get_proto(fib_entry),
+                                          dpo);
+    }
+
+    fib_entry = fib_entry_get(fib_entry_index);
+
+    esrc->fes_flags |= FIB_ENTRY_SRC_FLAG_ADDED;
+
+    fib_path_list_lock(esrc->fes_pl);
+    fib_path_list_unlock(old_path_list_index);
+
+    return (fib_entry);
+}
+
+
 fib_entry_src_flag_t
 fib_entry_src_action_remove (fib_entry_t *fib_entry,
                             fib_source_t source)