A Protocol Independent Hierarchical FIB (VPP-352)
[vpp.git] / vnet / vnet / lisp-gpe / ip_forward.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vnet/lisp-gpe/lisp_gpe_adjacency.h>
17 #include <vnet/fib/fib_table.h>
18 #include <vnet/fib/fib_entry.h>
19 #include <vnet/fib/ip6_fib.h>
20 #include <vnet/fib/ip4_fib.h>
21 #include <vnet/dpo/lookup_dpo.h>
22 #include <vnet/dpo/load_balance.h>
23
24 /**
25  * @brief Add route to IP4 or IP6 Destination FIB.
26  *
27  * Add a route to the destination FIB that results in the lookup
28  * in the SRC FIB. The SRC FIB is created is it does not yet exist.
29  *
30  * @param[in]   dst_table_id    Destination FIB Table-ID
31  * @param[in]   dst_prefix      Destination IP prefix.
32  * @param[out]  src_fib_index   The index/ID of the SRC FIB created.
33  */
34 u32
35 ip_dst_fib_add_route (u32 dst_fib_index, const ip_prefix_t * dst_prefix)
36 {
37   fib_node_index_t src_fib_index;
38   fib_prefix_t dst_fib_prefix;
39   fib_node_index_t dst_fei;
40
41   ASSERT (NULL != dst_prefix);
42
43   ip_prefix_to_fib_prefix (dst_prefix, &dst_fib_prefix);
44
45   /*
46    * lookup the destination prefix in the VRF table and retrieve the
47    * LISP associated data
48    */
49   dst_fei = fib_table_lookup_exact_match (dst_fib_index, &dst_fib_prefix);
50
51   /*
52    * If the FIB entry is not present, or not LISP sourced, add it
53    */
54   if (dst_fei == FIB_NODE_INDEX_INVALID ||
55       NULL == fib_entry_get_source_data (dst_fei, FIB_SOURCE_LISP))
56     {
57       dpo_id_t src_lkup_dpo = DPO_NULL;
58
59       /* create a new src FIB.  */
60       src_fib_index =
61         fib_table_create_and_lock (dst_fib_prefix.fp_proto,
62                                    "LISP-src for [%d,%U]",
63                                    dst_fib_index,
64                                    format_fib_prefix, &dst_fib_prefix);
65
66       /*
67        * create a data-path object to perform the source address lookup
68        * in the SRC FIB
69        */
70       lookup_dpo_add_or_lock_w_fib_index (src_fib_index,
71                                           (ip_prefix_version (dst_prefix) ==
72                                            IP6 ? DPO_PROTO_IP6 :
73                                            DPO_PROTO_IP4),
74                                           LOOKUP_INPUT_SRC_ADDR,
75                                           LOOKUP_TABLE_FROM_CONFIG,
76                                           &src_lkup_dpo);
77
78       /*
79        * add the entry to the destination FIB that uses the lookup DPO
80        */
81       dst_fei = fib_table_entry_special_dpo_add (dst_fib_index,
82                                                  &dst_fib_prefix,
83                                                  FIB_SOURCE_LISP,
84                                                  FIB_ENTRY_FLAG_EXCLUSIVE,
85                                                  &src_lkup_dpo);
86
87       /*
88        * the DPO is locked by the FIB entry, and we have no further
89        * need for it.
90        */
91       dpo_unlock (&src_lkup_dpo);
92
93       /*
94        * save the SRC FIB index on the entry so we can retrieve it for
95        * subsequent routes.
96        */
97       fib_entry_set_source_data (dst_fei, FIB_SOURCE_LISP, &src_fib_index);
98     }
99   else
100     {
101       /*
102        * destination FIB entry already present
103        */
104       src_fib_index = *(u32 *) fib_entry_get_source_data (dst_fei,
105                                                           FIB_SOURCE_LISP);
106     }
107
108   return (src_fib_index);
109 }
110
111 /**
112  * @brief Del route to IP4 or IP6 SD FIB.
113  *
114  * Remove routes from both destination and source FIBs.
115  *
116  * @param[in]   src_fib_index   The index/ID of the SRC FIB
117  * @param[in]   src_prefix      Source IP prefix.
118  * @param[in]   dst_fib_index   The index/ID of the DST FIB
119  * @param[in]   dst_prefix      Destination IP prefix.
120  */
121 void
122 ip_src_dst_fib_del_route (u32 src_fib_index,
123                           const ip_prefix_t * src_prefix,
124                           u32 dst_fib_index, const ip_prefix_t * dst_prefix)
125 {
126   fib_prefix_t dst_fib_prefix, src_fib_prefix;
127
128   ASSERT (NULL != dst_prefix);
129   ASSERT (NULL != src_prefix);
130
131   ip_prefix_to_fib_prefix (dst_prefix, &dst_fib_prefix);
132   ip_prefix_to_fib_prefix (src_prefix, &src_fib_prefix);
133
134   fib_table_entry_delete (src_fib_index, &src_fib_prefix, FIB_SOURCE_LISP);
135
136   if (0 == fib_table_get_num_entries (src_fib_index,
137                                       src_fib_prefix.fp_proto,
138                                       FIB_SOURCE_LISP))
139     {
140       /*
141        * there's nothing left, unlock the source FIB and the
142        * destination route
143        */
144       fib_table_entry_special_remove (dst_fib_index,
145                                       &dst_fib_prefix, FIB_SOURCE_LISP);
146       fib_table_unlock (src_fib_index, src_fib_prefix.fp_proto);
147     }
148 }
149
150 /**
151  * @brief Add route to IP4 or IP6 SRC FIB.
152  *
153  * Adds a route to in the LISP SRC FIB with the result of the route
154  * being the DPO passed.
155  *
156  * @param[in]   src_fib_index   The index/ID of the SRC FIB
157  * @param[in]   src_prefix      Source IP prefix.
158  * @param[in]   src_dpo         The DPO the route will link to.
159  */
160 void
161 ip_src_fib_add_route_w_dpo (u32 src_fib_index,
162                             const ip_prefix_t * src_prefix,
163                             const dpo_id_t * src_dpo)
164 {
165   fib_prefix_t src_fib_prefix;
166
167   ip_prefix_to_fib_prefix (src_prefix, &src_fib_prefix);
168
169   /*
170    * add the entry into the source fib.
171    */
172   fib_node_index_t src_fei;
173
174   src_fei = fib_table_lookup_exact_match (src_fib_index, &src_fib_prefix);
175
176   if (FIB_NODE_INDEX_INVALID == src_fei ||
177       !fib_entry_is_sourced (src_fei, FIB_SOURCE_LISP))
178     {
179       fib_table_entry_special_dpo_add (src_fib_index,
180                                        &src_fib_prefix,
181                                        FIB_SOURCE_LISP,
182                                        FIB_ENTRY_FLAG_EXCLUSIVE, src_dpo);
183     }
184 }
185
186 static void
187 ip_address_to_46 (const ip_address_t * addr,
188                   ip46_address_t * a, fib_protocol_t * proto)
189 {
190   *proto = (IP4 == ip_addr_version (addr) ?
191             FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6);
192   switch (*proto)
193     {
194     case FIB_PROTOCOL_IP4:
195       a->ip4 = addr->ip.v4;
196       break;
197     case FIB_PROTOCOL_IP6:
198       a->ip6 = addr->ip.v6;
199       break;
200     default:
201       ASSERT (0);
202       break;
203     }
204 }
205
206 static fib_route_path_t *
207 ip_src_fib_mk_paths (const lisp_fwd_path_t * paths)
208 {
209   const lisp_gpe_adjacency_t *ladj;
210   fib_route_path_t *rpaths = NULL;
211   u8 best_priority;
212   u32 ii;
213
214   vec_validate (rpaths, vec_len (paths) - 1);
215
216   best_priority = paths[0].priority;
217
218   vec_foreach_index (ii, paths)
219   {
220     if (paths[0].priority != best_priority)
221       break;
222
223     ladj = lisp_gpe_adjacency_get (paths[ii].lisp_adj);
224
225     ip_address_to_46 (&ladj->remote_rloc,
226                       &rpaths[ii].frp_addr, &rpaths[ii].frp_proto);
227
228     rpaths[ii].frp_sw_if_index = ladj->sw_if_index;
229     rpaths[ii].frp_weight = (paths[ii].weight ? paths[ii].weight : 1);
230     rpaths[ii].frp_label = MPLS_LABEL_INVALID;
231   }
232
233   ASSERT (0 != vec_len (rpaths));
234
235   return (rpaths);
236 }
237
238 /**
239  * @brief Add route to IP4 or IP6 SRC FIB.
240  *
241  * Adds a route to in the LISP SRC FIB for the tunnel.
242  *
243  * @param[in]   src_fib_index   The index/ID of the SRC FIB
244  * @param[in]   src_prefix      Source IP prefix.
245  * @param[in]   paths           The paths from which to construct the
246  *                              load balance
247  */
248 void
249 ip_src_fib_add_route (u32 src_fib_index,
250                       const ip_prefix_t * src_prefix,
251                       const lisp_fwd_path_t * paths)
252 {
253   fib_prefix_t src_fib_prefix;
254   fib_route_path_t *rpaths;
255
256   ip_prefix_to_fib_prefix (src_prefix, &src_fib_prefix);
257
258   rpaths = ip_src_fib_mk_paths (paths);
259
260   fib_table_entry_update (src_fib_index,
261                           &src_fib_prefix,
262                           FIB_SOURCE_LISP, FIB_ENTRY_FLAG_NONE, rpaths);
263   vec_free (rpaths);
264 }
265
266 /*
267  * fd.io coding-style-patch-verification: ON
268  *
269  * Local Variables:
270  * eval: (c-set-style "gnu")
271  * End:
272  */