27 #define dhcpv6_proxy_error(n,s) s, 29 #undef dhcpv6_proxy_error 32 #define foreach_dhcpv6_proxy_to_server_input_next \ 33 _ (DROP, "error-drop") \ 34 _ (LOOKUP, "ip6-lookup") \ 35 _ (SEND_TO_CLIENT, "dhcpv6-proxy-to-client") 40 #define _(s,n) DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_##s, 71 s =
format (s,
"DHCPV6 proxy: sent to server %U",
74 s =
format (s,
"DHCPV6 proxy: sent to client from %U",
79 s =
format (s,
" original_sw_if_index: %d, sw_if_index: %d\n",
89 u32 max_header_bytes = va_arg (*args,
u32);
92 header_bytes =
sizeof (h[0]);
93 if (max_header_bytes != 0 && header_bytes > max_header_bytes)
94 return format (s,
"dhcpv6 header truncated");
96 s =
format (s,
"DHCPV6 Proxy");
114 if ((a->
as_u8[0] & 0xe0) == 0x20 ||
115 (a->
as_u8[0] & 0xfe) == 0xfc) {
136 u32 n_left_from, next_index, *from, *to_next;
140 u32 pkts_to_server = 0, pkts_to_client = 0, pkts_no_server = 0;
141 u32 pkts_no_interface_address = 0, pkts_no_exceeding_max_hop = 0;
142 u32 pkts_no_src_address = 0;
143 u32 pkts_wrong_msg_type = 0;
144 u32 pkts_too_big = 0;
150 u32 rx_fib_idx = 0, server_fib_idx = 0;
154 while (n_left_from > 0)
160 while (n_left_from > 0 && n_left_to_next > 0)
164 u32 rx_sw_if_index = 0;
174 dhcpv6_option_t *fwd_opt;
175 dhcpv6_relay_hdr_t *r1;
177 dhcpv6_int_id_t *id1;
179 dhcpv6_client_mac_t *cmac;
181 u8 client_src_mac[6];
196 u0 = (
void *) h0 - (
sizeof (*u0));
197 ip0 = (
void *) u0 - (
sizeof (*ip0));
217 next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_SEND_TO_CLIENT;
223 pkts_wrong_msg_type++;
224 error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE;
225 next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
231 rx_sw_if_index = sw_if_index =
238 error0 = DHCPV6_PROXY_ERROR_NO_SERVER;
239 next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
267 fwd_opt->length = clib_host_to_net_u16 (len);
268 fwd_opt->option = clib_host_to_net_u16 (DHCPV6_OPTION_RELAY_MSG);
277 next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
278 pkts_no_exceeding_max_hop++;
289 r1->link_addr.as_u64[0] = 0;
290 r1->link_addr.as_u64[1] = 0;
291 goto link_address_set;
308 error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS;
309 next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
310 pkts_no_interface_address++;
319 sizeof (*vss1) +
sizeof (*cmac)) >
322 error0 = DHCPV6_PROXY_ERROR_PKT_TOO_BIG;
323 next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
331 id1->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_INTERFACE_ID);
332 id1->opt.length = clib_host_to_net_u16 (
sizeof (rx_sw_if_index));
333 id1->int_idx = clib_host_to_net_u32 (rx_sw_if_index);
341 cmac->opt.length = clib_host_to_net_u16 (
sizeof (*cmac) -
345 (DHCPV6_OPTION_CLIENT_LINK_LAYER_ADDRESS);
346 cmac->link_type = clib_host_to_net_u16 (1);
348 u1->
length +=
sizeof (*cmac);
356 u16 type_len =
sizeof (vss1->vss_type);
362 id_len =
sizeof (vss->
vpn_id);
363 memcpy (vss1->data, vss->
vpn_id, id_len);
373 vss1->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_VSS);
374 vss1->opt.length = clib_host_to_net_u16 (type_len + id_len);
375 u1->
length += type_len + id_len +
sizeof (vss1->opt);
381 u1->
src_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcpv6_to_client);
382 u1->
dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcpv6_to_server);
385 clib_host_to_net_u16 (clib_net_to_host_u16 (fwd_opt->length) +
386 sizeof (*r1) +
sizeof (*fwd_opt) +
387 sizeof (*u1) +
sizeof (*id1) + u1->
length);
390 ip1->ip_version_traffic_class_and_flow_label = 0x60;
391 ip1->payload_length = u1->
length;
396 &server->
dhcp_server.ip6 : &all_dhcpv6_server_address);
408 error0 = DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS;
409 next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_DROP;
410 pkts_no_src_address++;
419 ASSERT (bogus_length == 0);
421 next0 = DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP;
444 DHCPV6_PROXY_ERROR_ALLOC_FAIL, 1);
456 &all_dhcpv6_server_address);
464 to_next, n_left_to_next,
476 if (next0 == DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP)
487 to_next, n_left_to_next);
501 if (DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_LOOKUP == next0)
512 to_next, n_left_to_next,
520 DHCPV6_PROXY_ERROR_RELAY_TO_CLIENT,
523 DHCPV6_PROXY_ERROR_RELAY_TO_SERVER,
526 DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS,
527 pkts_no_interface_address);
529 DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE,
530 pkts_wrong_msg_type);
532 DHCPV6_PROXY_ERROR_NO_SRC_ADDRESS,
533 pkts_no_src_address);
535 DHCPV6_PROXY_ERROR_PKT_TOO_BIG, pkts_too_big);
542 .name =
"dhcpv6-proxy-to-server",
544 .vector_size =
sizeof (
u32),
551 #define _(s,n) [DHCPV6_PROXY_TO_SERVER_INPUT_NEXT_##s] = n, 559 .unformat_buffer = unformat_dhcpv6_proxy_header,
570 u32 n_left_from, *from;
581 while (n_left_from > 0)
586 dhcpv6_relay_hdr_t *h0;
596 u32 original_sw_if_index = ~0;
600 dhcpv6_option_t *r0 = 0, *o;
602 u8 interface_opt_flag = 0;
603 u8 relay_msg_opt_flag = 0;
605 u32 server_fib_idx, client_fib_idx;
616 error0 = DHCPV6_PROXY_ERROR_WRONG_MESSAGE_TYPE;
630 if (HOP_COUNT_LIMIT < h0->hop_count)
635 u0 = (
void *) h0 - (
sizeof (*u0));
636 ip0 = (
void *) u0 - (
sizeof (*ip0));
649 if (DHCPV6_OPTION_INTERFACE_ID == clib_net_to_host_u16 (o->option))
651 interface_opt_flag = 1;
652 if (clib_net_to_host_u16 (o->length) == sizeof (sw_if_index))
654 clib_net_to_host_u32 (((dhcpv6_int_id_t *) o)->int_idx);
657 error0 = DHCPV6_PROXY_ERROR_WRONG_INTERFACE_ID_OPTION;
661 if (DHCPV6_OPTION_RELAY_MSG == clib_net_to_host_u16 (o->option))
663 relay_msg_opt_flag = 1;
666 if ((relay_msg_opt_flag == 1) && (interface_opt_flag == 1))
670 clib_net_to_host_u16 (o->length));
672 (dhcpv6_option_t *) (((
uword) o) +
673 clib_net_to_host_u16 (o->length) +
677 if ((relay_msg_opt_flag == 0) || (r0 == 0))
679 error0 = DHCPV6_PROXY_ERROR_NO_RELAY_MESSAGE_OPTION;
685 error0 = DHCPV6_PROXY_ERROR_NO_CIRCUIT_ID_OPTION;
697 error0 = DHCPV6_PROXY_ERROR_NO_SERVER;
707 ip0->src_address.as_u64[0] == server->
dhcp_server.ip6.as_u64[0] &&
708 ip0->src_address.as_u64[1] == server->
dhcp_server.ip6.as_u64[1])
715 error0 = DHCPV6_PROXY_ERROR_BAD_SVR_FIB_OR_ADDRESS;
742 error0 = DHCPV6_PROXY_ERROR_NO_INTERFACE_ADDRESS;
746 len = clib_net_to_host_u16 (r0->length);
750 u1->
src_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcpv6_to_server);
751 u1->
dst_port = clib_net_to_host_u16 (UDP_DST_PORT_dhcpv6_to_client);
755 ip0->ip_version_traffic_class_and_flow_label & 0x00000fff;
763 ASSERT (bogus_length == 0);
777 clib_net_to_host_u16 (0x8100) : clib_net_to_host_u16 (0x86dd);
781 u32 *vlan_tag = (
u32 *) (mac0 + 1);
783 tmp = (si0->
sub.
id << 16) | 0x0800;
784 *vlan_tag = clib_host_to_net_u32 (tmp);
814 .name =
"dhcpv6-proxy-to-client",
816 .vector_size =
sizeof (
u32),
823 .unformat_buffer = unformat_dhcpv6_proxy_header,
838 all_dhcpv6_server_address.
as_u64[0] =
839 clib_host_to_net_u64 (0xFF05000000000000);
840 all_dhcpv6_server_address.
as_u64[1] = clib_host_to_net_u64 (0x00010003);
843 all_dhcpv6_server_relay_agent_address.
as_u64[0] =
844 clib_host_to_net_u64 (0xFF02000000000000);
845 all_dhcpv6_server_relay_agent_address.
as_u64[1] =
846 clib_host_to_net_u64 (0x00010002);
855 ip46_address_t * src_addr,
856 u32 rx_table_id,
u32 server_table_id,
int is_del)
859 u32 rx_fib_index = 0;
871 return VNET_API_ERROR_INVALID_DST_ADDRESS;
874 return VNET_API_ERROR_INVALID_SRC_ADDRESS;
883 addr, server_table_id))
901 .frp_sw_if_index = 0xffffffff,
908 rx_fib_index, server_table_id))
947 ip46_address_t
addr, src_addr;
948 int set_server = 0, set_src_address = 0;
949 u32 rx_table_id = 0, server_table_id = 0;
956 else if (
unformat (input,
"src-address %U",
959 else if (
unformat (input,
"server-fib-id %d", &server_table_id))
961 else if (
unformat (input,
"rx-fib-id %d", &rx_table_id))
969 if (is_del || (set_server && set_src_address))
974 server_table_id, is_del);
982 case VNET_API_ERROR_INVALID_DST_ADDRESS:
985 case VNET_API_ERROR_INVALID_SRC_ADDRESS:
988 case VNET_API_ERROR_NO_SUCH_ENTRY:
990 (0,
"Fib id %d: no per-fib DHCP server configured", rx_table_id);
1003 .path =
"set dhcpv6 proxy",
1004 .short_help =
"set dhcpv6 proxy [del] server <ipv6-addr> src-address <ipv6-addr> " 1005 "[server-fib-id <fib-id>] [rx-fib-id <fib-id>] ",
1020 s =
format (s,
"%=14s%=16s%s",
"RX FIB",
"Src Address",
1021 "Servers FIB,Address");
1027 s =
format (s,
"%=14u%=16U",
1067 .path =
"show dhcpv6 proxy",
1068 .short_help =
"Display dhcpv6 proxy info",
1078 u8 *vpn_ascii_id = 0;
1079 u32 oui = 0, fib_id = 0, tbl_id = ~0;
1083 if (
unformat (input,
"table %d", &tbl_id))
1085 else if (
unformat (input,
"oui %d", &oui))
1087 else if (
unformat (input,
"vpn-id %d", &fib_id))
1089 else if (
unformat (input,
"vpn-ascii-id %s", &vpn_ascii_id))
1101 vpn_ascii_id, oui, fib_id, is_del);
1106 case VNET_API_ERROR_NO_SUCH_ENTRY:
1116 .path =
"set dhcpv6 vss",
1117 .short_help =
"set dhcpv6 vss table <table-id> [oui <n> vpn-id <n> | vpn-ascii-id <text>]",
1134 .path =
"show dhcpv6 vss",
1135 .short_help =
"show dhcpv6 VSS",
1170 "No IPv6 address configured on",
1182 .path =
"show dhcpv6 link-address interface",
1183 .short_help =
"show dhcpv6 link-address interface <interface>",
#define foreach_ip_interface_address(lm, a, sw_if_index, loop, body)
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
void mfib_table_entry_delete(u32 fib_index, const mfib_prefix_t *prefix, mfib_source_t source)
Delete a FIB entry.
static ip6_address_t all_dhcpv6_server_relay_agent_address
u32 mfib_table_find_or_create_and_lock(fib_protocol_t proto, u32 table_id, mfib_source_t src)
Get the index of the FIB for a Table-ID.
static dhcp_vss_t * dhcp_get_vss_info(dhcp_proxy_main_t *dm, u32 rx_fib_index, fib_protocol_t proto)
Get the VSS data for the FIB index.
static u8 * format_dhcpv6_proxy_trace(u8 *s, va_list *args)
u32 * mfib_index_by_sw_if_index
Table index indexed by software interface.
A representation of a path as described by a route producer.
static clib_error_t * dhcpv6_proxy_set_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
vnet_main_t * vnet_get_main(void)
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
void dhcp_vss_walk(fib_protocol_t proto, dhcp_vss_walk_fn_t fn, void *ctx)
Walk/Visit each DHCP proxy VSS.
dhcp_server_t * dhcp_servers
The set of DHCP servers to which messages are relayed.
fib_node_index_t mfib_table_entry_path_update(u32 fib_index, const mfib_prefix_t *prefix, mfib_source_t source, const fib_route_path_t *rpath)
Add n paths to an entry (aka route) in the FIB.
static u8 * format_dhcpv6_proxy_header_with_length(u8 *s, va_list *args)
void dhcp_proxy_walk(fib_protocol_t proto, dhcp_proxy_walk_fn_t fn, void *ctx)
Walk/Visit each DHCP proxy server.
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
ethernet_interface_t * interfaces
dhcp_proxy_main_t dhcp_proxy_main
Shard 4/6 instance of DHCP main.
static ip6_address_t all_dhcpv6_server_address
int dhcp6_proxy_set_server(ip46_address_t *addr, ip46_address_t *src_addr, u32 rx_table_id, u32 server_table_id, int is_del)
#define ethernet_buffer_header_size(b)
Determine the size of the Ethernet headers of the current frame in the buffer.
int dhcp_vss_show_walk(dhcp_vss_t *vss, u32 rx_table_id, void *ctx)
Show (on CLI) a VSS config during a show walk.
u16 current_length
Nbytes between current data and the end of this buffer.
ip46_address_t dhcp_src_address
The source address to use in relayed messaes.
The Virtual Sub-net Selection information for a given RX FIB.
static clib_error_t * dhcpv6_vss_show_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
ip6_address_t * ip6_interface_first_address(ip6_main_t *im, u32 sw_if_index)
get first IPv6 interface address
static vlib_node_registration_t dhcpv6_proxy_to_server_node
(constructor) VLIB_REGISTER_NODE (dhcpv6_proxy_to_server_node)
u32 rx_fib_index
The FIB index (not the external Table-ID) in which the client is resides.
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
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)
Add a new (with no replication) or lock an existing entry.
dpo_proto_t frp_proto
The protocol of the address below.
unformat_function_t unformat_vnet_sw_interface
vlib_node_registration_t error_drop_node
(constructor) VLIB_REGISTER_NODE (error_drop_node)
static ip6_address_t * ip6_interface_first_global_or_site_address(ip6_main_t *im, u32 sw_if_index)
u8 vss_type
VSS type as defined in RFC 6607: 0 for NVT ASCII VPN Identifier 1 for RFC 2685 VPN-ID of 7 octects - ...
u32 error_drop_node_index
format_function_t format_vnet_sw_if_index_name
static vlib_buffer_t * vlib_buffer_copy(vlib_main_t *vm, vlib_buffer_t *b)
static clib_error_t * dhcp6_proxy_init(vlib_main_t *vm)
static char * dhcpv6_proxy_error_strings[]
#define clib_memcpy(d, s, n)
vl_api_interface_index_t sw_if_index
dhcpv6_proxy_to_server_input_next_t
#define VLIB_INIT_FUNCTION(x)
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
static dhcp_proxy_t * dhcp_get_proxy(dhcp_proxy_main_t *dm, u32 rx_fib_index, fib_protocol_t proto)
Get the DHCP proxy server data for the FIB index.
#define clib_error_return(e, args...)
static clib_error_t * dhcpv6_vss_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
int dhcp_proxy_server_add(fib_protocol_t proto, ip46_address_t *addr, ip46_address_t *src_address, u32 rx_fib_index, u32 server_table_id)
Add a new DHCP proxy server configuration.
static u32 vlib_get_buffer_index(vlib_main_t *vm, void *p)
Translate buffer pointer into buffer index.
static vlib_node_registration_t dhcpv6_proxy_to_client_node
(constructor) VLIB_REGISTER_NODE (dhcpv6_proxy_to_client_node)
#define foreach_dhcpv6_proxy_to_server_input_next
u32 server_fib_index
The FIB index (not the external Table-ID) in which the server is reachable.
Collection of global DHCP proxy data.
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
static clib_error_t * dhcpv6_proxy_show_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
void mfib_table_unlock(u32 fib_index, fib_protocol_t proto, mfib_source_t source)
Take a reference counting lock on the table.
static u8 ip46_address_is_zero(const ip46_address_t *ip46)
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
vnet_sw_interface_flags_t flags
int dhcp_proxy_set_vss(fib_protocol_t proto, u32 tbl_id, u8 vss_type, u8 *vpn_ascii_id, u32 oui, u32 vpn_index, u8 is_del)
Configure/set a new VSS info.
void mfib_table_lock(u32 fib_index, fib_protocol_t proto, mfib_source_t source)
Release a reference counting lock on the table.
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
format_function_t format_ip46_address
static_always_inline u32 vlib_buffer_get_default_data_size(vlib_main_t *vm)
#define VLIB_REGISTER_NODE(x,...)
u8 * vpn_ascii_id
Type 0 ASCII VPN Identifier.
u32 ft_table_id
Table ID (hash key) for this FIB.
void udp_unregister_dst_port(vlib_main_t *vm, udp_dst_port_t dst_port, u8 is_ip4)
static clib_error_t * dhcpv6_link_address_show_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
A representation of a single DHCP Server within a given VRF config.
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Aggregate type for a prefix.
vlib_main_t vlib_node_runtime_t * node
u32 unnumbered_sw_if_index
#define VLIB_CLI_COMMAND(x,...)
u16 ip6_tcp_udp_icmp_compute_checksum(vlib_main_t *vm, vlib_buffer_t *p0, ip6_header_t *ip0, int *bogus_lengthp)
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
ip46_address_t dhcp_server
The address of the DHCP server to which to relay the client's messages.
ip_lookup_main_t lookup_main
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
static vlib_main_t * vlib_get_main(void)
static void copy_ip6_address(ip6_address_t *dst, ip6_address_t *src)
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
struct _vlib_node_registration vlib_node_registration_t
A DHCP proxy representation fpr per-client VRF config.
int dhcp_proxy_server_del(fib_protocol_t proto, u32 rx_fib_index, ip46_address_t *addr, u32 server_table_id)
Delete a DHCP proxy config.
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u8 vpn_id[7]
Type 1 VPN-ID.
#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
VLIB buffer representation.
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
fib_table_t * fib_table_get(fib_node_index_t index, fib_protocol_t proto)
Get a pointer to a FIB table.
static ethernet_main_t * vnet_get_ethernet_main(void)
static ip6_mfib_t * ip6_mfib_get(u32 index)
Get the FIB at the given index.
vnet_sw_interface_type_t type
#define vec_foreach(var, vec)
Vector iterator.
void udp_register_dst_port(vlib_main_t *vm, udp_dst_port_t dst_port, u32 node_index, u8 is_ip4)
static void * ip_interface_address_get_address(ip_lookup_main_t *lm, ip_interface_address_t *a)
u16 fp_len
The mask length.
static int dhcp6_proxy_show_walk(dhcp_proxy_t *proxy, void *ctx)
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
u32 * fib_index_by_sw_if_index
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
static u8 * format_dhcp6_proxy_server(u8 *s, va_list *args)
const ip46_address_t zero_addr
A protocol Independent FIB table.
static uword dhcpv6_proxy_to_server_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
static uword dhcpv6_proxy_to_client_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)