NAT66 1:1 mapping (VPP-1108)
[vpp.git] / src / plugins / nat / nat66.c
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /**
16  * @file
17  * @brief NAT66 implementation
18  */
19
20 #include <nat/nat66.h>
21 #include <vnet/fib/fib_table.h>
22
23 nat66_main_t nat66_main;
24
25 /* *INDENT-OFF* */
26
27 /* Hook up input features */
28 VNET_FEATURE_INIT (nat66_in2out, static) = {
29   .arc_name = "ip6-unicast",
30   .node_name = "nat66-in2out",
31   .runs_before = VNET_FEATURES ("ip6-lookup"),
32 };
33 VNET_FEATURE_INIT (nat66_out2in, static) = {
34   .arc_name = "ip6-unicast",
35   .node_name = "nat66-out2in",
36   .runs_before = VNET_FEATURES ("ip6-lookup"),
37 };
38
39 /* *INDENT-ON* */
40
41
42 void
43 nat66_init (void)
44 {
45   nat66_main_t *nm = &nat66_main;
46   u32 static_mapping_buckets = 1024;
47   uword static_mapping_memory_size = 64 << 20;
48
49   clib_bihash_init_24_8 (&nm->sm_l, "nat66-static-map-by-local",
50                          static_mapping_buckets, static_mapping_memory_size);
51   clib_bihash_init_24_8 (&nm->sm_e, "nat66-static-map-by-external",
52                          static_mapping_buckets, static_mapping_memory_size);
53
54   nm->session_counters.name = "session counters";
55 }
56
57 int
58 nat66_interface_add_del (u32 sw_if_index, u8 is_inside, u8 is_add)
59 {
60   nat66_main_t *nm = &nat66_main;
61   snat_interface_t *interface = 0, *i;
62   const char *feature_name;
63
64   /* *INDENT-OFF* */
65   pool_foreach (i, nm->interfaces,
66   ({
67     if (i->sw_if_index == sw_if_index)
68       {
69         interface = i;
70         break;
71       }
72   }));
73   /* *INDENT-ON* */
74
75   if (is_add)
76     {
77       if (interface)
78         return VNET_API_ERROR_VALUE_EXIST;
79
80       pool_get (nm->interfaces, interface);
81       interface->sw_if_index = sw_if_index;
82       interface->flags =
83         is_inside ? NAT_INTERFACE_FLAG_IS_INSIDE :
84         NAT_INTERFACE_FLAG_IS_OUTSIDE;
85     }
86   else
87     {
88       if (!interface)
89         return VNET_API_ERROR_NO_SUCH_ENTRY;
90
91       pool_put (nm->interfaces, interface);
92     }
93
94   feature_name = is_inside ? "nat66-in2out" : "nat66-out2in";
95   return vnet_feature_enable_disable ("ip6-unicast", feature_name,
96                                       sw_if_index, is_add, 0, 0);
97 }
98
99 void
100 nat66_interfaces_walk (nat66_interface_walk_fn_t fn, void *ctx)
101 {
102   nat66_main_t *nm = &nat66_main;
103   snat_interface_t *i = 0;
104
105   /* *INDENT-OFF* */
106   pool_foreach (i, nm->interfaces,
107   ({
108     if (fn (i, ctx))
109       break;
110   }));
111   /* *INDENT-ON* */
112 }
113
114 nat66_static_mapping_t *
115 nat66_static_mapping_get (ip6_address_t * addr, u32 fib_index, u8 is_local)
116 {
117   nat66_main_t *nm = &nat66_main;
118   nat66_static_mapping_t *sm = 0;
119   nat66_sm_key_t sm_key;
120   clib_bihash_kv_24_8_t kv, value;
121
122   sm_key.addr.as_u64[0] = addr->as_u64[0];
123   sm_key.addr.as_u64[1] = addr->as_u64[1];
124   sm_key.fib_index = fib_index;
125   sm_key.rsvd = 0;
126
127   kv.key[0] = sm_key.as_u64[0];
128   kv.key[1] = sm_key.as_u64[1];
129   kv.key[2] = sm_key.as_u64[2];
130
131   if (!clib_bihash_search_24_8
132       (is_local ? &nm->sm_l : &nm->sm_e, &kv, &value))
133     sm = pool_elt_at_index (nm->sm, value.value);
134
135   return sm;
136 }
137
138 int
139 nat66_static_mapping_add_del (ip6_address_t * l_addr, ip6_address_t * e_addr,
140                               u32 vrf_id, u8 is_add)
141 {
142   nat66_main_t *nm = &nat66_main;
143   int rv = 0;
144   nat66_static_mapping_t *sm = 0;
145   nat66_sm_key_t sm_key;
146   clib_bihash_kv_24_8_t kv, value;
147   u32 fib_index = fib_table_find (FIB_PROTOCOL_IP6, vrf_id);
148
149   sm_key.addr.as_u64[0] = l_addr->as_u64[0];
150   sm_key.addr.as_u64[1] = l_addr->as_u64[1];
151   sm_key.fib_index = fib_index;
152   sm_key.rsvd = 0;
153   kv.key[0] = sm_key.as_u64[0];
154   kv.key[1] = sm_key.as_u64[1];
155   kv.key[2] = sm_key.as_u64[2];
156
157   if (!clib_bihash_search_24_8 (&nm->sm_l, &kv, &value))
158     sm = pool_elt_at_index (nm->sm, value.value);
159
160   if (is_add)
161     {
162       if (sm)
163         return VNET_API_ERROR_VALUE_EXIST;
164
165       fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
166                                                      FIB_SOURCE_PLUGIN_HI);
167       pool_get (nm->sm, sm);
168       memset (sm, 0, sizeof (*sm));
169       sm->l_addr.as_u64[0] = l_addr->as_u64[0];
170       sm->l_addr.as_u64[1] = l_addr->as_u64[1];
171       sm->e_addr.as_u64[0] = e_addr->as_u64[0];
172       sm->e_addr.as_u64[1] = e_addr->as_u64[1];
173       sm->fib_index = fib_index;
174
175       sm_key.fib_index = fib_index;
176       kv.key[0] = sm_key.as_u64[0];
177       kv.key[1] = sm_key.as_u64[1];
178       kv.key[2] = sm_key.as_u64[2];
179       kv.value = sm - nm->sm;
180       if (clib_bihash_add_del_24_8 (&nm->sm_l, &kv, 1))
181         clib_warning ("nat66-static-map-by-local add key failed");
182       sm_key.addr.as_u64[0] = e_addr->as_u64[0];
183       sm_key.addr.as_u64[1] = e_addr->as_u64[1];
184       sm_key.fib_index = 0;
185       kv.key[0] = sm_key.as_u64[0];
186       kv.key[1] = sm_key.as_u64[1];
187       kv.key[2] = sm_key.as_u64[2];
188       if (clib_bihash_add_del_24_8 (&nm->sm_e, &kv, 1))
189         clib_warning ("nat66-static-map-by-external add key failed");
190
191       vlib_validate_combined_counter (&nm->session_counters, kv.value);
192       vlib_zero_combined_counter (&nm->session_counters, kv.value);
193     }
194   else
195     {
196       if (!sm)
197         return VNET_API_ERROR_NO_SUCH_ENTRY;
198
199       kv.value = sm - nm->sm;
200       if (clib_bihash_add_del_24_8 (&nm->sm_l, &kv, 0))
201         clib_warning ("nat66-static-map-by-local delete key failed");
202       sm_key.addr.as_u64[0] = e_addr->as_u64[0];
203       sm_key.addr.as_u64[1] = e_addr->as_u64[1];
204       sm_key.fib_index = 0;
205       kv.key[0] = sm_key.as_u64[0];
206       kv.key[1] = sm_key.as_u64[1];
207       kv.key[2] = sm_key.as_u64[2];
208       if (clib_bihash_add_del_24_8 (&nm->sm_e, &kv, 0))
209         clib_warning ("nat66-static-map-by-external delete key failed");
210       fib_table_unlock (sm->fib_index, FIB_PROTOCOL_IP6,
211                         FIB_SOURCE_PLUGIN_HI);
212       pool_put (nm->sm, sm);
213     }
214
215   return rv;
216 }
217
218 void
219 nat66_static_mappings_walk (nat66_static_mapping_walk_fn_t fn, void *ctx)
220 {
221   nat66_main_t *nm = &nat66_main;
222   nat66_static_mapping_t *sm = 0;
223
224   /* *INDENT-OFF* */
225   pool_foreach (sm, nm->sm,
226   ({
227     if (fn (sm, ctx))
228       break;
229   }));
230   /* *INDENT-ON* */
231 }
232
233 /*
234  * fd.io coding-style-patch-verification: ON
235  *
236  * Local Variables:
237  * eval: (c-set-style "gnu")
238  * End:
239  */