gre: Multi-point interfaces
[vpp.git] / src / vnet / nhrp / nhrp.c
1 /*
2  * nhrp.h: next-hop resolution
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
19 #include <vnet/nhrp/nhrp.h>
20 #include <vnet/fib/fib_table.h>
21 #include <vnet/adj/adj_midchain.h>
22
23 static uword *nhrp_db;
24 static nhrp_entry_t *nhrp_pool;
25
26 void
27 nhrp_entry_adj_stack (const nhrp_entry_t * ne, adj_index_t ai)
28 {
29   adj_midchain_delegate_stack (ai, ne->ne_fib_index, &ne->ne_nh);
30 }
31
32 static adj_walk_rc_t
33 nhrp_entry_add_adj_walk (adj_index_t ai, void *ctx)
34 {
35   nhrp_entry_adj_stack (ctx, ai);
36
37   return (ADJ_WALK_RC_CONTINUE);
38 }
39
40 static adj_walk_rc_t
41 nhrp_entry_del_adj_walk (adj_index_t ai, void *ctx)
42 {
43   adj_midchain_delegate_unstack (ai);
44
45   return (ADJ_WALK_RC_CONTINUE);
46 }
47
48 nhrp_entry_t *
49 nhrp_entry_get (index_t nei)
50 {
51   return pool_elt_at_index (nhrp_pool, nei);
52 }
53
54 nhrp_entry_t *
55 nhrp_entry_find (u32 sw_if_index, const ip46_address_t * peer)
56 {
57   nhrp_key_t nk = {
58     .nk_peer = *peer,
59     .nk_sw_if_index = sw_if_index,
60   };
61   uword *p;
62
63   p = hash_get_mem (nhrp_db, &nk);
64
65   if (NULL != p)
66     return nhrp_entry_get (p[0]);
67
68   return (NULL);
69 }
70
71 int
72 nhrp_entry_add (u32 sw_if_index,
73                 const ip46_address_t * peer,
74                 u32 nh_table_id, const ip46_address_t * nh)
75 {
76   fib_protocol_t fproto;
77   nhrp_entry_t *ne;
78   u32 fib_index;
79   index_t nei;
80
81   fproto = (ip46_address_is_ip4 (nh) ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6);
82
83   fib_index = fib_table_find (fproto, nh_table_id);
84
85   if (~0 == fib_index)
86     {
87       return (VNET_API_ERROR_NO_SUCH_FIB);
88     }
89
90   ne = nhrp_entry_find (sw_if_index, peer);
91
92   if (NULL == ne)
93     {
94       nhrp_key_t nk = {
95         .nk_peer = *peer,
96         .nk_sw_if_index = sw_if_index,
97       };
98       nhrp_entry_t *ne;
99
100       pool_get_zero (nhrp_pool, ne);
101
102       nei = ne - nhrp_pool;
103       ne->ne_key = clib_mem_alloc (sizeof (*ne->ne_key));
104       clib_memcpy (ne->ne_key, &nk, sizeof (*ne->ne_key));
105
106       ip46_address_copy (&ne->ne_nh.fp_addr, nh);
107       ne->ne_nh.fp_proto = fproto;
108       ne->ne_nh.fp_len = (ne->ne_nh.fp_proto == FIB_PROTOCOL_IP4 ? 32 : 128);
109       ne->ne_fib_index = fib_index;
110
111       hash_set_mem (nhrp_db, ne->ne_key, nei);
112
113       adj_nbr_walk_nh (sw_if_index,
114                        ne->ne_nh.fp_proto,
115                        &ne->ne_key->nk_peer, nhrp_entry_add_adj_walk, ne);
116     }
117   else
118     return (VNET_API_ERROR_ENTRY_ALREADY_EXISTS);
119
120   return 0;
121 }
122
123 int
124 nhrp_entry_del (u32 sw_if_index, const ip46_address_t * peer)
125 {
126   nhrp_entry_t *ne;
127
128   ne = nhrp_entry_find (sw_if_index, peer);
129
130   if (ne != NULL)
131     {
132       hash_unset_mem (nhrp_db, ne->ne_key);
133
134       adj_nbr_walk_nh (sw_if_index,
135                        ne->ne_nh.fp_proto,
136                        &ne->ne_key->nk_peer, nhrp_entry_del_adj_walk, ne);
137
138       clib_mem_free (ne->ne_key);
139       pool_put (nhrp_pool, ne);
140     }
141   else
142     return (VNET_API_ERROR_ENTRY_ALREADY_EXISTS);
143
144   return 0;
145 }
146
147 u8 *
148 format_nhrp_entry (u8 * s, va_list * args)
149 {
150   index_t nei = va_arg (*args, index_t);
151   vnet_main_t *vnm = vnet_get_main ();
152   nhrp_entry_t *ne;
153
154   ne = nhrp_entry_get (nei);
155
156   s = format (s, "[%d] ", nei);
157   s = format (s, "%U:%U ", format_vnet_sw_if_index_name,
158               vnm, ne->ne_key->nk_sw_if_index,
159               format_ip46_address, &ne->ne_key->nk_peer, IP46_TYPE_ANY);
160   s = format (s, "via %d:%U",
161               fib_table_get_table_id (ne->ne_fib_index, ne->ne_nh.fp_proto),
162               format_fib_prefix, &ne->ne_nh);
163
164   return (s);
165 }
166
167 void
168 nhrp_walk (nhrp_walk_cb_t fn, void *ctx)
169 {
170   index_t nei;
171
172   /* *INDENT-OFF* */
173   pool_foreach_index(nei, nhrp_pool,
174   ({
175     fn(nei, ctx);
176   }));
177   /* *INDENT-ON* */
178 }
179
180 static clib_error_t *
181 nhrp_init (vlib_main_t * vm)
182 {
183   nhrp_db = hash_create_mem (0, sizeof (nhrp_key_t), sizeof (u32));
184
185   return (NULL);
186 }
187
188 VLIB_INIT_FUNCTION (nhrp_init);
189
190 /*
191  * fd.io coding-style-patch-verification: ON
192  *
193  * Local Variables:
194  * eval: (c-set-style "gnu")
195  * End:
196  */