#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
#define REP_DBG(_p, _fmt, _args...)
#endif
+#define foreach_replicate_dpo_error \
+_(BUFFER_ALLOCATION_FAILURE, "Buffer Allocation Failure")
+
+typedef enum {
+#define _(sym,str) REPLICATE_DPO_ERROR_##sym,
+ foreach_replicate_dpo_error
+#undef _
+ REPLICATE_DPO_N_ERROR,
+} replicate_dpo_error_t;
+
+static char * replicate_dpo_error_strings[] = {
+#define _(sym,string) string,
+ foreach_replicate_dpo_error
+#undef _
+};
/**
* Pool of all DPOs. It's not static so the DP can have fast access
/**
* The one instance of replicate main
*/
-replicate_main_t replicate_main;
+replicate_main_t replicate_main = {
+ .repm_counters = {
+ .name = "mroutes",
+ .stat_segment_name = "/net/mroute",
+ },
+};
static inline index_t
replicate_get_index (const replicate_t *rep)
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);
replicate_t *rep;
dpo_id_t *buckets;
+ repi &= ~MPLS_IS_REPLICATE;
rep = replicate_get(repi);
buckets = replicate_get_buckets(rep);
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)
{
{
replicate_t *rep;
+ repi &= ~MPLS_IS_REPLICATE;
rep = replicate_get(repi);
return (replicate_get_bucket_i(rep, bucket));
u32 n_buckets)
{
load_balance_path_t * nh;
- u16 ii, bucket;
+ u16 bucket;
bucket = 0;
*/
vec_foreach (nh, nhs)
{
- for (ii = 0; ii < nh->path_weight; ii++)
- {
- ASSERT(bucket < n_buckets);
- replicate_set_bucket_i(rep, bucket++, buckets, &nh->path_dpo);
- }
+ ASSERT(bucket < n_buckets);
+ replicate_set_bucket_i(rep, bucket++, buckets, &nh->path_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);
vlib_frame_t * frame)
{
vlib_combined_counter_main_t * cm = &replicate_main.repm_counters;
+ replicate_main_t * rm = &replicate_main;
u32 n_left_from, * from, * to_next, next_index;
- u32 cpu_index = os_get_cpu_number();
+ u32 thread_index = vlib_get_thread_index();
from = vlib_frame_vector_args (frame);
n_left_from = frame->n_vectors;
const replicate_t *rep0;
vlib_buffer_t * b0, *c0;
const dpo_id_t *dpo0;
+ u8 num_cloned;
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);
repi0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
rep0 = replicate_get(repi0);
vlib_increment_combined_counter(
- cm, cpu_index, repi0, 1,
+ cm, thread_index, repi0, 1,
vlib_buffer_length_in_chain(vm, b0));
- /* ship the original to the first bucket */
- dpo0 = replicate_get_bucket_i(rep0, 0);
- next0 = dpo0->dpoi_next_node;
- vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
+ vec_validate (rm->clones[thread_index], rep0->rep_n_buckets - 1);
- if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
- {
- replicate_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
- t->rep_index = repi0;
- t->dpo = *dpo0;
- }
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
- to_next, n_left_to_next,
- bi0, next0);
+ num_cloned = vlib_buffer_clone (vm, bi0, rm->clones[thread_index],
+ rep0->rep_n_buckets, 128);
+
+ if (num_cloned != rep0->rep_n_buckets)
+ {
+ vlib_node_increment_counter
+ (vm, node->node_index,
+ REPLICATE_DPO_ERROR_BUFFER_ALLOCATION_FAILURE, 1);
+ }
- /* ship copies to the rest of the buckets */
- for (bucket = 1; bucket < rep0->rep_n_buckets; bucket++)
+ for (bucket = 0; bucket < num_cloned; bucket++)
{
- /* Make a copy */
- c0 = vlib_buffer_copy(vm, b0);
- ci0 = vlib_get_buffer_index(vm, c0);
+ ci0 = rm->clones[thread_index][bucket];
+ c0 = vlib_get_buffer(vm, ci0);
to_next[0] = ci0;
to_next += 1;
next0 = dpo0->dpoi_next_node;
vnet_buffer (c0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
- if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
+ if (PREDICT_FALSE(c0->flags & VLIB_BUFFER_IS_TRACED))
{
- replicate_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+ replicate_trace_t *t;
+
+ vlib_trace_buffer (vm, node, next0, c0, 0);
+ t = vlib_add_trace (vm, node, c0, sizeof (*t));
t->rep_index = repi0;
t->dpo = *dpo0;
}
vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
to_next, n_left_to_next,
ci0, next0);
+ if (PREDICT_FALSE (n_left_to_next == 0))
+ {
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+ }
}
+ vec_reset_length (rm->clones[thread_index]);
}
vlib_put_next_frame (vm, node, next_index, n_left_to_next);
s = format (s, "replicate: %d via %U",
t->rep_index,
- format_dpo_id, &t->dpo);
+ format_dpo_id, &t->dpo, 0);
return s;
}
}
/**
- * @brief
+ * @brief IP4 replication node
*/
VLIB_REGISTER_NODE (ip4_replicate_node) = {
.function = ip4_replicate,
.name = "ip4-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] = "error-drop",
+ [0] = "ip4-drop",
},
};
}
/**
- * @brief
+ * @brief IPv6 replication node
*/
VLIB_REGISTER_NODE (ip6_replicate_node) = {
.function = ip6_replicate,
.name = "ip6-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] = "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] = "error-drop",
+ [0] = "mpls-drop",
},
};
+
+clib_error_t *
+replicate_dpo_init (vlib_main_t * vm)
+{
+ replicate_main_t * rm = &replicate_main;
+
+ vec_validate (rm->clones, vlib_num_workers());
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (replicate_dpo_init);