blob: da2deea65f62476a39f75fd67239d5d47f4e3ed8 [file] [log] [blame]
Neale Ranns2dd68522017-02-16 03:38:59 -08001/*
2 * proxy_node.c: common dhcp v4 and v6 proxy node processing
3 *
4 * Copyright (c) 2013 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/dhcp/dhcp_proxy.h>
19#include <vnet/fib/fib_table.h>
20
21/**
22 * @brief Shard 4/6 instance of DHCP main
23 */
24dhcp_proxy_main_t dhcp_proxy_main;
25
26void
27dhcp_proxy_walk (fib_protocol_t proto,
28 dhcp_proxy_walk_fn_t fn,
29 void *ctx)
30{
31 dhcp_proxy_main_t * dpm = &dhcp_proxy_main;
32 dhcp_server_t * server;
33 u32 server_index, i;
34
35 vec_foreach_index (i, dpm->dhcp_server_index_by_rx_fib_index[proto])
36 {
37 server_index = dpm->dhcp_server_index_by_rx_fib_index[proto][i];
38 if (~0 == server_index)
39 continue;
40
41 server = pool_elt_at_index (dpm->dhcp_servers[proto], server_index);
42
43 if (!fn(server, ctx))
44 break;
45 }
46}
47
48void
49dhcp_vss_walk (fib_protocol_t proto,
50 dhcp_vss_walk_fn_t fn,
51 void *ctx)
52{
53 dhcp_proxy_main_t * dpm = &dhcp_proxy_main;
54 dhcp_vss_t * vss;
55 u32 vss_index, i;
56 fib_table_t *fib;
57
58
59 vec_foreach_index (i, dpm->vss_index_by_rx_fib_index[proto])
60 {
61 vss_index = dpm->vss_index_by_rx_fib_index[proto][i];
62 if (~0 == vss_index)
63 continue;
64
65 vss = pool_elt_at_index (dpm->vss[proto], vss_index);
66
67 fib = fib_table_get(i, proto);
68
69 if (!fn(vss, fib->ft_table_id, ctx))
70 break;
71 }
72}
73
74int
75dhcp_proxy_server_del (fib_protocol_t proto,
76 u32 rx_fib_index)
77{
78 dhcp_proxy_main_t * dpm = &dhcp_proxy_main;
79 dhcp_server_t * server = 0;
80 int rc = 0;
81
82 server = dhcp_get_server(dpm, rx_fib_index, proto);
83
84 if (NULL == server)
85 {
86 rc = VNET_API_ERROR_NO_SUCH_ENTRY;
87 }
88 else
89 {
90 /* Use the default server again. */
91 dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] = ~0;
92
93 fib_table_unlock (server->server_fib_index, proto);
94
95 pool_put (dpm->dhcp_servers[proto], server);
96 }
97
98 return (rc);
99}
100
101int
102dhcp_proxy_server_add (fib_protocol_t proto,
103 ip46_address_t *addr,
104 ip46_address_t *src_address,
105 u32 rx_fib_index,
106 u32 server_table_id)
107{
108 dhcp_proxy_main_t * dpm = &dhcp_proxy_main;
109 dhcp_server_t * server = 0;
110 int new = 0;
111
112 server = dhcp_get_server(dpm, rx_fib_index, proto);
113
114 if (NULL == server)
115 {
116 vec_validate_init_empty(dpm->dhcp_server_index_by_rx_fib_index[proto],
117 rx_fib_index,
118 ~0);
119
120 pool_get (dpm->dhcp_servers[proto], server);
121 memset (server, 0, sizeof (*server));
122 new = 1;
123
124 dpm->dhcp_server_index_by_rx_fib_index[proto][rx_fib_index] =
125 server - dpm->dhcp_servers[proto];
126
127 server->rx_fib_index = rx_fib_index;
128 server->server_fib_index =
129 fib_table_find_or_create_and_lock(proto, server_table_id);
130 }
131 else
132 {
133 /* modify, may need to swap server FIBs */
134 u32 tmp_index;
135
136 tmp_index = fib_table_find(proto, server_table_id);
137
138 if (tmp_index != server->server_fib_index)
139 {
140 tmp_index = server->server_fib_index;
141
142 /* certainly swapping if the fib doesn't exist */
143 server->server_fib_index =
144 fib_table_find_or_create_and_lock(proto, server_table_id);
145 fib_table_unlock (tmp_index, proto);
146 }
147 }
148
149 server->dhcp_server = *addr;
150 server->dhcp_src_address = *src_address;
151
152 return (new);
153}
154
155typedef struct dhcp4_proxy_dump_walk_ctx_t_
156{
157 fib_protocol_t proto;
158 void *opaque;
159 u32 context;
160} dhcp_proxy_dump_walk_cxt_t;
161
162static int
163dhcp_proxy_dump_walk (dhcp_server_t *server,
164 void *arg)
165{
166 dhcp_proxy_dump_walk_cxt_t *ctx = arg;
167 fib_table_t *s_fib, *r_fib;
168 dhcp_vss_t *v;
169
170 v = dhcp_get_vss_info(&dhcp_proxy_main,
171 server->rx_fib_index,
172 ctx->proto);
173
174 s_fib = fib_table_get(server->server_fib_index, ctx->proto);
175 r_fib = fib_table_get(server->rx_fib_index, ctx->proto);
176
177 dhcp_send_details(ctx->proto,
178 ctx->opaque,
179 ctx->context,
180 &server->dhcp_server,
181 &server->dhcp_src_address,
182 s_fib->ft_table_id,
183 r_fib->ft_table_id,
184 (v ? v->fib_id : 0),
185 (v ? v->oui : 0));
186
187 return (1);
188}
189
190void
191dhcp_proxy_dump (fib_protocol_t proto,
192 void *opaque,
193 u32 context)
194{
195 dhcp_proxy_dump_walk_cxt_t ctx = {
196 .proto = proto,
197 .opaque = opaque,
198 .context = context,
199 };
200 dhcp_proxy_walk(proto, dhcp_proxy_dump_walk, &ctx);
201}
202
203int
204dhcp_vss_show_walk (dhcp_vss_t *vss,
205 u32 rx_table_id,
206 void *ctx)
207{
208 vlib_main_t * vm = ctx;
209
210 vlib_cli_output (vm, "%=6d%=6d%=12d",
211 rx_table_id,
212 vss->oui,
213 vss->fib_id);
214
215 return (1);
216}
217
218int dhcp_proxy_set_vss (fib_protocol_t proto,
219 u32 tbl_id,
220 u32 oui,
221 u32 fib_id,
222 int is_del)
223{
224 dhcp_proxy_main_t *dm = &dhcp_proxy_main;
225 dhcp_vss_t *v = NULL;
226 u32 rx_fib_index;
227 int rc = 0;
228
229 rx_fib_index = fib_table_find_or_create_and_lock(proto, tbl_id);
230 v = dhcp_get_vss_info(dm, rx_fib_index, proto);
231
232 if (NULL != v)
233 {
234 if (is_del)
235 {
236 /* release the lock held on the table when the VSS
237 * info was created */
238 fib_table_unlock (rx_fib_index, proto);
239
240 pool_put (dm->vss[proto], v);
241 dm->vss_index_by_rx_fib_index[proto][rx_fib_index] = ~0;
242 }
243 else
244 {
245 /* this is a modify */
246 v->fib_id = fib_id;
247 v->oui = oui;
248 }
249 }
250 else
251 {
252 if (is_del)
253 rc = VNET_API_ERROR_NO_SUCH_ENTRY;
254 else
255 {
256 /* create a new entry */
257 vec_validate_init_empty(dm->vss_index_by_rx_fib_index[proto],
258 rx_fib_index, ~0);
259
260 /* hold a lock on the table whilst the VSS info exist */
261 fib_table_lock (rx_fib_index, proto);
262
263 pool_get (dm->vss[proto], v);
264 v->fib_id = fib_id;
265 v->oui = oui;
266 dm->vss_index_by_rx_fib_index[proto][rx_fib_index] =
267 v - dm->vss[proto];
268 }
269 }
270
271 /* Release the lock taken during the create_or_lock at the start */
272 fib_table_unlock (rx_fib_index, proto);
273
274 return (rc);
275}