FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
cnat_node_snat.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <vlibmemory/api.h>
17 #include <cnat/cnat_node.h>
18 #include <cnat/cnat_snat.h>
19 
20 typedef enum cnat_snat_next_
21 {
25 
26 typedef struct cnat_snat_trace_
27 {
31 
34 
35 static u8 *
36 format_cnat_snat_trace (u8 * s, va_list * args)
37 {
38  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
39  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
40  cnat_snat_trace_t *t = va_arg (*args, cnat_snat_trace_t *);
41 
42  if (t->found)
43  s = format (s, "found: %U", format_cnat_session, &t->session, 1);
44  else
45  s = format (s, "not found");
46  return s;
47 }
48 
49 /* CNat sub for source NAT as a feature arc on ip[46]-unicast
50  This node's sub shouldn't apply to the same flows as
51  cnat_vip_inline */
55  vlib_buffer_t * b,
57 {
60  ip_protocol_t iproto;
62  udp_header_t *udp0;
63  u32 arc_next0;
64  u16 next0;
65  u16 sport;
66 
67  if (AF_IP4 == ctx->af)
68  {
69  ip4 = vlib_buffer_get_current (b);
70  iproto = ip4->protocol;
71  udp0 = (udp_header_t *) (ip4 + 1);
72  }
73  else
74  {
75  ip6 = vlib_buffer_get_current (b);
76  iproto = ip6->protocol;
77  udp0 = (udp_header_t *) (ip6 + 1);
78  }
79 
80  /* By default don't follow previous next0 */
81  vnet_feature_next (&arc_next0, b);
82  next0 = arc_next0;
83 
84  if (iproto != IP_PROTOCOL_UDP && iproto != IP_PROTOCOL_TCP)
85  {
86  /* Dont translate */
87  goto trace;
88  }
89 
90  if (!rv)
91  {
92  /* session table hit */
93  cnat_timestamp_update (session->value.cs_ts_index, ctx->now);
94  }
95  else
96  {
97  ip46_address_t ip46_dst_address;
98  if (AF_IP4 == ctx->af)
99  ip46_address_set_ip4 (&ip46_dst_address, &ip4->dst_address);
100  else
101  ip46_address_set_ip6 (&ip46_dst_address, &ip6->dst_address);
102  rv = cnat_search_snat_prefix (&ip46_dst_address, ctx->af);
103  if (!rv)
104  {
105  /* Prefix table hit, we shouldn't source NAT */
106  goto trace;
107  }
108  /* New flow, create the sessions if necessary. session will be a snat
109  session, and rsession will be a dnat session
110  Note: packet going through this path are going to the outside,
111  so they will never hit the NAT again (they are not going towards
112  a VIP) */
113  if (AF_IP4 == ctx->af)
114  {
116  &cm->snat_ip4);
118  &ip4->dst_address);
119  }
120  else
121  {
123  &cm->snat_ip6);
125  &ip6->dst_address);
126  }
127 
128  /* Port allocation, first try to use the original port, allocate one
129  if it is already used */
130  sport = udp0->src_port;
131  rv = cnat_allocate_port (cm, &sport);
132  if (rv)
133  {
135  CNAT_ERROR_EXHAUSTED_PORTS, 1);
136  next0 = CNAT_SNAT_NEXT_DROP;
137  goto trace;
138  }
139 
140  session->value.cs_port[VLIB_RX] = sport;
141  session->value.cs_port[VLIB_TX] = udp0->dst_port;
142  session->value.cs_lbi = INDEX_INVALID;
143  session->value.flags =
145 
147  }
148 
149 
150  if (AF_IP4 == ctx->af)
151  cnat_translation_ip4 (session, ip4, udp0);
152  else
153  cnat_translation_ip6 (session, ip6, udp0);
154 
155 trace:
156  if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
157  {
159 
160  t = vlib_add_trace (vm, node, b, sizeof (*t));
161 
162  if (NULL != session)
163  clib_memcpy (&t->session, session, sizeof (t->session));
164  }
165  return next0;
166 }
167 
171 {
172  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
174  1 /* do_trace */ );
176  0 /* do_trace */ );
177 }
178 
182 {
183  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
185  1 /* do_trace */ );
187  0 /* do_trace */ );
188 }
189 
190 /* *INDENT-OFF* */
192 {
193  .name = "ip4-cnat-snat",
194  .vector_size = sizeof (u32),
195  .format_trace = format_cnat_snat_trace,
197  .n_errors = CNAT_N_ERROR,
198  .error_strings = cnat_error_strings,
199  .n_next_nodes = CNAT_SNAT_N_NEXT,
200  .next_nodes =
201  {
202  [CNAT_SNAT_NEXT_DROP] = "ip4-drop",
203  }
204 };
205 
207 {
208  .name = "ip6-cnat-snat",
209  .vector_size = sizeof (u32),
210  .format_trace = format_cnat_snat_trace,
212  .n_errors = CNAT_N_ERROR,
213  .error_strings = cnat_error_strings,
214  .n_next_nodes = CNAT_SNAT_N_NEXT,
215  .next_nodes =
216  {
217  [CNAT_SNAT_NEXT_DROP] = "ip6-drop",
218  }
219 };
220 /* *INDENT-ON* */
221 
222 
224 {
225 .arc_name = "ip4-unicast",.node_name = "ip4-cnat-snat",};
226 
228 {
229 .arc_name = "ip6-unicast",.node_name = "ip6-cnat-snat",};
230 
231 /*
232  * fd.io coding-style-patch-verification: ON
233  *
234  * Local Variables:
235  * eval: (c-set-style "gnu")
236  * End:
237  */
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:899
#define CLIB_UNUSED(x)
Definition: clib.h:87
struct cnat_snat_trace_ cnat_snat_trace_t
u16 cs_port[VLIB_N_DIR]
ports in rx/tx
Definition: cnat_session.h:53
u8 * format_cnat_session(u8 *s, va_list *args)
Definition: cnat_session.c:70
VNET_FEATURE_INIT(cnat_snat_ip4_node, static)
vlib_main_t * vm
Definition: in2out_ed.c:1582
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
static_always_inline void ip46_address_set_ip6(ip46_address_t *dst, const ip6_address_t *src)
Definition: ip46_address.h:130
#define VLIB_NODE_FN(node)
Definition: node.h:202
vlib_node_registration_t cnat_snat_ip4_node
(constructor) VLIB_REGISTER_NODE (cnat_snat_ip4_node)
unsigned char u8
Definition: types.h:56
#define clib_memcpy(d, s, n)
Definition: string.h:180
A session represents the memory of a translation.
Definition: cnat_session.h:38
vl_api_ip6_address_t ip6
Definition: one.api:424
ip4_address_t dst_address
Definition: ip4_packet.h:125
unsigned int u32
Definition: types.h:88
ip46_address_t cs_ip[VLIB_N_DIR]
IP 4/6 address in the rx/tx direction.
Definition: cnat_session.h:48
u32 cs_ts_index
Timestamp index this session was last used.
Definition: cnat_session.h:93
vl_api_fib_path_type_t type
Definition: fib_types.api:123
enum ip_protocol ip_protocol_t
vnet_crypto_main_t * cm
Definition: quic_crypto.c:53
long ctx[MAX_CONNS]
Definition: main.c:144
static int cnat_allocate_port(cnat_main_t *cm, u16 *port)
Definition: cnat_types.h:252
static int cnat_search_snat_prefix(ip46_address_t *addr, ip_address_family_t af)
Definition: cnat_snat.h:22
unsigned short u16
Definition: types.h:57
static uword cnat_snat_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b, cnat_node_ctx_t *ctx, int rv, cnat_session_t *session)
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
#define PREDICT_FALSE(x)
Definition: clib.h:120
#define always_inline
Definition: ipsec.h:28
vl_api_ip4_address_t ip4
Definition: one.api:376
static_always_inline void cnat_translation_ip6(const cnat_session_t *session, ip6_header_t *ip6, udp_header_t *udp)
Definition: cnat_node.h:225
index_t cs_lbi
The load balance object to use to forward.
Definition: cnat_session.h:88
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1231
cnat_session_t session
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
static_always_inline void vnet_feature_next(u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:322
static u8 * format_cnat_snat_trace(u8 *s, va_list *args)
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1582
u32 flags
Indicates a return path session that was source NATed on the way in.
Definition: cnat_session.h:98
cnat_snat_next_
struct cnat_session_t_::@637 value
this value sits in the same memory location a &#39;value&#39; in the bihash kvp
static void cnat_timestamp_update(u32 index, f64 t)
Definition: cnat_types.h:199
vlib_node_registration_t cnat_snat_ip6_node
(constructor) VLIB_REGISTER_NODE (cnat_snat_ip6_node)
static_always_inline void cnat_translation_ip4(const cnat_session_t *session, ip4_header_t *ip4, udp_header_t *udp)
Definition: cnat_node.h:129
ip4_address_t snat_ip4
Definition: cnat_types.h:123
struct _vlib_node_registration vlib_node_registration_t
Definition: defs.h:47
enum cnat_snat_next_ cnat_snat_next_t
#define INDEX_INVALID
Invalid index - used when no index is known blazoned capitals INVALID speak volumes where ~0 does not...
Definition: dpo.h:47
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1583
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
cnat_main_t cnat_main
Definition: cnat_types.c:18
ip_address_family_t af
Definition: cnat_types.h:147
ip6_address_t snat_ip6
Definition: cnat_types.h:126
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:577
static_always_inline void cnat_session_create(cnat_session_t *session, cnat_node_ctx_t *ctx, u8 rsession_flags)
Create NAT sessions.
Definition: cnat_node.h:305
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:301
char * cnat_error_strings[]
Definition: cnat_types.c:23
static void ip46_address_set_ip4(ip46_address_t *ip46, const ip4_address_t *ip)
Definition: ip46_address.h:67
static uword cnat_node_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, cnat_node_sub_t cnat_sub, ip_address_family_t af, u8 do_trace)
Definition: cnat_node.h:404
Definition: defs.h:46
ip6_address_t dst_address
Definition: ip6_packet.h:310