Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1 | /* |
| 2 | * snat.c - simple nat plugin |
| 3 | * |
| 4 | * Copyright (c) 2016 Cisco and/or its affiliates. |
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at: |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | */ |
| 17 | |
| 18 | #include <vnet/vnet.h> |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 19 | #include <vnet/ip/ip.h> |
| 20 | #include <vnet/ip/ip4.h> |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 21 | #include <vnet/plugin/plugin.h> |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 22 | #include <nat/nat.h> |
| 23 | #include <nat/nat_ipfix_logging.h> |
| 24 | #include <nat/nat_det.h> |
| 25 | #include <nat/nat64.h> |
Matus Fabian | 8ebe625 | 2017-11-06 05:04:53 -0800 | [diff] [blame] | 26 | #include <nat/dslite.h> |
Matus Fabian | efcd1e9 | 2017-08-15 06:59:19 -0700 | [diff] [blame] | 27 | #include <nat/nat_reass.h> |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 28 | #include <vnet/fib/fib_table.h> |
| 29 | #include <vnet/fib/ip4_fib.h> |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 30 | |
Damjan Marion | 3b46cba | 2017-01-23 21:13:45 +0100 | [diff] [blame] | 31 | #include <vpp/app/version.h> |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 32 | |
| 33 | snat_main_t snat_main; |
| 34 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 35 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 36 | /* Hook up input features */ |
Damjan Marion | 8b3191e | 2016-11-09 19:54:20 +0100 | [diff] [blame] | 37 | VNET_FEATURE_INIT (ip4_snat_in2out, static) = { |
| 38 | .arc_name = "ip4-unicast", |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 39 | .node_name = "nat44-in2out", |
| 40 | .runs_before = VNET_FEATURES ("nat44-out2in"), |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 41 | }; |
Damjan Marion | 8b3191e | 2016-11-09 19:54:20 +0100 | [diff] [blame] | 42 | VNET_FEATURE_INIT (ip4_snat_out2in, static) = { |
| 43 | .arc_name = "ip4-unicast", |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 44 | .node_name = "nat44-out2in", |
Damjan Marion | 8b3191e | 2016-11-09 19:54:20 +0100 | [diff] [blame] | 45 | .runs_before = VNET_FEATURES ("ip4-lookup"), |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 46 | }; |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 47 | VNET_FEATURE_INIT (ip4_nat_classify, static) = { |
| 48 | .arc_name = "ip4-unicast", |
| 49 | .node_name = "nat44-classify", |
| 50 | .runs_before = VNET_FEATURES ("ip4-lookup"), |
| 51 | }; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 52 | VNET_FEATURE_INIT (ip4_snat_det_in2out, static) = { |
| 53 | .arc_name = "ip4-unicast", |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 54 | .node_name = "nat44-det-in2out", |
| 55 | .runs_before = VNET_FEATURES ("nat44-det-out2in"), |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 56 | }; |
| 57 | VNET_FEATURE_INIT (ip4_snat_det_out2in, static) = { |
| 58 | .arc_name = "ip4-unicast", |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 59 | .node_name = "nat44-det-out2in", |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 60 | .runs_before = VNET_FEATURES ("ip4-lookup"), |
| 61 | }; |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 62 | VNET_FEATURE_INIT (ip4_nat_det_classify, static) = { |
| 63 | .arc_name = "ip4-unicast", |
| 64 | .node_name = "nat44-det-classify", |
| 65 | .runs_before = VNET_FEATURES ("ip4-lookup"), |
| 66 | }; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 67 | VNET_FEATURE_INIT (ip4_snat_in2out_worker_handoff, static) = { |
| 68 | .arc_name = "ip4-unicast", |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 69 | .node_name = "nat44-in2out-worker-handoff", |
| 70 | .runs_before = VNET_FEATURES ("nat44-out2in-worker-handoff"), |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 71 | }; |
| 72 | VNET_FEATURE_INIT (ip4_snat_out2in_worker_handoff, static) = { |
| 73 | .arc_name = "ip4-unicast", |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 74 | .node_name = "nat44-out2in-worker-handoff", |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 75 | .runs_before = VNET_FEATURES ("ip4-lookup"), |
| 76 | }; |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 77 | VNET_FEATURE_INIT (ip4_nat_handoff_classify, static) = { |
| 78 | .arc_name = "ip4-unicast", |
| 79 | .node_name = "nat44-handoff-classify", |
| 80 | .runs_before = VNET_FEATURES ("ip4-lookup"), |
| 81 | }; |
Damjan Marion | 8b3191e | 2016-11-09 19:54:20 +0100 | [diff] [blame] | 82 | VNET_FEATURE_INIT (ip4_snat_in2out_fast, static) = { |
| 83 | .arc_name = "ip4-unicast", |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 84 | .node_name = "nat44-in2out-fast", |
| 85 | .runs_before = VNET_FEATURES ("nat44-out2in-fast"), |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 86 | }; |
Damjan Marion | 8b3191e | 2016-11-09 19:54:20 +0100 | [diff] [blame] | 87 | VNET_FEATURE_INIT (ip4_snat_out2in_fast, static) = { |
| 88 | .arc_name = "ip4-unicast", |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 89 | .node_name = "nat44-out2in-fast", |
Damjan Marion | 8b3191e | 2016-11-09 19:54:20 +0100 | [diff] [blame] | 90 | .runs_before = VNET_FEATURES ("ip4-lookup"), |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 91 | }; |
Matus Fabian | 161c59c | 2017-07-21 03:46:03 -0700 | [diff] [blame] | 92 | VNET_FEATURE_INIT (ip4_snat_hairpin_dst, static) = { |
| 93 | .arc_name = "ip4-unicast", |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 94 | .node_name = "nat44-hairpin-dst", |
Matus Fabian | 161c59c | 2017-07-21 03:46:03 -0700 | [diff] [blame] | 95 | .runs_before = VNET_FEATURES ("ip4-lookup"), |
| 96 | }; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 97 | |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 98 | /* Hook up output features */ |
| 99 | VNET_FEATURE_INIT (ip4_snat_in2out_output, static) = { |
| 100 | .arc_name = "ip4-output", |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 101 | .node_name = "nat44-in2out-output", |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 102 | .runs_before = VNET_FEATURES ("interface-output"), |
| 103 | }; |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 104 | VNET_FEATURE_INIT (ip4_snat_in2out_output_worker_handoff, static) = { |
| 105 | .arc_name = "ip4-output", |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 106 | .node_name = "nat44-in2out-output-worker-handoff", |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 107 | .runs_before = VNET_FEATURES ("interface-output"), |
| 108 | }; |
Matus Fabian | 161c59c | 2017-07-21 03:46:03 -0700 | [diff] [blame] | 109 | VNET_FEATURE_INIT (ip4_snat_hairpin_src, static) = { |
| 110 | .arc_name = "ip4-output", |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 111 | .node_name = "nat44-hairpin-src", |
Matus Fabian | 161c59c | 2017-07-21 03:46:03 -0700 | [diff] [blame] | 112 | .runs_before = VNET_FEATURES ("interface-output"), |
| 113 | }; |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 114 | |
Matus Fabian | 87da476 | 2017-10-04 08:03:56 -0700 | [diff] [blame] | 115 | /* Hook up ip4-local features */ |
| 116 | VNET_FEATURE_INIT (ip4_nat_hairpinning, static) = |
| 117 | { |
| 118 | .arc_name = "ip4-local", |
| 119 | .node_name = "nat44-hairpinning", |
| 120 | .runs_before = VNET_FEATURES("ip4-local-end-of-arc"), |
| 121 | }; |
| 122 | |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 123 | |
Damjan Marion | 3b46cba | 2017-01-23 21:13:45 +0100 | [diff] [blame] | 124 | /* *INDENT-OFF* */ |
| 125 | VLIB_PLUGIN_REGISTER () = { |
| 126 | .version = VPP_BUILD_VER, |
Damjan Marion | 1bfb0dd | 2017-03-22 11:08:39 +0100 | [diff] [blame] | 127 | .description = "Network Address Translation", |
Damjan Marion | 3b46cba | 2017-01-23 21:13:45 +0100 | [diff] [blame] | 128 | }; |
| 129 | /* *INDENT-ON* */ |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 130 | |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 131 | vlib_node_registration_t nat44_classify_node; |
| 132 | vlib_node_registration_t nat44_det_classify_node; |
| 133 | vlib_node_registration_t nat44_handoff_classify_node; |
| 134 | |
| 135 | typedef enum { |
| 136 | NAT44_CLASSIFY_NEXT_IN2OUT, |
| 137 | NAT44_CLASSIFY_NEXT_OUT2IN, |
| 138 | NAT44_CLASSIFY_N_NEXT, |
| 139 | } nat44_classify_next_t; |
| 140 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 141 | void |
| 142 | nat_free_session_data (snat_main_t * sm, snat_session_t * s, u32 thread_index) |
| 143 | { |
| 144 | snat_session_key_t key; |
| 145 | clib_bihash_kv_8_8_t kv; |
| 146 | nat_ed_ses_key_t ed_key; |
| 147 | clib_bihash_kv_16_8_t ed_kv; |
| 148 | int i; |
| 149 | snat_address_t *a; |
| 150 | snat_main_per_thread_data_t *tsm = |
| 151 | vec_elt_at_index (sm->per_thread_data, thread_index); |
| 152 | |
| 153 | /* Endpoint dependent session lookup tables */ |
| 154 | if (is_ed_session (s)) |
| 155 | { |
| 156 | ed_key.l_addr = s->out2in.addr; |
| 157 | ed_key.r_addr = s->ext_host_addr; |
| 158 | ed_key.fib_index = s->out2in.fib_index; |
| 159 | if (snat_is_unk_proto_session (s)) |
| 160 | { |
| 161 | ed_key.proto = s->in2out.port; |
| 162 | ed_key.r_port = 0; |
| 163 | ed_key.l_port = 0; |
| 164 | } |
| 165 | else |
| 166 | { |
| 167 | ed_key.proto = snat_proto_to_ip_proto (s->in2out.protocol); |
| 168 | ed_key.l_port = s->out2in.port; |
| 169 | ed_key.r_port = s->ext_host_port; |
| 170 | } |
| 171 | ed_kv.key[0] = ed_key.as_u64[0]; |
| 172 | ed_kv.key[1] = ed_key.as_u64[1]; |
| 173 | if (clib_bihash_add_del_16_8 (&sm->out2in_ed, &ed_kv, 0)) |
| 174 | clib_warning ("out2in_ed key del failed"); |
| 175 | |
| 176 | ed_key.l_addr = s->in2out.addr; |
| 177 | ed_key.fib_index = s->in2out.fib_index; |
| 178 | if (!snat_is_unk_proto_session (s)) |
| 179 | ed_key.l_port = s->in2out.port; |
| 180 | if (is_twice_nat_session (s)) |
| 181 | { |
| 182 | ed_key.r_addr = s->ext_host_nat_addr; |
| 183 | ed_key.r_port = s->ext_host_nat_port; |
| 184 | } |
| 185 | ed_kv.key[0] = ed_key.as_u64[0]; |
| 186 | ed_kv.key[1] = ed_key.as_u64[1]; |
| 187 | if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &ed_kv, 0)) |
| 188 | clib_warning ("in2out_ed key del failed"); |
| 189 | } |
| 190 | |
| 191 | if (snat_is_unk_proto_session (s)) |
| 192 | return; |
| 193 | |
| 194 | /* log NAT event */ |
| 195 | snat_ipfix_logging_nat44_ses_delete(s->in2out.addr.as_u32, |
| 196 | s->out2in.addr.as_u32, |
| 197 | s->in2out.protocol, |
| 198 | s->in2out.port, |
| 199 | s->out2in.port, |
| 200 | s->in2out.fib_index); |
| 201 | |
| 202 | /* Twice NAT address and port for external host */ |
| 203 | if (is_twice_nat_session (s)) |
| 204 | { |
| 205 | for (i = 0; i < vec_len (sm->twice_nat_addresses); i++) |
| 206 | { |
| 207 | key.protocol = s->in2out.protocol; |
| 208 | key.port = s->ext_host_nat_port; |
| 209 | a = sm->twice_nat_addresses + i; |
| 210 | if (a->addr.as_u32 == s->ext_host_nat_addr.as_u32) |
| 211 | { |
| 212 | snat_free_outside_address_and_port (sm->twice_nat_addresses, |
| 213 | thread_index, &key, i); |
| 214 | break; |
| 215 | } |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | if (is_ed_session (s)) |
| 220 | return; |
| 221 | |
| 222 | /* Session lookup tables */ |
| 223 | kv.key = s->in2out.as_u64; |
| 224 | if (clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0)) |
| 225 | clib_warning ("in2out key del failed"); |
| 226 | kv.key = s->out2in.as_u64; |
| 227 | if (clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0)) |
| 228 | clib_warning ("out2in key del failed"); |
| 229 | |
| 230 | if (snat_is_session_static (s)) |
| 231 | return; |
| 232 | |
| 233 | if (s->outside_address_index != ~0) |
| 234 | snat_free_outside_address_and_port (sm->addresses, thread_index, |
| 235 | &s->out2in, s->outside_address_index); |
| 236 | } |
| 237 | |
| 238 | snat_user_t * |
| 239 | nat_user_get_or_create (snat_main_t *sm, ip4_address_t *addr, u32 fib_index, |
| 240 | u32 thread_index) |
| 241 | { |
| 242 | snat_user_t *u = 0; |
| 243 | snat_user_key_t user_key; |
| 244 | clib_bihash_kv_8_8_t kv, value; |
| 245 | snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; |
| 246 | dlist_elt_t * per_user_list_head_elt; |
| 247 | |
| 248 | user_key.addr.as_u32 = addr->as_u32; |
| 249 | user_key.fib_index = fib_index; |
| 250 | kv.key = user_key.as_u64; |
| 251 | |
| 252 | /* Ever heard of the "user" = src ip4 address before? */ |
| 253 | if (clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) |
| 254 | { |
| 255 | /* no, make a new one */ |
| 256 | pool_get (tsm->users, u); |
| 257 | memset (u, 0, sizeof (*u)); |
| 258 | u->addr.as_u32 = addr->as_u32; |
| 259 | u->fib_index = fib_index; |
| 260 | |
| 261 | pool_get (tsm->list_pool, per_user_list_head_elt); |
| 262 | |
| 263 | u->sessions_per_user_list_head_index = per_user_list_head_elt - |
| 264 | tsm->list_pool; |
| 265 | |
| 266 | clib_dlist_init (tsm->list_pool, u->sessions_per_user_list_head_index); |
| 267 | |
| 268 | kv.value = u - tsm->users; |
| 269 | |
| 270 | /* add user */ |
| 271 | if (clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 1)) |
| 272 | clib_warning ("user_hash keay add failed"); |
| 273 | } |
| 274 | else |
| 275 | { |
| 276 | u = pool_elt_at_index (tsm->users, value.value); |
| 277 | } |
| 278 | |
| 279 | return u; |
| 280 | } |
| 281 | |
| 282 | snat_session_t * |
| 283 | nat_session_alloc_or_recycle (snat_main_t *sm, snat_user_t *u, u32 thread_index) |
| 284 | { |
| 285 | snat_session_t *s; |
| 286 | snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; |
| 287 | u32 oldest_per_user_translation_list_index, session_index; |
| 288 | dlist_elt_t * oldest_per_user_translation_list_elt; |
| 289 | dlist_elt_t * per_user_translation_list_elt; |
| 290 | |
| 291 | /* Over quota? Recycle the least recently used translation */ |
| 292 | if ((u->nsessions + u->nstaticsessions) >= sm->max_translations_per_user) |
| 293 | { |
| 294 | oldest_per_user_translation_list_index = |
| 295 | clib_dlist_remove_head (tsm->list_pool, |
| 296 | u->sessions_per_user_list_head_index); |
| 297 | |
| 298 | ASSERT (oldest_per_user_translation_list_index != ~0); |
| 299 | |
| 300 | /* Add it back to the end of the LRU list */ |
| 301 | clib_dlist_addtail (tsm->list_pool, |
| 302 | u->sessions_per_user_list_head_index, |
| 303 | oldest_per_user_translation_list_index); |
| 304 | /* Get the list element */ |
| 305 | oldest_per_user_translation_list_elt = |
| 306 | pool_elt_at_index (tsm->list_pool, |
| 307 | oldest_per_user_translation_list_index); |
| 308 | |
| 309 | /* Get the session index from the list element */ |
| 310 | session_index = oldest_per_user_translation_list_elt->value; |
| 311 | |
| 312 | /* Get the session */ |
| 313 | s = pool_elt_at_index (tsm->sessions, session_index); |
| 314 | nat_free_session_data (sm, s, thread_index); |
| 315 | s->outside_address_index = ~0; |
| 316 | s->flags = 0; |
| 317 | s->total_bytes = 0; |
| 318 | s->total_pkts = 0; |
| 319 | } |
| 320 | else |
| 321 | { |
| 322 | pool_get (tsm->sessions, s); |
| 323 | memset (s, 0, sizeof (*s)); |
| 324 | s->outside_address_index = ~0; |
| 325 | |
| 326 | /* Create list elts */ |
| 327 | pool_get (tsm->list_pool, per_user_translation_list_elt); |
| 328 | clib_dlist_init (tsm->list_pool, |
| 329 | per_user_translation_list_elt - tsm->list_pool); |
| 330 | |
| 331 | per_user_translation_list_elt->value = s - tsm->sessions; |
| 332 | s->per_user_index = per_user_translation_list_elt - tsm->list_pool; |
| 333 | s->per_user_list_head_index = u->sessions_per_user_list_head_index; |
| 334 | |
| 335 | clib_dlist_addtail (tsm->list_pool, |
| 336 | s->per_user_list_head_index, |
| 337 | per_user_translation_list_elt - tsm->list_pool); |
| 338 | } |
| 339 | |
| 340 | return s; |
| 341 | } |
| 342 | |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 343 | static inline uword |
| 344 | nat44_classify_node_fn_inline (vlib_main_t * vm, |
| 345 | vlib_node_runtime_t * node, |
| 346 | vlib_frame_t * frame) |
| 347 | { |
| 348 | u32 n_left_from, * from, * to_next; |
| 349 | nat44_classify_next_t next_index; |
| 350 | snat_main_t *sm = &snat_main; |
| 351 | |
| 352 | from = vlib_frame_vector_args (frame); |
| 353 | n_left_from = frame->n_vectors; |
| 354 | next_index = node->cached_next_index; |
| 355 | |
| 356 | while (n_left_from > 0) |
| 357 | { |
| 358 | u32 n_left_to_next; |
| 359 | |
| 360 | vlib_get_next_frame (vm, node, next_index, |
| 361 | to_next, n_left_to_next); |
| 362 | |
| 363 | while (n_left_from > 0 && n_left_to_next > 0) |
| 364 | { |
| 365 | u32 bi0; |
| 366 | vlib_buffer_t *b0; |
| 367 | u32 next0 = NAT44_CLASSIFY_NEXT_IN2OUT; |
| 368 | ip4_header_t *ip0; |
| 369 | snat_address_t *ap; |
| 370 | snat_session_key_t m_key0; |
| 371 | clib_bihash_kv_8_8_t kv0, value0; |
| 372 | |
| 373 | /* speculatively enqueue b0 to the current next frame */ |
| 374 | bi0 = from[0]; |
| 375 | to_next[0] = bi0; |
| 376 | from += 1; |
| 377 | to_next += 1; |
| 378 | n_left_from -= 1; |
| 379 | n_left_to_next -= 1; |
| 380 | |
| 381 | b0 = vlib_get_buffer (vm, bi0); |
| 382 | ip0 = vlib_buffer_get_current (b0); |
| 383 | |
| 384 | vec_foreach (ap, sm->addresses) |
| 385 | { |
| 386 | if (ip0->dst_address.as_u32 == ap->addr.as_u32) |
| 387 | { |
| 388 | next0 = NAT44_CLASSIFY_NEXT_OUT2IN; |
| 389 | break; |
| 390 | } |
| 391 | } |
| 392 | |
| 393 | if (PREDICT_FALSE (pool_elts (sm->static_mappings))) |
| 394 | { |
| 395 | m_key0.addr = ip0->dst_address; |
| 396 | m_key0.port = 0; |
| 397 | m_key0.protocol = 0; |
| 398 | m_key0.fib_index = sm->outside_fib_index; |
| 399 | kv0.key = m_key0.as_u64; |
| 400 | if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv0, &value0)) |
| 401 | { |
| 402 | next0 = NAT44_CLASSIFY_NEXT_OUT2IN; |
| 403 | } |
| 404 | } |
| 405 | /* verify speculative enqueue, maybe switch current next frame */ |
| 406 | vlib_validate_buffer_enqueue_x1 (vm, node, next_index, |
| 407 | to_next, n_left_to_next, |
| 408 | bi0, next0); |
| 409 | } |
| 410 | |
| 411 | vlib_put_next_frame (vm, node, next_index, n_left_to_next); |
| 412 | } |
| 413 | |
| 414 | return frame->n_vectors; |
| 415 | } |
| 416 | |
| 417 | static uword |
| 418 | nat44_classify_node_fn (vlib_main_t * vm, |
| 419 | vlib_node_runtime_t * node, |
| 420 | vlib_frame_t * frame) |
| 421 | { |
| 422 | return nat44_classify_node_fn_inline (vm, node, frame); |
| 423 | }; |
| 424 | |
| 425 | VLIB_REGISTER_NODE (nat44_classify_node) = { |
| 426 | .function = nat44_classify_node_fn, |
| 427 | .name = "nat44-classify", |
| 428 | .vector_size = sizeof (u32), |
| 429 | .type = VLIB_NODE_TYPE_INTERNAL, |
| 430 | .n_next_nodes = NAT44_CLASSIFY_N_NEXT, |
| 431 | .next_nodes = { |
| 432 | [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out", |
| 433 | [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in", |
| 434 | }, |
| 435 | }; |
| 436 | |
| 437 | VLIB_NODE_FUNCTION_MULTIARCH (nat44_classify_node, |
| 438 | nat44_classify_node_fn); |
| 439 | |
| 440 | static uword |
| 441 | nat44_det_classify_node_fn (vlib_main_t * vm, |
| 442 | vlib_node_runtime_t * node, |
| 443 | vlib_frame_t * frame) |
| 444 | { |
| 445 | return nat44_classify_node_fn_inline (vm, node, frame); |
| 446 | }; |
| 447 | |
| 448 | VLIB_REGISTER_NODE (nat44_det_classify_node) = { |
| 449 | .function = nat44_det_classify_node_fn, |
| 450 | .name = "nat44-det-classify", |
| 451 | .vector_size = sizeof (u32), |
| 452 | .type = VLIB_NODE_TYPE_INTERNAL, |
| 453 | .n_next_nodes = NAT44_CLASSIFY_N_NEXT, |
| 454 | .next_nodes = { |
| 455 | [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-det-in2out", |
| 456 | [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-det-out2in", |
| 457 | }, |
| 458 | }; |
| 459 | |
| 460 | VLIB_NODE_FUNCTION_MULTIARCH (nat44_det_classify_node, |
| 461 | nat44_det_classify_node_fn); |
| 462 | |
| 463 | static uword |
| 464 | nat44_handoff_classify_node_fn (vlib_main_t * vm, |
| 465 | vlib_node_runtime_t * node, |
| 466 | vlib_frame_t * frame) |
| 467 | { |
| 468 | return nat44_classify_node_fn_inline (vm, node, frame); |
| 469 | }; |
| 470 | |
| 471 | VLIB_REGISTER_NODE (nat44_handoff_classify_node) = { |
| 472 | .function = nat44_handoff_classify_node_fn, |
| 473 | .name = "nat44-handoff-classify", |
| 474 | .vector_size = sizeof (u32), |
| 475 | .type = VLIB_NODE_TYPE_INTERNAL, |
| 476 | .n_next_nodes = NAT44_CLASSIFY_N_NEXT, |
| 477 | .next_nodes = { |
| 478 | [NAT44_CLASSIFY_NEXT_IN2OUT] = "nat44-in2out-worker-handoff", |
| 479 | [NAT44_CLASSIFY_NEXT_OUT2IN] = "nat44-out2in-worker-handoff", |
| 480 | }, |
| 481 | }; |
| 482 | |
| 483 | VLIB_NODE_FUNCTION_MULTIARCH (nat44_handoff_classify_node, |
| 484 | nat44_handoff_classify_node_fn); |
| 485 | |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 486 | /** |
| 487 | * @brief Add/del NAT address to FIB. |
| 488 | * |
| 489 | * Add the external NAT address to the FIB as receive entries. This ensures |
| 490 | * that VPP will reply to ARP for this address and we don't need to enable |
| 491 | * proxy ARP on the outside interface. |
| 492 | * |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 493 | * @param addr IPv4 address. |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 494 | * @param plen address prefix length |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 495 | * @param sw_if_index Interface. |
| 496 | * @param is_add If 0 delete, otherwise add. |
| 497 | */ |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 498 | void |
| 499 | snat_add_del_addr_to_fib (ip4_address_t * addr, u8 p_len, u32 sw_if_index, |
| 500 | int is_add) |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 501 | { |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 502 | fib_prefix_t prefix = { |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 503 | .fp_len = p_len, |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 504 | .fp_proto = FIB_PROTOCOL_IP4, |
| 505 | .fp_addr = { |
| 506 | .ip4.as_u32 = addr->as_u32, |
| 507 | }, |
| 508 | }; |
| 509 | u32 fib_index = ip4_fib_table_get_index_for_sw_if_index(sw_if_index); |
| 510 | |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 511 | if (is_add) |
| 512 | fib_table_entry_update_one_path(fib_index, |
| 513 | &prefix, |
Matus Fabian | dccbee3 | 2017-01-31 22:20:30 -0800 | [diff] [blame] | 514 | FIB_SOURCE_PLUGIN_HI, |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 515 | (FIB_ENTRY_FLAG_CONNECTED | |
| 516 | FIB_ENTRY_FLAG_LOCAL | |
| 517 | FIB_ENTRY_FLAG_EXCLUSIVE), |
Neale Ranns | da78f95 | 2017-05-24 09:15:43 -0700 | [diff] [blame] | 518 | DPO_PROTO_IP4, |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 519 | NULL, |
| 520 | sw_if_index, |
| 521 | ~0, |
| 522 | 1, |
| 523 | NULL, |
| 524 | FIB_ROUTE_PATH_FLAG_NONE); |
| 525 | else |
| 526 | fib_table_entry_delete(fib_index, |
| 527 | &prefix, |
Matus Fabian | dccbee3 | 2017-01-31 22:20:30 -0800 | [diff] [blame] | 528 | FIB_SOURCE_PLUGIN_HI); |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 529 | } |
| 530 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 531 | void snat_add_address (snat_main_t *sm, ip4_address_t *addr, u32 vrf_id, |
| 532 | u8 twice_nat) |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 533 | { |
| 534 | snat_address_t * ap; |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 535 | snat_interface_t *i; |
Matus Fabian | 624b8d9 | 2017-09-12 04:15:30 -0700 | [diff] [blame] | 536 | vlib_thread_main_t *tm = vlib_get_thread_main (); |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 537 | |
Matus Fabian | 860dacc | 2016-10-25 04:19:26 -0700 | [diff] [blame] | 538 | /* Check if address already exists */ |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 539 | vec_foreach (ap, twice_nat ? sm->twice_nat_addresses : sm->addresses) |
Matus Fabian | 860dacc | 2016-10-25 04:19:26 -0700 | [diff] [blame] | 540 | { |
| 541 | if (ap->addr.as_u32 == addr->as_u32) |
| 542 | return; |
| 543 | } |
| 544 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 545 | if (twice_nat) |
| 546 | vec_add2 (sm->twice_nat_addresses, ap, 1); |
| 547 | else |
| 548 | vec_add2 (sm->addresses, ap, 1); |
| 549 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 550 | ap->addr = *addr; |
Matus Fabian | f8d8490 | 2017-07-23 23:41:03 -0700 | [diff] [blame] | 551 | if (vrf_id != ~0) |
| 552 | ap->fib_index = |
Neale Ranns | 1500254 | 2017-09-10 04:39:11 -0700 | [diff] [blame] | 553 | fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, vrf_id, |
| 554 | FIB_SOURCE_PLUGIN_HI); |
Matus Fabian | f8d8490 | 2017-07-23 23:41:03 -0700 | [diff] [blame] | 555 | else |
| 556 | ap->fib_index = ~0; |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 557 | #define _(N, i, n, s) \ |
Matus Fabian | 624b8d9 | 2017-09-12 04:15:30 -0700 | [diff] [blame] | 558 | clib_bitmap_alloc (ap->busy_##n##_port_bitmap, 65535); \ |
| 559 | ap->busy_##n##_ports = 0; \ |
| 560 | vec_validate_init_empty (ap->busy_##n##_ports_per_thread, tm->n_vlib_mains - 1, 0); |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 561 | foreach_snat_protocol |
| 562 | #undef _ |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 563 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 564 | if (twice_nat) |
| 565 | return; |
| 566 | |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 567 | /* Add external address to FIB */ |
| 568 | pool_foreach (i, sm->interfaces, |
| 569 | ({ |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 570 | if (nat_interface_is_inside(i)) |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 571 | continue; |
| 572 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 573 | snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1); |
Matus Fabian | dccbee3 | 2017-01-31 22:20:30 -0800 | [diff] [blame] | 574 | break; |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 575 | })); |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 576 | pool_foreach (i, sm->output_feature_interfaces, |
| 577 | ({ |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 578 | if (nat_interface_is_inside(i)) |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 579 | continue; |
| 580 | |
| 581 | snat_add_del_addr_to_fib(addr, 32, i->sw_if_index, 1); |
| 582 | break; |
| 583 | })); |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 584 | } |
| 585 | |
Matus Fabian | 724b815 | 2016-10-04 03:23:43 -0700 | [diff] [blame] | 586 | static int is_snat_address_used_in_static_mapping (snat_main_t *sm, |
| 587 | ip4_address_t addr) |
| 588 | { |
| 589 | snat_static_mapping_t *m; |
| 590 | pool_foreach (m, sm->static_mappings, |
| 591 | ({ |
| 592 | if (m->external_addr.as_u32 == addr.as_u32) |
| 593 | return 1; |
| 594 | })); |
| 595 | |
| 596 | return 0; |
| 597 | } |
| 598 | |
Matus Fabian | cfe0fc9 | 2017-05-10 06:37:47 -0700 | [diff] [blame] | 599 | void increment_v4_address (ip4_address_t * a) |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 600 | { |
| 601 | u32 v; |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 602 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 603 | v = clib_net_to_host_u32(a->as_u32) + 1; |
| 604 | a->as_u32 = clib_host_to_net_u32(v); |
| 605 | } |
| 606 | |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 607 | static void |
| 608 | snat_add_static_mapping_when_resolved (snat_main_t * sm, |
| 609 | ip4_address_t l_addr, |
| 610 | u16 l_port, |
| 611 | u32 sw_if_index, |
| 612 | u16 e_port, |
Dave Barach | 8b27537 | 2017-01-16 10:54:02 -0500 | [diff] [blame] | 613 | u32 vrf_id, |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 614 | snat_protocol_t proto, |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 615 | int addr_only, |
Dave Barach | 8b27537 | 2017-01-16 10:54:02 -0500 | [diff] [blame] | 616 | int is_add) |
| 617 | { |
| 618 | snat_static_map_resolve_t *rp; |
| 619 | |
| 620 | vec_add2 (sm->to_resolve, rp, 1); |
| 621 | rp->l_addr.as_u32 = l_addr.as_u32; |
| 622 | rp->l_port = l_port; |
| 623 | rp->sw_if_index = sw_if_index; |
| 624 | rp->e_port = e_port; |
| 625 | rp->vrf_id = vrf_id; |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 626 | rp->proto = proto; |
Dave Barach | 8b27537 | 2017-01-16 10:54:02 -0500 | [diff] [blame] | 627 | rp->addr_only = addr_only; |
| 628 | rp->is_add = is_add; |
| 629 | } |
| 630 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 631 | /** |
| 632 | * @brief Add static mapping. |
| 633 | * |
| 634 | * Create static mapping between local addr+port and external addr+port. |
| 635 | * |
| 636 | * @param l_addr Local IPv4 address. |
| 637 | * @param e_addr External IPv4 address. |
| 638 | * @param l_port Local port number. |
| 639 | * @param e_port External port number. |
| 640 | * @param vrf_id VRF ID. |
| 641 | * @param addr_only If 0 address port and pair mapping, otherwise address only. |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 642 | * @param sw_if_index External port instead of specific IP address. |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 643 | * @param is_add If 0 delete static mapping, otherwise add. |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 644 | * @param twice_nat If 1 translate external host address and port. |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 645 | * |
| 646 | * @returns |
| 647 | */ |
| 648 | int snat_add_static_mapping(ip4_address_t l_addr, ip4_address_t e_addr, |
| 649 | u16 l_port, u16 e_port, u32 vrf_id, int addr_only, |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 650 | u32 sw_if_index, snat_protocol_t proto, int is_add, |
| 651 | u8 twice_nat) |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 652 | { |
| 653 | snat_main_t * sm = &snat_main; |
| 654 | snat_static_mapping_t *m; |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 655 | snat_session_key_t m_key; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 656 | clib_bihash_kv_8_8_t kv, value; |
| 657 | snat_address_t *a = 0; |
| 658 | u32 fib_index = ~0; |
| 659 | uword * p; |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 660 | snat_interface_t *interface; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 661 | int i; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 662 | snat_main_per_thread_data_t *tsm; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 663 | |
Dave Barach | 8b27537 | 2017-01-16 10:54:02 -0500 | [diff] [blame] | 664 | /* If the external address is a specific interface address */ |
| 665 | if (sw_if_index != ~0) |
| 666 | { |
| 667 | ip4_address_t * first_int_addr; |
| 668 | |
| 669 | /* Might be already set... */ |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 670 | first_int_addr = ip4_interface_first_address |
Dave Barach | 8b27537 | 2017-01-16 10:54:02 -0500 | [diff] [blame] | 671 | (sm->ip4_main, sw_if_index, 0 /* just want the address*/); |
| 672 | |
| 673 | /* DHCP resolution required? */ |
| 674 | if (first_int_addr == 0) |
| 675 | { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 676 | snat_add_static_mapping_when_resolved |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 677 | (sm, l_addr, l_port, sw_if_index, e_port, vrf_id, proto, |
Dave Barach | 8b27537 | 2017-01-16 10:54:02 -0500 | [diff] [blame] | 678 | addr_only, is_add); |
| 679 | return 0; |
| 680 | } |
| 681 | else |
Dave Barach | e6e012f | 2017-12-18 08:11:37 -0500 | [diff] [blame] | 682 | { |
Dave Barach | 8b27537 | 2017-01-16 10:54:02 -0500 | [diff] [blame] | 683 | e_addr.as_u32 = first_int_addr->as_u32; |
Dave Barach | e6e012f | 2017-12-18 08:11:37 -0500 | [diff] [blame] | 684 | /* Identity mapping? */ |
| 685 | if (l_addr.as_u32 == 0) |
| 686 | l_addr.as_u32 = e_addr.as_u32; |
| 687 | } |
Dave Barach | 8b27537 | 2017-01-16 10:54:02 -0500 | [diff] [blame] | 688 | } |
| 689 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 690 | m_key.addr = e_addr; |
| 691 | m_key.port = addr_only ? 0 : e_port; |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 692 | m_key.protocol = addr_only ? 0 : proto; |
Matus Fabian | 7e46a4d | 2016-10-06 04:28:29 -0700 | [diff] [blame] | 693 | m_key.fib_index = sm->outside_fib_index; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 694 | kv.key = m_key.as_u64; |
| 695 | if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) |
| 696 | m = 0; |
| 697 | else |
| 698 | m = pool_elt_at_index (sm->static_mappings, value.value); |
| 699 | |
| 700 | if (is_add) |
| 701 | { |
| 702 | if (m) |
| 703 | return VNET_API_ERROR_VALUE_EXIST; |
| 704 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 705 | if (twice_nat && addr_only) |
| 706 | return VNET_API_ERROR_UNSUPPORTED; |
| 707 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 708 | /* Convert VRF id to FIB index */ |
| 709 | if (vrf_id != ~0) |
| 710 | { |
| 711 | p = hash_get (sm->ip4_main->fib_index_by_table_id, vrf_id); |
| 712 | if (!p) |
| 713 | return VNET_API_ERROR_NO_SUCH_FIB; |
| 714 | fib_index = p[0]; |
| 715 | } |
| 716 | /* If not specified use inside VRF id from SNAT plugin startup config */ |
| 717 | else |
| 718 | { |
Matus Fabian | 31c31aa | 2017-02-05 22:45:57 -0800 | [diff] [blame] | 719 | fib_index = sm->inside_fib_index; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 720 | vrf_id = sm->inside_vrf_id; |
| 721 | } |
| 722 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 723 | /* Find external address in allocated addresses and reserve port for |
| 724 | address and port pair mapping when dynamic translations enabled */ |
| 725 | if (!addr_only && !(sm->static_mapping_only)) |
| 726 | { |
| 727 | for (i = 0; i < vec_len (sm->addresses); i++) |
| 728 | { |
| 729 | if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) |
| 730 | { |
| 731 | a = sm->addresses + i; |
| 732 | /* External port must be unused */ |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 733 | switch (proto) |
| 734 | { |
| 735 | #define _(N, j, n, s) \ |
| 736 | case SNAT_PROTOCOL_##N: \ |
| 737 | if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \ |
| 738 | return VNET_API_ERROR_INVALID_VALUE; \ |
| 739 | clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \ |
| 740 | if (e_port > 1024) \ |
Matus Fabian | 624b8d9 | 2017-09-12 04:15:30 -0700 | [diff] [blame] | 741 | { \ |
| 742 | a->busy_##n##_ports++; \ |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 743 | a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \ |
Matus Fabian | 624b8d9 | 2017-09-12 04:15:30 -0700 | [diff] [blame] | 744 | } \ |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 745 | break; |
| 746 | foreach_snat_protocol |
| 747 | #undef _ |
| 748 | default: |
| 749 | clib_warning("unknown_protocol"); |
| 750 | return VNET_API_ERROR_INVALID_VALUE_2; |
| 751 | } |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 752 | break; |
| 753 | } |
| 754 | } |
| 755 | /* External address must be allocated */ |
| 756 | if (!a) |
| 757 | return VNET_API_ERROR_NO_SUCH_ENTRY; |
| 758 | } |
| 759 | |
| 760 | pool_get (sm->static_mappings, m); |
| 761 | memset (m, 0, sizeof (*m)); |
| 762 | m->local_addr = l_addr; |
| 763 | m->external_addr = e_addr; |
| 764 | m->addr_only = addr_only; |
| 765 | m->vrf_id = vrf_id; |
| 766 | m->fib_index = fib_index; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 767 | m->twice_nat = twice_nat; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 768 | if (!addr_only) |
| 769 | { |
| 770 | m->local_port = l_port; |
| 771 | m->external_port = e_port; |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 772 | m->proto = proto; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 773 | } |
| 774 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 775 | if (sm->workers) |
| 776 | { |
| 777 | ip4_header_t ip = { |
| 778 | .src_address = m->local_addr, |
| 779 | }; |
| 780 | m->worker_index = sm->worker_in2out_cb (&ip, m->fib_index); |
| 781 | tsm = vec_elt_at_index (sm->per_thread_data, m->worker_index); |
| 782 | } |
| 783 | else |
| 784 | tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); |
| 785 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 786 | m_key.addr = m->local_addr; |
| 787 | m_key.port = m->local_port; |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 788 | m_key.protocol = m->proto; |
Matus Fabian | 7e46a4d | 2016-10-06 04:28:29 -0700 | [diff] [blame] | 789 | m_key.fib_index = m->fib_index; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 790 | kv.key = m_key.as_u64; |
| 791 | kv.value = m - sm->static_mappings; |
| 792 | clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1); |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 793 | if (twice_nat) |
| 794 | { |
| 795 | m_key.port = clib_host_to_net_u16 (l_port); |
| 796 | kv.key = m_key.as_u64; |
| 797 | kv.value = ~0ULL; |
| 798 | if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1)) |
| 799 | clib_warning ("in2out key add failed"); |
| 800 | } |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 801 | |
| 802 | m_key.addr = m->external_addr; |
| 803 | m_key.port = m->external_port; |
Matus Fabian | 7e46a4d | 2016-10-06 04:28:29 -0700 | [diff] [blame] | 804 | m_key.fib_index = sm->outside_fib_index; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 805 | kv.key = m_key.as_u64; |
| 806 | kv.value = m - sm->static_mappings; |
| 807 | clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1); |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 808 | if (twice_nat) |
Matus Fabian | 4933168 | 2016-12-01 01:32:03 -0800 | [diff] [blame] | 809 | { |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 810 | m_key.port = clib_host_to_net_u16 (e_port); |
| 811 | kv.key = m_key.as_u64; |
| 812 | kv.value = ~0ULL; |
| 813 | if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1)) |
| 814 | clib_warning ("out2in key add failed"); |
Matus Fabian | 4933168 | 2016-12-01 01:32:03 -0800 | [diff] [blame] | 815 | } |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 816 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 817 | } |
| 818 | else |
| 819 | { |
| 820 | if (!m) |
| 821 | return VNET_API_ERROR_NO_SUCH_ENTRY; |
| 822 | |
| 823 | /* Free external address port */ |
| 824 | if (!addr_only && !(sm->static_mapping_only)) |
| 825 | { |
| 826 | for (i = 0; i < vec_len (sm->addresses); i++) |
| 827 | { |
| 828 | if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) |
| 829 | { |
| 830 | a = sm->addresses + i; |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 831 | switch (proto) |
| 832 | { |
| 833 | #define _(N, j, n, s) \ |
| 834 | case SNAT_PROTOCOL_##N: \ |
| 835 | clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \ |
| 836 | if (e_port > 1024) \ |
Matus Fabian | 624b8d9 | 2017-09-12 04:15:30 -0700 | [diff] [blame] | 837 | { \ |
| 838 | a->busy_##n##_ports--; \ |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 839 | a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \ |
Matus Fabian | 624b8d9 | 2017-09-12 04:15:30 -0700 | [diff] [blame] | 840 | } \ |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 841 | break; |
| 842 | foreach_snat_protocol |
| 843 | #undef _ |
| 844 | default: |
| 845 | clib_warning("unknown_protocol"); |
| 846 | return VNET_API_ERROR_INVALID_VALUE_2; |
| 847 | } |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 848 | break; |
| 849 | } |
| 850 | } |
| 851 | } |
| 852 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 853 | if (sm->num_workers > 1) |
| 854 | tsm = vec_elt_at_index (sm->per_thread_data, m->worker_index); |
| 855 | else |
| 856 | tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); |
| 857 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 858 | m_key.addr = m->local_addr; |
| 859 | m_key.port = m->local_port; |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 860 | m_key.protocol = m->proto; |
Matus Fabian | 7e46a4d | 2016-10-06 04:28:29 -0700 | [diff] [blame] | 861 | m_key.fib_index = m->fib_index; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 862 | kv.key = m_key.as_u64; |
| 863 | clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0); |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 864 | if (twice_nat) |
| 865 | { |
| 866 | m_key.port = clib_host_to_net_u16 (m->local_port); |
| 867 | kv.key = m_key.as_u64; |
| 868 | kv.value = ~0ULL; |
| 869 | if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0)) |
| 870 | clib_warning ("in2out key del failed"); |
| 871 | } |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 872 | |
| 873 | m_key.addr = m->external_addr; |
| 874 | m_key.port = m->external_port; |
Matus Fabian | 7e46a4d | 2016-10-06 04:28:29 -0700 | [diff] [blame] | 875 | m_key.fib_index = sm->outside_fib_index; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 876 | kv.key = m_key.as_u64; |
| 877 | clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0); |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 878 | if (twice_nat) |
| 879 | { |
| 880 | m_key.port = clib_host_to_net_u16 (m->external_port); |
| 881 | kv.key = m_key.as_u64; |
| 882 | kv.value = ~0ULL; |
| 883 | if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0)) |
| 884 | clib_warning ("in2out key del failed"); |
| 885 | } |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 886 | |
| 887 | /* Delete session(s) for static mapping if exist */ |
| 888 | if (!(sm->static_mapping_only) || |
| 889 | (sm->static_mapping_only && sm->static_mapping_connection_tracking)) |
| 890 | { |
| 891 | snat_user_key_t u_key; |
| 892 | snat_user_t *u; |
| 893 | dlist_elt_t * head, * elt; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 894 | u32 elt_index, head_index; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 895 | u32 ses_index; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 896 | u64 user_index; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 897 | snat_session_t * s; |
| 898 | |
| 899 | u_key.addr = m->local_addr; |
| 900 | u_key.fib_index = m->fib_index; |
| 901 | kv.key = u_key.as_u64; |
Matus Fabian | 092b3cd | 2017-09-19 05:42:38 -0700 | [diff] [blame] | 902 | if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 903 | { |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 904 | user_index = value.value; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 905 | u = pool_elt_at_index (tsm->users, user_index); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 906 | if (u->nstaticsessions) |
| 907 | { |
| 908 | head_index = u->sessions_per_user_list_head_index; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 909 | head = pool_elt_at_index (tsm->list_pool, head_index); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 910 | elt_index = head->next; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 911 | elt = pool_elt_at_index (tsm->list_pool, elt_index); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 912 | ses_index = elt->value; |
| 913 | while (ses_index != ~0) |
| 914 | { |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 915 | s = pool_elt_at_index (tsm->sessions, ses_index); |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 916 | elt = pool_elt_at_index (tsm->list_pool, elt->next); |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 917 | ses_index = elt->value; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 918 | |
| 919 | if (!addr_only) |
| 920 | { |
| 921 | if ((s->out2in.addr.as_u32 != e_addr.as_u32) && |
| 922 | (clib_net_to_host_u16 (s->out2in.port) != e_port)) |
| 923 | continue; |
| 924 | } |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 925 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 926 | nat_free_session_data (sm, s, tsm - sm->per_thread_data); |
| 927 | clib_dlist_remove (tsm->list_pool, s->per_user_index); |
| 928 | pool_put_index (tsm->list_pool, s->per_user_index); |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 929 | pool_put (tsm->sessions, s); |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 930 | u->nstaticsessions--; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 931 | |
| 932 | if (!addr_only) |
| 933 | break; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 934 | } |
| 935 | if (addr_only) |
| 936 | { |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 937 | pool_put (tsm->users, u); |
Matus Fabian | 092b3cd | 2017-09-19 05:42:38 -0700 | [diff] [blame] | 938 | clib_bihash_add_del_8_8 (&tsm->user_hash, &kv, 0); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 939 | } |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 940 | } |
| 941 | } |
| 942 | } |
| 943 | |
| 944 | /* Delete static mapping from pool */ |
| 945 | pool_put (sm->static_mappings, m); |
| 946 | } |
| 947 | |
Matus Fabian | ab7a805 | 2017-11-28 04:29:41 -0800 | [diff] [blame] | 948 | if (!addr_only || (l_addr.as_u32 == e_addr.as_u32)) |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 949 | return 0; |
| 950 | |
| 951 | /* Add/delete external address to FIB */ |
| 952 | pool_foreach (interface, sm->interfaces, |
| 953 | ({ |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 954 | if (nat_interface_is_inside(interface)) |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 955 | continue; |
| 956 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 957 | snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add); |
Matus Fabian | dccbee3 | 2017-01-31 22:20:30 -0800 | [diff] [blame] | 958 | break; |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 959 | })); |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 960 | pool_foreach (interface, sm->output_feature_interfaces, |
| 961 | ({ |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 962 | if (nat_interface_is_inside(interface)) |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 963 | continue; |
| 964 | |
| 965 | snat_add_del_addr_to_fib(&e_addr, 32, interface->sw_if_index, is_add); |
| 966 | break; |
| 967 | })); |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 968 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 969 | return 0; |
| 970 | } |
| 971 | |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 972 | int nat44_add_del_lb_static_mapping (ip4_address_t e_addr, u16 e_port, |
| 973 | snat_protocol_t proto, u32 vrf_id, |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 974 | nat44_lb_addr_port_t *locals, u8 is_add, |
| 975 | u8 twice_nat) |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 976 | { |
| 977 | snat_main_t * sm = &snat_main; |
| 978 | snat_static_mapping_t *m; |
| 979 | snat_session_key_t m_key; |
| 980 | clib_bihash_kv_8_8_t kv, value; |
| 981 | u32 fib_index; |
| 982 | snat_address_t *a = 0; |
| 983 | int i; |
| 984 | nat44_lb_addr_port_t *local; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 985 | u32 worker_index = 0, elt_index, head_index, ses_index; |
Matus Fabian | 092b3cd | 2017-09-19 05:42:38 -0700 | [diff] [blame] | 986 | snat_main_per_thread_data_t *tsm; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 987 | snat_user_key_t u_key; |
| 988 | snat_user_t *u; |
| 989 | snat_session_t * s; |
| 990 | dlist_elt_t * head, * elt; |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 991 | |
| 992 | m_key.addr = e_addr; |
| 993 | m_key.port = e_port; |
| 994 | m_key.protocol = proto; |
| 995 | m_key.fib_index = sm->outside_fib_index; |
| 996 | kv.key = m_key.as_u64; |
| 997 | if (clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) |
| 998 | m = 0; |
| 999 | else |
| 1000 | m = pool_elt_at_index (sm->static_mappings, value.value); |
| 1001 | |
| 1002 | if (is_add) |
| 1003 | { |
| 1004 | if (m) |
| 1005 | return VNET_API_ERROR_VALUE_EXIST; |
| 1006 | |
| 1007 | if (vec_len (locals) < 2) |
| 1008 | return VNET_API_ERROR_INVALID_VALUE; |
| 1009 | |
| 1010 | fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, |
Neale Ranns | 1500254 | 2017-09-10 04:39:11 -0700 | [diff] [blame] | 1011 | vrf_id, |
| 1012 | FIB_SOURCE_PLUGIN_HI); |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1013 | |
| 1014 | /* Find external address in allocated addresses and reserve port for |
| 1015 | address and port pair mapping when dynamic translations enabled */ |
| 1016 | if (!sm->static_mapping_only) |
| 1017 | { |
| 1018 | for (i = 0; i < vec_len (sm->addresses); i++) |
| 1019 | { |
| 1020 | if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) |
| 1021 | { |
| 1022 | a = sm->addresses + i; |
| 1023 | /* External port must be unused */ |
| 1024 | switch (proto) |
| 1025 | { |
| 1026 | #define _(N, j, n, s) \ |
| 1027 | case SNAT_PROTOCOL_##N: \ |
| 1028 | if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, e_port)) \ |
| 1029 | return VNET_API_ERROR_INVALID_VALUE; \ |
| 1030 | clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 1); \ |
| 1031 | if (e_port > 1024) \ |
Matus Fabian | 624b8d9 | 2017-09-12 04:15:30 -0700 | [diff] [blame] | 1032 | { \ |
| 1033 | a->busy_##n##_ports++; \ |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 1034 | a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]++; \ |
Matus Fabian | 624b8d9 | 2017-09-12 04:15:30 -0700 | [diff] [blame] | 1035 | } \ |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1036 | break; |
| 1037 | foreach_snat_protocol |
| 1038 | #undef _ |
| 1039 | default: |
| 1040 | clib_warning("unknown_protocol"); |
| 1041 | return VNET_API_ERROR_INVALID_VALUE_2; |
| 1042 | } |
| 1043 | break; |
| 1044 | } |
| 1045 | } |
| 1046 | /* External address must be allocated */ |
| 1047 | if (!a) |
| 1048 | return VNET_API_ERROR_NO_SUCH_ENTRY; |
| 1049 | } |
| 1050 | |
| 1051 | pool_get (sm->static_mappings, m); |
| 1052 | memset (m, 0, sizeof (*m)); |
| 1053 | m->external_addr = e_addr; |
| 1054 | m->addr_only = 0; |
| 1055 | m->vrf_id = vrf_id; |
| 1056 | m->fib_index = fib_index; |
| 1057 | m->external_port = e_port; |
| 1058 | m->proto = proto; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1059 | m->twice_nat = twice_nat; |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1060 | |
| 1061 | m_key.addr = m->external_addr; |
| 1062 | m_key.port = m->external_port; |
| 1063 | m_key.protocol = m->proto; |
| 1064 | m_key.fib_index = sm->outside_fib_index; |
| 1065 | kv.key = m_key.as_u64; |
| 1066 | kv.value = m - sm->static_mappings; |
| 1067 | if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 1)) |
| 1068 | { |
| 1069 | clib_warning ("static_mapping_by_external key add failed"); |
| 1070 | return VNET_API_ERROR_UNSPECIFIED; |
| 1071 | } |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1072 | |
| 1073 | /* Assign worker */ |
| 1074 | if (sm->workers) |
| 1075 | { |
Matus Fabian | 7865b5c | 2017-09-26 01:23:01 -0700 | [diff] [blame] | 1076 | worker_index = sm->first_worker_index + |
| 1077 | sm->workers[sm->next_worker++ % vec_len (sm->workers)]; |
Matus Fabian | 092b3cd | 2017-09-19 05:42:38 -0700 | [diff] [blame] | 1078 | tsm = vec_elt_at_index (sm->per_thread_data, worker_index); |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 1079 | m->worker_index = worker_index; |
Matus Fabian | 092b3cd | 2017-09-19 05:42:38 -0700 | [diff] [blame] | 1080 | } |
| 1081 | else |
| 1082 | tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); |
| 1083 | |
| 1084 | m_key.port = clib_host_to_net_u16 (m->external_port); |
| 1085 | kv.key = m_key.as_u64; |
| 1086 | kv.value = ~0ULL; |
| 1087 | if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 1)) |
| 1088 | { |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1089 | clib_warning ("out2in key add failed"); |
Matus Fabian | 092b3cd | 2017-09-19 05:42:38 -0700 | [diff] [blame] | 1090 | return VNET_API_ERROR_UNSPECIFIED; |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1091 | } |
| 1092 | |
Matus Fabian | 092b3cd | 2017-09-19 05:42:38 -0700 | [diff] [blame] | 1093 | m_key.fib_index = m->fib_index; |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1094 | for (i = 0; i < vec_len (locals); i++) |
| 1095 | { |
| 1096 | m_key.addr = locals[i].addr; |
| 1097 | m_key.port = locals[i].port; |
| 1098 | kv.key = m_key.as_u64; |
| 1099 | kv.value = m - sm->static_mappings; |
| 1100 | clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 1); |
flyingeagle23 | e8efd7d | 2017-09-11 16:02:40 +0800 | [diff] [blame] | 1101 | locals[i].prefix = (i == 0) ? locals[i].probability :\ |
| 1102 | (locals[i - 1].prefix + locals[i].probability); |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1103 | vec_add1 (m->locals, locals[i]); |
Matus Fabian | 7865b5c | 2017-09-26 01:23:01 -0700 | [diff] [blame] | 1104 | |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1105 | m_key.port = clib_host_to_net_u16 (locals[i].port); |
| 1106 | kv.key = m_key.as_u64; |
| 1107 | kv.value = ~0ULL; |
Matus Fabian | 092b3cd | 2017-09-19 05:42:38 -0700 | [diff] [blame] | 1108 | if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 1)) |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1109 | { |
| 1110 | clib_warning ("in2out key add failed"); |
| 1111 | return VNET_API_ERROR_UNSPECIFIED; |
| 1112 | } |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1113 | } |
| 1114 | } |
| 1115 | else |
| 1116 | { |
| 1117 | if (!m) |
| 1118 | return VNET_API_ERROR_NO_SUCH_ENTRY; |
| 1119 | |
Neale Ranns | 1500254 | 2017-09-10 04:39:11 -0700 | [diff] [blame] | 1120 | fib_table_unlock (m->fib_index, FIB_PROTOCOL_IP4, FIB_SOURCE_PLUGIN_HI); |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1121 | |
| 1122 | /* Free external address port */ |
| 1123 | if (!sm->static_mapping_only) |
| 1124 | { |
| 1125 | for (i = 0; i < vec_len (sm->addresses); i++) |
| 1126 | { |
| 1127 | if (sm->addresses[i].addr.as_u32 == e_addr.as_u32) |
| 1128 | { |
| 1129 | a = sm->addresses + i; |
| 1130 | switch (proto) |
| 1131 | { |
| 1132 | #define _(N, j, n, s) \ |
| 1133 | case SNAT_PROTOCOL_##N: \ |
| 1134 | clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, e_port, 0); \ |
| 1135 | if (e_port > 1024) \ |
Matus Fabian | 624b8d9 | 2017-09-12 04:15:30 -0700 | [diff] [blame] | 1136 | { \ |
| 1137 | a->busy_##n##_ports--; \ |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 1138 | a->busy_##n##_ports_per_thread[(e_port - 1024) / sm->port_per_thread]--; \ |
Matus Fabian | 624b8d9 | 2017-09-12 04:15:30 -0700 | [diff] [blame] | 1139 | } \ |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1140 | break; |
| 1141 | foreach_snat_protocol |
| 1142 | #undef _ |
| 1143 | default: |
| 1144 | clib_warning("unknown_protocol"); |
| 1145 | return VNET_API_ERROR_INVALID_VALUE_2; |
| 1146 | } |
| 1147 | break; |
| 1148 | } |
| 1149 | } |
| 1150 | } |
| 1151 | |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 1152 | tsm = vec_elt_at_index (sm->per_thread_data, m->worker_index); |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1153 | m_key.addr = m->external_addr; |
| 1154 | m_key.port = m->external_port; |
| 1155 | m_key.protocol = m->proto; |
| 1156 | m_key.fib_index = sm->outside_fib_index; |
| 1157 | kv.key = m_key.as_u64; |
| 1158 | if (clib_bihash_add_del_8_8(&sm->static_mapping_by_external, &kv, 0)) |
| 1159 | { |
| 1160 | clib_warning ("static_mapping_by_external key del failed"); |
| 1161 | return VNET_API_ERROR_UNSPECIFIED; |
| 1162 | } |
Matus Fabian | 7865b5c | 2017-09-26 01:23:01 -0700 | [diff] [blame] | 1163 | |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1164 | m_key.port = clib_host_to_net_u16 (m->external_port); |
| 1165 | kv.key = m_key.as_u64; |
Matus Fabian | 092b3cd | 2017-09-19 05:42:38 -0700 | [diff] [blame] | 1166 | if (clib_bihash_add_del_8_8(&tsm->out2in, &kv, 0)) |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1167 | { |
| 1168 | clib_warning ("outi2in key del failed"); |
| 1169 | return VNET_API_ERROR_UNSPECIFIED; |
| 1170 | } |
| 1171 | |
| 1172 | vec_foreach (local, m->locals) |
| 1173 | { |
| 1174 | m_key.addr = local->addr; |
| 1175 | m_key.port = local->port; |
| 1176 | m_key.fib_index = m->fib_index; |
| 1177 | kv.key = m_key.as_u64; |
| 1178 | if (clib_bihash_add_del_8_8(&sm->static_mapping_by_local, &kv, 0)) |
| 1179 | { |
| 1180 | clib_warning ("static_mapping_by_local key del failed"); |
| 1181 | return VNET_API_ERROR_UNSPECIFIED; |
| 1182 | } |
Matus Fabian | 7865b5c | 2017-09-26 01:23:01 -0700 | [diff] [blame] | 1183 | |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1184 | m_key.port = clib_host_to_net_u16 (local->port); |
| 1185 | kv.key = m_key.as_u64; |
Matus Fabian | 092b3cd | 2017-09-19 05:42:38 -0700 | [diff] [blame] | 1186 | if (clib_bihash_add_del_8_8(&tsm->in2out, &kv, 0)) |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1187 | { |
| 1188 | clib_warning ("in2out key del failed"); |
| 1189 | return VNET_API_ERROR_UNSPECIFIED; |
| 1190 | } |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1191 | /* Delete sessions */ |
| 1192 | u_key.addr = local->addr; |
| 1193 | u_key.fib_index = m->fib_index; |
| 1194 | kv.key = u_key.as_u64; |
| 1195 | if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) |
| 1196 | { |
| 1197 | u = pool_elt_at_index (tsm->users, value.value); |
| 1198 | if (u->nstaticsessions) |
| 1199 | { |
| 1200 | head_index = u->sessions_per_user_list_head_index; |
| 1201 | head = pool_elt_at_index (tsm->list_pool, head_index); |
| 1202 | elt_index = head->next; |
| 1203 | elt = pool_elt_at_index (tsm->list_pool, elt_index); |
| 1204 | ses_index = elt->value; |
| 1205 | while (ses_index != ~0) |
| 1206 | { |
| 1207 | s = pool_elt_at_index (tsm->sessions, ses_index); |
| 1208 | elt = pool_elt_at_index (tsm->list_pool, elt->next); |
| 1209 | ses_index = elt->value; |
| 1210 | |
| 1211 | if ((s->in2out.addr.as_u32 != local->addr.as_u32) && |
| 1212 | (clib_net_to_host_u16 (s->in2out.port) != local->port)) |
| 1213 | continue; |
| 1214 | |
| 1215 | nat_free_session_data (sm, s, tsm - sm->per_thread_data); |
| 1216 | clib_dlist_remove (tsm->list_pool, s->per_user_index); |
| 1217 | pool_put_index (tsm->list_pool, s->per_user_index); |
| 1218 | pool_put (tsm->sessions, s); |
| 1219 | u->nstaticsessions--; |
| 1220 | } |
| 1221 | } |
| 1222 | } |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1223 | } |
flyingeagle23 | 01ffc0c | 2017-09-13 19:03:56 +0800 | [diff] [blame] | 1224 | vec_free(m->locals); |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1225 | |
| 1226 | pool_put (sm->static_mappings, m); |
| 1227 | } |
| 1228 | |
| 1229 | return 0; |
| 1230 | } |
| 1231 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1232 | int |
| 1233 | snat_del_address (snat_main_t *sm, ip4_address_t addr, u8 delete_sm, |
| 1234 | u8 twice_nat) |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 1235 | { |
| 1236 | snat_address_t *a = 0; |
| 1237 | snat_session_t *ses; |
| 1238 | u32 *ses_to_be_removed = 0, *ses_index; |
| 1239 | clib_bihash_kv_8_8_t kv, value; |
| 1240 | snat_user_key_t user_key; |
| 1241 | snat_user_t *u; |
| 1242 | snat_main_per_thread_data_t *tsm; |
| 1243 | snat_static_mapping_t *m; |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 1244 | snat_interface_t *interface; |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 1245 | int i; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1246 | snat_address_t *addresses = twice_nat ? sm->twice_nat_addresses : sm->addresses; |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 1247 | |
| 1248 | /* Find SNAT address */ |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1249 | for (i=0; i < vec_len (addresses); i++) |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 1250 | { |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1251 | if (addresses[i].addr.as_u32 == addr.as_u32) |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 1252 | { |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1253 | a = addresses + i; |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 1254 | break; |
| 1255 | } |
| 1256 | } |
| 1257 | if (!a) |
| 1258 | return VNET_API_ERROR_NO_SUCH_ENTRY; |
| 1259 | |
| 1260 | if (delete_sm) |
| 1261 | { |
| 1262 | pool_foreach (m, sm->static_mappings, |
| 1263 | ({ |
| 1264 | if (m->external_addr.as_u32 == addr.as_u32) |
| 1265 | (void) snat_add_static_mapping (m->local_addr, m->external_addr, |
| 1266 | m->local_port, m->external_port, |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 1267 | m->vrf_id, m->addr_only, ~0, |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1268 | m->proto, 0, m->twice_nat); |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 1269 | })); |
| 1270 | } |
| 1271 | else |
| 1272 | { |
| 1273 | /* Check if address is used in some static mapping */ |
| 1274 | if (is_snat_address_used_in_static_mapping(sm, addr)) |
| 1275 | { |
| 1276 | clib_warning ("address used in static mapping"); |
| 1277 | return VNET_API_ERROR_UNSPECIFIED; |
| 1278 | } |
| 1279 | } |
| 1280 | |
Matus Fabian | f8d8490 | 2017-07-23 23:41:03 -0700 | [diff] [blame] | 1281 | if (a->fib_index != ~0) |
Neale Ranns | 1500254 | 2017-09-10 04:39:11 -0700 | [diff] [blame] | 1282 | fib_table_unlock(a->fib_index, FIB_PROTOCOL_IP4, |
| 1283 | FIB_SOURCE_PLUGIN_HI); |
Matus Fabian | f8d8490 | 2017-07-23 23:41:03 -0700 | [diff] [blame] | 1284 | |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 1285 | /* Delete sessions using address */ |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 1286 | if (a->busy_tcp_ports || a->busy_udp_ports || a->busy_icmp_ports) |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 1287 | { |
| 1288 | vec_foreach (tsm, sm->per_thread_data) |
| 1289 | { |
| 1290 | pool_foreach (ses, tsm->sessions, ({ |
| 1291 | if (ses->out2in.addr.as_u32 == addr.as_u32) |
| 1292 | { |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1293 | ses->outside_address_index = ~0; |
| 1294 | nat_free_session_data (sm, ses, tsm - sm->per_thread_data); |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 1295 | clib_dlist_remove (tsm->list_pool, ses->per_user_index); |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1296 | pool_put_index (tsm->list_pool, ses->per_user_index); |
| 1297 | vec_add1 (ses_to_be_removed, ses - tsm->sessions); |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 1298 | user_key.addr = ses->in2out.addr; |
| 1299 | user_key.fib_index = ses->in2out.fib_index; |
| 1300 | kv.key = user_key.as_u64; |
Matus Fabian | 092b3cd | 2017-09-19 05:42:38 -0700 | [diff] [blame] | 1301 | if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 1302 | { |
| 1303 | u = pool_elt_at_index (tsm->users, value.value); |
| 1304 | u->nsessions--; |
| 1305 | } |
| 1306 | } |
| 1307 | })); |
| 1308 | |
| 1309 | vec_foreach (ses_index, ses_to_be_removed) |
| 1310 | pool_put_index (tsm->sessions, ses_index[0]); |
| 1311 | |
| 1312 | vec_free (ses_to_be_removed); |
| 1313 | } |
| 1314 | } |
| 1315 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1316 | if (twice_nat) |
| 1317 | { |
| 1318 | vec_del1 (sm->twice_nat_addresses, i); |
| 1319 | return 0; |
| 1320 | } |
| 1321 | else |
| 1322 | vec_del1 (sm->addresses, i); |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 1323 | |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 1324 | /* Delete external address from FIB */ |
| 1325 | pool_foreach (interface, sm->interfaces, |
| 1326 | ({ |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 1327 | if (nat_interface_is_inside(interface)) |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 1328 | continue; |
| 1329 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 1330 | snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0); |
Matus Fabian | dccbee3 | 2017-01-31 22:20:30 -0800 | [diff] [blame] | 1331 | break; |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 1332 | })); |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 1333 | pool_foreach (interface, sm->output_feature_interfaces, |
| 1334 | ({ |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 1335 | if (nat_interface_is_inside(interface)) |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 1336 | continue; |
| 1337 | |
| 1338 | snat_add_del_addr_to_fib(&addr, 32, interface->sw_if_index, 0); |
| 1339 | break; |
| 1340 | })); |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 1341 | |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 1342 | return 0; |
| 1343 | } |
| 1344 | |
Matus Fabian | cfe0fc9 | 2017-05-10 06:37:47 -0700 | [diff] [blame] | 1345 | int snat_interface_add_del (u32 sw_if_index, u8 is_inside, int is_del) |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 1346 | { |
| 1347 | snat_main_t *sm = &snat_main; |
| 1348 | snat_interface_t *i; |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 1349 | const char * feature_name, *del_feature_name; |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 1350 | snat_address_t * ap; |
| 1351 | snat_static_mapping_t * m; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 1352 | snat_det_map_t * dm; |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 1353 | |
| 1354 | if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)) |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1355 | feature_name = is_inside ? "nat44-in2out-fast" : "nat44-out2in-fast"; |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 1356 | else |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1357 | { |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 1358 | if (sm->num_workers > 1 && !sm->deterministic) |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1359 | feature_name = is_inside ? "nat44-in2out-worker-handoff" : "nat44-out2in-worker-handoff"; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 1360 | else if (sm->deterministic) |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1361 | feature_name = is_inside ? "nat44-det-in2out" : "nat44-det-out2in"; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1362 | else |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1363 | feature_name = is_inside ? "nat44-in2out" : "nat44-out2in"; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1364 | } |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 1365 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 1366 | if (sm->fq_in2out_index == ~0 && !sm->deterministic && sm->num_workers > 1) |
| 1367 | sm->fq_in2out_index = vlib_frame_queue_main_init (sm->in2out_node_index, 0); |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1368 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 1369 | if (sm->fq_out2in_index == ~0 && !sm->deterministic && sm->num_workers > 1) |
| 1370 | sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0); |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1371 | |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 1372 | pool_foreach (i, sm->interfaces, |
| 1373 | ({ |
| 1374 | if (i->sw_if_index == sw_if_index) |
| 1375 | { |
| 1376 | if (is_del) |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 1377 | { |
| 1378 | if (nat_interface_is_inside(i) && nat_interface_is_outside(i)) |
| 1379 | { |
| 1380 | if (is_inside) |
| 1381 | i->flags &= ~NAT_INTERFACE_FLAG_IS_INSIDE; |
| 1382 | else |
| 1383 | i->flags &= ~NAT_INTERFACE_FLAG_IS_OUTSIDE; |
| 1384 | |
| 1385 | if (sm->num_workers > 1 && !sm->deterministic) |
| 1386 | del_feature_name = "nat44-handoff-classify"; |
| 1387 | else if (sm->deterministic) |
| 1388 | del_feature_name = "nat44-det-classify"; |
| 1389 | else |
| 1390 | del_feature_name = "nat44-classify"; |
| 1391 | |
| 1392 | vnet_feature_enable_disable ("ip4-unicast", del_feature_name, |
| 1393 | sw_if_index, 0, 0, 0); |
| 1394 | vnet_feature_enable_disable ("ip4-unicast", feature_name, |
| 1395 | sw_if_index, 1, 0, 0); |
| 1396 | } |
| 1397 | else |
| 1398 | { |
| 1399 | vnet_feature_enable_disable ("ip4-unicast", feature_name, |
| 1400 | sw_if_index, 0, 0, 0); |
| 1401 | pool_put (sm->interfaces, i); |
| 1402 | } |
| 1403 | } |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 1404 | else |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 1405 | { |
| 1406 | if ((nat_interface_is_inside(i) && is_inside) || |
| 1407 | (nat_interface_is_outside(i) && !is_inside)) |
| 1408 | return 0; |
| 1409 | |
| 1410 | if (sm->num_workers > 1 && !sm->deterministic) |
| 1411 | { |
| 1412 | del_feature_name = !is_inside ? "nat44-in2out-worker-handoff" : |
| 1413 | "nat44-out2in-worker-handoff"; |
| 1414 | feature_name = "nat44-handoff-classify"; |
| 1415 | } |
| 1416 | else if (sm->deterministic) |
| 1417 | { |
| 1418 | del_feature_name = !is_inside ? "nat44-det-in2out" : |
| 1419 | "nat44-det-out2in"; |
| 1420 | feature_name = "nat44-det-classify"; |
| 1421 | } |
| 1422 | else |
| 1423 | { |
| 1424 | del_feature_name = !is_inside ? "nat44-in2out" : "nat44-out2in"; |
| 1425 | feature_name = "nat44-classify"; |
| 1426 | } |
| 1427 | |
| 1428 | vnet_feature_enable_disable ("ip4-unicast", del_feature_name, |
| 1429 | sw_if_index, 0, 0, 0); |
| 1430 | vnet_feature_enable_disable ("ip4-unicast", feature_name, |
| 1431 | sw_if_index, 1, 0, 0); |
| 1432 | goto set_flags; |
| 1433 | } |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 1434 | |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 1435 | goto fib; |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 1436 | } |
| 1437 | })); |
| 1438 | |
| 1439 | if (is_del) |
| 1440 | return VNET_API_ERROR_NO_SUCH_ENTRY; |
| 1441 | |
| 1442 | pool_get (sm->interfaces, i); |
| 1443 | i->sw_if_index = sw_if_index; |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 1444 | i->flags = 0; |
| 1445 | vnet_feature_enable_disable ("ip4-unicast", feature_name, sw_if_index, 1, 0, 0); |
| 1446 | |
| 1447 | set_flags: |
| 1448 | if (is_inside) |
| 1449 | i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE; |
| 1450 | else |
| 1451 | i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE; |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 1452 | |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 1453 | /* Add/delete external addresses to FIB */ |
| 1454 | fib: |
| 1455 | if (is_inside) |
Matus Fabian | 87da476 | 2017-10-04 08:03:56 -0700 | [diff] [blame] | 1456 | { |
| 1457 | vnet_feature_enable_disable ("ip4-local", "nat44-hairpinning", |
| 1458 | sw_if_index, !is_del, 0, 0); |
| 1459 | return 0; |
| 1460 | } |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 1461 | |
| 1462 | vec_foreach (ap, sm->addresses) |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 1463 | snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del); |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 1464 | |
| 1465 | pool_foreach (m, sm->static_mappings, |
| 1466 | ({ |
Matus Fabian | ab7a805 | 2017-11-28 04:29:41 -0800 | [diff] [blame] | 1467 | if (!(m->addr_only) || (m->local_addr.as_u32 == m->external_addr.as_u32)) |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 1468 | continue; |
| 1469 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 1470 | snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del); |
| 1471 | })); |
| 1472 | |
| 1473 | pool_foreach (dm, sm->det_maps, |
| 1474 | ({ |
| 1475 | snat_add_del_addr_to_fib(&dm->out_addr, dm->out_plen, sw_if_index, !is_del); |
Matus Fabian | e1ae29a | 2017-01-27 00:47:58 -0800 | [diff] [blame] | 1476 | })); |
| 1477 | |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 1478 | return 0; |
| 1479 | } |
| 1480 | |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 1481 | int snat_interface_add_del_output_feature (u32 sw_if_index, |
| 1482 | u8 is_inside, |
| 1483 | int is_del) |
| 1484 | { |
| 1485 | snat_main_t *sm = &snat_main; |
| 1486 | snat_interface_t *i; |
| 1487 | snat_address_t * ap; |
| 1488 | snat_static_mapping_t * m; |
| 1489 | |
| 1490 | if (sm->deterministic || |
| 1491 | (sm->static_mapping_only && !(sm->static_mapping_connection_tracking))) |
| 1492 | return VNET_API_ERROR_UNSUPPORTED; |
| 1493 | |
| 1494 | if (is_inside) |
Matus Fabian | 161c59c | 2017-07-21 03:46:03 -0700 | [diff] [blame] | 1495 | { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1496 | vnet_feature_enable_disable ("ip4-unicast", "nat44-hairpin-dst", |
Matus Fabian | 161c59c | 2017-07-21 03:46:03 -0700 | [diff] [blame] | 1497 | sw_if_index, !is_del, 0, 0); |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1498 | vnet_feature_enable_disable ("ip4-output", "nat44-hairpin-src", |
Matus Fabian | 161c59c | 2017-07-21 03:46:03 -0700 | [diff] [blame] | 1499 | sw_if_index, !is_del, 0, 0); |
| 1500 | goto fq; |
| 1501 | } |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 1502 | |
| 1503 | if (sm->num_workers > 1) |
| 1504 | { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1505 | vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in-worker-handoff", |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 1506 | sw_if_index, !is_del, 0, 0); |
| 1507 | vnet_feature_enable_disable ("ip4-output", |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1508 | "nat44-in2out-output-worker-handoff", |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 1509 | sw_if_index, !is_del, 0, 0); |
| 1510 | } |
| 1511 | else |
| 1512 | { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1513 | vnet_feature_enable_disable ("ip4-unicast", "nat44-out2in", sw_if_index, |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 1514 | !is_del, 0, 0); |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1515 | vnet_feature_enable_disable ("ip4-output", "nat44-in2out-output", |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 1516 | sw_if_index, !is_del, 0, 0); |
| 1517 | } |
| 1518 | |
Matus Fabian | 161c59c | 2017-07-21 03:46:03 -0700 | [diff] [blame] | 1519 | fq: |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 1520 | if (sm->fq_in2out_output_index == ~0 && sm->num_workers > 1) |
| 1521 | sm->fq_in2out_output_index = |
| 1522 | vlib_frame_queue_main_init (sm->in2out_output_node_index, 0); |
| 1523 | |
| 1524 | if (sm->fq_out2in_index == ~0 && sm->num_workers > 1) |
| 1525 | sm->fq_out2in_index = vlib_frame_queue_main_init (sm->out2in_node_index, 0); |
| 1526 | |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 1527 | pool_foreach (i, sm->output_feature_interfaces, |
| 1528 | ({ |
| 1529 | if (i->sw_if_index == sw_if_index) |
| 1530 | { |
| 1531 | if (is_del) |
| 1532 | pool_put (sm->output_feature_interfaces, i); |
| 1533 | else |
| 1534 | return VNET_API_ERROR_VALUE_EXIST; |
| 1535 | |
| 1536 | goto fib; |
| 1537 | } |
| 1538 | })); |
| 1539 | |
| 1540 | if (is_del) |
| 1541 | return VNET_API_ERROR_NO_SUCH_ENTRY; |
| 1542 | |
| 1543 | pool_get (sm->output_feature_interfaces, i); |
| 1544 | i->sw_if_index = sw_if_index; |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 1545 | i->flags = 0; |
| 1546 | if (is_inside) |
| 1547 | i->flags |= NAT_INTERFACE_FLAG_IS_INSIDE; |
| 1548 | else |
| 1549 | i->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE; |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 1550 | |
| 1551 | /* Add/delete external addresses to FIB */ |
| 1552 | fib: |
| 1553 | if (is_inside) |
| 1554 | return 0; |
| 1555 | |
| 1556 | vec_foreach (ap, sm->addresses) |
| 1557 | snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, !is_del); |
| 1558 | |
| 1559 | pool_foreach (m, sm->static_mappings, |
| 1560 | ({ |
| 1561 | if (!(m->addr_only)) |
| 1562 | continue; |
| 1563 | |
| 1564 | snat_add_del_addr_to_fib(&m->external_addr, 32, sw_if_index, !is_del); |
| 1565 | })); |
| 1566 | |
| 1567 | return 0; |
| 1568 | } |
| 1569 | |
Matus Fabian | cfe0fc9 | 2017-05-10 06:37:47 -0700 | [diff] [blame] | 1570 | int snat_set_workers (uword * bitmap) |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1571 | { |
| 1572 | snat_main_t *sm = &snat_main; |
Matus Fabian | 7801ca2 | 2017-08-03 00:58:05 -0700 | [diff] [blame] | 1573 | int i, j = 0; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1574 | |
| 1575 | if (sm->num_workers < 2) |
| 1576 | return VNET_API_ERROR_FEATURE_DISABLED; |
| 1577 | |
| 1578 | if (clib_bitmap_last_set (bitmap) >= sm->num_workers) |
| 1579 | return VNET_API_ERROR_INVALID_WORKER; |
| 1580 | |
| 1581 | vec_free (sm->workers); |
| 1582 | clib_bitmap_foreach (i, bitmap, |
| 1583 | ({ |
| 1584 | vec_add1(sm->workers, i); |
Matus Fabian | 7801ca2 | 2017-08-03 00:58:05 -0700 | [diff] [blame] | 1585 | sm->per_thread_data[i].snat_thread_index = j; |
| 1586 | j++; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1587 | })); |
| 1588 | |
Matus Fabian | 7801ca2 | 2017-08-03 00:58:05 -0700 | [diff] [blame] | 1589 | sm->port_per_thread = (0xffff - 1024) / _vec_len (sm->workers); |
| 1590 | sm->num_snat_thread = _vec_len (sm->workers); |
| 1591 | |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1592 | return 0; |
| 1593 | } |
| 1594 | |
Dave Barach | 8b27537 | 2017-01-16 10:54:02 -0500 | [diff] [blame] | 1595 | |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 1596 | static void |
| 1597 | snat_ip4_add_del_interface_address_cb (ip4_main_t * im, |
| 1598 | uword opaque, |
| 1599 | u32 sw_if_index, |
| 1600 | ip4_address_t * address, |
| 1601 | u32 address_length, |
| 1602 | u32 if_address_index, |
| 1603 | u32 is_delete); |
| 1604 | |
Matus Fabian | 2769710 | 2017-11-09 01:43:47 -0800 | [diff] [blame] | 1605 | static int |
| 1606 | nat_alloc_addr_and_port_default (snat_address_t * addresses, |
| 1607 | u32 fib_index, |
| 1608 | u32 thread_index, |
| 1609 | snat_session_key_t * k, |
| 1610 | u32 * address_indexp, |
Matus Fabian | 2769710 | 2017-11-09 01:43:47 -0800 | [diff] [blame] | 1611 | u16 port_per_thread, |
| 1612 | u32 snat_thread_index); |
| 1613 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1614 | static clib_error_t * snat_init (vlib_main_t * vm) |
| 1615 | { |
| 1616 | snat_main_t * sm = &snat_main; |
Matus Fabian | 08ce432 | 2017-06-19 05:28:27 -0700 | [diff] [blame] | 1617 | clib_error_t * error = 0; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1618 | ip4_main_t * im = &ip4_main; |
| 1619 | ip_lookup_main_t * lm = &im->lookup_main; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1620 | uword *p; |
| 1621 | vlib_thread_registration_t *tr; |
| 1622 | vlib_thread_main_t *tm = vlib_get_thread_main (); |
| 1623 | uword *bitmap = 0; |
| 1624 | u32 i; |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 1625 | ip4_add_del_interface_address_callback_t cb4; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1626 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1627 | sm->vlib_main = vm; |
| 1628 | sm->vnet_main = vnet_get_main(); |
| 1629 | sm->ip4_main = im; |
| 1630 | sm->ip4_lookup_main = lm; |
| 1631 | sm->api_main = &api_main; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1632 | sm->first_worker_index = 0; |
| 1633 | sm->next_worker = 0; |
| 1634 | sm->num_workers = 0; |
Matus Fabian | 7801ca2 | 2017-08-03 00:58:05 -0700 | [diff] [blame] | 1635 | sm->num_snat_thread = 1; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1636 | sm->workers = 0; |
Matus Fabian | 7801ca2 | 2017-08-03 00:58:05 -0700 | [diff] [blame] | 1637 | sm->port_per_thread = 0xffff - 1024; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1638 | sm->fq_in2out_index = ~0; |
| 1639 | sm->fq_out2in_index = ~0; |
Matus Fabian | 6a0946f | 2017-04-12 03:36:13 -0700 | [diff] [blame] | 1640 | sm->udp_timeout = SNAT_UDP_TIMEOUT; |
| 1641 | sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT; |
| 1642 | sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT; |
| 1643 | sm->icmp_timeout = SNAT_ICMP_TIMEOUT; |
Matus Fabian | 2769710 | 2017-11-09 01:43:47 -0800 | [diff] [blame] | 1644 | sm->alloc_addr_and_port = nat_alloc_addr_and_port_default; |
Juraj Sloboda | 7b92979 | 2017-11-23 13:20:48 +0100 | [diff] [blame^] | 1645 | sm->forwarding_enabled = 0; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1646 | |
| 1647 | p = hash_get_mem (tm->thread_registrations_by_name, "workers"); |
| 1648 | if (p) |
| 1649 | { |
| 1650 | tr = (vlib_thread_registration_t *) p[0]; |
| 1651 | if (tr) |
| 1652 | { |
| 1653 | sm->num_workers = tr->count; |
| 1654 | sm->first_worker_index = tr->first_index; |
| 1655 | } |
| 1656 | } |
| 1657 | |
Matus Fabian | 7801ca2 | 2017-08-03 00:58:05 -0700 | [diff] [blame] | 1658 | vec_validate (sm->per_thread_data, tm->n_vlib_mains - 1); |
| 1659 | |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 1660 | /* Use all available workers by default */ |
| 1661 | if (sm->num_workers > 1) |
| 1662 | { |
| 1663 | for (i=0; i < sm->num_workers; i++) |
| 1664 | bitmap = clib_bitmap_set (bitmap, i, 1); |
| 1665 | snat_set_workers(bitmap); |
| 1666 | clib_bitmap_free (bitmap); |
| 1667 | } |
Matus Fabian | 7801ca2 | 2017-08-03 00:58:05 -0700 | [diff] [blame] | 1668 | else |
| 1669 | { |
| 1670 | sm->per_thread_data[0].snat_thread_index = 0; |
| 1671 | } |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1672 | |
Matus Fabian | cfe0fc9 | 2017-05-10 06:37:47 -0700 | [diff] [blame] | 1673 | error = snat_api_init(vm, sm); |
Matus Fabian | 08ce432 | 2017-06-19 05:28:27 -0700 | [diff] [blame] | 1674 | if (error) |
| 1675 | return error; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1676 | |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 1677 | /* Set up the interface address add/del callback */ |
| 1678 | cb4.function = snat_ip4_add_del_interface_address_cb; |
| 1679 | cb4.function_opaque = 0; |
| 1680 | |
| 1681 | vec_add1 (im->add_del_interface_address_callbacks, cb4); |
| 1682 | |
Matus Fabian | eea28d7 | 2017-01-13 04:15:54 -0800 | [diff] [blame] | 1683 | /* Init IPFIX logging */ |
| 1684 | snat_ipfix_logging_init(vm); |
| 1685 | |
Matus Fabian | efcd1e9 | 2017-08-15 06:59:19 -0700 | [diff] [blame] | 1686 | /* Init NAT64 */ |
Matus Fabian | 08ce432 | 2017-06-19 05:28:27 -0700 | [diff] [blame] | 1687 | error = nat64_init(vm); |
Matus Fabian | efcd1e9 | 2017-08-15 06:59:19 -0700 | [diff] [blame] | 1688 | if (error) |
| 1689 | return error; |
Matus Fabian | 06596c5 | 2017-06-06 04:53:28 -0700 | [diff] [blame] | 1690 | |
Matus Fabian | 8ebe625 | 2017-11-06 05:04:53 -0800 | [diff] [blame] | 1691 | dslite_init(vm); |
| 1692 | |
Matus Fabian | efcd1e9 | 2017-08-15 06:59:19 -0700 | [diff] [blame] | 1693 | /* Init virtual fragmenentation reassembly */ |
| 1694 | return nat_reass_init(vm); |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1695 | } |
| 1696 | |
| 1697 | VLIB_INIT_FUNCTION (snat_init); |
| 1698 | |
Matus Fabian | 8ebe625 | 2017-11-06 05:04:53 -0800 | [diff] [blame] | 1699 | void snat_free_outside_address_and_port (snat_address_t * addresses, |
Matus Fabian | 624b8d9 | 2017-09-12 04:15:30 -0700 | [diff] [blame] | 1700 | u32 thread_index, |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1701 | snat_session_key_t * k, |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1702 | u32 address_index) |
| 1703 | { |
| 1704 | snat_address_t *a; |
| 1705 | u16 port_host_byte_order = clib_net_to_host_u16 (k->port); |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1706 | |
Matus Fabian | 8ebe625 | 2017-11-06 05:04:53 -0800 | [diff] [blame] | 1707 | ASSERT (address_index < vec_len (addresses)); |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1708 | |
Matus Fabian | 8ebe625 | 2017-11-06 05:04:53 -0800 | [diff] [blame] | 1709 | a = addresses + address_index; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1710 | |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 1711 | switch (k->protocol) |
| 1712 | { |
| 1713 | #define _(N, i, n, s) \ |
| 1714 | case SNAT_PROTOCOL_##N: \ |
| 1715 | ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \ |
| 1716 | port_host_byte_order) == 1); \ |
| 1717 | clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \ |
| 1718 | port_host_byte_order, 0); \ |
| 1719 | a->busy_##n##_ports--; \ |
Matus Fabian | 624b8d9 | 2017-09-12 04:15:30 -0700 | [diff] [blame] | 1720 | a->busy_##n##_ports_per_thread[thread_index]--; \ |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 1721 | break; |
| 1722 | foreach_snat_protocol |
| 1723 | #undef _ |
| 1724 | default: |
| 1725 | clib_warning("unknown_protocol"); |
| 1726 | return; |
| 1727 | } |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1728 | } |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1729 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 1730 | /** |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1731 | * @brief Match NAT44 static mapping. |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 1732 | * |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 1733 | * @param sm NAT main. |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 1734 | * @param match Address and port to match. |
| 1735 | * @param mapping External or local address and port of the matched mapping. |
| 1736 | * @param by_external If 0 match by local address otherwise match by external |
| 1737 | * address. |
Juraj Sloboda | d367768 | 2017-04-14 03:24:45 +0200 | [diff] [blame] | 1738 | * @param is_addr_only If matched mapping is address only |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1739 | * @param twice_nat If matched mapping is twice NAT. |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 1740 | * |
| 1741 | * @returns 0 if match found otherwise 1. |
| 1742 | */ |
| 1743 | int snat_static_mapping_match (snat_main_t * sm, |
| 1744 | snat_session_key_t match, |
| 1745 | snat_session_key_t * mapping, |
Juraj Sloboda | d367768 | 2017-04-14 03:24:45 +0200 | [diff] [blame] | 1746 | u8 by_external, |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1747 | u8 *is_addr_only, |
| 1748 | u8 *twice_nat) |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 1749 | { |
| 1750 | clib_bihash_kv_8_8_t kv, value; |
| 1751 | snat_static_mapping_t *m; |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 1752 | snat_session_key_t m_key; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 1753 | clib_bihash_8_8_t *mapping_hash = &sm->static_mapping_by_local; |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1754 | u32 rand, lo = 0, hi, mid; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 1755 | |
| 1756 | if (by_external) |
| 1757 | mapping_hash = &sm->static_mapping_by_external; |
| 1758 | |
| 1759 | m_key.addr = match.addr; |
| 1760 | m_key.port = clib_net_to_host_u16 (match.port); |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 1761 | m_key.protocol = match.protocol; |
Matus Fabian | 7e46a4d | 2016-10-06 04:28:29 -0700 | [diff] [blame] | 1762 | m_key.fib_index = match.fib_index; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 1763 | |
| 1764 | kv.key = m_key.as_u64; |
| 1765 | |
| 1766 | if (clib_bihash_search_8_8 (mapping_hash, &kv, &value)) |
| 1767 | { |
| 1768 | /* Try address only mapping */ |
| 1769 | m_key.port = 0; |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 1770 | m_key.protocol = 0; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 1771 | kv.key = m_key.as_u64; |
| 1772 | if (clib_bihash_search_8_8 (mapping_hash, &kv, &value)) |
| 1773 | return 1; |
| 1774 | } |
| 1775 | |
| 1776 | m = pool_elt_at_index (sm->static_mappings, value.value); |
| 1777 | |
| 1778 | if (by_external) |
| 1779 | { |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1780 | if (vec_len (m->locals)) |
| 1781 | { |
| 1782 | hi = vec_len (m->locals) - 1; |
| 1783 | rand = 1 + (random_u32 (&sm->random_seed) % m->locals[hi].prefix); |
| 1784 | while (lo < hi) |
| 1785 | { |
flyingeagle23 | 6a58f4a | 2017-09-12 15:10:46 +0800 | [diff] [blame] | 1786 | mid = ((hi - lo) >> 1) + lo; |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1787 | (rand > m->locals[mid].prefix) ? (lo = mid + 1) : (hi = mid); |
| 1788 | } |
| 1789 | if (!(m->locals[lo].prefix >= rand)) |
| 1790 | return 1; |
| 1791 | mapping->addr = m->locals[lo].addr; |
| 1792 | mapping->port = clib_host_to_net_u16 (m->locals[lo].port); |
| 1793 | } |
| 1794 | else |
| 1795 | { |
| 1796 | mapping->addr = m->local_addr; |
| 1797 | /* Address only mapping doesn't change port */ |
| 1798 | mapping->port = m->addr_only ? match.port |
| 1799 | : clib_host_to_net_u16 (m->local_port); |
| 1800 | } |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 1801 | mapping->fib_index = m->fib_index; |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 1802 | mapping->protocol = m->proto; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 1803 | } |
| 1804 | else |
| 1805 | { |
| 1806 | mapping->addr = m->external_addr; |
| 1807 | /* Address only mapping doesn't change port */ |
| 1808 | mapping->port = m->addr_only ? match.port |
| 1809 | : clib_host_to_net_u16 (m->external_port); |
| 1810 | mapping->fib_index = sm->outside_fib_index; |
| 1811 | } |
| 1812 | |
Juraj Sloboda | d367768 | 2017-04-14 03:24:45 +0200 | [diff] [blame] | 1813 | if (PREDICT_FALSE(is_addr_only != 0)) |
| 1814 | *is_addr_only = m->addr_only; |
| 1815 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 1816 | if (PREDICT_FALSE(twice_nat != 0)) |
| 1817 | *twice_nat = m->twice_nat; |
| 1818 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 1819 | return 0; |
| 1820 | } |
| 1821 | |
Matus Fabian | 7801ca2 | 2017-08-03 00:58:05 -0700 | [diff] [blame] | 1822 | static_always_inline u16 |
Matus Fabian | 8ebe625 | 2017-11-06 05:04:53 -0800 | [diff] [blame] | 1823 | snat_random_port (u16 min, u16 max) |
Matus Fabian | 7801ca2 | 2017-08-03 00:58:05 -0700 | [diff] [blame] | 1824 | { |
Matus Fabian | 8ebe625 | 2017-11-06 05:04:53 -0800 | [diff] [blame] | 1825 | snat_main_t *sm = &snat_main; |
Matus Fabian | 7801ca2 | 2017-08-03 00:58:05 -0700 | [diff] [blame] | 1826 | return min + random_u32 (&sm->random_seed) / |
| 1827 | (random_u32_max() / (max - min + 1) + 1); |
| 1828 | } |
| 1829 | |
Matus Fabian | 2769710 | 2017-11-09 01:43:47 -0800 | [diff] [blame] | 1830 | int |
| 1831 | snat_alloc_outside_address_and_port (snat_address_t * addresses, |
| 1832 | u32 fib_index, |
| 1833 | u32 thread_index, |
| 1834 | snat_session_key_t * k, |
| 1835 | u32 * address_indexp, |
Matus Fabian | 2769710 | 2017-11-09 01:43:47 -0800 | [diff] [blame] | 1836 | u16 port_per_thread, |
| 1837 | u32 snat_thread_index) |
| 1838 | { |
| 1839 | snat_main_t *sm = &snat_main; |
| 1840 | |
| 1841 | return sm->alloc_addr_and_port(addresses, fib_index, thread_index, k, |
Matus Fabian | 51e759f | 2017-12-07 23:22:51 -0800 | [diff] [blame] | 1842 | address_indexp, port_per_thread, |
Matus Fabian | 2769710 | 2017-11-09 01:43:47 -0800 | [diff] [blame] | 1843 | snat_thread_index); |
| 1844 | } |
| 1845 | |
| 1846 | static int |
| 1847 | nat_alloc_addr_and_port_default (snat_address_t * addresses, |
| 1848 | u32 fib_index, |
| 1849 | u32 thread_index, |
| 1850 | snat_session_key_t * k, |
| 1851 | u32 * address_indexp, |
Matus Fabian | 2769710 | 2017-11-09 01:43:47 -0800 | [diff] [blame] | 1852 | u16 port_per_thread, |
| 1853 | u32 snat_thread_index) |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1854 | { |
Matus Fabian | 51e759f | 2017-12-07 23:22:51 -0800 | [diff] [blame] | 1855 | int i, gi = 0; |
| 1856 | snat_address_t *a, *ga = 0; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1857 | u32 portnum; |
| 1858 | |
Matus Fabian | 8ebe625 | 2017-11-06 05:04:53 -0800 | [diff] [blame] | 1859 | for (i = 0; i < vec_len (addresses); i++) |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1860 | { |
Matus Fabian | 8ebe625 | 2017-11-06 05:04:53 -0800 | [diff] [blame] | 1861 | a = addresses + i; |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 1862 | switch (k->protocol) |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1863 | { |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 1864 | #define _(N, j, n, s) \ |
| 1865 | case SNAT_PROTOCOL_##N: \ |
Matus Fabian | 8ebe625 | 2017-11-06 05:04:53 -0800 | [diff] [blame] | 1866 | if (a->busy_##n##_ports_per_thread[thread_index] < port_per_thread) \ |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 1867 | { \ |
Matus Fabian | 51e759f | 2017-12-07 23:22:51 -0800 | [diff] [blame] | 1868 | if (a->fib_index == fib_index) \ |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 1869 | { \ |
Matus Fabian | 51e759f | 2017-12-07 23:22:51 -0800 | [diff] [blame] | 1870 | while (1) \ |
| 1871 | { \ |
| 1872 | portnum = (port_per_thread * \ |
| 1873 | snat_thread_index) + \ |
| 1874 | snat_random_port(1, port_per_thread) + 1024; \ |
| 1875 | if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \ |
| 1876 | continue; \ |
| 1877 | clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \ |
| 1878 | a->busy_##n##_ports_per_thread[thread_index]++; \ |
| 1879 | a->busy_##n##_ports++; \ |
| 1880 | k->addr = a->addr; \ |
| 1881 | k->port = clib_host_to_net_u16(portnum); \ |
| 1882 | *address_indexp = i; \ |
| 1883 | return 0; \ |
| 1884 | } \ |
| 1885 | } \ |
| 1886 | else if (a->fib_index == ~0) \ |
| 1887 | { \ |
| 1888 | ga = a; \ |
| 1889 | gi = i; \ |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 1890 | } \ |
| 1891 | } \ |
| 1892 | break; |
| 1893 | foreach_snat_protocol |
| 1894 | #undef _ |
| 1895 | default: |
| 1896 | clib_warning("unknown protocol"); |
| 1897 | return 1; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1898 | } |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 1899 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1900 | } |
Matus Fabian | 51e759f | 2017-12-07 23:22:51 -0800 | [diff] [blame] | 1901 | |
| 1902 | if (ga) |
| 1903 | { |
| 1904 | a = ga; |
| 1905 | switch (k->protocol) |
| 1906 | { |
| 1907 | #define _(N, j, n, s) \ |
| 1908 | case SNAT_PROTOCOL_##N: \ |
| 1909 | while (1) \ |
| 1910 | { \ |
| 1911 | portnum = (port_per_thread * \ |
| 1912 | snat_thread_index) + \ |
| 1913 | snat_random_port(1, port_per_thread) + 1024; \ |
| 1914 | if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \ |
| 1915 | continue; \ |
| 1916 | clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \ |
| 1917 | a->busy_##n##_ports_per_thread[thread_index]++; \ |
| 1918 | a->busy_##n##_ports++; \ |
| 1919 | k->addr = a->addr; \ |
| 1920 | k->port = clib_host_to_net_u16(portnum); \ |
| 1921 | *address_indexp = gi; \ |
| 1922 | return 0; \ |
| 1923 | } |
| 1924 | break; |
| 1925 | foreach_snat_protocol |
| 1926 | #undef _ |
| 1927 | default: |
| 1928 | clib_warning ("unknown protocol"); |
| 1929 | return 1; |
| 1930 | } |
| 1931 | } |
| 1932 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1933 | /* Totally out of translations to use... */ |
Matus Fabian | eea28d7 | 2017-01-13 04:15:54 -0800 | [diff] [blame] | 1934 | snat_ipfix_logging_addresses_exhausted(0); |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1935 | return 1; |
| 1936 | } |
| 1937 | |
Matus Fabian | 2769710 | 2017-11-09 01:43:47 -0800 | [diff] [blame] | 1938 | static int |
| 1939 | nat_alloc_addr_and_port_mape (snat_address_t * addresses, |
| 1940 | u32 fib_index, |
| 1941 | u32 thread_index, |
| 1942 | snat_session_key_t * k, |
| 1943 | u32 * address_indexp, |
Matus Fabian | 2769710 | 2017-11-09 01:43:47 -0800 | [diff] [blame] | 1944 | u16 port_per_thread, |
| 1945 | u32 snat_thread_index) |
| 1946 | { |
| 1947 | snat_main_t *sm = &snat_main; |
| 1948 | snat_address_t *a = addresses; |
| 1949 | u16 m, ports, portnum, A, j; |
| 1950 | m = 16 - (sm->psid_offset + sm->psid_length); |
| 1951 | ports = (1 << (16 - sm->psid_length)) - (1 << m); |
| 1952 | |
| 1953 | if (!vec_len (addresses)) |
| 1954 | goto exhausted; |
| 1955 | |
| 1956 | switch (k->protocol) |
| 1957 | { |
| 1958 | #define _(N, i, n, s) \ |
| 1959 | case SNAT_PROTOCOL_##N: \ |
| 1960 | if (a->busy_##n##_ports < ports) \ |
| 1961 | { \ |
| 1962 | while (1) \ |
| 1963 | { \ |
| 1964 | A = snat_random_port(1, pow2_mask(sm->psid_offset)); \ |
| 1965 | j = snat_random_port(0, pow2_mask(m)); \ |
| 1966 | portnum = A | (sm->psid << sm->psid_offset) | (j << (16 - m)); \ |
| 1967 | if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, portnum)) \ |
| 1968 | continue; \ |
| 1969 | clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, portnum, 1); \ |
| 1970 | a->busy_##n##_ports++; \ |
| 1971 | k->addr = a->addr; \ |
| 1972 | k->port = clib_host_to_net_u16 (portnum); \ |
| 1973 | *address_indexp = i; \ |
| 1974 | return 0; \ |
| 1975 | } \ |
| 1976 | } \ |
| 1977 | break; |
| 1978 | foreach_snat_protocol |
| 1979 | #undef _ |
| 1980 | default: |
| 1981 | clib_warning("unknown protocol"); |
| 1982 | return 1; |
| 1983 | } |
| 1984 | |
| 1985 | exhausted: |
| 1986 | /* Totally out of translations to use... */ |
| 1987 | snat_ipfix_logging_addresses_exhausted(0); |
| 1988 | return 1; |
| 1989 | } |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1990 | |
| 1991 | static clib_error_t * |
| 1992 | add_address_command_fn (vlib_main_t * vm, |
| 1993 | unformat_input_t * input, |
| 1994 | vlib_cli_command_t * cmd) |
| 1995 | { |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 1996 | unformat_input_t _line_input, *line_input = &_line_input; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 1997 | snat_main_t * sm = &snat_main; |
| 1998 | ip4_address_t start_addr, end_addr, this_addr; |
| 1999 | u32 start_host_order, end_host_order; |
Juraj Sloboda | eab38d9 | 2017-03-06 19:55:21 -0800 | [diff] [blame] | 2000 | u32 vrf_id = ~0; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2001 | int i, count; |
Matus Fabian | 724b815 | 2016-10-04 03:23:43 -0700 | [diff] [blame] | 2002 | int is_add = 1; |
| 2003 | int rv = 0; |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2004 | clib_error_t *error = 0; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2005 | u8 twice_nat = 0; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2006 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2007 | /* Get a line of input. */ |
| 2008 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 2009 | return 0; |
| 2010 | |
Matus Fabian | 724b815 | 2016-10-04 03:23:43 -0700 | [diff] [blame] | 2011 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 2012 | { |
| 2013 | if (unformat (line_input, "%U - %U", |
| 2014 | unformat_ip4_address, &start_addr, |
| 2015 | unformat_ip4_address, &end_addr)) |
| 2016 | ; |
Juraj Sloboda | eab38d9 | 2017-03-06 19:55:21 -0800 | [diff] [blame] | 2017 | else if (unformat (line_input, "tenant-vrf %u", &vrf_id)) |
| 2018 | ; |
Matus Fabian | 724b815 | 2016-10-04 03:23:43 -0700 | [diff] [blame] | 2019 | else if (unformat (line_input, "%U", unformat_ip4_address, &start_addr)) |
| 2020 | end_addr = start_addr; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2021 | else if (unformat (line_input, "twice-nat")) |
| 2022 | twice_nat = 1; |
Matus Fabian | 724b815 | 2016-10-04 03:23:43 -0700 | [diff] [blame] | 2023 | else if (unformat (line_input, "del")) |
| 2024 | is_add = 0; |
| 2025 | else |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2026 | { |
| 2027 | error = clib_error_return (0, "unknown input '%U'", |
| 2028 | format_unformat_error, line_input); |
| 2029 | goto done; |
| 2030 | } |
Matus Fabian | 724b815 | 2016-10-04 03:23:43 -0700 | [diff] [blame] | 2031 | } |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2032 | |
| 2033 | if (sm->static_mapping_only) |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2034 | { |
| 2035 | error = clib_error_return (0, "static mapping only mode"); |
| 2036 | goto done; |
| 2037 | } |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2038 | |
| 2039 | start_host_order = clib_host_to_net_u32 (start_addr.as_u32); |
| 2040 | end_host_order = clib_host_to_net_u32 (end_addr.as_u32); |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2041 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2042 | if (end_host_order < start_host_order) |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2043 | { |
| 2044 | error = clib_error_return (0, "end address less than start address"); |
| 2045 | goto done; |
| 2046 | } |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2047 | |
| 2048 | count = (end_host_order - start_host_order) + 1; |
| 2049 | |
| 2050 | if (count > 1024) |
| 2051 | clib_warning ("%U - %U, %d addresses...", |
| 2052 | format_ip4_address, &start_addr, |
| 2053 | format_ip4_address, &end_addr, |
| 2054 | count); |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2055 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2056 | this_addr = start_addr; |
| 2057 | |
| 2058 | for (i = 0; i < count; i++) |
| 2059 | { |
Matus Fabian | 724b815 | 2016-10-04 03:23:43 -0700 | [diff] [blame] | 2060 | if (is_add) |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2061 | snat_add_address (sm, &this_addr, vrf_id, twice_nat); |
Matus Fabian | 724b815 | 2016-10-04 03:23:43 -0700 | [diff] [blame] | 2062 | else |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2063 | rv = snat_del_address (sm, this_addr, 0, twice_nat); |
Matus Fabian | 724b815 | 2016-10-04 03:23:43 -0700 | [diff] [blame] | 2064 | |
| 2065 | switch (rv) |
| 2066 | { |
| 2067 | case VNET_API_ERROR_NO_SUCH_ENTRY: |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2068 | error = clib_error_return (0, "S-NAT address not exist."); |
| 2069 | goto done; |
Matus Fabian | 724b815 | 2016-10-04 03:23:43 -0700 | [diff] [blame] | 2070 | case VNET_API_ERROR_UNSPECIFIED: |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2071 | error = clib_error_return (0, "S-NAT address used in static mapping."); |
| 2072 | goto done; |
Matus Fabian | 724b815 | 2016-10-04 03:23:43 -0700 | [diff] [blame] | 2073 | default: |
| 2074 | break; |
| 2075 | } |
| 2076 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2077 | increment_v4_address (&this_addr); |
| 2078 | } |
| 2079 | |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2080 | done: |
| 2081 | unformat_free (line_input); |
| 2082 | |
| 2083 | return error; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2084 | } |
| 2085 | |
| 2086 | VLIB_CLI_COMMAND (add_address_command, static) = { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2087 | .path = "nat44 add address", |
Hongjun Ni | 2bd3f8a | 2017-08-29 20:39:42 +0800 | [diff] [blame] | 2088 | .short_help = "nat44 add address <ip4-range-start> [- <ip4-range-end>] " |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2089 | "[tenant-vrf <vrf-id>] [twice-nat] [del]", |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2090 | .function = add_address_command_fn, |
| 2091 | }; |
| 2092 | |
| 2093 | static clib_error_t * |
| 2094 | snat_feature_command_fn (vlib_main_t * vm, |
| 2095 | unformat_input_t * input, |
| 2096 | vlib_cli_command_t * cmd) |
| 2097 | { |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2098 | unformat_input_t _line_input, *line_input = &_line_input; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2099 | vnet_main_t * vnm = vnet_get_main(); |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2100 | clib_error_t * error = 0; |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 2101 | u32 sw_if_index; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2102 | u32 * inside_sw_if_indices = 0; |
| 2103 | u32 * outside_sw_if_indices = 0; |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 2104 | u8 is_output_feature = 0; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2105 | int is_del = 0; |
| 2106 | int i; |
| 2107 | |
| 2108 | sw_if_index = ~0; |
| 2109 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2110 | /* Get a line of input. */ |
| 2111 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 2112 | return 0; |
| 2113 | |
| 2114 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2115 | { |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2116 | if (unformat (line_input, "in %U", unformat_vnet_sw_interface, |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2117 | vnm, &sw_if_index)) |
| 2118 | vec_add1 (inside_sw_if_indices, sw_if_index); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2119 | else if (unformat (line_input, "out %U", unformat_vnet_sw_interface, |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2120 | vnm, &sw_if_index)) |
| 2121 | vec_add1 (outside_sw_if_indices, sw_if_index); |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 2122 | else if (unformat (line_input, "output-feature")) |
| 2123 | is_output_feature = 1; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2124 | else if (unformat (line_input, "del")) |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2125 | is_del = 1; |
| 2126 | else |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2127 | { |
| 2128 | error = clib_error_return (0, "unknown input '%U'", |
| 2129 | format_unformat_error, line_input); |
| 2130 | goto done; |
| 2131 | } |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2132 | } |
| 2133 | |
| 2134 | if (vec_len (inside_sw_if_indices)) |
| 2135 | { |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2136 | for (i = 0; i < vec_len(inside_sw_if_indices); i++) |
| 2137 | { |
| 2138 | sw_if_index = inside_sw_if_indices[i]; |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 2139 | if (is_output_feature) |
| 2140 | { |
| 2141 | if (snat_interface_add_del_output_feature (sw_if_index, 1, is_del)) |
| 2142 | { |
| 2143 | error = clib_error_return (0, "%s %U failed", |
| 2144 | is_del ? "del" : "add", |
| 2145 | format_vnet_sw_interface_name, vnm, |
| 2146 | vnet_get_sw_interface (vnm, |
| 2147 | sw_if_index)); |
| 2148 | goto done; |
| 2149 | } |
| 2150 | } |
| 2151 | else |
| 2152 | { |
| 2153 | if (snat_interface_add_del (sw_if_index, 1, is_del)) |
| 2154 | { |
| 2155 | error = clib_error_return (0, "%s %U failed", |
| 2156 | is_del ? "del" : "add", |
| 2157 | format_vnet_sw_interface_name, vnm, |
| 2158 | vnet_get_sw_interface (vnm, |
| 2159 | sw_if_index)); |
| 2160 | goto done; |
| 2161 | } |
| 2162 | } |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2163 | } |
| 2164 | } |
| 2165 | |
| 2166 | if (vec_len (outside_sw_if_indices)) |
| 2167 | { |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2168 | for (i = 0; i < vec_len(outside_sw_if_indices); i++) |
| 2169 | { |
| 2170 | sw_if_index = outside_sw_if_indices[i]; |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 2171 | if (is_output_feature) |
| 2172 | { |
| 2173 | if (snat_interface_add_del_output_feature (sw_if_index, 0, is_del)) |
| 2174 | { |
| 2175 | error = clib_error_return (0, "%s %U failed", |
| 2176 | is_del ? "del" : "add", |
| 2177 | format_vnet_sw_interface_name, vnm, |
| 2178 | vnet_get_sw_interface (vnm, |
| 2179 | sw_if_index)); |
| 2180 | goto done; |
| 2181 | } |
| 2182 | } |
| 2183 | else |
| 2184 | { |
| 2185 | if (snat_interface_add_del (sw_if_index, 0, is_del)) |
| 2186 | { |
| 2187 | error = clib_error_return (0, "%s %U failed", |
| 2188 | is_del ? "del" : "add", |
| 2189 | format_vnet_sw_interface_name, vnm, |
| 2190 | vnet_get_sw_interface (vnm, |
| 2191 | sw_if_index)); |
| 2192 | goto done; |
| 2193 | } |
| 2194 | } |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2195 | } |
| 2196 | } |
| 2197 | |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2198 | done: |
| 2199 | unformat_free (line_input); |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2200 | vec_free (inside_sw_if_indices); |
| 2201 | vec_free (outside_sw_if_indices); |
| 2202 | |
| 2203 | return error; |
| 2204 | } |
| 2205 | |
| 2206 | VLIB_CLI_COMMAND (set_interface_snat_command, static) = { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2207 | .path = "set interface nat44", |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2208 | .function = snat_feature_command_fn, |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2209 | .short_help = "set interface nat44 in <intfc> out <intfc> [output-feature] " |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 2210 | "[del]", |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2211 | }; |
| 2212 | |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 2213 | uword |
| 2214 | unformat_snat_protocol (unformat_input_t * input, va_list * args) |
| 2215 | { |
| 2216 | u32 *r = va_arg (*args, u32 *); |
| 2217 | |
| 2218 | if (0); |
| 2219 | #define _(N, i, n, s) else if (unformat (input, s)) *r = SNAT_PROTOCOL_##N; |
| 2220 | foreach_snat_protocol |
| 2221 | #undef _ |
| 2222 | else |
| 2223 | return 0; |
| 2224 | return 1; |
| 2225 | } |
| 2226 | |
| 2227 | u8 * |
| 2228 | format_snat_protocol (u8 * s, va_list * args) |
| 2229 | { |
| 2230 | u32 i = va_arg (*args, u32); |
| 2231 | u8 *t = 0; |
| 2232 | |
| 2233 | switch (i) |
| 2234 | { |
| 2235 | #define _(N, j, n, str) case SNAT_PROTOCOL_##N: t = (u8 *) str; break; |
| 2236 | foreach_snat_protocol |
| 2237 | #undef _ |
| 2238 | default: |
| 2239 | s = format (s, "unknown"); |
Matus Fabian | f8cd581 | 2017-07-11 03:55:02 -0700 | [diff] [blame] | 2240 | return s; |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 2241 | } |
| 2242 | s = format (s, "%s", t); |
| 2243 | return s; |
| 2244 | } |
| 2245 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2246 | static clib_error_t * |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2247 | add_static_mapping_command_fn (vlib_main_t * vm, |
| 2248 | unformat_input_t * input, |
| 2249 | vlib_cli_command_t * cmd) |
| 2250 | { |
| 2251 | unformat_input_t _line_input, *line_input = &_line_input; |
| 2252 | clib_error_t * error = 0; |
| 2253 | ip4_address_t l_addr, e_addr; |
| 2254 | u32 l_port = 0, e_port = 0, vrf_id = ~0; |
| 2255 | int is_add = 1; |
| 2256 | int addr_only = 1; |
Dave Barach | 8b27537 | 2017-01-16 10:54:02 -0500 | [diff] [blame] | 2257 | u32 sw_if_index = ~0; |
| 2258 | vnet_main_t * vnm = vnet_get_main(); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2259 | int rv; |
Matus Fabian | ab7a805 | 2017-11-28 04:29:41 -0800 | [diff] [blame] | 2260 | snat_protocol_t proto = ~0; |
Matus Fabian | b449f48 | 2017-02-05 22:14:41 -0800 | [diff] [blame] | 2261 | u8 proto_set = 0; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2262 | u8 twice_nat = 0; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2263 | |
| 2264 | /* Get a line of input. */ |
| 2265 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 2266 | return 0; |
| 2267 | |
| 2268 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 2269 | { |
| 2270 | if (unformat (line_input, "local %U %u", unformat_ip4_address, &l_addr, |
| 2271 | &l_port)) |
| 2272 | addr_only = 0; |
| 2273 | else if (unformat (line_input, "local %U", unformat_ip4_address, &l_addr)) |
| 2274 | ; |
| 2275 | else if (unformat (line_input, "external %U %u", unformat_ip4_address, |
| 2276 | &e_addr, &e_port)) |
| 2277 | addr_only = 0; |
| 2278 | else if (unformat (line_input, "external %U", unformat_ip4_address, |
| 2279 | &e_addr)) |
| 2280 | ; |
Dave Barach | 8b27537 | 2017-01-16 10:54:02 -0500 | [diff] [blame] | 2281 | else if (unformat (line_input, "external %U %u", |
| 2282 | unformat_vnet_sw_interface, vnm, &sw_if_index, |
| 2283 | &e_port)) |
| 2284 | addr_only = 0; |
| 2285 | |
| 2286 | else if (unformat (line_input, "external %U", |
| 2287 | unformat_vnet_sw_interface, vnm, &sw_if_index)) |
| 2288 | ; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2289 | else if (unformat (line_input, "vrf %u", &vrf_id)) |
| 2290 | ; |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 2291 | else if (unformat (line_input, "%U", unformat_snat_protocol, &proto)) |
Matus Fabian | b449f48 | 2017-02-05 22:14:41 -0800 | [diff] [blame] | 2292 | proto_set = 1; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2293 | else if (unformat (line_input, "twice-nat")) |
| 2294 | twice_nat = 1; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2295 | else if (unformat (line_input, "del")) |
| 2296 | is_add = 0; |
| 2297 | else |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2298 | { |
| 2299 | error = clib_error_return (0, "unknown input: '%U'", |
| 2300 | format_unformat_error, line_input); |
| 2301 | goto done; |
| 2302 | } |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2303 | } |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2304 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2305 | if (twice_nat && addr_only) |
| 2306 | { |
| 2307 | error = clib_error_return (0, "twice NAT only for 1:1 NAPT"); |
| 2308 | goto done; |
| 2309 | } |
| 2310 | |
Matus Fabian | b449f48 | 2017-02-05 22:14:41 -0800 | [diff] [blame] | 2311 | if (!addr_only && !proto_set) |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2312 | { |
| 2313 | error = clib_error_return (0, "missing protocol"); |
| 2314 | goto done; |
| 2315 | } |
Matus Fabian | b449f48 | 2017-02-05 22:14:41 -0800 | [diff] [blame] | 2316 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2317 | rv = snat_add_static_mapping(l_addr, e_addr, (u16) l_port, (u16) e_port, |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2318 | vrf_id, addr_only, sw_if_index, proto, is_add, |
| 2319 | twice_nat); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2320 | |
| 2321 | switch (rv) |
| 2322 | { |
| 2323 | case VNET_API_ERROR_INVALID_VALUE: |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2324 | error = clib_error_return (0, "External port already in use."); |
| 2325 | goto done; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2326 | case VNET_API_ERROR_NO_SUCH_ENTRY: |
| 2327 | if (is_add) |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2328 | error = clib_error_return (0, "External addres must be allocated."); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2329 | else |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2330 | error = clib_error_return (0, "Mapping not exist."); |
| 2331 | goto done; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2332 | case VNET_API_ERROR_NO_SUCH_FIB: |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2333 | error = clib_error_return (0, "No such VRF id."); |
| 2334 | goto done; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2335 | case VNET_API_ERROR_VALUE_EXIST: |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2336 | error = clib_error_return (0, "Mapping already exist."); |
| 2337 | goto done; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2338 | default: |
| 2339 | break; |
| 2340 | } |
| 2341 | |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2342 | done: |
| 2343 | unformat_free (line_input); |
| 2344 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2345 | return error; |
| 2346 | } |
| 2347 | |
| 2348 | /*? |
| 2349 | * @cliexpar |
| 2350 | * @cliexstart{snat add static mapping} |
| 2351 | * Static mapping allows hosts on the external network to initiate connection |
| 2352 | * to to the local network host. |
| 2353 | * To create static mapping between local host address 10.0.0.3 port 6303 and |
Matus Fabian | b449f48 | 2017-02-05 22:14:41 -0800 | [diff] [blame] | 2354 | * external address 4.4.4.4 port 3606 for TCP protocol use: |
Hongjun Ni | 2bd3f8a | 2017-08-29 20:39:42 +0800 | [diff] [blame] | 2355 | * vpp# nat44 add static mapping tcp local 10.0.0.3 6303 external 4.4.4.4 3606 |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2356 | * If not runnig "static mapping only" NAT plugin mode use before: |
| 2357 | * vpp# nat44 add address 4.4.4.4 |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2358 | * To create static mapping between local and external address use: |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2359 | * vpp# nat44 add static mapping local 10.0.0.3 external 4.4.4.4 |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2360 | * @cliexend |
| 2361 | ?*/ |
| 2362 | VLIB_CLI_COMMAND (add_static_mapping_command, static) = { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2363 | .path = "nat44 add static mapping", |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2364 | .function = add_static_mapping_command_fn, |
| 2365 | .short_help = |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2366 | "nat44 add static mapping tcp|udp|icmp local <addr> [<port>] " |
| 2367 | "external <addr> [<port>] [vrf <table-id>] [twice-nat] [del]", |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2368 | }; |
| 2369 | |
| 2370 | static clib_error_t * |
Matus Fabian | ab7a805 | 2017-11-28 04:29:41 -0800 | [diff] [blame] | 2371 | add_identity_mapping_command_fn (vlib_main_t * vm, |
| 2372 | unformat_input_t * input, |
| 2373 | vlib_cli_command_t * cmd) |
| 2374 | { |
| 2375 | unformat_input_t _line_input, *line_input = &_line_input; |
| 2376 | clib_error_t * error = 0; |
| 2377 | ip4_address_t addr; |
| 2378 | u32 port = 0, vrf_id = ~0; |
| 2379 | int is_add = 1; |
| 2380 | int addr_only = 1; |
| 2381 | u32 sw_if_index = ~0; |
| 2382 | vnet_main_t * vnm = vnet_get_main(); |
| 2383 | int rv; |
| 2384 | snat_protocol_t proto; |
| 2385 | |
| 2386 | addr.as_u32 = 0; |
| 2387 | |
| 2388 | /* Get a line of input. */ |
| 2389 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 2390 | return 0; |
| 2391 | |
| 2392 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 2393 | { |
| 2394 | if (unformat (line_input, "%U", unformat_ip4_address, &addr)) |
| 2395 | ; |
| 2396 | else if (unformat (line_input, "external %U", |
| 2397 | unformat_vnet_sw_interface, vnm, &sw_if_index)) |
| 2398 | ; |
| 2399 | else if (unformat (line_input, "vrf %u", &vrf_id)) |
| 2400 | ; |
| 2401 | else if (unformat (line_input, "%U %u", unformat_snat_protocol, &proto, |
| 2402 | &port)) |
| 2403 | addr_only = 0; |
| 2404 | else if (unformat (line_input, "del")) |
| 2405 | is_add = 0; |
| 2406 | else |
| 2407 | { |
| 2408 | error = clib_error_return (0, "unknown input: '%U'", |
| 2409 | format_unformat_error, line_input); |
| 2410 | goto done; |
| 2411 | } |
| 2412 | } |
| 2413 | |
| 2414 | rv = snat_add_static_mapping(addr, addr, (u16) port, (u16) port, |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2415 | vrf_id, addr_only, sw_if_index, proto, is_add, |
| 2416 | 0); |
Matus Fabian | ab7a805 | 2017-11-28 04:29:41 -0800 | [diff] [blame] | 2417 | |
| 2418 | switch (rv) |
| 2419 | { |
| 2420 | case VNET_API_ERROR_INVALID_VALUE: |
| 2421 | error = clib_error_return (0, "External port already in use."); |
| 2422 | goto done; |
| 2423 | case VNET_API_ERROR_NO_SUCH_ENTRY: |
| 2424 | if (is_add) |
| 2425 | error = clib_error_return (0, "External addres must be allocated."); |
| 2426 | else |
| 2427 | error = clib_error_return (0, "Mapping not exist."); |
| 2428 | goto done; |
| 2429 | case VNET_API_ERROR_NO_SUCH_FIB: |
| 2430 | error = clib_error_return (0, "No such VRF id."); |
| 2431 | goto done; |
| 2432 | case VNET_API_ERROR_VALUE_EXIST: |
| 2433 | error = clib_error_return (0, "Mapping already exist."); |
| 2434 | goto done; |
| 2435 | default: |
| 2436 | break; |
| 2437 | } |
| 2438 | |
| 2439 | done: |
| 2440 | unformat_free (line_input); |
| 2441 | |
| 2442 | return error; |
| 2443 | } |
| 2444 | |
| 2445 | /*? |
| 2446 | * @cliexpar |
| 2447 | * @cliexstart{snat add identity mapping} |
| 2448 | * Identity mapping translate an IP address to itself. |
| 2449 | * To create identity mapping for address 10.0.0.3 port 6303 for TCP protocol |
| 2450 | * use: |
| 2451 | * vpp# nat44 add identity mapping 10.0.0.3 tcp 6303 |
| 2452 | * To create identity mapping for address 10.0.0.3 use: |
| 2453 | * vpp# nat44 add identity mapping 10.0.0.3 |
| 2454 | * To create identity mapping for DHCP addressed interface use: |
| 2455 | * vpp# nat44 add identity mapping GigabitEthernet0/a/0 tcp 3606 |
| 2456 | * @cliexend |
| 2457 | ?*/ |
| 2458 | VLIB_CLI_COMMAND (add_identity_mapping_command, static) = { |
| 2459 | .path = "nat44 add identity mapping", |
| 2460 | .function = add_identity_mapping_command_fn, |
| 2461 | .short_help = "nat44 add identity mapping <interface>|<ip4-addr> " |
| 2462 | "[<protocol> <port>] [vrf <table-id>] [del]", |
| 2463 | }; |
| 2464 | |
| 2465 | static clib_error_t * |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 2466 | add_lb_static_mapping_command_fn (vlib_main_t * vm, |
| 2467 | unformat_input_t * input, |
| 2468 | vlib_cli_command_t * cmd) |
| 2469 | { |
| 2470 | unformat_input_t _line_input, *line_input = &_line_input; |
| 2471 | clib_error_t * error = 0; |
| 2472 | ip4_address_t l_addr, e_addr; |
| 2473 | u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0; |
| 2474 | int is_add = 1; |
| 2475 | int rv; |
| 2476 | snat_protocol_t proto; |
| 2477 | u8 proto_set = 0; |
| 2478 | nat44_lb_addr_port_t *locals = 0, local; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2479 | u8 twice_nat = 0; |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 2480 | |
| 2481 | /* Get a line of input. */ |
| 2482 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 2483 | return 0; |
| 2484 | |
| 2485 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 2486 | { |
| 2487 | if (unformat (line_input, "local %U:%u probability %u", |
| 2488 | unformat_ip4_address, &l_addr, &l_port, &probability)) |
| 2489 | { |
| 2490 | memset (&local, 0, sizeof (local)); |
| 2491 | local.addr = l_addr; |
| 2492 | local.port = (u16) l_port; |
| 2493 | local.probability = (u8) probability; |
| 2494 | vec_add1 (locals, local); |
| 2495 | } |
| 2496 | else if (unformat (line_input, "external %U:%u", unformat_ip4_address, |
| 2497 | &e_addr, &e_port)) |
| 2498 | ; |
| 2499 | else if (unformat (line_input, "vrf %u", &vrf_id)) |
| 2500 | ; |
| 2501 | else if (unformat (line_input, "protocol %U", unformat_snat_protocol, |
| 2502 | &proto)) |
| 2503 | proto_set = 1; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2504 | else if (unformat (line_input, "twice-nat")) |
| 2505 | twice_nat = 1; |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 2506 | else if (unformat (line_input, "del")) |
| 2507 | is_add = 0; |
| 2508 | else |
| 2509 | { |
| 2510 | error = clib_error_return (0, "unknown input: '%U'", |
| 2511 | format_unformat_error, line_input); |
| 2512 | goto done; |
| 2513 | } |
| 2514 | } |
| 2515 | |
| 2516 | if (vec_len (locals) < 2) |
| 2517 | { |
| 2518 | error = clib_error_return (0, "at least two local must be set"); |
| 2519 | goto done; |
| 2520 | } |
| 2521 | |
| 2522 | if (!proto_set) |
| 2523 | { |
| 2524 | error = clib_error_return (0, "missing protocol"); |
| 2525 | goto done; |
| 2526 | } |
| 2527 | |
| 2528 | rv = nat44_add_del_lb_static_mapping (e_addr, (u16) e_port, proto, vrf_id, |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2529 | locals, is_add, twice_nat); |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 2530 | |
| 2531 | switch (rv) |
| 2532 | { |
| 2533 | case VNET_API_ERROR_INVALID_VALUE: |
| 2534 | error = clib_error_return (0, "External port already in use."); |
| 2535 | goto done; |
| 2536 | case VNET_API_ERROR_NO_SUCH_ENTRY: |
| 2537 | if (is_add) |
| 2538 | error = clib_error_return (0, "External addres must be allocated."); |
| 2539 | else |
| 2540 | error = clib_error_return (0, "Mapping not exist."); |
| 2541 | goto done; |
| 2542 | case VNET_API_ERROR_VALUE_EXIST: |
| 2543 | error = clib_error_return (0, "Mapping already exist."); |
| 2544 | goto done; |
| 2545 | default: |
| 2546 | break; |
| 2547 | } |
| 2548 | |
| 2549 | done: |
| 2550 | unformat_free (line_input); |
| 2551 | vec_free (locals); |
| 2552 | |
| 2553 | return error; |
| 2554 | } |
| 2555 | |
| 2556 | VLIB_CLI_COMMAND (add_lb_static_mapping_command, static) = { |
| 2557 | .path = "nat44 add load-balancing static mapping", |
| 2558 | .function = add_lb_static_mapping_command_fn, |
| 2559 | .short_help = |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2560 | "nat44 add load-balancing static mapping protocol tcp|udp " |
| 2561 | "external <addr>:<port> local <addr>:<port> probability <n> [twice-nat] " |
| 2562 | "[vrf <table-id>] [del]", |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 2563 | }; |
| 2564 | |
| 2565 | static clib_error_t * |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 2566 | set_workers_command_fn (vlib_main_t * vm, |
| 2567 | unformat_input_t * input, |
| 2568 | vlib_cli_command_t * cmd) |
| 2569 | { |
| 2570 | unformat_input_t _line_input, *line_input = &_line_input; |
| 2571 | uword *bitmap = 0; |
| 2572 | int rv = 0; |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2573 | clib_error_t *error = 0; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 2574 | |
| 2575 | /* Get a line of input. */ |
| 2576 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 2577 | return 0; |
| 2578 | |
| 2579 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 2580 | { |
| 2581 | if (unformat (line_input, "%U", unformat_bitmap_list, &bitmap)) |
| 2582 | ; |
| 2583 | else |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2584 | { |
| 2585 | error = clib_error_return (0, "unknown input '%U'", |
| 2586 | format_unformat_error, line_input); |
| 2587 | goto done; |
| 2588 | } |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 2589 | } |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 2590 | |
| 2591 | if (bitmap == 0) |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2592 | { |
| 2593 | error = clib_error_return (0, "List of workers must be specified."); |
| 2594 | goto done; |
| 2595 | } |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 2596 | |
| 2597 | rv = snat_set_workers(bitmap); |
| 2598 | |
| 2599 | clib_bitmap_free (bitmap); |
| 2600 | |
| 2601 | switch (rv) |
| 2602 | { |
| 2603 | case VNET_API_ERROR_INVALID_WORKER: |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2604 | error = clib_error_return (0, "Invalid worker(s)."); |
| 2605 | goto done; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 2606 | case VNET_API_ERROR_FEATURE_DISABLED: |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2607 | error = clib_error_return (0, |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 2608 | "Supported only if 2 or more workes available."); |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2609 | goto done; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 2610 | default: |
| 2611 | break; |
| 2612 | } |
| 2613 | |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2614 | done: |
| 2615 | unformat_free (line_input); |
| 2616 | |
| 2617 | return error; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 2618 | } |
| 2619 | |
| 2620 | /*? |
| 2621 | * @cliexpar |
| 2622 | * @cliexstart{set snat workers} |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2623 | * Set NAT workers if 2 or more workers available, use: |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 2624 | * vpp# set snat workers 0-2,5 |
| 2625 | * @cliexend |
| 2626 | ?*/ |
| 2627 | VLIB_CLI_COMMAND (set_workers_command, static) = { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2628 | .path = "set nat workers", |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 2629 | .function = set_workers_command_fn, |
| 2630 | .short_help = |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2631 | "set nat workers <workers-list>", |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 2632 | }; |
| 2633 | |
| 2634 | static clib_error_t * |
Matus Fabian | eea28d7 | 2017-01-13 04:15:54 -0800 | [diff] [blame] | 2635 | snat_ipfix_logging_enable_disable_command_fn (vlib_main_t * vm, |
| 2636 | unformat_input_t * input, |
| 2637 | vlib_cli_command_t * cmd) |
| 2638 | { |
| 2639 | unformat_input_t _line_input, *line_input = &_line_input; |
| 2640 | u32 domain_id = 0; |
| 2641 | u32 src_port = 0; |
| 2642 | u8 enable = 1; |
| 2643 | int rv = 0; |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2644 | clib_error_t *error = 0; |
Matus Fabian | eea28d7 | 2017-01-13 04:15:54 -0800 | [diff] [blame] | 2645 | |
| 2646 | /* Get a line of input. */ |
| 2647 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 2648 | return 0; |
| 2649 | |
| 2650 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 2651 | { |
| 2652 | if (unformat (line_input, "domain %d", &domain_id)) |
| 2653 | ; |
| 2654 | else if (unformat (line_input, "src-port %d", &src_port)) |
| 2655 | ; |
| 2656 | else if (unformat (line_input, "disable")) |
| 2657 | enable = 0; |
| 2658 | else |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2659 | { |
| 2660 | error = clib_error_return (0, "unknown input '%U'", |
| 2661 | format_unformat_error, line_input); |
| 2662 | goto done; |
| 2663 | } |
Matus Fabian | eea28d7 | 2017-01-13 04:15:54 -0800 | [diff] [blame] | 2664 | } |
Matus Fabian | eea28d7 | 2017-01-13 04:15:54 -0800 | [diff] [blame] | 2665 | |
| 2666 | rv = snat_ipfix_logging_enable_disable (enable, domain_id, (u16) src_port); |
| 2667 | |
| 2668 | if (rv) |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2669 | { |
| 2670 | error = clib_error_return (0, "ipfix logging enable failed"); |
| 2671 | goto done; |
| 2672 | } |
Matus Fabian | eea28d7 | 2017-01-13 04:15:54 -0800 | [diff] [blame] | 2673 | |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 2674 | done: |
| 2675 | unformat_free (line_input); |
| 2676 | |
| 2677 | return error; |
Matus Fabian | eea28d7 | 2017-01-13 04:15:54 -0800 | [diff] [blame] | 2678 | } |
| 2679 | |
| 2680 | /*? |
| 2681 | * @cliexpar |
| 2682 | * @cliexstart{snat ipfix logging} |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2683 | * To enable NAT IPFIX logging use: |
| 2684 | * vpp# nat ipfix logging |
Matus Fabian | eea28d7 | 2017-01-13 04:15:54 -0800 | [diff] [blame] | 2685 | * To set IPFIX exporter use: |
| 2686 | * vpp# set ipfix exporter collector 10.10.10.3 src 10.10.10.1 |
| 2687 | * @cliexend |
| 2688 | ?*/ |
| 2689 | VLIB_CLI_COMMAND (snat_ipfix_logging_enable_disable_command, static) = { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2690 | .path = "nat ipfix logging", |
Matus Fabian | eea28d7 | 2017-01-13 04:15:54 -0800 | [diff] [blame] | 2691 | .function = snat_ipfix_logging_enable_disable_command_fn, |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2692 | .short_help = "nat ipfix logging [domain <domain-id>] [src-port <port>] [disable]", |
Matus Fabian | eea28d7 | 2017-01-13 04:15:54 -0800 | [diff] [blame] | 2693 | }; |
| 2694 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2695 | static u32 |
| 2696 | snat_get_worker_in2out_cb (ip4_header_t * ip0, u32 rx_fib_index0) |
| 2697 | { |
| 2698 | snat_main_t *sm = &snat_main; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2699 | u32 next_worker_index = 0; |
Matus Fabian | 7865b5c | 2017-09-26 01:23:01 -0700 | [diff] [blame] | 2700 | u32 hash; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2701 | |
Matus Fabian | 7865b5c | 2017-09-26 01:23:01 -0700 | [diff] [blame] | 2702 | next_worker_index = sm->first_worker_index; |
| 2703 | hash = ip0->src_address.as_u32 + (ip0->src_address.as_u32 >> 8) + |
| 2704 | (ip0->src_address.as_u32 >> 16) + (ip0->src_address.as_u32 >>24); |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2705 | |
Matus Fabian | 7865b5c | 2017-09-26 01:23:01 -0700 | [diff] [blame] | 2706 | if (PREDICT_TRUE (is_pow2 (_vec_len (sm->workers)))) |
| 2707 | next_worker_index += sm->workers[hash & (_vec_len (sm->workers) - 1)]; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2708 | else |
Matus Fabian | 7865b5c | 2017-09-26 01:23:01 -0700 | [diff] [blame] | 2709 | next_worker_index += sm->workers[hash % _vec_len (sm->workers)]; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2710 | |
| 2711 | return next_worker_index; |
| 2712 | } |
| 2713 | |
| 2714 | static u32 |
| 2715 | snat_get_worker_out2in_cb (ip4_header_t * ip0, u32 rx_fib_index0) |
| 2716 | { |
| 2717 | snat_main_t *sm = &snat_main; |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 2718 | udp_header_t *udp; |
| 2719 | u16 port; |
| 2720 | snat_session_key_t m_key; |
| 2721 | clib_bihash_kv_8_8_t kv, value; |
| 2722 | snat_static_mapping_t *m; |
| 2723 | nat_ed_ses_key_t key; |
| 2724 | clib_bihash_kv_16_8_t s_kv, s_value; |
| 2725 | snat_main_per_thread_data_t *tsm; |
| 2726 | snat_session_t *s; |
| 2727 | int i; |
| 2728 | u32 proto; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2729 | |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 2730 | /* first try static mappings without port */ |
| 2731 | if (PREDICT_FALSE (pool_elts (sm->static_mappings))) |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2732 | { |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 2733 | m_key.addr = ip0->dst_address; |
| 2734 | m_key.port = 0; |
| 2735 | m_key.protocol = 0; |
| 2736 | m_key.fib_index = rx_fib_index0; |
| 2737 | kv.key = m_key.as_u64; |
| 2738 | if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) |
| 2739 | { |
| 2740 | m = pool_elt_at_index (sm->static_mappings, value.value); |
| 2741 | return m->worker_index; |
| 2742 | } |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2743 | } |
| 2744 | |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 2745 | proto = ip_proto_to_snat_proto (ip0->protocol); |
| 2746 | udp = ip4_next_header (ip0); |
| 2747 | port = udp->dst_port; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2748 | |
Matus Fabian | 51e759f | 2017-12-07 23:22:51 -0800 | [diff] [blame] | 2749 | if (PREDICT_FALSE (ip4_is_fragment (ip0))) |
| 2750 | { |
| 2751 | if (PREDICT_FALSE (nat_reass_is_drop_frag (0))) |
| 2752 | return vlib_get_thread_index (); |
| 2753 | |
| 2754 | if (PREDICT_TRUE (!ip4_is_first_fragment (ip0))) |
| 2755 | { |
| 2756 | nat_reass_ip4_t *reass; |
| 2757 | |
| 2758 | reass = nat_ip4_reass_find (ip0->src_address, ip0->dst_address, |
| 2759 | ip0->fragment_id, ip0->protocol); |
| 2760 | |
| 2761 | if (reass && (reass->thread_index != (u32) ~ 0)) |
| 2762 | return reass->thread_index; |
| 2763 | else |
| 2764 | return vlib_get_thread_index (); |
| 2765 | } |
| 2766 | } |
| 2767 | |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 2768 | /* unknown protocol */ |
| 2769 | if (PREDICT_FALSE (proto == ~0)) |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2770 | { |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 2771 | key.l_addr = ip0->dst_address; |
| 2772 | key.r_addr = ip0->src_address; |
| 2773 | key.fib_index = rx_fib_index0; |
| 2774 | key.proto = ip0->protocol; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 2775 | key.r_port = 0; |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 2776 | key.l_port = 0; |
| 2777 | s_kv.key[0] = key.as_u64[0]; |
| 2778 | s_kv.key[1] = key.as_u64[1]; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2779 | |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 2780 | if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value)) |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2781 | { |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 2782 | for (i = 0; i < _vec_len (sm->per_thread_data); i++) |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2783 | { |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 2784 | tsm = vec_elt_at_index (sm->per_thread_data, i); |
| 2785 | if (!pool_is_free_index(tsm->sessions, s_value.value)) |
| 2786 | { |
| 2787 | s = pool_elt_at_index (tsm->sessions, s_value.value); |
| 2788 | if (s->out2in.addr.as_u32 == ip0->dst_address.as_u32 && |
| 2789 | s->out2in.port == ip0->protocol && |
| 2790 | snat_is_unk_proto_session (s)) |
| 2791 | return i; |
| 2792 | } |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2793 | } |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 2794 | } |
| 2795 | |
| 2796 | /* if no session use current thread */ |
| 2797 | return vlib_get_thread_index (); |
| 2798 | } |
| 2799 | |
| 2800 | if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_ICMP)) |
| 2801 | { |
| 2802 | icmp46_header_t * icmp = (icmp46_header_t *) udp; |
| 2803 | icmp_echo_header_t *echo = (icmp_echo_header_t *)(icmp + 1); |
| 2804 | if (!icmp_is_error_message (icmp)) |
| 2805 | port = echo->identifier; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2806 | else |
| 2807 | { |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 2808 | ip4_header_t *inner_ip = (ip4_header_t *)(echo + 1); |
| 2809 | proto = ip_proto_to_snat_proto (inner_ip->protocol); |
| 2810 | void *l4_header = ip4_next_header (inner_ip); |
| 2811 | switch (proto) |
| 2812 | { |
| 2813 | case SNAT_PROTOCOL_ICMP: |
| 2814 | icmp = (icmp46_header_t*)l4_header; |
| 2815 | echo = (icmp_echo_header_t *)(icmp + 1); |
| 2816 | port = echo->identifier; |
| 2817 | break; |
| 2818 | case SNAT_PROTOCOL_UDP: |
| 2819 | case SNAT_PROTOCOL_TCP: |
| 2820 | port = ((tcp_udp_header_t*)l4_header)->src_port; |
| 2821 | break; |
| 2822 | default: |
| 2823 | return vlib_get_thread_index (); |
| 2824 | } |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2825 | } |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2826 | } |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2827 | |
Matus Fabian | ed3c160 | 2017-09-21 05:07:12 -0700 | [diff] [blame] | 2828 | /* try static mappings with port */ |
| 2829 | if (PREDICT_FALSE (pool_elts (sm->static_mappings))) |
| 2830 | { |
| 2831 | m_key.addr = ip0->dst_address; |
| 2832 | m_key.port = clib_net_to_host_u16 (port); |
| 2833 | m_key.protocol = proto; |
| 2834 | m_key.fib_index = rx_fib_index0; |
| 2835 | kv.key = m_key.as_u64; |
| 2836 | if (!clib_bihash_search_8_8 (&sm->static_mapping_by_external, &kv, &value)) |
| 2837 | { |
| 2838 | m = pool_elt_at_index (sm->static_mappings, value.value); |
| 2839 | return m->worker_index; |
| 2840 | } |
| 2841 | } |
| 2842 | |
| 2843 | /* worker by outside port */ |
| 2844 | return (u32) ((clib_net_to_host_u16 (port) - 1024) / sm->port_per_thread); |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2845 | } |
| 2846 | |
Matus Fabian | eea28d7 | 2017-01-13 04:15:54 -0800 | [diff] [blame] | 2847 | static clib_error_t * |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2848 | snat_config (vlib_main_t * vm, unformat_input_t * input) |
| 2849 | { |
| 2850 | snat_main_t * sm = &snat_main; |
| 2851 | u32 translation_buckets = 1024; |
| 2852 | u32 translation_memory_size = 128<<20; |
| 2853 | u32 user_buckets = 128; |
| 2854 | u32 user_memory_size = 64<<20; |
| 2855 | u32 max_translations_per_user = 100; |
| 2856 | u32 outside_vrf_id = 0; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2857 | u32 inside_vrf_id = 0; |
| 2858 | u32 static_mapping_buckets = 1024; |
| 2859 | u32 static_mapping_memory_size = 64<<20; |
Matus Fabian | 51e759f | 2017-12-07 23:22:51 -0800 | [diff] [blame] | 2860 | u32 nat64_bib_buckets = 1024; |
| 2861 | u32 nat64_bib_memory_size = 128 << 20; |
| 2862 | u32 nat64_st_buckets = 2048; |
| 2863 | u32 nat64_st_memory_size = 256 << 20; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2864 | u8 static_mapping_only = 0; |
| 2865 | u8 static_mapping_connection_tracking = 0; |
Matus Fabian | 092b3cd | 2017-09-19 05:42:38 -0700 | [diff] [blame] | 2866 | snat_main_per_thread_data_t *tsm; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2867 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2868 | sm->deterministic = 0; |
| 2869 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2870 | while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) |
| 2871 | { |
| 2872 | if (unformat (input, "translation hash buckets %d", &translation_buckets)) |
| 2873 | ; |
| 2874 | else if (unformat (input, "translation hash memory %d", |
| 2875 | &translation_memory_size)); |
| 2876 | else if (unformat (input, "user hash buckets %d", &user_buckets)) |
| 2877 | ; |
| 2878 | else if (unformat (input, "user hash memory %d", |
| 2879 | &user_memory_size)) |
| 2880 | ; |
| 2881 | else if (unformat (input, "max translations per user %d", |
| 2882 | &max_translations_per_user)) |
| 2883 | ; |
| 2884 | else if (unformat (input, "outside VRF id %d", |
| 2885 | &outside_vrf_id)) |
| 2886 | ; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2887 | else if (unformat (input, "inside VRF id %d", |
| 2888 | &inside_vrf_id)) |
| 2889 | ; |
| 2890 | else if (unformat (input, "static mapping only")) |
| 2891 | { |
| 2892 | static_mapping_only = 1; |
| 2893 | if (unformat (input, "connection tracking")) |
| 2894 | static_mapping_connection_tracking = 1; |
| 2895 | } |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2896 | else if (unformat (input, "deterministic")) |
| 2897 | sm->deterministic = 1; |
Matus Fabian | 51e759f | 2017-12-07 23:22:51 -0800 | [diff] [blame] | 2898 | else if (unformat (input, "nat64 bib hash buckets %d", |
| 2899 | &nat64_bib_buckets)) |
| 2900 | ; |
| 2901 | else if (unformat (input, "nat64 bib hash memory %d", |
| 2902 | &nat64_bib_memory_size)) |
| 2903 | ; |
| 2904 | else if (unformat (input, "nat64 st hash buckets %d", &nat64_st_buckets)) |
| 2905 | ; |
| 2906 | else if (unformat (input, "nat64 st hash memory %d", |
| 2907 | &nat64_st_memory_size)) |
| 2908 | ; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2909 | else |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2910 | return clib_error_return (0, "unknown input '%U'", |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2911 | format_unformat_error, input); |
| 2912 | } |
| 2913 | |
| 2914 | /* for show commands, etc. */ |
| 2915 | sm->translation_buckets = translation_buckets; |
| 2916 | sm->translation_memory_size = translation_memory_size; |
Matus Fabian | 41fef50 | 2017-09-22 02:43:05 -0700 | [diff] [blame] | 2917 | /* do not exceed load factor 10 */ |
| 2918 | sm->max_translations = 10 * translation_buckets; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2919 | sm->user_buckets = user_buckets; |
| 2920 | sm->user_memory_size = user_memory_size; |
| 2921 | sm->max_translations_per_user = max_translations_per_user; |
| 2922 | sm->outside_vrf_id = outside_vrf_id; |
Matus Fabian | 31c31aa | 2017-02-05 22:45:57 -0800 | [diff] [blame] | 2923 | sm->outside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, |
Neale Ranns | 1500254 | 2017-09-10 04:39:11 -0700 | [diff] [blame] | 2924 | outside_vrf_id, |
| 2925 | FIB_SOURCE_PLUGIN_HI); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2926 | sm->inside_vrf_id = inside_vrf_id; |
Matus Fabian | 31c31aa | 2017-02-05 22:45:57 -0800 | [diff] [blame] | 2927 | sm->inside_fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, |
Neale Ranns | 1500254 | 2017-09-10 04:39:11 -0700 | [diff] [blame] | 2928 | inside_vrf_id, |
| 2929 | FIB_SOURCE_PLUGIN_HI); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2930 | sm->static_mapping_only = static_mapping_only; |
| 2931 | sm->static_mapping_connection_tracking = static_mapping_connection_tracking; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2932 | |
Matus Fabian | 51e759f | 2017-12-07 23:22:51 -0800 | [diff] [blame] | 2933 | nat64_set_hash(nat64_bib_buckets, nat64_bib_memory_size, nat64_st_buckets, |
| 2934 | nat64_st_memory_size); |
| 2935 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2936 | if (sm->deterministic) |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2937 | { |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2938 | sm->in2out_node_index = snat_det_in2out_node.index; |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 2939 | sm->in2out_output_node_index = ~0; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2940 | sm->out2in_node_index = snat_det_out2in_node.index; |
Juraj Sloboda | 7a1bde0 | 2017-04-03 08:43:58 +0200 | [diff] [blame] | 2941 | sm->icmp_match_in2out_cb = icmp_match_in2out_det; |
| 2942 | sm->icmp_match_out2in_cb = icmp_match_out2in_det; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 2943 | } |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2944 | else |
| 2945 | { |
| 2946 | sm->worker_in2out_cb = snat_get_worker_in2out_cb; |
| 2947 | sm->worker_out2in_cb = snat_get_worker_out2in_cb; |
| 2948 | sm->in2out_node_index = snat_in2out_node.index; |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 2949 | sm->in2out_output_node_index = snat_in2out_output_node.index; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2950 | sm->out2in_node_index = snat_out2in_node.index; |
| 2951 | if (!static_mapping_only || |
| 2952 | (static_mapping_only && static_mapping_connection_tracking)) |
| 2953 | { |
Juraj Sloboda | 557a71c | 2017-02-22 05:16:06 -0800 | [diff] [blame] | 2954 | sm->icmp_match_in2out_cb = icmp_match_in2out_slow; |
| 2955 | sm->icmp_match_out2in_cb = icmp_match_out2in_slow; |
| 2956 | |
Matus Fabian | 092b3cd | 2017-09-19 05:42:38 -0700 | [diff] [blame] | 2957 | vec_foreach (tsm, sm->per_thread_data) |
| 2958 | { |
| 2959 | clib_bihash_init_8_8 (&tsm->in2out, "in2out", translation_buckets, |
| 2960 | translation_memory_size); |
| 2961 | |
| 2962 | clib_bihash_init_8_8 (&tsm->out2in, "out2in", translation_buckets, |
| 2963 | translation_memory_size); |
| 2964 | |
| 2965 | clib_bihash_init_8_8 (&tsm->user_hash, "users", user_buckets, |
| 2966 | user_memory_size); |
| 2967 | } |
| 2968 | |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 2969 | clib_bihash_init_16_8 (&sm->in2out_ed, "in2out-ed", |
Matus Fabian | 7968e6c | 2017-07-06 05:37:49 -0700 | [diff] [blame] | 2970 | translation_buckets, translation_memory_size); |
| 2971 | |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 2972 | clib_bihash_init_16_8 (&sm->out2in_ed, "out2in-ed", |
Matus Fabian | 7968e6c | 2017-07-06 05:37:49 -0700 | [diff] [blame] | 2973 | translation_buckets, translation_memory_size); |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2974 | } |
Juraj Sloboda | 557a71c | 2017-02-22 05:16:06 -0800 | [diff] [blame] | 2975 | else |
| 2976 | { |
| 2977 | sm->icmp_match_in2out_cb = icmp_match_in2out_fast; |
| 2978 | sm->icmp_match_out2in_cb = icmp_match_out2in_fast; |
| 2979 | } |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2980 | clib_bihash_init_8_8 (&sm->static_mapping_by_local, |
| 2981 | "static_mapping_by_local", static_mapping_buckets, |
| 2982 | static_mapping_memory_size); |
| 2983 | |
| 2984 | clib_bihash_init_8_8 (&sm->static_mapping_by_external, |
| 2985 | "static_mapping_by_external", static_mapping_buckets, |
| 2986 | static_mapping_memory_size); |
| 2987 | } |
| 2988 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2989 | return 0; |
| 2990 | } |
| 2991 | |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 2992 | VLIB_CONFIG_FUNCTION (snat_config, "nat"); |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 2993 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 2994 | u8 * format_snat_session_state (u8 * s, va_list * args) |
| 2995 | { |
| 2996 | u32 i = va_arg (*args, u32); |
| 2997 | u8 *t = 0; |
| 2998 | |
| 2999 | switch (i) |
| 3000 | { |
| 3001 | #define _(v, N, str) case SNAT_SESSION_##N: t = (u8 *) str; break; |
| 3002 | foreach_snat_session_state |
| 3003 | #undef _ |
| 3004 | default: |
| 3005 | t = format (t, "unknown"); |
| 3006 | } |
| 3007 | s = format (s, "%s", t); |
| 3008 | return s; |
| 3009 | } |
| 3010 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3011 | u8 * format_snat_key (u8 * s, va_list * args) |
| 3012 | { |
| 3013 | snat_session_key_t * key = va_arg (*args, snat_session_key_t *); |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3014 | |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 3015 | s = format (s, "%U proto %U port %d fib %d", |
| 3016 | format_ip4_address, &key->addr, |
| 3017 | format_snat_protocol, key->protocol, |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3018 | clib_net_to_host_u16 (key->port), key->fib_index); |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3019 | return s; |
| 3020 | } |
| 3021 | |
| 3022 | u8 * format_snat_session (u8 * s, va_list * args) |
| 3023 | { |
| 3024 | snat_main_t * sm __attribute__((unused)) = va_arg (*args, snat_main_t *); |
| 3025 | snat_session_t * sess = va_arg (*args, snat_session_t *); |
| 3026 | |
Matus Fabian | 7968e6c | 2017-07-06 05:37:49 -0700 | [diff] [blame] | 3027 | if (snat_is_unk_proto_session (sess)) |
| 3028 | { |
| 3029 | s = format (s, " i2o %U proto %u fib %u\n", |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3030 | format_ip4_address, &sess->in2out.addr, |
| 3031 | clib_net_to_host_u16 (sess->in2out.port), |
Matus Fabian | 7968e6c | 2017-07-06 05:37:49 -0700 | [diff] [blame] | 3032 | sess->in2out.fib_index); |
| 3033 | s = format (s, " o2i %U proto %u fib %u\n", |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3034 | format_ip4_address, &sess->out2in.addr, |
| 3035 | clib_net_to_host_u16 (sess->out2in.port), |
Matus Fabian | 7968e6c | 2017-07-06 05:37:49 -0700 | [diff] [blame] | 3036 | sess->out2in.fib_index); |
| 3037 | } |
| 3038 | else |
| 3039 | { |
| 3040 | s = format (s, " i2o %U\n", format_snat_key, &sess->in2out); |
| 3041 | s = format (s, " o2i %U\n", format_snat_key, &sess->out2in); |
| 3042 | } |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3043 | if (is_twice_nat_session (sess)) |
| 3044 | { |
| 3045 | s = format (s, " external host o2i %U:%d i2o %U:%d\n", |
| 3046 | format_ip4_address, &sess->ext_host_addr, |
| 3047 | clib_net_to_host_u16 (sess->ext_host_port), |
| 3048 | format_ip4_address, &sess->ext_host_nat_addr, |
| 3049 | clib_net_to_host_u16 (sess->ext_host_nat_port)); |
| 3050 | } |
| 3051 | else |
| 3052 | { |
| 3053 | if (sess->ext_host_addr.as_u32) |
| 3054 | s = format (s, " external host %U\n", |
| 3055 | format_ip4_address, &sess->ext_host_addr); |
| 3056 | } |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3057 | s = format (s, " last heard %.2f\n", sess->last_heard); |
| 3058 | s = format (s, " total pkts %d, total bytes %lld\n", |
| 3059 | sess->total_pkts, sess->total_bytes); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3060 | if (snat_is_session_static (sess)) |
| 3061 | s = format (s, " static translation\n"); |
| 3062 | else |
| 3063 | s = format (s, " dynamic translation\n"); |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 3064 | if (sess->flags & SNAT_SESSION_FLAG_LOAD_BALANCING) |
| 3065 | s = format (s, " load-balancing\n"); |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3066 | if (is_twice_nat_session (sess)) |
| 3067 | s = format (s, " twice-nat\n"); |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3068 | |
| 3069 | return s; |
| 3070 | } |
| 3071 | |
| 3072 | u8 * format_snat_user (u8 * s, va_list * args) |
| 3073 | { |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 3074 | snat_main_per_thread_data_t * sm = va_arg (*args, snat_main_per_thread_data_t *); |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3075 | snat_user_t * u = va_arg (*args, snat_user_t *); |
| 3076 | int verbose = va_arg (*args, int); |
| 3077 | dlist_elt_t * head, * elt; |
| 3078 | u32 elt_index, head_index; |
| 3079 | u32 session_index; |
| 3080 | snat_session_t * sess; |
| 3081 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3082 | s = format (s, "%U: %d dynamic translations, %d static translations\n", |
| 3083 | format_ip4_address, &u->addr, u->nsessions, u->nstaticsessions); |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3084 | |
| 3085 | if (verbose == 0) |
| 3086 | return s; |
| 3087 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3088 | if (u->nsessions || u->nstaticsessions) |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3089 | { |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3090 | head_index = u->sessions_per_user_list_head_index; |
| 3091 | head = pool_elt_at_index (sm->list_pool, head_index); |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3092 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3093 | elt_index = head->next; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3094 | elt = pool_elt_at_index (sm->list_pool, elt_index); |
| 3095 | session_index = elt->value; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3096 | |
| 3097 | while (session_index != ~0) |
| 3098 | { |
| 3099 | sess = pool_elt_at_index (sm->sessions, session_index); |
| 3100 | |
| 3101 | s = format (s, " %U\n", format_snat_session, sm, sess); |
| 3102 | |
| 3103 | elt_index = elt->next; |
| 3104 | elt = pool_elt_at_index (sm->list_pool, elt_index); |
| 3105 | session_index = elt->value; |
| 3106 | } |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3107 | } |
| 3108 | |
| 3109 | return s; |
| 3110 | } |
| 3111 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3112 | u8 * format_snat_static_mapping (u8 * s, va_list * args) |
| 3113 | { |
| 3114 | snat_static_mapping_t *m = va_arg (*args, snat_static_mapping_t *); |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 3115 | nat44_lb_addr_port_t *local; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3116 | |
| 3117 | if (m->addr_only) |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3118 | s = format (s, "local %U external %U vrf %d %s", |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3119 | format_ip4_address, &m->local_addr, |
| 3120 | format_ip4_address, &m->external_addr, |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3121 | m->vrf_id, m->twice_nat ? "twice-nat" : ""); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3122 | else |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 3123 | { |
| 3124 | if (vec_len (m->locals)) |
| 3125 | { |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3126 | s = format (s, "%U vrf %d external %U:%d %s", |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 3127 | format_snat_protocol, m->proto, |
| 3128 | m->vrf_id, |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3129 | format_ip4_address, &m->external_addr, m->external_port, |
| 3130 | m->twice_nat ? "twice-nat" : ""); |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 3131 | vec_foreach (local, m->locals) |
| 3132 | s = format (s, "\n local %U:%d probability %d\%", |
| 3133 | format_ip4_address, &local->addr, local->port, |
| 3134 | local->probability); |
| 3135 | } |
| 3136 | else |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3137 | s = format (s, "%U local %U:%d external %U:%d vrf %d %s", |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 3138 | format_snat_protocol, m->proto, |
| 3139 | format_ip4_address, &m->local_addr, m->local_port, |
| 3140 | format_ip4_address, &m->external_addr, m->external_port, |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3141 | m->vrf_id, m->twice_nat ? "twice-nat" : ""); |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 3142 | } |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3143 | return s; |
| 3144 | } |
| 3145 | |
Matus Fabian | e22e546 | 2017-02-14 23:33:43 -0800 | [diff] [blame] | 3146 | u8 * format_snat_static_map_to_resolve (u8 * s, va_list * args) |
| 3147 | { |
| 3148 | snat_static_map_resolve_t *m = va_arg (*args, snat_static_map_resolve_t *); |
| 3149 | vnet_main_t *vnm = vnet_get_main(); |
| 3150 | |
| 3151 | if (m->addr_only) |
| 3152 | s = format (s, "local %U external %U vrf %d", |
| 3153 | format_ip4_address, &m->l_addr, |
| 3154 | format_vnet_sw_interface_name, vnm, |
| 3155 | vnet_get_sw_interface (vnm, m->sw_if_index), |
| 3156 | m->vrf_id); |
| 3157 | else |
| 3158 | s = format (s, "%U local %U:%d external %U:%d vrf %d", |
| 3159 | format_snat_protocol, m->proto, |
| 3160 | format_ip4_address, &m->l_addr, m->l_port, |
| 3161 | format_vnet_sw_interface_name, vnm, |
| 3162 | vnet_get_sw_interface (vnm, m->sw_if_index), m->e_port, |
| 3163 | m->vrf_id); |
| 3164 | |
| 3165 | return s; |
| 3166 | } |
| 3167 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3168 | u8 * format_det_map_ses (u8 * s, va_list * args) |
| 3169 | { |
| 3170 | snat_det_map_t * det_map = va_arg (*args, snat_det_map_t *); |
| 3171 | ip4_address_t in_addr, out_addr; |
| 3172 | u32 in_offset, out_offset; |
| 3173 | snat_det_session_t * ses = va_arg (*args, snat_det_session_t *); |
| 3174 | u32 * i = va_arg (*args, u32 *); |
| 3175 | |
| 3176 | u32 user_index = *i / SNAT_DET_SES_PER_USER; |
| 3177 | in_addr.as_u32 = clib_host_to_net_u32 ( |
| 3178 | clib_net_to_host_u32(det_map->in_addr.as_u32) + user_index); |
| 3179 | in_offset = clib_net_to_host_u32(in_addr.as_u32) - |
| 3180 | clib_net_to_host_u32(det_map->in_addr.as_u32); |
| 3181 | out_offset = in_offset / det_map->sharing_ratio; |
| 3182 | out_addr.as_u32 = clib_host_to_net_u32( |
| 3183 | clib_net_to_host_u32(det_map->out_addr.as_u32) + out_offset); |
| 3184 | s = format (s, "in %U:%d out %U:%d external host %U:%d state: %U expire: %d\n", |
| 3185 | format_ip4_address, &in_addr, |
| 3186 | clib_net_to_host_u16 (ses->in_port), |
| 3187 | format_ip4_address, &out_addr, |
| 3188 | clib_net_to_host_u16 (ses->out.out_port), |
| 3189 | format_ip4_address, &ses->out.ext_host_addr, |
| 3190 | clib_net_to_host_u16 (ses->out.ext_host_port), |
| 3191 | format_snat_session_state, ses->state, |
| 3192 | ses->expire); |
| 3193 | |
| 3194 | return s; |
| 3195 | } |
| 3196 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3197 | static clib_error_t * |
| 3198 | show_snat_command_fn (vlib_main_t * vm, |
| 3199 | unformat_input_t * input, |
| 3200 | vlib_cli_command_t * cmd) |
| 3201 | { |
| 3202 | int verbose = 0; |
| 3203 | snat_main_t * sm = &snat_main; |
| 3204 | snat_user_t * u; |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3205 | snat_static_mapping_t *m; |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 3206 | snat_interface_t *i; |
Matus Fabian | 07ea761 | 2016-12-15 05:30:37 -0800 | [diff] [blame] | 3207 | snat_address_t * ap; |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 3208 | vnet_main_t *vnm = vnet_get_main(); |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 3209 | snat_main_per_thread_data_t *tsm; |
Matus Fabian | 8bf68e8 | 2017-01-12 04:24:35 -0800 | [diff] [blame] | 3210 | u32 users_num = 0, sessions_num = 0, *worker, *sw_if_index; |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 3211 | uword j = 0; |
Matus Fabian | e22e546 | 2017-02-14 23:33:43 -0800 | [diff] [blame] | 3212 | snat_static_map_resolve_t *rp; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3213 | snat_det_map_t * dm; |
| 3214 | snat_det_session_t * ses; |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3215 | |
| 3216 | if (unformat (input, "detail")) |
| 3217 | verbose = 1; |
| 3218 | else if (unformat (input, "verbose")) |
| 3219 | verbose = 2; |
| 3220 | |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3221 | if (sm->static_mapping_only) |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3222 | { |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3223 | if (sm->static_mapping_connection_tracking) |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 3224 | vlib_cli_output (vm, "NAT plugin mode: static mapping only connection " |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3225 | "tracking"); |
| 3226 | else |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 3227 | vlib_cli_output (vm, "NAT plugin mode: static mapping only"); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3228 | } |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3229 | else if (sm->deterministic) |
| 3230 | { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 3231 | vlib_cli_output (vm, "NAT plugin mode: deterministic mapping"); |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3232 | } |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3233 | else |
| 3234 | { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 3235 | vlib_cli_output (vm, "NAT plugin mode: dynamic translations enabled"); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3236 | } |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3237 | |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 3238 | if (verbose > 0) |
| 3239 | { |
| 3240 | pool_foreach (i, sm->interfaces, |
| 3241 | ({ |
| 3242 | vlib_cli_output (vm, "%U %s", format_vnet_sw_interface_name, vnm, |
| 3243 | vnet_get_sw_interface (vnm, i->sw_if_index), |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 3244 | (nat_interface_is_inside(i) && |
| 3245 | nat_interface_is_outside(i)) ? "in out" : |
| 3246 | (nat_interface_is_inside(i) ? "in" : "out")); |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 3247 | })); |
Matus Fabian | 07ea761 | 2016-12-15 05:30:37 -0800 | [diff] [blame] | 3248 | |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 3249 | pool_foreach (i, sm->output_feature_interfaces, |
| 3250 | ({ |
| 3251 | vlib_cli_output (vm, "%U output-feature %s", |
| 3252 | format_vnet_sw_interface_name, vnm, |
| 3253 | vnet_get_sw_interface (vnm, i->sw_if_index), |
Matus Fabian | 36ea2d6 | 2017-10-24 04:13:49 -0700 | [diff] [blame] | 3254 | (nat_interface_is_inside(i) && |
| 3255 | nat_interface_is_outside(i)) ? "in out" : |
| 3256 | (nat_interface_is_inside(i) ? "in" : "out")); |
Matus Fabian | 93d84c9 | 2017-07-19 08:06:01 -0700 | [diff] [blame] | 3257 | })); |
| 3258 | |
Matus Fabian | 8bf68e8 | 2017-01-12 04:24:35 -0800 | [diff] [blame] | 3259 | if (vec_len (sm->auto_add_sw_if_indices)) |
| 3260 | { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 3261 | vlib_cli_output (vm, "NAT44 pool addresses interfaces:"); |
Matus Fabian | 8bf68e8 | 2017-01-12 04:24:35 -0800 | [diff] [blame] | 3262 | vec_foreach (sw_if_index, sm->auto_add_sw_if_indices) |
| 3263 | { |
| 3264 | vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm, |
| 3265 | vnet_get_sw_interface (vnm, *sw_if_index)); |
| 3266 | } |
| 3267 | } |
| 3268 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3269 | if (vec_len (sm->auto_add_sw_if_indices_twice_nat)) |
| 3270 | { |
| 3271 | vlib_cli_output (vm, "NAT44 twice-nat pool addresses interfaces:"); |
| 3272 | vec_foreach (sw_if_index, sm->auto_add_sw_if_indices_twice_nat) |
| 3273 | { |
| 3274 | vlib_cli_output (vm, "%U", format_vnet_sw_interface_name, vnm, |
| 3275 | vnet_get_sw_interface (vnm, *sw_if_index)); |
| 3276 | } |
| 3277 | } |
| 3278 | |
| 3279 | vlib_cli_output (vm, "NAT44 pool addresses:"); |
Matus Fabian | 07ea761 | 2016-12-15 05:30:37 -0800 | [diff] [blame] | 3280 | vec_foreach (ap, sm->addresses) |
| 3281 | { |
Matus Fabian | 07ea761 | 2016-12-15 05:30:37 -0800 | [diff] [blame] | 3282 | vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr); |
Juraj Sloboda | eab38d9 | 2017-03-06 19:55:21 -0800 | [diff] [blame] | 3283 | if (ap->fib_index != ~0) |
| 3284 | vlib_cli_output (vm, " tenant VRF: %u", |
| 3285 | ip4_fib_get(ap->fib_index)->table_id); |
| 3286 | else |
| 3287 | vlib_cli_output (vm, " tenant VRF independent"); |
Matus Fabian | 09d96f4 | 2017-02-02 01:43:00 -0800 | [diff] [blame] | 3288 | #define _(N, i, n, s) \ |
| 3289 | vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s); |
| 3290 | foreach_snat_protocol |
| 3291 | #undef _ |
Matus Fabian | 07ea761 | 2016-12-15 05:30:37 -0800 | [diff] [blame] | 3292 | } |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3293 | |
| 3294 | vlib_cli_output (vm, "NAT44 twice-nat pool addresses:"); |
| 3295 | vec_foreach (ap, sm->twice_nat_addresses) |
| 3296 | { |
| 3297 | vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr); |
| 3298 | if (ap->fib_index != ~0) |
| 3299 | vlib_cli_output (vm, " tenant VRF: %u", |
| 3300 | ip4_fib_get(ap->fib_index)->table_id); |
| 3301 | else |
| 3302 | vlib_cli_output (vm, " tenant VRF independent"); |
| 3303 | #define _(N, i, n, s) \ |
| 3304 | vlib_cli_output (vm, " %d busy %s ports", ap->busy_##n##_ports, s); |
| 3305 | foreach_snat_protocol |
| 3306 | #undef _ |
| 3307 | } |
Matus Fabian | 588144a | 2016-10-24 03:30:00 -0700 | [diff] [blame] | 3308 | } |
| 3309 | |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 3310 | if (sm->num_workers > 1) |
| 3311 | { |
| 3312 | vlib_cli_output (vm, "%d workers", vec_len (sm->workers)); |
| 3313 | if (verbose > 0) |
| 3314 | { |
| 3315 | vec_foreach (worker, sm->workers) |
| 3316 | { |
| 3317 | vlib_worker_thread_t *w = |
| 3318 | vlib_worker_threads + *worker + sm->first_worker_index; |
Matus Fabian | eea28d7 | 2017-01-13 04:15:54 -0800 | [diff] [blame] | 3319 | vlib_cli_output (vm, " %s", w->name); |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 3320 | } |
| 3321 | } |
| 3322 | } |
| 3323 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3324 | if (sm->deterministic) |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3325 | { |
Matus Fabian | 6a0946f | 2017-04-12 03:36:13 -0700 | [diff] [blame] | 3326 | vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout); |
| 3327 | vlib_cli_output (vm, "tcp-established timeout: %dsec", |
| 3328 | sm->tcp_established_timeout); |
| 3329 | vlib_cli_output (vm, "tcp-transitory timeout: %dsec", |
| 3330 | sm->tcp_transitory_timeout); |
| 3331 | vlib_cli_output (vm, "icmp timeout: %dsec", sm->icmp_timeout); |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3332 | vlib_cli_output (vm, "%d deterministic mappings", |
| 3333 | pool_elts (sm->det_maps)); |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3334 | if (verbose > 0) |
| 3335 | { |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3336 | pool_foreach (dm, sm->det_maps, |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3337 | ({ |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3338 | vlib_cli_output (vm, "in %U/%d out %U/%d\n", |
| 3339 | format_ip4_address, &dm->in_addr, dm->in_plen, |
| 3340 | format_ip4_address, &dm->out_addr, dm->out_plen); |
| 3341 | vlib_cli_output (vm, " outside address sharing ratio: %d\n", |
| 3342 | dm->sharing_ratio); |
| 3343 | vlib_cli_output (vm, " number of ports per inside host: %d\n", |
| 3344 | dm->ports_per_host); |
| 3345 | vlib_cli_output (vm, " sessions number: %d\n", dm->ses_num); |
| 3346 | if (verbose > 1) |
| 3347 | { |
| 3348 | vec_foreach_index (j, dm->sessions) |
| 3349 | { |
| 3350 | ses = vec_elt_at_index (dm->sessions, j); |
| 3351 | if (ses->in_port) |
| 3352 | vlib_cli_output (vm, " %U", format_det_map_ses, dm, ses, |
| 3353 | &j); |
| 3354 | } |
| 3355 | } |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3356 | })); |
| 3357 | } |
| 3358 | } |
| 3359 | else |
| 3360 | { |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3361 | if (sm->static_mapping_only && !(sm->static_mapping_connection_tracking)) |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 3362 | { |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3363 | vlib_cli_output (vm, "%d static mappings", |
| 3364 | pool_elts (sm->static_mappings)); |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 3365 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3366 | if (verbose > 0) |
Matus Fabian | 475f055 | 2016-10-19 06:17:52 -0700 | [diff] [blame] | 3367 | { |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3368 | pool_foreach (m, sm->static_mappings, |
| 3369 | ({ |
| 3370 | vlib_cli_output (vm, "%U", format_snat_static_mapping, m); |
| 3371 | })); |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3372 | } |
| 3373 | } |
| 3374 | else |
| 3375 | { |
| 3376 | vec_foreach (tsm, sm->per_thread_data) |
| 3377 | { |
| 3378 | users_num += pool_elts (tsm->users); |
| 3379 | sessions_num += pool_elts (tsm->sessions); |
| 3380 | } |
| 3381 | |
| 3382 | vlib_cli_output (vm, "%d users, %d outside addresses, %d active sessions," |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3383 | " %d static mappings, %d twice-nat addresses", |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3384 | users_num, |
| 3385 | vec_len (sm->addresses), |
| 3386 | sessions_num, |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3387 | pool_elts (sm->static_mappings), |
| 3388 | vec_len (sm->twice_nat_addresses)); |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3389 | |
| 3390 | if (verbose > 0) |
| 3391 | { |
Matus Fabian | 704018c | 2017-09-04 02:17:18 -0700 | [diff] [blame] | 3392 | vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->in2out_ed, |
| 3393 | verbose - 1); |
| 3394 | vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->out2in_ed, |
| 3395 | verbose - 1); |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3396 | vec_foreach_index (j, sm->per_thread_data) |
Matus Fabian | e22e546 | 2017-02-14 23:33:43 -0800 | [diff] [blame] | 3397 | { |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3398 | tsm = vec_elt_at_index (sm->per_thread_data, j); |
| 3399 | |
| 3400 | if (pool_elts (tsm->users) == 0) |
| 3401 | continue; |
| 3402 | |
| 3403 | vlib_worker_thread_t *w = vlib_worker_threads + j; |
| 3404 | vlib_cli_output (vm, "Thread %d (%s at lcore %u):", j, w->name, |
| 3405 | w->lcore_id); |
Matus Fabian | 092b3cd | 2017-09-19 05:42:38 -0700 | [diff] [blame] | 3406 | vlib_cli_output (vm, " %U", format_bihash_8_8, &tsm->in2out, |
| 3407 | verbose - 1); |
| 3408 | vlib_cli_output (vm, " %U", format_bihash_8_8, &tsm->out2in, |
| 3409 | verbose - 1); |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3410 | vlib_cli_output (vm, " %d list pool elements", |
| 3411 | pool_elts (tsm->list_pool)); |
| 3412 | |
| 3413 | pool_foreach (u, tsm->users, |
| 3414 | ({ |
| 3415 | vlib_cli_output (vm, " %U", format_snat_user, tsm, u, |
| 3416 | verbose - 1); |
| 3417 | })); |
| 3418 | } |
| 3419 | |
| 3420 | if (pool_elts (sm->static_mappings)) |
| 3421 | { |
| 3422 | vlib_cli_output (vm, "static mappings:"); |
| 3423 | pool_foreach (m, sm->static_mappings, |
| 3424 | ({ |
| 3425 | vlib_cli_output (vm, "%U", format_snat_static_mapping, m); |
| 3426 | })); |
| 3427 | for (j = 0; j < vec_len (sm->to_resolve); j++) |
| 3428 | { |
| 3429 | rp = sm->to_resolve + j; |
| 3430 | vlib_cli_output (vm, "%U", |
| 3431 | format_snat_static_map_to_resolve, rp); |
| 3432 | } |
Matus Fabian | e22e546 | 2017-02-14 23:33:43 -0800 | [diff] [blame] | 3433 | } |
Matus Fabian | db64988 | 2016-08-26 05:45:27 -0700 | [diff] [blame] | 3434 | } |
| 3435 | } |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3436 | } |
Matus Fabian | efcd1e9 | 2017-08-15 06:59:19 -0700 | [diff] [blame] | 3437 | |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3438 | return 0; |
| 3439 | } |
| 3440 | |
| 3441 | VLIB_CLI_COMMAND (show_snat_command, static) = { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 3442 | .path = "show nat44", |
| 3443 | .short_help = "show nat44", |
Dave Barach | 20c02cb | 2016-06-26 10:42:08 -0400 | [diff] [blame] | 3444 | .function = show_snat_command_fn, |
| 3445 | }; |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3446 | |
| 3447 | |
| 3448 | static void |
| 3449 | snat_ip4_add_del_interface_address_cb (ip4_main_t * im, |
| 3450 | uword opaque, |
| 3451 | u32 sw_if_index, |
| 3452 | ip4_address_t * address, |
| 3453 | u32 address_length, |
| 3454 | u32 if_address_index, |
| 3455 | u32 is_delete) |
| 3456 | { |
| 3457 | snat_main_t *sm = &snat_main; |
Dave Barach | 8b27537 | 2017-01-16 10:54:02 -0500 | [diff] [blame] | 3458 | snat_static_map_resolve_t *rp; |
| 3459 | u32 *indices_to_delete = 0; |
Matus Fabian | ab7a805 | 2017-11-28 04:29:41 -0800 | [diff] [blame] | 3460 | ip4_address_t l_addr; |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3461 | int i, j; |
Dave Barach | 8b27537 | 2017-01-16 10:54:02 -0500 | [diff] [blame] | 3462 | int rv; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3463 | u8 twice_nat = 0; |
| 3464 | snat_address_t *addresses = sm->addresses; |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3465 | |
| 3466 | for (i = 0; i < vec_len(sm->auto_add_sw_if_indices); i++) |
| 3467 | { |
| 3468 | if (sw_if_index == sm->auto_add_sw_if_indices[i]) |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3469 | goto match; |
| 3470 | } |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3471 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3472 | for (i = 0; i < vec_len(sm->auto_add_sw_if_indices_twice_nat); i++) |
| 3473 | { |
| 3474 | twice_nat = 1; |
| 3475 | addresses = sm->twice_nat_addresses; |
| 3476 | if (sw_if_index == sm->auto_add_sw_if_indices_twice_nat[i]) |
| 3477 | goto match; |
| 3478 | } |
| 3479 | |
| 3480 | return; |
| 3481 | |
| 3482 | match: |
| 3483 | if (!is_delete) |
| 3484 | { |
| 3485 | /* Don't trip over lease renewal, static config */ |
| 3486 | for (j = 0; j < vec_len(addresses); j++) |
| 3487 | if (addresses[j].addr.as_u32 == address->as_u32) |
| 3488 | return; |
| 3489 | |
| 3490 | snat_add_address (sm, address, ~0, twice_nat); |
| 3491 | /* Scan static map resolution vector */ |
| 3492 | for (j = 0; j < vec_len (sm->to_resolve); j++) |
| 3493 | { |
| 3494 | rp = sm->to_resolve + j; |
| 3495 | /* On this interface? */ |
| 3496 | if (rp->sw_if_index == sw_if_index) |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3497 | { |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3498 | /* Indetity mapping? */ |
| 3499 | if (rp->l_addr.as_u32 == 0) |
| 3500 | l_addr.as_u32 = address[0].as_u32; |
| 3501 | else |
| 3502 | l_addr.as_u32 = rp->l_addr.as_u32; |
| 3503 | /* Add the static mapping */ |
| 3504 | rv = snat_add_static_mapping (l_addr, |
| 3505 | address[0], |
| 3506 | rp->l_port, |
| 3507 | rp->e_port, |
| 3508 | rp->vrf_id, |
| 3509 | rp->addr_only, |
| 3510 | ~0 /* sw_if_index */, |
| 3511 | rp->proto, |
| 3512 | rp->is_add, |
| 3513 | 0); |
| 3514 | if (rv) |
| 3515 | clib_warning ("snat_add_static_mapping returned %d", |
| 3516 | rv); |
| 3517 | vec_add1 (indices_to_delete, j); |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3518 | } |
| 3519 | } |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3520 | /* If we resolved any of the outstanding static mappings */ |
| 3521 | if (vec_len(indices_to_delete)) |
| 3522 | { |
| 3523 | /* Delete them */ |
| 3524 | for (j = vec_len(indices_to_delete)-1; j >= 0; j--) |
| 3525 | vec_delete(sm->to_resolve, 1, j); |
| 3526 | vec_free(indices_to_delete); |
| 3527 | } |
| 3528 | return; |
| 3529 | } |
| 3530 | else |
| 3531 | { |
| 3532 | (void) snat_del_address(sm, address[0], 1, twice_nat); |
| 3533 | return; |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3534 | } |
| 3535 | } |
| 3536 | |
| 3537 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3538 | int snat_add_interface_address (snat_main_t *sm, u32 sw_if_index, int is_del, |
| 3539 | u8 twice_nat) |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3540 | { |
| 3541 | ip4_main_t * ip4_main = sm->ip4_main; |
| 3542 | ip4_address_t * first_int_addr; |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 3543 | snat_static_map_resolve_t *rp; |
| 3544 | u32 *indices_to_delete = 0; |
| 3545 | int i, j; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3546 | u32 *auto_add_sw_if_indices = |
| 3547 | twice_nat ? sm->auto_add_sw_if_indices_twice_nat : sm->auto_add_sw_if_indices; |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3548 | |
| 3549 | first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, |
| 3550 | 0 /* just want the address*/); |
| 3551 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3552 | for (i = 0; i < vec_len(auto_add_sw_if_indices); i++) |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3553 | { |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3554 | if (auto_add_sw_if_indices[i] == sw_if_index) |
Matus Fabian | 8bf68e8 | 2017-01-12 04:24:35 -0800 | [diff] [blame] | 3555 | { |
| 3556 | if (is_del) |
| 3557 | { |
| 3558 | /* if have address remove it */ |
| 3559 | if (first_int_addr) |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3560 | (void) snat_del_address (sm, first_int_addr[0], 1, twice_nat); |
Matus Fabian | 36532bd | 2017-01-23 23:42:28 -0800 | [diff] [blame] | 3561 | else |
| 3562 | { |
| 3563 | for (j = 0; j < vec_len (sm->to_resolve); j++) |
| 3564 | { |
| 3565 | rp = sm->to_resolve + j; |
| 3566 | if (rp->sw_if_index == sw_if_index) |
| 3567 | vec_add1 (indices_to_delete, j); |
| 3568 | } |
| 3569 | if (vec_len(indices_to_delete)) |
| 3570 | { |
| 3571 | for (j = vec_len(indices_to_delete)-1; j >= 0; j--) |
| 3572 | vec_del1(sm->to_resolve, j); |
| 3573 | vec_free(indices_to_delete); |
| 3574 | } |
| 3575 | } |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3576 | if (twice_nat) |
| 3577 | vec_del1(sm->auto_add_sw_if_indices_twice_nat, i); |
| 3578 | else |
| 3579 | vec_del1(sm->auto_add_sw_if_indices, i); |
Matus Fabian | 8bf68e8 | 2017-01-12 04:24:35 -0800 | [diff] [blame] | 3580 | } |
| 3581 | else |
| 3582 | return VNET_API_ERROR_VALUE_EXIST; |
| 3583 | |
| 3584 | return 0; |
| 3585 | } |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3586 | } |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 3587 | |
Matus Fabian | 8bf68e8 | 2017-01-12 04:24:35 -0800 | [diff] [blame] | 3588 | if (is_del) |
| 3589 | return VNET_API_ERROR_NO_SUCH_ENTRY; |
| 3590 | |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3591 | /* add to the auto-address list */ |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3592 | if (twice_nat) |
| 3593 | vec_add1(sm->auto_add_sw_if_indices_twice_nat, sw_if_index); |
| 3594 | else |
| 3595 | vec_add1(sm->auto_add_sw_if_indices, sw_if_index); |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3596 | |
| 3597 | /* If the address is already bound - or static - add it now */ |
| 3598 | if (first_int_addr) |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3599 | snat_add_address (sm, first_int_addr, ~0, twice_nat); |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3600 | |
| 3601 | return 0; |
| 3602 | } |
| 3603 | |
| 3604 | static clib_error_t * |
| 3605 | snat_add_interface_address_command_fn (vlib_main_t * vm, |
| 3606 | unformat_input_t * input, |
| 3607 | vlib_cli_command_t * cmd) |
| 3608 | { |
| 3609 | snat_main_t *sm = &snat_main; |
| 3610 | unformat_input_t _line_input, *line_input = &_line_input; |
| 3611 | u32 sw_if_index; |
| 3612 | int rv; |
Matus Fabian | 8bf68e8 | 2017-01-12 04:24:35 -0800 | [diff] [blame] | 3613 | int is_del = 0; |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 3614 | clib_error_t *error = 0; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3615 | u8 twice_nat = 0; |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3616 | |
| 3617 | /* Get a line of input. */ |
| 3618 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 3619 | return 0; |
| 3620 | |
| 3621 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 3622 | { |
| 3623 | if (unformat (line_input, "%U", unformat_vnet_sw_interface, |
| 3624 | sm->vnet_main, &sw_if_index)) |
| 3625 | ; |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3626 | else if (unformat (line_input, "twice-nat")) |
| 3627 | twice_nat = 1; |
Matus Fabian | 8bf68e8 | 2017-01-12 04:24:35 -0800 | [diff] [blame] | 3628 | else if (unformat (line_input, "del")) |
| 3629 | is_del = 1; |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3630 | else |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 3631 | { |
| 3632 | error = clib_error_return (0, "unknown input '%U'", |
| 3633 | format_unformat_error, line_input); |
| 3634 | goto done; |
| 3635 | } |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3636 | } |
| 3637 | |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3638 | rv = snat_add_interface_address (sm, sw_if_index, is_del, twice_nat); |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3639 | |
| 3640 | switch (rv) |
| 3641 | { |
| 3642 | case 0: |
| 3643 | break; |
| 3644 | |
| 3645 | default: |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 3646 | error = clib_error_return (0, "snat_add_interface_address returned %d", |
| 3647 | rv); |
| 3648 | goto done; |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3649 | } |
Billy McFall | a9a20e7 | 2017-02-15 11:39:12 -0500 | [diff] [blame] | 3650 | |
| 3651 | done: |
| 3652 | unformat_free (line_input); |
| 3653 | |
| 3654 | return error; |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3655 | } |
| 3656 | |
| 3657 | VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 3658 | .path = "nat44 add interface address", |
Matus Fabian | b932d26 | 2017-12-18 05:38:24 -0800 | [diff] [blame] | 3659 | .short_help = "nat44 add interface address <interface> [twice-nat] [del]", |
Dave Barach | cab65ec | 2017-01-11 13:01:14 -0500 | [diff] [blame] | 3660 | .function = snat_add_interface_address_command_fn, |
| 3661 | }; |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3662 | |
Matus Fabian | 5ba86f7 | 2017-10-26 03:37:38 -0700 | [diff] [blame] | 3663 | int |
| 3664 | nat44_del_session (snat_main_t *sm, ip4_address_t *addr, u16 port, |
| 3665 | snat_protocol_t proto, u32 vrf_id, int is_in) |
| 3666 | { |
| 3667 | snat_main_per_thread_data_t *tsm; |
| 3668 | clib_bihash_kv_8_8_t kv, value; |
| 3669 | ip4_header_t ip; |
| 3670 | u32 fib_index = fib_table_find (FIB_PROTOCOL_IP4, vrf_id); |
| 3671 | snat_session_key_t key; |
| 3672 | snat_session_t *s; |
| 3673 | clib_bihash_8_8_t *t; |
| 3674 | snat_user_key_t u_key; |
| 3675 | snat_user_t *u; |
| 3676 | |
| 3677 | ip.dst_address.as_u32 = ip.src_address.as_u32 = addr->as_u32; |
| 3678 | if (sm->num_workers) |
| 3679 | tsm = |
| 3680 | vec_elt_at_index (sm->per_thread_data, |
| 3681 | sm->worker_in2out_cb (&ip, fib_index)); |
| 3682 | else |
| 3683 | tsm = vec_elt_at_index (sm->per_thread_data, sm->num_workers); |
| 3684 | |
| 3685 | key.addr.as_u32 = addr->as_u32; |
| 3686 | key.port = clib_host_to_net_u16 (port); |
| 3687 | key.protocol = proto; |
| 3688 | key.fib_index = fib_index; |
| 3689 | kv.key = key.as_u64; |
| 3690 | t = is_in ? &tsm->in2out : &tsm->out2in; |
| 3691 | if (!clib_bihash_search_8_8 (t, &kv, &value)) |
| 3692 | { |
| 3693 | s = pool_elt_at_index (tsm->sessions, value.value); |
| 3694 | kv.key = s->in2out.as_u64; |
| 3695 | clib_bihash_add_del_8_8 (&tsm->in2out, &kv, 0); |
| 3696 | kv.key = s->out2in.as_u64; |
| 3697 | clib_bihash_add_del_8_8 (&tsm->out2in, &kv, 0); |
| 3698 | u_key.addr = s->in2out.addr; |
| 3699 | u_key.fib_index = s->in2out.fib_index; |
| 3700 | kv.key = u_key.as_u64; |
| 3701 | if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value)) |
| 3702 | { |
| 3703 | u = pool_elt_at_index (tsm->users, value.value); |
| 3704 | u->nsessions--; |
| 3705 | } |
| 3706 | clib_dlist_remove (tsm->list_pool, s->per_user_index); |
| 3707 | pool_put (tsm->sessions, s); |
| 3708 | return 0; |
| 3709 | } |
| 3710 | |
| 3711 | return VNET_API_ERROR_NO_SUCH_ENTRY; |
| 3712 | } |
| 3713 | |
| 3714 | static clib_error_t * |
| 3715 | nat44_del_session_command_fn (vlib_main_t * vm, |
| 3716 | unformat_input_t * input, |
| 3717 | vlib_cli_command_t * cmd) |
| 3718 | { |
| 3719 | snat_main_t *sm = &snat_main; |
| 3720 | unformat_input_t _line_input, *line_input = &_line_input; |
| 3721 | int is_in = 0; |
| 3722 | clib_error_t *error = 0; |
| 3723 | ip4_address_t addr; |
| 3724 | u32 port = 0, vrf_id = sm->outside_vrf_id; |
| 3725 | snat_protocol_t proto; |
| 3726 | int rv; |
| 3727 | |
| 3728 | /* Get a line of input. */ |
| 3729 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 3730 | return 0; |
| 3731 | |
| 3732 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 3733 | { |
| 3734 | if (unformat (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port, |
| 3735 | unformat_snat_protocol, &proto)) |
| 3736 | ; |
| 3737 | else if (unformat (line_input, "in")) |
| 3738 | { |
| 3739 | is_in = 1; |
| 3740 | vrf_id = sm->inside_vrf_id; |
| 3741 | } |
| 3742 | else if (unformat (line_input, "vrf %u", &vrf_id)) |
| 3743 | ; |
| 3744 | else |
| 3745 | { |
| 3746 | error = clib_error_return (0, "unknown input '%U'", |
| 3747 | format_unformat_error, line_input); |
| 3748 | goto done; |
| 3749 | } |
| 3750 | } |
| 3751 | |
| 3752 | rv = nat44_del_session(sm, &addr, port, proto, vrf_id, is_in); |
| 3753 | |
| 3754 | switch (rv) |
| 3755 | { |
| 3756 | case 0: |
| 3757 | break; |
| 3758 | |
| 3759 | default: |
| 3760 | error = clib_error_return (0, "nat44_del_session returned %d", rv); |
| 3761 | goto done; |
| 3762 | } |
| 3763 | |
| 3764 | done: |
| 3765 | unformat_free (line_input); |
| 3766 | |
| 3767 | return error; |
| 3768 | } |
| 3769 | |
| 3770 | VLIB_CLI_COMMAND (nat44_del_session_command, static) = { |
| 3771 | .path = "nat44 del session", |
| 3772 | .short_help = "nat44 del session in|out <addr>:<port> tcp|udp|icmp [vrf <id>]", |
| 3773 | .function = nat44_del_session_command_fn, |
| 3774 | }; |
| 3775 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3776 | static clib_error_t * |
Matus Fabian | 2769710 | 2017-11-09 01:43:47 -0800 | [diff] [blame] | 3777 | nat44_set_alloc_addr_and_port_alg_command_fn (vlib_main_t * vm, |
| 3778 | unformat_input_t * input, |
| 3779 | vlib_cli_command_t * cmd) |
| 3780 | { |
| 3781 | snat_main_t *sm = &snat_main; |
| 3782 | unformat_input_t _line_input, *line_input = &_line_input; |
| 3783 | clib_error_t *error = 0; |
| 3784 | u32 psid, psid_offset, psid_length; |
| 3785 | |
| 3786 | /* Get a line of input. */ |
| 3787 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 3788 | return 0; |
| 3789 | |
| 3790 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 3791 | { |
| 3792 | if (unformat (line_input, "default")) |
| 3793 | sm->alloc_addr_and_port = nat_alloc_addr_and_port_default; |
| 3794 | else if (unformat (line_input, "map-e psid %d psid-offset %d psid-len %d", |
| 3795 | &psid, &psid_offset, &psid_length)) |
| 3796 | { |
| 3797 | sm->alloc_addr_and_port = nat_alloc_addr_and_port_mape; |
| 3798 | sm->psid = (u16) psid; |
| 3799 | sm->psid_offset = (u16) psid_offset; |
| 3800 | sm->psid_length = (u16) psid_length; |
| 3801 | } |
| 3802 | else |
| 3803 | { |
| 3804 | error = clib_error_return (0, "unknown input '%U'", |
| 3805 | format_unformat_error, line_input); |
| 3806 | goto done; |
| 3807 | } |
| 3808 | } |
| 3809 | |
| 3810 | done: |
| 3811 | unformat_free (line_input); |
| 3812 | |
| 3813 | return error; |
| 3814 | }; |
| 3815 | |
| 3816 | VLIB_CLI_COMMAND (nat44_set_alloc_addr_and_port_alg_command, static) = { |
Matus Fabian | 51e759f | 2017-12-07 23:22:51 -0800 | [diff] [blame] | 3817 | .path = "nat addr-port-assignment-alg", |
| 3818 | .short_help = "nat addr-port-assignment-alg <alg-name> [<alg-params>]", |
Matus Fabian | 2769710 | 2017-11-09 01:43:47 -0800 | [diff] [blame] | 3819 | .function = nat44_set_alloc_addr_and_port_alg_command_fn, |
| 3820 | }; |
| 3821 | |
| 3822 | static clib_error_t * |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3823 | snat_det_map_command_fn (vlib_main_t * vm, |
| 3824 | unformat_input_t * input, |
| 3825 | vlib_cli_command_t * cmd) |
| 3826 | { |
| 3827 | snat_main_t *sm = &snat_main; |
| 3828 | unformat_input_t _line_input, *line_input = &_line_input; |
| 3829 | ip4_address_t in_addr, out_addr; |
| 3830 | u32 in_plen, out_plen; |
| 3831 | int is_add = 1, rv; |
| 3832 | clib_error_t *error = 0; |
| 3833 | |
| 3834 | /* Get a line of input. */ |
| 3835 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 3836 | return 0; |
| 3837 | |
| 3838 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 3839 | { |
| 3840 | if (unformat (line_input, "in %U/%u", unformat_ip4_address, &in_addr, &in_plen)) |
| 3841 | ; |
| 3842 | else if (unformat (line_input, "out %U/%u", unformat_ip4_address, &out_addr, &out_plen)) |
| 3843 | ; |
| 3844 | else if (unformat (line_input, "del")) |
| 3845 | is_add = 0; |
| 3846 | else |
| 3847 | { |
| 3848 | error = clib_error_return (0, "unknown input '%U'", |
| 3849 | format_unformat_error, line_input); |
| 3850 | goto done; |
| 3851 | } |
| 3852 | } |
| 3853 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3854 | rv = snat_det_add_map(sm, &in_addr, (u8) in_plen, &out_addr, (u8)out_plen, |
| 3855 | is_add); |
| 3856 | |
| 3857 | if (rv) |
| 3858 | { |
| 3859 | error = clib_error_return (0, "snat_det_add_map return %d", rv); |
| 3860 | goto done; |
| 3861 | } |
| 3862 | |
| 3863 | done: |
| 3864 | unformat_free (line_input); |
| 3865 | |
| 3866 | return error; |
| 3867 | } |
| 3868 | |
| 3869 | /*? |
| 3870 | * @cliexpar |
| 3871 | * @cliexstart{snat deterministic add} |
| 3872 | * Create bijective mapping of inside address to outside address and port range |
| 3873 | * pairs, with the purpose of enabling deterministic NAT to reduce logging in |
| 3874 | * CGN deployments. |
| 3875 | * To create deterministic mapping between inside network 10.0.0.0/18 and |
| 3876 | * outside network 1.1.1.0/30 use: |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 3877 | * # vpp# nat44 deterministic add in 10.0.0.0/18 out 1.1.1.0/30 |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3878 | * @cliexend |
| 3879 | ?*/ |
| 3880 | VLIB_CLI_COMMAND (snat_det_map_command, static) = { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 3881 | .path = "nat44 deterministic add", |
| 3882 | .short_help = "nat44 deterministic add in <addr>/<plen> out <addr>/<plen> [del]", |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3883 | .function = snat_det_map_command_fn, |
| 3884 | }; |
| 3885 | |
| 3886 | static clib_error_t * |
| 3887 | snat_det_forward_command_fn (vlib_main_t * vm, |
| 3888 | unformat_input_t * input, |
| 3889 | vlib_cli_command_t * cmd) |
| 3890 | { |
| 3891 | snat_main_t *sm = &snat_main; |
| 3892 | unformat_input_t _line_input, *line_input = &_line_input; |
| 3893 | ip4_address_t in_addr, out_addr; |
| 3894 | u16 lo_port; |
| 3895 | snat_det_map_t * dm; |
| 3896 | clib_error_t *error = 0; |
| 3897 | |
| 3898 | /* Get a line of input. */ |
| 3899 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 3900 | return 0; |
| 3901 | |
| 3902 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 3903 | { |
| 3904 | if (unformat (line_input, "%U", unformat_ip4_address, &in_addr)) |
| 3905 | ; |
| 3906 | else |
| 3907 | { |
| 3908 | error = clib_error_return (0, "unknown input '%U'", |
| 3909 | format_unformat_error, line_input); |
| 3910 | goto done; |
| 3911 | } |
| 3912 | } |
| 3913 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3914 | dm = snat_det_map_by_user(sm, &in_addr); |
| 3915 | if (!dm) |
| 3916 | vlib_cli_output (vm, "no match"); |
| 3917 | else |
| 3918 | { |
| 3919 | snat_det_forward (dm, &in_addr, &out_addr, &lo_port); |
| 3920 | vlib_cli_output (vm, "%U:<%d-%d>", format_ip4_address, &out_addr, |
| 3921 | lo_port, lo_port + dm->ports_per_host - 1); |
| 3922 | } |
| 3923 | |
| 3924 | done: |
| 3925 | unformat_free (line_input); |
| 3926 | |
| 3927 | return error; |
| 3928 | } |
| 3929 | |
| 3930 | /*? |
| 3931 | * @cliexpar |
| 3932 | * @cliexstart{snat deterministic forward} |
| 3933 | * Return outside address and port range from inside address for deterministic |
| 3934 | * NAT. |
| 3935 | * To obtain outside address and port of inside host use: |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 3936 | * vpp# nat44 deterministic forward 10.0.0.2 |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3937 | * 1.1.1.0:<1054-1068> |
| 3938 | * @cliexend |
| 3939 | ?*/ |
| 3940 | VLIB_CLI_COMMAND (snat_det_forward_command, static) = { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 3941 | .path = "nat44 deterministic forward", |
| 3942 | .short_help = "nat44 deterministic forward <addr>", |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3943 | .function = snat_det_forward_command_fn, |
| 3944 | }; |
| 3945 | |
| 3946 | static clib_error_t * |
| 3947 | snat_det_reverse_command_fn (vlib_main_t * vm, |
| 3948 | unformat_input_t * input, |
| 3949 | vlib_cli_command_t * cmd) |
| 3950 | { |
| 3951 | snat_main_t *sm = &snat_main; |
| 3952 | unformat_input_t _line_input, *line_input = &_line_input; |
| 3953 | ip4_address_t in_addr, out_addr; |
| 3954 | u32 out_port; |
| 3955 | snat_det_map_t * dm; |
| 3956 | clib_error_t *error = 0; |
| 3957 | |
| 3958 | /* Get a line of input. */ |
| 3959 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 3960 | return 0; |
| 3961 | |
| 3962 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 3963 | { |
| 3964 | if (unformat (line_input, "%U:%d", unformat_ip4_address, &out_addr, &out_port)) |
| 3965 | ; |
| 3966 | else |
| 3967 | { |
| 3968 | error = clib_error_return (0, "unknown input '%U'", |
| 3969 | format_unformat_error, line_input); |
| 3970 | } |
| 3971 | } |
| 3972 | |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 3973 | if (out_port < 1024 || out_port > 65535) |
| 3974 | { |
| 3975 | error = clib_error_return (0, "wrong port, must be <1024-65535>"); |
| 3976 | goto done; |
| 3977 | } |
| 3978 | |
| 3979 | dm = snat_det_map_by_out(sm, &out_addr); |
| 3980 | if (!dm) |
| 3981 | vlib_cli_output (vm, "no match"); |
| 3982 | else |
| 3983 | { |
| 3984 | snat_det_reverse (dm, &out_addr, (u16) out_port, &in_addr); |
| 3985 | vlib_cli_output (vm, "%U", format_ip4_address, &in_addr); |
| 3986 | } |
| 3987 | |
| 3988 | done: |
| 3989 | unformat_free (line_input); |
| 3990 | |
| 3991 | return error; |
| 3992 | } |
| 3993 | |
| 3994 | /*? |
| 3995 | * @cliexpar |
| 3996 | * @cliexstart{snat deterministic reverse} |
| 3997 | * Return inside address from outside address and port for deterministic NAT. |
| 3998 | * To obtain inside host address from outside address and port use: |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 3999 | * #vpp nat44 deterministic reverse 1.1.1.1:1276 |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 4000 | * 10.0.16.16 |
| 4001 | * @cliexend |
| 4002 | ?*/ |
| 4003 | VLIB_CLI_COMMAND (snat_det_reverse_command, static) = { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 4004 | .path = "nat44 deterministic reverse", |
| 4005 | .short_help = "nat44 deterministic reverse <addr>:<port>", |
Matus Fabian | 066f034 | 2017-02-10 03:48:01 -0800 | [diff] [blame] | 4006 | .function = snat_det_reverse_command_fn, |
| 4007 | }; |
Matus Fabian | 6a0946f | 2017-04-12 03:36:13 -0700 | [diff] [blame] | 4008 | |
| 4009 | static clib_error_t * |
| 4010 | set_timeout_command_fn (vlib_main_t * vm, |
| 4011 | unformat_input_t * input, |
| 4012 | vlib_cli_command_t * cmd) |
| 4013 | { |
| 4014 | snat_main_t *sm = &snat_main; |
| 4015 | unformat_input_t _line_input, *line_input = &_line_input; |
| 4016 | clib_error_t *error = 0; |
| 4017 | |
| 4018 | /* Get a line of input. */ |
| 4019 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 4020 | return 0; |
| 4021 | |
| 4022 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 4023 | { |
| 4024 | if (unformat (line_input, "udp %u", &sm->udp_timeout)) |
| 4025 | ; |
| 4026 | else if (unformat (line_input, "tcp-established %u", |
| 4027 | &sm->tcp_established_timeout)) |
| 4028 | ; |
| 4029 | else if (unformat (line_input, "tcp-transitory %u", |
| 4030 | &sm->tcp_transitory_timeout)) |
| 4031 | ; |
| 4032 | else if (unformat (line_input, "icmp %u", &sm->icmp_timeout)) |
| 4033 | ; |
| 4034 | else if (unformat (line_input, "reset")) |
| 4035 | { |
| 4036 | sm->udp_timeout = SNAT_UDP_TIMEOUT; |
| 4037 | sm->tcp_established_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT; |
| 4038 | sm->tcp_transitory_timeout = SNAT_TCP_TRANSITORY_TIMEOUT; |
| 4039 | sm->icmp_timeout = SNAT_ICMP_TIMEOUT; |
| 4040 | } |
| 4041 | else |
| 4042 | { |
| 4043 | error = clib_error_return (0, "unknown input '%U'", |
| 4044 | format_unformat_error, line_input); |
| 4045 | goto done; |
| 4046 | } |
| 4047 | } |
| 4048 | |
Matus Fabian | 6a0946f | 2017-04-12 03:36:13 -0700 | [diff] [blame] | 4049 | done: |
| 4050 | unformat_free (line_input); |
| 4051 | |
| 4052 | return error; |
| 4053 | } |
| 4054 | |
| 4055 | /*? |
| 4056 | * @cliexpar |
| 4057 | * @cliexstart{set snat deterministic timeout} |
| 4058 | * Set values of timeouts for deterministic NAT (in seconds), use: |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 4059 | * vpp# set nat44 deterministic timeout udp 120 tcp-established 7500 |
Matus Fabian | 6a0946f | 2017-04-12 03:36:13 -0700 | [diff] [blame] | 4060 | * tcp-transitory 250 icmp 90 |
| 4061 | * To reset default values use: |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 4062 | * vpp# set nat44 deterministic timeout reset |
Matus Fabian | 6a0946f | 2017-04-12 03:36:13 -0700 | [diff] [blame] | 4063 | * @cliexend |
| 4064 | ?*/ |
| 4065 | VLIB_CLI_COMMAND (set_timeout_command, static) = { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 4066 | .path = "set nat44 deterministic timeout", |
Matus Fabian | 6a0946f | 2017-04-12 03:36:13 -0700 | [diff] [blame] | 4067 | .function = set_timeout_command_fn, |
| 4068 | .short_help = |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 4069 | "set nat44 deterministic timeout [udp <sec> | tcp-established <sec> " |
Matus Fabian | 6a0946f | 2017-04-12 03:36:13 -0700 | [diff] [blame] | 4070 | "tcp-transitory <sec> | icmp <sec> | reset]", |
| 4071 | }; |
Martin Gálik | 6bc8c64 | 2017-04-19 01:12:27 -0700 | [diff] [blame] | 4072 | |
| 4073 | static clib_error_t * |
| 4074 | snat_det_close_session_out_fn (vlib_main_t *vm, |
| 4075 | unformat_input_t * input, |
| 4076 | vlib_cli_command_t * cmd) |
| 4077 | { |
| 4078 | snat_main_t *sm = &snat_main; |
| 4079 | unformat_input_t _line_input, *line_input = &_line_input; |
| 4080 | ip4_address_t out_addr, ext_addr, in_addr; |
Aequitas | fc4510b | 2017-09-23 12:58:49 +0800 | [diff] [blame] | 4081 | u32 out_port, ext_port; |
Martin Gálik | 6bc8c64 | 2017-04-19 01:12:27 -0700 | [diff] [blame] | 4082 | snat_det_map_t * dm; |
| 4083 | snat_det_session_t * ses; |
| 4084 | snat_det_out_key_t key; |
| 4085 | clib_error_t *error = 0; |
| 4086 | |
| 4087 | /* Get a line of input. */ |
| 4088 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 4089 | return 0; |
| 4090 | |
| 4091 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 4092 | { |
| 4093 | if (unformat (line_input, "%U:%d %U:%d", |
| 4094 | unformat_ip4_address, &out_addr, &out_port, |
| 4095 | unformat_ip4_address, &ext_addr, &ext_port)) |
| 4096 | ; |
| 4097 | else |
| 4098 | { |
| 4099 | error = clib_error_return (0, "unknown input '%U'", |
| 4100 | format_unformat_error, line_input); |
| 4101 | goto done; |
| 4102 | } |
| 4103 | } |
| 4104 | |
| 4105 | unformat_free (line_input); |
| 4106 | |
| 4107 | dm = snat_det_map_by_out(sm, &out_addr); |
| 4108 | if (!dm) |
| 4109 | vlib_cli_output (vm, "no match"); |
| 4110 | else |
| 4111 | { |
Aequitas | fc4510b | 2017-09-23 12:58:49 +0800 | [diff] [blame] | 4112 | snat_det_reverse(dm, &ext_addr, (u16)out_port, &in_addr); |
Martin Gálik | 6bc8c64 | 2017-04-19 01:12:27 -0700 | [diff] [blame] | 4113 | key.ext_host_addr = out_addr; |
Aequitas | fc4510b | 2017-09-23 12:58:49 +0800 | [diff] [blame] | 4114 | key.ext_host_port = ntohs((u16)ext_port); |
| 4115 | key.out_port = ntohs((u16)out_port); |
Martin Gálik | 6bc8c64 | 2017-04-19 01:12:27 -0700 | [diff] [blame] | 4116 | ses = snat_det_get_ses_by_out(dm, &out_addr, key.as_u64); |
| 4117 | if (!ses) |
| 4118 | vlib_cli_output (vm, "no match"); |
| 4119 | else |
| 4120 | snat_det_ses_close(dm, ses); |
| 4121 | } |
| 4122 | |
| 4123 | done: |
| 4124 | unformat_free (line_input); |
| 4125 | |
| 4126 | return error; |
| 4127 | } |
| 4128 | |
| 4129 | /*? |
| 4130 | * @cliexpar |
| 4131 | * @cliexstart{snat deterministic close session out} |
| 4132 | * Close session using outside ip address and port |
| 4133 | * and external ip address and port, use: |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 4134 | * vpp# nat44 deterministic close session out 1.1.1.1:1276 2.2.2.2:2387 |
Martin Gálik | 6bc8c64 | 2017-04-19 01:12:27 -0700 | [diff] [blame] | 4135 | * @cliexend |
| 4136 | ?*/ |
| 4137 | VLIB_CLI_COMMAND (snat_det_close_sesion_out_command, static) = { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 4138 | .path = "nat44 deterministic close session out", |
| 4139 | .short_help = "nat44 deterministic close session out " |
Martin Gálik | 6bc8c64 | 2017-04-19 01:12:27 -0700 | [diff] [blame] | 4140 | "<out_addr>:<out_port> <ext_addr>:<ext_port>", |
| 4141 | .function = snat_det_close_session_out_fn, |
| 4142 | }; |
| 4143 | |
| 4144 | static clib_error_t * |
| 4145 | snat_det_close_session_in_fn (vlib_main_t *vm, |
| 4146 | unformat_input_t * input, |
| 4147 | vlib_cli_command_t * cmd) |
| 4148 | { |
| 4149 | snat_main_t *sm = &snat_main; |
| 4150 | unformat_input_t _line_input, *line_input = &_line_input; |
| 4151 | ip4_address_t in_addr, ext_addr; |
Aequitas | fc4510b | 2017-09-23 12:58:49 +0800 | [diff] [blame] | 4152 | u32 in_port, ext_port; |
Martin Gálik | 6bc8c64 | 2017-04-19 01:12:27 -0700 | [diff] [blame] | 4153 | snat_det_map_t * dm; |
| 4154 | snat_det_session_t * ses; |
| 4155 | snat_det_out_key_t key; |
| 4156 | clib_error_t *error = 0; |
| 4157 | |
| 4158 | /* Get a line of input. */ |
| 4159 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 4160 | return 0; |
| 4161 | |
| 4162 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 4163 | { |
| 4164 | if (unformat (line_input, "%U:%d %U:%d", |
| 4165 | unformat_ip4_address, &in_addr, &in_port, |
| 4166 | unformat_ip4_address, &ext_addr, &ext_port)) |
| 4167 | ; |
| 4168 | else |
| 4169 | { |
| 4170 | error = clib_error_return (0, "unknown input '%U'", |
| 4171 | format_unformat_error, line_input); |
| 4172 | goto done; |
| 4173 | } |
| 4174 | } |
| 4175 | |
| 4176 | unformat_free (line_input); |
| 4177 | |
| 4178 | dm = snat_det_map_by_user (sm, &in_addr); |
| 4179 | if (!dm) |
| 4180 | vlib_cli_output (vm, "no match"); |
| 4181 | else |
| 4182 | { |
| 4183 | key.ext_host_addr = ext_addr; |
Aequitas | fc4510b | 2017-09-23 12:58:49 +0800 | [diff] [blame] | 4184 | key.ext_host_port = ntohs ((u16)ext_port); |
| 4185 | ses = snat_det_find_ses_by_in (dm, &in_addr, ntohs((u16)in_port), key); |
Martin Gálik | 6bc8c64 | 2017-04-19 01:12:27 -0700 | [diff] [blame] | 4186 | if (!ses) |
| 4187 | vlib_cli_output (vm, "no match"); |
| 4188 | else |
| 4189 | snat_det_ses_close(dm, ses); |
| 4190 | } |
| 4191 | |
| 4192 | done: |
| 4193 | unformat_free(line_input); |
| 4194 | |
| 4195 | return error; |
| 4196 | } |
| 4197 | |
| 4198 | /*? |
| 4199 | * @cliexpar |
| 4200 | * @cliexstart{snat deterministic close_session_in} |
| 4201 | * Close session using inside ip address and port |
| 4202 | * and external ip address and port, use: |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 4203 | * vpp# nat44 deterministic close session in 3.3.3.3:3487 2.2.2.2:2387 |
Martin Gálik | 6bc8c64 | 2017-04-19 01:12:27 -0700 | [diff] [blame] | 4204 | * @cliexend |
| 4205 | ?*/ |
| 4206 | VLIB_CLI_COMMAND (snat_det_close_session_in_command, static) = { |
Matus Fabian | 2ba92e3 | 2017-08-21 07:05:03 -0700 | [diff] [blame] | 4207 | .path = "nat44 deterministic close session in", |
| 4208 | .short_help = "nat44 deterministic close session in " |
Martin Gálik | 6bc8c64 | 2017-04-19 01:12:27 -0700 | [diff] [blame] | 4209 | "<in_addr>:<in_port> <ext_addr>:<ext_port>", |
| 4210 | .function = snat_det_close_session_in_fn, |
| 4211 | }; |
Juraj Sloboda | 7b92979 | 2017-11-23 13:20:48 +0100 | [diff] [blame^] | 4212 | |
| 4213 | static clib_error_t * |
| 4214 | snat_forwarding_set_command_fn (vlib_main_t *vm, |
| 4215 | unformat_input_t * input, |
| 4216 | vlib_cli_command_t * cmd) |
| 4217 | { |
| 4218 | snat_main_t *sm = &snat_main; |
| 4219 | unformat_input_t _line_input, *line_input = &_line_input; |
| 4220 | u8 forwarding_enable; |
| 4221 | u8 forwarding_enable_set = 0; |
| 4222 | clib_error_t *error = 0; |
| 4223 | |
| 4224 | /* Get a line of input. */ |
| 4225 | if (!unformat_user (input, unformat_line_input, line_input)) |
| 4226 | return clib_error_return (0, "'enable' or 'disable' expected"); |
| 4227 | |
| 4228 | while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) |
| 4229 | { |
| 4230 | if (!forwarding_enable_set && unformat (line_input, "enable")) |
| 4231 | { |
| 4232 | forwarding_enable = 1; |
| 4233 | forwarding_enable_set = 1; |
| 4234 | } |
| 4235 | else if (!forwarding_enable_set && unformat (line_input, "disable")) |
| 4236 | { |
| 4237 | forwarding_enable = 0; |
| 4238 | forwarding_enable_set = 1; |
| 4239 | } |
| 4240 | else |
| 4241 | { |
| 4242 | error = clib_error_return (0, "unknown input '%U'", |
| 4243 | format_unformat_error, line_input); |
| 4244 | goto done; |
| 4245 | } |
| 4246 | } |
| 4247 | |
| 4248 | if (!forwarding_enable_set) |
| 4249 | { |
| 4250 | error = clib_error_return (0, "'enable' or 'disable' expected"); |
| 4251 | goto done; |
| 4252 | } |
| 4253 | |
| 4254 | sm->forwarding_enabled = forwarding_enable; |
| 4255 | |
| 4256 | done: |
| 4257 | unformat_free(line_input); |
| 4258 | |
| 4259 | return error; |
| 4260 | } |
| 4261 | |
| 4262 | /*? |
| 4263 | * @cliexpar |
| 4264 | * @cliexstart{nat44 forwarding} |
| 4265 | * Enable or disable forwarding |
| 4266 | * Forward packets which don't match existing translation |
| 4267 | * or static mapping instead of dropping them. |
| 4268 | * To enable forwarding, use: |
| 4269 | * vpp# nat44 forwarding enable |
| 4270 | * To disable forwarding, use: |
| 4271 | * vpp# nat44 forwarding disable |
| 4272 | * @cliexend |
| 4273 | ?*/ |
| 4274 | VLIB_CLI_COMMAND (snat_forwarding_set_command, static) = { |
| 4275 | .path = "nat44 forwarding", |
| 4276 | .short_help = "nat44 forwarding enable|disable", |
| 4277 | .function = snat_forwarding_set_command_fn, |
| 4278 | }; |