aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/lisp-gpe
diff options
context:
space:
mode:
authorFlorin Coras <fcoras@cisco.com>2017-01-26 14:25:34 -0800
committerNeale Ranns <nranns@cisco.com>2017-02-13 08:51:30 +0000
commitce1b4c7f05ce28d7b73eb7ed0a8ea4bd483f09e9 (patch)
tree5e7f6cab01b2df39d12d3865af7c809916c51d63 /src/vnet/lisp-gpe
parentfdd81af6afe6c782ad2c1a139210378badec626b (diff)
Basic support for LISP-GPE encapsulated NSH packets
Change-Id: I97fedb0f70dd18ed9bbe985407cc5fe714e8a2e2 Signed-off-by: Florin Coras <fcoras@cisco.com>
Diffstat (limited to 'src/vnet/lisp-gpe')
-rw-r--r--src/vnet/lisp-gpe/interface.c196
-rw-r--r--src/vnet/lisp-gpe/lisp_gpe.c2
-rw-r--r--src/vnet/lisp-gpe/lisp_gpe.h9
-rw-r--r--src/vnet/lisp-gpe/lisp_gpe_adjacency.c8
-rw-r--r--src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c309
-rw-r--r--src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h31
6 files changed, 543 insertions, 12 deletions
diff --git a/src/vnet/lisp-gpe/interface.c b/src/vnet/lisp-gpe/interface.c
index 3288b2414b7..d12dc362dac 100644
--- a/src/vnet/lisp-gpe/interface.c
+++ b/src/vnet/lisp-gpe/interface.c
@@ -201,7 +201,7 @@ VNET_HW_INTERFACE_CLASS (lisp_gpe_hw_class) = {
typedef struct
{
- u32 lb_index;
+ u32 dpo_index;
} l2_lisp_gpe_tx_trace_t;
static u8 *
@@ -211,7 +211,7 @@ format_l2_lisp_gpe_tx_trace (u8 * s, va_list * args)
CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
l2_lisp_gpe_tx_trace_t *t = va_arg (*args, l2_lisp_gpe_tx_trace_t *);
- s = format (s, "L2-LISP-GPE-TX: load-balance %d", t->lb_index);
+ s = format (s, "L2-LISP-GPE-TX: load-balance %d", t->dpo_index);
return s;
}
@@ -278,7 +278,7 @@ l2_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
{
l2_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
sizeof (*tr));
- tr->lb_index = lbi0;
+ tr->dpo_index = lbi0;
}
vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
n_left_to_next, bi0, l2_arc_to_lb);
@@ -306,6 +306,110 @@ VNET_DEVICE_CLASS (l2_lisp_gpe_device_class,static) = {
};
/* *INDENT-ON* */
+typedef struct
+{
+ u32 dpo_index;
+} nsh_lisp_gpe_tx_trace_t;
+
+u8 *
+format_nsh_lisp_gpe_tx_trace (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ nsh_lisp_gpe_tx_trace_t *t = va_arg (*args, nsh_lisp_gpe_tx_trace_t *);
+
+ s = format (s, "NSH-GPE-TX: tunnel %d", t->dpo_index);
+ return s;
+}
+
+/**
+ * @brief LISP-GPE interface TX for NSH overlays.
+ * @node nsh_lisp_gpe_interface_tx
+ *
+ * The NSH LISP-GPE interface TX function.
+ *
+ * @param[in] vm vlib_main_t corresponding to the current thread.
+ * @param[in] node vlib_node_runtime_t data for this node.
+ * @param[in] frame vlib_frame_t whose contents should be dispatched.
+ *
+ * @return number of vectors in frame.
+ */
+static uword
+nsh_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame)
+{
+ u32 n_left_from, next_index, *from, *to_next;
+ lisp_gpe_main_t *lgm = &lisp_gpe_main;
+
+ from = vlib_frame_vector_args (from_frame);
+ n_left_from = from_frame->n_vectors;
+
+ next_index = node->cached_next_index;
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ vlib_buffer_t *b0;
+ u32 bi0;
+ u32 *nsh0, next0;
+ const dpo_id_t *dpo0;
+
+ bi0 = from[0];
+ to_next[0] = bi0;
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ nsh0 = vlib_buffer_get_current (b0);
+
+ vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_LCAF;
+
+ /* lookup SPI + SI (second word of the NSH header).
+ * NB: Load balancing was done by the control plane */
+ dpo0 = lisp_nsh_fib_lookup (lgm, nsh0[1]);
+
+ next0 = dpo0->dpoi_next_node;
+ vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
+
+ if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ nsh_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
+ sizeof (*tr));
+ tr->dpo_index = dpo0->dpoi_index;
+ }
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+ n_left_to_next, bi0, next0);
+ }
+
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ }
+
+ return from_frame->n_vectors;
+}
+
+static u8 *
+format_nsh_lisp_gpe_name (u8 * s, va_list * args)
+{
+ u32 dev_instance = va_arg (*args, u32);
+ return format (s, "nsh_lisp_gpe%d", dev_instance);
+}
+
+/* *INDENT-OFF* */
+VNET_DEVICE_CLASS (nsh_lisp_gpe_device_class,static) = {
+ .name = "NSH_LISP_GPE",
+ .format_device_name = format_nsh_lisp_gpe_name,
+ .format_tx_trace = format_nsh_lisp_gpe_tx_trace,
+ .tx_function = nsh_lisp_gpe_interface_tx,
+};
+/* *INDENT-ON* */
+
static vnet_hw_interface_t *
lisp_gpe_create_iface (lisp_gpe_main_t * lgm, u32 vni, u32 dp_table,
vnet_device_class_t * dev_class,
@@ -615,6 +719,72 @@ lisp_gpe_del_l2_iface (lisp_gpe_main_t * lgm, u32 vni, u32 bd_id)
lisp_gpe_remove_iface (lgm, hip[0], bd_index, &lgm->l2_ifaces);
}
+/**
+ * @brief Add LISP-GPE NSH interface.
+ *
+ * Creates LISP-GPE interface, sets it in L3 mode.
+ *
+ * @param[in] lgm Reference to @ref lisp_gpe_main_t.
+ * @param[in] a Parameters to create interface.
+ *
+ * @return sw_if_index.
+ */
+u32
+lisp_gpe_add_nsh_iface (lisp_gpe_main_t * lgm)
+{
+ vnet_main_t *vnm = lgm->vnet_main;
+ tunnel_lookup_t *nsh_ifaces = &lgm->nsh_ifaces;
+ vnet_hw_interface_t *hi;
+ uword *hip, *si;
+
+ hip = hash_get (nsh_ifaces->hw_if_index_by_dp_table, 0);
+
+ if (hip)
+ {
+ clib_warning ("NSH interface 0 already exists");
+ return ~0;
+ }
+
+ si = hash_get (nsh_ifaces->sw_if_index_by_vni, 0);
+ if (si)
+ {
+ clib_warning ("NSH interface already exists");
+ return ~0;
+ }
+
+ /* create lisp iface and populate tunnel tables */
+ hi = lisp_gpe_create_iface (lgm, 0, 0,
+ &nsh_lisp_gpe_device_class, &lgm->nsh_ifaces);
+
+ /* enable interface */
+ vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
+ VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+ vnet_hw_interface_set_flags (vnm, hi->hw_if_index,
+ VNET_HW_INTERFACE_FLAG_LINK_UP);
+
+ return (hi->sw_if_index);
+}
+
+/**
+ * @brief Del LISP-GPE NSH interface.
+ *
+ */
+void
+lisp_gpe_del_nsh_iface (lisp_gpe_main_t * lgm)
+{
+ tunnel_lookup_t *nsh_ifaces = &lgm->nsh_ifaces;
+ uword *hip;
+
+ hip = hash_get (nsh_ifaces->hw_if_index_by_dp_table, 0);
+
+ if (hip == 0)
+ {
+ clib_warning ("The NSH 0 interface doesn't exist");
+ return;
+ }
+ lisp_gpe_remove_iface (lgm, hip[0], 0, &lgm->nsh_ifaces);
+}
+
static clib_error_t *
lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
@@ -623,6 +793,7 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
u8 is_add = 1;
u32 table_id, vni, bd_id;
u8 vni_is_set = 0, vrf_is_set = 0, bd_index_is_set = 0;
+ u8 nsh_iface = 0;
if (vnet_lisp_gpe_enable_disable_status () == 0)
{
@@ -651,6 +822,10 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
{
bd_index_is_set = 1;
}
+ else if (unformat (line_input, "nsh"))
+ {
+ nsh_iface = 1;
+ }
else
{
return clib_error_return (0, "parse error: '%U'",
@@ -689,6 +864,21 @@ lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
lisp_gpe_tenant_l3_iface_unlock (vni);
}
+ if (nsh_iface)
+ {
+ if (is_add)
+ {
+ if (~0 == lisp_gpe_add_nsh_iface (&lisp_gpe_main))
+ {
+ return clib_error_return (0, "NSH interface not created");
+ }
+ else
+ {
+ lisp_gpe_del_nsh_iface (&lisp_gpe_main);
+ }
+ }
+ }
+
return (NULL);
}
diff --git a/src/vnet/lisp-gpe/lisp_gpe.c b/src/vnet/lisp-gpe/lisp_gpe.c
index e78d45c9020..e76c03f0033 100644
--- a/src/vnet/lisp-gpe/lisp_gpe.c
+++ b/src/vnet/lisp-gpe/lisp_gpe.c
@@ -151,6 +151,7 @@ lisp_gpe_add_del_fwd_entry_command_fn (vlib_main_t * vm,
gid_address_copy (&a->lcl_eid, leid);
gid_address_copy (&a->rmt_eid, reid);
a->locator_pairs = pairs;
+ a->action = action;
rv = vnet_lisp_gpe_add_del_fwd_entry (a, 0);
if (0 != rv)
@@ -291,7 +292,6 @@ format_vnet_lisp_gpe_status (u8 * s, va_list * args)
return format (s, "%s", lgm->is_en ? "enabled" : "disabled");
}
-
/** LISP-GPE init function. */
clib_error_t *
lisp_gpe_init (vlib_main_t * vm)
diff --git a/src/vnet/lisp-gpe/lisp_gpe.h b/src/vnet/lisp-gpe/lisp_gpe.h
index 3288c99ffee..e92df38542c 100644
--- a/src/vnet/lisp-gpe/lisp_gpe.h
+++ b/src/vnet/lisp-gpe/lisp_gpe.h
@@ -119,6 +119,15 @@ typedef struct lisp_gpe_main
/** Load-balance for a miss in the table */
dpo_id_t l2_lb_cp_lkup;
+ /* NSH data structures
+ * ================== */
+
+ BVT (clib_bihash) nsh_fib;
+
+ tunnel_lookup_t nsh_ifaces;
+
+ const dpo_id_t *nsh_cp_lkup;
+
/** convenience */
vlib_main_t *vlib_main;
vnet_main_t *vnet_main;
diff --git a/src/vnet/lisp-gpe/lisp_gpe_adjacency.c b/src/vnet/lisp-gpe/lisp_gpe_adjacency.c
index 8c96a25cc5d..1dbf8677f71 100644
--- a/src/vnet/lisp-gpe/lisp_gpe_adjacency.c
+++ b/src/vnet/lisp-gpe/lisp_gpe_adjacency.c
@@ -211,6 +211,8 @@ lisp_gpe_adj_proto_from_vnet_link_type (vnet_link_t linkt)
return (LISP_GPE_NEXT_PROTO_IP6);
case VNET_LINK_ETHERNET:
return (LISP_GPE_NEXT_PROTO_ETHERNET);
+ case VNET_LINK_NSH:
+ return (LISP_GPE_NEXT_PROTO_NSH);
default:
ASSERT (0);
}
@@ -254,14 +256,14 @@ lisp_gpe_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
ladj = pool_elt_at_index (lisp_adj_pool, lai);
lgt = lisp_gpe_tunnel_get (ladj->tunnel_index);
linkt = adj_get_link_type (ai);
-
adj_nbr_midchain_update_rewrite
(ai, lisp_gpe_fixup,
(VNET_LINK_ETHERNET == linkt ?
ADJ_MIDCHAIN_FLAG_NO_COUNT :
ADJ_MIDCHAIN_FLAG_NONE),
- lisp_gpe_tunnel_build_rewrite
- (lgt, ladj, lisp_gpe_adj_proto_from_vnet_link_type (linkt)));
+ lisp_gpe_tunnel_build_rewrite (lgt, ladj,
+ lisp_gpe_adj_proto_from_vnet_link_type
+ (linkt)));
lisp_gpe_adj_stack_one (ladj, ai);
}
diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c
index 7ad8679e8c0..e51b585e1be 100644
--- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c
+++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c
@@ -340,10 +340,14 @@ gid_to_dp_address (gid_address_t * g, dp_address_t * d)
d->type = FID_ADDR_IP_PREF;
break;
case GID_ADDR_MAC:
- default:
mac_copy (&d->mac, &gid_address_mac (g));
d->type = FID_ADDR_MAC;
break;
+ case GID_ADDR_NSH:
+ default:
+ d->nsh = gid_address_nsh (g).spi << 8 | gid_address_nsh (g).si;
+ d->type = FID_ADDR_NSH;
+ break;
}
}
@@ -671,7 +675,7 @@ del_l2_fwd_entry (lisp_gpe_main_t * lgm,
}
/**
- * @brief Construct and insert the forwarding information used by a L2 entry
+ * @brief Construct and insert the forwarding information used by an L2 entry
*/
static void
lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_t * lfe)
@@ -688,7 +692,16 @@ lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_t * lfe)
}
else
{
- dpo_copy (&dpo, &lgm->l2_lb_cp_lkup);
+ switch (lfe->action)
+ {
+ case SEND_MAP_REQUEST:
+ dpo_copy (&dpo, &lgm->l2_lb_cp_lkup);
+ break;
+ case NO_ACTION:
+ case FORWARD_NATIVE:
+ case DROP:
+ dpo_copy (&dpo, drop_dpo_get (DPO_PROTO_ETHERNET));
+ }
}
/* add entry to l2 lisp fib */
@@ -785,6 +798,276 @@ add_l2_fwd_entry (lisp_gpe_main_t * lgm,
}
/**
+ * @brief Lookup NSH SD FIB entry
+ *
+ * Does an SPI+SI lookup in the NSH LISP FIB.
+ *
+ * @param[in] lgm Reference to @ref lisp_gpe_main_t.
+ * @param[in] spi_si SPI + SI.
+ *
+ * @return next node index.
+ */
+const dpo_id_t *
+lisp_nsh_fib_lookup (lisp_gpe_main_t * lgm, u32 spi_si)
+{
+ int rv;
+ BVT (clib_bihash_kv) kv, value;
+
+ memset (&kv, 0, sizeof (kv));
+ kv.key[0] = spi_si;
+ rv = BV (clib_bihash_search_inline_2) (&lgm->nsh_fib, &kv, &value);
+
+ if (rv != 0)
+ {
+ return lgm->nsh_cp_lkup;
+ }
+ else
+ {
+ lisp_gpe_fwd_entry_t *lfe;
+ lfe = pool_elt_at_index (lgm->lisp_fwd_entry_pool, value.value);
+ return &lfe->nsh.choice;
+ }
+}
+
+/**
+ * @brief Add/del NSH FIB entry
+ *
+ * Inserts value in NSH FIB keyed by SPI+SI. If entry is
+ * overwritten the associated value is returned.
+ *
+ * @param[in] lgm Reference to @ref lisp_gpe_main_t.
+ * @param[in] spi_si SPI + SI.
+ * @param[in] dpo Load balanced mapped to SPI + SI
+ *
+ * @return ~0 or value of overwritten entry.
+ */
+static u32
+lisp_nsh_fib_add_del_entry (u32 spi_si, u32 lfei, u8 is_add)
+{
+ lisp_gpe_main_t *lgm = &lisp_gpe_main;
+ BVT (clib_bihash_kv) kv, value;
+ u32 old_val = ~0;
+
+ memset (&kv, 0, sizeof (kv));
+ kv.key[0] = spi_si;
+ kv.value = 0ULL;
+
+ if (BV (clib_bihash_search) (&lgm->nsh_fib, &kv, &value) == 0)
+ old_val = value.value;
+
+ if (!is_add)
+ BV (clib_bihash_add_del) (&lgm->nsh_fib, &kv, 0 /* is_add */ );
+ else
+ {
+ kv.value = lfei;
+ BV (clib_bihash_add_del) (&lgm->nsh_fib, &kv, 1 /* is_add */ );
+ }
+ return old_val;
+}
+
+#define NSH_FIB_DEFAULT_HASH_NUM_BUCKETS (64 * 1024)
+#define NSH_FIB_DEFAULT_HASH_MEMORY_SIZE (32<<20)
+
+static void
+nsh_fib_init (lisp_gpe_main_t * lgm)
+{
+ BV (clib_bihash_init) (&lgm->nsh_fib, "nsh fib",
+ 1 << max_log2 (NSH_FIB_DEFAULT_HASH_NUM_BUCKETS),
+ NSH_FIB_DEFAULT_HASH_MEMORY_SIZE);
+
+ /*
+ * the result from a 'miss' in a NSH Table
+ */
+ lgm->nsh_cp_lkup = lisp_cp_dpo_get (DPO_PROTO_NSH);
+}
+
+static void
+del_nsh_fwd_entry_i (lisp_gpe_main_t * lgm, lisp_gpe_fwd_entry_t * lfe)
+{
+ lisp_fwd_path_t *path;
+
+ if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
+ {
+ vec_foreach (path, lfe->paths)
+ {
+ lisp_gpe_adjacency_unlock (path->lisp_adj);
+ }
+ fib_path_list_child_remove (lfe->nsh.path_list_index,
+ lfe->nsh.child_index);
+ dpo_reset (&lfe->nsh.choice);
+ }
+
+ lisp_nsh_fib_add_del_entry (fid_addr_nsh (&lfe->key->rmt), (u32) ~ 0, 0);
+
+ hash_unset_mem (lgm->lisp_gpe_fwd_entries, lfe->key);
+ clib_mem_free (lfe->key);
+ pool_put (lgm->lisp_fwd_entry_pool, lfe);
+}
+
+/**
+ * @brief Delete LISP NSH forwarding entry.
+ *
+ * Coordinates the removal of forwarding entries for NSH LISP overlay:
+ *
+ * @param[in] lgm Reference to @ref lisp_gpe_main_t.
+ * @param[in] a Parameters for building the forwarding entry.
+ *
+ * @return 0 on success.
+ */
+static int
+del_nsh_fwd_entry (lisp_gpe_main_t * lgm,
+ vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
+{
+ lisp_gpe_fwd_entry_key_t key;
+ lisp_gpe_fwd_entry_t *lfe;
+
+ lfe = find_fwd_entry (lgm, a, &key);
+
+ if (NULL == lfe)
+ return VNET_API_ERROR_INVALID_VALUE;
+
+ del_nsh_fwd_entry_i (lgm, lfe);
+
+ return (0);
+}
+
+/**
+ * @brief Construct and insert the forwarding information used by an NSH entry
+ */
+static void
+lisp_gpe_nsh_update_fwding (lisp_gpe_fwd_entry_t * lfe)
+{
+ lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
+ dpo_id_t dpo = DPO_INVALID;
+ vnet_hw_interface_t *hi;
+ uword *hip;
+
+ if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
+ {
+ fib_path_list_contribute_forwarding (lfe->nsh.path_list_index,
+ FIB_FORW_CHAIN_TYPE_NSH,
+ &lfe->nsh.dpo);
+
+ /*
+ * LISP encap is always the same for this SPI+SI so we do that hash now
+ * and stack on the choice.
+ */
+ if (DPO_LOAD_BALANCE == lfe->nsh.dpo.dpoi_type)
+ {
+ const dpo_id_t *tmp;
+ const load_balance_t *lb;
+ int hash;
+
+ lb = load_balance_get (lfe->nsh.dpo.dpoi_index);
+ hash = fid_addr_nsh (&lfe->key->rmt) % lb->lb_n_buckets;
+ tmp =
+ load_balance_get_bucket_i (lb, hash & lb->lb_n_buckets_minus_1);
+
+ dpo_copy (&dpo, tmp);
+ }
+ }
+ else
+ {
+ switch (lfe->action)
+ {
+ case SEND_MAP_REQUEST:
+ dpo_copy (&dpo, lgm->nsh_cp_lkup);
+ break;
+ case NO_ACTION:
+ case FORWARD_NATIVE:
+ case DROP:
+ dpo_copy (&dpo, drop_dpo_get (DPO_PROTO_NSH));
+ }
+ }
+
+ /* We have only one nsh-lisp interface (no NSH virtualization) */
+ hip = hash_get (lgm->nsh_ifaces.hw_if_index_by_dp_table, 0);
+ hi = vnet_get_hw_interface (lgm->vnet_main, hip[0]);
+
+ dpo_stack_from_node (hi->tx_node_index, &lfe->nsh.choice, &dpo);
+
+ /* add entry to nsh lisp fib */
+ lisp_nsh_fib_add_del_entry (fid_addr_nsh (&lfe->key->rmt),
+ lfe - lgm->lisp_fwd_entry_pool, 1);
+
+ dpo_reset (&dpo);
+}
+
+/**
+ * @brief Add LISP NSH forwarding entry.
+ *
+ * Coordinates the creation of forwarding entries for L2 LISP overlay:
+ * creates lisp-gpe tunnel and injects new entry in Source/Dest L2 FIB.
+ *
+ * @param[in] lgm Reference to @ref lisp_gpe_main_t.
+ * @param[in] a Parameters for building the forwarding entry.
+ *
+ * @return 0 on success.
+ */
+static int
+add_nsh_fwd_entry (lisp_gpe_main_t * lgm,
+ vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
+{
+ lisp_gpe_fwd_entry_key_t key;
+ lisp_gpe_fwd_entry_t *lfe;
+
+ lfe = find_fwd_entry (lgm, a, &key);
+
+ if (NULL != lfe)
+ /* don't support updates */
+ return VNET_API_ERROR_INVALID_VALUE;
+
+ pool_get (lgm->lisp_fwd_entry_pool, lfe);
+ memset (lfe, 0, sizeof (*lfe));
+ lfe->key = clib_mem_alloc (sizeof (key));
+ memcpy (lfe->key, &key, sizeof (key));
+
+ hash_set_mem (lgm->lisp_gpe_fwd_entries, lfe->key,
+ lfe - lgm->lisp_fwd_entry_pool);
+
+ lfe->type = (a->is_negative ?
+ LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE :
+ LISP_GPE_FWD_ENTRY_TYPE_NORMAL);
+ lfe->tenant = 0;
+
+ if (LISP_GPE_FWD_ENTRY_TYPE_NEGATIVE != lfe->type)
+ {
+ fib_route_path_t *rpaths;
+
+ /*
+ * Make the sorted array of LISP paths with their resp. adjacency
+ */
+ lisp_gpe_fwd_entry_mk_paths (lfe, a);
+
+ /*
+ * From the LISP paths, construct a FIB path list that will
+ * contribute a load-balance.
+ */
+ rpaths = lisp_gpe_mk_fib_paths (lfe->paths);
+
+ lfe->nsh.path_list_index =
+ fib_path_list_create (FIB_PATH_LIST_FLAG_NONE, rpaths);
+
+ /*
+ * become a child of the path-list so we receive updates when
+ * its forwarding state changes. this includes an implicit lock.
+ */
+ lfe->nsh.child_index =
+ fib_path_list_child_add (lfe->nsh.path_list_index,
+ FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY,
+ lfe - lgm->lisp_fwd_entry_pool);
+ }
+ else
+ {
+ lfe->action = a->action;
+ }
+
+ lisp_gpe_nsh_update_fwding (lfe);
+
+ return 0;
+}
+
+/**
* @brief conver from the embedded fib_node_t struct to the LSIP entry
*/
static lisp_gpe_fwd_entry_t *
@@ -802,7 +1085,12 @@ static fib_node_back_walk_rc_t
lisp_gpe_fib_node_back_walk (fib_node_t * node,
fib_node_back_walk_ctx_t * ctx)
{
- lisp_gpe_l2_update_fwding (lisp_gpe_fwd_entry_from_fib_node (node));
+ lisp_gpe_fwd_entry_t *lfe = lisp_gpe_fwd_entry_from_fib_node (node);
+
+ if (fid_addr_type (&lfe->key->rmt) == FID_ADDR_MAC)
+ lisp_gpe_l2_update_fwding (lfe);
+ else if (fid_addr_type (&lfe->key->rmt) == FID_ADDR_NSH)
+ lisp_gpe_nsh_update_fwding (lfe);
return (FIB_NODE_BACK_WALK_CONTINUE);
}
@@ -877,6 +1165,11 @@ vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
return add_l2_fwd_entry (lgm, a);
else
return del_l2_fwd_entry (lgm, a);
+ case GID_ADDR_NSH:
+ if (a->is_add)
+ return add_nsh_fwd_entry (lgm, a);
+ else
+ return del_nsh_fwd_entry (lgm, a);
default:
clib_warning ("Forwarding entries for type %d not supported!", type);
return -1;
@@ -903,6 +1196,9 @@ vnet_lisp_gpe_fwd_entry_flush (void)
case FID_ADDR_IP_PREF:
del_ip_fwd_entry_i (lgm, lfe);
break;
+ case FID_ADDR_NSH:
+ del_nsh_fwd_entry_i (lgm, lfe);
+ break;
}
}));
/* *INDENT-ON* */
@@ -967,6 +1263,10 @@ format_lisp_gpe_fwd_entry (u8 * s, va_list ap)
s = format (s, " fib-path-list:%d\n", lfe->l2.path_list_index);
s = format (s, " dpo:%U\n", format_dpo_id, &lfe->l2.dpo, 0);
break;
+ case FID_ADDR_NSH:
+ s = format (s, " fib-path-list:%d\n", lfe->nsh.path_list_index);
+ s = format (s, " dpo:%U\n", format_dpo_id, &lfe->nsh.dpo, 0);
+ break;
case FID_ADDR_IP_PREF:
break;
}
@@ -1036,6 +1336,7 @@ lisp_gpe_fwd_entry_init (vlib_main_t * vm)
return (error);
l2_fib_init (lgm);
+ nsh_fib_init (lgm);
fib_node_register_type (FIB_NODE_TYPE_LISP_GPE_FWD_ENTRY, &lisp_fwd_vft);
diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h
index f79236711ea..d58895a3e28 100644
--- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h
+++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.h
@@ -81,7 +81,7 @@ typedef struct lisp_gpe_fwd_entry_t_
fib_node_t node;
/**
- * The Entry's key: {lEID,r-EID,vni}
+ * The Entry's key: {lEID,rEID,vni}
*/
lisp_gpe_fwd_entry_key_t *key;
@@ -150,6 +150,33 @@ typedef struct lisp_gpe_fwd_entry_t_
*/
dpo_id_t dpo;
} l2;
+
+ /**
+ * Fields relevant to an NSH entry
+ */
+ struct
+ {
+ /**
+ * The path-list created for the forwarding
+ */
+ fib_node_index_t path_list_index;
+
+ /**
+ * Child index of this entry on the path-list
+ */
+ u32 child_index;
+
+ /**
+ * The DPO contributed by NSH
+ */
+ dpo_id_t dpo;
+
+ /**
+ * The DPO used for forwarding. Obtained after stacking tx node
+ * onto lb choice
+ */
+ dpo_id_t choice;
+ } nsh;
};
union
@@ -177,6 +204,8 @@ extern void vnet_lisp_gpe_fwd_entry_flush (void);
extern u32 lisp_l2_fib_lookup (lisp_gpe_main_t * lgm,
u16 bd_index, u8 src_mac[8], u8 dst_mac[8]);
+extern const dpo_id_t *lisp_nsh_fib_lookup (lisp_gpe_main_t * lgm,
+ u32 spi_si);
#endif
/*