FD.io VPP  v21.01
Vector Packet Processing
cnat_node_vip.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_translation.h>
19 #include <cnat/cnat_inline.h>
20 #include <cnat/cnat_src_policy.h>
21 
22 #include <vnet/dpo/load_balance.h>
24 
25 #include <vnet/ip/ip4_inlines.h>
26 #include <vnet/ip/ip6_inlines.h>
27 
29 {
36 
38 {
43 
46 
47 static u8 *
48 format_cnat_translation_trace (u8 * s, va_list * args)
49 {
50  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
51  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
53 
54  if (t->found_session)
55  s = format (s, "found: %U", format_cnat_session, &t->session, 1);
56  else if (t->created_session)
57  s = format (s, "created: %U\n tr: %U",
59  format_cnat_translation, &t->tr, 0);
60  else if (t->has_tr)
61  s = format (s, "tr pass: %U", format_cnat_translation, &t->tr, 0);
62  else
63  s = format (s, "not found");
64  return s;
65 }
66 
67 /* CNat sub for NAT behind a fib entry (VIP or interposed real IP) */
68 static uword
71  vlib_buffer_t * b,
73 {
75  const cnat_translation_t *ct = NULL;
76  ip4_header_t *ip4 = NULL;
77  ip_protocol_t iproto;
78  ip6_header_t *ip6 = NULL;
79  udp_header_t *udp0;
80  cnat_client_t *cc;
81  u16 next0;
82  index_t cti;
83  int created_session = 0;
85  if (AF_IP4 == ctx->af)
86  {
87  ip4 = vlib_buffer_get_current (b);
88  iproto = ip4->protocol;
89  udp0 = (udp_header_t *) (ip4 + 1);
90  }
91  else
92  {
93  ip6 = vlib_buffer_get_current (b);
94  iproto = ip6->protocol;
95  udp0 = (udp_header_t *) (ip6 + 1);
96  }
97 
98  cc = cnat_client_get (vnet_buffer (b)->ip.adj_index[VLIB_TX]);
99 
100  if (iproto != IP_PROTOCOL_UDP && iproto != IP_PROTOCOL_TCP
101  && iproto != IP_PROTOCOL_ICMP && iproto != IP_PROTOCOL_ICMP6)
102  {
103  /* Dont translate & follow the fib programming */
104  next0 = cc->cc_parent.dpoi_next_node;
105  vnet_buffer (b)->ip.adj_index[VLIB_TX] = cc->cc_parent.dpoi_index;
106  goto trace;
107  }
108 
109  if (!rv)
110  {
111  /* session table hit */
112  cnat_timestamp_update (session->value.cs_ts_index, ctx->now);
113 
114  if (INDEX_INVALID != session->value.cs_lbi)
115  {
116  /* Translate & follow the translation given LB */
117  ct = cnat_translation_get (session->value.ct_index);
118  next0 = ct->ct_lb.dpoi_next_node;
119  vnet_buffer (b)->ip.adj_index[VLIB_TX] = session->value.cs_lbi;
120  }
121  else if (session->value.flags & CNAT_SESSION_FLAG_HAS_SNAT)
122  {
123  /* The return needs DNAT, so we need an additionnal
124  * lookup after translation */
126  }
127  else
128  {
129  /* Translate & follow the fib programming */
130  next0 = cc->cc_parent.dpoi_next_node;
131  vnet_buffer (b)->ip.adj_index[VLIB_TX] = cc->cc_parent.dpoi_index;
132  }
133  }
134  else
135  {
136  ct =
138  clib_host_to_net_u16 (udp0->dst_port), iproto);
139  if (NULL == ct)
140  {
141  /* Dont translate & Follow the fib programming */
142  vnet_buffer (b)->ip.adj_index[VLIB_TX] = cc->cc_parent.dpoi_index;
143  next0 = cc->cc_parent.dpoi_next_node;
144  goto trace;
145  }
146 
147  /* New flow, create the sessions */
148  const load_balance_t *lb0;
149  cnat_ep_trk_t *trk0;
150  u32 hash_c0, bucket0;
151  u32 rsession_flags = 0;
152  const dpo_id_t *dpo0;
153 
154  lb0 = load_balance_get (ct->ct_lb.dpoi_index);
155  if (!lb0->lb_n_buckets)
156  {
157  /* Dont translate & Follow the fib programming */
158  vnet_buffer (b)->ip.adj_index[VLIB_TX] = cc->cc_parent.dpoi_index;
159  next0 = cc->cc_parent.dpoi_next_node;
160  goto trace;
161  }
162 
163  /* session table miss */
164  hash_c0 = (AF_IP4 == ctx->af ?
167  bucket0 = hash_c0 % lb0->lb_n_buckets;
168  dpo0 = load_balance_get_fwd_bucket (lb0, bucket0);
169 
170  /* add the session */
171  trk0 = &ct->ct_paths[bucket0];
172 
173  ip46_address_copy (&session->value.cs_ip[VLIB_TX],
174  &trk0->ct_ep[VLIB_TX].ce_ip.ip);
175  if (ip_address_is_zero (&trk0->ct_ep[VLIB_RX].ce_ip))
176  {
177  if (AF_IP4 == ctx->af)
179  &ip4->src_address);
180  else
182  &ip6->src_address);
183  }
184  else
185  {
186  /* We source NAT with the translation */
187  rsession_flags |= CNAT_SESSION_FLAG_HAS_SNAT;
188  ip46_address_copy (&session->value.cs_ip[VLIB_RX],
189  &trk0->ct_ep[VLIB_RX].ce_ip.ip);
190  }
191  session->value.cs_port[VLIB_TX] =
192  clib_host_to_net_u16 (trk0->ct_ep[VLIB_TX].ce_port);
193  session->value.cs_port[VLIB_RX] =
194  clib_host_to_net_u16 (trk0->ct_ep[VLIB_RX].ce_port);
195 
196  session->value.ct_index = ct - cnat_translation_pool;
197  session->value.cs_lbi = dpo0->dpoi_index;
198 
199  rv = cspm->vip_policy (vm, b, session, &rsession_flags, ct, ctx);
201  rv = cspm->default_policy (vm, b, session, &rsession_flags, ct, ctx);
202  if (rv)
203  {
206  CNAT_ERROR_EXHAUSTED_PORTS, 1);
208  goto trace;
209  }
210 
211  /* refcnt session in current client */
213  cnat_session_create (session, ctx, rsession_flags);
214  created_session = 1;
215 
216  next0 = ct->ct_lb.dpoi_next_node;
217  vnet_buffer (b)->ip.adj_index[VLIB_TX] = session->value.cs_lbi;
218  }
219 
220  if (AF_IP4 == ctx->af)
221  cnat_translation_ip4 (session, ip4, udp0);
222  else
223  cnat_translation_ip6 (session, ip6, udp0);
224 
225  if (NULL != ct)
226  {
227  cti = ct - cnat_translation_pool;
228  vlib_increment_combined_counter (cntm, ctx->thread_index, cti, 1,
230  }
231 
232 trace:
233  if (PREDICT_FALSE (ctx->do_trace))
234  {
236 
237  t = vlib_add_trace (vm, node, b, sizeof (*t));
238 
239  t->found_session = !rv;
241  if (t->found_session || t->created_session)
242  clib_memcpy (&t->session, session, sizeof (t->session));
243  t->has_tr = (NULL != ct);
244  if (t->has_tr)
245  clib_memcpy (&t->tr, ct, sizeof (cnat_translation_t));
246  }
247  return next0;
248 }
249 
253 {
254  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
256  1 /* do_trace */ );
258  0 /* do_trace */ );
259 }
260 
264 {
265  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
267  1 /* do_trace */ );
269  0 /* do_trace */ );
270 }
271 
272 /* *INDENT-OFF* */
274 {
275  .name = "ip4-cnat-tx",
276  .vector_size = sizeof (u32),
277  .format_trace = format_cnat_translation_trace,
279  .n_errors = 0,
280  .n_next_nodes = CNAT_TRANSLATION_N_NEXT,
281  .next_nodes =
282  {
283  [CNAT_TRANSLATION_NEXT_DROP] = "ip4-drop",
284  [CNAT_TRANSLATION_NEXT_LOOKUP] = "ip4-lookup",
285  }
286 };
288 {
289  .name = "ip6-cnat-tx",
290  .vector_size = sizeof (u32),
291  .format_trace = format_cnat_translation_trace,
293  .n_errors = 0,
294  .n_next_nodes = CNAT_TRANSLATION_N_NEXT,
295  .next_nodes =
296  {
297  [CNAT_TRANSLATION_NEXT_DROP] = "ip6-drop",
298  [CNAT_TRANSLATION_NEXT_LOOKUP] = "ip6-lookup",
299  }
300 };
301 /* *INDENT-ON* */
302 
303 /*
304  * fd.io coding-style-patch-verification: ON
305  *
306  * Local Variables:
307  * eval: (c-set-style "gnu")
308  * End:
309  */
u16 lb_n_buckets
number of buckets in the load-balance.
Definition: load_balance.h:116
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:899
vlib_node_registration_t cnat_vip_ip6_node
(constructor) VLIB_REGISTER_NODE (cnat_vip_ip6_node)
Definition: cnat_node_vip.c:45
#define CLIB_UNUSED(x)
Definition: clib.h:87
static void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 thread_index, u32 index, u64 n_packets, u64 n_bytes)
Increment a combined counter.
Definition: counter.h:239
ip4_address_t src_address
Definition: ip4_packet.h:125
static_always_inline cnat_translation_t * cnat_translation_get(index_t cti)
static u32 ip4_compute_flow_hash(const ip4_header_t *ip, flow_hash_config_t flow_hash_config)
Definition: ip4_inlines.h:51
cnat_src_policy_main_t cnat_src_policy_main
flow_hash_config_t lb_hash_config
the hash config to use when selecting a bucket.
Definition: load_balance.h:161
static const dpo_id_t * load_balance_get_fwd_bucket(const load_balance_t *lb, u16 bucket)
u16 cs_port[VLIB_N_DIR]
ports in rx/tx
Definition: cnat_session.h:53
ip46_address_t ip
Definition: ip_types.h:81
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
u8 * format_cnat_session(u8 *s, va_list *args)
Definition: cnat_session.c:71
dpo_id_t cc_parent
How to send packets to this client post translation.
Definition: cnat_client.h:47
A Translation represents the translation of a VEP to one of a set of real server addresses.
cnat_translation_t tr
Definition: cnat_node_vip.c:31
vlib_main_t * vm
Definition: in2out_ed.c:1578
enum cnat_translation_next_t_ cnat_translation_next_t
index_t parent_cci
Parent cnat_client index if cloned via interpose or own index if vanilla client.
Definition: cnat_client.h:74
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
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:402
ip6_address_t src_address
Definition: ip6_packet.h:310
unsigned char u8
Definition: types.h:56
cnat_translation_t * cnat_translation_pool
#define clib_memcpy(d, s, n)
Definition: string.h:180
A session represents the memory of a translation.
Definition: cnat_session.h:38
static_always_inline cnat_translation_t * cnat_find_translation(index_t cti, u16 port, ip_protocol_t proto)
vl_api_ip6_address_t ip6
Definition: one.api:424
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
static_always_inline u32 cnat_client_cnt_session(cnat_client_t *cc)
Add a session refcnt to this client.
Definition: cnat_client.h:202
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:170
enum ip_protocol ip_protocol_t
static_always_inline void ip46_address_copy(ip46_address_t *dst, const ip46_address_t *src)
Definition: ip46_address.h:123
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
The FIB DPO provieds;.
Definition: load_balance.h:106
bool ip_address_is_zero(const ip_address_t *ip)
Definition: ip_types.c:102
#define PREDICT_FALSE(x)
Definition: clib.h:121
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
cnat_ep_trk_t * ct_paths
The vector of tracked back-ends.
u32 ct_index
Persist translation->ct_lb.dpoi_next_node when cs_lbi != INDEX_INVALID.
Definition: cnat_session.h:105
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
static_always_inline cnat_client_t * cnat_client_get(index_t i)
Definition: cnat_client.h:91
cnat_vip_source_policy_t default_policy
ip_address_family_t af
Definition: cnat_types.h:164
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:170
cnat_endpoint_t ct_ep[VLIB_N_DIR]
The EP being tracked.
cnat_translation_next_t_
Definition: cnat_node_vip.c:37
static u8 * format_cnat_translation_trace(u8 *s, va_list *args)
Definition: cnat_node_vip.c:48
struct cnat_translation_trace_t_ cnat_translation_trace_t
vlib_node_registration_t cnat_vip_ip4_node
(constructor) VLIB_REGISTER_NODE (cnat_vip_ip4_node)
Definition: cnat_node_vip.c:44
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1578
u32 flags
session flags if cs_lbi == INDEX_INVALID
Definition: cnat_session.h:100
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
dpo_id_t ct_lb
The LB used to forward to the backends.
static load_balance_t * load_balance_get(index_t lbi)
Definition: load_balance.h:220
u8 * format_cnat_translation(u8 *s, va_list *args)
static u32 ip6_compute_flow_hash(const ip6_header_t *ip, flow_hash_config_t flow_hash_config)
Definition: ip6_inlines.h:49
struct _vlib_node_registration vlib_node_registration_t
vlib_combined_counter_main_t cnat_translation_counters
Counters for each translation.
Definition: defs.h:47
index_t dpoi_index
the index of objects of that type
Definition: dpo.h:188
vl_api_address_t ip
Definition: l2.api:501
static uword cnat_vip_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)
Definition: cnat_node_vip.c:69
#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:1579
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
A collection of combined counters.
Definition: counter.h:207
#define vnet_buffer(b)
Definition: buffer.h:417
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
u16 dpoi_next_node
The next VLIB node to follow.
Definition: dpo.h:184
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:302
Data used to track an EP in the FIB.
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
cnat_vip_source_policy_t vip_policy
struct cnat_session_t_::@633 value
this value sits in the same memory location a &#39;value&#39; in the bihash kvp
A client is a representation of an IP address behind the NAT.
Definition: cnat_client.h:35