22 #define NAT_HA_RETRIES 3 24 #define foreach_nat_ha_counter \ 25 _(RECV_ADD, "add-event-recv", 0) \ 26 _(RECV_DEL, "del-event-recv", 1) \ 27 _(RECV_REFRESH, "refresh-event-recv", 2) \ 28 _(SEND_ADD, "add-event-send", 3) \ 29 _(SEND_DEL, "del-event-send", 4) \ 30 _(SEND_REFRESH, "refresh-event-send", 5) \ 31 _(RECV_ACK, "ack-recv", 6) \ 32 _(SEND_ACK, "ack-send", 7) \ 33 _(RETRY_COUNT, "retry-count", 8) \ 34 _(MISSED_COUNT, "missed-count", 9) 37 #define NAT_HA_VERSION 0x01 40 #define NAT_HA_FLAG_ACK 0x01 88 #define _(N, s, v) NAT_HA_COUNTER_##N = v, 227 nat_log_debug (
"ACK for seq %d received", clib_net_to_host_u32 (seq));
239 u32 i, *del, *to_delete = 0;
264 [NAT_HA_COUNTER_MISSED_COUNT],
277 nat_log_warn (
"HA NAT state sync can't allocate buffer");
282 b->
flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
283 b->
flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
336 #define _(N, s, v) ha->counters[v].name = s; \ 337 ha->counters[v].stat_segment_name = "/nat44/ha/" s; \ 338 vlib_validate_simple_counter(&ha->counters[v], 0); \ 339 vlib_zero_simple_counter(&ha->counters[v], 0); 365 nat_ha_handoff_node.index, 1);
371 nat_log_info (
"HA listening on port %d for state sync", port);
424 in_addr.
as_u32 =
event->in_addr;
425 out_addr.
as_u32 =
event->out_addr;
426 eh_addr.
as_u32 =
event->eh_addr;
427 ehn_addr.
as_u32 =
event->ehn_addr;
428 fib_index = clib_net_to_host_u32 (event->
fib_index);
429 flags = clib_net_to_host_u16 (event->
flags);
433 fib_index, flags, thread_index);
446 out_addr.
as_u32 =
event->out_addr;
447 eh_addr.
as_u32 =
event->eh_addr;
448 fib_index = clib_net_to_host_u32 (event->
fib_index);
451 event->
protocol, fib_index, thread_index);
459 u32 fib_index, total_pkts;
465 out_addr.
as_u32 =
event->out_addr;
466 eh_addr.
as_u32 =
event->eh_addr;
467 fib_index = clib_net_to_host_u32 (event->
fib_index);
468 total_pkts = clib_net_to_host_u32 (event->
total_pkts);
469 total_bytes = clib_net_to_host_u64 (event->
total_bytes);
472 event->
protocol, fib_index, total_pkts, total_bytes,
508 b->
flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
509 b->
flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
564 is_resync, thread_index);
590 nat_log_warn (
"HA NAT state sync can't allocate buffer");
622 offset +=
sizeof (*event);
630 [NAT_HA_COUNTER_SEND_ADD],
635 [NAT_HA_COUNTER_SEND_DEL],
640 [NAT_HA_COUNTER_SEND_REFRESH],
666 #define skip_if_disabled() \ 668 nat_ha_main_t *ha = &nat_ha_main; \ 669 if (PREDICT_TRUE (!ha->dst_port)) \ 692 event.flags = clib_host_to_net_u16 (flags);
693 event.in_addr = in_addr->
as_u32;
694 event.in_port = in_port;
695 event.out_addr = out_addr->
as_u32;
696 event.out_port = out_port;
697 event.eh_addr = eh_addr->
as_u32;
698 event.eh_port = eh_port;
699 event.ehn_addr = ehn_addr->
as_u32;
700 event.ehn_port = ehn_port;
701 event.fib_index = clib_host_to_net_u32 (fib_index);
702 event.protocol = proto;
708 u16 eh_port,
u8 proto,
u32 fib_index,
u32 thread_index)
716 event.out_addr = out_addr->
as_u32;
717 event.out_port = out_port;
718 event.eh_addr = eh_addr->
as_u32;
719 event.eh_port = eh_port;
720 event.fib_index = clib_host_to_net_u32 (fib_index);
721 event.protocol = proto;
727 u16 eh_port,
u8 proto,
u32 fib_index,
u32 total_pkts,
728 u64 total_bytes,
u32 thread_index,
f64 * last_refreshed,
f64 now)
738 *last_refreshed = now;
741 event.out_addr = out_addr->
as_u32;
742 event.out_port = out_port;
743 event.eh_addr = eh_addr->
as_u32;
744 event.eh_port = eh_port;
745 event.fib_index = clib_host_to_net_u32 (fib_index);
746 event.protocol = proto;
747 event.total_pkts = clib_host_to_net_u32 (total_pkts);
748 event.total_bytes = clib_host_to_net_u64 (total_bytes);
769 .state = VLIB_NODE_STATE_INTERRUPT,
770 .name =
"nat-ha-worker",
780 uword *event_data = 0;
786 nat_log_info (
"nat-ha-process: bogus kickoff event received");
800 nat_ha_worker_node.index);
811 .name =
"nat-ha-process",
834 return VNET_API_ERROR_IN_PROGRESS;
847 nat_ha_sadd (&ses->in2out.addr, ses->in2out.port,
848 &ses->out2in.addr, ses->out2in.port,
849 &ses->ext_host_addr, ses->ext_host_port,
850 &ses->ext_host_nat_addr, ses->ext_host_nat_port,
851 ses->in2out.protocol, ses->in2out.fib_index,
889 #define foreach_nat_ha_error \ 890 _(PROCESSED, "pkts-processed") \ 891 _(BAD_VERSION, "bad-version") 895 #define _(sym, str) NAT_HA_ERROR_##sym, 901 static char *nat_ha_error_strings[] = {
902 #define _(sym, str) str, 912 u32 n_left_from, *from, next_index, *to_next;
915 u32 pkts_processed = 0;
924 while (n_left_from > 0)
930 while (n_left_from > 0 && n_left_to_next > 0)
932 u32 bi0, next0, src_addr0, dst_addr0;;
936 u16 event_count0, src_port0, dst_port0, old_len0;
959 b0->
error = node->
errors[NAT_HA_ERROR_BAD_VERSION];
963 event_count0 = clib_net_to_host_u16 (h0->
count);
986 b0->
current_length =
sizeof (*ip0) +
sizeof (*udp0) +
sizeof (*h0);
998 ip0->
ttl = host_config_ttl;
1015 [NAT_HA_COUNTER_SEND_ACK],
1016 thread_index, 0, 1);
1020 && (b0->
flags & VLIB_BUFFER_IS_TRACED)))
1030 to_next, n_left_to_next,
1038 NAT_HA_ERROR_PROCESSED, pkts_processed);
1047 .vector_size =
sizeof (
u32),
1050 .n_errors =
ARRAY_LEN (nat_ha_error_strings),
1066 #define foreach_nat_ha_handoff_error \ 1067 _(CONGESTION_DROP, "congestion drop") \ 1068 _(SAME_WORKER, "same worker") \ 1069 _(DO_HANDOFF, "do handoff") 1073 #define _(sym,str) NAT_HA_HANDOFF_ERROR_##sym, 1079 static char *nat_ha_handoff_error_strings[] = {
1080 #define _(sym,string) string, 1105 u32 n_enq, n_left_from, *from;
1108 u32 do_handoff = 0, same_worker = 0;
1115 ti = thread_indices;
1117 while (n_left_from > 0)
1124 if (ti[0] != thread_index)
1130 && (b[0]->
flags & VLIB_BUFFER_IS_TRACED)))
1146 if (n_enq < frame->n_vectors)
1148 NAT_HA_HANDOFF_ERROR_CONGESTION_DROP,
1151 NAT_HA_HANDOFF_ERROR_SAME_WORKER, same_worker);
1153 NAT_HA_HANDOFF_ERROR_DO_HANDOFF, do_handoff);
1160 .name =
"nat-ha-handoff",
1161 .vector_size =
sizeof (
u32),
1164 .n_errors =
ARRAY_LEN(nat_ha_handoff_error_strings),
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
#define nat_log_info(...)
#define vec_foreach_index(var, v)
Iterate over vector indices.
static char * nat_ha_handoff_error_strings[]
struct nat_ha_main_s nat_ha_main_t
vlib_node_registration_t nat_ha_handoff_node
(constructor) VLIB_REGISTER_NODE (nat_ha_handoff_node)
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
static uword * vlib_process_wait_for_event(vlib_main_t *vm)
static uword nat_ha_handoff_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
#define skip_if_disabled()
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
static void vlib_node_set_interrupt_pending(vlib_main_t *vm, u32 node_index)
#define clib_memcpy_fast(a, b, c)
static f64 vlib_time_now(vlib_main_t *vm)
u32 vlib_frame_queue_main_init(u32 node_index, u32 frame_queue_nelts)
u16 current_length
Nbytes between current data and the end of this buffer.
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
#define nat_log_warn(...)
#define foreach_nat_ha_handoff_error
#define clib_atomic_fetch_sub(a, b)
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
clib_memset(h->entries, 0, sizeof(h->entries[0])*entries)
void(* nat_ha_sref_cb_t)(ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 fib_index, u32 total_pkts, u64 total_bytes, u32 thread_index)
void nat_ha_sadd(ip4_address_t *in_addr, u16 in_port, ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, ip4_address_t *ehn_addr, u16 ehn_port, u8 proto, u32 fib_index, u16 flags, u32 thread_index, u8 is_resync)
Create session add HA event.
static void vlib_increment_simple_counter(vlib_simple_counter_main_t *cm, u32 thread_index, u32 index, u64 increment)
Increment a simple counter.
static void nat_ha_header_create(vlib_buffer_t *b, u32 *offset, u32 thread_index)
vlib_error_t * errors
Vector of errors for this node.
static_always_inline void nat_ha_recv_add(nat_ha_event_t *event, f64 now, u32 thread_index)
void nat_ha_get_resync_status(u8 *in_resync, u32 *resync_ack_missed)
Get resync status.
vlib_main_t ** vlib_mains
static u8 * format_nat_ha_trace(u8 *s, va_list *args)
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
static_always_inline void nat_ha_recv_refresh(nat_ha_event_t *event, f64 now, u32 thread_index)
vlib_node_registration_t ip4_lookup_node
(constructor) VLIB_REGISTER_NODE (ip4_lookup_node)
void nat_ha_sref(ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 fib_index, u32 total_pkts, u64 total_bytes, u32 thread_index, f64 *last_refreshed, f64 now)
Create session refresh HA event.
#define clib_memcpy(d, s, n)
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
static char * nat_ha_error_strings[]
nat_ha_main_t nat_ha_main
ip4_address_t dst_ip_address
#define static_always_inline
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
static void * ip4_next_header(ip4_header_t *i)
#define foreach_nat_ha_error
A collection of simple counters.
struct ip4_main_t::@212 host_config
Template information for VPP generated packets.
static u8 * format_nat_ha_handoff_trace(u8 *s, va_list *args)
static u32 vlib_get_buffer_index(vlib_main_t *vm, void *p)
Translate buffer pointer into buffer index.
static uword nat_ha_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
vlib_error_t error
Error code for buffers to be enqueued to error handler.
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
static_always_inline void nat_ha_event_process(nat_ha_event_t *event, f64 now, u32 thread_index)
vlib_node_registration_t nat_ha_node
(constructor) VLIB_REGISTER_NODE (nat_ha_node)
static_always_inline void nat_ha_recv_del(nat_ha_event_t *event, u32 thread_index)
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.
void nat_ha_get_listener(ip4_address_t *addr, u16 *port, u32 *path_mtu)
Get HA listener/local configuration.
void nat_ha_flush(u8 is_resync)
Flush the current HA data (for testing)
#define vec_del1(v, i)
Delete the element at index I.
static int nat_ha_resend_queue_add(u32 seq, u8 *data, u8 data_len, u8 is_resync, u32 thread_index)
u32 node_index
Node index.
#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).
#define nat_log_notice(...)
nat_ha_per_thread_data_t * per_thread_data
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
#define VLIB_REGISTER_NODE(x,...)
#define nat_log_debug(...)
vlib_node_registration_t nat_ha_worker_node
(constructor) VLIB_REGISTER_NODE (nat_ha_worker_node)
#define vec_free(V)
Free vector's memory (no header).
void udp_unregister_dst_port(vlib_main_t *vm, udp_dst_port_t dst_port, u8 is_ip4)
nat_ha_resend_entry_t * resend_queue
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.
void(* nat_ha_resync_event_cb_t)(u32 client_index, u32 pid, u32 missed_count)
static uword nat_ha_worker_fn(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
int nat_ha_set_listener(ip4_address_t *addr, u16 port, u32 path_mtu)
Set HA listener (local settings)
vlib_frame_t * state_sync_frame
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
int nat_ha_set_failover(ip4_address_t *addr, u16 port, u32 session_refresh_interval)
Set HA failover (remote settings)
vlib_simple_counter_main_t counters[NAT_HA_N_COUNTERS]
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
uword * thread_registrations_by_name
vlib_node_registration_t nat_ha_process_node
(constructor) VLIB_REGISTER_NODE (nat_ha_process_node)
void nat_ha_sdel(ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 fib_index, u32 thread_index)
Create session delete HA event.
#define clib_atomic_fetch_add(a, b)
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
template key/value backing page structure
static_always_inline void nat_ha_event_add(nat_ha_event_t *event, u8 do_flush, u32 thread_index, u8 is_resync)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
vlib_buffer_t * state_sync_buffer
#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
static void nat_ha_resync_fin(void)
VLIB buffer representation.
static_always_inline void nat_ha_ack_recv(u32 seq, u32 thread_index)
snat_main_per_thread_data_t * per_thread_data
static uword nat_ha_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
#define ip_csum_update(sum, old, new, type, field)
void nat_ha_get_failover(ip4_address_t *addr, u16 *port, u32 *session_refresh_interval)
Get HA failover/remote settings.
static_always_inline u32 vlib_buffer_enqueue_to_thread(vlib_main_t *vm, u32 frame_queue_index, u32 *buffer_indices, u16 *thread_indices, u32 n_packets, int drop_on_congestion)
#define hash_get_mem(h, key)
struct clib_bihash_value offset
template key/value backing page structure
ip4_main_t ip4_main
Global ip4 main structure.
void(* nat_ha_sadd_cb_t)(ip4_address_t *in_addr, u16 in_port, ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, ip4_address_t *ehn_addr, u16 ehn_port, u8 proto, u32 fib_index, u16 flags, u32 thread_index)
static vlib_thread_main_t * vlib_get_thread_main()
static void nat_ha_send(vlib_frame_t *f, vlib_buffer_t *b, u8 is_resync, u32 thread_index)
#define vec_foreach(var, vec)
Vector iterator.
#define IP4_HEADER_FLAG_DONT_FRAGMENT
u16 flags
Copy of main node flags.
int nat44_ha_resync(u32 client_index, u32 pid, nat_ha_resync_event_cb_t event_callback)
void udp_register_dst_port(vlib_main_t *vm, udp_dst_port_t dst_port, u32 node_index, u8 is_ip4)
u32 session_refresh_interval
static_always_inline void vlib_get_buffers(vlib_main_t *vm, u32 *bi, vlib_buffer_t **b, int count)
Translate array of buffer indices into buffer pointers.
#define VLIB_NODE_FLAG_TRACE
static void nat_ha_resend_scan(f64 now, u32 thread_index)
#define foreach_nat_ha_counter
nat_ha_resync_event_cb_t event_callback
static u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
u8 ttl
TTL to use for host generated packets.
snat_session_t * sessions
void(* nat_ha_sdel_cb_t)(ip4_address_t *out_addr, u16 out_port, ip4_address_t *eh_addr, u16 eh_port, u8 proto, u32 fib_index, u32 thread_index)
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
static u16 ip4_header_checksum(ip4_header_t *i)
static u16 ip_csum_fold(ip_csum_t c)
void nat_ha_init(vlib_main_t *vm, nat_ha_sadd_cb_t sadd_cb, nat_ha_sdel_cb_t sdel_cb, nat_ha_sref_cb_t sref_cb)
Initialize NAT HA.
u32 state_sync_next_event_offset
ip4_address_t src_ip_address