+static void
+bfd_create_frame_to_next_node (vlib_main_t *vm, vlib_node_runtime_t *rt,
+ u32 bi, const bfd_session_t *bs, u32 next,
+ vlib_combined_counter_main_t *tx_counter)
+{
+ vlib_buffer_t *b = vlib_get_buffer (vm, bi);
+ vlib_node_t *from_node = vlib_get_node (vm, rt->node_index);
+ ASSERT (next < vec_len (from_node->next_nodes));
+ u32 to_node_index = from_node->next_nodes[next];
+ vlib_frame_t *f = vlib_get_frame_to_node (vm, to_node_index);
+ u32 *to_next = vlib_frame_vector_args (f);
+ to_next[0] = bi;
+ f->n_vectors = 1;
+ if (b->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ f->frame_flags |= VLIB_NODE_FLAG_TRACE;
+ }
+ vlib_put_frame_to_node (vm, to_node_index, f);
+ vlib_increment_combined_counter (tx_counter, vm->thread_index, bs->bs_idx, 1,
+ vlib_buffer_length_in_chain (vm, b));
+}
+
+int
+bfd_udp_calc_next_node (const struct bfd_session_s *bs, u32 * next_node)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ const bfd_udp_session_t *bus = &bs->udp;
+ ip_adjacency_t *adj = adj_get (bus->adj_index);
+
+ /* don't try to send the buffer if the interface is not up */
+ if (!vnet_sw_interface_is_up (vnm, bus->key.sw_if_index))
+ return 0;
+
+ switch (adj->lookup_next_index)
+ {
+ case IP_LOOKUP_NEXT_ARP:
+ switch (bs->transport)
+ {
+ case BFD_TRANSPORT_UDP4:
+ *next_node = BFD_TX_IP4_ARP;
+ return 1;
+ case BFD_TRANSPORT_UDP6:
+ *next_node = BFD_TX_IP6_NDP;
+ return 1;
+ }
+ break;
+ case IP_LOOKUP_NEXT_REWRITE:
+ switch (bs->transport)
+ {
+ case BFD_TRANSPORT_UDP4:
+ *next_node = BFD_TX_IP4_REWRITE;
+ return 1;
+ case BFD_TRANSPORT_UDP6:
+ *next_node = BFD_TX_IP6_REWRITE;
+ return 1;
+ }
+ break;
+ case IP_LOOKUP_NEXT_MIDCHAIN:
+ switch (bs->transport)
+ {
+ case BFD_TRANSPORT_UDP4:
+ *next_node = BFD_TX_IP4_MIDCHAIN;
+ return 1;
+ case BFD_TRANSPORT_UDP6:
+ *next_node = BFD_TX_IP6_MIDCHAIN;
+ return 1;
+ }
+ break;
+ default:
+ /* drop */
+ break;
+ }
+ return 0;
+}
+
+int
+bfd_transport_udp4 (vlib_main_t *vm, vlib_node_runtime_t *rt, u32 bi,
+ const struct bfd_session_s *bs, int is_echo)
+{
+ u32 next_node;
+ int rv = bfd_udp_calc_next_node (bs, &next_node);
+ bfd_main_t *bm = bfd_udp_main.bfd_main;
+ if (rv)
+ {
+ bfd_create_frame_to_next_node (vm, rt, bi, bs, next_node,
+ is_echo ? &bm->tx_echo_counter :
+ &bm->tx_counter);
+ }
+ return rv;
+}
+
+int
+bfd_transport_udp6 (vlib_main_t *vm, vlib_node_runtime_t *rt, u32 bi,
+ const struct bfd_session_s *bs, int is_echo)
+{
+ u32 next_node;
+ int rv = bfd_udp_calc_next_node (bs, &next_node);
+ bfd_main_t *bm = bfd_udp_main.bfd_main;
+ if (rv)
+ {
+ bfd_create_frame_to_next_node (vm, rt, bi, bs, next_node,
+ is_echo ? &bm->tx_echo_counter :
+ &bm->tx_counter);
+ }
+ return 1;
+}
+