FD.io VPP  v21.01.1
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 #include <cnat/cnat_inline.h>
20 #include <cnat/cnat_src_policy.h>
21 
22 typedef enum cnat_snat_next_
23 {
27 
28 typedef struct cnat_snat_trace_
29 {
34 
37 
38 static u8 *
39 format_cnat_snat_trace (u8 * s, va_list * args)
40 {
41  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
42  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
43  cnat_snat_trace_t *t = va_arg (*args, cnat_snat_trace_t *);
44 
45  if (t->found_session)
46  s = format (s, "found: %U", format_cnat_session, &t->session, 1);
47  else if (t->created_session)
48  s = format (s, "created: %U\n tr: %U",
50  else
51  s = format (s, "not found");
52  return s;
53 }
54 
55 /* CNat sub for source NAT as a feature arc on ip[46]-unicast
56  This node's sub shouldn't apply to the same flows as
57  cnat_vip_inline */
58 static uword
61  vlib_buffer_t * b,
63 {
65  int created_session = 0;
66  ip4_header_t *ip4 = NULL;
67  ip_protocol_t iproto;
68  ip6_header_t *ip6 = NULL;
69  udp_header_t *udp0;
70  u32 arc_next0;
71  u16 next0;
72  u16 sport;
73 
74  if (AF_IP4 == ctx->af)
75  {
76  ip4 = vlib_buffer_get_current (b);
77  iproto = ip4->protocol;
78  udp0 = (udp_header_t *) (ip4 + 1);
79  }
80  else
81  {
82  ip6 = vlib_buffer_get_current (b);
83  iproto = ip6->protocol;
84  udp0 = (udp_header_t *) (ip6 + 1);
85  }
86 
87  /* By default don't follow previous next0 */
88  vnet_feature_next (&arc_next0, b);
89  next0 = arc_next0;
90 
91  if (iproto != IP_PROTOCOL_UDP && iproto != IP_PROTOCOL_TCP
92  && iproto != IP_PROTOCOL_ICMP && iproto != IP_PROTOCOL_ICMP6)
93  {
94  /* Dont translate */
95  goto trace;
96  }
97 
98  if (!rv)
99  {
100  /* session table hit */
101  cnat_timestamp_update (session->value.cs_ts_index, ctx->now);
102  }
103  else
104  {
105  ip46_address_t ip46_dst_address;
106  if (AF_IP4 == ctx->af)
107  ip46_address_set_ip4 (&ip46_dst_address, &ip4->dst_address);
108  else
109  ip46_address_set_ip6 (&ip46_dst_address, &ip6->dst_address);
110  rv = cnat_search_snat_prefix (&ip46_dst_address, ctx->af);
111  if (!rv)
112  {
113  /* Prefix table hit, we shouldn't source NAT */
114  goto trace;
115  }
116  /* New flow, create the sessions if necessary. session will be a snat
117  session, and rsession will be a dnat session
118  Note: packet going through this path are going to the outside,
119  so they will never hit the NAT again (they are not going towards
120  a VIP) */
121  if (AF_IP4 == ctx->af)
122  {
124  &ip_addr_v4 (&cm->snat_ip4.ce_ip));
126  &ip4->dst_address);
127  }
128  else
129  {
131  &ip_addr_v6 (&cm->snat_ip6.ce_ip));
133  &ip6->dst_address);
134  }
135 
136 
137  sport = 0;
138  rv = cnat_allocate_port (&sport, iproto);
139  if (rv)
140  {
142  CNAT_ERROR_EXHAUSTED_PORTS, 1);
143  next0 = CNAT_SNAT_NEXT_DROP;
144  goto trace;
145  }
146  session->value.cs_port[VLIB_RX] = sport;
147  session->value.cs_port[VLIB_TX] = sport;
148  if (iproto == IP_PROTOCOL_TCP || iproto == IP_PROTOCOL_UDP)
149  session->value.cs_port[VLIB_TX] = udp0->dst_port;
150 
151  session->value.cs_lbi = INDEX_INVALID;
152  session->value.flags =
154 
155  created_session = 1;
157  }
158 
159 
160  if (AF_IP4 == ctx->af)
161  cnat_translation_ip4 (session, ip4, udp0);
162  else
163  cnat_translation_ip6 (session, ip6, udp0);
164 
165 trace:
166  if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
167  {
169 
170  t = vlib_add_trace (vm, node, b, sizeof (*t));
171 
172  t->found_session = !rv;
174  if (t->found_session || t->created_session)
175  clib_memcpy (&t->session, session, sizeof (t->session));
176  }
177  return next0;
178 }
179 
183 {
184  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
186  1 /* do_trace */ );
188  0 /* do_trace */ );
189 }
190 
194 {
195  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
197  1 /* do_trace */ );
199  0 /* do_trace */ );
200 }
201 
202 /* *INDENT-OFF* */
204 {
205  .name = "ip4-cnat-snat",
206  .vector_size = sizeof (u32),
207  .format_trace = format_cnat_snat_trace,
209  .n_errors = CNAT_N_ERROR,
210  .error_strings = cnat_error_strings,
211  .n_next_nodes = CNAT_SNAT_N_NEXT,
212  .next_nodes =
213  {
214  [CNAT_SNAT_NEXT_DROP] = "ip4-drop",
215  }
216 };
217 
219 {
220  .name = "ip6-cnat-snat",
221  .vector_size = sizeof (u32),
222  .format_trace = format_cnat_snat_trace,
224  .n_errors = CNAT_N_ERROR,
225  .error_strings = cnat_error_strings,
226  .n_next_nodes = CNAT_SNAT_N_NEXT,
227  .next_nodes =
228  {
229  [CNAT_SNAT_NEXT_DROP] = "ip6-drop",
230  }
231 };
232 
234 {
235  .arc_name = "ip4-unicast",
236  .node_name = "ip4-cnat-snat",
237 };
238 
240 {
241  .arc_name = "ip6-unicast",
242  .node_name = "ip6-cnat-snat",
243 };
244 
245 /* *INDENT-ON* */
246 
247 /*
248  * fd.io coding-style-patch-verification: ON
249  *
250  * Local Variables:
251  * eval: (c-set-style "gnu")
252  * End:
253  */
int cnat_allocate_port(u16 *port, ip_protocol_t iproto)
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
#define ip_addr_v6(_a)
Definition: ip_types.h:92
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
This session source port was allocated, free it on cleanup.
Definition: cnat_session.h:120
This session doesn&#39;t have a client, do not attempt to free it.
Definition: cnat_session.h:124
cnat_endpoint_t snat_ip6
Definition: cnat_types.h:134
struct cnat_snat_trace_ cnat_snat_trace_t
u16 cs_port[VLIB_N_DIR]
ports in rx/tx
Definition: cnat_session.h:53
static uword cnat_snat_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b, cnat_node_ctx_t *ctx, int rv, cnat_session_t *session)
u8 * format_cnat_session(u8 *s, va_list *args)
Definition: cnat_session.c:71
VNET_FEATURE_INIT(cnat_snat_ip4_node, static)
vlib_main_t * vm
Definition: in2out_ed.c:1580
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:203
static void cnat_timestamp_update(u32 index, f64 t)
Definition: cnat_inline.h:47
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
description fragment has unexpected format
Definition: map.api:433
const cJSON *const b
Definition: cJSON.h:255
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
Indicates a return path session that was source NATed on the way in.
Definition: cnat_session.h:116
enum ip_protocol ip_protocol_t
vnet_crypto_main_t * cm
Definition: quic_crypto.c:53
long ctx[MAX_CONNS]
Definition: main.c:144
unsigned short u16
Definition: types.h:57
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:233
#define PREDICT_FALSE(x)
Definition: clib.h:121
int cnat_search_snat_prefix(ip46_address_t *addr, ip_address_family_t af)
Definition: cnat_snat.c:106
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:562
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
ip_address_family_t af
Definition: cnat_types.h:164
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:170
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:1580
u32 flags
session flags if cs_lbi == INDEX_INVALID
Definition: cnat_session.h:100
cnat_snat_next_
#define ip_addr_v4(_a)
Definition: ip_types.h:91
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:305
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:1581
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_t ce_ip
Definition: cnat_types.h:62
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:634
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:721
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:302
cnat_endpoint_t snat_ip4
Definition: cnat_types.h:131
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:815
Definition: defs.h:46
struct cnat_session_t_::@633 value
this value sits in the same memory location a &#39;value&#39; in the bihash kvp
ip6_address_t dst_address
Definition: ip6_packet.h:310