]> git.proxmox.com Git - mirror_frr.git/blob - staticd/static_zebra.c
Merge pull request #3775 from pguibert6WIND/ospf_missing_interface_handling_2
[mirror_frr.git] / staticd / static_zebra.c
1 /*
2 * Zebra connect code.
3 * Copyright (C) 2018 Cumulus Networks, Inc.
4 * Donald Sharp
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 #include <zebra.h>
21
22 #include "thread.h"
23 #include "command.h"
24 #include "network.h"
25 #include "prefix.h"
26 #include "routemap.h"
27 #include "table.h"
28 #include "srcdest_table.h"
29 #include "stream.h"
30 #include "memory.h"
31 #include "zclient.h"
32 #include "filter.h"
33 #include "plist.h"
34 #include "log.h"
35 #include "nexthop.h"
36 #include "nexthop_group.h"
37 #include "hash.h"
38 #include "jhash.h"
39
40 #include "static_vrf.h"
41 #include "static_routes.h"
42 #include "static_zebra.h"
43 #include "static_nht.h"
44 #include "static_vty.h"
45
46 /* Zebra structure to hold current status. */
47 struct zclient *zclient;
48 static struct hash *static_nht_hash;
49
50 static struct interface *zebra_interface_if_lookup(struct stream *s, vrf_id_t vrf_id)
51 {
52 char ifname_tmp[INTERFACE_NAMSIZ];
53
54 /* Read interface name. */
55 stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
56
57 /* And look it up. */
58 return if_lookup_by_name(ifname_tmp,
59 vrf_lookup_by_id(vrf_id));
60 }
61
62 /* Inteface addition message from zebra. */
63 static int interface_add(ZAPI_CALLBACK_ARGS)
64 {
65 struct interface *ifp;
66
67 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
68
69 if (!ifp)
70 return 0;
71
72 static_ifindex_update(ifp, true);
73 return 0;
74 }
75
76 static int interface_delete(ZAPI_CALLBACK_ARGS)
77 {
78 struct interface *ifp;
79 struct stream *s;
80
81 s = zclient->ibuf;
82 /* zebra_interface_state_read () updates interface structure in iflist
83 */
84 ifp = zebra_interface_state_read(s, vrf_id);
85
86 if (ifp == NULL)
87 return 0;
88
89 if_set_index(ifp, IFINDEX_INTERNAL);
90
91 static_ifindex_update(ifp, false);
92 return 0;
93 }
94
95 static int interface_address_add(ZAPI_CALLBACK_ARGS)
96 {
97 zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
98
99 return 0;
100 }
101
102 static int interface_address_delete(ZAPI_CALLBACK_ARGS)
103 {
104 struct connected *c;
105
106 c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
107
108 if (!c)
109 return 0;
110
111 connected_free(c);
112 return 0;
113 }
114
115 static int interface_state_up(ZAPI_CALLBACK_ARGS)
116 {
117 struct interface *ifp;
118
119 ifp = zebra_interface_if_lookup(zclient->ibuf, vrf_id);
120
121 if (ifp) {
122 if (if_is_vrf(ifp)) {
123 struct static_vrf *svrf =
124 static_vrf_lookup_by_id(vrf_id);
125
126 static_fixup_vrf_ids(svrf);
127 static_config_install_delayed_routes(svrf);
128 }
129
130 /* Install any static reliant on this interface coming up */
131 static_install_intf_nh(ifp);
132 }
133
134 return 0;
135 }
136
137 static int interface_state_down(ZAPI_CALLBACK_ARGS)
138 {
139 zebra_interface_state_read(zclient->ibuf, vrf_id);
140
141 return 0;
142 }
143
144 static int route_notify_owner(ZAPI_CALLBACK_ARGS)
145 {
146 struct prefix p;
147 enum zapi_route_notify_owner note;
148 uint32_t table_id;
149 char buf[PREFIX_STRLEN];
150
151 if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note))
152 return -1;
153
154 prefix2str(&p, buf, sizeof(buf));
155
156 switch (note) {
157 case ZAPI_ROUTE_FAIL_INSTALL:
158 zlog_warn("%s: Route %s failed to install for table: %u",
159 __PRETTY_FUNCTION__, buf, table_id);
160 break;
161 case ZAPI_ROUTE_BETTER_ADMIN_WON:
162 zlog_warn("%s: Route %s over-ridden by better route for table: %u",
163 __PRETTY_FUNCTION__, buf, table_id);
164 break;
165 case ZAPI_ROUTE_INSTALLED:
166 break;
167 case ZAPI_ROUTE_REMOVED:
168 break;
169 case ZAPI_ROUTE_REMOVE_FAIL:
170 zlog_warn("%s: Route %s failure to remove for table: %u",
171 __PRETTY_FUNCTION__, buf, table_id);
172 break;
173 }
174
175 return 0;
176 }
177 static void zebra_connected(struct zclient *zclient)
178 {
179 zclient_send_reg_requests(zclient, VRF_DEFAULT);
180 }
181
182 struct static_nht_data {
183 struct prefix *nh;
184
185 vrf_id_t nh_vrf_id;
186
187 uint32_t refcount;
188 uint8_t nh_num;
189 };
190
191 static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS)
192 {
193 struct static_nht_data *nhtd, lookup;
194 struct zapi_route nhr;
195 afi_t afi = AFI_IP;
196
197 if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
198 zlog_warn("Failure to decode nexthop update message");
199 return 1;
200 }
201
202 if (nhr.prefix.family == AF_INET6)
203 afi = AFI_IP6;
204
205 memset(&lookup, 0, sizeof(lookup));
206 lookup.nh = &nhr.prefix;
207 lookup.nh_vrf_id = vrf_id;
208
209 nhtd = hash_lookup(static_nht_hash, &lookup);
210
211 if (nhtd) {
212 nhtd->nh_num = nhr.nexthop_num;
213
214 static_nht_update(&nhr.prefix, nhr.nexthop_num, afi,
215 nhtd->nh_vrf_id);
216 } else
217 zlog_err("No nhtd?");
218
219 return 1;
220 }
221
222 static void static_zebra_capabilities(struct zclient_capabilities *cap)
223 {
224 mpls_enabled = cap->mpls_enabled;
225 }
226
227 static unsigned int static_nht_hash_key(const void *data)
228 {
229 const struct static_nht_data *nhtd = data;
230 unsigned int key = 0;
231
232 key = prefix_hash_key(nhtd->nh);
233 return jhash_1word(nhtd->nh_vrf_id, key);
234 }
235
236 static bool static_nht_hash_cmp(const void *d1, const void *d2)
237 {
238 const struct static_nht_data *nhtd1 = d1;
239 const struct static_nht_data *nhtd2 = d2;
240
241 if (nhtd1->nh_vrf_id != nhtd2->nh_vrf_id)
242 return false;
243
244 return prefix_same(nhtd1->nh, nhtd2->nh);
245 }
246
247 static void *static_nht_hash_alloc(void *data)
248 {
249 struct static_nht_data *copy = data;
250 struct static_nht_data *new;
251
252 new = XMALLOC(MTYPE_TMP, sizeof(*new));
253
254 new->nh = prefix_new();
255 prefix_copy(new->nh, copy->nh);
256 new->refcount = 0;
257 new->nh_num = 0;
258 new->nh_vrf_id = copy->nh_vrf_id;
259
260 return new;
261 }
262
263 static void static_nht_hash_free(void *data)
264 {
265 struct static_nht_data *nhtd = data;
266
267 prefix_free(nhtd->nh);
268 XFREE(MTYPE_TMP, nhtd);
269 }
270
271 void static_zebra_nht_register(struct static_route *si, bool reg)
272 {
273 struct static_nht_data *nhtd, lookup;
274 uint32_t cmd;
275 struct prefix p;
276 afi_t afi = AFI_IP;
277
278 cmd = (reg) ?
279 ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
280
281 if (si->nh_registered && reg)
282 return;
283
284 if (!si->nh_registered && !reg)
285 return;
286
287 memset(&p, 0, sizeof(p));
288 switch (si->type) {
289 case STATIC_IFNAME:
290 case STATIC_BLACKHOLE:
291 return;
292 case STATIC_IPV4_GATEWAY:
293 case STATIC_IPV4_GATEWAY_IFNAME:
294 p.family = AF_INET;
295 p.prefixlen = IPV4_MAX_BITLEN;
296 p.u.prefix4 = si->addr.ipv4;
297 afi = AFI_IP;
298 break;
299 case STATIC_IPV6_GATEWAY:
300 case STATIC_IPV6_GATEWAY_IFNAME:
301 p.family = AF_INET6;
302 p.prefixlen = IPV6_MAX_BITLEN;
303 p.u.prefix6 = si->addr.ipv6;
304 afi = AFI_IP6;
305 break;
306 }
307
308 memset(&lookup, 0, sizeof(lookup));
309 lookup.nh = &p;
310 lookup.nh_vrf_id = si->nh_vrf_id;
311
312 si->nh_registered = reg;
313
314 if (reg) {
315 nhtd = hash_get(static_nht_hash, &lookup,
316 static_nht_hash_alloc);
317 nhtd->refcount++;
318
319 if (nhtd->refcount > 1) {
320 static_nht_update(nhtd->nh, nhtd->nh_num,
321 afi, si->nh_vrf_id);
322 return;
323 }
324 } else {
325 nhtd = hash_lookup(static_nht_hash, &lookup);
326 if (!nhtd)
327 return;
328
329 nhtd->refcount--;
330 if (nhtd->refcount >= 1)
331 return;
332
333 hash_release(static_nht_hash, nhtd);
334 static_nht_hash_free(nhtd);
335 }
336
337 if (zclient_send_rnh(zclient, cmd, &p, false, si->nh_vrf_id) < 0)
338 zlog_warn("%s: Failure to send nexthop to zebra",
339 __PRETTY_FUNCTION__);
340 }
341
342 extern void static_zebra_route_add(struct route_node *rn,
343 struct static_route *si_changed,
344 vrf_id_t vrf_id, safi_t safi, bool install)
345 {
346 struct static_route *si = rn->info;
347 const struct prefix *p, *src_pp;
348 struct zapi_nexthop *api_nh;
349 struct zapi_route api;
350 uint32_t nh_num = 0;
351
352 p = src_pp = NULL;
353 srcdest_rnode_prefixes(rn, &p, &src_pp);
354
355 memset(&api, 0, sizeof(api));
356 api.vrf_id = vrf_id;
357 api.type = ZEBRA_ROUTE_STATIC;
358 api.safi = safi;
359 memcpy(&api.prefix, p, sizeof(api.prefix));
360
361 if (src_pp) {
362 SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
363 memcpy(&api.src_prefix, src_pp, sizeof(api.src_prefix));
364 }
365 SET_FLAG(api.flags, ZEBRA_FLAG_RR_USE_DISTANCE);
366 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
367 if (si_changed->distance) {
368 SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
369 api.distance = si_changed->distance;
370 }
371 if (si_changed->tag) {
372 SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
373 api.tag = si_changed->tag;
374 }
375 if (si_changed->table_id != 0) {
376 SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
377 api.tableid = si_changed->table_id;
378 }
379 for (/*loaded above*/; si; si = si->next) {
380 api_nh = &api.nexthops[nh_num];
381 if (si->nh_vrf_id == VRF_UNKNOWN)
382 continue;
383
384 if (si->distance != si_changed->distance)
385 continue;
386
387 if (si->table_id != si_changed->table_id)
388 continue;
389
390 api_nh->vrf_id = si->nh_vrf_id;
391 api_nh->onlink = si->onlink;
392
393 switch (si->type) {
394 case STATIC_IFNAME:
395 if (si->ifindex == IFINDEX_INTERNAL)
396 continue;
397 api_nh->ifindex = si->ifindex;
398 api_nh->type = NEXTHOP_TYPE_IFINDEX;
399 break;
400 case STATIC_IPV4_GATEWAY:
401 if (!si->nh_valid)
402 continue;
403 api_nh->type = NEXTHOP_TYPE_IPV4;
404 api_nh->gate = si->addr;
405 break;
406 case STATIC_IPV4_GATEWAY_IFNAME:
407 if (si->ifindex == IFINDEX_INTERNAL)
408 continue;
409 api_nh->ifindex = si->ifindex;
410 api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
411 api_nh->gate = si->addr;
412 break;
413 case STATIC_IPV6_GATEWAY:
414 if (!si->nh_valid)
415 continue;
416 api_nh->type = NEXTHOP_TYPE_IPV6;
417 api_nh->gate = si->addr;
418 break;
419 case STATIC_IPV6_GATEWAY_IFNAME:
420 if (si->ifindex == IFINDEX_INTERNAL)
421 continue;
422 api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
423 api_nh->ifindex = si->ifindex;
424 api_nh->gate = si->addr;
425 break;
426 case STATIC_BLACKHOLE:
427 api_nh->type = NEXTHOP_TYPE_BLACKHOLE;
428 switch (si->bh_type) {
429 case STATIC_BLACKHOLE_DROP:
430 case STATIC_BLACKHOLE_NULL:
431 api_nh->bh_type = BLACKHOLE_NULL;
432 break;
433 case STATIC_BLACKHOLE_REJECT:
434 api_nh->bh_type = BLACKHOLE_REJECT;
435 }
436 break;
437 }
438
439 if (si->snh_label.num_labels) {
440 int i;
441
442 SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
443 api_nh->label_num = si->snh_label.num_labels;
444 for (i = 0; i < api_nh->label_num; i++)
445 api_nh->labels[i] = si->snh_label.label[i];
446 }
447 nh_num++;
448 }
449
450 api.nexthop_num = nh_num;
451
452 /*
453 * If we have been given an install but nothing is valid
454 * go ahead and delete the route for double plus fun
455 */
456 if (!nh_num && install)
457 install = false;
458
459 zclient_route_send(install ?
460 ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
461 zclient, &api);
462 }
463 void static_zebra_init(void)
464 {
465 struct zclient_options opt = { .receive_notify = true };
466
467 zclient = zclient_new(master, &opt);
468
469 zclient_init(zclient, ZEBRA_ROUTE_STATIC, 0, &static_privs);
470 zclient->zebra_capabilities = static_zebra_capabilities;
471 zclient->zebra_connected = zebra_connected;
472 zclient->interface_add = interface_add;
473 zclient->interface_delete = interface_delete;
474 zclient->interface_up = interface_state_up;
475 zclient->interface_down = interface_state_down;
476 zclient->interface_address_add = interface_address_add;
477 zclient->interface_address_delete = interface_address_delete;
478 zclient->route_notify_owner = route_notify_owner;
479 zclient->nexthop_update = static_zebra_nexthop_update;
480
481 static_nht_hash = hash_create(static_nht_hash_key,
482 static_nht_hash_cmp,
483 "Static Nexthop Tracking hash");
484 }