aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/dpdk/device/node.c2
-rw-r--r--src/vat/api_format.c133
-rw-r--r--src/vnet.am2
-rw-r--r--src/vnet/adj/adj.c13
-rw-r--r--src/vnet/adj/adj.h6
-rw-r--r--src/vnet/adj/adj_internal.h14
-rw-r--r--src/vnet/adj/adj_mcast.c134
-rw-r--r--src/vnet/adj/adj_mcast.h27
-rw-r--r--src/vnet/adj/adj_midchain.c62
-rw-r--r--src/vnet/adj/adj_nbr.c2
-rw-r--r--src/vnet/buffer.h3
-rw-r--r--src/vnet/devices/ssvm/node.c2
-rw-r--r--src/vnet/dhcp/dhcp6_proxy_node.c1
-rw-r--r--src/vnet/dpo/dpo.c10
-rw-r--r--src/vnet/dpo/dpo.h8
-rw-r--r--src/vnet/dpo/interface_dpo.c416
-rw-r--r--src/vnet/dpo/interface_dpo.h67
-rw-r--r--src/vnet/dpo/lookup_dpo.c211
-rw-r--r--src/vnet/dpo/lookup_dpo.h20
-rw-r--r--src/vnet/dpo/mpls_disposition.c364
-rw-r--r--src/vnet/dpo/mpls_disposition.h85
-rw-r--r--src/vnet/dpo/mpls_label_dpo.c6
-rw-r--r--src/vnet/dpo/replicate_dpo.c48
-rw-r--r--src/vnet/dpo/replicate_dpo.h2
-rw-r--r--src/vnet/ethernet/arp.c1
-rw-r--r--src/vnet/ethernet/interface.c2
-rwxr-xr-xsrc/vnet/ethernet/node.c4
-rw-r--r--src/vnet/ethernet/types.def4
-rw-r--r--src/vnet/fib/fib_api.h4
-rw-r--r--src/vnet/fib/fib_entry.c47
-rw-r--r--src/vnet/fib/fib_entry.h13
-rw-r--r--src/vnet/fib/fib_entry_src.c154
-rw-r--r--src/vnet/fib/fib_internal.h1
-rw-r--r--src/vnet/fib/fib_path.c222
-rw-r--r--src/vnet/fib/fib_path.h17
-rw-r--r--src/vnet/fib/fib_path_ext.c4
-rw-r--r--src/vnet/fib/fib_path_ext.h3
-rw-r--r--src/vnet/fib/fib_path_list.c270
-rw-r--r--src/vnet/fib/fib_path_list.h22
-rw-r--r--src/vnet/fib/fib_table.c47
-rw-r--r--src/vnet/fib/fib_test.c345
-rw-r--r--src/vnet/fib/fib_test.h111
-rw-r--r--src/vnet/fib/fib_types.c15
-rw-r--r--src/vnet/fib/fib_types.h60
-rw-r--r--src/vnet/fib/mpls_fib.c15
-rw-r--r--src/vnet/handoff.h10
-rw-r--r--src/vnet/interface.c2
-rw-r--r--src/vnet/ip/ip.api3
-rw-r--r--src/vnet/ip/ip4_forward.c20
-rw-r--r--src/vnet/ip/ip6_forward.c23
-rw-r--r--src/vnet/ip/ip6_neighbor.c1
-rw-r--r--src/vnet/ip/ip_api.c98
-rwxr-xr-xsrc/vnet/ip/lookup.c3
-rw-r--r--src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c1
-rw-r--r--src/vnet/mfib/ip4_mfib.c1
-rw-r--r--src/vnet/mfib/ip6_mfib.c1
-rw-r--r--src/vnet/mfib/mfib_entry.c395
-rw-r--r--src/vnet/mfib/mfib_entry.h20
-rw-r--r--src/vnet/mfib/mfib_forward.c29
-rw-r--r--src/vnet/mfib/mfib_table.c8
-rw-r--r--src/vnet/mfib/mfib_table.h1
-rw-r--r--src/vnet/mfib/mfib_test.c127
-rw-r--r--src/vnet/mpls/mpls.api87
-rw-r--r--src/vnet/mpls/mpls.c17
-rw-r--r--src/vnet/mpls/mpls_api.c97
-rw-r--r--src/vnet/mpls/mpls_input.c2
-rw-r--r--src/vnet/mpls/mpls_lookup.c236
-rw-r--r--src/vnet/mpls/mpls_tunnel.c883
-rw-r--r--src/vnet/mpls/mpls_tunnel.h57
-rw-r--r--src/vnet/mpls/mpls_types.h20
-rw-r--r--src/vnet/srp/interface.c2
-rw-r--r--test/test_ip_mcast.py1
-rw-r--r--test/test_mpls.py277
-rw-r--r--test/vpp_ip_route.py38
-rw-r--r--test/vpp_mpls_tunnel_interface.py46
-rw-r--r--test/vpp_papi_provider.py16
76 files changed, 4393 insertions, 1128 deletions
diff --git a/src/plugins/dpdk/device/node.c b/src/plugins/dpdk/device/node.c
index b10e0fadb6f..0549ba5d23e 100644
--- a/src/plugins/dpdk/device/node.c
+++ b/src/plugins/dpdk/device/node.c
@@ -52,7 +52,7 @@ always_inline int
vlib_buffer_is_mpls (vlib_buffer_t * b)
{
ethernet_header_t *h = (ethernet_header_t *) vlib_buffer_get_current (b);
- return (h->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS_UNICAST));
+ return (h->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS));
}
always_inline u32
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index 61b8e1d8de4..107aa012c02 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -16369,32 +16369,82 @@ api_netmap_delete (vat_main_t * vam)
return ret;
}
-static void vl_api_mpls_tunnel_details_t_handler
- (vl_api_mpls_tunnel_details_t * mp)
+static void
+vl_api_mpls_fib_path_print (vat_main_t * vam, vl_api_fib_path2_t * fp)
+{
+ if (fp->afi == IP46_TYPE_IP6)
+ print (vam->ofp,
+ " weight %d, sw_if_index %d, is_local %d, is_drop %d, "
+ "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U",
+ ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local,
+ fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi,
+ format_ip6_address, fp->next_hop);
+ else if (fp->afi == IP46_TYPE_IP4)
+ print (vam->ofp,
+ " weight %d, sw_if_index %d, is_local %d, is_drop %d, "
+ "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U",
+ ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local,
+ fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi,
+ format_ip4_address, fp->next_hop);
+}
+
+static void
+vl_api_mpls_fib_path_json_print (vat_json_node_t * node,
+ vl_api_fib_path2_t * fp)
+{
+ struct in_addr ip4;
+ struct in6_addr ip6;
+
+ vat_json_object_add_uint (node, "weight", ntohl (fp->weight));
+ vat_json_object_add_uint (node, "sw_if_index", ntohl (fp->sw_if_index));
+ vat_json_object_add_uint (node, "is_local", fp->is_local);
+ vat_json_object_add_uint (node, "is_drop", fp->is_drop);
+ vat_json_object_add_uint (node, "is_unreach", fp->is_unreach);
+ vat_json_object_add_uint (node, "is_prohibit", fp->is_prohibit);
+ vat_json_object_add_uint (node, "next_hop_afi", fp->afi);
+ if (fp->afi == IP46_TYPE_IP4)
+ {
+ clib_memcpy (&ip4, &fp->next_hop, sizeof (ip4));
+ vat_json_object_add_ip4 (node, "next_hop", ip4);
+ }
+ else if (fp->afi == IP46_TYPE_IP6)
+ {
+ clib_memcpy (&ip6, &fp->next_hop, sizeof (ip6));
+ vat_json_object_add_ip6 (node, "next_hop", ip6);
+ }
+}
+
+static void
+vl_api_mpls_tunnel_details_t_handler (vl_api_mpls_tunnel_details_t * mp)
{
vat_main_t *vam = &vat_main;
- i32 len = mp->mt_next_hop_n_labels;
+ int count = ntohl (mp->mt_count);
+ vl_api_fib_path2_t *fp;
i32 i;
- print (vam->ofp, "[%d]: via %U %d labels ",
- mp->tunnel_index,
- format_ip4_address, mp->mt_next_hop,
- ntohl (mp->mt_next_hop_sw_if_index));
- for (i = 0; i < len; i++)
+ print (vam->ofp, "[%d]: sw_if_index %d via:",
+ ntohl (mp->mt_tunnel_index), ntohl (mp->mt_sw_if_index));
+ fp = mp->mt_paths;
+ for (i = 0; i < count; i++)
{
- print (vam->ofp, "%u ", ntohl (mp->mt_next_hop_out_labels[i]));
+ vl_api_mpls_fib_path_print (vam, fp);
+ fp++;
}
+
print (vam->ofp, "");
}
-static void vl_api_mpls_tunnel_details_t_handler_json
- (vl_api_mpls_tunnel_details_t * mp)
+#define vl_api_mpls_tunnel_details_t_endian vl_noop_handler
+#define vl_api_mpls_tunnel_details_t_print vl_noop_handler
+
+static void
+vl_api_mpls_tunnel_details_t_handler_json (vl_api_mpls_tunnel_details_t * mp)
{
vat_main_t *vam = &vat_main;
vat_json_node_t *node = NULL;
- struct in_addr ip4;
+ int count = ntohl (mp->mt_count);
+ vl_api_fib_path2_t *fp;
i32 i;
- i32 len = mp->mt_next_hop_n_labels;
if (VAT_JSON_ARRAY != vam->json_tree.type)
{
@@ -16404,17 +16454,17 @@ static void vl_api_mpls_tunnel_details_t_handler_json
node = vat_json_array_add (&vam->json_tree);
vat_json_init_object (node);
- vat_json_object_add_uint (node, "tunnel_index", ntohl (mp->tunnel_index));
- clib_memcpy (&ip4, &(mp->mt_next_hop), sizeof (ip4));
- vat_json_object_add_ip4 (node, "next_hop", ip4);
- vat_json_object_add_uint (node, "next_hop_sw_if_index",
- ntohl (mp->mt_next_hop_sw_if_index));
- vat_json_object_add_uint (node, "l2_only", ntohl (mp->mt_l2_only));
- vat_json_object_add_uint (node, "label_count", len);
- for (i = 0; i < len; i++)
+ vat_json_object_add_uint (node, "tunnel_index",
+ ntohl (mp->mt_tunnel_index));
+ vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->mt_sw_if_index));
+
+ vat_json_object_add_uint (node, "l2_only", mp->mt_l2_only);
+
+ fp = mp->mt_paths;
+ for (i = 0; i < count; i++)
{
- vat_json_object_add_uint (node, "label",
- ntohl (mp->mt_next_hop_out_labels[i]));
+ vl_api_mpls_fib_path_json_print (node, fp);
+ fp++;
}
}
@@ -16453,6 +16503,7 @@ api_mpls_tunnel_dump (vat_main_t * vam)
#define vl_api_mpls_fib_details_t_endian vl_noop_handler
#define vl_api_mpls_fib_details_t_print vl_noop_handler
+
static void
vl_api_mpls_fib_details_t_handler (vl_api_mpls_fib_details_t * mp)
{
@@ -16467,20 +16518,7 @@ vl_api_mpls_fib_details_t_handler (vl_api_mpls_fib_details_t * mp)
fp = mp->path;
for (i = 0; i < count; i++)
{
- if (fp->afi == IP46_TYPE_IP6)
- print (vam->ofp,
- " weight %d, sw_if_index %d, is_local %d, is_drop %d, "
- "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U",
- ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local,
- fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi,
- format_ip6_address, fp->next_hop);
- else if (fp->afi == IP46_TYPE_IP4)
- print (vam->ofp,
- " weight %d, sw_if_index %d, is_local %d, is_drop %d, "
- "is_unreach %d, is_prohitbit %d, afi %d, next_hop %U",
- ntohl (fp->weight), ntohl (fp->sw_if_index), fp->is_local,
- fp->is_drop, fp->is_unreach, fp->is_prohibit, fp->afi,
- format_ip4_address, fp->next_hop);
+ vl_api_mpls_fib_path_print (vam, fp);
fp++;
}
}
@@ -16491,8 +16529,6 @@ static void vl_api_mpls_fib_details_t_handler_json
vat_main_t *vam = &vat_main;
int count = ntohl (mp->count);
vat_json_node_t *node = NULL;
- struct in_addr ip4;
- struct in6_addr ip6;
vl_api_fib_path2_t *fp;
int i;
@@ -16511,23 +16547,8 @@ static void vl_api_mpls_fib_details_t_handler_json
fp = mp->path;
for (i = 0; i < count; i++)
{
- vat_json_object_add_uint (node, "weight", ntohl (fp->weight));
- vat_json_object_add_uint (node, "sw_if_index", ntohl (fp->sw_if_index));
- vat_json_object_add_uint (node, "is_local", fp->is_local);
- vat_json_object_add_uint (node, "is_drop", fp->is_drop);
- vat_json_object_add_uint (node, "is_unreach", fp->is_unreach);
- vat_json_object_add_uint (node, "is_prohibit", fp->is_prohibit);
- vat_json_object_add_uint (node, "next_hop_afi", fp->afi);
- if (fp->afi == IP46_TYPE_IP4)
- {
- clib_memcpy (&ip4, &fp->next_hop, sizeof (ip4));
- vat_json_object_add_ip4 (node, "next_hop", ip4);
- }
- else if (fp->afi == IP46_TYPE_IP6)
- {
- clib_memcpy (&ip6, &fp->next_hop, sizeof (ip6));
- vat_json_object_add_ip6 (node, "next_hop", ip6);
- }
+ vl_api_mpls_fib_path_json_print (node, fp);
+ fp++;
}
}
diff --git a/src/vnet.am b/src/vnet.am
index 643ae92e3c6..bed4902ba0a 100644
--- a/src/vnet.am
+++ b/src/vnet.am
@@ -990,6 +990,8 @@ libvnet_la_SOURCES += \
vnet/dpo/lookup_dpo.c \
vnet/dpo/classify_dpo.c \
vnet/dpo/replicate_dpo.c \
+ vnet/dpo/interface_dpo.c \
+ vnet/dpo/mpls_disposition.c \
vnet/dpo/mpls_label_dpo.c
nobase_include_HEADERS += \
diff --git a/src/vnet/adj/adj.c b/src/vnet/adj/adj.c
index 90182006f60..36dfe500eb3 100644
--- a/src/vnet/adj/adj.c
+++ b/src/vnet/adj/adj.c
@@ -67,6 +67,10 @@ adj_alloc (fib_protocol_t proto)
adj->lookup_next_index = 0;
adj->ia_delegates = NULL;
+ /* lest it become a midchain in the future */
+ memset(&adj->sub_type.midchain.next_dpo, 0,
+ sizeof(adj->sub_type.midchain.next_dpo));
+
ip4_main.lookup_main.adjacency_heap = adj_pool;
ip6_main.lookup_main.adjacency_heap = adj_pool;
@@ -118,6 +122,9 @@ format_ip_adjacency (u8 * s, va_list * args)
case IP_LOOKUP_NEXT_MCAST:
s = format (s, "%U", format_adj_mcast, adj_index, 0);
break;
+ case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
+ s = format (s, "%U", format_adj_mcast_midchain, adj_index, 0);
+ break;
default:
break;
}
@@ -180,6 +187,7 @@ adj_last_lock_gone (ip_adjacency_t *adj)
adj->rewrite_header.sw_if_index);
break;
case IP_LOOKUP_NEXT_MCAST:
+ case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
adj_mcast_remove(adj->ia_nh_proto,
adj->rewrite_header.sw_if_index);
break;
@@ -338,6 +346,7 @@ adj_walk (u32 sw_if_index,
FOR_EACH_FIB_IP_PROTOCOL(proto)
{
adj_nbr_walk(sw_if_index, proto, cb, ctx);
+ adj_mcast_walk(sw_if_index, proto, cb, ctx);
}
}
@@ -544,9 +553,9 @@ adj_show (vlib_main_t * vm,
* [@0]
* [@1] glean: loop0
* [@2] ipv4 via 1.0.0.2 loop0: IP4: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
- * [@3] mpls via 1.0.0.2 loop0: MPLS_UNICAST: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
+ * [@3] mpls via 1.0.0.2 loop0: MPLS: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
* [@4] ipv4 via 1.0.0.3 loop0: IP4: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
- * [@5] mpls via 1.0.0.3 loop0: MPLS_UNICAST: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
+ * [@5] mpls via 1.0.0.3 loop0: MPLS: 00:00:22:aa:bb:cc -> 00:00:11:aa:bb:cc
* @cliexend
?*/
VLIB_CLI_COMMAND (adj_show_command, static) = {
diff --git a/src/vnet/adj/adj.h b/src/vnet/adj/adj.h
index 32997c91f92..ed5eb1f1e88 100644
--- a/src/vnet/adj/adj.h
+++ b/src/vnet/adj/adj.h
@@ -81,6 +81,10 @@ typedef enum
/** Multicast Adjacency. */
IP_LOOKUP_NEXT_MCAST,
+ /** Multicast Midchain Adjacency. An Adjacency for sending macst packets
+ * on a tunnel/virtual interface */
+ IP_LOOKUP_NEXT_MCAST_MIDCHAIN,
+
IP_LOOKUP_N_NEXT,
} __attribute__ ((packed)) ip_lookup_next_t;
@@ -107,6 +111,7 @@ typedef enum
[IP_LOOKUP_NEXT_REWRITE] = "ip4-rewrite", \
[IP_LOOKUP_NEXT_MCAST] = "ip4-rewrite-mcast", \
[IP_LOOKUP_NEXT_MIDCHAIN] = "ip4-midchain", \
+ [IP_LOOKUP_NEXT_MCAST_MIDCHAIN] = "ip4-mcast-midchain", \
[IP_LOOKUP_NEXT_ICMP_ERROR] = "ip4-icmp-error", \
}
@@ -119,6 +124,7 @@ typedef enum
[IP_LOOKUP_NEXT_REWRITE] = "ip6-rewrite", \
[IP_LOOKUP_NEXT_MCAST] = "ip6-rewrite-mcast", \
[IP_LOOKUP_NEXT_MIDCHAIN] = "ip6-midchain", \
+ [IP_LOOKUP_NEXT_MCAST_MIDCHAIN] = "ip6-mcast-midchain", \
[IP_LOOKUP_NEXT_ICMP_ERROR] = "ip6-icmp-error", \
[IP6_LOOKUP_NEXT_HOP_BY_HOP] = "ip6-hop-by-hop", \
[IP6_LOOKUP_NEXT_ADD_HOP_BY_HOP] = "ip6-add-hop-by-hop", \
diff --git a/src/vnet/adj/adj_internal.h b/src/vnet/adj/adj_internal.h
index 306686255b8..2c123c542a1 100644
--- a/src/vnet/adj/adj_internal.h
+++ b/src/vnet/adj/adj_internal.h
@@ -17,6 +17,7 @@
#define __ADJ_INTERNAL_H__
#include <vnet/adj/adj.h>
+#include <vnet/adj/adj_mcast.h>
#include <vnet/ip/ip.h>
#include <vnet/mpls/mpls.h>
#include <vnet/adj/adj_l2.h>
@@ -87,11 +88,14 @@ adj_get_index (ip_adjacency_t *adj)
return (adj - adj_pool);
}
-extern void adj_nbr_update_rewrite_internal (ip_adjacency_t *adj,
- ip_lookup_next_t adj_next_index,
- u32 complete_next_index,
- u32 next_index,
- u8 *rewrite);
+extern void adj_nbr_update_rewrite_internal(ip_adjacency_t *adj,
+ ip_lookup_next_t adj_next_index,
+ u32 complete_next_index,
+ u32 next_index,
+ u8 *rewrite);
+extern void adj_midchain_setup(adj_index_t adj_index,
+ adj_midchain_fixup_t fixup,
+ adj_flags_t flags);
extern ip_adjacency_t * adj_alloc(fib_protocol_t proto);
diff --git a/src/vnet/adj/adj_mcast.c b/src/vnet/adj/adj_mcast.c
index 4f678e43e80..755abfd4639 100644
--- a/src/vnet/adj/adj_mcast.c
+++ b/src/vnet/adj/adj_mcast.c
@@ -13,7 +13,7 @@
* limitations under the License.
*/
-#include <vnet/adj/adj.h>
+#include <vnet/adj/adj_mcast.h>
#include <vnet/adj/adj_internal.h>
#include <vnet/fib/fib_walk.h>
#include <vnet/ip/ip.h>
@@ -129,6 +129,59 @@ adj_mcast_update_rewrite (adj_index_t adj_index,
adj->rewrite_header.dst_mcast_mask = clib_host_to_net_u32(mask);
}
+/**
+ * adj_mcast_midchain_update_rewrite
+ *
+ * Update the adjacency's rewrite string. A NULL string implies the
+ * rewirte is reset (i.e. when ARP/ND etnry is gone).
+ * NB: the adj being updated may be handling traffic in the DP.
+ */
+void
+adj_mcast_midchain_update_rewrite (adj_index_t adj_index,
+ adj_midchain_fixup_t fixup,
+ adj_flags_t flags,
+ u8 *rewrite,
+ u8 offset,
+ u32 mask)
+{
+ ip_adjacency_t *adj;
+
+ ASSERT(ADJ_INDEX_INVALID != adj_index);
+
+ adj = adj_get(adj_index);
+
+ /*
+ * one time only update. since we don't support chainging the tunnel
+ * src,dst, this is all we need.
+ */
+ ASSERT(adj->lookup_next_index == IP_LOOKUP_NEXT_MCAST);
+ /*
+ * tunnels can always provide a rewrite.
+ */
+ ASSERT(NULL != rewrite);
+
+ adj_midchain_setup(adj_index, fixup, flags);
+
+ /*
+ * update the adj's rewrite string and build the arc
+ * from the rewrite node to the interface's TX node
+ */
+ adj_nbr_update_rewrite_internal(adj, IP_LOOKUP_NEXT_MCAST_MIDCHAIN,
+ adj_get_mcast_node(adj->ia_nh_proto),
+ vnet_tx_node_index_for_sw_interface(
+ vnet_get_main(),
+ adj->rewrite_header.sw_if_index),
+ rewrite);
+
+ /*
+ * set the fields corresponding to the mcast IP address rewrite
+ * The mask must be stored in network byte order, since the packet's
+ * IP address will also be in network order.
+ */
+ adj->rewrite_header.dst_mcast_offset = offset;
+ adj->rewrite_header.dst_mcast_mask = clib_host_to_net_u32(mask);
+}
+
void
adj_mcast_remove (fib_protocol_t proto,
u32 sw_if_index)
@@ -260,6 +313,24 @@ adj_mcast_interface_delete (vnet_main_t * vnm,
VNET_SW_INTERFACE_ADD_DEL_FUNCTION(adj_mcast_interface_delete);
+/**
+ * @brief Walk the multicast Adjacencies on a given interface
+ */
+void
+adj_mcast_walk (u32 sw_if_index,
+ fib_protocol_t proto,
+ adj_walk_cb_t cb,
+ void *ctx)
+{
+ if (vec_len(adj_mcasts[proto]) > sw_if_index)
+ {
+ if (ADJ_INDEX_INVALID != adj_mcasts[proto][sw_if_index])
+ {
+ cb(adj_mcasts[proto][sw_if_index], ctx);
+ }
+ }
+}
+
u8*
format_adj_mcast (u8* s, va_list *ap)
{
@@ -269,6 +340,8 @@ format_adj_mcast (u8* s, va_list *ap)
s = format(s, "%U-mcast: ",
format_fib_protocol, adj->ia_nh_proto);
+ if (adj->rewrite_header.flags & VNET_REWRITE_HAS_FEATURES)
+ s = format(s, "[features] ");
s = format (s, "%U",
format_vnet_rewrite,
&adj->rewrite_header, sizeof (adj->rewrite_data), 0);
@@ -276,6 +349,28 @@ format_adj_mcast (u8* s, va_list *ap)
return (s);
}
+u8*
+format_adj_mcast_midchain (u8* s, va_list *ap)
+{
+ index_t index = va_arg(*ap, index_t);
+ CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
+ vnet_main_t * vnm = vnet_get_main();
+ ip_adjacency_t * adj = adj_get(index);
+
+ s = format(s, "%U-mcast-midchain: ",
+ format_fib_protocol, adj->ia_nh_proto);
+ s = format (s, "%U",
+ format_vnet_rewrite,
+ vnm->vlib_main, &adj->rewrite_header,
+ sizeof (adj->rewrite_data), 0);
+ s = format (s, "\n%Ustacked-on:\n%U%U",
+ format_white_space, indent,
+ format_white_space, indent+2,
+ format_dpo_id, &adj->sub_type.midchain.next_dpo, indent+2);
+
+ return (s);
+}
+
static void
adj_dpo_lock (dpo_id_t *dpo)
@@ -293,6 +388,11 @@ const static dpo_vft_t adj_mcast_dpo_vft = {
.dv_unlock = adj_dpo_unlock,
.dv_format = format_adj_mcast,
};
+const static dpo_vft_t adj_mcast_midchain_dpo_vft = {
+ .dv_lock = adj_dpo_lock,
+ .dv_unlock = adj_dpo_unlock,
+ .dv_format = format_adj_mcast_midchain,
+};
/**
* @brief The per-protocol VLIB graph nodes that are assigned to a mcast
@@ -320,6 +420,31 @@ const static char* const * const adj_mcast_nodes[DPO_PROTO_NUM] =
};
/**
+ * @brief The per-protocol VLIB graph nodes that are assigned to a mcast
+ * object.
+ *
+ * this means that these graph nodes are ones from which a mcast is the
+ * parent object in the DPO-graph.
+ */
+const static char* const adj_mcast_midchain_ip4_nodes[] =
+{
+ "ip4-mcast-midchain",
+ NULL,
+};
+const static char* const adj_mcast_midchain_ip6_nodes[] =
+{
+ "ip6-mcast-midchain",
+ NULL,
+};
+
+const static char* const * const adj_mcast_midchain_nodes[DPO_PROTO_NUM] =
+{
+ [DPO_PROTO_IP4] = adj_mcast_midchain_ip4_nodes,
+ [DPO_PROTO_IP6] = adj_mcast_midchain_ip6_nodes,
+ [DPO_PROTO_MPLS] = NULL,
+};
+
+/**
* @brief Return the size of the adj DB.
* This is only for testing purposes so an efficient implementation is not needed
*/
@@ -349,5 +474,10 @@ adj_mcast_db_size (void)
void
adj_mcast_module_init (void)
{
- dpo_register(DPO_ADJACENCY_MCAST, &adj_mcast_dpo_vft, adj_mcast_nodes);
+ dpo_register(DPO_ADJACENCY_MCAST,
+ &adj_mcast_dpo_vft,
+ adj_mcast_nodes);
+ dpo_register(DPO_ADJACENCY_MCAST_MIDCHAIN,
+ &adj_mcast_midchain_dpo_vft,
+ adj_mcast_midchain_nodes);
}
diff --git a/src/vnet/adj/adj_mcast.h b/src/vnet/adj/adj_mcast.h
index 40d44313357..bfb0d6f6d11 100644
--- a/src/vnet/adj/adj_mcast.h
+++ b/src/vnet/adj/adj_mcast.h
@@ -26,6 +26,7 @@
#define __ADJ_MCAST_H__
#include <vnet/adj/adj_types.h>
+#include <vnet/adj/adj_midchain.h>
/**
* @brief
@@ -69,9 +70,35 @@ extern void adj_mcast_update_rewrite(adj_index_t adj_index,
u32 mask);
/**
+ * @brief
+ * Update the rewrite string for an existing adjacecny and
+ * Convert the adjacency into a midchain
+ *
+ * @param
+ * The index of the adj to update
+ *
+ * @param
+ * The new rewrite
+ */
+extern void adj_mcast_midchain_update_rewrite(adj_index_t adj_index,
+ adj_midchain_fixup_t fixup,
+ adj_flags_t flags,
+ u8 *rewrite,
+ u8 offset,
+ u32 mask);
+/**
+ * @brief Walk the multicast Adjacencies on a given interface
+ */
+extern void adj_mcast_walk (u32 sw_if_index,
+ fib_protocol_t adj_nh_proto,
+ adj_walk_cb_t cb,
+ void *ctx);
+
+/**
* @brief Format/display a mcast adjacency.
*/
extern u8* format_adj_mcast(u8* s, va_list *ap);
+extern u8* format_adj_mcast_midchain(u8* s, va_list *ap);
/**
* @brief Get the sze of the mcast adj DB. Test purposes only.
diff --git a/src/vnet/adj/adj_midchain.c b/src/vnet/adj/adj_midchain.c
index 5756de4393d..a93a1c3e1b7 100644
--- a/src/vnet/adj/adj_midchain.c
+++ b/src/vnet/adj/adj_midchain.c
@@ -346,7 +346,7 @@ adj_get_midchain_node (vnet_link_t link)
static u8
adj_midchain_get_feature_arc_index_for_link_type (const ip_adjacency_t *adj)
{
- u8 arc = (u8) ~0;
+ u8 arc = (u8) ~0;
switch (adj->ia_link)
{
case VNET_LINK_IP4:
@@ -393,17 +393,14 @@ adj_nbr_midchain_get_tx_node (ip_adjacency_t *adj)
}
/**
- * adj_nbr_midchain_update_rewrite
+ * adj_midchain_setup
*
- * Update the adjacency's rewrite string. A NULL string implies the
- * rewrite is reset (i.e. when ARP/ND etnry is gone).
- * NB: the adj being updated may be handling traffic in the DP.
+ * Setup the adj as a mid-chain
*/
void
-adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
- adj_midchain_fixup_t fixup,
- adj_flags_t flags,
- u8 *rewrite)
+adj_midchain_setup (adj_index_t adj_index,
+ adj_midchain_fixup_t fixup,
+ adj_flags_t flags)
{
u32 feature_index, tx_node;
ip_adjacency_t *adj;
@@ -413,16 +410,6 @@ adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
adj = adj_get(adj_index);
- /*
- * one time only update. since we don't support chainging the tunnel
- * src,dst, this is all we need.
- */
- ASSERT(adj->lookup_next_index == IP_LOOKUP_NEXT_ARP);
- /*
- * tunnels can always provide a rewrite.
- */
- ASSERT(NULL != rewrite);
-
adj->sub_type.midchain.fixup_func = fixup;
adj->ia_flags |= flags;
@@ -447,6 +434,38 @@ adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
dpo_stack_from_node(tx_node,
&adj->sub_type.midchain.next_dpo,
drop_dpo_get(vnet_link_to_dpo_proto(adj->ia_link)));
+}
+
+/**
+ * adj_nbr_midchain_update_rewrite
+ *
+ * Update the adjacency's rewrite string. A NULL string implies the
+ * rewrite is reset (i.e. when ARP/ND etnry is gone).
+ * NB: the adj being updated may be handling traffic in the DP.
+ */
+void
+adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
+ adj_midchain_fixup_t fixup,
+ adj_flags_t flags,
+ u8 *rewrite)
+{
+ ip_adjacency_t *adj;
+
+ ASSERT(ADJ_INDEX_INVALID != adj_index);
+
+ adj = adj_get(adj_index);
+
+ /*
+ * one time only update. since we don't support chainging the tunnel
+ * src,dst, this is all we need.
+ */
+ ASSERT(adj->lookup_next_index == IP_LOOKUP_NEXT_ARP);
+ /*
+ * tunnels can always provide a rewrite.
+ */
+ ASSERT(NULL != rewrite);
+
+ adj_midchain_setup(adj_index, fixup, flags);
/*
* update the rewirte with the workers paused.
@@ -454,7 +473,7 @@ adj_nbr_midchain_update_rewrite (adj_index_t adj_index,
adj_nbr_update_rewrite_internal(adj,
IP_LOOKUP_NEXT_MIDCHAIN,
adj_get_midchain_node(adj->ia_link),
- tx_node,
+ adj_nbr_midchain_get_tx_node(adj),
rewrite);
}
@@ -496,7 +515,8 @@ adj_nbr_midchain_stack (adj_index_t adj_index,
adj = adj_get(adj_index);
- ASSERT(IP_LOOKUP_NEXT_MIDCHAIN == adj->lookup_next_index);
+ ASSERT((IP_LOOKUP_NEXT_MIDCHAIN == adj->lookup_next_index) ||
+ (IP_LOOKUP_NEXT_MCAST_MIDCHAIN == adj->lookup_next_index));
dpo_stack_from_node(adj_nbr_midchain_get_tx_node(adj),
&adj->sub_type.midchain.next_dpo,
diff --git a/src/vnet/adj/adj_nbr.c b/src/vnet/adj/adj_nbr.c
index ddacb030f1d..3d450d1fba3 100644
--- a/src/vnet/adj/adj_nbr.c
+++ b/src/vnet/adj/adj_nbr.c
@@ -195,8 +195,6 @@ adj_nbr_alloc (fib_protocol_t nh_proto,
adj->ia_link = link_type;
adj->ia_nh_proto = nh_proto;
adj->rewrite_header.sw_if_index = sw_if_index;
- memset(&adj->sub_type.midchain.next_dpo, 0,
- sizeof(adj->sub_type.midchain.next_dpo));
adj_nbr_evaluate_feature (adj_get_index(adj));
return (adj);
diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h
index ea3ce0938de..ed869d1f768 100644
--- a/src/vnet/buffer.h
+++ b/src/vnet/buffer.h
@@ -130,6 +130,9 @@ typedef struct
/* Rewrite length */
u32 save_rewrite_length;
+
+ /* MFIB RPF ID */
+ u32 rpf_id;
};
/* ICMP */
diff --git a/src/vnet/devices/ssvm/node.c b/src/vnet/devices/ssvm/node.c
index 539b4161d7a..b7a8db0528c 100644
--- a/src/vnet/devices/ssvm/node.c
+++ b/src/vnet/devices/ssvm/node.c
@@ -210,7 +210,7 @@ ssvm_eth_device_input (ssvm_eth_main_t * em,
next0 = SSVM_ETH_INPUT_NEXT_IP4_INPUT;
else if (type0 == ETHERNET_TYPE_IP6)
next0 = SSVM_ETH_INPUT_NEXT_IP6_INPUT;
- else if (type0 == ETHERNET_TYPE_MPLS_UNICAST)
+ else if (type0 == ETHERNET_TYPE_MPLS)
next0 = SSVM_ETH_INPUT_NEXT_MPLS_INPUT;
l3_offset0 = ((next0 == SSVM_ETH_INPUT_NEXT_IP4_INPUT ||
diff --git a/src/vnet/dhcp/dhcp6_proxy_node.c b/src/vnet/dhcp/dhcp6_proxy_node.c
index 524cb095357..de73154dddb 100644
--- a/src/vnet/dhcp/dhcp6_proxy_node.c
+++ b/src/vnet/dhcp/dhcp6_proxy_node.c
@@ -883,6 +883,7 @@ dhcp6_proxy_set_server (ip46_address_t *addr,
mfib_table_entry_update(rx_fib_index,
&all_dhcp_servers,
MFIB_SOURCE_DHCP,
+ MFIB_RPF_ID_NONE,
MFIB_ENTRY_FLAG_ACCEPT_ALL_ITF);
mfib_table_lock(rx_fib_index, FIB_PROTOCOL_IP6);
}
diff --git a/src/vnet/dpo/dpo.c b/src/vnet/dpo/dpo.c
index d8e075a7f2f..dfc2bd923ce 100644
--- a/src/vnet/dpo/dpo.c
+++ b/src/vnet/dpo/dpo.c
@@ -37,6 +37,8 @@
#include <vnet/dpo/classify_dpo.h>
#include <vnet/dpo/ip_null_dpo.h>
#include <vnet/dpo/replicate_dpo.h>
+#include <vnet/dpo/interface_dpo.h>
+#include <vnet/dpo/mpls_disposition.h>
/**
* Array of char* names for the DPO types and protos
@@ -182,6 +184,12 @@ dpo_set (dpo_id_t *dpo,
case IP_LOOKUP_NEXT_MIDCHAIN:
dpo->dpoi_type = DPO_ADJACENCY_MIDCHAIN;
break;
+ case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
+ dpo->dpoi_type = DPO_ADJACENCY_MCAST_MIDCHAIN;
+ break;
+ case IP_LOOKUP_NEXT_MCAST:
+ dpo->dpoi_type = DPO_ADJACENCY_MCAST;
+ break;
default:
break;
}
@@ -453,6 +461,8 @@ dpo_module_init (vlib_main_t * vm)
lookup_dpo_module_init();
ip_null_dpo_module_init();
replicate_module_init();
+ interface_dpo_module_init();
+ mpls_disp_dpo_module_init();
return (NULL);
}
diff --git a/src/vnet/dpo/dpo.h b/src/vnet/dpo/dpo.h
index 48b92d3d3d6..5aa4e2d2165 100644
--- a/src/vnet/dpo/dpo.h
+++ b/src/vnet/dpo/dpo.h
@@ -108,12 +108,15 @@ typedef enum dpo_type_t_ {
DPO_ADJACENCY_MIDCHAIN,
DPO_ADJACENCY_GLEAN,
DPO_ADJACENCY_MCAST,
+ DPO_ADJACENCY_MCAST_MIDCHAIN,
DPO_RECEIVE,
DPO_LOOKUP,
DPO_LISP_CP,
DPO_CLASSIFY,
DPO_MPLS_LABEL,
+ DPO_MPLS_DISPOSITION,
DPO_MFIB_ENTRY,
+ DPO_INTERFACE,
DPO_LAST,
} __attribute__((packed)) dpo_type_t;
@@ -129,6 +132,7 @@ typedef enum dpo_type_t_ {
[DPO_ADJACENCY_MIDCHAIN] = "dpo-adjacency-midcahin", \
[DPO_ADJACENCY_GLEAN] = "dpo-glean", \
[DPO_ADJACENCY_MCAST] = "dpo-adj-mcast", \
+ [DPO_ADJACENCY_MCAST_MIDCHAIN] = "dpo-adj-mcast-midchain", \
[DPO_RECEIVE] = "dpo-receive", \
[DPO_LOOKUP] = "dpo-lookup", \
[DPO_LOAD_BALANCE] = "dpo-load-balance", \
@@ -136,7 +140,9 @@ typedef enum dpo_type_t_ {
[DPO_LISP_CP] = "dpo-lisp-cp", \
[DPO_CLASSIFY] = "dpo-classify", \
[DPO_MPLS_LABEL] = "dpo-mpls-label", \
- [DPO_MFIB_ENTRY] = "dpo-mfib_entry" \
+ [DPO_MPLS_DISPOSITION] = "dpo-mpls-diposition", \
+ [DPO_MFIB_ENTRY] = "dpo-mfib_entry", \
+ [DPO_INTERFACE] = "dpo-interface" \
}
/**
diff --git a/src/vnet/dpo/interface_dpo.c b/src/vnet/dpo/interface_dpo.c
new file mode 100644
index 00000000000..50ca756f9da
--- /dev/null
+++ b/src/vnet/dpo/interface_dpo.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/dpo/interface_dpo.h>
+#include <vnet/fib/fib_node.h>
+
+/*
+ * The 'DB' of interface DPOs.
+ * There is only one per-interface per-protocol, so this is a per-interface
+ * vector
+ */
+static index_t *interface_dpo_db[DPO_PROTO_NUM];
+
+static interface_dpo_t *
+interface_dpo_alloc (void)
+{
+ interface_dpo_t *ido;
+
+ pool_get(interface_dpo_pool, ido);
+
+ return (ido);
+}
+
+static inline interface_dpo_t *
+interface_dpo_get_from_dpo (const dpo_id_t *dpo)
+{
+ ASSERT(DPO_INTERFACE == dpo->dpoi_type);
+
+ return (interface_dpo_get(dpo->dpoi_index));
+}
+
+static inline index_t
+interface_dpo_get_index (interface_dpo_t *ido)
+{
+ return (ido - interface_dpo_pool);
+}
+
+static void
+interface_dpo_lock (dpo_id_t *dpo)
+{
+ interface_dpo_t *ido;
+
+ ido = interface_dpo_get_from_dpo(dpo);
+ ido->ido_locks++;
+}
+
+static void
+interface_dpo_unlock (dpo_id_t *dpo)
+{
+ interface_dpo_t *ido;
+
+ ido = interface_dpo_get_from_dpo(dpo);
+ ido->ido_locks--;
+
+ if (0 == ido->ido_locks)
+ {
+ interface_dpo_db[ido->ido_proto][ido->ido_sw_if_index] =
+ INDEX_INVALID;
+ pool_put(interface_dpo_pool, ido);
+ }
+}
+
+/*
+ * interface_dpo_add_or_lock
+ *
+ * Add/create and lock a new or lock an existing for the interface DPO
+ * on the interface and protocol given
+ */
+void
+interface_dpo_add_or_lock (dpo_proto_t proto,
+ u32 sw_if_index,
+ dpo_id_t *dpo)
+{
+ interface_dpo_t *ido;
+
+ vec_validate_init_empty(interface_dpo_db[proto],
+ sw_if_index,
+ INDEX_INVALID);
+
+ if (INDEX_INVALID == interface_dpo_db[proto][sw_if_index])
+ {
+ ido = interface_dpo_alloc();
+
+ ido->ido_sw_if_index = sw_if_index;
+ ido->ido_proto = proto;
+
+ interface_dpo_db[proto][sw_if_index] =
+ interface_dpo_get_index(ido);
+ }
+ else
+ {
+ ido = interface_dpo_get(interface_dpo_db[proto][sw_if_index]);
+ }
+
+ dpo_set(dpo, DPO_INTERFACE, proto, interface_dpo_get_index(ido));
+}
+
+
+static clib_error_t *
+interface_dpo_interface_state_change (vnet_main_t * vnm,
+ u32 sw_if_index,
+ u32 flags)
+{
+ /*
+ */
+ return (NULL);
+}
+
+VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(
+ interface_dpo_interface_state_change);
+
+/**
+ * @brief Registered callback for HW interface state changes
+ */
+static clib_error_t *
+interface_dpo_hw_interface_state_change (vnet_main_t * vnm,
+ u32 hw_if_index,
+ u32 flags)
+{
+ return (NULL);
+}
+
+VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION(
+ interface_dpo_hw_interface_state_change);
+
+static clib_error_t *
+interface_dpo_interface_delete (vnet_main_t * vnm,
+ u32 sw_if_index,
+ u32 is_add)
+{
+ return (NULL);
+}
+
+VNET_SW_INTERFACE_ADD_DEL_FUNCTION(
+ interface_dpo_interface_delete);
+
+u8*
+format_interface_dpo (u8* s, va_list *ap)
+{
+ index_t index = va_arg(*ap, index_t);
+ CLIB_UNUSED(u32 indent) = va_arg(*ap, u32);
+ vnet_main_t * vnm = vnet_get_main();
+ interface_dpo_t *ido = interface_dpo_get(index);
+
+ return (format(s, "%U-dpo: %U",
+ format_vnet_sw_interface_name,
+ vnm,
+ vnet_get_sw_interface(vnm, ido->ido_sw_if_index),
+ format_dpo_proto, ido->ido_proto));
+}
+
+static void
+interface_dpo_mem_show (void)
+{
+ fib_show_memory_usage("Interface",
+ pool_elts(interface_dpo_pool),
+ pool_len(interface_dpo_pool),
+ sizeof(interface_dpo_t));
+}
+
+
+const static dpo_vft_t interface_dpo_vft = {
+ .dv_lock = interface_dpo_lock,
+ .dv_unlock = interface_dpo_unlock,
+ .dv_format = format_interface_dpo,
+ .dv_mem_show = interface_dpo_mem_show,
+};
+
+/**
+ * @brief The per-protocol VLIB graph nodes that are assigned to a glean
+ * object.
+ *
+ * this means that these graph nodes are ones from which a glean is the
+ * parent object in the DPO-graph.
+ */
+const static char* const interface_dpo_ip4_nodes[] =
+{
+ "interface-dpo-ip4",
+ NULL,
+};
+const static char* const interface_dpo_ip6_nodes[] =
+{
+ "interface-dpo-ip4",
+ NULL,
+};
+
+const static char* const * const interface_dpo_nodes[DPO_PROTO_NUM] =
+{
+ [DPO_PROTO_IP4] = interface_dpo_ip4_nodes,
+ [DPO_PROTO_IP6] = interface_dpo_ip6_nodes,
+ [DPO_PROTO_MPLS] = NULL,
+};
+
+void
+interface_dpo_module_init (void)
+{
+ dpo_register(DPO_INTERFACE,
+ &interface_dpo_vft,
+ interface_dpo_nodes);
+}
+
+/**
+ * @brief Interface DPO trace data
+ */
+typedef struct interface_dpo_trace_t_
+{
+ u32 sw_if_index;
+} interface_dpo_trace_t;
+
+typedef enum interface_dpo_next_t_
+{
+ INTERFACE_DPO_DROP = 0,
+ INTERFACE_DPO_INPUT = 1,
+} interface_dpo_next_t;
+
+always_inline uword
+interface_dpo_inline (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame)
+{
+ u32 n_left_from, next_index, * from, * to_next;
+ u32 cpu_index = os_get_cpu_number();
+ vnet_interface_main_t *im;
+
+ im = &vnet_get_main ()->interface_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 >= 4 && n_left_to_next > 2)
+ {
+ const interface_dpo_t *ido0, *ido1;
+ u32 bi0, idoi0, bi1, idoi1;
+ vlib_buffer_t *b0, *b1;
+
+ bi0 = from[0];
+ to_next[0] = bi0;
+ bi1 = from[1];
+ to_next[1] = bi1;
+ from += 2;
+ to_next += 2;
+ n_left_from -= 2;
+ n_left_to_next -= 2;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ b1 = vlib_get_buffer (vm, bi1);
+
+ idoi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+ idoi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
+ ido0 = interface_dpo_get(idoi0);
+ ido1 = interface_dpo_get(idoi1);
+
+ vnet_buffer(b0)->sw_if_index[VLIB_RX] = ido0->ido_sw_if_index;
+ vnet_buffer(b1)->sw_if_index[VLIB_RX] = ido1->ido_sw_if_index;
+
+ vlib_increment_combined_counter (im->combined_sw_if_counters
+ + VNET_INTERFACE_COUNTER_RX,
+ cpu_index,
+ ido0->ido_sw_if_index,
+ 1,
+ vlib_buffer_length_in_chain (vm, b0));
+ vlib_increment_combined_counter (im->combined_sw_if_counters
+ + VNET_INTERFACE_COUNTER_RX,
+ cpu_index,
+ ido1->ido_sw_if_index,
+ 1,
+ vlib_buffer_length_in_chain (vm, b1));
+
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ interface_dpo_trace_t *tr0;
+
+ tr0 = vlib_add_trace (vm, node, b0, sizeof (*tr0));
+ tr0->sw_if_index = ido0->ido_sw_if_index;
+ }
+ if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ interface_dpo_trace_t *tr1;
+
+ tr1 = vlib_add_trace (vm, node, b1, sizeof (*tr1));
+ tr1->sw_if_index = ido1->ido_sw_if_index;
+ }
+
+ vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
+ n_left_to_next, bi0, bi1,
+ INTERFACE_DPO_INPUT,
+ INTERFACE_DPO_INPUT);
+ }
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ const interface_dpo_t * ido0;
+ vlib_buffer_t * b0;
+ u32 bi0, idoi0;
+
+ 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);
+
+ idoi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+ ido0 = interface_dpo_get(idoi0);
+
+ /* Swap the RX interface of the packet to the one the
+ * interface DPR represents */
+ vnet_buffer(b0)->sw_if_index[VLIB_RX] = ido0->ido_sw_if_index;
+
+ /* Bump the interface's RX coutners */
+ vlib_increment_combined_counter (im->combined_sw_if_counters
+ + VNET_INTERFACE_COUNTER_RX,
+ cpu_index,
+ ido0->ido_sw_if_index,
+ 1,
+ vlib_buffer_length_in_chain (vm, b0));
+
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ interface_dpo_trace_t *tr;
+
+ tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
+ tr->sw_if_index = ido0->ido_sw_if_index;
+ }
+
+ vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
+ n_left_to_next, bi0,
+ INTERFACE_DPO_INPUT);
+ }
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ }
+ return from_frame->n_vectors;
+}
+
+static u8 *
+format_interface_dpo_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 *);
+ interface_dpo_trace_t * t = va_arg (*args, interface_dpo_trace_t *);
+ uword indent = format_get_indent (s);
+ s = format (s, "%U sw_if_index:%d",
+ format_white_space, indent,
+ t->sw_if_index);
+ return s;
+}
+
+static uword
+interface_dpo_ip4 (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame)
+{
+ return (interface_dpo_inline(vm, node, from_frame));
+}
+
+static uword
+interface_dpo_ip6 (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame)
+{
+ return (interface_dpo_inline(vm, node, from_frame));
+}
+
+VLIB_REGISTER_NODE (interface_dpo_ip4_node) = {
+ .function = interface_dpo_ip4,
+ .name = "interface-dpo-ip4",
+ .vector_size = sizeof (u32),
+ .format_trace = format_interface_dpo_trace,
+
+ .n_next_nodes = 2,
+ .next_nodes = {
+ [INTERFACE_DPO_DROP] = "ip4-drop",
+ [INTERFACE_DPO_INPUT] = "ip4-input",
+ },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (interface_dpo_ip4_node,
+ interface_dpo_ip4)
+
+VLIB_REGISTER_NODE (interface_dpo_ip6_node) = {
+ .function = interface_dpo_ip6,
+ .name = "interface-dpo-ip6",
+ .vector_size = sizeof (u32),
+ .format_trace = format_interface_dpo_trace,
+
+ .n_next_nodes = 2,
+ .next_nodes = {
+ [INTERFACE_DPO_DROP] = "ip6-drop",
+ [INTERFACE_DPO_INPUT] = "ip6-input",
+ },
+};
+
+VLIB_NODE_FUNCTION_MULTIARCH (interface_dpo_ip6_node,
+ interface_dpo_ip6)
+
diff --git a/src/vnet/dpo/interface_dpo.h b/src/vnet/dpo/interface_dpo.h
new file mode 100644
index 00000000000..1538dfbbf06
--- /dev/null
+++ b/src/vnet/dpo/interface_dpo.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @brief
+ * The data-path object representing interfaceing the packet, i.e. it's for-us
+ */
+
+#ifndef __INTERFACE_DPO_H__
+#define __INTERFACE_DPO_H__
+
+#include <vnet/dpo/dpo.h>
+
+typedef struct interface_dpo_t_
+{
+ /**
+ * The Software interface index that the packets will be given
+ * as the ingress/rx interface
+ */
+ u32 ido_sw_if_index;
+
+ /**
+ * next VLIB node. A '<proto>-input' node.
+ */
+ u32 ido_next_node;
+
+ /**
+ * DPO protocol that the packets will have as they 'ingress'
+ * on this interface
+ */
+ dpo_proto_t ido_proto;
+
+ /**
+ * number of locks.
+ */
+ u16 ido_locks;
+} interface_dpo_t;
+
+extern void interface_dpo_add_or_lock (dpo_proto_t proto,
+ u32 sw_if_index,
+ dpo_id_t *dpo);
+
+extern void interface_dpo_module_init(void);
+
+/**
+ * @brief pool of all interface DPOs
+ */
+interface_dpo_t *interface_dpo_pool;
+
+static inline interface_dpo_t *
+interface_dpo_get (index_t index)
+{
+ return (pool_elt_at_index(interface_dpo_pool, index));
+}
+
+#endif
diff --git a/src/vnet/dpo/lookup_dpo.c b/src/vnet/dpo/lookup_dpo.c
index 97ad0a44cce..e5b00a79e52 100644
--- a/src/vnet/dpo/lookup_dpo.c
+++ b/src/vnet/dpo/lookup_dpo.c
@@ -21,8 +21,12 @@
#include <vnet/fib/ip4_fib.h>
#include <vnet/fib/ip6_fib.h>
#include <vnet/fib/mpls_fib.h>
+#include <vnet/mfib/mfib_table.h>
+#include <vnet/mfib/ip4_mfib.h>
+#include <vnet/mfib/ip6_mfib.h>
static const char *const lookup_input_names[] = LOOKUP_INPUTS;
+static const char *const lookup_cast_names[] = LOOKUP_CASTS;
/**
* @brief Enumeration of the lookup subtypes
@@ -31,6 +35,7 @@ typedef enum lookup_sub_type_t_
{
LOOKUP_SUB_TYPE_SRC,
LOOKUP_SUB_TYPE_DST,
+ LOOKUP_SUB_TYPE_DST_MCAST,
LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE,
} lookup_sub_type_t;
#define LOOKUP_SUB_TYPE_NUM (LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE+1)
@@ -67,6 +72,7 @@ lookup_dpo_get_index (lookup_dpo_t *lkd)
static void
lookup_dpo_add_or_lock_i (fib_node_index_t fib_index,
dpo_proto_t proto,
+ lookup_cast_t cast,
lookup_input_t input,
lookup_table_t table_config,
dpo_id_t *dpo)
@@ -79,6 +85,7 @@ lookup_dpo_add_or_lock_i (fib_node_index_t fib_index,
lkd->lkd_proto = proto;
lkd->lkd_input = input;
lkd->lkd_table = table_config;
+ lkd->lkd_cast = cast;
/*
* use the input type to select the lookup sub-type
@@ -100,6 +107,10 @@ lookup_dpo_add_or_lock_i (fib_node_index_t fib_index,
type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST];
break;
}
+ if (LOOKUP_MULTICAST == cast)
+ {
+ type = lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_MCAST];
+ }
}
if (0 == type)
@@ -115,20 +126,29 @@ lookup_dpo_add_or_lock_i (fib_node_index_t fib_index,
void
lookup_dpo_add_or_lock_w_fib_index (fib_node_index_t fib_index,
dpo_proto_t proto,
+ lookup_cast_t cast,
lookup_input_t input,
lookup_table_t table_config,
dpo_id_t *dpo)
{
if (LOOKUP_TABLE_FROM_CONFIG == table_config)
{
- fib_table_lock(fib_index, dpo_proto_to_fib(proto));
+ if (LOOKUP_UNICAST == cast)
+ {
+ fib_table_lock(fib_index, dpo_proto_to_fib(proto));
+ }
+ else
+ {
+ mfib_table_lock(fib_index, dpo_proto_to_fib(proto));
+ }
}
- lookup_dpo_add_or_lock_i(fib_index, proto, input, table_config, dpo);
+ lookup_dpo_add_or_lock_i(fib_index, proto, cast, input, table_config, dpo);
}
void
lookup_dpo_add_or_lock_w_table_id (u32 table_id,
dpo_proto_t proto,
+ lookup_cast_t cast,
lookup_input_t input,
lookup_table_t table_config,
dpo_id_t *dpo)
@@ -137,13 +157,22 @@ lookup_dpo_add_or_lock_w_table_id (u32 table_id,
if (LOOKUP_TABLE_FROM_CONFIG == table_config)
{
- fib_index =
- fib_table_find_or_create_and_lock(dpo_proto_to_fib(proto),
- table_id);
+ if (LOOKUP_UNICAST == cast)
+ {
+ fib_index =
+ fib_table_find_or_create_and_lock(dpo_proto_to_fib(proto),
+ table_id);
+ }
+ else
+ {
+ fib_index =
+ mfib_table_find_or_create_and_lock(dpo_proto_to_fib(proto),
+ table_id);
+ }
}
ASSERT(FIB_NODE_INDEX_INVALID != fib_index);
- lookup_dpo_add_or_lock_i(fib_index, proto, input, table_config, dpo);
+ lookup_dpo_add_or_lock_i(fib_index, proto, cast, input, table_config, dpo);
}
u8*
@@ -156,16 +185,29 @@ format_lookup_dpo (u8 *s, va_list *args)
if (LOOKUP_TABLE_FROM_INPUT_INTERFACE == lkd->lkd_table)
{
- s = format(s, "%s lookup in interface's %U table",
+ s = format(s, "%s,%s lookup in interface's %U table",
lookup_input_names[lkd->lkd_input],
+ lookup_cast_names[lkd->lkd_cast],
format_dpo_proto, lkd->lkd_proto);
}
else
{
- s = format(s, "%s lookup in %U",
- lookup_input_names[lkd->lkd_input],
- format_fib_table_name, lkd->lkd_fib_index,
- dpo_proto_to_fib(lkd->lkd_proto));
+ if (LOOKUP_UNICAST == lkd->lkd_cast)
+ {
+ s = format(s, "%s,%s lookup in %U",
+ lookup_input_names[lkd->lkd_input],
+ lookup_cast_names[lkd->lkd_cast],
+ format_fib_table_name, lkd->lkd_fib_index,
+ dpo_proto_to_fib(lkd->lkd_proto));
+ }
+ else
+ {
+ s = format(s, "%s,%s lookup in %U",
+ lookup_input_names[lkd->lkd_input],
+ lookup_cast_names[lkd->lkd_cast],
+ format_mfib_table_name, lkd->lkd_fib_index,
+ dpo_proto_to_fib(lkd->lkd_proto));
+ }
}
return (s);
}
@@ -193,8 +235,16 @@ lookup_dpo_unlock (dpo_id_t *dpo)
{
if (LOOKUP_TABLE_FROM_CONFIG == lkd->lkd_table)
{
- fib_table_unlock(lkd->lkd_fib_index,
- dpo_proto_to_fib(lkd->lkd_proto));
+ if (LOOKUP_UNICAST == lkd->lkd_cast)
+ {
+ fib_table_unlock(lkd->lkd_fib_index,
+ dpo_proto_to_fib(lkd->lkd_proto));
+ }
+ else
+ {
+ mfib_table_unlock(lkd->lkd_fib_index,
+ dpo_proto_to_fib(lkd->lkd_proto));
+ }
}
pool_put(lookup_dpo_pool, lkd);
}
@@ -1069,6 +1119,123 @@ VLIB_REGISTER_NODE (lookup_mpls_dst_itf_node) = {
};
VLIB_NODE_FUNCTION_MULTIARCH (lookup_mpls_dst_itf_node, lookup_mpls_dst_itf)
+typedef enum lookup_ip_dst_mcast_next_t_ {
+ LOOKUP_IP_DST_MCAST_NEXT_RPF,
+ LOOKUP_IP_DST_MCAST_N_NEXT,
+} mfib_forward_lookup_next_t;
+
+always_inline uword
+lookup_dpo_ip_dst_mcast_inline (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame,
+ int is_v4)
+{
+ u32 n_left_from, next_index, * from, * to_next;
+
+ from = vlib_frame_vector_args (from_frame);
+ n_left_from = from_frame->n_vectors;
+
+ next_index = LOOKUP_IP_DST_MCAST_NEXT_RPF;
+
+ 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 >= 4 && n_left_to_next >= 2) */
+ /* } */
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0, lkdi0, fib_index0, next0;
+ const lookup_dpo_t * lkd0;
+ fib_node_index_t mfei0;
+ vlib_buffer_t * b0;
+
+ 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);
+
+ /* dst lookup was done by mpls lookup */
+ lkdi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+ lkd0 = lookup_dpo_get(lkdi0);
+ fib_index0 = lkd0->lkd_fib_index;
+ next0 = LOOKUP_IP_DST_MCAST_NEXT_RPF;
+
+ if (is_v4)
+ {
+ ip4_header_t * ip0;
+
+ ip0 = vlib_buffer_get_current (b0);
+ mfei0 = ip4_mfib_table_lookup(ip4_mfib_get(fib_index0),
+ &ip0->src_address,
+ &ip0->dst_address,
+ 64);
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ lookup_trace_t *tr = vlib_add_trace (vm, node,
+ b0, sizeof (*tr));
+ tr->fib_index = fib_index0;
+ tr->lbi = mfei0;
+ tr->addr.ip4 = ip0->dst_address;
+ }
+ }
+ else
+ {
+ ip6_header_t * ip0;
+
+ ip0 = vlib_buffer_get_current (b0);
+ mfei0 = ip6_mfib_table_lookup2(ip6_mfib_get(fib_index0),
+ &ip0->src_address,
+ &ip0->dst_address);
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ lookup_trace_t *tr = vlib_add_trace (vm, node,
+ b0, sizeof (*tr));
+ tr->fib_index = fib_index0;
+ tr->lbi = mfei0;
+ tr->addr.ip6 = ip0->dst_address;
+ }
+ }
+
+ vnet_buffer (b0)->ip.adj_index[VLIB_TX] = mfei0;
+
+ 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;
+}
+
+always_inline uword
+lookup_ip4_dst_mcast (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame)
+{
+ return (lookup_dpo_ip_dst_mcast_inline(vm, node, from_frame, 1));
+}
+
+VLIB_REGISTER_NODE (lookup_ip4_dst_mcast_node) = {
+ .function = lookup_ip4_dst_mcast,
+ .name = "lookup-ip4-dst-mcast",
+ .vector_size = sizeof (u32),
+
+ .format_trace = format_lookup_trace,
+ .n_next_nodes = LOOKUP_IP_DST_MCAST_N_NEXT,
+ .next_nodes = {
+ [LOOKUP_IP_DST_MCAST_NEXT_RPF] = "ip4-mfib-forward-rpf",
+ },
+};
+VLIB_NODE_FUNCTION_MULTIARCH (lookup_ip4_dst_mcast_node,
+ lookup_ip4_dst_mcast)
+
static void
lookup_dpo_mem_show (void)
{
@@ -1129,6 +1296,22 @@ const static char* const * const lookup_dst_nodes[DPO_PROTO_NUM] =
[DPO_PROTO_MPLS] = lookup_dst_mpls_nodes,
};
+const static char* const lookup_dst_mcast_ip4_nodes[] =
+{
+ "lookup-ip4-dst-mcast",
+ NULL,
+};
+const static char* const lookup_dst_mcast_ip6_nodes[] =
+{
+ "lookup-ip6-dst-mcast",
+ NULL,
+};
+const static char* const * const lookup_dst_mcast_nodes[DPO_PROTO_NUM] =
+{
+ [DPO_PROTO_IP4] = lookup_dst_mcast_ip4_nodes,
+ [DPO_PROTO_IP6] = lookup_dst_mcast_ip6_nodes,
+};
+
const static char* const lookup_dst_from_interface_ip4_nodes[] =
{
"lookup-ip4-dst-itf",
@@ -1168,6 +1351,8 @@ lookup_dpo_module_init (void)
dpo_register_new_type(&lkd_vft, lookup_src_nodes);
lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST] =
dpo_register_new_type(&lkd_vft, lookup_dst_nodes);
+ lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_MCAST] =
+ dpo_register_new_type(&lkd_vft, lookup_dst_mcast_nodes);
lookup_dpo_sub_types[LOOKUP_SUB_TYPE_DST_TABLE_FROM_INTERFACE] =
dpo_register_new_type(&lkd_vft, lookup_dst_from_interface_nodes);
}
diff --git a/src/vnet/dpo/lookup_dpo.h b/src/vnet/dpo/lookup_dpo.h
index ff283388868..7dfd0385a9d 100644
--- a/src/vnet/dpo/lookup_dpo.h
+++ b/src/vnet/dpo/lookup_dpo.h
@@ -47,6 +47,19 @@ typedef enum lookup_table_t_ {
}
/**
+ * Switch to use the packet's source or destination address for lookup
+ */
+typedef enum lookup_cast_t_ {
+ LOOKUP_UNICAST,
+ LOOKUP_MULTICAST,
+} __attribute__ ((packed)) lookup_cast_t;
+
+#define LOOKUP_CASTS { \
+ [LOOKUP_UNICAST] = "unicast", \
+ [LOOKUP_MULTICAST] = "multicast", \
+}
+
+/**
* A representation of an MPLS label for imposition in the data-path
*/
typedef struct lookup_dpo_t
@@ -74,6 +87,11 @@ typedef struct lookup_dpo_t
lookup_table_t lkd_table;
/**
+ * Unicast of rmulticast FIB lookup
+ */
+ lookup_cast_t lkd_cast;
+
+ /**
* Number of locks
*/
u16 lkd_locks;
@@ -81,11 +99,13 @@ typedef struct lookup_dpo_t
extern void lookup_dpo_add_or_lock_w_fib_index(fib_node_index_t fib_index,
dpo_proto_t proto,
+ lookup_cast_t cast,
lookup_input_t input,
lookup_table_t table,
dpo_id_t *dpo);
extern void lookup_dpo_add_or_lock_w_table_id(u32 table_id,
dpo_proto_t proto,
+ lookup_cast_t cast,
lookup_input_t input,
lookup_table_t table,
dpo_id_t *dpo);
diff --git a/src/vnet/dpo/mpls_disposition.c b/src/vnet/dpo/mpls_disposition.c
new file mode 100644
index 00000000000..5dc33fcfdbd
--- /dev/null
+++ b/src/vnet/dpo/mpls_disposition.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/ip/ip.h>
+#include <vnet/dpo/mpls_disposition.h>
+#include <vnet/mpls/mpls.h>
+
+/*
+ * pool of all MPLS Label DPOs
+ */
+mpls_disp_dpo_t *mpls_disp_dpo_pool;
+
+static mpls_disp_dpo_t *
+mpls_disp_dpo_alloc (void)
+{
+ mpls_disp_dpo_t *mdd;
+
+ pool_get_aligned(mpls_disp_dpo_pool, mdd, CLIB_CACHE_LINE_BYTES);
+ memset(mdd, 0, sizeof(*mdd));
+
+ dpo_reset(&mdd->mdd_dpo);
+
+ return (mdd);
+}
+
+static index_t
+mpls_disp_dpo_get_index (mpls_disp_dpo_t *mdd)
+{
+ return (mdd - mpls_disp_dpo_pool);
+}
+
+index_t
+mpls_disp_dpo_create (dpo_proto_t payload_proto,
+ fib_rpf_id_t rpf_id,
+ const dpo_id_t *dpo)
+{
+ mpls_disp_dpo_t *mdd;
+
+ mdd = mpls_disp_dpo_alloc();
+
+ mdd->mdd_payload_proto = payload_proto;
+ mdd->mdd_rpf_id = rpf_id;
+
+ dpo_stack(DPO_MPLS_DISPOSITION,
+ mdd->mdd_payload_proto,
+ &mdd->mdd_dpo,
+ dpo);
+
+ return (mpls_disp_dpo_get_index(mdd));
+}
+
+u8*
+format_mpls_disp_dpo (u8 *s, va_list *args)
+{
+ index_t index = va_arg (*args, index_t);
+ u32 indent = va_arg (*args, u32);
+ mpls_disp_dpo_t *mdd;
+
+ mdd = mpls_disp_dpo_get(index);
+
+ s = format(s, "mpls-disposition:[%d]:[%U]",
+ index,
+ format_dpo_proto, mdd->mdd_payload_proto);
+
+ s = format(s, "\n%U", format_white_space, indent);
+ s = format(s, "%U", format_dpo_id, &mdd->mdd_dpo, indent+2);
+
+ return (s);
+}
+
+static void
+mpls_disp_dpo_lock (dpo_id_t *dpo)
+{
+ mpls_disp_dpo_t *mdd;
+
+ mdd = mpls_disp_dpo_get(dpo->dpoi_index);
+
+ mdd->mdd_locks++;
+}
+
+static void
+mpls_disp_dpo_unlock (dpo_id_t *dpo)
+{
+ mpls_disp_dpo_t *mdd;
+
+ mdd = mpls_disp_dpo_get(dpo->dpoi_index);
+
+ mdd->mdd_locks--;
+
+ if (0 == mdd->mdd_locks)
+ {
+ dpo_reset(&mdd->mdd_dpo);
+ pool_put(mpls_disp_dpo_pool, mdd);
+ }
+}
+
+/**
+ * @brief A struct to hold tracing information for the MPLS label disposition
+ * node.
+ */
+typedef struct mpls_label_disposition_trace_t_
+{
+ index_t mdd;
+} mpls_label_disposition_trace_t;
+
+always_inline uword
+mpls_label_disposition_inline (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame,
+ u8 payload_is_ip4,
+ u8 payload_is_ip6)
+{
+ u32 n_left_from, next_index, * from, * to_next;
+
+ 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 >= 4 && n_left_to_next >= 2)
+ {
+ mpls_disp_dpo_t *mdd0, *mdd1;
+ u32 bi0, mddi0, bi1, mddi1;
+ vlib_buffer_t * b0, *b1;
+ u32 next0, next1;
+
+ bi0 = to_next[0] = from[0];
+ bi1 = to_next[1] = from[1];
+
+ /* Prefetch next iteration. */
+ {
+ vlib_buffer_t * p2, * p3;
+
+ p2 = vlib_get_buffer (vm, from[2]);
+ p3 = vlib_get_buffer (vm, from[3]);
+
+ vlib_prefetch_buffer_header (p2, STORE);
+ vlib_prefetch_buffer_header (p3, STORE);
+
+ CLIB_PREFETCH (p2->data, sizeof (ip6_header_t), STORE);
+ CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), STORE);
+ }
+
+ from += 2;
+ to_next += 2;
+ n_left_from -= 2;
+ n_left_to_next -= 2;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ b1 = vlib_get_buffer (vm, bi1);
+
+ /* dst lookup was done by ip4 lookup */
+ mddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+ mddi1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
+ mdd0 = mpls_disp_dpo_get(mddi0);
+ mdd1 = mpls_disp_dpo_get(mddi1);
+
+ if (payload_is_ip4)
+ {
+ /*
+ * decrement the TTL on ingress to the LSP
+ */
+ }
+ else if (payload_is_ip6)
+ {
+ /*
+ * decrement the TTL on ingress to the LSP
+ */
+ }
+
+ next0 = mdd0->mdd_dpo.dpoi_next_node;
+ next1 = mdd1->mdd_dpo.dpoi_next_node;
+ vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mdd0->mdd_dpo.dpoi_index;
+ vnet_buffer(b1)->ip.adj_index[VLIB_TX] = mdd1->mdd_dpo.dpoi_index;
+ vnet_buffer(b0)->ip.rpf_id = mdd0->mdd_rpf_id;
+ vnet_buffer(b1)->ip.rpf_id = mdd1->mdd_rpf_id;
+
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ mpls_label_disposition_trace_t *tr =
+ vlib_add_trace (vm, node, b0, sizeof (*tr));
+
+ tr->mdd = mddi0;
+ }
+ if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ mpls_label_disposition_trace_t *tr =
+ vlib_add_trace (vm, node, b1, sizeof (*tr));
+ tr->mdd = mddi1;
+ }
+
+ vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
+ n_left_to_next,
+ bi0, bi1, next0, next1);
+ }
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ mpls_disp_dpo_t *mdd0;
+ vlib_buffer_t * b0;
+ u32 bi0, mddi0;
+ u32 next0;
+
+ 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);
+
+ /* dst lookup was done by ip4 lookup */
+ mddi0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
+ mdd0 = mpls_disp_dpo_get(mddi0);
+
+ if (payload_is_ip4)
+ {
+ /*
+ * decrement the TTL on ingress to the LSP
+ */
+ }
+ else if (payload_is_ip6)
+ {
+ /*
+ * decrement the TTL on ingress to the LSP
+ */
+ }
+ else
+ {
+ }
+
+ next0 = mdd0->mdd_dpo.dpoi_next_node;
+ vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mdd0->mdd_dpo.dpoi_index;
+ vnet_buffer(b0)->ip.rpf_id = mdd0->mdd_rpf_id;
+
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ mpls_label_disposition_trace_t *tr =
+ vlib_add_trace (vm, node, b0, sizeof (*tr));
+ tr->mdd = mddi0;
+ }
+
+ 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_mpls_label_disposition_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 *);
+ CLIB_UNUSED (mpls_label_disposition_trace_t * t);
+
+ t = va_arg (*args, mpls_label_disposition_trace_t *);
+
+ s = format(s, "disp:%d", t->mdd);
+ return (s);
+}
+
+static uword
+ip4_mpls_label_disposition (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return (mpls_label_disposition_inline(vm, node, frame, 1, 0));
+}
+
+VLIB_REGISTER_NODE (ip4_mpls_label_disposition_node) = {
+ .function = ip4_mpls_label_disposition,
+ .name = "ip4-mpls-label-disposition",
+ .vector_size = sizeof (u32),
+
+ .format_trace = format_mpls_label_disposition_trace,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [0] = "ip4-drop",
+ }
+};
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_mpls_label_disposition_node,
+ ip4_mpls_label_disposition)
+
+static uword
+ip6_mpls_label_disposition (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return (mpls_label_disposition_inline(vm, node, frame, 0, 1));
+}
+
+VLIB_REGISTER_NODE (ip6_mpls_label_disposition_node) = {
+ .function = ip6_mpls_label_disposition,
+ .name = "ip6-mpls-label-disposition",
+ .vector_size = sizeof (u32),
+
+ .format_trace = format_mpls_label_disposition_trace,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [0] = "ip6-drop",
+ }
+};
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_disposition_node,
+ ip6_mpls_label_disposition)
+
+static void
+mpls_disp_dpo_mem_show (void)
+{
+ fib_show_memory_usage("MPLS label",
+ pool_elts(mpls_disp_dpo_pool),
+ pool_len(mpls_disp_dpo_pool),
+ sizeof(mpls_disp_dpo_t));
+}
+
+const static dpo_vft_t mdd_vft = {
+ .dv_lock = mpls_disp_dpo_lock,
+ .dv_unlock = mpls_disp_dpo_unlock,
+ .dv_format = format_mpls_disp_dpo,
+ .dv_mem_show = mpls_disp_dpo_mem_show,
+};
+
+const static char* const mpls_label_disp_ip4_nodes[] =
+{
+ "ip4-mpls-label-disposition",
+ NULL,
+};
+const static char* const mpls_label_disp_ip6_nodes[] =
+{
+ "ip6-mpls-label-disposition",
+ NULL,
+};
+const static char* const * const mpls_label_disp_nodes[DPO_PROTO_NUM] =
+{
+ [DPO_PROTO_IP4] = mpls_label_disp_ip4_nodes,
+ [DPO_PROTO_IP6] = mpls_label_disp_ip6_nodes,
+};
+
+
+void
+mpls_disp_dpo_module_init (void)
+{
+ dpo_register(DPO_MPLS_DISPOSITION, &mdd_vft, mpls_label_disp_nodes);
+}
diff --git a/src/vnet/dpo/mpls_disposition.h b/src/vnet/dpo/mpls_disposition.h
new file mode 100644
index 00000000000..9c0150830d2
--- /dev/null
+++ b/src/vnet/dpo/mpls_disposition.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MPLS_DISP_DPO_H__
+#define __MPLS_DISP_DPO_H__
+
+#include <vnet/vnet.h>
+#include <vnet/mpls/packet.h>
+#include <vnet/dpo/dpo.h>
+#include <vnet/mfib/mfib_types.h>
+
+/**
+ * A representation of an MPLS label for imposition in the data-path
+ */
+typedef struct mpls_disp_dpo_t
+{
+ /**
+ * Next DPO in the graph
+ */
+ dpo_id_t mdd_dpo;
+
+ /**
+ * The protocol of the payload/packets that are being encapped
+ */
+ dpo_proto_t mdd_payload_proto;
+
+ /**
+ * RPF-ID (if this is an mcast disposition)
+ */
+ fib_rpf_id_t mdd_rpf_id;
+
+ /**
+ * Number of locks/users of the label
+ */
+ u16 mdd_locks;
+} mpls_disp_dpo_t;
+
+/**
+ * @brief Assert that the MPLS label object is less than a cache line in size.
+ * Should this get any bigger then we will need to reconsider how many labels
+ * can be pushed in one object.
+ */
+_Static_assert((sizeof(mpls_disp_dpo_t) <= CLIB_CACHE_LINE_BYTES),
+ "MPLS Disposition DPO is larger than one cache line.");
+
+/**
+ * @brief Create an MPLS label object
+ *
+ * @param payload_proto The ptocool of the payload packets that will
+ * be imposed with this label header.
+ * @param dpo The parent of the created MPLS label object
+ */
+extern index_t mpls_disp_dpo_create(dpo_proto_t payload_proto,
+ fib_rpf_id_t rpf_id,
+ const dpo_id_t *dpo);
+
+extern u8* format_mpls_disp_dpo(u8 *s, va_list *args);
+
+
+/*
+ * Encapsulation violation for fast data-path access
+ */
+extern mpls_disp_dpo_t *mpls_disp_dpo_pool;
+
+static inline mpls_disp_dpo_t *
+mpls_disp_dpo_get (index_t index)
+{
+ return (pool_elt_at_index(mpls_disp_dpo_pool, index));
+}
+
+extern void mpls_disp_dpo_module_init(void);
+
+#endif
diff --git a/src/vnet/dpo/mpls_label_dpo.c b/src/vnet/dpo/mpls_label_dpo.c
index be9b28507ba..4d84b9001ce 100644
--- a/src/vnet/dpo/mpls_label_dpo.c
+++ b/src/vnet/dpo/mpls_label_dpo.c
@@ -562,7 +562,7 @@ VLIB_REGISTER_NODE (mpls_label_imposition_node) = {
.format_trace = format_mpls_label_imposition_trace,
.n_next_nodes = 1,
.next_nodes = {
- [0] = "error-drop",
+ [0] = "mpls-drop",
}
};
VLIB_NODE_FUNCTION_MULTIARCH (mpls_label_imposition_node,
@@ -584,7 +584,7 @@ VLIB_REGISTER_NODE (ip4_mpls_label_imposition_node) = {
.format_trace = format_mpls_label_imposition_trace,
.n_next_nodes = 1,
.next_nodes = {
- [0] = "error-drop",
+ [0] = "ip4-drop",
}
};
VLIB_NODE_FUNCTION_MULTIARCH (ip4_mpls_label_imposition_node,
@@ -606,7 +606,7 @@ VLIB_REGISTER_NODE (ip6_mpls_label_imposition_node) = {
.format_trace = format_mpls_label_imposition_trace,
.n_next_nodes = 1,
.next_nodes = {
- [0] = "error-drop",
+ [0] = "ip6-drop",
}
};
VLIB_NODE_FUNCTION_MULTIARCH (ip6_mpls_label_imposition_node,
diff --git a/src/vnet/dpo/replicate_dpo.c b/src/vnet/dpo/replicate_dpo.c
index e25ceae91fe..9fdb9a05071 100644
--- a/src/vnet/dpo/replicate_dpo.c
+++ b/src/vnet/dpo/replicate_dpo.c
@@ -17,6 +17,7 @@
#include <vnet/dpo/replicate_dpo.h>
#include <vnet/dpo/drop_dpo.h>
#include <vnet/adj/adj.h>
+#include <vnet/mpls/mpls_types.h>
#undef REP_DEBUG
@@ -106,6 +107,7 @@ replicate_format (index_t repi,
dpo_id_t *buckets;
u32 i;
+ repi &= ~MPLS_IS_REPLICATE;
rep = replicate_get(repi);
vlib_get_combined_counter(&(replicate_main.repm_counters), repi, &to);
buckets = replicate_get_buckets(rep);
@@ -187,6 +189,7 @@ replicate_set_bucket (index_t repi,
replicate_t *rep;
dpo_id_t *buckets;
+ repi &= ~MPLS_IS_REPLICATE;
rep = replicate_get(repi);
buckets = replicate_get_buckets(rep);
@@ -199,11 +202,13 @@ int
replicate_is_drop (const dpo_id_t *dpo)
{
replicate_t *rep;
+ index_t repi;
if (DPO_REPLICATE != dpo->dpoi_type)
return (0);
- rep = replicate_get(dpo->dpoi_index);
+ repi = dpo->dpoi_index & ~MPLS_IS_REPLICATE;
+ rep = replicate_get(repi);
if (1 == rep->rep_n_buckets)
{
@@ -218,6 +223,7 @@ replicate_get_bucket (index_t repi,
{
replicate_t *rep;
+ repi &= ~MPLS_IS_REPLICATE;
rep = replicate_get(repi);
return (replicate_get_bucket_i(rep, bucket));
@@ -288,9 +294,11 @@ replicate_multipath_update (const dpo_id_t *dpo,
dpo_id_t *tmp_dpo;
u32 ii, n_buckets;
replicate_t *rep;
+ index_t repi;
ASSERT(DPO_REPLICATE == dpo->dpoi_type);
- rep = replicate_get(dpo->dpoi_index);
+ repi = dpo->dpoi_index & ~MPLS_IS_REPLICATE;
+ rep = replicate_get(repi);
nhs = replicate_multipath_next_hop_fixup(next_hops,
rep->rep_proto);
n_buckets = vec_len(nhs);
@@ -718,7 +726,7 @@ format_replicate_trace (u8 * s, va_list * args)
s = format (s, "replicate: %d via %U",
t->rep_index,
- format_dpo_id, &t->dpo);
+ format_dpo_id, &t->dpo, 0);
return s;
}
@@ -731,7 +739,7 @@ ip4_replicate (vlib_main_t * vm,
}
/**
- * @brief
+ * @brief IP4 replication node
*/
VLIB_REGISTER_NODE (ip4_replicate_node) = {
.function = ip4_replicate,
@@ -744,7 +752,7 @@ VLIB_REGISTER_NODE (ip4_replicate_node) = {
.format_trace = format_replicate_trace,
.n_next_nodes = 1,
.next_nodes = {
- [0] = "error-drop",
+ [0] = "ip4-drop",
},
};
@@ -757,7 +765,7 @@ ip6_replicate (vlib_main_t * vm,
}
/**
- * @brief
+ * @brief IPv6 replication node
*/
VLIB_REGISTER_NODE (ip6_replicate_node) = {
.function = ip6_replicate,
@@ -770,7 +778,33 @@ VLIB_REGISTER_NODE (ip6_replicate_node) = {
.format_trace = format_replicate_trace,
.n_next_nodes = 1,
.next_nodes = {
- [0] = "error-drop",
+ [0] = "ip6-drop",
+ },
+};
+
+static uword
+mpls_replicate (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return (replicate_inline (vm, node, frame));
+}
+
+/**
+ * @brief MPLS replication node
+ */
+VLIB_REGISTER_NODE (mpls_replicate_node) = {
+ .function = mpls_replicate,
+ .name = "mpls-replicate",
+ .vector_size = sizeof (u32),
+
+ .n_errors = ARRAY_LEN(replicate_dpo_error_strings),
+ .error_strings = replicate_dpo_error_strings,
+
+ .format_trace = format_replicate_trace,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [0] = "mpls-drop",
},
};
diff --git a/src/vnet/dpo/replicate_dpo.h b/src/vnet/dpo/replicate_dpo.h
index 77273015c9e..7383184a2ea 100644
--- a/src/vnet/dpo/replicate_dpo.h
+++ b/src/vnet/dpo/replicate_dpo.h
@@ -25,6 +25,7 @@
#include <vnet/dpo/dpo.h>
#include <vnet/dpo/load_balance.h>
#include <vnet/fib/fib_types.h>
+#include <vnet/mpls/mpls_types.h>
/**
* replicate main
@@ -119,6 +120,7 @@ extern replicate_t *replicate_pool;
static inline replicate_t*
replicate_get (index_t repi)
{
+ repi &= ~MPLS_IS_REPLICATE;
return (pool_elt_at_index(replicate_pool, repi));
}
diff --git a/src/vnet/ethernet/arp.c b/src/vnet/ethernet/arp.c
index c74a097ec79..dd509193386 100644
--- a/src/vnet/ethernet/arp.c
+++ b/src/vnet/ethernet/arp.c
@@ -507,6 +507,7 @@ arp_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
case IP_LOOKUP_NEXT_PUNT:
case IP_LOOKUP_NEXT_LOCAL:
case IP_LOOKUP_NEXT_REWRITE:
+ case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
case IP_LOOKUP_NEXT_MIDCHAIN:
case IP_LOOKUP_NEXT_ICMP_ERROR:
case IP_LOOKUP_N_NEXT:
diff --git a/src/vnet/ethernet/interface.c b/src/vnet/ethernet/interface.c
index 335e3f9f270..9ac30bc6652 100644
--- a/src/vnet/ethernet/interface.c
+++ b/src/vnet/ethernet/interface.c
@@ -115,7 +115,7 @@ ethernet_build_rewrite (vnet_main_t * vnm,
#define _(a,b) case VNET_LINK_##a: type = ETHERNET_TYPE_##b; break
_(IP4, IP4);
_(IP6, IP6);
- _(MPLS, MPLS_UNICAST);
+ _(MPLS, MPLS);
_(ARP, ARP);
#undef _
default:
diff --git a/src/vnet/ethernet/node.c b/src/vnet/ethernet/node.c
index f7787ed21f8..5305012f26d 100755
--- a/src/vnet/ethernet/node.c
+++ b/src/vnet/ethernet/node.c
@@ -249,7 +249,7 @@ determine_next_node (ethernet_main_t * em,
{
*next0 = em->l3_next.input_next_ip6;
}
- else if (type0 == ETHERNET_TYPE_MPLS_UNICAST)
+ else if (type0 == ETHERNET_TYPE_MPLS)
{
*next0 = em->l3_next.input_next_mpls;
@@ -1252,7 +1252,7 @@ next_by_ethertype_register (next_by_ethertype_t * l3_next,
{
l3_next->input_next_ip6 = next_index;
}
- else if (ethertype == ETHERNET_TYPE_MPLS_UNICAST)
+ else if (ethertype == ETHERNET_TYPE_MPLS)
{
l3_next->input_next_mpls = next_index;
}
diff --git a/src/vnet/ethernet/types.def b/src/vnet/ethernet/types.def
index 643f3152a85..7dab8ee1c1a 100644
--- a/src/vnet/ethernet/types.def
+++ b/src/vnet/ethernet/types.def
@@ -85,8 +85,8 @@ ethernet_type (0x876D, SECURE_DATA)
ethernet_type (0x8808, MAC_CONTROL)
ethernet_type (0x8809, SLOW_PROTOCOLS)
ethernet_type (0x880B, PPP)
-ethernet_type (0x8847, MPLS_UNICAST)
-ethernet_type (0x8848, MPLS_MULTICAST)
+ethernet_type (0x8847, MPLS)
+ethernet_type (0x8848, MPLS_UPSTREAM_ASSIGNED)
ethernet_type (0x8863, PPPOE_DISCOVERY)
ethernet_type (0x8864, PPPOE_SESSION)
ethernet_type (0x886D, INTEL_ANS)
diff --git a/src/vnet/fib/fib_api.h b/src/vnet/fib/fib_api.h
index f82753170db..10d0cb58a95 100644
--- a/src/vnet/fib/fib_api.h
+++ b/src/vnet/fib/fib_api.h
@@ -24,6 +24,7 @@ add_del_route_check (fib_protocol_t table_proto,
fib_protocol_t next_hop_table_proto,
u32 next_hop_table_id,
u8 create_missing_tables,
+ u8 is_rpf_id,
u32 * fib_index, u32 * next_hop_fib_index);
int
@@ -33,10 +34,13 @@ add_del_route_t_handler (u8 is_multipath,
u8 is_unreach,
u8 is_prohibit,
u8 is_local,
+ u8 is_multicast,
u8 is_classify,
u32 classify_table_index,
u8 is_resolve_host,
u8 is_resolve_attached,
+ u8 is_interface_rx,
+ u8 is_rpf_id,
u32 fib_index,
const fib_prefix_t * prefix,
u8 next_hop_proto_is_ip4,
diff --git a/src/vnet/fib/fib_entry.c b/src/vnet/fib/fib_entry.c
index dac1fce995f..6f811aa1414 100644
--- a/src/vnet/fib/fib_entry.c
+++ b/src/vnet/fib/fib_entry.c
@@ -75,13 +75,7 @@ fib_entry_get_default_chain_type (const fib_entry_t *fib_entry)
return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
case FIB_PROTOCOL_MPLS:
if (MPLS_EOS == fib_entry->fe_prefix.fp_eos)
- /*
- * If the entry being asked is a eos-MPLS label entry,
- * then use the payload-protocol field, that we stashed there
- * for just this purpose
- */
- return (fib_forw_chain_type_from_dpo_proto(
- fib_entry->fe_prefix.fp_payload_proto));
+ return (FIB_FORW_CHAIN_TYPE_MPLS_EOS);
else
return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
}
@@ -371,6 +365,35 @@ fib_entry_contribute_urpf (fib_node_index_t entry_index,
}
/*
+ * If the client is request a chain for multicast forwarding then swap
+ * the chain type to one that can provide such transport.
+ */
+static fib_forward_chain_type_t
+fib_entry_chain_type_mcast_to_ucast (fib_forward_chain_type_t fct)
+{
+ switch (fct)
+ {
+ case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
+ case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
+ /*
+ * we can only transport IP multicast packets if there is an
+ * LSP.
+ */
+ fct = FIB_FORW_CHAIN_TYPE_MPLS_EOS;
+ break;
+ case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
+ case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
+ case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
+ case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
+ case FIB_FORW_CHAIN_TYPE_ETHERNET:
+ case FIB_FORW_CHAIN_TYPE_NSH:
+ break;
+ }
+
+ return (fct);
+}
+
+/*
* fib_entry_contribute_forwarding
*
* Get an lock the forwarding information (DPO) contributed by the FIB entry.
@@ -385,6 +408,11 @@ fib_entry_contribute_forwarding (fib_node_index_t fib_entry_index,
fib_entry = fib_entry_get(fib_entry_index);
+ /*
+ * mfib children ask for mcast chains. fix these to the appropriate ucast types.
+ */
+ fct = fib_entry_chain_type_mcast_to_ucast(fct);
+
if (fct == fib_entry_get_default_chain_type(fib_entry))
{
dpo_copy(dpo, &fib_entry->fe_lb);
@@ -414,6 +442,11 @@ fib_entry_contribute_forwarding (fib_node_index_t fib_entry_index,
dpo_copy(dpo, &fed->fd_dpo);
}
+ /*
+ * don't allow the special index indicating replicate.vs.load-balance
+ * to escape to the clients
+ */
+ dpo->dpoi_index &= ~MPLS_IS_REPLICATE;
}
const dpo_id_t *
diff --git a/src/vnet/fib/fib_entry.h b/src/vnet/fib/fib_entry.h
index a3f75e6084a..b17a0b6444c 100644
--- a/src/vnet/fib/fib_entry.h
+++ b/src/vnet/fib/fib_entry.h
@@ -193,6 +193,11 @@ typedef enum fib_entry_attribute_t_ {
*/
FIB_ENTRY_ATTRIBUTE_LOCAL,
/**
+ * The prefix/address is a multicast prefix.
+ * this aplies only to MPLS. IP multicast is handled by mfib
+ */
+ FIB_ENTRY_ATTRIBUTE_MULTICAST,
+ /**
* The prefix/address exempted from loose uRPF check
* To be used with caution
*/
@@ -200,7 +205,7 @@ typedef enum fib_entry_attribute_t_ {
/**
* Marker. add new entries before this one.
*/
- FIB_ENTRY_ATTRIBUTE_LAST = FIB_ENTRY_ATTRIBUTE_URPF_EXEMPT,
+ FIB_ENTRY_ATTRIBUTE_LAST = FIB_ENTRY_ATTRIBUTE_MULTICAST,
} fib_entry_attribute_t;
/**
@@ -215,7 +220,8 @@ typedef enum fib_entry_attribute_t_ {
[FIB_ENTRY_ATTRIBUTE_DROP] = "drop", \
[FIB_ENTRY_ATTRIBUTE_EXCLUSIVE] = "exclusive", \
[FIB_ENTRY_ATTRIBUTE_LOCAL] = "local", \
- [FIB_ENTRY_ATTRIBUTE_URPF_EXEMPT] = "uRPF-exempt" \
+ [FIB_ENTRY_ATTRIBUTE_URPF_EXEMPT] = "uRPF-exempt", \
+ [FIB_ENTRY_ATTRIBUTE_MULTICAST] = "multicast", \
}
#define FOR_EACH_FIB_ATTRIBUTE(_item) \
@@ -232,6 +238,7 @@ typedef enum fib_entry_flag_t_ {
FIB_ENTRY_FLAG_LOCAL = (1 << FIB_ENTRY_ATTRIBUTE_LOCAL),
FIB_ENTRY_FLAG_IMPORT = (1 << FIB_ENTRY_ATTRIBUTE_IMPORT),
FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT = (1 << FIB_ENTRY_ATTRIBUTE_URPF_EXEMPT),
+ FIB_ENTRY_FLAG_MULTICAST = (1 << FIB_ENTRY_ATTRIBUTE_MULTICAST),
} __attribute__((packed)) fib_entry_flag_t;
/**
@@ -396,7 +403,7 @@ typedef struct fib_entry_t_ {
* paint the header straight on without the need to check the packet
* type to derive the EOS bit value.
*/
- dpo_id_t fe_lb; // [FIB_FORW_CHAIN_MPLS_NUM];
+ dpo_id_t fe_lb;
/**
* Vector of source infos.
* Most entries will only have 1 source. So we optimise for memory usage,
diff --git a/src/vnet/fib/fib_entry_src.c b/src/vnet/fib/fib_entry_src.c
index aa1d5a24a0f..a700282ee9b 100644
--- a/src/vnet/fib/fib_entry_src.c
+++ b/src/vnet/fib/fib_entry_src.c
@@ -17,6 +17,7 @@
#include <vnet/dpo/load_balance.h>
#include <vnet/dpo/mpls_label_dpo.h>
#include <vnet/dpo/drop_dpo.h>
+#include <vnet/dpo/replicate_dpo.h>
#include <vnet/fib/fib_entry_src.h>
#include <vnet/fib/fib_table.h>
@@ -229,8 +230,6 @@ fib_forward_chain_type_t
fib_entry_chain_type_fixup (const fib_entry_t *entry,
fib_forward_chain_type_t fct)
{
- ASSERT(FIB_FORW_CHAIN_TYPE_MPLS_EOS == fct);
-
/*
* The EOS chain is a tricky since one cannot know the adjacency
* to link to without knowing what the packets payload protocol
@@ -238,6 +237,11 @@ fib_entry_chain_type_fixup (const fib_entry_t *entry,
*/
fib_forward_chain_type_t dfct;
+ if (FIB_FORW_CHAIN_TYPE_MPLS_EOS != fct)
+ {
+ return (fct);
+ }
+
dfct = fib_entry_get_default_chain_type(entry);
if (FIB_FORW_CHAIN_TYPE_MPLS_EOS == dfct)
@@ -303,7 +307,12 @@ fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
* found a matching extension. stack it to obtain the forwarding
* info for this path.
*/
- ctx->next_hops = fib_path_ext_stack(path_ext, ctx->fib_entry, ctx->fct, ctx->next_hops);
+ ctx->next_hops =
+ fib_path_ext_stack(path_ext,
+ ctx->fct,
+ fib_entry_chain_type_fixup(ctx->fib_entry,
+ ctx->fct),
+ ctx->next_hops);
}
else
{
@@ -355,6 +364,9 @@ fib_entry_src_collect_forwarding (fib_node_index_t pl_index,
fib_entry_chain_type_fixup(ctx->fib_entry,
ctx->fct),
&nh->path_dpo);
+ fib_path_stack_mpls_disp(path_index,
+ ctx->fib_entry->fe_prefix.fp_payload_proto,
+ &nh->path_dpo);
break;
}
@@ -424,50 +436,70 @@ fib_entry_src_mk_lb (fib_entry_t *fib_entry,
/*
* first time create
*/
- flow_hash_config_t fhc;
-
- fhc = fib_table_get_flow_hash_config(fib_entry->fe_fib_index,
- dpo_proto_to_fib(lb_proto));
- dpo_set(dpo_lb,
- DPO_LOAD_BALANCE,
- lb_proto,
- load_balance_create(0, lb_proto, fhc));
+ if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
+ {
+ dpo_set(dpo_lb,
+ DPO_REPLICATE,
+ lb_proto,
+ MPLS_IS_REPLICATE | replicate_create(0, lb_proto));
+ }
+ else
+ {
+ flow_hash_config_t fhc;
+
+ fhc = fib_table_get_flow_hash_config(fib_entry->fe_fib_index,
+ dpo_proto_to_fib(lb_proto));
+ dpo_set(dpo_lb,
+ DPO_LOAD_BALANCE,
+ lb_proto,
+ load_balance_create(0, lb_proto, fhc));
+ }
}
- 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
- * append the always present local0 interface (index 0) to the
- * uRPF list so it is not empty. that way packets pass the loose check.
- */
- index_t ui = fib_path_list_get_urpf(esrc->fes_pl);
-
- if ((fib_entry_is_sourced(fib_entry_get_index(fib_entry),
- FIB_SOURCE_URPF_EXEMPT) ||
- (esrc->fes_entry_flags & FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT))&&
- (0 == fib_urpf_check_size(ui)))
+ if (esrc->fes_entry_flags & FIB_ENTRY_FLAG_MULTICAST)
{
- /*
- * The uRPF list we get from the path-list is shared by all
- * other users of the list, but the uRPF exemption applies
- * only to this prefix. So we need our own list.
- */
- ui = fib_urpf_list_alloc_and_lock();
- fib_urpf_list_append(ui, 0);
- fib_urpf_list_bake(ui);
- load_balance_set_urpf(dpo_lb->dpoi_index, ui);
- fib_urpf_list_unlock(ui);
+ /*
+ * MPLS multicast
+ */
+ replicate_multipath_update(dpo_lb, ctx.next_hops);
}
else
{
- load_balance_set_urpf(dpo_lb->dpoi_index, ui);
+ 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
+ * append the always present local0 interface (index 0) to the
+ * uRPF list so it is not empty. that way packets pass the loose check.
+ */
+ index_t ui = fib_path_list_get_urpf(esrc->fes_pl);
+
+ if ((fib_entry_is_sourced(fib_entry_get_index(fib_entry),
+ FIB_SOURCE_URPF_EXEMPT) ||
+ (esrc->fes_entry_flags & FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT))&&
+ (0 == fib_urpf_check_size(ui)))
+ {
+ /*
+ * The uRPF list we get from the path-list is shared by all
+ * other users of the list, but the uRPF exemption applies
+ * only to this prefix. So we need our own list.
+ */
+ ui = fib_urpf_list_alloc_and_lock();
+ fib_urpf_list_append(ui, 0);
+ fib_urpf_list_bake(ui);
+ load_balance_set_urpf(dpo_lb->dpoi_index, ui);
+ fib_urpf_list_unlock(ui);
+ }
+ else
+ {
+ load_balance_set_urpf(dpo_lb->dpoi_index, ui);
+ }
+ load_balance_set_fib_entry_flags(dpo_lb->dpoi_index,
+ fib_entry_get_flags_i(fib_entry));
}
- load_balance_set_fib_entry_flags(dpo_lb->dpoi_index,
- fib_entry_get_flags_i(fib_entry));
}
void
@@ -887,21 +919,6 @@ fib_entry_src_action_remove (fib_entry_t *fib_entry,
return (sflags);
}
-static inline int
-fib_route_recurses_via_self (const fib_prefix_t *prefix,
- const fib_route_path_t *rpath)
-{
- /*
- * not all zeros next hop &&
- * is recursive path &&
- * nexthop is same as the route's address
- */
- return ((!ip46_address_is_zero(&rpath->frp_addr)) &&
- (~0 == rpath->frp_sw_if_index) &&
- (0 == ip46_address_cmp(&rpath->frp_addr, &prefix->fp_addr)));
-
-}
-
/*
* fib_route_attached_cross_table
*
@@ -962,14 +979,14 @@ fib_entry_src_flags_2_path_list_flags (fib_entry_flag_t eflags)
{
plf |= FIB_PATH_LIST_FLAG_DROP;
}
- if (eflags & FIB_ENTRY_FLAG_LOCAL)
- {
- plf |= FIB_PATH_LIST_FLAG_LOCAL;
- }
if (eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
{
plf |= FIB_PATH_LIST_FLAG_EXCLUSIVE;
}
+ if (eflags & FIB_ENTRY_FLAG_LOCAL)
+ {
+ plf |= FIB_PATH_LIST_FLAG_LOCAL;
+ }
return (plf);
}
@@ -980,25 +997,6 @@ fib_entry_flags_update (const fib_entry_t *fib_entry,
fib_path_list_flags_t *pl_flags,
fib_entry_src_t *esrc)
{
- /*
- * don't allow the addition of a recursive looped path for prefix
- * via itself.
- */
- if (fib_route_recurses_via_self(&fib_entry->fe_prefix, rpath))
- {
- /*
- * force the install of a drop path-list.
- * we want the entry to have some path-list, mainly so
- * the dodgy path can be rmeoved when the source stops playing
- * silly buggers.
- */
- *pl_flags |= FIB_PATH_LIST_FLAG_DROP;
- }
- else
- {
- *pl_flags &= ~FIB_PATH_LIST_FLAG_DROP;
- }
-
if ((esrc->fes_src == FIB_SOURCE_API) ||
(esrc->fes_src == FIB_SOURCE_CLI))
{
diff --git a/src/vnet/fib/fib_internal.h b/src/vnet/fib/fib_internal.h
index 2d980bcce0a..8abc0e07313 100644
--- a/src/vnet/fib/fib_internal.h
+++ b/src/vnet/fib/fib_internal.h
@@ -25,6 +25,7 @@
#undef FIB_DEBUG
extern void fib_prefix_from_mpls_label(mpls_label_t label,
+ mpls_eos_bit_t eos,
fib_prefix_t *prf);
extern int fib_route_path_cmp(const fib_route_path_t *rpath1,
diff --git a/src/vnet/fib/fib_path.c b/src/vnet/fib/fib_path.c
index 6b202a97824..f81f41706c5 100644
--- a/src/vnet/fib/fib_path.c
+++ b/src/vnet/fib/fib_path.c
@@ -21,6 +21,8 @@
#include <vnet/dpo/receive_dpo.h>
#include <vnet/dpo/load_balance_map.h>
#include <vnet/dpo/lookup_dpo.h>
+#include <vnet/dpo/interface_dpo.h>
+#include <vnet/dpo/mpls_disposition.h>
#include <vnet/adj/adj.h>
#include <vnet/adj/adj_mcast.h>
@@ -67,6 +69,10 @@ typedef enum fib_path_type_t_ {
*/
FIB_PATH_TYPE_DEAG,
/**
+ * interface receive.
+ */
+ FIB_PATH_TYPE_INTF_RX,
+ /**
* receive. it's for-us.
*/
FIB_PATH_TYPE_RECEIVE,
@@ -88,6 +94,7 @@ typedef enum fib_path_type_t_ {
[FIB_PATH_TYPE_SPECIAL] = "special", \
[FIB_PATH_TYPE_EXCLUSIVE] = "exclusive", \
[FIB_PATH_TYPE_DEAG] = "deag", \
+ [FIB_PATH_TYPE_INTF_RX] = "intf-rx", \
[FIB_PATH_TYPE_RECEIVE] = "receive", \
}
@@ -220,10 +227,16 @@ typedef struct fib_path_t_ {
* The next-hop
*/
ip46_address_t fp_ip;
- /**
- * The local label to resolve through.
- */
- mpls_label_t fp_local_label;
+ struct {
+ /**
+ * The local label to resolve through.
+ */
+ mpls_label_t fp_local_label;
+ /**
+ * The EOS bit of the resolving label
+ */
+ mpls_eos_bit_t fp_eos;
+ };
} fp_nh;
/**
* The FIB table index in which to find the next-hop.
@@ -254,6 +267,10 @@ typedef struct fib_path_t_ {
* The FIB index in which to perfom the next lookup
*/
fib_node_index_t fp_tbl_id;
+ /**
+ * The RPF-ID to tag the packets with
+ */
+ fib_rpf_id_t fp_rpf_id;
} deag;
struct {
} special;
@@ -273,6 +290,12 @@ typedef struct fib_path_t_ {
*/
ip46_address_t fp_addr;
} receive;
+ struct {
+ /**
+ * The interface on which the packets will be input.
+ */
+ u32 fp_interface;
+ } intf_rx;
};
STRUCT_MARK(path_hash_end);
@@ -444,9 +467,11 @@ format_fib_path (u8 * s, va_list * args)
case FIB_PATH_TYPE_RECURSIVE:
if (FIB_PROTOCOL_MPLS == path->fp_nh_proto)
{
- s = format (s, "via %U",
+ s = format (s, "via %U %U",
format_mpls_unicast_label,
- path->recursive.fp_nh.fp_local_label);
+ path->recursive.fp_nh.fp_local_label,
+ format_mpls_eos_bit,
+ path->recursive.fp_nh.fp_eos);
}
else
{
@@ -465,6 +490,7 @@ format_fib_path (u8 * s, va_list * args)
break;
case FIB_PATH_TYPE_RECEIVE:
+ case FIB_PATH_TYPE_INTF_RX:
case FIB_PATH_TYPE_SPECIAL:
case FIB_PATH_TYPE_DEAG:
case FIB_PATH_TYPE_EXCLUSIVE:
@@ -736,6 +762,7 @@ fib_path_unresolve (fib_path_t *path)
break;
case FIB_PATH_TYPE_SPECIAL:
case FIB_PATH_TYPE_RECEIVE:
+ case FIB_PATH_TYPE_INTF_RX:
case FIB_PATH_TYPE_DEAG:
/*
* these hold only the path's DPO, which is reset below.
@@ -754,16 +781,24 @@ fib_path_unresolve (fib_path_t *path)
}
static fib_forward_chain_type_t
-fib_path_proto_to_chain_type (fib_protocol_t proto)
+fib_path_to_chain_type (const fib_path_t *path)
{
- switch (proto)
+ switch (path->fp_nh_proto)
{
case FIB_PROTOCOL_IP4:
return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
case FIB_PROTOCOL_IP6:
return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
case FIB_PROTOCOL_MPLS:
- return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
+ if (FIB_PATH_TYPE_RECURSIVE == path->fp_type &&
+ MPLS_EOS == path->recursive.fp_nh.fp_eos)
+ {
+ return (FIB_FORW_CHAIN_TYPE_MPLS_EOS);
+ }
+ else
+ {
+ return (FIB_FORW_CHAIN_TYPE_MPLS_EOS);
+ }
}
return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
}
@@ -793,7 +828,7 @@ fib_path_back_walk_notify (fib_node_t *node,
*/
fib_path_recursive_adj_update(
path,
- fib_path_proto_to_chain_type(path->fp_nh_proto),
+ fib_path_to_chain_type(path),
&path->fp_dpo);
}
if ((FIB_NODE_BW_REASON_FLAG_ADJ_UPDATE & ctx->fnbw_reason) ||
@@ -931,6 +966,8 @@ FIXME comment
path->fp_oper_flags |= FIB_PATH_OPER_FLAG_DROP;
}
break;
+ case FIB_PATH_TYPE_INTF_RX:
+ ASSERT(0);
case FIB_PATH_TYPE_DEAG:
/*
* FIXME When VRF delete is allowed this will need a poke.
@@ -986,6 +1023,14 @@ fib_path_route_flags_to_cfg_flags (const fib_route_path_t *rpath)
cfg_flags |= FIB_PATH_CFG_FLAG_LOCAL;
if (rpath->frp_flags & FIB_ROUTE_PATH_ATTACHED)
cfg_flags |= FIB_PATH_CFG_FLAG_ATTACHED;
+ if (rpath->frp_flags & FIB_ROUTE_PATH_INTF_RX)
+ cfg_flags |= FIB_PATH_CFG_FLAG_INTF_RX;
+ if (rpath->frp_flags & FIB_ROUTE_PATH_RPF_ID)
+ cfg_flags |= FIB_PATH_CFG_FLAG_RPF_ID;
+ if (rpath->frp_flags & FIB_ROUTE_PATH_EXCLUSIVE)
+ cfg_flags |= FIB_PATH_CFG_FLAG_EXCLUSIVE;
+ if (rpath->frp_flags & FIB_ROUTE_PATH_DROP)
+ cfg_flags |= FIB_PATH_CFG_FLAG_DROP;
return (cfg_flags);
}
@@ -998,8 +1043,6 @@ fib_path_route_flags_to_cfg_flags (const fib_route_path_t *rpath)
*/
fib_node_index_t
fib_path_create (fib_node_index_t pl_index,
- fib_protocol_t nh_proto,
- fib_path_cfg_flags_t flags,
const fib_route_path_t *rpath)
{
fib_path_t *path;
@@ -1012,7 +1055,7 @@ fib_path_create (fib_node_index_t pl_index,
dpo_reset(&path->fp_dpo);
path->fp_pl_index = pl_index;
- path->fp_nh_proto = nh_proto;
+ path->fp_nh_proto = rpath->frp_proto;
path->fp_via_fib = FIB_NODE_INDEX_INVALID;
path->fp_weight = rpath->frp_weight;
if (0 == path->fp_weight)
@@ -1023,8 +1066,7 @@ fib_path_create (fib_node_index_t pl_index,
*/
path->fp_weight = 1;
}
- path->fp_cfg_flags = flags;
- path->fp_cfg_flags |= fib_path_route_flags_to_cfg_flags(rpath);
+ path->fp_cfg_flags = fib_path_route_flags_to_cfg_flags(rpath);
/*
* deduce the path's tpye from the parementers and save what is needed.
@@ -1035,6 +1077,17 @@ fib_path_create (fib_node_index_t pl_index,
path->receive.fp_interface = rpath->frp_sw_if_index;
path->receive.fp_addr = rpath->frp_addr;
}
+ else if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_INTF_RX)
+ {
+ path->fp_type = FIB_PATH_TYPE_INTF_RX;
+ path->intf_rx.fp_interface = rpath->frp_sw_if_index;
+ }
+ else if (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RPF_ID)
+ {
+ path->fp_type = FIB_PATH_TYPE_DEAG;
+ path->deag.fp_tbl_id = rpath->frp_fib_index;
+ path->deag.fp_rpf_id = rpath->frp_rpf_id;
+ }
else if (~0 != rpath->frp_sw_if_index)
{
if (ip46_address_is_zero(&rpath->frp_addr))
@@ -1069,6 +1122,7 @@ fib_path_create (fib_node_index_t pl_index,
if (FIB_PROTOCOL_MPLS == path->fp_nh_proto)
{
path->recursive.fp_nh.fp_local_label = rpath->frp_local_label;
+ path->recursive.fp_nh.fp_eos = rpath->frp_eos;
}
else
{
@@ -1238,17 +1292,13 @@ fib_path_cmp_i (const fib_path_t *path1,
res = ip46_address_cmp(&path1->attached_next_hop.fp_nh,
&path2->attached_next_hop.fp_nh);
if (0 == res) {
- res = vnet_sw_interface_compare(
- vnet_get_main(),
- path1->attached_next_hop.fp_interface,
- path2->attached_next_hop.fp_interface);
+ res = (path1->attached_next_hop.fp_interface -
+ path2->attached_next_hop.fp_interface);
}
break;
case FIB_PATH_TYPE_ATTACHED:
- res = vnet_sw_interface_compare(
- vnet_get_main(),
- path1->attached.fp_interface,
- path2->attached.fp_interface);
+ res = (path1->attached.fp_interface -
+ path2->attached.fp_interface);
break;
case FIB_PATH_TYPE_RECURSIVE:
res = ip46_address_cmp(&path1->recursive.fp_nh,
@@ -1261,6 +1311,13 @@ fib_path_cmp_i (const fib_path_t *path1,
break;
case FIB_PATH_TYPE_DEAG:
res = (path1->deag.fp_tbl_id - path2->deag.fp_tbl_id);
+ if (0 == res)
+ {
+ res = (path1->deag.fp_rpf_id - path2->deag.fp_rpf_id);
+ }
+ break;
+ case FIB_PATH_TYPE_INTF_RX:
+ res = (path1->intf_rx.fp_interface - path2->intf_rx.fp_interface);
break;
case FIB_PATH_TYPE_SPECIAL:
case FIB_PATH_TYPE_RECEIVE:
@@ -1336,22 +1393,22 @@ fib_path_cmp_w_route_path (fib_node_index_t path_index,
&rpath->frp_addr);
if (0 == res)
{
- res = vnet_sw_interface_compare(
- vnet_get_main(),
- path->attached_next_hop.fp_interface,
- rpath->frp_sw_if_index);
+ res = (path->attached_next_hop.fp_interface -
+ rpath->frp_sw_if_index);
}
break;
case FIB_PATH_TYPE_ATTACHED:
- res = vnet_sw_interface_compare(
- vnet_get_main(),
- path->attached.fp_interface,
- rpath->frp_sw_if_index);
+ res = (path->attached.fp_interface - rpath->frp_sw_if_index);
break;
case FIB_PATH_TYPE_RECURSIVE:
if (FIB_PROTOCOL_MPLS == path->fp_nh_proto)
{
res = path->recursive.fp_nh.fp_local_label - rpath->frp_local_label;
+
+ if (res == 0)
+ {
+ res = path->recursive.fp_nh.fp_eos - rpath->frp_eos;
+ }
}
else
{
@@ -1364,9 +1421,16 @@ fib_path_cmp_w_route_path (fib_node_index_t path_index,
res = (path->recursive.fp_tbl_id - rpath->frp_fib_index);
}
break;
+ case FIB_PATH_TYPE_INTF_RX:
+ res = (path->intf_rx.fp_interface - rpath->frp_sw_if_index);
+ break;
case FIB_PATH_TYPE_DEAG:
res = (path->deag.fp_tbl_id - rpath->frp_fib_index);
- break;
+ if (0 == res)
+ {
+ res = (path->deag.fp_rpf_id - rpath->frp_rpf_id);
+ }
+ break;
case FIB_PATH_TYPE_SPECIAL:
case FIB_PATH_TYPE_RECEIVE:
case FIB_PATH_TYPE_EXCLUSIVE:
@@ -1465,6 +1529,7 @@ fib_path_recursive_loop_detect (fib_node_index_t path_index,
case FIB_PATH_TYPE_SPECIAL:
case FIB_PATH_TYPE_DEAG:
case FIB_PATH_TYPE_RECEIVE:
+ case FIB_PATH_TYPE_INTF_RX:
case FIB_PATH_TYPE_EXCLUSIVE:
/*
* these path types cannot be part of a loop, since they are the leaves
@@ -1563,7 +1628,9 @@ fib_path_resolve (fib_node_index_t path_index)
if (FIB_PROTOCOL_MPLS == path->fp_nh_proto)
{
- fib_prefix_from_mpls_label(path->recursive.fp_nh.fp_local_label, &pfx);
+ fib_prefix_from_mpls_label(path->recursive.fp_nh.fp_local_label,
+ path->recursive.fp_nh.fp_eos,
+ &pfx);
}
else
{
@@ -1592,7 +1659,7 @@ fib_path_resolve (fib_node_index_t path_index)
*/
fib_path_recursive_adj_update(
path,
- fib_path_proto_to_chain_type(path->fp_nh_proto),
+ fib_path_to_chain_type(path),
&path->fp_dpo);
break;
@@ -1605,16 +1672,25 @@ fib_path_resolve (fib_node_index_t path_index)
drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto)));
break;
case FIB_PATH_TYPE_DEAG:
+ {
/*
* Resolve via a lookup DPO.
* FIXME. control plane should add routes with a table ID
*/
- lookup_dpo_add_or_lock_w_fib_index(path->deag.fp_tbl_id,
- fib_proto_to_dpo(path->fp_nh_proto),
- LOOKUP_INPUT_DST_ADDR,
- LOOKUP_TABLE_FROM_CONFIG,
- &path->fp_dpo);
+ lookup_cast_t cast;
+
+ cast = (path->fp_cfg_flags & FIB_PATH_CFG_FLAG_RPF_ID ?
+ LOOKUP_MULTICAST :
+ LOOKUP_UNICAST);
+
+ lookup_dpo_add_or_lock_w_fib_index(path->deag.fp_tbl_id,
+ fib_proto_to_dpo(path->fp_nh_proto),
+ cast,
+ LOOKUP_INPUT_DST_ADDR,
+ LOOKUP_TABLE_FROM_CONFIG,
+ &path->fp_dpo);
break;
+ }
case FIB_PATH_TYPE_RECEIVE:
/*
* Resolve via a receive DPO.
@@ -1624,6 +1700,15 @@ fib_path_resolve (fib_node_index_t path_index)
&path->receive.fp_addr,
&path->fp_dpo);
break;
+ case FIB_PATH_TYPE_INTF_RX: {
+ /*
+ * Resolve via a receive DPO.
+ */
+ interface_dpo_add_or_lock(fib_proto_to_dpo(path->fp_nh_proto),
+ path->intf_rx.fp_interface,
+ &path->fp_dpo);
+ break;
+ }
case FIB_PATH_TYPE_EXCLUSIVE:
/*
* Resolve via the user provided DPO
@@ -1652,6 +1737,7 @@ fib_path_get_resolving_interface (fib_node_index_t path_index)
return (path->receive.fp_interface);
case FIB_PATH_TYPE_RECURSIVE:
return (fib_entry_get_resolving_interface(path->fp_via_fib));
+ case FIB_PATH_TYPE_INTF_RX:
case FIB_PATH_TYPE_SPECIAL:
case FIB_PATH_TYPE_DEAG:
case FIB_PATH_TYPE_EXCLUSIVE:
@@ -1743,6 +1829,7 @@ fib_path_contribute_urpf (fib_node_index_t path_index,
case FIB_PATH_TYPE_DEAG:
case FIB_PATH_TYPE_RECEIVE:
+ case FIB_PATH_TYPE_INTF_RX:
/*
* these path types don't link to an adj
*/
@@ -1751,6 +1838,44 @@ fib_path_contribute_urpf (fib_node_index_t path_index,
}
void
+fib_path_stack_mpls_disp (fib_node_index_t path_index,
+ dpo_proto_t payload_proto,
+ dpo_id_t *dpo)
+{
+ fib_path_t *path;
+
+ path = fib_path_get(path_index);
+
+ ASSERT(path);
+
+ switch (path->fp_type)
+ {
+ case FIB_PATH_TYPE_DEAG:
+ {
+ dpo_id_t tmp = DPO_INVALID;
+
+ dpo_copy(&tmp, dpo);
+ dpo_set(dpo,
+ DPO_MPLS_DISPOSITION,
+ payload_proto,
+ mpls_disp_dpo_create(payload_proto,
+ path->deag.fp_rpf_id,
+ &tmp));
+ dpo_reset(&tmp);
+ break;
+ }
+ case FIB_PATH_TYPE_RECEIVE:
+ case FIB_PATH_TYPE_ATTACHED:
+ case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:
+ case FIB_PATH_TYPE_RECURSIVE:
+ case FIB_PATH_TYPE_INTF_RX:
+ case FIB_PATH_TYPE_EXCLUSIVE:
+ case FIB_PATH_TYPE_SPECIAL:
+ break;
+ }
+}
+
+void
fib_path_contribute_forwarding (fib_node_index_t path_index,
fib_forward_chain_type_t fct,
dpo_id_t *dpo)
@@ -1769,7 +1894,7 @@ fib_path_contribute_forwarding (fib_node_index_t path_index,
* This then represents the path's 'native' protocol; IP.
* For all others will need to go find something else.
*/
- if (fib_path_proto_to_chain_type(path->fp_nh_proto) == fct)
+ if (fib_path_to_chain_type(path) == fct)
{
dpo_copy(dpo, &path->fp_dpo);
}
@@ -1813,10 +1938,10 @@ fib_path_contribute_forwarding (fib_node_index_t path_index,
case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
- fib_path_recursive_adj_update(path, fct, dpo);
- break;
case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
case FIB_FORW_CHAIN_TYPE_MCAST_IP6:
+ fib_path_recursive_adj_update(path, fct, dpo);
+ break;
case FIB_FORW_CHAIN_TYPE_ETHERNET:
case FIB_FORW_CHAIN_TYPE_NSH:
ASSERT(0);
@@ -1829,13 +1954,14 @@ fib_path_contribute_forwarding (fib_node_index_t path_index,
case FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS:
lookup_dpo_add_or_lock_w_table_id(MPLS_FIB_DEFAULT_TABLE_ID,
DPO_PROTO_MPLS,
+ LOOKUP_UNICAST,
LOOKUP_INPUT_DST_ADDR,
LOOKUP_TABLE_FROM_CONFIG,
dpo);
break;
+ case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
case FIB_FORW_CHAIN_TYPE_UNICAST_IP4:
case FIB_FORW_CHAIN_TYPE_UNICAST_IP6:
- case FIB_FORW_CHAIN_TYPE_MPLS_EOS:
dpo_copy(dpo, &path->fp_dpo);
break;
case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
@@ -1870,7 +1996,7 @@ fib_path_contribute_forwarding (fib_node_index_t path_index,
ai = adj_mcast_add_or_lock(path->fp_nh_proto,
fib_forw_chain_type_to_link_type(fct),
path->attached.fp_interface);
- dpo_set(dpo, DPO_ADJACENCY_MCAST,
+ dpo_set(dpo, DPO_ADJACENCY,
fib_forw_chain_type_to_dpo_proto(fct),
ai);
adj_unlock(ai);
@@ -1878,6 +2004,14 @@ fib_path_contribute_forwarding (fib_node_index_t path_index,
break;
}
break;
+ case FIB_PATH_TYPE_INTF_RX:
+ /*
+ * Create the adj needed for sending IP multicast traffic
+ */
+ interface_dpo_add_or_lock(fib_forw_chain_type_to_dpo_proto(fct),
+ path->attached.fp_interface,
+ dpo);
+ break;
case FIB_PATH_TYPE_RECEIVE:
case FIB_PATH_TYPE_SPECIAL:
dpo_copy(dpo, &path->fp_dpo);
diff --git a/src/vnet/fib/fib_path.h b/src/vnet/fib/fib_path.h
index 14efc1ab842..334be6f56e6 100644
--- a/src/vnet/fib/fib_path.h
+++ b/src/vnet/fib/fib_path.h
@@ -69,6 +69,14 @@ typedef enum fib_path_cfg_attribute_t_ {
/**
* The path is a for-us path
*/
+ FIB_PATH_CFG_ATTRIBUTE_INTF_RX,
+ /**
+ * The path is a deag with rpf-id
+ */
+ FIB_PATH_CFG_ATTRIBUTE_RPF_ID,
+ /**
+ * The path is an interface recieve
+ */
FIB_PATH_CFG_ATTRIBUTE_LOCAL,
/**
* Marker. Add new types before this one, then update it.
@@ -88,6 +96,8 @@ typedef enum fib_path_cfg_attribute_t_ {
[FIB_PATH_CFG_ATTRIBUTE_RESOLVE_ATTACHED] = "resolve-attached", \
[FIB_PATH_CFG_ATTRIBUTE_LOCAL] = "local", \
[FIB_PATH_CFG_ATTRIBUTE_ATTACHED] = "attached", \
+ [FIB_PATH_CFG_ATTRIBUTE_INTF_RX] = "interface-rx", \
+ [FIB_PATH_CFG_ATTRIBUTE_RPF_ID] = "rpf-id", \
}
#define FOR_EACH_FIB_PATH_CFG_ATTRIBUTE(_item) \
@@ -106,6 +116,8 @@ typedef enum fib_path_cfg_flags_t_ {
FIB_PATH_CFG_FLAG_RESOLVE_ATTACHED = (1 << FIB_PATH_CFG_ATTRIBUTE_RESOLVE_ATTACHED),
FIB_PATH_CFG_FLAG_LOCAL = (1 << FIB_PATH_CFG_ATTRIBUTE_LOCAL),
FIB_PATH_CFG_FLAG_ATTACHED = (1 << FIB_PATH_CFG_ATTRIBUTE_ATTACHED),
+ FIB_PATH_CFG_FLAG_INTF_RX = (1 << FIB_PATH_CFG_ATTRIBUTE_INTF_RX),
+ FIB_PATH_CFG_FLAG_RPF_ID = (1 << FIB_PATH_CFG_ATTRIBUTE_RPF_ID),
} __attribute__ ((packed)) fib_path_cfg_flags_t;
@@ -117,8 +129,6 @@ extern u8 *fib_path_adj_format(fib_node_index_t pi,
extern u8 * format_fib_path(u8 * s, va_list * args);
extern fib_node_index_t fib_path_create(fib_node_index_t pl_index,
- fib_protocol_t nh_proto,
- fib_path_cfg_flags_t flags,
const fib_route_path_t *path);
extern fib_node_index_t fib_path_create_special(fib_node_index_t pl_index,
fib_protocol_t nh_proto,
@@ -145,6 +155,9 @@ extern load_balance_path_t * fib_path_append_nh_for_multipath_hash(
fib_node_index_t path_index,
fib_forward_chain_type_t fct,
load_balance_path_t *hash_key);
+extern void fib_path_stack_mpls_disp(fib_node_index_t path_index,
+ dpo_proto_t payload_proto,
+ dpo_id_t *dpo);
extern void fib_path_contribute_forwarding(fib_node_index_t path_index,
fib_forward_chain_type_t type,
dpo_id_t *dpo);
diff --git a/src/vnet/fib/fib_path_ext.c b/src/vnet/fib/fib_path_ext.c
index f75b5626c04..08293bcf175 100644
--- a/src/vnet/fib/fib_path_ext.c
+++ b/src/vnet/fib/fib_path_ext.c
@@ -103,8 +103,8 @@ fib_path_ext_is_imp_null (fib_path_ext_t *path_ext)
load_balance_path_t *
fib_path_ext_stack (fib_path_ext_t *path_ext,
- const fib_entry_t *entry,
fib_forward_chain_type_t child_fct,
+ fib_forward_chain_type_t imp_null_fct,
load_balance_path_t *nhs)
{
fib_forward_chain_type_t parent_fct;
@@ -129,7 +129,7 @@ fib_path_ext_stack (fib_path_ext_t *path_ext,
*/
if (fib_path_ext_is_imp_null(path_ext))
{
- parent_fct = fib_entry_chain_type_fixup(entry, child_fct);
+ parent_fct = imp_null_fct;
}
else
{
diff --git a/src/vnet/fib/fib_path_ext.h b/src/vnet/fib/fib_path_ext.h
index cf8f8df00c6..d617700d026 100644
--- a/src/vnet/fib/fib_path_ext.h
+++ b/src/vnet/fib/fib_path_ext.h
@@ -18,6 +18,7 @@
#include <vnet/mpls/mpls.h>
#include <vnet/fib/fib_types.h>
+#include <vnet/dpo/load_balance.h>
/**
* A path extension is a per-entry addition to the forwarding information
@@ -61,8 +62,8 @@ extern void fib_path_ext_resolve(fib_path_ext_t *path_ext,
fib_node_index_t path_list_index);
extern load_balance_path_t *fib_path_ext_stack(fib_path_ext_t *path_ext,
- const struct fib_entry_t_ *entry,
fib_forward_chain_type_t fct,
+ fib_forward_chain_type_t imp_null_fct,
load_balance_path_t *nhs);
#endif
diff --git a/src/vnet/fib/fib_path_list.c b/src/vnet/fib/fib_path_list.c
index b9a391b33f5..ea6565dd19b 100644
--- a/src/vnet/fib/fib_path_list.c
+++ b/src/vnet/fib/fib_path_list.c
@@ -41,13 +41,6 @@ typedef struct fib_path_list_t_ {
fib_path_list_flags_t fpl_flags;
/**
- * The next-hop protocol for the paths in this path list.
- * Note that fixing the proto here means we don't support a mix of
- * v4 and v6 paths. ho hum.
- */
- fib_protocol_t fpl_nh_proto;
-
- /**
* Vector of paths indicies for all configured paths.
* For shareable path-lists this list MUST not change.
*/
@@ -57,6 +50,11 @@ typedef struct fib_path_list_t_ {
* the RPF list calculated for this path list
*/
fib_node_index_t fpl_urpf;
+
+ /**
+ * Hash table of paths. valid only with INDEXED flag
+ */
+ uword *fpl_db;
} fib_path_list_t;
/*
@@ -131,7 +129,6 @@ format_fib_path_list (u8 * s, va_list * args)
s = format (s, " index:%u", fib_path_list_get_index(path_list));
s = format (s, " locks:%u", path_list->fpl_node.fn_locks);
- s = format (s, " proto:%U", format_fib_protocol, path_list->fpl_nh_proto);
if (FIB_PATH_LIST_FLAG_NONE != path_list->fpl_flags)
{
@@ -156,26 +153,6 @@ format_fib_path_list (u8 * s, va_list * args)
}
u8 *
-fib_path_list_adjs_format (fib_node_index_t path_list_index,
- u32 indent,
- u8 * s)
-{
- fib_path_list_t *path_list;
- u32 i;
-
- path_list = fib_path_list_get(path_list_index);
-
- vec_foreach_index (i, path_list->fpl_paths)
- {
- s = fib_path_adj_format(path_list->fpl_paths[i],
- indent, s);
- }
-
- return (s);
-}
-
-
-u8 *
fib_path_list_format (fib_node_index_t path_list_index,
u8 * s)
{
@@ -648,27 +625,6 @@ fib_path_list_is_looped (fib_node_index_t path_list_index)
return (path_list->fpl_flags & FIB_PATH_LIST_FLAG_LOOPED);
}
-static fib_path_cfg_flags_t
-fib_path_list_flags_2_path_flags (fib_path_list_flags_t plf)
-{
- fib_path_cfg_flags_t pf = FIB_PATH_CFG_FLAG_NONE;
-
- if (plf & FIB_PATH_LIST_FLAG_LOCAL)
- {
- pf |= FIB_PATH_CFG_FLAG_LOCAL;
- }
- if (plf & FIB_PATH_LIST_FLAG_DROP)
- {
- pf |= FIB_PATH_CFG_FLAG_DROP;
- }
- if (plf & FIB_PATH_LIST_FLAG_EXCLUSIVE)
- {
- pf |= FIB_PATH_CFG_FLAG_EXCLUSIVE;
- }
-
- return (pf);
-}
-
static fib_path_list_flags_t
fib_path_list_flags_fixup (fib_path_list_flags_t flags)
{
@@ -695,18 +651,15 @@ fib_path_list_create (fib_path_list_flags_t flags,
flags = fib_path_list_flags_fixup(flags);
path_list = fib_path_list_alloc(&path_list_index);
path_list->fpl_flags = flags;
- /*
- * we'll assume for now all paths are the same next-hop protocol
- */
- path_list->fpl_nh_proto = rpaths[0].frp_proto;
- vec_foreach_index(i, rpaths)
+ if (NULL != rpaths)
{
- vec_add1(path_list->fpl_paths,
- fib_path_create(path_list_index,
- path_list->fpl_nh_proto,
- fib_path_list_flags_2_path_flags(flags),
- &rpaths[i]));
+ vec_foreach_index(i, rpaths)
+ {
+ vec_add1(path_list->fpl_paths,
+ fib_path_create(path_list_index,
+ &rpaths[i]));
+ }
}
/*
@@ -748,6 +701,27 @@ fib_path_list_create (fib_path_list_flags_t flags,
return (path_list_index);
}
+static fib_path_cfg_flags_t
+fib_path_list_flags_2_path_flags (fib_path_list_flags_t plf)
+{
+ fib_path_cfg_flags_t pf = FIB_PATH_CFG_FLAG_NONE;
+
+ if (plf & FIB_PATH_LIST_FLAG_DROP)
+ {
+ pf |= FIB_PATH_CFG_FLAG_DROP;
+ }
+ if (plf & FIB_PATH_LIST_FLAG_EXCLUSIVE)
+ {
+ pf |= FIB_PATH_CFG_FLAG_EXCLUSIVE;
+ }
+ if (plf & FIB_PATH_LIST_FLAG_LOCAL)
+ {
+ pf |= FIB_PATH_CFG_FLAG_LOCAL;
+ }
+
+ return (pf);
+}
+
fib_node_index_t
fib_path_list_create_special (fib_protocol_t nh_proto,
fib_path_list_flags_t flags,
@@ -758,11 +732,10 @@ fib_path_list_create_special (fib_protocol_t nh_proto,
path_list = fib_path_list_alloc(&path_list_index);
path_list->fpl_flags = flags;
- path_list->fpl_nh_proto = nh_proto;
path_index =
fib_path_create_special(path_list_index,
- path_list->fpl_nh_proto,
+ nh_proto,
fib_path_list_flags_2_path_flags(flags),
dpo);
vec_add1(path_list->fpl_paths, path_index);
@@ -776,6 +749,30 @@ fib_path_list_create_special (fib_protocol_t nh_proto,
}
/*
+ * return the index info the path-lists's vector of paths, of the matching path.
+ * ~0 if not found
+ */
+u32
+fib_path_list_find_rpath (fib_node_index_t path_list_index,
+ const fib_route_path_t *rpath)
+{
+ fib_path_list_t *path_list;
+ u32 ii;
+
+ path_list = fib_path_list_get(path_list_index);
+
+ vec_foreach_index (ii, path_list->fpl_paths)
+ {
+ if (!fib_path_cmp_w_route_path(path_list->fpl_paths[ii], rpath))
+ {
+ return (ii);
+ }
+ }
+ return (~0);
+}
+
+
+/*
* fib_path_list_copy_and_path_add
*
* Create a copy of a path-list and append one more path to it.
@@ -783,12 +780,61 @@ fib_path_list_create_special (fib_protocol_t nh_proto,
* can be a shared path-list from the data-base.
*/
fib_node_index_t
+fib_path_list_path_add (fib_node_index_t path_list_index,
+ const fib_route_path_t *rpaths)
+{
+ fib_node_index_t new_path_index, *orig_path_index;
+ fib_path_list_t *path_list;
+
+ /*
+ * alloc the new list before we retrieve the old one, lest
+ * the alloc result in a realloc
+ */
+ path_list = fib_path_list_get(path_list_index);
+
+ ASSERT(1 == vec_len(rpaths));
+ ASSERT(!(path_list->fpl_flags & FIB_PATH_LIST_FLAG_SHARED));
+
+ FIB_PATH_LIST_DBG(orig_path_list, "path-add");
+
+ new_path_index = fib_path_create(path_list_index,
+ rpaths);
+
+ vec_foreach (orig_path_index, path_list->fpl_paths)
+ {
+ /*
+ * don't add duplicate paths
+ */
+ if (0 == fib_path_cmp(new_path_index, *orig_path_index))
+ {
+ return (*orig_path_index);
+ }
+ }
+
+ /*
+ * Add the new path - no sort, no sharing, no key..
+ */
+ vec_add1(path_list->fpl_paths, new_path_index);
+
+ FIB_PATH_LIST_DBG(path_list, "path-added");
+
+ /*
+ * no shared path list requested. resolve and use the one
+ * just created.
+ */
+ fib_path_resolve(new_path_index);
+
+ return (new_path_index);
+}
+
+fib_node_index_t
fib_path_list_copy_and_path_add (fib_node_index_t orig_path_list_index,
- fib_path_list_flags_t flags,
- const fib_route_path_t *rpaths)
+ fib_path_list_flags_t flags,
+ const fib_route_path_t *rpaths)
{
fib_node_index_t path_index, new_path_index, *orig_path_index;
fib_path_list_t *path_list, *orig_path_list;
+ fib_node_index_t exist_path_list_index;
fib_node_index_t path_list_index;
fib_node_index_t pi;
@@ -806,13 +852,11 @@ fib_path_list_copy_and_path_add (fib_node_index_t orig_path_list_index,
flags = fib_path_list_flags_fixup(flags);
path_list->fpl_flags = flags;
- path_list->fpl_nh_proto = orig_path_list->fpl_nh_proto;
+
vec_validate(path_list->fpl_paths, vec_len(orig_path_list->fpl_paths));
pi = 0;
new_path_index = fib_path_create(path_list_index,
- path_list->fpl_nh_proto,
- fib_path_list_flags_2_path_flags(flags),
rpaths);
vec_foreach (orig_path_index, orig_path_list->fpl_paths)
@@ -845,47 +889,80 @@ fib_path_list_copy_and_path_add (fib_node_index_t orig_path_list_index,
FIB_PATH_LIST_DBG(path_list, "path-added");
/*
- * If a shared path list is requested, consult the DB for a match
+ * check for a matching path-list in the DB.
+ * If we find one then we can return the existing one and destroy the
+ * new one just created.
*/
- if (path_list->fpl_flags & FIB_PATH_LIST_FLAG_SHARED)
+ exist_path_list_index = fib_path_list_db_find(path_list);
+ if (FIB_NODE_INDEX_INVALID != exist_path_list_index)
{
- fib_node_index_t exist_path_list_index;
- /*
- * check for a matching path-list in the DB.
- * If we find one then we can return the existing one and destroy the
- * new one just created.
- */
- exist_path_list_index = fib_path_list_db_find(path_list);
- if (FIB_NODE_INDEX_INVALID != exist_path_list_index)
- {
- fib_path_list_destroy(path_list);
+ fib_path_list_destroy(path_list);
- path_list_index = exist_path_list_index;
- }
- else
- {
- /*
- * if there was not a matching path-list, then this
- * new one will need inserting into the DB and resolving.
- */
- fib_path_list_db_insert(path_list_index);
-
- path_list = fib_path_list_resolve(path_list);
- }
+ path_list_index = exist_path_list_index;
}
else
{
- /*
- * no shared path list requested. resolve and use the one
- * just created.
- */
- path_list = fib_path_list_resolve(path_list);
+ /*
+ * if there was not a matching path-list, then this
+ * new one will need inserting into the DB and resolving.
+ */
+ fib_path_list_db_insert(path_list_index);
+
+ path_list = fib_path_list_resolve(path_list);
}
return (path_list_index);
}
/*
+ * fib_path_list_path_remove
+ */
+fib_node_index_t
+fib_path_list_path_remove (fib_node_index_t path_list_index,
+ const fib_route_path_t *rpaths)
+{
+ fib_node_index_t match_path_index, tmp_path_index;
+ fib_path_list_t *path_list;
+ fib_node_index_t pi;
+
+ path_list = fib_path_list_get(path_list_index);
+
+ ASSERT(1 == vec_len(rpaths));
+ ASSERT(!(path_list->fpl_flags & FIB_PATH_LIST_FLAG_SHARED));
+
+ FIB_PATH_LIST_DBG(orig_path_list, "path-remove");
+
+ /*
+ * create a representation of the path to be removed, so it
+ * can be used as a comparison object during the copy.
+ */
+ tmp_path_index = fib_path_create(path_list_index,
+ rpaths);
+ match_path_index = FIB_NODE_INDEX_INVALID;
+
+ vec_foreach_index (pi, path_list->fpl_paths)
+ {
+ if (0 == fib_path_cmp(tmp_path_index,
+ path_list->fpl_paths[pi]))
+ {
+ /*
+ * match - remove it
+ */
+ match_path_index = path_list->fpl_paths[pi];
+ fib_path_destroy(match_path_index);
+ vec_del1(path_list->fpl_paths, pi);
+ }
+ }
+
+ /*
+ * done with the temporary now
+ */
+ fib_path_destroy(tmp_path_index);
+
+ return (match_path_index);
+}
+
+/*
* fib_path_list_copy_and_path_remove
*
* Copy the path-list excluding the path passed.
@@ -911,7 +988,6 @@ fib_path_list_copy_and_path_remove (fib_node_index_t orig_path_list_index,
FIB_PATH_LIST_DBG(orig_path_list, "copy-remove");
path_list->fpl_flags = flags;
- path_list->fpl_nh_proto = orig_path_list->fpl_nh_proto;
/*
* allocate as many paths as we might need in one go, rather than
* using vec_add to do a few at a time.
@@ -927,8 +1003,6 @@ fib_path_list_copy_and_path_remove (fib_node_index_t orig_path_list_index,
* can be used as a comparison object during the copy.
*/
tmp_path_index = fib_path_create(path_list_index,
- path_list->fpl_nh_proto,
- fib_path_list_flags_2_path_flags(flags),
rpaths);
vec_foreach (orig_path_index, orig_path_list->fpl_paths)
diff --git a/src/vnet/fib/fib_path_list.h b/src/vnet/fib/fib_path_list.h
index b4971addfba..9d2462119fb 100644
--- a/src/vnet/fib/fib_path_list.h
+++ b/src/vnet/fib/fib_path_list.h
@@ -39,6 +39,11 @@ typedef enum fib_path_list_attribute_t_ {
*/
FIB_PATH_LIST_ATTRIBUTE_SHARED = FIB_PATH_LIST_ATTRIBUTE_FIRST,
/**
+ * Indexed means the path-list keeps a hash table of all paths for
+ * fast lookup. The lookup result is the fib_node_index of the path.
+ */
+ FIB_PATH_LIST_ATTRIBUTE_INDEXED,
+ /**
* explicit drop path-list. Used when the entry source needs to
* force a drop, despite the fact the path info is present.
*/
@@ -73,6 +78,7 @@ typedef enum fib_path_list_attribute_t_ {
typedef enum fib_path_list_flags_t_ {
FIB_PATH_LIST_FLAG_NONE = 0,
FIB_PATH_LIST_FLAG_SHARED = (1 << FIB_PATH_LIST_ATTRIBUTE_SHARED),
+ FIB_PATH_LIST_FLAG_INDEXED = (1 << FIB_PATH_LIST_ATTRIBUTE_INDEXED),
FIB_PATH_LIST_FLAG_DROP = (1 << FIB_PATH_LIST_ATTRIBUTE_DROP),
FIB_PATH_LIST_FLAG_LOCAL = (1 << FIB_PATH_LIST_ATTRIBUTE_LOCAL),
FIB_PATH_LIST_FLAG_EXCLUSIVE = (1 << FIB_PATH_LIST_ATTRIBUTE_EXCLUSIVE),
@@ -83,10 +89,11 @@ typedef enum fib_path_list_flags_t_ {
#define FIB_PATH_LIST_ATTRIBUTES { \
[FIB_PATH_LIST_ATTRIBUTE_SHARED] = "shared", \
+ [FIB_PATH_LIST_ATTRIBUTE_INDEXED] = "indexed", \
[FIB_PATH_LIST_ATTRIBUTE_RESOLVED] = "resolved", \
[FIB_PATH_LIST_ATTRIBUTE_DROP] = "drop", \
[FIB_PATH_LIST_ATTRIBUTE_EXCLUSIVE] = "exclusive", \
- [FIB_PATH_LIST_ATTRIBUTE_LOCAL] = "local", \
+ [FIB_PATH_LIST_ATTRIBUTE_LOCAL] = "local", \
[FIB_PATH_LIST_ATTRIBUTE_LOOPED] = "looped", \
[FIB_PATH_LIST_ATTRIBUTE_NO_URPF] = "no-uRPF", \
}
@@ -110,6 +117,13 @@ extern fib_node_index_t fib_path_list_copy_and_path_remove(
fib_node_index_t pl_index,
fib_path_list_flags_t flags,
const fib_route_path_t *path);
+extern fib_node_index_t fib_path_list_path_add (
+ fib_node_index_t path_list_index,
+ const fib_route_path_t *rpaths);
+extern fib_node_index_t fib_path_list_path_remove (
+ fib_node_index_t path_list_index,
+ const fib_route_path_t *rpaths);
+
extern u32 fib_path_list_get_n_paths(fib_node_index_t pl_index);
extern void fib_path_list_contribute_forwarding(fib_node_index_t path_list_index,
@@ -137,11 +151,11 @@ extern int fib_path_list_is_looped(fib_node_index_t path_list_index);
extern fib_protocol_t fib_path_list_get_proto(fib_node_index_t path_list_index);
extern u8 * fib_path_list_format(fib_node_index_t pl_index,
u8 * s);
-extern u8 * fib_path_list_adjs_format(fib_node_index_t pl_index,
- u32 indent,
- u8 * s);
extern index_t fib_path_list_lb_map_add_or_lock(fib_node_index_t pl_index,
const fib_node_index_t *pis);
+extern u32 fib_path_list_find_rpath (fib_node_index_t path_list_index,
+ const fib_route_path_t *rpath);
+
/**
* A callback function type for walking a path-list's paths
*/
diff --git a/src/vnet/fib/fib_table.c b/src/vnet/fib/fib_table.c
index 6c3162e7489..b31f35e3520 100644
--- a/src/vnet/fib/fib_table.c
+++ b/src/vnet/fib/fib_table.c
@@ -475,8 +475,21 @@ fib_table_entry_special_remove (u32 fib_index,
*/
static void
fib_table_route_path_fixup (const fib_prefix_t *prefix,
+ fib_entry_flag_t eflags,
fib_route_path_t *path)
{
+ /*
+ * not all zeros next hop &&
+ * is recursive path &&
+ * nexthop is same as the route's address
+ */
+ if ((!ip46_address_is_zero(&path->frp_addr)) &&
+ (~0 == path->frp_sw_if_index) &&
+ (0 == ip46_address_cmp(&path->frp_addr, &prefix->fp_addr)))
+ {
+ /* Prefix recurses via itse;f */
+ path->frp_flags |= FIB_ROUTE_PATH_DROP;
+ }
if (fib_prefix_is_host(prefix) &&
ip46_address_is_zero(&path->frp_addr) &&
path->frp_sw_if_index != ~0)
@@ -484,7 +497,19 @@ fib_table_route_path_fixup (const fib_prefix_t *prefix,
path->frp_addr = prefix->fp_addr;
path->frp_flags |= FIB_ROUTE_PATH_ATTACHED;
}
-}
+ if (eflags & FIB_ENTRY_FLAG_DROP)
+ {
+ path->frp_flags |= FIB_ROUTE_PATH_DROP;
+ }
+ if (eflags & FIB_ENTRY_FLAG_LOCAL)
+ {
+ path->frp_flags |= FIB_ROUTE_PATH_LOCAL;
+ }
+ if (eflags & FIB_ENTRY_FLAG_EXCLUSIVE)
+ {
+ path->frp_flags |= FIB_ROUTE_PATH_EXCLUSIVE;
+ }
+}
fib_node_index_t
fib_table_entry_path_add (u32 fib_index,
@@ -536,7 +561,7 @@ fib_table_entry_path_add2 (u32 fib_index,
for (ii = 0; ii < vec_len(rpath); ii++)
{
- fib_table_route_path_fixup(prefix, &rpath[ii]);
+ fib_table_route_path_fixup(prefix, flags, &rpath[ii]);
}
if (FIB_NODE_INDEX_INVALID == fib_entry_index)
@@ -583,11 +608,6 @@ fib_table_entry_path_remove2 (u32 fib_index,
fib_table = fib_table_get(fib_index, prefix->fp_proto);
fib_entry_index = fib_table_lookup_exact_match_i(fib_table, prefix);
- for (ii = 0; ii < vec_len(rpath); ii++)
- {
- fib_table_route_path_fixup(prefix, &rpath[ii]);
- }
-
if (FIB_NODE_INDEX_INVALID == fib_entry_index)
{
/*
@@ -605,6 +625,15 @@ fib_table_entry_path_remove2 (u32 fib_index,
fib_entry_lock(fib_entry_index);
was_sourced = fib_entry_is_sourced(fib_entry_index, source);
+ for (ii = 0; ii < vec_len(rpath); ii++)
+ {
+ fib_table_route_path_fixup(
+ prefix,
+ fib_entry_get_flags_for_source(fib_entry_index,
+ source),
+ &rpath[ii]);
+ }
+
src_flag = fib_entry_path_remove(fib_entry_index, source, rpath);
if (!(FIB_ENTRY_SRC_FLAG_ADDED & src_flag))
@@ -661,7 +690,6 @@ fib_table_entry_path_remove (u32 fib_index,
};
fib_route_path_t *paths = NULL;
- fib_table_route_path_fixup(prefix, &path);
vec_add1(paths, path);
fib_table_entry_path_remove2(fib_index, prefix, source, paths);
@@ -692,7 +720,7 @@ fib_table_entry_update (u32 fib_index,
for (ii = 0; ii < vec_len(paths); ii++)
{
- fib_table_route_path_fixup(prefix, &paths[ii]);
+ fib_table_route_path_fixup(prefix, flags, &paths[ii]);
}
/*
* sort the paths provided by the control plane. this means
@@ -750,7 +778,6 @@ fib_table_entry_update_one_path (u32 fib_index,
};
fib_route_path_t *paths = NULL;
- fib_table_route_path_fixup(prefix, &path);
vec_add1(paths, path);
fib_entry_index =
diff --git a/src/vnet/fib/fib_test.c b/src/vnet/fib/fib_test.c
index 3c9b8a38fe1..e4a8a70e0d0 100644
--- a/src/vnet/fib/fib_test.c
+++ b/src/vnet/fib/fib_test.c
@@ -25,6 +25,8 @@
#include <vnet/dpo/receive_dpo.h>
#include <vnet/dpo/ip_null_dpo.h>
#include <vnet/bfd/bfd_main.h>
+#include <vnet/dpo/interface_dpo.h>
+#include <vnet/dpo/replicate_dpo.h>
#include <vnet/mpls/mpls.h>
@@ -271,6 +273,7 @@ typedef enum fib_test_lb_bucket_type_t_ {
FT_LB_O_LB,
FT_LB_SPECIAL,
FT_LB_ADJ,
+ FT_LB_INTF,
} fib_test_lb_bucket_type_t;
typedef struct fib_test_lb_bucket_t_ {
@@ -315,6 +318,31 @@ typedef struct fib_test_lb_bucket_t_ {
};
} fib_test_lb_bucket_t;
+typedef enum fib_test_rep_bucket_type_t_ {
+ FT_REP_LABEL_O_ADJ,
+ FT_REP_DISP_MFIB_LOOKUP,
+ FT_REP_INTF,
+} fib_test_rep_bucket_type_t;
+
+typedef struct fib_test_rep_bucket_t_ {
+ fib_test_rep_bucket_type_t type;
+
+ union
+ {
+ struct
+ {
+ mpls_eos_bit_t eos;
+ mpls_label_t label;
+ u8 ttl;
+ adj_index_t adj;
+ } label_o_adj;
+ struct
+ {
+ adj_index_t adj;
+ } adj;
+ };
+} fib_test_rep_bucket_t;
+
#define FIB_TEST_LB(_cond, _comment, _args...) \
{ \
if (!FIB_TEST_I(_cond, _comment, ##_args)) { \
@@ -322,7 +350,83 @@ typedef struct fib_test_lb_bucket_t_ {
} \
}
-static int
+int
+fib_test_validate_rep_v (const replicate_t *rep,
+ u16 n_buckets,
+ va_list ap)
+{
+ const fib_test_rep_bucket_t *exp;
+ const dpo_id_t *dpo;
+ int bucket;
+
+ FIB_TEST_LB((n_buckets == rep->rep_n_buckets),
+ "n_buckets = %d", rep->rep_n_buckets);
+
+ for (bucket = 0; bucket < n_buckets; bucket++)
+ {
+ exp = va_arg(ap, fib_test_rep_bucket_t*);
+
+ dpo = replicate_get_bucket_i(rep, bucket);
+
+ switch (exp->type)
+ {
+ case FT_REP_LABEL_O_ADJ:
+ {
+ const mpls_label_dpo_t *mld;
+ mpls_label_t hdr;
+ FIB_TEST_LB((DPO_MPLS_LABEL == dpo->dpoi_type),
+ "bucket %d stacks on %U",
+ bucket,
+ format_dpo_type, dpo->dpoi_type);
+
+ mld = mpls_label_dpo_get(dpo->dpoi_index);
+ hdr = clib_net_to_host_u32(mld->mld_hdr[0].label_exp_s_ttl);
+
+ FIB_TEST_LB((vnet_mpls_uc_get_label(hdr) ==
+ exp->label_o_adj.label),
+ "bucket %d stacks on label %d",
+ bucket,
+ exp->label_o_adj.label);
+
+ FIB_TEST_LB((vnet_mpls_uc_get_s(hdr) ==
+ exp->label_o_adj.eos),
+ "bucket %d stacks on label %d %U",
+ bucket,
+ exp->label_o_adj.label,
+ format_mpls_eos_bit, exp->label_o_adj.eos);
+
+ FIB_TEST_LB((DPO_ADJACENCY_INCOMPLETE == mld->mld_dpo.dpoi_type),
+ "bucket %d label stacks on %U",
+ bucket,
+ format_dpo_type, mld->mld_dpo.dpoi_type);
+
+ FIB_TEST_LB((exp->label_o_adj.adj == mld->mld_dpo.dpoi_index),
+ "bucket %d label stacks on adj %d",
+ bucket,
+ exp->label_o_adj.adj);
+ }
+ break;
+ case FT_REP_INTF:
+ FIB_TEST_LB((DPO_INTERFACE == dpo->dpoi_type),
+ "bucket %d stacks on %U",
+ bucket,
+ format_dpo_type, dpo->dpoi_type);
+
+ FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
+ "bucket %d stacks on adj %d",
+ bucket,
+ exp->adj.adj);
+ break;
+ case FT_REP_DISP_MFIB_LOOKUP:
+// ASSERT(0);
+ break;
+ }
+ }
+
+ return (!0);
+}
+
+int
fib_test_validate_lb_v (const load_balance_t *lb,
u16 n_buckets,
va_list ap)
@@ -484,6 +588,16 @@ fib_test_validate_lb_v (const load_balance_t *lb,
bucket,
exp->adj.adj);
break;
+ case FT_LB_INTF:
+ FIB_TEST_I((DPO_INTERFACE == dpo->dpoi_type),
+ "bucket %d stacks on %U",
+ bucket,
+ format_dpo_type, dpo->dpoi_type);
+ FIB_TEST_LB((exp->adj.adj == dpo->dpoi_index),
+ "bucket %d stacks on adj %d",
+ bucket,
+ exp->adj.adj);
+ break;
case FT_LB_O_LB:
FIB_TEST_I((DPO_LOAD_BALANCE == dpo->dpoi_type),
"bucket %d stacks on %U",
@@ -509,14 +623,13 @@ fib_test_validate_lb_v (const load_balance_t *lb,
return (!0);
}
-static int
+int
fib_test_validate_entry (fib_node_index_t fei,
fib_forward_chain_type_t fct,
u16 n_buckets,
...)
{
dpo_id_t dpo = DPO_INVALID;
- const load_balance_t *lb;
fib_prefix_t pfx;
index_t fw_lbi;
u32 fib_index;
@@ -529,47 +642,59 @@ fib_test_validate_entry (fib_node_index_t fei,
fib_index = fib_entry_get_fib_index(fei);
fib_entry_contribute_forwarding(fei, fct, &dpo);
- FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
- "Entry links to %U",
- format_dpo_type, dpo.dpoi_type);
- lb = load_balance_get(dpo.dpoi_index);
-
- res = fib_test_validate_lb_v(lb, n_buckets, ap);
+ if (DPO_REPLICATE == dpo.dpoi_type)
+ {
+ const replicate_t *rep;
- /*
- * ensure that the LB contributed by the entry is the
- * same as the LB in the forwarding tables
- */
- if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
+ rep = replicate_get(dpo.dpoi_index);
+ res = fib_test_validate_rep_v(rep, n_buckets, ap);
+ }
+ else
{
- switch (pfx.fp_proto)
- {
- case FIB_PROTOCOL_IP4:
- fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
- break;
- case FIB_PROTOCOL_IP6:
- fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
- break;
- case FIB_PROTOCOL_MPLS:
- {
- mpls_unicast_header_t hdr = {
- .label_exp_s_ttl = 0,
- };
+ const load_balance_t *lb;
+
+ FIB_TEST_LB((DPO_LOAD_BALANCE == dpo.dpoi_type),
+ "Entry links to %U",
+ format_dpo_type, dpo.dpoi_type);
- vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
- vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
- hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
+ lb = load_balance_get(dpo.dpoi_index);
+ res = fib_test_validate_lb_v(lb, n_buckets, ap);
- fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
+ /*
+ * ensure that the LB contributed by the entry is the
+ * same as the LB in the forwarding tables
+ */
+ if (fct == fib_entry_get_default_chain_type(fib_entry_get(fei)))
+ {
+ switch (pfx.fp_proto)
+ {
+ case FIB_PROTOCOL_IP4:
+ fw_lbi = ip4_fib_forwarding_lookup(fib_index, &pfx.fp_addr.ip4);
+ break;
+ case FIB_PROTOCOL_IP6:
+ fw_lbi = ip6_fib_table_fwding_lookup(&ip6_main, fib_index, &pfx.fp_addr.ip6);
break;
+ case FIB_PROTOCOL_MPLS:
+ {
+ mpls_unicast_header_t hdr = {
+ .label_exp_s_ttl = 0,
+ };
+
+ vnet_mpls_uc_set_label(&hdr.label_exp_s_ttl, pfx.fp_label);
+ vnet_mpls_uc_set_s(&hdr.label_exp_s_ttl, pfx.fp_eos);
+ hdr.label_exp_s_ttl = clib_host_to_net_u32(hdr.label_exp_s_ttl);
+
+ fw_lbi = mpls_fib_table_forwarding_lookup(fib_index, &hdr);
+ break;
+ }
+ default:
+ fw_lbi = 0;
}
- default:
- fw_lbi = 0;
+ FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
+ "Contributed LB = FW LB: %U\n %U",
+ format_load_balance, fw_lbi, 0,
+ format_load_balance, dpo.dpoi_index, 0);
}
- FIB_TEST_LB((fw_lbi == dpo.dpoi_index),
- "Contributed LB = FW LB: %U\n %U",
- format_load_balance, fw_lbi, 0,
- format_load_balance, dpo.dpoi_index, 0);
}
dpo_reset(&dpo);
@@ -1289,6 +1414,7 @@ fib_test_v4 (void)
lookup_dpo_add_or_lock_w_fib_index(fib_index,
DPO_PROTO_IP4,
+ LOOKUP_UNICAST,
LOOKUP_INPUT_DST_ADDR,
LOOKUP_TABLE_FROM_CONFIG,
&ex_dpo);
@@ -2605,7 +2731,6 @@ fib_test_v4 (void)
NULL,
FIB_ROUTE_PATH_FLAG_NONE);
-
fei = fib_table_lookup(fib_index, &pfx_5_5_5_6_s_32);
dpo1 = fib_entry_contribute_ip_forwarding(fei);
@@ -7493,6 +7618,7 @@ lfib_test (void)
fib_route_path_t *rpaths = NULL, rpath = {
.frp_proto = FIB_PROTOCOL_MPLS,
.frp_local_label = 1200,
+ .frp_eos = MPLS_NON_EOS,
.frp_sw_if_index = ~0, // recurive
.frp_fib_index = 0, // Default MPLS fib
.frp_weight = 1,
@@ -7608,6 +7734,146 @@ lfib_test (void)
dpo_reset(&ip_1200);
/*
+ * An rx-interface route.
+ * like the tail of an mcast LSP
+ */
+ dpo_id_t idpo = DPO_INVALID;
+
+ interface_dpo_add_or_lock(DPO_PROTO_IP4,
+ tm->hw[0]->sw_if_index,
+ &idpo);
+
+ fib_prefix_t pfx_2500 = {
+ .fp_len = 21,
+ .fp_proto = FIB_PROTOCOL_MPLS,
+ .fp_label = 2500,
+ .fp_eos = MPLS_EOS,
+ .fp_payload_proto = DPO_PROTO_IP4,
+ };
+ fib_test_lb_bucket_t rx_intf_0 = {
+ .type = FT_LB_INTF,
+ .adj = {
+ .adj = idpo.dpoi_index,
+ },
+ };
+
+ lfe = fib_table_entry_update_one_path(fib_index,
+ &pfx_2500,
+ FIB_SOURCE_API,
+ FIB_ENTRY_FLAG_NONE,
+ FIB_PROTOCOL_IP4,
+ NULL,
+ tm->hw[0]->sw_if_index,
+ ~0, // invalid fib index
+ 0,
+ NULL,
+ FIB_ROUTE_PATH_INTF_RX);
+ FIB_TEST(fib_test_validate_entry(lfe,
+ FIB_FORW_CHAIN_TYPE_MPLS_EOS,
+ 1,
+ &rx_intf_0),
+ "2500 rx-interface 0");
+ fib_table_entry_delete(fib_index, &pfx_2500, FIB_SOURCE_API);
+
+ /*
+ * An MPLS mulicast entry
+ */
+ fib_prefix_t pfx_3500 = {
+ .fp_len = 21,
+ .fp_proto = FIB_PROTOCOL_MPLS,
+ .fp_label = 3500,
+ .fp_eos = MPLS_EOS,
+ .fp_payload_proto = DPO_PROTO_IP4,
+ };
+ fib_test_rep_bucket_t mc_0 = {
+ .type = FT_REP_LABEL_O_ADJ,
+ .label_o_adj = {
+ .adj = ai_mpls_10_10_10_1,
+ .label = 3300,
+ .eos = MPLS_EOS,
+ },
+ };
+ fib_test_rep_bucket_t mc_intf_0 = {
+ .type = FT_REP_INTF,
+ .adj = {
+ .adj = idpo.dpoi_index,
+ },
+ };
+ mpls_label_t *l3300 = NULL;
+ vec_add1(l3300, 3300);
+
+ lfe = fib_table_entry_update_one_path(lfib_index,
+ &pfx_3500,
+ FIB_SOURCE_API,
+ FIB_ENTRY_FLAG_MULTICAST,
+ FIB_PROTOCOL_IP4,
+ &nh_10_10_10_1,
+ tm->hw[0]->sw_if_index,
+ ~0, // invalid fib index
+ 1,
+ l3300,
+ FIB_ROUTE_PATH_FLAG_NONE);
+ FIB_TEST(fib_test_validate_entry(lfe,
+ FIB_FORW_CHAIN_TYPE_MPLS_EOS,
+ 1,
+ &mc_0),
+ "3500 via replicate over 10.10.10.1");
+
+ /*
+ * MPLS Bud-node. Add a replication via an interface-receieve path
+ */
+ lfe = fib_table_entry_path_add(lfib_index,
+ &pfx_3500,
+ FIB_SOURCE_API,
+ FIB_ENTRY_FLAG_MULTICAST,
+ FIB_PROTOCOL_IP4,
+ NULL,
+ tm->hw[0]->sw_if_index,
+ ~0, // invalid fib index
+ 0,
+ NULL,
+ FIB_ROUTE_PATH_INTF_RX);
+ FIB_TEST(fib_test_validate_entry(lfe,
+ FIB_FORW_CHAIN_TYPE_MPLS_EOS,
+ 2,
+ &mc_0,
+ &mc_intf_0),
+ "3500 via replicate over 10.10.10.1 and interface-rx");
+
+ /*
+ * Add a replication via an interface-free for-us path
+ */
+ fib_test_rep_bucket_t mc_disp = {
+ .type = FT_REP_DISP_MFIB_LOOKUP,
+ .adj = {
+ .adj = idpo.dpoi_index,
+ },
+ };
+ lfe = fib_table_entry_path_add(lfib_index,
+ &pfx_3500,
+ FIB_SOURCE_API,
+ FIB_ENTRY_FLAG_MULTICAST,
+ FIB_PROTOCOL_IP4,
+ NULL,
+ 5, // rpf-id
+ 0, // default table
+ 0,
+ NULL,
+ FIB_ROUTE_PATH_RPF_ID);
+ FIB_TEST(fib_test_validate_entry(lfe,
+ FIB_FORW_CHAIN_TYPE_MPLS_EOS,
+ 3,
+ &mc_0,
+ &mc_disp,
+ &mc_intf_0),
+ "3500 via replicate over 10.10.10.1 and interface-rx");
+
+
+
+ fib_table_entry_delete(fib_index, &pfx_3500, FIB_SOURCE_API);
+ dpo_reset(&idpo);
+
+ /*
* cleanup
*/
mpls_sw_interface_enable_disable(&mpls_main,
@@ -7617,6 +7883,9 @@ lfib_test (void)
FIB_TEST(lb_count == pool_elts(load_balance_pool),
"Load-balance resources freed %d of %d",
lb_count, pool_elts(load_balance_pool));
+ FIB_TEST(0 == pool_elts(interface_dpo_pool),
+ "interface_dpo resources freed %d of %d",
+ 0, pool_elts(interface_dpo_pool));
return (0);
}
diff --git a/src/vnet/fib/fib_test.h b/src/vnet/fib/fib_test.h
new file mode 100644
index 00000000000..b98680bf683
--- /dev/null
+++ b/src/vnet/fib/fib_test.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __FIB_TEST_H__
+#define __FIB_TEST_H__
+
+#include <vnet/fib/fib_types.h>
+
+typedef enum fib_test_lb_bucket_type_t_ {
+ FT_LB_LABEL_O_ADJ,
+ FT_LB_LABEL_STACK_O_ADJ,
+ FT_LB_LABEL_O_LB,
+ FT_LB_O_LB,
+ FT_LB_SPECIAL,
+ FT_LB_ADJ,
+ FT_LB_INTF,
+} fib_test_lb_bucket_type_t;
+
+typedef struct fib_test_lb_bucket_t_ {
+ fib_test_lb_bucket_type_t type;
+
+ union
+ {
+ struct
+ {
+ mpls_eos_bit_t eos;
+ mpls_label_t label;
+ u8 ttl;
+ adj_index_t adj;
+ } label_o_adj;
+ struct
+ {
+ mpls_eos_bit_t eos;
+ mpls_label_t label_stack[8];
+ u8 label_stack_size;
+ u8 ttl;
+ adj_index_t adj;
+ } label_stack_o_adj;
+ struct
+ {
+ mpls_eos_bit_t eos;
+ mpls_label_t label;
+ u8 ttl;
+ index_t lb;
+ } label_o_lb;
+ struct
+ {
+ index_t adj;
+ } adj;
+ struct
+ {
+ index_t lb;
+ } lb;
+ struct
+ {
+ index_t adj;
+ } special;
+ };
+} fib_test_lb_bucket_t;
+
+typedef enum fib_test_rep_bucket_type_t_ {
+ FT_REP_LABEL_O_ADJ,
+ FT_REP_INTF,
+} fib_test_rep_bucket_type_t;
+
+typedef struct fib_test_rep_bucket_t_ {
+ fib_test_rep_bucket_type_t type;
+
+ union
+ {
+ struct
+ {
+ mpls_eos_bit_t eos;
+ mpls_label_t label;
+ u8 ttl;
+ adj_index_t adj;
+ } label_o_adj;
+ struct
+ {
+ adj_index_t adj;
+ } adj;
+ };
+} fib_test_rep_bucket_t;
+
+
+extern int fib_test_validate_rep_v(const replicate_t *rep,
+ u16 n_buckets,
+ va_list ap);
+
+extern int fib_test_validate_lb_v(const load_balance_t *lb,
+ u16 n_buckets,
+ va_list ap);
+
+extern int fib_test_validate_entry(fib_node_index_t fei,
+ fib_forward_chain_type_t fct,
+ u16 n_buckets,
+ ...);
+
+#endif
diff --git a/src/vnet/fib/fib_types.c b/src/vnet/fib/fib_types.c
index 2837a59db01..8165f3eb313 100644
--- a/src/vnet/fib/fib_types.c
+++ b/src/vnet/fib/fib_types.c
@@ -66,12 +66,13 @@ fib_prefix_from_ip46_addr (const ip46_address_t *addr,
void
fib_prefix_from_mpls_label (mpls_label_t label,
+ mpls_eos_bit_t eos,
fib_prefix_t *pfx)
{
pfx->fp_proto = FIB_PROTOCOL_MPLS;
pfx->fp_len = 21;
pfx->fp_label = label;
- pfx->fp_eos = MPLS_NON_EOS;
+ pfx->fp_eos = eos;
}
int
@@ -194,17 +195,7 @@ fib_route_path_cmp (const fib_route_path_t *rpath1,
if (0 != res) return (res);
- if (~0 != rpath1->frp_sw_if_index &&
- ~0 != rpath2->frp_sw_if_index)
- {
- res = vnet_sw_interface_compare(vnet_get_main(),
- rpath1->frp_sw_if_index,
- rpath2->frp_sw_if_index);
- }
- else
- {
- res = rpath1->frp_sw_if_index - rpath2->frp_sw_if_index;
- }
+ res = (rpath1->frp_sw_if_index - rpath2->frp_sw_if_index);
if (0 != res) return (res);
diff --git a/src/vnet/fib/fib_types.h b/src/vnet/fib/fib_types.h
index 1c5299a9214..4cb73e8a7a6 100644
--- a/src/vnet/fib/fib_types.h
+++ b/src/vnet/fib/fib_types.h
@@ -286,9 +286,37 @@ typedef enum fib_route_path_flags_t_
* Attached path
*/
FIB_ROUTE_PATH_ATTACHED = (1 << 3),
+ /**
+ * A Drop path - resolve the path on the drop DPO
+ */
+ FIB_ROUTE_PATH_DROP = (1 << 4),
+ /**
+ * Don't resolve the path, use the DPO the client provides
+ */
+ FIB_ROUTE_PATH_EXCLUSIVE = (1 << 5),
+ /**
+ * A path that result in received traffic being recieved/recirculated
+ * so that it appears to have arrived on the new interface
+ */
+ FIB_ROUTE_PATH_INTF_RX = (1 << 6),
+ /**
+ * A local path with a RPF-ID => multicast traffic
+ */
+ FIB_ROUTE_PATH_RPF_ID = (1 << 7),
} fib_route_path_flags_t;
/**
+ * An RPF-ID is numerical value that is used RPF validate. An entry
+ * has-a RPF-ID, when a packet egress from (e.g. an LSP) it gains an
+ * RPF-ID, these two are compared for the RPF check.
+ * This replaces the interfce based chack (since the LSP has no associated
+ * interface.
+ */
+typedef u32 fib_rpf_id_t;
+
+#define MFIB_RPF_ID_NONE (0)
+
+/**
* @brief
* A representation of a path as described by a route producer.
* These paramenters will determine the path 'type', of which there are:
@@ -321,17 +349,29 @@ typedef struct fib_route_path_t_ {
*/
ip46_address_t frp_addr;
- /**
- * The MPLS local Label to reursively resolve through.
- * This is valid when the path type is MPLS.
- */
- mpls_label_t frp_local_label;
+ struct {
+ /**
+ * The MPLS local Label to reursively resolve through.
+ * This is valid when the path type is MPLS.
+ */
+ mpls_label_t frp_local_label;
+ /**
+ * EOS bit for the resolving label
+ */
+ mpls_eos_bit_t frp_eos;
+ };
+ };
+ union {
+ /**
+ * The interface.
+ * Will be invalid for recursive paths.
+ */
+ u32 frp_sw_if_index;
+ /**
+ * The RPF-ID
+ */
+ fib_rpf_id_t frp_rpf_id;
};
- /**
- * The interface.
- * Will be invalid for recursive paths.
- */
- u32 frp_sw_if_index;
/**
* The FIB index to lookup the nexthop
* Only valid for recursive paths.
diff --git a/src/vnet/fib/mpls_fib.c b/src/vnet/fib/mpls_fib.c
index 4b2b76ea154..19f9f3c1432 100644
--- a/src/vnet/fib/mpls_fib.c
+++ b/src/vnet/fib/mpls_fib.c
@@ -165,6 +165,7 @@ mpls_fib_create_with_table_id (u32 table_id)
lookup_dpo_add_or_lock_w_fib_index(0, // unused
DPO_PROTO_IP4,
+ LOOKUP_UNICAST,
LOOKUP_INPUT_DST_ADDR,
LOOKUP_TABLE_FROM_INPUT_INTERFACE,
&dpo);
@@ -179,6 +180,7 @@ mpls_fib_create_with_table_id (u32 table_id)
lookup_dpo_add_or_lock_w_fib_index(0, //unsued
DPO_PROTO_MPLS,
+ LOOKUP_UNICAST,
LOOKUP_INPUT_DST_ADDR,
LOOKUP_TABLE_FROM_INPUT_INTERFACE,
&dpo);
@@ -197,6 +199,7 @@ mpls_fib_create_with_table_id (u32 table_id)
lookup_dpo_add_or_lock_w_fib_index(0, //unused
DPO_PROTO_IP6,
+ LOOKUP_UNICAST,
LOOKUP_INPUT_DST_ADDR,
LOOKUP_TABLE_FROM_INPUT_INTERFACE,
&dpo);
@@ -210,6 +213,7 @@ mpls_fib_create_with_table_id (u32 table_id)
prefix.fp_eos = MPLS_NON_EOS;
lookup_dpo_add_or_lock_w_fib_index(0, // unsued
DPO_PROTO_MPLS,
+ LOOKUP_UNICAST,
LOOKUP_INPUT_DST_ADDR,
LOOKUP_TABLE_FROM_INPUT_INTERFACE,
&dpo);
@@ -320,8 +324,15 @@ mpls_fib_forwarding_table_update (mpls_fib_t *mf,
{
mpls_label_t key;
- ASSERT(DPO_LOAD_BALANCE == dpo->dpoi_type);
-
+ ASSERT((DPO_LOAD_BALANCE == dpo->dpoi_type) ||
+ (DPO_REPLICATE == dpo->dpoi_type));
+ if (CLIB_DEBUG > 0)
+ {
+ if (DPO_REPLICATE == dpo->dpoi_type)
+ ASSERT(dpo->dpoi_index & MPLS_IS_REPLICATE);
+ if (DPO_LOAD_BALANCE == dpo->dpoi_type)
+ ASSERT(!(dpo->dpoi_index & MPLS_IS_REPLICATE));
+ }
key = mpls_fib_entry_mk_key(label, eos);
mf->mf_lbs[key] = dpo->dpoi_index;
diff --git a/src/vnet/handoff.h b/src/vnet/handoff.h
index 815206a9f8c..04ba8bfbc02 100644
--- a/src/vnet/handoff.h
+++ b/src/vnet/handoff.h
@@ -150,7 +150,7 @@ eth_get_sym_key (ethernet_header_t * h0)
ip->dst_address.as_u64[0] ^
ip->dst_address.as_u64[1] ^ ip->protocol);
}
- else if (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS_UNICAST))
+ else if (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS))
{
hash_key = mpls_get_key ((mpls_unicast_header_t *) (h0 + 1));
}
@@ -179,8 +179,7 @@ eth_get_sym_key (ethernet_header_t * h0)
ip->dst_address.as_u64[0] ^
ip->dst_address.as_u64[1] ^ ip->protocol);
}
- else if (outer->type ==
- clib_host_to_net_u16 (ETHERNET_TYPE_MPLS_UNICAST))
+ else if (outer->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS))
{
hash_key = mpls_get_key ((mpls_unicast_header_t *) (outer + 1));
}
@@ -210,7 +209,7 @@ eth_get_key (ethernet_header_t * h0)
{
hash_key = ipv6_get_key ((ip6_header_t *) (h0 + 1));
}
- else if (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS_UNICAST))
+ else if (h0->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS))
{
hash_key = mpls_get_key ((mpls_unicast_header_t *) (h0 + 1));
}
@@ -230,8 +229,7 @@ eth_get_key (ethernet_header_t * h0)
{
hash_key = ipv6_get_key ((ip6_header_t *) (outer + 1));
}
- else if (outer->type ==
- clib_host_to_net_u16 (ETHERNET_TYPE_MPLS_UNICAST))
+ else if (outer->type == clib_host_to_net_u16 (ETHERNET_TYPE_MPLS))
{
hash_key = mpls_get_key ((mpls_unicast_header_t *) (outer + 1));
}
diff --git a/src/vnet/interface.c b/src/vnet/interface.c
index 2a1e70e8927..45417b2f5c0 100644
--- a/src/vnet/interface.c
+++ b/src/vnet/interface.c
@@ -1360,7 +1360,7 @@ vnet_link_to_l3_proto (vnet_link_t link)
case VNET_LINK_IP6:
return (VNET_L3_PACKET_TYPE_IP6);
case VNET_LINK_MPLS:
- return (VNET_L3_PACKET_TYPE_MPLS_UNICAST);
+ return (VNET_L3_PACKET_TYPE_MPLS);
case VNET_LINK_ARP:
return (VNET_L3_PACKET_TYPE_ARP);
case VNET_LINK_ETHERNET:
diff --git a/src/vnet/ip/ip.api b/src/vnet/ip/ip.api
index 5c2df32cfd0..6af1714f34d 100644
--- a/src/vnet/ip/ip.api
+++ b/src/vnet/ip/ip.api
@@ -478,6 +478,7 @@ define ip_mroute_add_del
u32 table_id;
u32 entry_flags;
u32 itf_flags;
+ u32 rpf_id;
u16 grp_address_length;
u8 create_vrf_if_needed;
u8 is_add;
@@ -518,6 +519,8 @@ manual_endian manual_print define ip_mfib_details
{
u32 context;
u32 table_id;
+ u32 entry_flags;
+ u32 rpf_id;
u8 address_length;
u8 grp_address[4];
u8 src_address[4];
diff --git a/src/vnet/ip/ip4_forward.c b/src/vnet/ip/ip4_forward.c
index fdfe7f63dfc..9fdf9b3cee1 100644
--- a/src/vnet/ip/ip4_forward.c
+++ b/src/vnet/ip/ip4_forward.c
@@ -2752,6 +2752,16 @@ ip4_rewrite_mcast (vlib_main_t * vm,
return ip4_rewrite_inline (vm, node, frame, 0, 0, 1);
}
+static uword
+ip4_mcast_midchain (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ if (adj_are_counters_enabled ())
+ return ip4_rewrite_inline (vm, node, frame, 1, 1, 1);
+ else
+ return ip4_rewrite_inline (vm, node, frame, 0, 1, 1);
+}
+
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip4_rewrite_node) = {
.function = ip4_rewrite,
@@ -2778,6 +2788,16 @@ VLIB_REGISTER_NODE (ip4_rewrite_mcast_node) = {
};
VLIB_NODE_FUNCTION_MULTIARCH (ip4_rewrite_mcast_node, ip4_rewrite_mcast)
+VLIB_REGISTER_NODE (ip4_mcast_midchain_node, static) = {
+ .function = ip4_mcast_midchain,
+ .name = "ip4-mcast-midchain",
+ .vector_size = sizeof (u32),
+
+ .format_trace = format_ip4_rewrite_trace,
+ .sibling_of = "ip4-rewrite",
+};
+VLIB_NODE_FUNCTION_MULTIARCH (ip4_mcast_midchain_node, ip4_mcast_midchain)
+
VLIB_REGISTER_NODE (ip4_midchain_node) = {
.function = ip4_midchain,
.name = "ip4-midchain",
diff --git a/src/vnet/ip/ip6_forward.c b/src/vnet/ip/ip6_forward.c
index c2fc4f873f2..a369f79fbb8 100644
--- a/src/vnet/ip/ip6_forward.c
+++ b/src/vnet/ip/ip6_forward.c
@@ -2246,6 +2246,16 @@ ip6_midchain (vlib_main_t * vm,
return ip6_rewrite_inline (vm, node, frame, 0, 1, 0);
}
+static uword
+ip6_mcast_midchain (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ if (adj_are_counters_enabled ())
+ return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
+ else
+ return ip6_rewrite_inline (vm, node, frame, 1, 1, 1);
+}
+
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (ip6_midchain_node) =
{
@@ -2290,6 +2300,19 @@ VLIB_REGISTER_NODE (ip6_rewrite_mcast_node) =
VLIB_NODE_FUNCTION_MULTIARCH (ip6_rewrite_mcast_node, ip6_rewrite_mcast);
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (ip6_mcast_midchain_node, static) =
+{
+ .function = ip6_mcast_midchain,
+ .name = "ip6-mcast-midchain",
+ .vector_size = sizeof (u32),
+ .format_trace = format_ip6_rewrite_trace,
+ .sibling_of = "ip6-rewrite",
+};
+/* *INDENT-ON* */
+
+VLIB_NODE_FUNCTION_MULTIARCH (ip6_mcast_midchain_node, ip6_mcast_midchain);
+
/*
* Hop-by-Hop handling
*/
diff --git a/src/vnet/ip/ip6_neighbor.c b/src/vnet/ip/ip6_neighbor.c
index 2af546df8de..58b997aa0db 100644
--- a/src/vnet/ip/ip6_neighbor.c
+++ b/src/vnet/ip/ip6_neighbor.c
@@ -557,6 +557,7 @@ ip6_ethernet_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
case IP_LOOKUP_NEXT_PUNT:
case IP_LOOKUP_NEXT_LOCAL:
case IP_LOOKUP_NEXT_REWRITE:
+ case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
case IP_LOOKUP_NEXT_MIDCHAIN:
case IP_LOOKUP_NEXT_ICMP_ERROR:
case IP_LOOKUP_N_NEXT:
diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c
index b9f1782b342..9c9cb4a445a 100644
--- a/src/vnet/ip/ip_api.c
+++ b/src/vnet/ip/ip_api.c
@@ -438,17 +438,20 @@ vl_api_ip6_fib_dump_t_handler (vl_api_ip6_fib_dump_t * mp)
}
static void
-send_ip_mfib_details (vpe_api_main_t * am,
- unix_shared_memory_queue_t * q,
- u32 table_id,
- mfib_prefix_t * pfx,
- fib_route_path_encode_t * api_rpaths, u32 context)
+send_ip_mfib_details (unix_shared_memory_queue_t * q,
+ u32 context, u32 table_id, fib_node_index_t mfei)
{
+ fib_route_path_encode_t *api_rpath, *api_rpaths = NULL;
vl_api_ip_mfib_details_t *mp;
- fib_route_path_encode_t *api_rpath;
+ mfib_entry_t *mfib_entry;
vl_api_fib_path_t *fp;
+ mfib_prefix_t pfx;
int path_count;
+ mfib_entry = mfib_entry_get (mfei);
+ mfib_entry_get_prefix (mfei, &pfx);
+ mfib_entry_encode (mfei, &api_rpaths);
+
path_count = vec_len (api_rpaths);
mp = vl_msg_api_alloc (sizeof (*mp) + path_count * sizeof (*fp));
if (!mp)
@@ -457,12 +460,14 @@ send_ip_mfib_details (vpe_api_main_t * am,
mp->_vl_msg_id = ntohs (VL_API_IP_FIB_DETAILS);
mp->context = context;
+ mp->rpf_id = mfib_entry->mfe_rpf_id;
+ mp->entry_flags = mfib_entry->mfe_flags;
mp->table_id = htonl (table_id);
- mp->address_length = pfx->fp_len;
- memcpy (mp->grp_address, &pfx->fp_grp_addr.ip4,
- sizeof (pfx->fp_grp_addr.ip4));
- memcpy (mp->src_address, &pfx->fp_src_addr.ip4,
- sizeof (pfx->fp_src_addr.ip4));
+ mp->address_length = pfx.fp_len;
+ memcpy (mp->grp_address, &pfx.fp_grp_addr.ip4,
+ sizeof (pfx.fp_grp_addr.ip4));
+ memcpy (mp->src_address, &pfx.fp_src_addr.ip4,
+ sizeof (pfx.fp_src_addr.ip4));
mp->count = htonl (path_count);
fp = mp->path;
@@ -475,6 +480,7 @@ send_ip_mfib_details (vpe_api_main_t * am,
copy_fib_next_hop (api_rpath, fp);
fp++;
}
+ vec_free (api_rpaths);
vl_msg_api_send_shmem (q, (u8 *) & mp);
}
@@ -497,13 +503,10 @@ vl_api_ip_mfib_table_dump_walk (fib_node_index_t fei, void *arg)
static void
vl_api_ip_mfib_dump_t_handler (vl_api_ip_mfib_dump_t * mp)
{
- vpe_api_main_t *am = &vpe_api_main;
unix_shared_memory_queue_t *q;
ip4_main_t *im = &ip4_main;
mfib_table_t *mfib_table;
fib_node_index_t *mfeip;
- mfib_prefix_t pfx;
- fib_route_path_encode_t *api_rpaths = NULL;
vl_api_ip_mfib_dump_ctc_t ctx = {
.entries = NULL,
};
@@ -524,21 +527,16 @@ vl_api_ip_mfib_dump_t_handler (vl_api_ip_mfib_dump_t * mp)
vec_foreach (mfeip, ctx.entries)
{
- mfib_entry_get_prefix (*mfeip, &pfx);
- mfib_entry_encode (*mfeip, &api_rpaths);
- send_ip_mfib_details (am, q,
+ send_ip_mfib_details (q, mp->context,
mfib_table->mft_table_id,
- &pfx, api_rpaths,
- mp->context);
+ *mfeip);
}
- vec_reset_length (api_rpaths);
vec_reset_length (ctx.entries);
}));
/* *INDENT-ON* */
vec_free (ctx.entries);
- vec_free (api_rpaths);
}
static void
@@ -705,10 +703,13 @@ add_del_route_t_handler (u8 is_multipath,
u8 is_unreach,
u8 is_prohibit,
u8 is_local,
+ u8 is_multicast,
u8 is_classify,
u32 classify_table_index,
u8 is_resolve_host,
u8 is_resolve_attached,
+ u8 is_interface_rx,
+ u8 is_rpf_id,
u32 fib_index,
const fib_prefix_t * prefix,
u8 next_hop_proto_is_ip4,
@@ -731,16 +732,24 @@ add_del_route_t_handler (u8 is_multipath,
.frp_label_stack = next_hop_out_label_stack,
};
fib_route_path_t *paths = NULL;
+ fib_entry_flag_t entry_flags = FIB_ENTRY_FLAG_NONE;
if (MPLS_LABEL_INVALID != next_hop_via_label)
{
path.frp_proto = FIB_PROTOCOL_MPLS;
path.frp_local_label = next_hop_via_label;
+ path.frp_eos = MPLS_NON_EOS;
}
if (is_resolve_host)
path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_HOST;
if (is_resolve_attached)
path_flags |= FIB_ROUTE_PATH_RESOLVE_VIA_ATTACHED;
+ if (is_interface_rx)
+ path_flags |= FIB_ROUTE_PATH_INTF_RX;
+ if (is_rpf_id)
+ path_flags |= FIB_ROUTE_PATH_RPF_ID;
+ if (is_multicast)
+ entry_flags |= FIB_ENTRY_FLAG_MULTICAST;
path.frp_flags = path_flags;
@@ -754,8 +763,7 @@ add_del_route_t_handler (u8 is_multipath,
if (is_add)
fib_table_entry_path_add2 (fib_index,
prefix,
- FIB_SOURCE_API,
- FIB_ENTRY_FLAG_NONE, paths);
+ FIB_SOURCE_API, entry_flags, paths);
else
fib_table_entry_path_remove2 (fib_index,
prefix, FIB_SOURCE_API, paths);
@@ -826,8 +834,7 @@ add_del_route_t_handler (u8 is_multipath,
{
vec_add1 (paths, path);
fib_table_entry_update (fib_index,
- prefix,
- FIB_SOURCE_API, FIB_ENTRY_FLAG_NONE, paths);
+ prefix, FIB_SOURCE_API, entry_flags, paths);
vec_free (paths);
}
else
@@ -847,7 +854,7 @@ add_del_route_check (fib_protocol_t table_proto,
fib_protocol_t next_hop_table_proto,
u32 next_hop_table_id,
u8 create_missing_tables,
- u32 * fib_index, u32 * next_hop_fib_index)
+ u8 is_rpf_id, u32 * fib_index, u32 * next_hop_fib_index)
{
vnet_main_t *vnm = vnet_get_main ();
@@ -866,7 +873,7 @@ add_del_route_check (fib_protocol_t table_proto,
}
}
- if (~0 != ntohl (next_hop_sw_if_index))
+ if (!is_rpf_id && ~0 != ntohl (next_hop_sw_if_index))
{
if (pool_is_free_index (vnm->interface_main.sw_interfaces,
ntohl (next_hop_sw_if_index)))
@@ -876,16 +883,27 @@ add_del_route_check (fib_protocol_t table_proto,
}
else
{
- *next_hop_fib_index = fib_table_find (next_hop_table_proto,
- ntohl (next_hop_table_id));
+ if (is_rpf_id)
+ *next_hop_fib_index = mfib_table_find (next_hop_table_proto,
+ ntohl (next_hop_table_id));
+ else
+ *next_hop_fib_index = fib_table_find (next_hop_table_proto,
+ ntohl (next_hop_table_id));
if (~0 == *next_hop_fib_index)
{
if (create_missing_tables)
{
- *next_hop_fib_index =
- fib_table_find_or_create_and_lock (next_hop_table_proto,
- ntohl (next_hop_table_id));
+ if (is_rpf_id)
+ *next_hop_fib_index =
+ mfib_table_find_or_create_and_lock (next_hop_table_proto,
+ ntohl
+ (next_hop_table_id));
+ else
+ *next_hop_fib_index =
+ fib_table_find_or_create_and_lock (next_hop_table_proto,
+ ntohl
+ (next_hop_table_id));
}
else
{
@@ -910,7 +928,7 @@ ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
mp->next_hop_sw_if_index,
FIB_PROTOCOL_IP4,
mp->next_hop_table_id,
- mp->create_vrf_if_needed,
+ mp->create_vrf_if_needed, 0,
&fib_index, &next_hop_fib_index);
if (0 != rv)
@@ -943,11 +961,11 @@ ip4_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
mp->is_drop,
mp->is_unreach,
mp->is_prohibit,
- mp->is_local,
+ mp->is_local, 0,
mp->is_classify,
mp->classify_table_index,
mp->is_resolve_host,
- mp->is_resolve_attached,
+ mp->is_resolve_attached, 0, 0,
fib_index, &pfx, 1,
&nh,
ntohl (mp->next_hop_sw_if_index),
@@ -969,7 +987,7 @@ ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
mp->next_hop_sw_if_index,
FIB_PROTOCOL_IP6,
mp->next_hop_table_id,
- mp->create_vrf_if_needed,
+ mp->create_vrf_if_needed, 0,
&fib_index, &next_hop_fib_index);
if (0 != rv)
@@ -1002,11 +1020,11 @@ ip6_add_del_route_t_handler (vl_api_ip_add_del_route_t * mp)
mp->is_drop,
mp->is_unreach,
mp->is_prohibit,
- mp->is_local,
+ mp->is_local, 0,
mp->is_classify,
mp->classify_table_index,
mp->is_resolve_host,
- mp->is_resolve_attached,
+ mp->is_resolve_attached, 0, 0,
fib_index, &pfx, 0,
&nh, ntohl (mp->next_hop_sw_if_index),
next_hop_fib_index,
@@ -1075,6 +1093,7 @@ mroute_add_del_handler (u8 is_add,
u32 fib_index,
const mfib_prefix_t * prefix,
u32 entry_flags,
+ fib_rpf_id_t rpf_id,
u32 next_hop_sw_if_index, u32 itf_flags)
{
stats_dslock_with_hint (1 /* release hint */ , 2 /* tag */ );
@@ -1091,7 +1110,7 @@ mroute_add_del_handler (u8 is_add,
if (!is_local && ~0 == next_hop_sw_if_index)
{
mfib_table_entry_update (fib_index, prefix,
- MFIB_SOURCE_API, entry_flags);
+ MFIB_SOURCE_API, rpf_id, entry_flags);
}
else
{
@@ -1152,6 +1171,7 @@ api_mroute_add_del_t_handler (vl_api_ip_mroute_add_del_t * mp)
mp->is_local,
fib_index, &pfx,
ntohl (mp->entry_flags),
+ ntohl (mp->rpf_id),
ntohl (mp->next_hop_sw_if_index),
ntohl (mp->itf_flags)));
}
diff --git a/src/vnet/ip/lookup.c b/src/vnet/ip/lookup.c
index ec9a1f97ac9..597de06b5e3 100755
--- a/src/vnet/ip/lookup.c
+++ b/src/vnet/ip/lookup.c
@@ -450,6 +450,7 @@ vnet_ip_route_cmd (vlib_main_t * vm,
unformat_mpls_unicast_label, &rpath.frp_local_label))
{
rpath.frp_weight = 1;
+ rpath.frp_eos = MPLS_NON_EOS;
rpath.frp_proto = FIB_PROTOCOL_MPLS;
rpath.frp_sw_if_index = ~0;
vec_add1 (rpaths, rpath);
@@ -923,7 +924,7 @@ vnet_ip_mroute_cmd (vlib_main_t * vm,
else if (eflags)
{
mfib_table_entry_update (fib_index, &pfx, MFIB_SOURCE_CLI,
- eflags);
+ MFIB_RPF_ID_NONE, eflags);
}
else
{
diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c
index efa724e0d5b..d2954e9649a 100644
--- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c
+++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c
@@ -88,6 +88,7 @@ ip_dst_fib_add_route (u32 dst_fib_index, const ip_prefix_t * dst_prefix)
(ip_prefix_version (dst_prefix) ==
IP6 ? DPO_PROTO_IP6 :
DPO_PROTO_IP4),
+ LOOKUP_UNICAST,
LOOKUP_INPUT_SRC_ADDR,
LOOKUP_TABLE_FROM_CONFIG,
&src_lkup_dpo);
diff --git a/src/vnet/mfib/ip4_mfib.c b/src/vnet/mfib/ip4_mfib.c
index 164cafa118b..3ed7cba7b6f 100644
--- a/src/vnet/mfib/ip4_mfib.c
+++ b/src/vnet/mfib/ip4_mfib.c
@@ -72,6 +72,7 @@ ip4_create_mfib_with_table_id (u32 table_id)
mfib_table_entry_update(mfib_table->mft_index,
&prefix,
MFIB_SOURCE_DEFAULT_ROUTE,
+ MFIB_RPF_ID_NONE,
MFIB_ENTRY_FLAG_DROP);
}
diff --git a/src/vnet/mfib/ip6_mfib.c b/src/vnet/mfib/ip6_mfib.c
index 991b91c6498..116fee2222a 100644
--- a/src/vnet/mfib/ip6_mfib.c
+++ b/src/vnet/mfib/ip6_mfib.c
@@ -195,6 +195,7 @@ ip6_create_mfib_with_table_id (u32 table_id)
mfib_table_entry_update(mfib_table->mft_index,
&all_zeros,
MFIB_SOURCE_DEFAULT_ROUTE,
+ MFIB_RPF_ID_NONE,
MFIB_ENTRY_FLAG_DROP);
/*
diff --git a/src/vnet/mfib/mfib_entry.c b/src/vnet/mfib/mfib_entry.c
index 1aa8e0864ca..847f25e7f1f 100644
--- a/src/vnet/mfib/mfib_entry.c
+++ b/src/vnet/mfib/mfib_entry.c
@@ -49,6 +49,15 @@
#endif
/**
+ * MFIB extensions to each path
+ */
+typedef struct mfib_path_ext_t_
+{
+ mfib_itf_flags_t mfpe_flags;
+ fib_node_index_t mfpe_path;
+} mfib_path_ext_t;
+
+/**
* The source of an MFIB entry
*/
typedef struct mfib_entry_src_t_
@@ -59,22 +68,39 @@ typedef struct mfib_entry_src_t_
mfib_source_t mfes_src;
/**
+ * Route flags
+ */
+ mfib_entry_flags_t mfes_flags;
+
+ /**
* The path-list of forwarding interfaces
*/
fib_node_index_t mfes_pl;
/**
- * Route flags
+ * RPF-ID
*/
- mfib_entry_flags_t mfes_flags;
+ fib_rpf_id_t mfes_rpf_id;
+
+ /**
+ * Hash table of path extensions
+ */
+ mfib_path_ext_t *mfes_exts;
/**
- * The hash table of all interfaces
+ * The hash table of all interfaces.
+ * This is forwarding time information derived from the paths
+ * and their extensions.
*/
mfib_itf_t *mfes_itfs;
} mfib_entry_src_t;
/**
+ * Pool of path extensions
+ */
+static mfib_path_ext_t *mfib_path_ext_pool;
+
+/**
* String names for each source
*/
static const char *mfib_source_names[] = MFIB_SOURCE_NAMES;
@@ -123,6 +149,24 @@ format_mfib_entry_dpo (u8 * s, va_list * args)
MFIB_ENTRY_FORMAT_BRIEF));
}
+static inline mfib_path_ext_t *
+mfib_entry_path_ext_get (index_t mi)
+{
+ return (pool_elt_at_index(mfib_path_ext_pool, mi));
+}
+
+static u8 *
+format_mfib_entry_path_ext (u8 * s, va_list * args)
+{
+ mfib_path_ext_t *path_ext;
+ index_t mpi = va_arg(*args, index_t);
+
+ path_ext = mfib_entry_path_ext_get(mpi);
+ return (format(s, "path:%d flags:%U",
+ path_ext->mfpe_path,
+ format_mfib_itf_flags, path_ext->mfpe_flags));
+}
+
u8 *
format_mfib_entry (u8 * s, va_list * args)
{
@@ -141,6 +185,8 @@ format_mfib_entry (u8 * s, va_list * args)
if (level >= MFIB_ENTRY_FORMAT_DETAIL)
{
+ fib_node_index_t path_index, mpi;
+
s = format (s, "\n");
s = format (s, " fib:%d", mfib_entry->mfe_fib_index);
s = format (s, " index:%d", mfib_entry_get_index(mfib_entry));
@@ -153,6 +199,14 @@ format_mfib_entry (u8 * s, va_list * args)
{
s = fib_path_list_format(msrc->mfes_pl, s);
}
+ s = format (s, " Extensions:\n",
+ mfib_source_names[msrc->mfes_src]);
+ hash_foreach(path_index, mpi, msrc->mfes_exts,
+ ({
+ s = format(s, " %U\n", format_mfib_entry_path_ext, mpi);
+ }));
+ s = format (s, " Interface-Forwarding:\n",
+ mfib_source_names[msrc->mfes_src]);
hash_foreach(sw_if_index, mfi, msrc->mfes_itfs,
({
s = format(s, " %U\n", format_mfib_itf, mfi);
@@ -165,7 +219,7 @@ format_mfib_entry (u8 * s, va_list * args)
({
s = format(s, "\n %U", format_mfib_itf, mfi);
}));
-
+ s = format(s, "\n RPF-ID:%d", mfib_entry->mfe_rpf_id);
s = format(s, "\n %U-chain\n %U",
format_fib_forw_chain_type,
mfib_entry_get_default_chain_type(mfib_entry),
@@ -314,13 +368,6 @@ mfib_entry_src_remove (mfib_entry_t *mfib_entry,
}
}
-static int
-mfib_entry_src_n_itfs (const mfib_entry_src_t *msrc)
-{
- return (hash_elts(msrc->mfes_itfs));
-}
-
-
static void
mfib_entry_last_lock_gone (fib_node_t *node)
{
@@ -338,7 +385,6 @@ mfib_entry_last_lock_gone (fib_node_t *node)
mfib_entry_src_flush(msrc);
}
- fib_path_list_unlock(mfib_entry->mfe_parent);
vec_free(mfib_entry->mfe_srcs);
fib_node_deinit(&mfib_entry->mfe_node);
@@ -417,10 +463,9 @@ mfib_entry_alloc (u32 fib_index,
mfib_entry->mfe_flags = 0;
mfib_entry->mfe_fib_index = fib_index;
mfib_entry->mfe_prefix = *prefix;
- mfib_entry->mfe_parent = FIB_NODE_INDEX_INVALID;
- mfib_entry->mfe_sibling = FIB_NODE_INDEX_INVALID;
mfib_entry->mfe_srcs = NULL;
mfib_entry->mfe_itfs = NULL;
+ mfib_entry->mfe_rpf_id = MFIB_RPF_ID_NONE;
dpo_reset(&mfib_entry->mfe_rep);
@@ -431,10 +476,57 @@ mfib_entry_alloc (u32 fib_index,
return (mfib_entry);
}
+static inline mfib_path_ext_t *
+mfib_entry_path_ext_find (mfib_path_ext_t *exts,
+ fib_node_index_t path_index)
+{
+ uword *p;
+
+ p = hash_get(exts, path_index);
+
+ if (NULL != p)
+ {
+ return (mfib_entry_path_ext_get(p[0]));
+ }
+
+ return (NULL);
+}
+
+static mfib_path_ext_t*
+mfib_path_ext_add (mfib_entry_src_t *msrc,
+ fib_node_index_t path_index,
+ mfib_itf_flags_t mfi_flags)
+{
+ mfib_path_ext_t *path_ext;
+
+ pool_get(mfib_path_ext_pool, path_ext);
+
+ path_ext->mfpe_flags = mfi_flags;
+ path_ext->mfpe_path = path_index;
+
+ hash_set(msrc->mfes_exts, path_index,
+ path_ext - mfib_path_ext_pool);
+
+ return (path_ext);
+}
+
+static void
+mfib_path_ext_remove (mfib_entry_src_t *msrc,
+ fib_node_index_t path_index)
+{
+ mfib_path_ext_t *path_ext;
+
+ path_ext = mfib_entry_path_ext_find(msrc->mfes_exts, path_index);
+
+ hash_unset(msrc->mfes_exts, path_index);
+ pool_put(mfib_path_ext_pool, path_ext);
+}
+
typedef struct mfib_entry_collect_forwarding_ctx_t_
{
load_balance_path_t * next_hops;
fib_forward_chain_type_t fct;
+ mfib_entry_src_t *msrc;
} mfib_entry_collect_forwarding_ctx_t;
static int
@@ -455,6 +547,20 @@ mfib_entry_src_collect_forwarding (fib_node_index_t pl_index,
return (!0);
}
+ /*
+ * If the path is not forwarding to use it
+ */
+ mfib_path_ext_t *path_ext;
+
+ path_ext = mfib_entry_path_ext_find(ctx->msrc->mfes_exts,
+ path_index);
+
+ if (NULL != path_ext &&
+ !(path_ext->mfpe_flags & MFIB_ITF_FLAG_FORWARD))
+ {
+ return (!0);
+ }
+
switch (ctx->fct)
{
case FIB_FORW_CHAIN_TYPE_MCAST_IP4:
@@ -483,46 +589,61 @@ mfib_entry_src_collect_forwarding (fib_node_index_t pl_index,
}
static void
-mfib_entry_stack (mfib_entry_t *mfib_entry)
+mfib_entry_stack (mfib_entry_t *mfib_entry,
+ mfib_entry_src_t *msrc)
{
dpo_proto_t dp;
dp = fib_proto_to_dpo(mfib_entry_get_proto(mfib_entry));
- if (FIB_NODE_INDEX_INVALID != mfib_entry->mfe_parent)
+ if (NULL != msrc &&
+ FIB_NODE_INDEX_INVALID != msrc->mfes_pl)
{
mfib_entry_collect_forwarding_ctx_t ctx = {
.next_hops = NULL,
.fct = mfib_entry_get_default_chain_type(mfib_entry),
+ .msrc = msrc,
};
- fib_path_list_walk(mfib_entry->mfe_parent,
+ fib_path_list_walk(msrc->mfes_pl,
mfib_entry_src_collect_forwarding,
&ctx);
if (!(MFIB_ENTRY_FLAG_EXCLUSIVE & mfib_entry->mfe_flags))
{
- /*
- * each path contirbutes a next-hop. form a replicate
- * from those choices.
- */
- if (!dpo_id_is_valid(&mfib_entry->mfe_rep) ||
- dpo_is_drop(&mfib_entry->mfe_rep))
+ if (NULL == ctx.next_hops)
{
- dpo_id_t tmp_dpo = DPO_INVALID;
-
- dpo_set(&tmp_dpo,
- DPO_REPLICATE, dp,
- replicate_create(0, dp));
-
+ /*
+ * no next-hops, stack directly on the drop
+ */
dpo_stack(DPO_MFIB_ENTRY, dp,
&mfib_entry->mfe_rep,
- &tmp_dpo);
-
- dpo_reset(&tmp_dpo);
+ drop_dpo_get(dp));
+ }
+ else
+ {
+ /*
+ * each path contirbutes a next-hop. form a replicate
+ * from those choices.
+ */
+ if (!dpo_id_is_valid(&mfib_entry->mfe_rep) ||
+ dpo_is_drop(&mfib_entry->mfe_rep))
+ {
+ dpo_id_t tmp_dpo = DPO_INVALID;
+
+ dpo_set(&tmp_dpo,
+ DPO_REPLICATE, dp,
+ replicate_create(0, dp));
+
+ dpo_stack(DPO_MFIB_ENTRY, dp,
+ &mfib_entry->mfe_rep,
+ &tmp_dpo);
+
+ dpo_reset(&tmp_dpo);
+ }
+ replicate_multipath_update(&mfib_entry->mfe_rep,
+ ctx.next_hops);
}
- replicate_multipath_update(&mfib_entry->mfe_rep,
- ctx.next_hops);
}
else
{
@@ -548,11 +669,11 @@ mfib_entry_stack (mfib_entry_t *mfib_entry)
}
}
-static void
-mfib_entry_forwarding_path_add (mfib_entry_src_t *msrc,
- const fib_route_path_t *rpath)
+static fib_node_index_t
+mfib_entry_src_path_add (mfib_entry_src_t *msrc,
+ const fib_route_path_t *rpath)
{
- fib_node_index_t old_pl_index;
+ fib_node_index_t path_index;
fib_route_path_t *rpaths;
ASSERT(!(MFIB_ENTRY_FLAG_EXCLUSIVE & msrc->mfes_flags));
@@ -563,32 +684,26 @@ mfib_entry_forwarding_path_add (mfib_entry_src_t *msrc,
rpaths = NULL;
vec_add1(rpaths, rpath[0]);
- old_pl_index = msrc->mfes_pl;
-
if (FIB_NODE_INDEX_INVALID == msrc->mfes_pl)
{
- msrc->mfes_pl =
- fib_path_list_create(FIB_PATH_LIST_FLAG_NO_URPF,
- rpaths);
- }
- else
- {
- msrc->mfes_pl =
- fib_path_list_copy_and_path_add(msrc->mfes_pl,
- FIB_PATH_LIST_FLAG_NO_URPF,
- rpaths);
+ /* A non-shared path-list */
+ msrc->mfes_pl = fib_path_list_create(FIB_PATH_LIST_FLAG_NO_URPF,
+ NULL);
+ fib_path_list_lock(msrc->mfes_pl);
}
- fib_path_list_lock(msrc->mfes_pl);
- fib_path_list_unlock(old_pl_index);
+
+ path_index = fib_path_list_path_add(msrc->mfes_pl, rpaths);
vec_free(rpaths);
+
+ return (path_index);
}
-static int
-mfib_entry_forwarding_path_remove (mfib_entry_src_t *msrc,
- const fib_route_path_t *rpath)
+static fib_node_index_t
+mfib_entry_src_path_remove (mfib_entry_src_t *msrc,
+ const fib_route_path_t *rpath)
{
- fib_node_index_t old_pl_index;
+ fib_node_index_t path_index;
fib_route_path_t *rpaths;
ASSERT(!(MFIB_ENTRY_FLAG_EXCLUSIVE & msrc->mfes_flags));
@@ -599,56 +714,31 @@ mfib_entry_forwarding_path_remove (mfib_entry_src_t *msrc,
rpaths = NULL;
vec_add1(rpaths, rpath[0]);
- old_pl_index = msrc->mfes_pl;
-
- msrc->mfes_pl =
- fib_path_list_copy_and_path_remove(msrc->mfes_pl,
- FIB_PATH_LIST_FLAG_NONE,
- rpaths);
-
- fib_path_list_lock(msrc->mfes_pl);
- fib_path_list_unlock(old_pl_index);
+ path_index = fib_path_list_path_remove(msrc->mfes_pl, rpaths);
vec_free(rpaths);
- return (FIB_NODE_INDEX_INVALID != msrc->mfes_pl);
+ return (path_index);
}
static void
mfib_entry_recalculate_forwarding (mfib_entry_t *mfib_entry)
{
- fib_node_index_t old_pl_index;
mfib_entry_src_t *bsrc;
- old_pl_index = mfib_entry->mfe_parent;
-
/*
* copy the forwarding data from the bast source
*/
bsrc = mfib_entry_get_best_src(mfib_entry);
- if (NULL == bsrc)
- {
- mfib_entry->mfe_parent = FIB_NODE_INDEX_INVALID;
- }
- else
+ if (NULL != bsrc)
{
- mfib_entry->mfe_parent = bsrc->mfes_pl;
mfib_entry->mfe_flags = bsrc->mfes_flags;
mfib_entry->mfe_itfs = bsrc->mfes_itfs;
+ mfib_entry->mfe_rpf_id = bsrc->mfes_rpf_id;
}
- /*
- * re-stack the entry on the best forwarding info.
- */
- if (old_pl_index != mfib_entry->mfe_parent ||
- FIB_NODE_INDEX_INVALID == old_pl_index)
- {
- mfib_entry_stack(mfib_entry);
-
- fib_path_list_lock(mfib_entry->mfe_parent);
- fib_path_list_unlock(old_pl_index);
- }
+ mfib_entry_stack(mfib_entry, bsrc);
}
@@ -656,6 +746,7 @@ fib_node_index_t
mfib_entry_create (u32 fib_index,
mfib_source_t source,
const mfib_prefix_t *prefix,
+ fib_rpf_id_t rpf_id,
mfib_entry_flags_t entry_flags)
{
fib_node_index_t mfib_entry_index;
@@ -666,6 +757,7 @@ mfib_entry_create (u32 fib_index,
&mfib_entry_index);
msrc = mfib_entry_src_find_or_create(mfib_entry, source);
msrc->mfes_flags = entry_flags;
+ msrc->mfes_rpf_id = rpf_id;
mfib_entry_recalculate_forwarding(mfib_entry);
@@ -682,13 +774,14 @@ static int
mfib_entry_src_ok_for_delete (const mfib_entry_src_t *msrc)
{
return ((MFIB_ENTRY_FLAG_NONE == msrc->mfes_flags &&
- 0 == mfib_entry_src_n_itfs(msrc)));
+ 0 == fib_path_list_get_n_paths(msrc->mfes_pl)));
}
int
mfib_entry_update (fib_node_index_t mfib_entry_index,
mfib_source_t source,
mfib_entry_flags_t entry_flags,
+ fib_rpf_id_t rpf_id,
index_t repi)
{
mfib_entry_t *mfib_entry;
@@ -697,6 +790,7 @@ mfib_entry_update (fib_node_index_t mfib_entry_index,
mfib_entry = mfib_entry_get(mfib_entry_index);
msrc = mfib_entry_src_find_or_create(mfib_entry, source);
msrc->mfes_flags = entry_flags;
+ msrc->mfes_rpf_id = rpf_id;
if (INDEX_INVALID != repi)
{
@@ -768,55 +862,79 @@ mfib_entry_path_update (fib_node_index_t mfib_entry_index,
const fib_route_path_t *rpath,
mfib_itf_flags_t itf_flags)
{
+ fib_node_index_t path_index;
+ mfib_path_ext_t *path_ext;
+ mfib_itf_flags_t old, new;
mfib_entry_t *mfib_entry;
mfib_entry_src_t *msrc;
- mfib_itf_t *mfib_itf;
mfib_entry = mfib_entry_get(mfib_entry_index);
ASSERT(NULL != mfib_entry);
msrc = mfib_entry_src_find_or_create(mfib_entry, source);
/*
- * search for the interface in the current set
+ * add the path to the path-list. If it's a duplicate we'll get
+ * back the original path.
+ */
+ path_index = mfib_entry_src_path_add(msrc, rpath);
+
+ /*
+ * find the path extension for that path
*/
- mfib_itf = mfib_entry_itf_find(msrc->mfes_itfs,
- rpath[0].frp_sw_if_index);
+ path_ext = mfib_entry_path_ext_find(msrc->mfes_exts, path_index);
- if (NULL == mfib_itf)
+ if (NULL == path_ext)
{
- /*
- * this is a path we do not yet have. If it is forwarding then we
- * add it to the replication set
- */
- if (itf_flags & MFIB_ITF_FLAG_FORWARD)
- {
- mfib_entry_forwarding_path_add(msrc, rpath);
- }
- /*
- * construct a new ITF for this entry's list
- */
- mfib_entry_itf_add(msrc,
- rpath[0].frp_sw_if_index,
- mfib_itf_create(rpath[0].frp_sw_if_index,
- itf_flags));
+ old = MFIB_ITF_FLAG_NONE;
+ path_ext = mfib_path_ext_add(msrc, path_index, itf_flags);
}
else
{
- int was_forwarding = !!(mfib_itf->mfi_flags & MFIB_ITF_FLAG_FORWARD);
- int is_forwarding = !!(itf_flags & MFIB_ITF_FLAG_FORWARD);
+ old = path_ext->mfpe_flags;
+ path_ext->mfpe_flags = itf_flags;
+ }
- if (!was_forwarding && is_forwarding)
- {
- mfib_entry_forwarding_path_add(msrc, rpath);
- }
- else if (was_forwarding && !is_forwarding)
+ /*
+ * Has the path changed its contribution to the input interface set.
+ * Which only paths with interfaces can do...
+ */
+ if (~0 != rpath[0].frp_sw_if_index)
+ {
+ mfib_itf_t *mfib_itf;
+
+ new = itf_flags;
+
+ if (old != new)
{
- mfib_entry_forwarding_path_remove(msrc, rpath);
+ if (MFIB_ITF_FLAG_NONE == new)
+ {
+ /*
+ * no more interface flags on this path, remove
+ * from the data-plane set
+ */
+ mfib_entry_itf_remove(msrc, rpath[0].frp_sw_if_index);
+ }
+ else if (MFIB_ITF_FLAG_NONE == old)
+ {
+ /*
+ * This interface is now contributing
+ */
+ mfib_entry_itf_add(msrc,
+ rpath[0].frp_sw_if_index,
+ mfib_itf_create(rpath[0].frp_sw_if_index,
+ itf_flags));
+ }
+ else
+ {
+ /*
+ * change of flag contributions
+ */
+ mfib_itf = mfib_entry_itf_find(msrc->mfes_itfs,
+ rpath[0].frp_sw_if_index);
+ /* Seen by packets inflight */
+ mfib_itf->mfi_flags = new;
+ }
}
- /*
- * packets in flight see these updates.
- */
- mfib_itf->mfi_flags = itf_flags;
}
mfib_entry_recalculate_forwarding(mfib_entry);
@@ -833,9 +951,9 @@ mfib_entry_path_remove (fib_node_index_t mfib_entry_index,
mfib_source_t source,
const fib_route_path_t *rpath)
{
+ fib_node_index_t path_index;
mfib_entry_t *mfib_entry;
mfib_entry_src_t *msrc;
- mfib_itf_t *mfib_itf;
mfib_entry = mfib_entry_get(mfib_entry_index);
ASSERT(NULL != mfib_entry);
@@ -850,33 +968,23 @@ mfib_entry_path_remove (fib_node_index_t mfib_entry_index,
}
/*
- * search for the interface in the current set
+ * remove the path from the path-list. If it's not there we'll get
+ * back invalid
*/
- mfib_itf = mfib_entry_itf_find(msrc->mfes_itfs,
- rpath[0].frp_sw_if_index);
+ path_index = mfib_entry_src_path_remove(msrc, rpath);
- if (NULL == mfib_itf)
+ if (FIB_NODE_INDEX_INVALID != path_index)
{
/*
- * removing a path that does not exist
+ * don't need the extension, nor the interface anymore
*/
- return (mfib_entry_ok_for_delete(mfib_entry));
- }
-
- /*
- * we have this path. If it is forwarding then we
- * remove it to the replication set
- */
- if (mfib_itf->mfi_flags & MFIB_ITF_FLAG_FORWARD)
- {
- mfib_entry_forwarding_path_remove(msrc, rpath);
+ mfib_path_ext_remove(msrc, path_index);
+ if (~0 != rpath[0].frp_sw_if_index)
+ {
+ mfib_entry_itf_remove(msrc, rpath[0].frp_sw_if_index);
+ }
}
- /*
- * remove the interface/path from this entry's list
- */
- mfib_entry_itf_remove(msrc, rpath[0].frp_sw_if_index);
-
if (mfib_entry_src_ok_for_delete(msrc))
{
/*
@@ -1057,11 +1165,14 @@ mfib_entry_encode (fib_node_index_t mfib_entry_index,
fib_route_path_encode_t **api_rpaths)
{
mfib_entry_t *mfib_entry;
+ mfib_entry_src_t *bsrc;
mfib_entry = mfib_entry_get(mfib_entry_index);
- if (FIB_NODE_INDEX_INVALID != mfib_entry->mfe_parent)
+ bsrc = mfib_entry_get_best_src(mfib_entry);
+
+ if (FIB_NODE_INDEX_INVALID != bsrc->mfes_pl)
{
- fib_path_list_walk(mfib_entry->mfe_parent,
+ fib_path_list_walk(bsrc->mfes_pl,
fib_path_encode,
api_rpaths);
}
diff --git a/src/vnet/mfib/mfib_entry.h b/src/vnet/mfib/mfib_entry.h
index dc8f49aad1a..4f62b18ec65 100644
--- a/src/vnet/mfib/mfib_entry.h
+++ b/src/vnet/mfib/mfib_entry.h
@@ -42,17 +42,6 @@ typedef struct mfib_entry_t_ {
* The index of the FIB table this entry is in
*/
u32 mfe_fib_index;
- /**
- * the path-list for which this entry is a child. This is also the path-list
- * that is contributing forwarding for this entry.
- */
- fib_node_index_t mfe_parent;
- /**
- * index of this entry in the parent's child list.
- * This is set when this entry is added as a child, but can also
- * be changed by the parent as it manages its list.
- */
- u32 mfe_sibling;
/**
* A vector of sources contributing forwarding
@@ -65,7 +54,7 @@ typedef struct mfib_entry_t_ {
CLIB_CACHE_LINE_ALIGN_MARK(cacheline1);
/**
- * The Replicate DPO used for forwarding.
+ * The DPO used for forwarding; replicate, drop, etc..
*/
dpo_id_t mfe_rep;
@@ -75,6 +64,11 @@ typedef struct mfib_entry_t_ {
mfib_entry_flags_t mfe_flags;
/**
+ * RPF-ID used when the packets ingress not from an interface
+ */
+ fib_rpf_id_t mfe_rpf_id;
+
+ /**
* A hash table of interfaces
*/
mfib_itf_t *mfe_itfs;
@@ -90,11 +84,13 @@ extern u8 *format_mfib_entry(u8 * s, va_list * args);
extern fib_node_index_t mfib_entry_create(u32 fib_index,
mfib_source_t source,
const mfib_prefix_t *prefix,
+ fib_rpf_id_t rpf_id,
mfib_entry_flags_t entry_flags);
extern int mfib_entry_update(fib_node_index_t fib_entry_index,
mfib_source_t source,
mfib_entry_flags_t entry_flags,
+ fib_rpf_id_t rpf_id,
index_t rep_dpo);
extern void mfib_entry_path_update(fib_node_index_t fib_entry_index,
diff --git a/src/vnet/mfib/mfib_forward.c b/src/vnet/mfib/mfib_forward.c
index 5fe0a57c03b..3d8f4f98cb0 100644
--- a/src/vnet/mfib/mfib_forward.c
+++ b/src/vnet/mfib/mfib_forward.c
@@ -380,13 +380,27 @@ mfib_forward_rpf (vlib_main_t * vm,
* for the case of throughput traffic that is not replicated
* to the host stack nor sets local flags
*/
- if (PREDICT_TRUE(NULL != mfi0))
+
+ /*
+ * If the mfib entry has a configured RPF-ID check that
+ * in preference to an interface based RPF
+ */
+ if (MFIB_RPF_ID_NONE != mfe0->mfe_rpf_id)
{
- iflags0 = mfi0->mfi_flags;
+ iflags0 = (mfe0->mfe_rpf_id == vnet_buffer(b0)->ip.rpf_id ?
+ MFIB_ITF_FLAG_ACCEPT :
+ MFIB_ITF_FLAG_NONE);
}
else
{
- iflags0 = MFIB_ITF_FLAG_NONE;
+ if (PREDICT_TRUE(NULL != mfi0))
+ {
+ iflags0 = mfi0->mfi_flags;
+ }
+ else
+ {
+ iflags0 = MFIB_ITF_FLAG_NONE;
+ }
}
eflags0 = mfe0->mfe_flags;
@@ -436,17 +450,16 @@ mfib_forward_rpf (vlib_main_t * vm,
{
mfib_forward_rpf_trace_t *t0;
- t0 = vlib_add_trace (vm, node, b0, sizeof (t0[0]));
+ t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
t0->entry_index = mfei0;
+ t0->itf_flags = iflags0;
if (NULL == mfi0)
{
t0->sw_if_index = ~0;
- t0->itf_flags = MFIB_ITF_FLAG_NONE;
}
else
{
t0->sw_if_index = mfi0->mfi_sw_if_index;
- t0->itf_flags = mfi0->mfi_flags;
}
}
vlib_validate_buffer_enqueue_x1 (vm, node, next,
@@ -478,7 +491,7 @@ VLIB_REGISTER_NODE (ip4_mfib_forward_rpf_node, static) = {
.n_next_nodes = MFIB_FORWARD_RPF_N_NEXT,
.next_nodes = {
- [MFIB_FORWARD_RPF_NEXT_DROP] = "error-drop",
+ [MFIB_FORWARD_RPF_NEXT_DROP] = "ip4-drop",
},
};
@@ -503,7 +516,7 @@ VLIB_REGISTER_NODE (ip6_mfib_forward_rpf_node, static) = {
.n_next_nodes = MFIB_FORWARD_RPF_N_NEXT,
.next_nodes = {
- [MFIB_FORWARD_RPF_NEXT_DROP] = "error-drop",
+ [MFIB_FORWARD_RPF_NEXT_DROP] = "ip6-drop",
},
};
diff --git a/src/vnet/mfib/mfib_table.c b/src/vnet/mfib/mfib_table.c
index 3b4bd985893..7ffe8941e75 100644
--- a/src/vnet/mfib/mfib_table.c
+++ b/src/vnet/mfib/mfib_table.c
@@ -165,6 +165,7 @@ fib_node_index_t
mfib_table_entry_update (u32 fib_index,
const mfib_prefix_t *prefix,
mfib_source_t source,
+ fib_rpf_id_t rpf_id,
mfib_entry_flags_t entry_flags)
{
fib_node_index_t mfib_entry_index;
@@ -181,7 +182,8 @@ mfib_table_entry_update (u32 fib_index,
* update to a non-existing entry with non-zero flags
*/
mfib_entry_index = mfib_entry_create(fib_index, source,
- prefix, entry_flags);
+ prefix, rpf_id,
+ entry_flags);
mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
}
@@ -198,6 +200,7 @@ mfib_table_entry_update (u32 fib_index,
if (mfib_entry_update(mfib_entry_index,
source,
entry_flags,
+ rpf_id,
INDEX_INVALID))
{
/*
@@ -230,6 +233,7 @@ mfib_table_entry_path_update (u32 fib_index,
mfib_entry_index = mfib_entry_create(fib_index,
source,
prefix,
+ MFIB_RPF_ID_NONE,
MFIB_ENTRY_FLAG_NONE);
mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
@@ -304,6 +308,7 @@ mfib_table_entry_special_add (u32 fib_index,
mfib_entry_index = mfib_entry_create(fib_index,
source,
prefix,
+ MFIB_RPF_ID_NONE,
MFIB_ENTRY_FLAG_NONE);
mfib_table_entry_insert(mfib_table, prefix, mfib_entry_index);
@@ -311,6 +316,7 @@ mfib_table_entry_special_add (u32 fib_index,
mfib_entry_update(mfib_entry_index, source,
(MFIB_ENTRY_FLAG_EXCLUSIVE | entry_flags),
+ MFIB_RPF_ID_NONE,
rep_dpo);
return (mfib_entry_index);
diff --git a/src/vnet/mfib/mfib_table.h b/src/vnet/mfib/mfib_table.h
index 95239f7cb17..83aa04ef797 100644
--- a/src/vnet/mfib/mfib_table.h
+++ b/src/vnet/mfib/mfib_table.h
@@ -122,6 +122,7 @@ extern fib_node_index_t mfib_table_lookup_exact_match(u32 fib_index,
extern fib_node_index_t mfib_table_entry_update(u32 fib_index,
const mfib_prefix_t *prefix,
mfib_source_t source,
+ fib_rpf_id_t rpf_id,
mfib_entry_flags_t flags);
/**
diff --git a/src/vnet/mfib/mfib_test.c b/src/vnet/mfib/mfib_test.c
index 36a303e844d..7c92ae99b1d 100644
--- a/src/vnet/mfib/mfib_test.c
+++ b/src/vnet/mfib/mfib_test.c
@@ -20,6 +20,8 @@
#include <vnet/mfib/mfib_signal.h>
#include <vnet/mfib/ip6_mfib.h>
#include <vnet/fib/fib_path_list.h>
+#include <vnet/fib/fib_test.h>
+#include <vnet/fib/fib_table.h>
#include <vnet/dpo/replicate_dpo.h>
#include <vnet/adj/adj_mcast.h>
@@ -201,8 +203,8 @@ mfib_test_validate_rep_v (const replicate_t *rep,
if (DPO_RECEIVE != dt)
{
MFIB_TEST_REP((ai == dpo->dpoi_index),
- "bucket %d stacks on %U",
- bucket,
+ "bucket %d [exp:%d] stacks on %U",
+ bucket, ai,
format_dpo_id, dpo, 0);
}
}
@@ -734,6 +736,7 @@ mfib_test_i (fib_protocol_t PROTO,
mfib_table_entry_update(fib_index,
pfx_s_g,
MFIB_SOURCE_API,
+ MFIB_RPF_ID_NONE,
MFIB_ENTRY_FLAG_SIGNAL);
MFIB_TEST(mfib_test_entry(mfei,
MFIB_ENTRY_FLAG_SIGNAL,
@@ -824,6 +827,7 @@ mfib_test_i (fib_protocol_t PROTO,
mfib_table_entry_update(fib_index,
pfx_s_g,
MFIB_SOURCE_API,
+ MFIB_RPF_ID_NONE,
(MFIB_ENTRY_FLAG_SIGNAL |
MFIB_ENTRY_FLAG_CONNECTED));
MFIB_TEST(mfib_test_entry(mfei,
@@ -965,6 +969,7 @@ mfib_test_i (fib_protocol_t PROTO,
mfib_table_entry_update(fib_index,
pfx_s_g,
MFIB_SOURCE_API,
+ MFIB_RPF_ID_NONE,
MFIB_ENTRY_FLAG_NONE);
mfei = mfib_table_lookup_exact_match(fib_index,
pfx_s_g);
@@ -1074,6 +1079,117 @@ mfib_test_i (fib_protocol_t PROTO,
dpo_reset(&td);
/*
+ * A Multicast LSP. This a mLDP head-end
+ */
+ fib_node_index_t ai_mpls_10_10_10_1, lfei;
+ ip46_address_t nh_10_10_10_1 = {
+ .ip4 = {
+ .as_u32 = clib_host_to_net_u32(0x0a0a0a01),
+ },
+ };
+ ai_mpls_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4,
+ VNET_LINK_MPLS,
+ &nh_10_10_10_1,
+ tm->hw[0]->sw_if_index);
+
+ fib_prefix_t pfx_3500 = {
+ .fp_len = 21,
+ .fp_proto = FIB_PROTOCOL_MPLS,
+ .fp_label = 3500,
+ .fp_eos = MPLS_EOS,
+ .fp_payload_proto = DPO_PROTO_IP4,
+ };
+ fib_test_rep_bucket_t mc_0 = {
+ .type = FT_REP_LABEL_O_ADJ,
+ .label_o_adj = {
+ .adj = ai_mpls_10_10_10_1,
+ .label = 3300,
+ .eos = MPLS_EOS,
+ },
+ };
+ mpls_label_t *l3300 = NULL;
+ vec_add1(l3300, 3300);
+
+ /*
+ * MPLS enable an interface so we get the MPLS table created
+ */
+ mpls_sw_interface_enable_disable(&mpls_main,
+ tm->hw[0]->sw_if_index,
+ 1);
+
+ lfei = fib_table_entry_update_one_path(0, // default MPLS Table
+ &pfx_3500,
+ FIB_SOURCE_API,
+ FIB_ENTRY_FLAG_MULTICAST,
+ FIB_PROTOCOL_IP4,
+ &nh_10_10_10_1,
+ tm->hw[0]->sw_if_index,
+ ~0, // invalid fib index
+ 1,
+ l3300,
+ FIB_ROUTE_PATH_FLAG_NONE);
+ MFIB_TEST(fib_test_validate_entry(lfei,
+ FIB_FORW_CHAIN_TYPE_MPLS_EOS,
+ 1,
+ &mc_0),
+ "3500 via replicate over 10.10.10.1");
+
+ /*
+ * An (S,G) that resolves via the mLDP head-end
+ */
+ fib_route_path_t path_via_mldp = {
+ .frp_proto = FIB_PROTOCOL_MPLS,
+ .frp_local_label = pfx_3500.fp_label,
+ .frp_eos = MPLS_EOS,
+ .frp_sw_if_index = 0xffffffff,
+ .frp_fib_index = 0,
+ .frp_weight = 1,
+ .frp_flags = FIB_ROUTE_PATH_FLAG_NONE,
+ };
+ dpo_id_t mldp_dpo = DPO_INVALID;
+
+ fib_entry_contribute_forwarding(lfei,
+ FIB_FORW_CHAIN_TYPE_MPLS_EOS,
+ &mldp_dpo);
+
+ mfei = mfib_table_entry_path_update(fib_index,
+ pfx_s_g,
+ MFIB_SOURCE_API,
+ &path_via_mldp,
+ MFIB_ITF_FLAG_FORWARD);
+
+ MFIB_TEST(mfib_test_entry(mfei,
+ MFIB_ENTRY_FLAG_NONE,
+ 1,
+ DPO_REPLICATE, mldp_dpo.dpoi_index),
+ "%U over-mLDP replicate OK",
+ format_mfib_prefix, pfx_s_g);
+
+ /*
+ * add a for-us path. this tests two types of non-attached paths on one entry
+ */
+ mfei = mfib_table_entry_path_update(fib_index,
+ pfx_s_g,
+ MFIB_SOURCE_API,
+ &path_for_us,
+ MFIB_ITF_FLAG_FORWARD);
+ MFIB_TEST(mfib_test_entry(mfei,
+ MFIB_ENTRY_FLAG_NONE,
+ 2,
+ DPO_REPLICATE, mldp_dpo.dpoi_index,
+ DPO_RECEIVE, 0),
+ "%U mLDP+for-us replicate OK",
+ format_mfib_prefix, pfx_s_g);
+
+ mfib_table_entry_delete(fib_index,
+ pfx_s_g,
+ MFIB_SOURCE_API);
+ fib_table_entry_delete(0,
+ &pfx_3500,
+ FIB_SOURCE_API);
+ dpo_reset(&mldp_dpo);
+
+ /*
* Unlock the table - it's the last lock so should be gone thereafter
*/
mfib_table_unlock(fib_index, PROTO);
@@ -1087,6 +1203,13 @@ mfib_test_i (fib_protocol_t PROTO,
adj_unlock(ai_3);
/*
+ * MPLS disable the interface
+ */
+ mpls_sw_interface_enable_disable(&mpls_main,
+ tm->hw[0]->sw_if_index,
+ 0);
+
+ /*
* test we've leaked no resources
*/
MFIB_TEST(0 == adj_mcast_db_size(), "%d MCAST adjs", adj_mcast_db_size());
diff --git a/src/vnet/mpls/mpls.api b/src/vnet/mpls/mpls.api
index 2e3bfaf53f5..a1e1270a853 100644
--- a/src/vnet/mpls/mpls.api
+++ b/src/vnet/mpls/mpls.api
@@ -55,6 +55,7 @@ define mpls_ip_bind_unbind_reply
@param context - sender context, to match reply w/ request
@param mt_is_add - Is this a route add or delete
@param mt_sw_if_index - The SW interface index of the tunnel to delete
+ @param mt_is_multicast - Is the tunnel's underlying LSP multicast
@param mt_next_hop_proto_is_ip4 - The next-hop is IPV4
@param mt_next_hop_weight - The weight, for UCMP
@param mt_next_hop[16] - the nextop address
@@ -70,6 +71,7 @@ define mpls_tunnel_add_del
u32 mt_sw_if_index;
u8 mt_is_add;
u8 mt_l2_only;
+ u8 mt_is_multicast;
u8 mt_next_hop_proto_is_ip4;
u8 mt_next_hop_weight;
u8 mt_next_hop[16];
@@ -102,30 +104,43 @@ define mpls_tunnel_dump
i32 tunnel_index;
};
-/** \brief mpls eth tunnel operational state response
- @param tunnel_index - eth tunnel identifier
- @param intfc_address - interface ipv4 addr
- @param mask_width - interface ipv4 addr mask
- @param hw_if_index - interface id
- @param l2_only -
- @param tunnel_dst_mac -
- @param tx_sw_if_index -
- @param encap_index - reference to mpls label table
- @param nlabels - number of resolved labels
- @param labels - resolved labels
+/** \brief FIB path
+ @param sw_if_index - index of the interface
+ @param weight - The weight, for UCMP
+ @param is_local - local if non-zero, else remote
+ @param is_drop - Drop the packet
+ @param is_unreach - Drop the packet and rate limit send ICMP unreachable
+ @param is_prohibit - Drop the packet and rate limit send ICMP prohibited
+ @param afi - the afi of the next hop, IP46_TYPE_IP4=1, IP46_TYPE_IP6=2
+ @param next_hop[16] - the next hop address
+
+ WARNING: this type is replicated, pending cleanup completion
+
+*/
+typeonly manual_print manual_endian define fib_path2
+{
+ u32 sw_if_index;
+ u32 weight;
+ u8 is_local;
+ u8 is_drop;
+ u8 is_unreach;
+ u8 is_prohibit;
+ u8 afi;
+ u8 next_hop[16];
+ u32 labels[16];
+};
+
+/** \brief mpls tunnel details
*/
-define mpls_tunnel_details
+manual_endian manual_print define mpls_tunnel_details
{
u32 context;
- u32 tunnel_index;
- u8 mt_l2_only;
u8 mt_sw_if_index;
- u8 mt_next_hop_proto_is_ip4;
- u8 mt_next_hop[16];
- u32 mt_next_hop_sw_if_index;
- u32 mt_next_hop_table_id;
- u32 mt_next_hop_n_labels;
- u32 mt_next_hop_out_labels[mt_next_hop_n_labels];
+ u8 mt_tunnel_index;
+ u8 mt_l2_only;
+ u8 mt_is_multicast;
+ u32 mt_count;
+ vl_api_fib_path2_t mt_paths[mt_count];
};
/** \brief MPLS Route Add / del route
@@ -140,10 +155,14 @@ define mpls_tunnel_details
create them
@param mr_is_add - Is this a route add or delete
@param mr_is_classify - Is this route result a classify
+ @param mr_is_multicast - Is this a multicast route
@param mr_is_multipath - Is this route update a multipath - i.e. is this
a path addition to an existing route
@param mr_is_resolve_host - Recurse resolution constraint via a host prefix
@param mr_is_resolve_attached - Recurse resolution constraint via attached prefix
+ @param mr_is_interface_rx - Interface Receive path
+ @param mr_is_interface_rx - RPF-ID Receive path. The next-hop interface
+ is used as the RPF-ID
@param mr_next_hop_proto_is_ip4 - The next-hop is IPV4
@param mr_next_hop_weight - The weight, for UCMP
@param mr_next_hop[16] - the nextop address
@@ -164,9 +183,12 @@ define mpls_route_add_del
u8 mr_create_table_if_needed;
u8 mr_is_add;
u8 mr_is_classify;
+ u8 mr_is_multicast;
u8 mr_is_multipath;
u8 mr_is_resolve_host;
u8 mr_is_resolve_attached;
+ u8 mr_is_interface_rx;
+ u8 mr_is_rpf_id;
u8 mr_next_hop_proto_is_ip4;
u8 mr_next_hop_weight;
u8 mr_next_hop[16];
@@ -187,31 +209,6 @@ define mpls_route_add_del_reply
i32 retval;
};
-/** \brief FIB path
- @param sw_if_index - index of the interface
- @param weight - The weight, for UCMP
- @param is_local - local if non-zero, else remote
- @param is_drop - Drop the packet
- @param is_unreach - Drop the packet and rate limit send ICMP unreachable
- @param is_prohibit - Drop the packet and rate limit send ICMP prohibited
- @param afi - the afi of the next hop, IP46_TYPE_IP4=1, IP46_TYPE_IP6=2
- @param next_hop[16] - the next hop address
-
- WARNING: this type is replicated, pending cleanup completion
-
-*/
-typeonly manual_print manual_endian define fib_path2
-{
- u32 sw_if_index;
- u32 weight;
- u8 is_local;
- u8 is_drop;
- u8 is_unreach;
- u8 is_prohibit;
- u8 afi;
- u8 next_hop[16];
-};
-
/** \brief Dump MPLS fib table
@param client_index - opaque cookie to identify the sender
*/
diff --git a/src/vnet/mpls/mpls.c b/src/vnet/mpls/mpls.c
index 482577b17ef..451b15cf03c 100644
--- a/src/vnet/mpls/mpls.c
+++ b/src/vnet/mpls/mpls.c
@@ -286,7 +286,15 @@ vnet_mpls_local_label (vlib_main_t * vm,
rpath.frp_proto = FIB_PROTOCOL_IP4;
vec_add1(rpaths, rpath);
}
-
+ else if (unformat (line_input, "rx-ip4 %U",
+ unformat_vnet_sw_interface, vnm,
+ &rpath.frp_sw_if_index))
+ {
+ rpath.frp_weight = 1;
+ rpath.frp_proto = FIB_PROTOCOL_IP4;
+ rpath.frp_flags = FIB_ROUTE_PATH_INTF_RX;
+ vec_add1(rpaths, rpath);
+ }
else if (unformat (line_input, "via %U %U",
unformat_ip6_address,
&rpath.frp_addr.ip6,
@@ -512,10 +520,3 @@ mpls_init (vlib_main_t * vm)
}
VLIB_INIT_FUNCTION (mpls_init);
-
-mpls_main_t * mpls_get_main (vlib_main_t * vm)
-{
- vlib_call_init_function (vm, mpls_init);
- return &mpls_main;
-}
-
diff --git a/src/vnet/mpls/mpls_api.c b/src/vnet/mpls/mpls_api.c
index f1aef6c92c6..6bfc491d344 100644
--- a/src/vnet/mpls/mpls_api.c
+++ b/src/vnet/mpls/mpls_api.c
@@ -27,6 +27,7 @@
#include <vnet/fib/fib_table.h>
#include <vnet/fib/fib_api.h>
#include <vnet/fib/mpls_fib.h>
+#include <vnet/fib/fib_path_list.h>
#include <vnet/vnet_msg_enum.h>
@@ -163,6 +164,7 @@ mpls_route_add_del_t_handler (vnet_main_t * vnm,
dpo_proto_to_fib (pfx.fp_payload_proto),
mp->mr_next_hop_table_id,
mp->mr_create_table_if_needed,
+ mp->mr_is_rpf_id,
&fib_index, &next_hop_fib_index);
if (0 != rv)
@@ -192,10 +194,13 @@ mpls_route_add_del_t_handler (vnet_main_t * vnm,
0, // mp->is_unreach,
0, // mp->is_prohibit,
0, // mp->is_local,
+ mp->mr_is_multicast,
mp->mr_is_classify,
mp->mr_classify_table_index,
mp->mr_is_resolve_host,
mp->mr_is_resolve_attached,
+ mp->mr_is_interface_rx,
+ mp->mr_is_rpf_id,
fib_index, &pfx,
mp->mr_next_hop_proto_is_ip4,
&nh, ntohl (mp->mr_next_hop_sw_if_index),
@@ -229,46 +234,54 @@ vl_api_mpls_tunnel_add_del_t_handler (vl_api_mpls_tunnel_add_del_t * mp)
int rv = 0;
u32 tunnel_sw_if_index;
int ii;
+ fib_route_path_t rpath, *rpaths = NULL;
+
+ memset (&rpath, 0, sizeof (rpath));
stats_dslock_with_hint (1 /* release hint */ , 5 /* tag */ );
- if (mp->mt_is_add)
+ if (mp->mt_next_hop_proto_is_ip4)
{
- fib_route_path_t rpath, *rpaths = NULL;
- mpls_label_t *label_stack = NULL;
-
- memset (&rpath, 0, sizeof (rpath));
-
- if (mp->mt_next_hop_proto_is_ip4)
- {
- rpath.frp_proto = FIB_PROTOCOL_IP4;
- clib_memcpy (&rpath.frp_addr.ip4,
- mp->mt_next_hop, sizeof (rpath.frp_addr.ip4));
- }
- else
- {
- rpath.frp_proto = FIB_PROTOCOL_IP6;
- clib_memcpy (&rpath.frp_addr.ip6,
- mp->mt_next_hop, sizeof (rpath.frp_addr.ip6));
- }
- rpath.frp_sw_if_index = ntohl (mp->mt_next_hop_sw_if_index);
+ rpath.frp_proto = FIB_PROTOCOL_IP4;
+ clib_memcpy (&rpath.frp_addr.ip4,
+ mp->mt_next_hop, sizeof (rpath.frp_addr.ip4));
+ }
+ else
+ {
+ rpath.frp_proto = FIB_PROTOCOL_IP6;
+ clib_memcpy (&rpath.frp_addr.ip6,
+ mp->mt_next_hop, sizeof (rpath.frp_addr.ip6));
+ }
+ rpath.frp_sw_if_index = ntohl (mp->mt_next_hop_sw_if_index);
+ rpath.frp_weight = 1;
+ if (mp->mt_is_add)
+ {
for (ii = 0; ii < mp->mt_next_hop_n_out_labels; ii++)
- vec_add1 (label_stack, ntohl (mp->mt_next_hop_out_label_stack[ii]));
+ vec_add1 (rpath.frp_label_stack,
+ ntohl (mp->mt_next_hop_out_label_stack[ii]));
+ }
- vec_add1 (rpaths, rpath);
+ vec_add1 (rpaths, rpath);
- vnet_mpls_tunnel_add (rpaths, label_stack,
- mp->mt_l2_only, &tunnel_sw_if_index);
- vec_free (rpaths);
- vec_free (label_stack);
+ tunnel_sw_if_index = ntohl (mp->mt_sw_if_index);
+
+ if (mp->mt_is_add)
+ {
+ if (~0 == tunnel_sw_if_index)
+ tunnel_sw_if_index = vnet_mpls_tunnel_create (mp->mt_l2_only,
+ mp->mt_is_multicast);
+ vnet_mpls_tunnel_path_add (tunnel_sw_if_index, rpaths);
}
else
{
tunnel_sw_if_index = ntohl (mp->mt_sw_if_index);
- vnet_mpls_tunnel_del (tunnel_sw_if_index);
+ if (!vnet_mpls_tunnel_path_remove (tunnel_sw_if_index, rpaths))
+ vnet_mpls_tunnel_del (tunnel_sw_if_index);
}
+ vec_free (rpaths);
+
stats_dsunlock ();
/* *INDENT-OFF* */
@@ -289,10 +302,12 @@ typedef struct mpls_tunnel_send_walk_ctx_t_
static void
send_mpls_tunnel_entry (u32 mti, void *arg)
{
+ fib_route_path_encode_t *api_rpaths, *api_rpath;
mpls_tunnel_send_walk_ctx_t *ctx;
vl_api_mpls_tunnel_details_t *mp;
const mpls_tunnel_t *mt;
- u32 nlabels;
+ vl_api_fib_path2_t *fp;
+ u32 n;
ctx = arg;
@@ -300,18 +315,34 @@ send_mpls_tunnel_entry (u32 mti, void *arg)
return;
mt = mpls_tunnel_get (mti);
- nlabels = vec_len (mt->mt_label_stack);
+ n = fib_path_list_get_n_paths (mt->mt_path_list);
+
+ mp = vl_msg_api_alloc (sizeof (*mp) + n * sizeof (vl_api_fib_path2_t));
+ memset (mp, 0, sizeof (*mp) + n * sizeof (vl_api_fib_path2_t));
- mp = vl_msg_api_alloc (sizeof (*mp) + nlabels * sizeof (u32));
- memset (mp, 0, sizeof (*mp));
mp->_vl_msg_id = ntohs (VL_API_MPLS_TUNNEL_DETAILS);
mp->context = ctx->context;
- mp->tunnel_index = ntohl (mti);
- memcpy (mp->mt_next_hop_out_labels,
- mt->mt_label_stack, nlabels * sizeof (u32));
+ mp->mt_tunnel_index = ntohl (mti);
+ mp->mt_count = ntohl (n);
+
+ fib_path_list_walk (mt->mt_path_list, fib_path_encode, &api_rpaths);
+
+ fp = mp->mt_paths;
+ vec_foreach (api_rpath, api_rpaths)
+ {
+ memset (fp, 0, sizeof (*fp));
+
+ fp->weight = htonl (api_rpath->rpath.frp_weight);
+ fp->sw_if_index = htonl (api_rpath->rpath.frp_sw_if_index);
+ copy_fib_next_hop (api_rpath, fp);
+ fp++;
+ }
// FIXME
+ // memcpy (mp->mt_next_hop_out_labels,
+ // mt->mt_label_stack, nlabels * sizeof (u32));
+
vl_msg_api_send_shmem (ctx->q, (u8 *) & mp);
}
diff --git a/src/vnet/mpls/mpls_input.c b/src/vnet/mpls/mpls_input.c
index 1b9bdd05eed..86ad8bba270 100644
--- a/src/vnet/mpls/mpls_input.c
+++ b/src/vnet/mpls/mpls_input.c
@@ -291,7 +291,7 @@ mpls_setup_nodes (vlib_main_t * vm)
rt->last_outer_fib_index = 0;
rt->mpls_main = &mpls_main;
- ethernet_register_input_type (vm, ETHERNET_TYPE_MPLS_UNICAST,
+ ethernet_register_input_type (vm, ETHERNET_TYPE_MPLS,
mpls_input_node.index);
}
diff --git a/src/vnet/mpls/mpls_lookup.c b/src/vnet/mpls/mpls_lookup.c
index ace6a70fe80..3c6be7e85ec 100644
--- a/src/vnet/mpls/mpls_lookup.c
+++ b/src/vnet/mpls/mpls_lookup.c
@@ -20,8 +20,17 @@
#include <vnet/mpls/mpls.h>
#include <vnet/fib/mpls_fib.h>
#include <vnet/dpo/load_balance.h>
+#include <vnet/dpo/replicate_dpo.h>
-vlib_node_registration_t mpls_lookup_node;
+/**
+ * Static MPLS VLIB forwarding node
+ */
+static vlib_node_registration_t mpls_lookup_node;
+
+/**
+ * The arc/edge from the MPLS lookup node to the MPLS replicate node
+ */
+static u32 mpls_lookup_to_replicate_edge;
typedef struct {
u32 next_index;
@@ -156,81 +165,123 @@ mpls_lookup (vlib_main_t * vm,
lbi2 = mpls_fib_table_forwarding_lookup (lfib_index2, h2);
lbi3 = mpls_fib_table_forwarding_lookup (lfib_index3, h3);
- lb0 = load_balance_get(lbi0);
- lb1 = load_balance_get(lbi1);
- lb2 = load_balance_get(lbi2);
- lb3 = load_balance_get(lbi3);
-
hash_c0 = vnet_buffer(b0)->ip.flow_hash = 0;
hash_c1 = vnet_buffer(b1)->ip.flow_hash = 0;
hash_c2 = vnet_buffer(b2)->ip.flow_hash = 0;
hash_c3 = vnet_buffer(b3)->ip.flow_hash = 0;
- if (PREDICT_FALSE(lb0->lb_n_buckets > 1))
+ if (MPLS_IS_REPLICATE & lbi0)
{
- hash_c0 = vnet_buffer (b0)->ip.flow_hash =
- mpls_compute_flow_hash(h0, lb0->lb_hash_config);
+ next0 = mpls_lookup_to_replicate_edge;
+ vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
+ (lbi0 & ~MPLS_IS_REPLICATE);
}
- if (PREDICT_FALSE(lb1->lb_n_buckets > 1))
+ else
{
- hash_c1 = vnet_buffer (b1)->ip.flow_hash =
- mpls_compute_flow_hash(h1, lb1->lb_hash_config);
+ lb0 = load_balance_get(lbi0);
+
+ if (PREDICT_FALSE(lb0->lb_n_buckets > 1))
+ {
+ hash_c0 = vnet_buffer (b0)->ip.flow_hash =
+ mpls_compute_flow_hash(h0, lb0->lb_hash_config);
+ }
+ ASSERT (lb0->lb_n_buckets > 0);
+ ASSERT (is_pow2 (lb0->lb_n_buckets));
+ dpo0 = load_balance_get_bucket_i(lb0,
+ (hash_c0 &
+ (lb0->lb_n_buckets_minus_1)));
+ next0 = dpo0->dpoi_next_node;
+
+ vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
+
+ vlib_increment_combined_counter
+ (cm, thread_index, lbi0, 1,
+ vlib_buffer_length_in_chain (vm, b0));
}
- if (PREDICT_FALSE(lb2->lb_n_buckets > 1))
+ if (MPLS_IS_REPLICATE & lbi1)
{
- hash_c2 = vnet_buffer (b2)->ip.flow_hash =
- mpls_compute_flow_hash(h2, lb2->lb_hash_config);
+ next1 = mpls_lookup_to_replicate_edge;
+ vnet_buffer (b1)->ip.adj_index[VLIB_TX] =
+ (lbi1 & ~MPLS_IS_REPLICATE);
}
- if (PREDICT_FALSE(lb3->lb_n_buckets > 1))
+ else
{
- hash_c3 = vnet_buffer (b3)->ip.flow_hash =
- mpls_compute_flow_hash(h3, lb3->lb_hash_config);
- }
-
- ASSERT (lb0->lb_n_buckets > 0);
- ASSERT (is_pow2 (lb0->lb_n_buckets));
- ASSERT (lb1->lb_n_buckets > 0);
- ASSERT (is_pow2 (lb1->lb_n_buckets));
- ASSERT (lb2->lb_n_buckets > 0);
- ASSERT (is_pow2 (lb2->lb_n_buckets));
- ASSERT (lb3->lb_n_buckets > 0);
- ASSERT (is_pow2 (lb3->lb_n_buckets));
-
- dpo0 = load_balance_get_bucket_i(lb0,
- (hash_c0 &
- (lb0->lb_n_buckets_minus_1)));
- dpo1 = load_balance_get_bucket_i(lb1,
- (hash_c1 &
- (lb1->lb_n_buckets_minus_1)));
- dpo2 = load_balance_get_bucket_i(lb2,
- (hash_c2 &
- (lb2->lb_n_buckets_minus_1)));
- dpo3 = load_balance_get_bucket_i(lb3,
- (hash_c3 &
- (lb3->lb_n_buckets_minus_1)));
+ lb1 = load_balance_get(lbi1);
- next0 = dpo0->dpoi_next_node;
- next1 = dpo1->dpoi_next_node;
- next2 = dpo2->dpoi_next_node;
- next3 = dpo3->dpoi_next_node;
+ if (PREDICT_FALSE(lb1->lb_n_buckets > 1))
+ {
+ hash_c1 = vnet_buffer (b1)->ip.flow_hash =
+ mpls_compute_flow_hash(h1, lb1->lb_hash_config);
+ }
+ ASSERT (lb1->lb_n_buckets > 0);
+ ASSERT (is_pow2 (lb1->lb_n_buckets));
+ dpo1 = load_balance_get_bucket_i(lb1,
+ (hash_c1 &
+ (lb1->lb_n_buckets_minus_1)));
+ next1 = dpo1->dpoi_next_node;
+
+ vnet_buffer (b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
+
+ vlib_increment_combined_counter
+ (cm, thread_index, lbi1, 1,
+ vlib_buffer_length_in_chain (vm, b1));
+ }
+ if (MPLS_IS_REPLICATE & lbi2)
+ {
+ next2 = mpls_lookup_to_replicate_edge;
+ vnet_buffer (b2)->ip.adj_index[VLIB_TX] =
+ (lbi2 & ~MPLS_IS_REPLICATE);
+ }
+ else
+ {
+ lb2 = load_balance_get(lbi2);
- vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
- vnet_buffer (b1)->ip.adj_index[VLIB_TX] = dpo1->dpoi_index;
- vnet_buffer (b2)->ip.adj_index[VLIB_TX] = dpo2->dpoi_index;
- vnet_buffer (b3)->ip.adj_index[VLIB_TX] = dpo3->dpoi_index;
+ if (PREDICT_FALSE(lb2->lb_n_buckets > 1))
+ {
+ hash_c2 = vnet_buffer (b2)->ip.flow_hash =
+ mpls_compute_flow_hash(h2, lb2->lb_hash_config);
+ }
+ ASSERT (lb2->lb_n_buckets > 0);
+ ASSERT (is_pow2 (lb2->lb_n_buckets));
+ dpo2 = load_balance_get_bucket_i(lb2,
+ (hash_c2 &
+ (lb2->lb_n_buckets_minus_1)));
+ next2 = dpo2->dpoi_next_node;
+
+ vnet_buffer (b2)->ip.adj_index[VLIB_TX] = dpo2->dpoi_index;
+
+ vlib_increment_combined_counter
+ (cm, thread_index, lbi2, 1,
+ vlib_buffer_length_in_chain (vm, b2));
+ }
+ if (MPLS_IS_REPLICATE & lbi3)
+ {
+ next3 = mpls_lookup_to_replicate_edge;
+ vnet_buffer (b3)->ip.adj_index[VLIB_TX] =
+ (lbi3 & ~MPLS_IS_REPLICATE);
+ }
+ else
+ {
+ lb3 = load_balance_get(lbi3);
- vlib_increment_combined_counter
- (cm, thread_index, lbi0, 1,
- vlib_buffer_length_in_chain (vm, b0));
- vlib_increment_combined_counter
- (cm, thread_index, lbi1, 1,
- vlib_buffer_length_in_chain (vm, b1));
- vlib_increment_combined_counter
- (cm, thread_index, lbi2, 1,
- vlib_buffer_length_in_chain (vm, b2));
- vlib_increment_combined_counter
- (cm, thread_index, lbi3, 1,
- vlib_buffer_length_in_chain (vm, b3));
+ if (PREDICT_FALSE(lb3->lb_n_buckets > 1))
+ {
+ hash_c3 = vnet_buffer (b3)->ip.flow_hash =
+ mpls_compute_flow_hash(h3, lb3->lb_hash_config);
+ }
+ ASSERT (lb3->lb_n_buckets > 0);
+ ASSERT (is_pow2 (lb3->lb_n_buckets));
+ dpo3 = load_balance_get_bucket_i(lb3,
+ (hash_c3 &
+ (lb3->lb_n_buckets_minus_1)));
+ next3 = dpo3->dpoi_next_node;
+
+ vnet_buffer (b3)->ip.adj_index[VLIB_TX] = dpo3->dpoi_index;
+
+ vlib_increment_combined_counter
+ (cm, thread_index, lbi3, 1,
+ vlib_buffer_length_in_chain (vm, b3));
+ }
/*
* before we pop the label copy th values we need to maintain.
@@ -331,31 +382,41 @@ mpls_lookup (vlib_main_t * vm,
vnet_buffer(b0)->sw_if_index[VLIB_RX]);
lbi0 = mpls_fib_table_forwarding_lookup(lfib_index0, h0);
- lb0 = load_balance_get(lbi0);
-
hash_c0 = vnet_buffer(b0)->ip.flow_hash = 0;
- if (PREDICT_FALSE(lb0->lb_n_buckets > 1))
+
+ if (MPLS_IS_REPLICATE & lbi0)
{
- hash_c0 = vnet_buffer (b0)->ip.flow_hash =
- mpls_compute_flow_hash(h0, lb0->lb_hash_config);
+ next0 = mpls_lookup_to_replicate_edge;
+ vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
+ (lbi0 & ~MPLS_IS_REPLICATE);
}
+ else
+ {
+ lb0 = load_balance_get(lbi0);
- ASSERT (lb0->lb_n_buckets > 0);
- ASSERT (is_pow2 (lb0->lb_n_buckets));
+ if (PREDICT_FALSE(lb0->lb_n_buckets > 1))
+ {
+ hash_c0 = vnet_buffer (b0)->ip.flow_hash =
+ mpls_compute_flow_hash(h0, lb0->lb_hash_config);
+ }
- dpo0 = load_balance_get_bucket_i(lb0,
- (hash_c0 &
- (lb0->lb_n_buckets_minus_1)));
+ ASSERT (lb0->lb_n_buckets > 0);
+ ASSERT (is_pow2 (lb0->lb_n_buckets));
- next0 = dpo0->dpoi_next_node;
- vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
+ dpo0 = load_balance_get_bucket_i(lb0,
+ (hash_c0 &
+ (lb0->lb_n_buckets_minus_1)));
- vlib_increment_combined_counter
- (cm, thread_index, lbi0, 1,
- vlib_buffer_length_in_chain (vm, b0));
+ next0 = dpo0->dpoi_next_node;
+ vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
+
+ vlib_increment_combined_counter
+ (cm, thread_index, lbi0, 1,
+ vlib_buffer_length_in_chain (vm, b0));
+ }
/*
- * before we pop the label copy th values we need to maintain.
+ * before we pop the label copy, values we need to maintain.
* The label header is in network byte order.
* last byte is the TTL.
* bits 2 to 4 inclusive are the EXP bits
@@ -398,7 +459,7 @@ static char * mpls_error_strings[] = {
#undef mpls_error
};
-VLIB_REGISTER_NODE (mpls_lookup_node) = {
+VLIB_REGISTER_NODE (mpls_lookup_node, static) = {
.function = mpls_lookup,
.name = "mpls-lookup",
/* Takes a vector of packets. */
@@ -621,3 +682,22 @@ VLIB_REGISTER_NODE (mpls_load_balance_node) = {
};
VLIB_NODE_FUNCTION_MULTIARCH (mpls_load_balance_node, mpls_load_balance)
+
+
+static clib_error_t *
+mpls_lookup_init (vlib_main_t * vm)
+{
+ clib_error_t * error;
+
+ if ((error = vlib_call_init_function (vm, mpls_init)))
+ return error;
+
+ mpls_lookup_to_replicate_edge =
+ vlib_node_add_named_next(vm,
+ mpls_lookup_node.index,
+ "mpls-replicate");
+
+ return (NULL);
+}
+
+VLIB_INIT_FUNCTION (mpls_lookup_init);
diff --git a/src/vnet/mpls/mpls_tunnel.c b/src/vnet/mpls/mpls_tunnel.c
index ac6fdcdf1d7..1254dd9ddfb 100644
--- a/src/vnet/mpls/mpls_tunnel.c
+++ b/src/vnet/mpls/mpls_tunnel.c
@@ -18,9 +18,12 @@
#include <vnet/vnet.h>
#include <vnet/pg/pg.h>
#include <vnet/mpls/mpls_tunnel.h>
+#include <vnet/mpls/mpls_types.h>
#include <vnet/ip/ip.h>
#include <vnet/fib/fib_path_list.h>
#include <vnet/adj/adj_midchain.h>
+#include <vnet/adj/adj_mcast.h>
+#include <vnet/dpo/replicate_dpo.h>
/**
* @brief pool of tunnel instances
@@ -38,109 +41,189 @@ static u32 * mpls_tunnel_free_hw_if_indices;
static u32 *mpls_tunnel_db;
/**
+ * @brief MPLS tunnel flags strings
+ */
+static const char *mpls_tunnel_attribute_names[] = MPLS_TUNNEL_ATTRIBUTES;
+
+/**
* @brief Get a tunnel object from a SW interface index
*/
static mpls_tunnel_t*
mpls_tunnel_get_from_sw_if_index (u32 sw_if_index)
{
if ((vec_len(mpls_tunnel_db) < sw_if_index) ||
- (~0 == mpls_tunnel_db[sw_if_index]))
- return (NULL);
+ (~0 == mpls_tunnel_db[sw_if_index]))
+ return (NULL);
return (pool_elt_at_index(mpls_tunnel_pool,
- mpls_tunnel_db[sw_if_index]));
+ mpls_tunnel_db[sw_if_index]));
}
/**
- * @brief Return true if the label stack is imp-null only
+ * @brief Build a rewrite string for the MPLS tunnel.
*/
-static fib_forward_chain_type_t
-mpls_tunnel_get_fwd_chain_type (const mpls_tunnel_t *mt)
+static u8*
+mpls_tunnel_build_rewrite_i (void)
{
- if ((1 == vec_len(mt->mt_label_stack)) &&
- (mt->mt_label_stack[0] == MPLS_IETF_IMPLICIT_NULL_LABEL))
- {
- /*
- * the only label in the label stack is implicit null
- * we need to build an IP chain.
- */
- if (FIB_PROTOCOL_IP4 == fib_path_list_get_proto(mt->mt_path_list))
- {
- return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4);
- }
- else
- {
- return (FIB_FORW_CHAIN_TYPE_UNICAST_IP6);
- }
- }
- else
- {
- return (FIB_FORW_CHAIN_TYPE_MPLS_NON_EOS);
- }
+ /*
+ * passing the adj code a NULL rewirte means 'i don't have one cos
+ * t'other end is unresolved'. That's not the case here. For the mpls
+ * tunnel there are just no bytes of encap to apply in the adj. We'll impose
+ * the label stack once we choose a path. So return a zero length rewrite.
+ */
+ u8 *rewrite = NULL;
+
+ vec_validate(rewrite, 0);
+ vec_reset_length(rewrite);
+
+ return (rewrite);
}
/**
* @brief Build a rewrite string for the MPLS tunnel.
- *
- * We have choices here;
- * 1 - have an Adjacency with a zero length string and stack it on
- * MPLS label objects
- * 2 - put the label header rewrites in the adjacency string.
- *
- * We choose 2 since it results in fewer graph nodes in the egress path
*/
static u8*
mpls_tunnel_build_rewrite (vnet_main_t * vnm,
- u32 sw_if_index,
- vnet_link_t link_type,
- const void *dst_address)
+ u32 sw_if_index,
+ vnet_link_t link_type,
+ const void *dst_address)
{
- mpls_unicast_header_t *muh;
- mpls_tunnel_t *mt;
- u8 *rewrite;
- u32 mti, ii;
+ return (mpls_tunnel_build_rewrite_i());
+}
- rewrite = NULL;
- mti = mpls_tunnel_db[sw_if_index];
- mt = pool_elt_at_index(mpls_tunnel_pool, mti);
+typedef struct mpls_tunnel_collect_forwarding_ctx_t_
+{
+ load_balance_path_t * next_hops;
+ const mpls_tunnel_t *mt;
+ fib_forward_chain_type_t fct;
+} mpls_tunnel_collect_forwarding_ctx_t;
+
+static int
+mpls_tunnel_collect_forwarding (fib_node_index_t pl_index,
+ fib_node_index_t path_index,
+ void *arg)
+{
+ mpls_tunnel_collect_forwarding_ctx_t *ctx;
+ fib_path_ext_t *path_ext;
+ int have_path_ext;
+
+ ctx = arg;
/*
- * The vector must be allocated as u8 so the length is correct
+ * if the path is not resolved, don't include it.
*/
- ASSERT(0 < vec_len(mt->mt_label_stack));
- vec_validate(rewrite, (sizeof(*muh) * vec_len(mt->mt_label_stack)) - 1);
- ASSERT(rewrite);
- muh = (mpls_unicast_header_t *)rewrite;
+ if (!fib_path_is_resolved(path_index))
+ {
+ return (!0);
+ }
/*
- * The last (inner most) label in the stack may be EOS, all the rest Non-EOS
+ * get the matching path-extension for the path being visited.
*/
- for (ii = 0; ii < vec_len(mt->mt_label_stack)-1; ii++)
+ have_path_ext = 0;
+ vec_foreach(path_ext, ctx->mt->mt_path_exts)
{
- vnet_mpls_uc_set_label(&muh[ii].label_exp_s_ttl, mt->mt_label_stack[ii]);
- vnet_mpls_uc_set_ttl(&muh[ii].label_exp_s_ttl, 255);
- vnet_mpls_uc_set_exp(&muh[ii].label_exp_s_ttl, 0);
- vnet_mpls_uc_set_s(&muh[ii].label_exp_s_ttl, MPLS_NON_EOS);
- muh[ii].label_exp_s_ttl = clib_host_to_net_u32(muh[ii].label_exp_s_ttl);
+ if (path_ext->fpe_path_index == path_index)
+ {
+ have_path_ext = 1;
+ break;
+ }
}
- vnet_mpls_uc_set_label(&muh[ii].label_exp_s_ttl, mt->mt_label_stack[ii]);
- vnet_mpls_uc_set_ttl(&muh[ii].label_exp_s_ttl, 255);
- vnet_mpls_uc_set_exp(&muh[ii].label_exp_s_ttl, 0);
-
- if ((VNET_LINK_MPLS == link_type) &&
- (mt->mt_label_stack[ii] != MPLS_IETF_IMPLICIT_NULL_LABEL))
+ if (have_path_ext)
{
- vnet_mpls_uc_set_s(&muh[ii].label_exp_s_ttl, MPLS_NON_EOS);
+ /*
+ * found a matching extension. stack it to obtain the forwarding
+ * info for this path.
+ */
+ ctx->next_hops = fib_path_ext_stack(path_ext,
+ ctx->fct,
+ ctx->fct,
+ ctx->next_hops);
}
else
+ ASSERT(0);
+ /*
+ * else
+ * There should be a path-extenios associated with each path
+ */
+
+ return (!0);
+}
+
+static void
+mpls_tunnel_mk_lb (mpls_tunnel_t *mt,
+ vnet_link_t linkt,
+ fib_forward_chain_type_t fct,
+ dpo_id_t *dpo_lb)
+{
+ dpo_proto_t lb_proto;
+
+ /*
+ * If the entry has path extensions then we construct a load-balance
+ * by stacking the extensions on the forwarding chains of the paths.
+ * Otherwise we use the load-balance of the path-list
+ */
+ mpls_tunnel_collect_forwarding_ctx_t ctx = {
+ .mt = mt,
+ .next_hops = NULL,
+ .fct = fct,
+ };
+
+ /*
+ * As an optimisation we allocate the vector of next-hops to be sized
+ * equal to the maximum nuber of paths we will need, which is also the
+ * most likely number we will need, since in most cases the paths are 'up'.
+ */
+ vec_validate(ctx.next_hops, fib_path_list_get_n_paths(mt->mt_path_list));
+ vec_reset_length(ctx.next_hops);
+
+ lb_proto = vnet_link_to_dpo_proto(linkt);
+
+ fib_path_list_walk(mt->mt_path_list,
+ mpls_tunnel_collect_forwarding,
+ &ctx);
+
+ if (!dpo_id_is_valid(dpo_lb))
{
- vnet_mpls_uc_set_s(&muh[ii].label_exp_s_ttl, MPLS_EOS);
+ /*
+ * first time create
+ */
+ if (mt->mt_flags & MPLS_TUNNEL_FLAG_MCAST)
+ {
+ dpo_set(dpo_lb,
+ DPO_REPLICATE,
+ lb_proto,
+ replicate_create(0, lb_proto));
+ }
+ else
+ {
+ flow_hash_config_t fhc;
+
+ fhc = 0; // FIXME
+ /* fhc = fib_table_get_flow_hash_config(fib_entry->fe_fib_index, */
+ /* dpo_proto_to_fib(lb_proto)); */
+ dpo_set(dpo_lb,
+ DPO_LOAD_BALANCE,
+ lb_proto,
+ load_balance_create(0, lb_proto, fhc));
+ }
}
- muh[ii].label_exp_s_ttl = clib_host_to_net_u32(muh[ii].label_exp_s_ttl);
-
- return (rewrite);
+ if (mt->mt_flags & MPLS_TUNNEL_FLAG_MCAST)
+ {
+ /*
+ * MPLS multicast
+ */
+ replicate_multipath_update(dpo_lb, ctx.next_hops);
+ }
+ else
+ {
+ load_balance_multipath_update(dpo_lb,
+ ctx.next_hops,
+ LOAD_BALANCE_FLAG_NONE);
+ vec_free(ctx.next_hops);
+ }
}
/**
@@ -161,45 +244,47 @@ mpls_tunnel_stack (adj_index_t ai)
mt = mpls_tunnel_get_from_sw_if_index(sw_if_index);
if (NULL == mt)
- return;
+ return;
/*
- * find the adjacency that is contributed by the FIB path-list
- * that this tunnel resovles via, and use it as the next adj
- * in the midchain
+ * while we're stacking the adj, remove the tunnel from the child list
+ * of the path list. this breaks a circular dependency of walk updates
+ * where the create of adjacencies in the children can lead to walks
+ * that get back here.
*/
- if (vnet_hw_interface_get_flags(vnet_get_main(),
- mt->mt_hw_if_index) &
- VNET_HW_INTERFACE_FLAG_LINK_UP)
- {
- dpo_id_t dpo = DPO_INVALID;
+ fib_path_list_lock(mt->mt_path_list);
- fib_path_list_contribute_forwarding(mt->mt_path_list,
- mpls_tunnel_get_fwd_chain_type(mt),
- &dpo);
-
- if (DPO_LOAD_BALANCE == dpo.dpoi_type)
- {
- /*
- * we don't support multiple paths, so no need to load-balance.
- * pull the first and only choice and stack directly on that.
- */
- load_balance_t *lb;
-
- lb = load_balance_get (dpo.dpoi_index);
+ fib_path_list_child_remove(mt->mt_path_list,
+ mt->mt_sibling_index);
- ASSERT(1 == lb->lb_n_buckets);
+ /*
+ * Construct the DPO (load-balance or replicate) that we can stack
+ * the tunnel's midchain on
+ */
+ if (vnet_hw_interface_get_flags(vnet_get_main(),
+ mt->mt_hw_if_index) &
+ VNET_HW_INTERFACE_FLAG_LINK_UP)
+ {
+ dpo_id_t dpo = DPO_INVALID;
- dpo_copy(&dpo, load_balance_get_bucket_i (lb, 0));
- }
+ mpls_tunnel_mk_lb(mt,
+ adj->ia_link,
+ FIB_FORW_CHAIN_TYPE_MPLS_EOS,
+ &dpo);
- adj_nbr_midchain_stack(ai, &dpo);
- dpo_reset(&dpo);
+ adj_nbr_midchain_stack(ai, &dpo);
+ dpo_reset(&dpo);
}
else
{
- adj_nbr_midchain_unstack(ai);
+ adj_nbr_midchain_unstack(ai);
}
+
+ mt->mt_sibling_index = fib_path_list_child_add(mt->mt_path_list,
+ FIB_NODE_TYPE_MPLS_TUNNEL,
+ mt - mpls_tunnel_pool);
+
+ fib_path_list_lock(mt->mt_path_list);
}
/**
@@ -207,7 +292,7 @@ mpls_tunnel_stack (adj_index_t ai)
*/
static adj_walk_rc_t
mpls_adj_walk_cb (adj_index_t ai,
- void *ctx)
+ void *ctx)
{
mpls_tunnel_stack(ai);
@@ -224,17 +309,17 @@ mpls_tunnel_restack (mpls_tunnel_t *mt)
*/
FOR_EACH_FIB_PROTOCOL(proto)
{
- adj_nbr_walk(mt->mt_sw_if_index,
- proto,
- mpls_adj_walk_cb,
- NULL);
+ adj_nbr_walk(mt->mt_sw_if_index,
+ proto,
+ mpls_adj_walk_cb,
+ NULL);
}
}
static clib_error_t *
mpls_tunnel_admin_up_down (vnet_main_t * vnm,
- u32 hw_if_index,
- u32 flags)
+ u32 hw_if_index,
+ u32 flags)
{
vnet_hw_interface_t * hi;
mpls_tunnel_t *mt;
@@ -244,13 +329,13 @@ mpls_tunnel_admin_up_down (vnet_main_t * vnm,
mt = mpls_tunnel_get_from_sw_if_index(hi->sw_if_index);
if (NULL == mt)
- return (NULL);
+ return (NULL);
if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
- vnet_hw_interface_set_flags (vnm, hw_if_index,
- VNET_HW_INTERFACE_FLAG_LINK_UP);
+ vnet_hw_interface_set_flags (vnm, hw_if_index,
+ VNET_HW_INTERFACE_FLAG_LINK_UP);
else
- vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */);
+ vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */);
mpls_tunnel_restack(mt);
@@ -263,22 +348,58 @@ mpls_tunnel_admin_up_down (vnet_main_t * vnm,
*/
static void
mpls_tunnel_fixup (vlib_main_t *vm,
- ip_adjacency_t *adj,
- vlib_buffer_t *b0)
+ ip_adjacency_t *adj,
+ vlib_buffer_t *b0)
{
+ /*
+ * A no-op w.r.t. the header. but reset the 'have we pushed any
+ * MPLS labels onto the packet' flag. That way when we enter the
+ * tunnel we'll get a TTL set to 255
+ */
+ vnet_buffer(b0)->mpls.first = 0;
}
static void
mpls_tunnel_update_adj (vnet_main_t * vnm,
- u32 sw_if_index,
- adj_index_t ai)
+ u32 sw_if_index,
+ adj_index_t ai)
{
- adj_nbr_midchain_update_rewrite(
- ai, mpls_tunnel_fixup,
- ADJ_FLAG_NONE,
- mpls_tunnel_build_rewrite(vnm, sw_if_index,
- adj_get_link_type(ai),
- NULL));
+ ip_adjacency_t *adj;
+
+ ASSERT(ADJ_INDEX_INVALID != ai);
+
+ adj = adj_get(ai);
+
+ switch (adj->lookup_next_index)
+ {
+ case IP_LOOKUP_NEXT_ARP:
+ case IP_LOOKUP_NEXT_GLEAN:
+ adj_nbr_midchain_update_rewrite(ai, mpls_tunnel_fixup,
+ ADJ_FLAG_NONE,
+ mpls_tunnel_build_rewrite_i());
+ break;
+ case IP_LOOKUP_NEXT_MCAST:
+ /*
+ * Construct a partial rewrite from the known ethernet mcast dest MAC
+ * There's no MAC fixup, so the last 2 parameters are 0
+ */
+ adj_mcast_midchain_update_rewrite(ai, mpls_tunnel_fixup,
+ ADJ_FLAG_NONE,
+ mpls_tunnel_build_rewrite_i(),
+ 0, 0);
+ break;
+
+ case IP_LOOKUP_NEXT_DROP:
+ case IP_LOOKUP_NEXT_PUNT:
+ case IP_LOOKUP_NEXT_LOCAL:
+ case IP_LOOKUP_NEXT_REWRITE:
+ case IP_LOOKUP_NEXT_MIDCHAIN:
+ case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
+ case IP_LOOKUP_NEXT_ICMP_ERROR:
+ case IP_LOOKUP_N_NEXT:
+ ASSERT (0);
+ break;
+ }
mpls_tunnel_stack(ai);
}
@@ -312,7 +433,7 @@ typedef struct mpls_tunnel_trace_t_
static u8 *
format_mpls_tunnel_tx_trace (u8 * s,
- va_list * args)
+ 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 *);
@@ -327,8 +448,8 @@ format_mpls_tunnel_tx_trace (u8 * s,
*/
static uword
mpls_tunnel_tx (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * frame)
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
{
u32 next_index;
u32 * from, * to_next, n_left_from, n_left_to_next;
@@ -355,32 +476,32 @@ mpls_tunnel_tx (vlib_main_t * vm,
* FIXME DUAL LOOP
*/
while (n_left_from > 0 && n_left_to_next > 0)
- {
- vlib_buffer_t * b0;
- u32 bi0;
+ {
+ vlib_buffer_t * b0;
+ u32 bi0;
- bi0 = from[0];
- to_next[0] = bi0;
- from += 1;
- to_next += 1;
- n_left_from -= 1;
- n_left_to_next -= 1;
+ 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);
+ b0 = vlib_get_buffer(vm, bi0);
- vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mt->mt_l2_adj;
+ vnet_buffer(b0)->ip.adj_index[VLIB_TX] = mt->mt_l2_adj;
- if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
- {
- mpls_tunnel_trace_t *tr = vlib_add_trace (vm, node,
- b0, sizeof (*tr));
- tr->tunnel_id = rd->dev_instance;
- }
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ mpls_tunnel_trace_t *tr = vlib_add_trace (vm, node,
+ b0, sizeof (*tr));
+ tr->tunnel_id = rd->dev_instance;
+ }
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
- to_next, n_left_to_next,
- bi0, mt->mt_l2_tx_arc);
- }
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+ to_next, n_left_to_next,
+ bi0, mt->mt_l2_tx_arc);
+ }
vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}
@@ -417,13 +538,13 @@ mpls_tunnel_get (u32 mti)
*/
void
mpls_tunnel_walk (mpls_tunnel_walk_cb_t cb,
- void *ctx)
+ void *ctx)
{
u32 mti;
pool_foreach_index(mti, mpls_tunnel_pool,
({
- cb(mti, ctx);
+ cb(mti, ctx);
}));
}
@@ -435,25 +556,22 @@ vnet_mpls_tunnel_del (u32 sw_if_index)
mt = mpls_tunnel_get_from_sw_if_index(sw_if_index);
if (NULL == mt)
- return;
-
- fib_path_list_child_remove(mt->mt_path_list,
- mt->mt_sibling_index);
- if (ADJ_INDEX_INVALID != mt->mt_l2_adj)
- adj_unlock(mt->mt_l2_adj);
+ return;
- vec_free(mt->mt_label_stack);
+ if (FIB_NODE_INDEX_INVALID != mt->mt_path_list)
+ fib_path_list_child_remove(mt->mt_path_list,
+ mt->mt_sibling_index);
+ if (ADJ_INDEX_INVALID != mt->mt_l2_adj)
+ adj_unlock(mt->mt_l2_adj);
vec_add1 (mpls_tunnel_free_hw_if_indices, mt->mt_hw_if_index);
pool_put(mpls_tunnel_pool, mt);
mpls_tunnel_db[sw_if_index] = ~0;
}
-void
-vnet_mpls_tunnel_add (fib_route_path_t *rpaths,
- mpls_label_t *label_stack,
- u8 l2_only,
- u32 *sw_if_index)
+u32
+vnet_mpls_tunnel_create (u8 l2_only,
+ u8 is_multicast)
{
vnet_hw_interface_t * hi;
mpls_tunnel_t *mt;
@@ -466,28 +584,33 @@ vnet_mpls_tunnel_add (fib_route_path_t *rpaths,
mti = mt - mpls_tunnel_pool;
fib_node_init(&mt->mt_node, FIB_NODE_TYPE_MPLS_TUNNEL);
mt->mt_l2_adj = ADJ_INDEX_INVALID;
+ mt->mt_path_list = FIB_NODE_INDEX_INVALID;
+ mt->mt_sibling_index = FIB_NODE_INDEX_INVALID;
+
+ if (is_multicast)
+ mt->mt_flags |= MPLS_TUNNEL_FLAG_MCAST;
/*
* Create a new, or re=use and old, tunnel HW interface
*/
if (vec_len (mpls_tunnel_free_hw_if_indices) > 0)
{
- mt->mt_hw_if_index =
- mpls_tunnel_free_hw_if_indices[vec_len(mpls_tunnel_free_hw_if_indices)-1];
- _vec_len (mpls_tunnel_free_hw_if_indices) -= 1;
- hi = vnet_get_hw_interface (vnm, mt->mt_hw_if_index);
- hi->hw_instance = mti;
- hi->dev_instance = mti;
+ mt->mt_hw_if_index =
+ mpls_tunnel_free_hw_if_indices[vec_len(mpls_tunnel_free_hw_if_indices)-1];
+ _vec_len (mpls_tunnel_free_hw_if_indices) -= 1;
+ hi = vnet_get_hw_interface (vnm, mt->mt_hw_if_index);
+ hi->hw_instance = mti;
+ hi->dev_instance = mti;
}
- else
+ else
{
- mt->mt_hw_if_index = vnet_register_interface(
- vnm,
- mpls_tunnel_class.index,
- mti,
- mpls_tunnel_hw_interface_class.index,
- mti);
- hi = vnet_get_hw_interface(vnm, mt->mt_hw_if_index);
+ mt->mt_hw_if_index = vnet_register_interface(
+ vnm,
+ mpls_tunnel_class.index,
+ mti,
+ mpls_tunnel_hw_interface_class.index,
+ mti);
+ hi = vnet_get_hw_interface(vnm, mt->mt_hw_if_index);
}
/*
@@ -497,43 +620,218 @@ vnet_mpls_tunnel_add (fib_route_path_t *rpaths,
vec_validate_init_empty(mpls_tunnel_db, mt->mt_sw_if_index, ~0);
mpls_tunnel_db[mt->mt_sw_if_index] = mti;
+ if (l2_only)
+ {
+ mt->mt_l2_adj =
+ adj_nbr_add_or_lock(fib_path_list_get_proto(mt->mt_path_list),
+ VNET_LINK_ETHERNET,
+ &zero_addr,
+ mt->mt_sw_if_index);
+
+ mt->mt_l2_tx_arc = vlib_node_add_named_next(vlib_get_main(),
+ hi->tx_node_index,
+ "adj-l2-midchain");
+ }
+
+ return (mt->mt_sw_if_index);
+}
+
+/*
+ * mpls_tunnel_path_ext_add
+ *
+ * append a path extension to the entry's list
+ */
+static void
+mpls_tunnel_path_ext_append (mpls_tunnel_t *mt,
+ const fib_route_path_t *rpath)
+{
+ if (NULL != rpath->frp_label_stack)
+ {
+ fib_path_ext_t *path_ext;
+
+ vec_add2(mt->mt_path_exts, path_ext, 1);
+
+ fib_path_ext_init(path_ext, mt->mt_path_list, rpath);
+ }
+}
+
+/*
+ * mpls_tunnel_path_ext_insert
+ *
+ * insert, sorted, a path extension to the entry's list.
+ * It's not strictly necessary in sort the path extensions, since each
+ * extension has the path index to which it resolves. However, by being
+ * sorted the load-balance produced has a deterministic order, not an order
+ * based on the sequence of extension additions. this is a considerable benefit.
+ */
+static void
+mpls_tunnel_path_ext_insert (mpls_tunnel_t *mt,
+ const fib_route_path_t *rpath)
+{
+ if (0 == vec_len(mt->mt_path_exts))
+ return (mpls_tunnel_path_ext_append(mt, rpath));
+
+ if (NULL != rpath->frp_label_stack)
+ {
+ fib_path_ext_t path_ext;
+ int i = 0;
+
+ fib_path_ext_init(&path_ext, mt->mt_path_list, rpath);
+
+ while (i < vec_len(mt->mt_path_exts) &&
+ (fib_path_ext_cmp(&mt->mt_path_exts[i], rpath) < 0))
+ {
+ i++;
+ }
+
+ vec_insert_elts(mt->mt_path_exts, &path_ext, 1, i);
+ }
+}
+
+void
+vnet_mpls_tunnel_path_add (u32 sw_if_index,
+ fib_route_path_t *rpaths)
+{
+ mpls_tunnel_t *mt;
+ u32 mti;
+
+ mt = mpls_tunnel_get_from_sw_if_index(sw_if_index);
+
+ if (NULL == mt)
+ return;
+
+ mti = mt - mpls_tunnel_pool;
+
/*
* construct a path-list from the path provided
*/
- mt->mt_path_list = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, rpaths);
- mt->mt_sibling_index = fib_path_list_child_add(mt->mt_path_list,
- FIB_NODE_TYPE_MPLS_TUNNEL,
- mti);
+ if (FIB_NODE_INDEX_INVALID == mt->mt_path_list)
+ {
+ mt->mt_path_list = fib_path_list_create(FIB_PATH_LIST_FLAG_SHARED, rpaths);
+ mt->mt_sibling_index = fib_path_list_child_add(mt->mt_path_list,
+ FIB_NODE_TYPE_MPLS_TUNNEL,
+ mti);
+ }
+ else
+ {
+ fib_node_index_t old_pl_index;
+ fib_path_ext_t *path_ext;
+
+ old_pl_index = mt->mt_path_list;
+
+ mt->mt_path_list =
+ fib_path_list_copy_and_path_add(old_pl_index,
+ FIB_PATH_LIST_FLAG_SHARED,
+ rpaths);
+
+ fib_path_list_child_remove(old_pl_index,
+ mt->mt_sibling_index);
+ mt->mt_sibling_index = fib_path_list_child_add(mt->mt_path_list,
+ FIB_NODE_TYPE_MPLS_TUNNEL,
+ mti);
+ /*
+ * re-resolve all the path-extensions with the new path-list
+ */
+ vec_foreach(path_ext, mt->mt_path_exts)
+ {
+ fib_path_ext_resolve(path_ext, mt->mt_path_list);
+ }
+ }
+ mpls_tunnel_path_ext_insert(mt, rpaths);
+ mpls_tunnel_restack(mt);
+}
+
+int
+vnet_mpls_tunnel_path_remove (u32 sw_if_index,
+ fib_route_path_t *rpaths)
+{
+ mpls_tunnel_t *mt;
+ u32 mti;
- mt->mt_label_stack = vec_dup(label_stack);
+ mt = mpls_tunnel_get_from_sw_if_index(sw_if_index);
- if (l2_only)
+ if (NULL == mt)
+ return (0);
+
+ mti = mt - mpls_tunnel_pool;
+
+ /*
+ * construct a path-list from the path provided
+ */
+ if (FIB_NODE_INDEX_INVALID == mt->mt_path_list)
{
- mt->mt_l2_adj =
- adj_nbr_add_or_lock(fib_path_list_get_proto(mt->mt_path_list),
- VNET_LINK_ETHERNET,
- &zero_addr,
- mt->mt_sw_if_index);
-
- mt->mt_l2_tx_arc = vlib_node_add_named_next(vlib_get_main(),
- hi->tx_node_index,
- "adj-l2-midchain");
+ /* can't remove a path if we have onoe */
+ return (0);
}
-
- *sw_if_index = mt->mt_sw_if_index;
+ else
+ {
+ fib_node_index_t old_pl_index;
+ fib_path_ext_t *path_ext;
+
+ old_pl_index = mt->mt_path_list;
+
+ mt->mt_path_list =
+ fib_path_list_copy_and_path_remove(old_pl_index,
+ FIB_PATH_LIST_FLAG_SHARED,
+ rpaths);
+
+ fib_path_list_child_remove(old_pl_index,
+ mt->mt_sibling_index);
+
+ if (FIB_NODE_INDEX_INVALID == mt->mt_path_list)
+ {
+ /* no paths left */
+ return (0);
+ }
+ else
+ {
+ mt->mt_sibling_index =
+ fib_path_list_child_add(mt->mt_path_list,
+ FIB_NODE_TYPE_MPLS_TUNNEL,
+ mti);
+ }
+ /*
+ * find the matching path extension and remove it
+ */
+ vec_foreach(path_ext, mt->mt_path_exts)
+ {
+ if (!fib_path_ext_cmp(path_ext, rpaths))
+ {
+ /*
+ * delete the element moving the remaining elements down 1 position.
+ * this preserves the sorted order.
+ */
+ vec_free(path_ext->fpe_label_stack);
+ vec_delete(mt->mt_path_exts, 1,
+ (path_ext - mt->mt_path_exts));
+ break;
+ }
+ }
+ /*
+ * re-resolve all the path-extensions with the new path-list
+ */
+ vec_foreach(path_ext, mt->mt_path_exts)
+ {
+ fib_path_ext_resolve(path_ext, mt->mt_path_list);
+ }
+
+ mpls_tunnel_restack(mt);
+ }
+
+ return (fib_path_list_get_n_paths(mt->mt_path_list));
}
+
static clib_error_t *
vnet_create_mpls_tunnel_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
{
unformat_input_t _line_input, * line_input = &_line_input;
vnet_main_t * vnm = vnet_get_main();
- u8 is_del = 0;
- u8 l2_only = 0;
+ u8 is_del = 0, l2_only = 0, is_multicast =0;
fib_route_path_t rpath, *rpaths = NULL;
- mpls_label_t out_label = MPLS_LABEL_INVALID, *labels = NULL;
+ mpls_label_t out_label = MPLS_LABEL_INVALID;
u32 sw_if_index;
clib_error_t *error = NULL;
@@ -541,87 +839,89 @@ vnet_create_mpls_tunnel_command_fn (vlib_main_t * vm,
/* Get a line of input. */
if (! unformat_user (input, unformat_line_input, line_input))
- return 0;
+ return 0;
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
- if (unformat (line_input, "del %U",
- unformat_vnet_sw_interface, vnm,
- &sw_if_index))
- is_del = 1;
- else if (unformat (line_input, "add"))
- is_del = 0;
- else if (unformat (line_input, "out-label %U",
- unformat_mpls_unicast_label, &out_label))
- {
- vec_add1(labels, out_label);
- }
- else if (unformat (line_input, "via %U %U",
- unformat_ip4_address,
- &rpath.frp_addr.ip4,
- unformat_vnet_sw_interface, vnm,
- &rpath.frp_sw_if_index))
- {
- rpath.frp_weight = 1;
- rpath.frp_proto = FIB_PROTOCOL_IP4;
- }
-
- else if (unformat (line_input, "via %U %U",
- unformat_ip6_address,
- &rpath.frp_addr.ip6,
- unformat_vnet_sw_interface, vnm,
- &rpath.frp_sw_if_index))
- {
- rpath.frp_weight = 1;
- rpath.frp_proto = FIB_PROTOCOL_IP6;
- }
- else if (unformat (line_input, "via %U",
- unformat_ip6_address,
- &rpath.frp_addr.ip6))
- {
- rpath.frp_fib_index = 0;
- rpath.frp_weight = 1;
- rpath.frp_sw_if_index = ~0;
- rpath.frp_proto = FIB_PROTOCOL_IP6;
- }
- else if (unformat (line_input, "via %U",
- unformat_ip4_address,
- &rpath.frp_addr.ip4))
- {
- rpath.frp_fib_index = 0;
- rpath.frp_weight = 1;
- rpath.frp_sw_if_index = ~0;
- rpath.frp_proto = FIB_PROTOCOL_IP4;
- }
- else if (unformat (line_input, "l2-only"))
- l2_only = 1;
- else
- {
- error = clib_error_return (0, "unknown input '%U'",
- format_unformat_error, line_input);
- goto done;
- }
+ if (unformat (line_input, "del %U",
+ unformat_vnet_sw_interface, vnm,
+ &sw_if_index))
+ is_del = 1;
+ else if (unformat (line_input, "add"))
+ is_del = 0;
+ else if (unformat (line_input, "out-label %U",
+ unformat_mpls_unicast_label, &out_label))
+ {
+ vec_add1(rpath.frp_label_stack, out_label);
+ }
+ else if (unformat (line_input, "via %U %U",
+ unformat_ip4_address,
+ &rpath.frp_addr.ip4,
+ unformat_vnet_sw_interface, vnm,
+ &rpath.frp_sw_if_index))
+ {
+ rpath.frp_weight = 1;
+ rpath.frp_proto = FIB_PROTOCOL_IP4;
+ }
+
+ else if (unformat (line_input, "via %U %U",
+ unformat_ip6_address,
+ &rpath.frp_addr.ip6,
+ unformat_vnet_sw_interface, vnm,
+ &rpath.frp_sw_if_index))
+ {
+ rpath.frp_weight = 1;
+ rpath.frp_proto = FIB_PROTOCOL_IP6;
+ }
+ else if (unformat (line_input, "via %U",
+ unformat_ip6_address,
+ &rpath.frp_addr.ip6))
+ {
+ rpath.frp_fib_index = 0;
+ rpath.frp_weight = 1;
+ rpath.frp_sw_if_index = ~0;
+ rpath.frp_proto = FIB_PROTOCOL_IP6;
+ }
+ else if (unformat (line_input, "via %U",
+ unformat_ip4_address,
+ &rpath.frp_addr.ip4))
+ {
+ rpath.frp_fib_index = 0;
+ rpath.frp_weight = 1;
+ rpath.frp_sw_if_index = ~0;
+ rpath.frp_proto = FIB_PROTOCOL_IP4;
+ }
+ else if (unformat (line_input, "l2-only"))
+ l2_only = 1;
+ else if (unformat (line_input, "multicast"))
+ is_multicast = 1;
+ else
+ {
+ error = clib_error_return (0, "unknown input '%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
}
if (is_del)
{
- vnet_mpls_tunnel_del(sw_if_index);
+ vnet_mpls_tunnel_del(sw_if_index);
}
else
{
- if (0 == vec_len(labels))
- {
- error = clib_error_return (0, "No Output Labels '%U'",
- format_unformat_error, line_input);
- goto done;
- }
-
- vec_add1(rpaths, rpath);
- vnet_mpls_tunnel_add(rpaths, labels, l2_only, &sw_if_index);
+ if (0 == vec_len(rpath.frp_label_stack))
+ {
+ error = clib_error_return (0, "No Output Labels '%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+
+ vec_add1(rpaths, rpath);
+ sw_if_index = vnet_mpls_tunnel_create(l2_only, is_multicast);
+ vnet_mpls_tunnel_path_add(sw_if_index, rpaths);
}
done:
- vec_free(labels);
vec_free(rpaths);
unformat_free (line_input);
@@ -638,7 +938,7 @@ done:
?*/
VLIB_CLI_COMMAND (create_mpls_tunnel_command, static) = {
.path = "mpls tunnel",
- .short_help =
+ .short_help =
"mpls tunnel via [addr] [interface] [out-labels]",
.function = vnet_create_mpls_tunnel_command_fn,
};
@@ -647,19 +947,28 @@ static u8 *
format_mpls_tunnel (u8 * s, va_list * args)
{
mpls_tunnel_t *mt = va_arg (*args, mpls_tunnel_t *);
- int ii;
+ mpls_tunnel_attribute_t attr;
+ fib_path_ext_t *path_ext;
s = format(s, "mpls_tunnel%d: sw_if_index:%d hw_if_index:%d",
- mt - mpls_tunnel_pool,
- mt->mt_sw_if_index,
- mt->mt_hw_if_index);
- s = format(s, "\n label-stack:\n ");
- for (ii = 0; ii < vec_len(mt->mt_label_stack); ii++)
- {
- s = format(s, "%d, ", mt->mt_label_stack[ii]);
+ mt - mpls_tunnel_pool,
+ mt->mt_sw_if_index,
+ mt->mt_hw_if_index);
+ if (MPLS_TUNNEL_FLAG_NONE != mt->mt_flags) {
+ s = format(s, " \n flags:");
+ FOR_EACH_MPLS_TUNNEL_ATTRIBUTE(attr) {
+ if ((1<<attr) & mt->mt_flags) {
+ s = format (s, "%s,", mpls_tunnel_attribute_names[attr]);
+ }
+ }
}
s = format(s, "\n via:\n");
s = fib_path_list_format(mt->mt_path_list, s);
+ s = format(s, " Extensions:");
+ vec_foreach(path_ext, mt->mt_path_exts)
+ {
+ s = format(s, "\n %U", format_fib_path_ext, path_ext);
+ }
s = format(s, "\n");
return (s);
@@ -667,42 +976,42 @@ format_mpls_tunnel (u8 * s, va_list * args)
static clib_error_t *
show_mpls_tunnel_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
{
mpls_tunnel_t * mt;
u32 mti = ~0;
if (pool_elts (mpls_tunnel_pool) == 0)
- vlib_cli_output (vm, "No MPLS tunnels configured...");
+ vlib_cli_output (vm, "No MPLS tunnels configured...");
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
- if (unformat (input, "%d", &mti))
- ;
- else
- break;
+ if (unformat (input, "%d", &mti))
+ ;
+ else
+ break;
}
if (~0 == mti)
{
- pool_foreach (mt, mpls_tunnel_pool,
- ({
- vlib_cli_output (vm, "[@%d] %U",
- mt - mpls_tunnel_pool,
- format_mpls_tunnel, mt);
- }));
+ pool_foreach (mt, mpls_tunnel_pool,
+ ({
+ vlib_cli_output (vm, "[@%d] %U",
+ mt - mpls_tunnel_pool,
+ format_mpls_tunnel, mt);
+ }));
}
else
{
- if (pool_is_free_index(mpls_tunnel_pool, mti))
- return clib_error_return (0, "Not atunnel index %d", mti);
+ if (pool_is_free_index(mpls_tunnel_pool, mti))
+ return clib_error_return (0, "Not atunnel index %d", mti);
- mt = pool_elt_at_index(mpls_tunnel_pool, mti);
+ mt = pool_elt_at_index(mpls_tunnel_pool, mti);
- vlib_cli_output (vm, "[@%d] %U",
- mt - mpls_tunnel_pool,
- format_mpls_tunnel, mt);
+ vlib_cli_output (vm, "[@%d] %U",
+ mt - mpls_tunnel_pool,
+ format_mpls_tunnel, mt);
}
return 0;
@@ -715,7 +1024,7 @@ show_mpls_tunnel_command_fn (vlib_main_t * vm,
* @cliexstart{sh mpls tunnel 2}
* [@2] mpls_tunnel2: sw_if_index:5 hw_if_index:5
* label-stack:
- * 3,
+ * 3,
* via:
* index:26 locks:1 proto:ipv4 uPRF-list:26 len:1 itfs:[2, ]
* index:26 pl-index:26 ipv4 weight=1 attached-nexthop: oper-flags:resolved,
@@ -743,7 +1052,7 @@ mpls_tunnel_from_fib_node (fib_node_t *node)
*/
static fib_node_back_walk_rc_t
mpls_tunnel_back_walk (fib_node_t *node,
- fib_node_back_walk_ctx_t *ctx)
+ fib_node_back_walk_ctx_t *ctx)
{
mpls_tunnel_restack(mpls_tunnel_from_fib_node(node));
diff --git a/src/vnet/mpls/mpls_tunnel.h b/src/vnet/mpls/mpls_tunnel.h
index ee56c0fc8e3..0b55d0dbe3d 100644
--- a/src/vnet/mpls/mpls_tunnel.h
+++ b/src/vnet/mpls/mpls_tunnel.h
@@ -17,6 +17,31 @@
#define __MPLS_TUNNEL_H__
#include <vnet/mpls/mpls.h>
+#include <vnet/fib/fib_path_ext.h>
+
+typedef enum mpls_tunnel_attribute_t_
+{
+ MPLS_TUNNEL_ATTRIBUTE_FIRST = 0,
+ /**
+ * @brief The tunnel has an underlying multicast LSP
+ */
+ MPLS_TUNNEL_ATTRIBUTE_MCAST = MPLS_TUNNEL_ATTRIBUTE_FIRST,
+ MPLS_TUNNEL_ATTRIBUTE_LAST = MPLS_TUNNEL_ATTRIBUTE_MCAST,
+} mpls_tunnel_attribute_t;
+
+#define MPLS_TUNNEL_ATTRIBUTES { \
+ [MPLS_TUNNEL_ATTRIBUTE_MCAST] = "multicast", \
+}
+#define FOR_EACH_MPLS_TUNNEL_ATTRIBUTE(_item) \
+ for (_item = MPLS_TUNNEL_ATTRIBUTE_FIRST; \
+ _item < MPLS_TUNNEL_ATTRIBUTE_LAST; \
+ _item++)
+
+typedef enum mpls_tunnel_flag_t_ {
+ MPLS_TUNNEL_FLAG_NONE = 0,
+ MPLS_TUNNEL_FLAG_MCAST = (1 << MPLS_TUNNEL_ATTRIBUTE_MCAST),
+} __attribute__ ((packed)) mpls_tunnel_flags_t;
+
/**
* @brief A uni-directional MPLS tunnel
@@ -29,6 +54,11 @@ typedef struct mpls_tunnel_t_
fib_node_t mt_node;
/**
+ * @brief Tunnel flags
+ */
+ mpls_tunnel_flags_t mt_flags;
+
+ /**
* @brief If the tunnel is an L2 tunnel, this is the link type ETHERNET
* adjacency
*/
@@ -50,9 +80,9 @@ typedef struct mpls_tunnel_t_
u32 mt_sibling_index;
/**
- * @brief The Label stack to apply to egress packets
+ * A vector of path extensions o hold the label stack for each path
*/
- mpls_label_t *mt_label_stack;
+ fib_path_ext_t *mt_path_exts;
/**
* @brief Flag to indicate the tunnel is only for L2 traffic, that is
@@ -74,12 +104,27 @@ typedef struct mpls_tunnel_t_
/**
* @brief Create a new MPLS tunnel
+ * @return the SW Interface index of the newly created tuneel
*/
-extern void vnet_mpls_tunnel_add (fib_route_path_t *rpath,
- mpls_label_t *label_stack,
- u8 l2_only,
- u32 *sw_if_index);
+extern u32 vnet_mpls_tunnel_create (u8 l2_only,
+ u8 is_multicast);
+/**
+ * @brief Add a path to an MPLS tunnel
+ */
+extern void vnet_mpls_tunnel_path_add (u32 sw_if_index,
+ fib_route_path_t *rpath);
+
+/**
+ * @brief remove a path from a tunnel.
+ * @return the number of remaining paths. 0 implies the tunnel can be deleted
+ */
+extern int vnet_mpls_tunnel_path_remove (u32 sw_if_index,
+ fib_route_path_t *rpath);
+
+/**
+ * @brief Delete an MPLS tunnel
+ */
extern void vnet_mpls_tunnel_del (u32 sw_if_index);
extern const mpls_tunnel_t *mpls_tunnel_get(u32 index);
diff --git a/src/vnet/mpls/mpls_types.h b/src/vnet/mpls/mpls_types.h
index d7c629df832..b1075cdda57 100644
--- a/src/vnet/mpls/mpls_types.h
+++ b/src/vnet/mpls/mpls_types.h
@@ -1,3 +1,17 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#ifndef __MPLS_TYPES_H__
#define __MPLS_TYPES_H__
@@ -36,4 +50,10 @@
(((_lbl) > MPLS_IETF_MIN_UNRES_LABEL) && \
((_lbl) <= MPLS_IETF_MAX_UNRES_LABEL))
+/**
+ * The top bit of the index, which is the result of the MPLS lookup
+ * is used to determine if the DPO is a load-balance or a replicate
+ */
+#define MPLS_IS_REPLICATE 0x80000000
+
#endif
diff --git a/src/vnet/srp/interface.c b/src/vnet/srp/interface.c
index d427cc3c523..44e2b0d6460 100644
--- a/src/vnet/srp/interface.c
+++ b/src/vnet/srp/interface.c
@@ -58,7 +58,7 @@ srp_build_rewrite (vnet_main_t * vnm,
#define _(a,b) case VNET_LINK_##a: type = ETHERNET_TYPE_##b; break
_ (IP4, IP4);
_ (IP6, IP6);
- _ (MPLS, MPLS_UNICAST);
+ _ (MPLS, MPLS);
_ (ARP, ARP);
#undef _
default:
diff --git a/test/test_ip_mcast.py b/test/test_ip_mcast.py
index 36d597a7cf5..c1397d70492 100644
--- a/test/test_ip_mcast.py
+++ b/test/test_ip_mcast.py
@@ -622,6 +622,7 @@ class TestIPMcast(VppTestCase):
(MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT |
MRouteItfFlags.MFIB_ITF_FLAG_NEGATE_SIGNAL))
+ self.vapi.cli("clear trace")
tx = self._mcast_connected_send_stream("232.1.1.1")
signals = self.vapi.mfib_signal_dump()
diff --git a/test/test_mpls.py b/test/test_mpls.py
index fc832644a10..700b70918f6 100644
--- a/test/test_mpls.py
+++ b/test/test_mpls.py
@@ -5,7 +5,9 @@ import socket
from framework import VppTestCase, VppTestRunner
from vpp_ip_route import VppIpRoute, VppRoutePath, VppMplsRoute, \
- VppMplsIpBind
+ VppMplsIpBind, VppIpMRoute, VppMRoutePath, \
+ MRouteItfFlags, MRouteEntryFlags
+from vpp_mpls_tunnel_interface import VppMPLSTunnelInterface
from scapy.packet import Raw
from scapy.layers.l2 import Ether
@@ -21,7 +23,7 @@ class TestMPLS(VppTestCase):
super(TestMPLS, self).setUp()
# create 2 pg interfaces
- self.create_pg_interfaces(range(2))
+ self.create_pg_interfaces(range(4))
# setup both interfaces
# assign them different tables.
@@ -53,10 +55,12 @@ class TestMPLS(VppTestCase):
mpls_labels,
mpls_ttl=255,
ping=0,
- ip_itf=None):
+ ip_itf=None,
+ dst_ip=None,
+ n=257):
self.reset_packet_infos()
pkts = []
- for i in range(0, 257):
+ for i in range(0, n):
info = self.create_packet_info(src_if, src_if)
payload = self.info_to_payload(info)
p = Ether(dst=src_if.local_mac, src=src_if.remote_mac)
@@ -67,9 +71,14 @@ class TestMPLS(VppTestCase):
else:
p = p / MPLS(label=mpls_labels[ii], ttl=mpls_ttl, s=0)
if not ping:
- p = (p / IP(src=src_if.local_ip4, dst=src_if.remote_ip4) /
- UDP(sport=1234, dport=1234) /
- Raw(payload))
+ if not dst_ip:
+ p = (p / IP(src=src_if.local_ip4, dst=src_if.remote_ip4) /
+ UDP(sport=1234, dport=1234) /
+ Raw(payload))
+ else:
+ p = (p / IP(src=src_if.local_ip4, dst=dst_ip) /
+ UDP(sport=1234, dport=1234) /
+ Raw(payload))
else:
p = (p / IP(src=ip_itf.remote_ip4,
dst=ip_itf.local_ip4) /
@@ -254,6 +263,13 @@ class TestMPLS(VppTestCase):
except:
raise
+ def send_and_assert_no_replies(self, intf, pkts, remark):
+ intf.add_stream(pkts)
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+ for i in self.pg_interfaces:
+ i.assert_nothing_captured(remark=remark)
+
def test_swap(self):
""" MPLS label swap tests """
@@ -278,7 +294,7 @@ class TestMPLS(VppTestCase):
self.pg_start()
rx = self.pg0.get_capture()
- self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33])
+ self.verify_capture_labelled(self.pg0, rx, tx, [33])
#
# A simple MPLS xconnect - non-eos label in label out
@@ -358,7 +374,7 @@ class TestMPLS(VppTestCase):
self.pg_start()
rx = self.pg0.get_capture()
- self.verify_capture_labelled_ip4(self.pg0, rx, tx, [33, 44, 45])
+ self.verify_capture_labelled(self.pg0, rx, tx, [33, 44, 45], num=2)
#
# A recursive non-EOS x-connect, which resolves through another
@@ -576,25 +592,19 @@ class TestMPLS(VppTestCase):
#
# Create a tunnel with a single out label
#
- nh_addr = socket.inet_pton(socket.AF_INET, self.pg0.remote_ip4)
-
- reply = self.vapi.mpls_tunnel_add_del(
- 0xffffffff, # don't know the if index yet
- 1, # IPv4 next-hop
- nh_addr,
- self.pg0.sw_if_index,
- 0, # next-hop-table-id
- 1, # next-hop-weight
- 2, # num-out-labels,
- [44, 46])
- self.vapi.sw_interface_set_flags(reply.sw_if_index, admin_up_down=1)
+ mpls_tun = VppMPLSTunnelInterface(self,
+ [VppRoutePath(self.pg0.remote_ip4,
+ self.pg0.sw_if_index,
+ labels=[44, 46])])
+ mpls_tun.add_vpp_config()
+ mpls_tun.admin_up()
#
# add an unlabelled route through the new tunnel
#
route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
[VppRoutePath("0.0.0.0",
- reply.sw_if_index)])
+ mpls_tun._sw_if_index)])
route_10_0_0_3.add_vpp_config()
self.vapi.cli("clear trace")
@@ -738,6 +748,229 @@ class TestMPLS(VppTestCase):
route_35_eos.remove_vpp_config()
route_34_eos.remove_vpp_config()
+ def test_interface_rx(self):
+ """ MPLS Interface Receive """
+
+ #
+ # Add a non-recursive route that will forward the traffic
+ # post-interface-rx
+ #
+ route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
+ table_id=1,
+ paths=[VppRoutePath(self.pg1.remote_ip4,
+ self.pg1.sw_if_index)])
+ route_10_0_0_1.add_vpp_config()
+
+ #
+ # An interface receive label that maps traffic to RX on interface
+ # pg1
+ # by injecting the packet in on pg0, which is in table 0
+ # doing an interface-rx on pg1 and matching a route in table 1
+ # if the packet egresses, then we must have swapped to pg1
+ # so as to have matched the route in table 1
+ #
+ route_34_eos = VppMplsRoute(self, 34, 1,
+ [VppRoutePath("0.0.0.0",
+ self.pg1.sw_if_index,
+ is_interface_rx=1)])
+ route_34_eos.add_vpp_config()
+
+ #
+ # ping an interface in the default table
+ # PG0 is in the default table
+ #
+ self.vapi.cli("clear trace")
+ tx = self.create_stream_labelled_ip4(self.pg0, [34], n=257,
+ dst_ip="10.0.0.1")
+ self.pg0.add_stream(tx)
+
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg1.get_capture(257)
+ self.verify_capture_ip4(self.pg1, rx, tx)
+
+ def test_mcast_mid_point(self):
+ """ MPLS Multicast Mid Point """
+
+ #
+ # Add a non-recursive route that will forward the traffic
+ # post-interface-rx
+ #
+ route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
+ table_id=1,
+ paths=[VppRoutePath(self.pg1.remote_ip4,
+ self.pg1.sw_if_index)])
+ route_10_0_0_1.add_vpp_config()
+
+ #
+ # Add a mcast entry that replicate to pg2 and pg3
+ # and replicate to a interface-rx (like a bud node would)
+ #
+ route_3400_eos = VppMplsRoute(self, 3400, 1,
+ [VppRoutePath(self.pg2.remote_ip4,
+ self.pg2.sw_if_index,
+ labels=[3401]),
+ VppRoutePath(self.pg3.remote_ip4,
+ self.pg3.sw_if_index,
+ labels=[3402]),
+ VppRoutePath("0.0.0.0",
+ self.pg1.sw_if_index,
+ is_interface_rx=1)],
+ is_multicast=1)
+ route_3400_eos.add_vpp_config()
+
+ #
+ # ping an interface in the default table
+ # PG0 is in the default table
+ #
+ self.vapi.cli("clear trace")
+ tx = self.create_stream_labelled_ip4(self.pg0, [3400], n=257,
+ dst_ip="10.0.0.1")
+ self.pg0.add_stream(tx)
+
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg1.get_capture(257)
+ self.verify_capture_ip4(self.pg1, rx, tx)
+
+ rx = self.pg2.get_capture(257)
+ self.verify_capture_labelled(self.pg2, rx, tx, [3401])
+ rx = self.pg3.get_capture(257)
+ self.verify_capture_labelled(self.pg3, rx, tx, [3402])
+
+ def test_mcast_head(self):
+ """ MPLS Multicast Head-end """
+
+ #
+ # Create a multicast tunnel with two replications
+ #
+ mpls_tun = VppMPLSTunnelInterface(self,
+ [VppRoutePath(self.pg2.remote_ip4,
+ self.pg2.sw_if_index,
+ labels=[42]),
+ VppRoutePath(self.pg3.remote_ip4,
+ self.pg3.sw_if_index,
+ labels=[43])],
+ is_multicast=1)
+ mpls_tun.add_vpp_config()
+ mpls_tun.admin_up()
+
+ #
+ # add an unlabelled route through the new tunnel
+ #
+ route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
+ [VppRoutePath("0.0.0.0",
+ mpls_tun._sw_if_index)])
+ route_10_0_0_3.add_vpp_config()
+
+ self.vapi.cli("clear trace")
+ tx = self.create_stream_ip4(self.pg0, "10.0.0.3")
+ self.pg0.add_stream(tx)
+
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg2.get_capture(257)
+ self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [42])
+ rx = self.pg3.get_capture(257)
+ self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [43])
+
+ #
+ # An an IP multicast route via the tunnel
+ # A (*,G).
+ # one accepting interface, pg0, 1 forwarding interface via the tunnel
+ #
+ route_232_1_1_1 = VppIpMRoute(
+ self,
+ "0.0.0.0",
+ "232.1.1.1", 32,
+ MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
+ [VppMRoutePath(self.pg0.sw_if_index,
+ MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
+ VppMRoutePath(mpls_tun._sw_if_index,
+ MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
+ route_232_1_1_1.add_vpp_config()
+
+ self.vapi.cli("clear trace")
+ tx = self.create_stream_ip4(self.pg0, "232.1.1.1")
+ self.pg0.add_stream(tx)
+
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg2.get_capture(257)
+ self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [42])
+ rx = self.pg3.get_capture(257)
+ self.verify_capture_tunneled_ip4(self.pg0, rx, tx, [43])
+
+ def test_mcast_tail(self):
+ """ MPLS Multicast Tail """
+
+ #
+ # Add a multicast route that will forward the traffic
+ # post-disposition
+ #
+ route_232_1_1_1 = VppIpMRoute(
+ self,
+ "0.0.0.0",
+ "232.1.1.1", 32,
+ MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
+ table_id=1,
+ paths=[VppMRoutePath(self.pg1.sw_if_index,
+ MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
+ route_232_1_1_1.add_vpp_config()
+
+ #
+ # An interface receive label that maps traffic to RX on interface
+ # pg1
+ # by injecting the packet in on pg0, which is in table 0
+ # doing an rpf-id and matching a route in table 1
+ # if the packet egresses, then we must have matched the route in
+ # table 1
+ #
+ route_34_eos = VppMplsRoute(self, 34, 1,
+ [VppRoutePath("0.0.0.0",
+ self.pg1.sw_if_index,
+ nh_table_id=1,
+ rpf_id=55)],
+ is_multicast=1)
+
+ route_34_eos.add_vpp_config()
+
+ #
+ # Drop due to interface lookup miss
+ #
+ self.vapi.cli("clear trace")
+ tx = self.create_stream_labelled_ip4(self.pg0, [34],
+ dst_ip="232.1.1.1", n=1)
+ self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop none")
+
+ #
+ # set the RPF-ID of the enrtry to match the input packet's
+ #
+ route_232_1_1_1.update_rpf_id(55)
+
+ self.vapi.cli("clear trace")
+ tx = self.create_stream_labelled_ip4(self.pg0, [34],
+ dst_ip="232.1.1.1", n=257)
+ self.pg0.add_stream(tx)
+
+ self.pg_enable_capture(self.pg_interfaces)
+ self.pg_start()
+
+ rx = self.pg1.get_capture(257)
+ self.verify_capture_ip4(self.pg1, rx, tx)
+
+ #
+ # set the RPF-ID of the enrtry to not match the input packet's
+ #
+ route_232_1_1_1.update_rpf_id(56)
+ tx = self.create_stream_labelled_ip4(self.pg0, [34],
+ dst_ip="232.1.1.1")
+ self.send_and_assert_no_replies(self.pg0, tx, "RPF-ID drop 56")
+
class TestMPLSDisabled(VppTestCase):
""" MPLS disabled """
diff --git a/test/vpp_ip_route.py b/test/vpp_ip_route.py
index faf5f801b4b..d6146f28fab 100644
--- a/test/vpp_ip_route.py
+++ b/test/vpp_ip_route.py
@@ -55,15 +55,24 @@ class VppRoutePath(object):
nh_table_id=0,
labels=[],
nh_via_label=MPLS_LABEL_INVALID,
- is_ip6=0):
+ is_ip6=0,
+ rpf_id=0,
+ is_interface_rx=0):
self.nh_itf = nh_sw_if_index
self.nh_table_id = nh_table_id
self.nh_via_label = nh_via_label
self.nh_labels = labels
+ self.weight = 1
+ self.rpf_id = rpf_id
if is_ip6:
self.nh_addr = inet_pton(AF_INET6, nh_addr)
else:
self.nh_addr = inet_pton(AF_INET, nh_addr)
+ self.is_interface_rx = is_interface_rx
+ self.is_rpf_id = 0
+ if rpf_id != 0:
+ self.is_rpf_id = 1
+ self.nh_itf = rpf_id
class VppMRoutePath(VppRoutePath):
@@ -176,13 +185,15 @@ class VppIpMRoute(VppObject):
"""
def __init__(self, test, src_addr, grp_addr,
- grp_addr_len, e_flags, paths, table_id=0, is_ip6=0):
+ grp_addr_len, e_flags, paths, table_id=0,
+ rpf_id=0, is_ip6=0):
self._test = test
self.paths = paths
self.grp_addr_len = grp_addr_len
self.table_id = table_id
self.e_flags = e_flags
self.is_ip6 = is_ip6
+ self.rpf_id = rpf_id
if is_ip6:
self.grp_addr = inet_pton(AF_INET6, grp_addr)
@@ -199,6 +210,7 @@ class VppIpMRoute(VppObject):
self.e_flags,
path.nh_itf,
path.nh_i_flags,
+ rpf_id=self.rpf_id,
table_id=self.table_id,
is_ipv6=self.is_ip6)
self._test.registry.register(self, self._test.logger)
@@ -226,6 +238,18 @@ class VppIpMRoute(VppObject):
table_id=self.table_id,
is_ipv6=self.is_ip6)
+ def update_rpf_id(self, rpf_id):
+ self.rpf_id = rpf_id
+ self._test.vapi.ip_mroute_add_del(self.src_addr,
+ self.grp_addr,
+ self.grp_addr_len,
+ self.e_flags,
+ 0xffffffff,
+ 0,
+ rpf_id=self.rpf_id,
+ table_id=self.table_id,
+ is_ipv6=self.is_ip6)
+
def update_path_flags(self, itf, flags):
for path in self.paths:
if path.nh_itf == itf:
@@ -342,14 +366,17 @@ class VppMplsRoute(VppObject):
MPLS Route/LSP
"""
- def __init__(self, test, local_label, eos_bit, paths, table_id=0):
+ def __init__(self, test, local_label, eos_bit, paths, table_id=0,
+ is_multicast=0):
self._test = test
self.paths = paths
self.local_label = local_label
self.eos_bit = eos_bit
self.table_id = table_id
+ self.is_multicast = is_multicast
def add_vpp_config(self):
+ is_multipath = len(self.paths) > 1
for path in self.paths:
self._test.vapi.mpls_route_add_del(
self.local_label,
@@ -357,7 +384,11 @@ class VppMplsRoute(VppObject):
1,
path.nh_addr,
path.nh_itf,
+ is_multicast=self.is_multicast,
+ is_multipath=is_multipath,
table_id=self.table_id,
+ is_interface_rx=path.is_interface_rx,
+ is_rpf_id=path.is_rpf_id,
next_hop_out_label_stack=path.nh_labels,
next_hop_n_out_labels=len(
path.nh_labels),
@@ -372,6 +403,7 @@ class VppMplsRoute(VppObject):
1,
path.nh_addr,
path.nh_itf,
+ is_rpf_id=path.is_rpf_id,
table_id=self.table_id,
is_add=0)
diff --git a/test/vpp_mpls_tunnel_interface.py b/test/vpp_mpls_tunnel_interface.py
new file mode 100644
index 00000000000..f200157444b
--- /dev/null
+++ b/test/vpp_mpls_tunnel_interface.py
@@ -0,0 +1,46 @@
+
+from vpp_interface import VppInterface
+from vpp_ip_route import VppRoutePath
+import socket
+
+
+class VppMPLSTunnelInterface(VppInterface):
+ """
+ VPP MPLS Tunnel interface
+ """
+
+ def __init__(self, test, paths, is_multicast=0):
+ """ Create MPLS Tunnel interface """
+ self._sw_if_index = 0
+ super(VppMPLSTunnelInterface, self).__init__(test)
+ self._test = test
+ self.t_paths = paths
+ self.is_multicast = is_multicast
+
+ def add_vpp_config(self):
+ self._sw_if_index = 0xffffffff
+ for path in self.t_paths:
+ reply = self.test.vapi.mpls_tunnel_add_del(
+ self._sw_if_index,
+ 1, # IPv4 next-hop
+ path.nh_addr,
+ path.nh_itf,
+ path.nh_table_id,
+ path.weight,
+ next_hop_out_label_stack=path.nh_labels,
+ next_hop_n_out_labels=len(path.nh_labels),
+ is_multicast=self.is_multicast)
+ self._sw_if_index = reply.sw_if_index
+
+ def remove_vpp_config(self):
+ for path in self.t_paths:
+ reply = self.test.vapi.mpls_tunnel_add_del(
+ self.sw_if_index,
+ 1, # IPv4 next-hop
+ path.nh_addr,
+ path.nh_itf,
+ path.nh_table_id,
+ path.weight,
+ next_hop_out_label_stack=path.nh_labels,
+ next_hop_n_out_labels=len(path.nh_labels),
+ is_add=0)
diff --git a/test/vpp_papi_provider.py b/test/vpp_papi_provider.py
index e8025dff68e..ceb684b75f6 100644
--- a/test/vpp_papi_provider.py
+++ b/test/vpp_papi_provider.py
@@ -849,6 +849,9 @@ class VppPapiProvider(object):
create_vrf_if_needed=0,
is_resolve_host=0,
is_resolve_attached=0,
+ is_interface_rx=0,
+ is_rpf_id=0,
+ is_multicast=0,
is_add=1,
is_drop=0,
is_multipath=0,
@@ -872,6 +875,7 @@ class VppPapiProvider(object):
:param is_local: (Default value = 0)
:param is_classify: (Default value = 0)
:param is_multipath: (Default value = 0)
+ :param is_multicast: (Default value = 0)
:param is_resolve_host: (Default value = 0)
:param is_resolve_attached: (Default value = 0)
:param not_last: (Default value = 0)
@@ -889,8 +893,11 @@ class VppPapiProvider(object):
'mr_is_add': is_add,
'mr_is_classify': is_classify,
'mr_is_multipath': is_multipath,
+ 'mr_is_multicast': is_multicast,
'mr_is_resolve_host': is_resolve_host,
'mr_is_resolve_attached': is_resolve_attached,
+ 'mr_is_interface_rx': is_interface_rx,
+ 'mr_is_rpf_id': is_rpf_id,
'mr_next_hop_proto_is_ip4': next_hop_proto_is_ip4,
'mr_next_hop_weight': next_hop_weight,
'mr_next_hop': next_hop_address,
@@ -936,7 +943,8 @@ class VppPapiProvider(object):
next_hop_via_label=MPLS_LABEL_INVALID,
create_vrf_if_needed=0,
is_add=1,
- l2_only=0):
+ l2_only=0,
+ is_multicast=0):
"""
:param dst_address_length:
@@ -956,8 +964,8 @@ class VppPapiProvider(object):
:param is_multipath: (Default value = 0)
:param is_resolve_host: (Default value = 0)
:param is_resolve_attached: (Default value = 0)
- :param not_last: (Default value = 0)
:param next_hop_weight: (Default value = 1)
+ :param is_multicast: (Default value = 0)
"""
return self.api(
@@ -965,6 +973,7 @@ class VppPapiProvider(object):
{'mt_sw_if_index': tun_sw_if_index,
'mt_is_add': is_add,
'mt_l2_only': l2_only,
+ 'mt_is_multicast': is_multicast,
'mt_next_hop_proto_is_ip4': next_hop_proto_is_ip4,
'mt_next_hop_weight': next_hop_weight,
'mt_next_hop': next_hop_address,
@@ -1469,6 +1478,7 @@ class VppPapiProvider(object):
e_flags,
next_hop_sw_if_index,
i_flags,
+ rpf_id=0,
table_id=0,
create_vrf_if_needed=0,
is_add=1,
@@ -1481,6 +1491,8 @@ class VppPapiProvider(object):
{'next_hop_sw_if_index': next_hop_sw_if_index,
'entry_flags': e_flags,
'itf_flags': i_flags,
+ 'table_id': table_id,
+ 'rpf_id': rpf_id,
'create_vrf_if_needed': create_vrf_if_needed,
'is_add': is_add,
'is_ipv6': is_ipv6,