+
+typedef enum lookup_ip_dst_mcast_next_t_ {
+ LOOKUP_IP_DST_MCAST_NEXT_DROP,
+ 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_fwd_lookup(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;
+
+ if (!(b0->flags & VNET_BUFFER_F_LOOP_COUNTER_VALID)) {
+ vnet_buffer2(b0)->loop_counter = 0;
+ b0->flags |= VNET_BUFFER_F_LOOP_COUNTER_VALID;
+ }
+
+ vnet_buffer2(b0)->loop_counter++;
+
+ if (PREDICT_FALSE(vnet_buffer2(b0)->loop_counter > MAX_LUKPS_PER_PACKET))
+ next0 = LOOKUP_IP_DST_MCAST_NEXT_DROP;
+
+ 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;
+}
+
+VLIB_NODE_FN (lookup_ip4_dst_mcast_node) (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) = {
+ .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_DROP] = "ip4-drop",
+ [LOOKUP_IP_DST_MCAST_NEXT_RPF] = "ip4-mfib-forward-rpf",
+ },
+};
+
+VLIB_NODE_FN (lookup_ip6_dst_mcast_node) (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, 0));
+}
+
+VLIB_REGISTER_NODE (lookup_ip6_dst_mcast_node) = {
+ .name = "lookup-ip6-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_DROP] = "ip6-drop",
+ [LOOKUP_IP_DST_MCAST_NEXT_RPF] = "ip6-mfib-forward-rpf",
+ },
+};