Line data Source code
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_inline.h>
19 : #include <cnat/cnat_src_policy.h>
20 :
21 : typedef enum cnat_translation_next_t_
22 : {
23 : CNAT_TRANSLATION_NEXT_DROP,
24 : CNAT_TRANSLATION_NEXT_LOOKUP,
25 : CNAT_TRANSLATION_N_NEXT,
26 : } cnat_translation_next_t;
27 :
28 : vlib_node_registration_t cnat_vip_ip4_node;
29 : vlib_node_registration_t cnat_vip_ip6_node;
30 :
31 : /* CNat sub for NAT behind a fib entry (VIP or interposed real IP) */
32 : static uword
33 5220 : cnat_vip_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *b,
34 : cnat_node_ctx_t *ctx, int session_not_found,
35 : cnat_session_t *session)
36 : {
37 5220 : vlib_combined_counter_main_t *cntm = &cnat_translation_counters;
38 5220 : cnat_src_policy_main_t *cspm = &cnat_src_policy_main;
39 5220 : const cnat_translation_t *ct = NULL;
40 5220 : ip4_header_t *ip4 = NULL;
41 : ip_protocol_t iproto;
42 5220 : ip6_header_t *ip6 = NULL;
43 : udp_header_t *udp0;
44 : cnat_client_t *cc;
45 : u16 next0;
46 : index_t cti;
47 5220 : u8 trace_flags = 0;
48 : int rv;
49 :
50 5220 : if (AF_IP4 == ctx->af)
51 : {
52 2655 : ip4 = vlib_buffer_get_current (b);
53 2655 : iproto = ip4->protocol;
54 2655 : udp0 = (udp_header_t *) (ip4 + 1);
55 : }
56 : else
57 : {
58 2565 : ip6 = vlib_buffer_get_current (b);
59 2565 : iproto = ip6->protocol;
60 2565 : udp0 = (udp_header_t *) (ip6 + 1);
61 : }
62 :
63 5220 : cc = cnat_client_get (vnet_buffer (b)->ip.adj_index[VLIB_TX]);
64 :
65 : /* Wrong session key */
66 5220 : if (session->key.cs_proto == 0)
67 : {
68 : /* Dont translate & follow the fib programming */
69 0 : next0 = cc->cc_parent.dpoi_next_node;
70 0 : vnet_buffer (b)->ip.adj_index[VLIB_TX] = cc->cc_parent.dpoi_index;
71 0 : goto trace;
72 : }
73 :
74 5220 : if (!session_not_found)
75 : {
76 : /* session table hit */
77 3930 : cnat_timestamp_update (session->value.cs_ts_index, ctx->now);
78 :
79 3930 : if (INDEX_INVALID != session->value.cs_lbi)
80 : {
81 : /* Translate & follow the translation given LB */
82 2220 : next0 = session->value.dpoi_next_node;
83 2220 : vnet_buffer (b)->ip.adj_index[VLIB_TX] = session->value.cs_lbi;
84 : }
85 1710 : else if (session->value.flags & CNAT_SESSION_FLAG_HAS_SNAT)
86 : {
87 : /* The return needs DNAT, so we need an additionnal
88 : * lookup after translation */
89 540 : next0 = CNAT_TRANSLATION_NEXT_LOOKUP;
90 : }
91 : else
92 : {
93 : /* Translate & follow the fib programming */
94 1170 : next0 = cc->cc_parent.dpoi_next_node;
95 1170 : vnet_buffer (b)->ip.adj_index[VLIB_TX] = cc->cc_parent.dpoi_index;
96 : }
97 : }
98 : else
99 : {
100 : ct =
101 1290 : cnat_find_translation (cc->parent_cci,
102 1290 : clib_host_to_net_u16 (udp0->dst_port), iproto);
103 1290 : if (NULL == ct)
104 : {
105 : /* Dont translate & Follow the fib programming */
106 1170 : vnet_buffer (b)->ip.adj_index[VLIB_TX] = cc->cc_parent.dpoi_index;
107 1170 : next0 = cc->cc_parent.dpoi_next_node;
108 1170 : goto trace;
109 : }
110 :
111 : /* New flow, create the sessions */
112 : cnat_ep_trk_t *trk0;
113 120 : u32 rsession_flags = 0;
114 120 : u32 dpoi_index = -1;
115 :
116 120 : trk0 = cnat_load_balance (ct, ctx->af, ip4, ip6, &dpoi_index);
117 120 : if (PREDICT_FALSE (NULL == trk0))
118 : {
119 : /* Dont translate & Follow the fib programming */
120 0 : vnet_buffer (b)->ip.adj_index[VLIB_TX] = cc->cc_parent.dpoi_index;
121 0 : next0 = cc->cc_parent.dpoi_next_node;
122 0 : goto trace;
123 : }
124 :
125 : /* add the session */
126 120 : ip46_address_copy (&session->value.cs_ip[VLIB_TX],
127 120 : &trk0->ct_ep[VLIB_TX].ce_ip.ip);
128 120 : if (ip_address_is_zero (&trk0->ct_ep[VLIB_RX].ce_ip))
129 : {
130 120 : if (AF_IP4 == ctx->af)
131 72 : ip46_address_set_ip4 (&session->value.cs_ip[VLIB_RX],
132 72 : &ip4->src_address);
133 : else
134 48 : ip46_address_set_ip6 (&session->value.cs_ip[VLIB_RX],
135 48 : &ip6->src_address);
136 : }
137 : else
138 : {
139 : /* We source NAT with the translation */
140 0 : rsession_flags |= CNAT_SESSION_FLAG_HAS_SNAT;
141 0 : ip46_address_copy (&session->value.cs_ip[VLIB_RX],
142 0 : &trk0->ct_ep[VLIB_RX].ce_ip.ip);
143 : }
144 120 : session->value.cs_port[VLIB_TX] =
145 120 : clib_host_to_net_u16 (trk0->ct_ep[VLIB_TX].ce_port);
146 120 : session->value.cs_port[VLIB_RX] =
147 120 : clib_host_to_net_u16 (trk0->ct_ep[VLIB_RX].ce_port);
148 :
149 120 : session->value.dpoi_next_node = ct->ct_lb.dpoi_next_node;
150 120 : session->value.cs_lbi = dpoi_index;
151 120 : session->value.flags = 0;
152 :
153 120 : rv = cspm->vip_policy (vm, b, session, &rsession_flags, ct, ctx);
154 120 : if (CNAT_SOURCE_ERROR_USE_DEFAULT == rv)
155 0 : rv = cspm->default_policy (vm, b, session, &rsession_flags, ct, ctx);
156 120 : if (rv)
157 : {
158 0 : if (CNAT_SOURCE_ERROR_EXHAUSTED_PORTS == rv)
159 : {
160 0 : vlib_node_registration_t *node =
161 0 : (AF_IP4 == ctx->af) ? &cnat_vip_ip4_node : &cnat_vip_ip6_node;
162 0 : vlib_node_increment_counter (vm, node->index,
163 : CNAT_ERROR_EXHAUSTED_PORTS, 1);
164 : }
165 0 : next0 = CNAT_TRANSLATION_NEXT_DROP;
166 0 : goto trace;
167 : }
168 :
169 : /* refcnt session in current client */
170 120 : cnat_client_cnt_session (cc);
171 120 : cnat_session_create (session, ctx);
172 120 : if (!(ct->flags & CNAT_TR_FLAG_NO_RETURN_SESSION))
173 120 : cnat_rsession_create (session, ctx, CNAT_LOCATION_FIB, rsession_flags);
174 120 : trace_flags |= CNAT_TRACE_SESSION_CREATED;
175 :
176 120 : next0 = ct->ct_lb.dpoi_next_node;
177 120 : vnet_buffer (b)->ip.adj_index[VLIB_TX] = session->value.cs_lbi;
178 : }
179 :
180 4050 : if (AF_IP4 == ctx->af)
181 2070 : cnat_translation_ip4 (session, ip4, udp0, vnet_buffer (b)->oflags);
182 : else
183 1980 : cnat_translation_ip6 (session, ip6, udp0, vnet_buffer (b)->oflags);
184 :
185 4050 : if (NULL != ct)
186 : {
187 120 : cti = ct - cnat_translation_pool;
188 120 : vlib_increment_combined_counter (cntm, ctx->thread_index, cti, 1,
189 : vlib_buffer_length_in_chain (vm, b));
190 : }
191 :
192 3930 : trace:
193 5220 : if (PREDICT_FALSE (ctx->do_trace))
194 : {
195 5220 : trace_flags |= session_not_found ? 0 : CNAT_TRACE_SESSION_FOUND;
196 5220 : cnat_add_trace (vm, node, b, session, ct, trace_flags);
197 : }
198 5220 : return next0;
199 : }
200 :
201 752 : VLIB_NODE_FN (cnat_vip_ip4_node) (vlib_main_t * vm,
202 : vlib_node_runtime_t * node,
203 : vlib_frame_t * frame)
204 : {
205 177 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
206 177 : return cnat_node_inline (vm, node, frame, cnat_vip_node_fn, AF_IP4,
207 : CNAT_LOCATION_FIB, 1 /* do_trace */);
208 0 : return cnat_node_inline (vm, node, frame, cnat_vip_node_fn, AF_IP4,
209 : CNAT_LOCATION_FIB, 0 /* do_trace */);
210 : }
211 :
212 746 : VLIB_NODE_FN (cnat_vip_ip6_node) (vlib_main_t * vm,
213 : vlib_node_runtime_t * node,
214 : vlib_frame_t * frame)
215 : {
216 171 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
217 171 : return cnat_node_inline (vm, node, frame, cnat_vip_node_fn, AF_IP6,
218 : CNAT_LOCATION_FIB, 1 /* do_trace */);
219 0 : return cnat_node_inline (vm, node, frame, cnat_vip_node_fn, AF_IP6,
220 : CNAT_LOCATION_FIB, 0 /* do_trace */);
221 : }
222 :
223 164204 : VLIB_REGISTER_NODE (cnat_vip_ip4_node) =
224 : {
225 : .name = "ip4-cnat-tx",
226 : .vector_size = sizeof (u32),
227 : .format_trace = format_cnat_trace,
228 : .type = VLIB_NODE_TYPE_INTERNAL,
229 : .n_errors = 0,
230 : .n_next_nodes = CNAT_TRANSLATION_N_NEXT,
231 : .next_nodes =
232 : {
233 : [CNAT_TRANSLATION_NEXT_DROP] = "ip4-drop",
234 : [CNAT_TRANSLATION_NEXT_LOOKUP] = "ip4-lookup",
235 : },
236 : };
237 164204 : VLIB_REGISTER_NODE (cnat_vip_ip6_node) =
238 : {
239 : .name = "ip6-cnat-tx",
240 : .vector_size = sizeof (u32),
241 : .format_trace = format_cnat_trace,
242 : .type = VLIB_NODE_TYPE_INTERNAL,
243 : .n_errors = 0,
244 : .n_next_nodes = CNAT_TRANSLATION_N_NEXT,
245 : .next_nodes =
246 : {
247 : [CNAT_TRANSLATION_NEXT_DROP] = "ip6-drop",
248 : [CNAT_TRANSLATION_NEXT_LOOKUP] = "ip6-lookup",
249 : },
250 : };
251 :
252 : /*
253 : * fd.io coding-style-patch-verification: ON
254 : *
255 : * Local Variables:
256 : * eval: (c-set-style "gnu")
257 : * End:
258 : */
|