]> git.proxmox.com Git - mirror_frr.git/blob - staticd/static_zebra.c
Merge pull request #10953 from leonshaw/fix/bgp-rm-leak
[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 #include "static_debug.h"
46
47 DEFINE_MTYPE_STATIC(STATIC, STATIC_NHT_DATA, "Static Nexthop tracking data");
48 PREDECL_HASH(static_nht_hash);
49
50 struct static_nht_data {
51 struct static_nht_hash_item itm;
52
53 struct prefix nh;
54 safi_t safi;
55
56 vrf_id_t nh_vrf_id;
57
58 uint32_t refcount;
59 uint8_t nh_num;
60 };
61
62 static int static_nht_data_cmp(const struct static_nht_data *nhtd1,
63 const struct static_nht_data *nhtd2)
64 {
65 if (nhtd1->nh_vrf_id != nhtd2->nh_vrf_id)
66 return numcmp(nhtd1->nh_vrf_id, nhtd2->nh_vrf_id);
67 if (nhtd1->safi != nhtd2->safi)
68 return numcmp(nhtd1->safi, nhtd2->safi);
69
70 return prefix_cmp(&nhtd1->nh, &nhtd2->nh);
71 }
72
73 static unsigned int static_nht_data_hash(const struct static_nht_data *nhtd)
74 {
75 unsigned int key = 0;
76
77 key = prefix_hash_key(&nhtd->nh);
78 return jhash_2words(nhtd->nh_vrf_id, nhtd->safi, key);
79 }
80
81 DECLARE_HASH(static_nht_hash, struct static_nht_data, itm, static_nht_data_cmp,
82 static_nht_data_hash);
83
84 static struct static_nht_hash_head static_nht_hash[1];
85
86 /* Zebra structure to hold current status. */
87 struct zclient *zclient;
88 uint32_t zebra_ecmp_count = MULTIPATH_NUM;
89
90 /* Interface addition message from zebra. */
91 static int static_ifp_create(struct interface *ifp)
92 {
93 static_ifindex_update(ifp, true);
94
95 return 0;
96 }
97
98 static int static_ifp_destroy(struct interface *ifp)
99 {
100 static_ifindex_update(ifp, false);
101 return 0;
102 }
103
104 static int interface_address_add(ZAPI_CALLBACK_ARGS)
105 {
106 zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
107
108 return 0;
109 }
110
111 static int interface_address_delete(ZAPI_CALLBACK_ARGS)
112 {
113 struct connected *c;
114
115 c = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
116
117 if (!c)
118 return 0;
119
120 connected_free(&c);
121 return 0;
122 }
123
124 static int static_ifp_up(struct interface *ifp)
125 {
126 /* Install any static reliant on this interface coming up */
127 static_install_intf_nh(ifp);
128 static_ifindex_update(ifp, true);
129
130 return 0;
131 }
132
133 static int static_ifp_down(struct interface *ifp)
134 {
135 static_ifindex_update(ifp, false);
136
137 return 0;
138 }
139
140 static int route_notify_owner(ZAPI_CALLBACK_ARGS)
141 {
142 struct prefix p;
143 enum zapi_route_notify_owner note;
144 uint32_t table_id;
145 safi_t safi;
146
147 if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note, NULL,
148 &safi))
149 return -1;
150
151 switch (note) {
152 case ZAPI_ROUTE_FAIL_INSTALL:
153 static_nht_mark_state(&p, safi, vrf_id, STATIC_NOT_INSTALLED);
154 zlog_warn("%s: Route %pFX failed to install for table: %u",
155 __func__, &p, table_id);
156 break;
157 case ZAPI_ROUTE_BETTER_ADMIN_WON:
158 static_nht_mark_state(&p, safi, vrf_id, STATIC_NOT_INSTALLED);
159 zlog_warn(
160 "%s: Route %pFX over-ridden by better route for table: %u",
161 __func__, &p, table_id);
162 break;
163 case ZAPI_ROUTE_INSTALLED:
164 static_nht_mark_state(&p, safi, vrf_id, STATIC_INSTALLED);
165 break;
166 case ZAPI_ROUTE_REMOVED:
167 static_nht_mark_state(&p, safi, vrf_id, STATIC_NOT_INSTALLED);
168 break;
169 case ZAPI_ROUTE_REMOVE_FAIL:
170 static_nht_mark_state(&p, safi, vrf_id, STATIC_INSTALLED);
171 zlog_warn("%s: Route %pFX failure to remove for table: %u",
172 __func__, &p, table_id);
173 break;
174 }
175
176 return 0;
177 }
178 static void zebra_connected(struct zclient *zclient)
179 {
180 zclient_send_reg_requests(zclient, VRF_DEFAULT);
181 }
182
183 /* API to check whether the configured nexthop address is
184 * one of its local connected address or not.
185 */
186 static bool
187 static_nexthop_is_local(vrf_id_t vrfid, struct prefix *addr, int family)
188 {
189 if (family == AF_INET) {
190 if (if_address_is_local(&addr->u.prefix4, AF_INET, vrfid))
191 return true;
192 } else if (family == AF_INET6) {
193 if (if_address_is_local(&addr->u.prefix6, AF_INET6, vrfid))
194 return true;
195 }
196 return false;
197 }
198 static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS)
199 {
200 struct static_nht_data *nhtd, lookup;
201 struct zapi_route nhr;
202 struct prefix matched;
203 afi_t afi = AFI_IP;
204
205 if (!zapi_nexthop_update_decode(zclient->ibuf, &matched, &nhr)) {
206 zlog_err("Failure to decode nexthop update message");
207 return 1;
208 }
209
210 if (matched.family == AF_INET6)
211 afi = AFI_IP6;
212
213 if (nhr.type == ZEBRA_ROUTE_CONNECT) {
214 if (static_nexthop_is_local(vrf_id, &matched,
215 nhr.prefix.family))
216 nhr.nexthop_num = 0;
217 }
218
219 memset(&lookup, 0, sizeof(lookup));
220 lookup.nh = matched;
221 lookup.nh_vrf_id = vrf_id;
222 lookup.safi = nhr.safi;
223
224 nhtd = static_nht_hash_find(static_nht_hash, &lookup);
225
226 if (nhtd) {
227 nhtd->nh_num = nhr.nexthop_num;
228
229 static_nht_reset_start(&matched, afi, nhr.safi,
230 nhtd->nh_vrf_id);
231 static_nht_update(NULL, &matched, nhr.nexthop_num, afi,
232 nhr.safi, nhtd->nh_vrf_id);
233 } else
234 zlog_err("No nhtd?");
235
236 return 1;
237 }
238
239 static void static_zebra_capabilities(struct zclient_capabilities *cap)
240 {
241 mpls_enabled = cap->mpls_enabled;
242 zebra_ecmp_count = cap->ecmp;
243 }
244
245 static struct static_nht_data *
246 static_nht_hash_getref(const struct static_nht_data *ref)
247 {
248 struct static_nht_data *nhtd;
249
250 nhtd = static_nht_hash_find(static_nht_hash, ref);
251 if (!nhtd) {
252 nhtd = XCALLOC(MTYPE_STATIC_NHT_DATA, sizeof(*nhtd));
253
254 prefix_copy(&nhtd->nh, &ref->nh);
255 nhtd->nh_vrf_id = ref->nh_vrf_id;
256 nhtd->safi = ref->safi;
257
258 static_nht_hash_add(static_nht_hash, nhtd);
259 }
260
261 nhtd->refcount++;
262 return nhtd;
263 }
264
265 static bool static_nht_hash_decref(struct static_nht_data *nhtd)
266 {
267 if (--nhtd->refcount > 0)
268 return true;
269
270 static_nht_hash_del(static_nht_hash, nhtd);
271 XFREE(MTYPE_STATIC_NHT_DATA, nhtd);
272 return false;
273 }
274
275 static void static_nht_hash_clear(void)
276 {
277 struct static_nht_data *nhtd;
278
279 while ((nhtd = static_nht_hash_pop(static_nht_hash)))
280 XFREE(MTYPE_STATIC_NHT_DATA, nhtd);
281 }
282
283 void static_zebra_nht_register(struct static_nexthop *nh, bool reg)
284 {
285 struct static_path *pn = nh->pn;
286 struct route_node *rn = pn->rn;
287 struct static_route_info *si = static_route_info_from_rnode(rn);
288 struct static_nht_data lookup;
289 uint32_t cmd;
290 struct prefix p;
291 afi_t afi = AFI_IP;
292
293 cmd = (reg) ?
294 ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
295
296 if (nh->nh_registered && reg)
297 return;
298
299 if (!nh->nh_registered && !reg)
300 return;
301
302 memset(&p, 0, sizeof(p));
303 switch (nh->type) {
304 case STATIC_IFNAME:
305 case STATIC_BLACKHOLE:
306 return;
307 case STATIC_IPV4_GATEWAY:
308 case STATIC_IPV4_GATEWAY_IFNAME:
309 p.family = AF_INET;
310 p.prefixlen = IPV4_MAX_BITLEN;
311 p.u.prefix4 = nh->addr.ipv4;
312 afi = AFI_IP;
313 break;
314 case STATIC_IPV6_GATEWAY:
315 case STATIC_IPV6_GATEWAY_IFNAME:
316 p.family = AF_INET6;
317 p.prefixlen = IPV6_MAX_BITLEN;
318 p.u.prefix6 = nh->addr.ipv6;
319 afi = AFI_IP6;
320 break;
321 }
322
323 memset(&lookup, 0, sizeof(lookup));
324 lookup.nh = p;
325 lookup.nh_vrf_id = nh->nh_vrf_id;
326 lookup.safi = si->safi;
327
328 nh->nh_registered = reg;
329
330 if (reg) {
331 struct static_nht_data *nhtd;
332
333 nhtd = static_nht_hash_getref(&lookup);
334
335 if (nhtd->refcount > 1) {
336 DEBUGD(&static_dbg_route,
337 "Already registered nexthop(%pFX) for %pRN %d",
338 &p, rn, nhtd->nh_num);
339 if (nhtd->nh_num)
340 static_nht_update(&rn->p, &nhtd->nh,
341 nhtd->nh_num, afi, si->safi,
342 nh->nh_vrf_id);
343 return;
344 }
345 } else {
346 struct static_nht_data *nhtd;
347
348 nhtd = static_nht_hash_find(static_nht_hash, &lookup);
349 if (!nhtd)
350 return;
351 if (static_nht_hash_decref(nhtd))
352 return;
353 }
354
355 DEBUGD(&static_dbg_route, "%s nexthop(%pFX) for %pRN",
356 reg ? "Registering" : "Unregistering", &p, rn);
357
358 if (zclient_send_rnh(zclient, cmd, &p, si->safi, false, false,
359 nh->nh_vrf_id) == ZCLIENT_SEND_FAILURE)
360 zlog_warn("%s: Failure to send nexthop to zebra", __func__);
361 }
362 /*
363 * When nexthop gets updated via configuration then use the
364 * already registered NH and resend the route to zebra
365 */
366 int static_zebra_nh_update(struct static_nexthop *nh)
367 {
368 struct static_path *pn = nh->pn;
369 struct route_node *rn = pn->rn;
370 struct static_route_info *si = static_route_info_from_rnode(rn);
371 struct static_nht_data *nhtd, lookup = {};
372 struct prefix p = {};
373 afi_t afi = AFI_IP;
374
375 if (!nh->nh_registered)
376 return 0;
377
378 switch (nh->type) {
379 case STATIC_IFNAME:
380 case STATIC_BLACKHOLE:
381 return 0;
382 case STATIC_IPV4_GATEWAY:
383 case STATIC_IPV4_GATEWAY_IFNAME:
384 p.family = AF_INET;
385 p.prefixlen = IPV4_MAX_BITLEN;
386 p.u.prefix4 = nh->addr.ipv4;
387 afi = AFI_IP;
388 break;
389 case STATIC_IPV6_GATEWAY:
390 case STATIC_IPV6_GATEWAY_IFNAME:
391 p.family = AF_INET6;
392 p.prefixlen = IPV6_MAX_BITLEN;
393 p.u.prefix6 = nh->addr.ipv6;
394 afi = AFI_IP6;
395 break;
396 }
397
398 lookup.nh = p;
399 lookup.nh_vrf_id = nh->nh_vrf_id;
400 lookup.safi = si->safi;
401
402 nhtd = static_nht_hash_find(static_nht_hash, &lookup);
403 if (nhtd && nhtd->nh_num) {
404 nh->state = STATIC_START;
405 static_nht_update(&rn->p, &nhtd->nh, nhtd->nh_num, afi,
406 si->safi, nh->nh_vrf_id);
407 return 1;
408 }
409 return 0;
410 }
411
412 extern void static_zebra_route_add(struct static_path *pn, bool install)
413 {
414 struct route_node *rn = pn->rn;
415 struct static_route_info *si = rn->info;
416 struct static_nexthop *nh;
417 const struct prefix *p, *src_pp;
418 struct zapi_nexthop *api_nh;
419 struct zapi_route api;
420 uint32_t nh_num = 0;
421
422 p = src_pp = NULL;
423 srcdest_rnode_prefixes(rn, &p, &src_pp);
424
425 memset(&api, 0, sizeof(api));
426 api.vrf_id = si->svrf->vrf->vrf_id;
427 api.type = ZEBRA_ROUTE_STATIC;
428 api.safi = si->safi;
429 memcpy(&api.prefix, p, sizeof(api.prefix));
430
431 if (src_pp) {
432 SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
433 memcpy(&api.src_prefix, src_pp, sizeof(api.src_prefix));
434 }
435 SET_FLAG(api.flags, ZEBRA_FLAG_RR_USE_DISTANCE);
436 SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
437 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
438 if (pn->distance) {
439 SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
440 api.distance = pn->distance;
441 }
442 if (pn->tag) {
443 SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
444 api.tag = pn->tag;
445 }
446 if (pn->table_id != 0) {
447 SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
448 api.tableid = pn->table_id;
449 }
450 frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
451 /* Don't overrun the nexthop array */
452 if (nh_num == zebra_ecmp_count)
453 break;
454
455 api_nh = &api.nexthops[nh_num];
456 if (nh->nh_vrf_id == VRF_UNKNOWN)
457 continue;
458
459 api_nh->vrf_id = nh->nh_vrf_id;
460 if (nh->onlink)
461 SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
462 if (nh->color != 0) {
463 SET_FLAG(api.message, ZAPI_MESSAGE_SRTE);
464 api_nh->srte_color = nh->color;
465 }
466
467 nh->state = STATIC_SENT_TO_ZEBRA;
468
469 switch (nh->type) {
470 case STATIC_IFNAME:
471 if (nh->ifindex == IFINDEX_INTERNAL)
472 continue;
473 api_nh->ifindex = nh->ifindex;
474 api_nh->type = NEXTHOP_TYPE_IFINDEX;
475 break;
476 case STATIC_IPV4_GATEWAY:
477 if (!nh->nh_valid)
478 continue;
479 api_nh->type = NEXTHOP_TYPE_IPV4;
480 api_nh->gate = nh->addr;
481 break;
482 case STATIC_IPV4_GATEWAY_IFNAME:
483 if (nh->ifindex == IFINDEX_INTERNAL)
484 continue;
485 api_nh->ifindex = nh->ifindex;
486 api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
487 api_nh->gate = nh->addr;
488 break;
489 case STATIC_IPV6_GATEWAY:
490 if (!nh->nh_valid)
491 continue;
492 api_nh->type = NEXTHOP_TYPE_IPV6;
493 api_nh->gate = nh->addr;
494 break;
495 case STATIC_IPV6_GATEWAY_IFNAME:
496 if (nh->ifindex == IFINDEX_INTERNAL)
497 continue;
498 api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
499 api_nh->ifindex = nh->ifindex;
500 api_nh->gate = nh->addr;
501 break;
502 case STATIC_BLACKHOLE:
503 api_nh->type = NEXTHOP_TYPE_BLACKHOLE;
504 switch (nh->bh_type) {
505 case STATIC_BLACKHOLE_DROP:
506 case STATIC_BLACKHOLE_NULL:
507 api_nh->bh_type = BLACKHOLE_NULL;
508 break;
509 case STATIC_BLACKHOLE_REJECT:
510 api_nh->bh_type = BLACKHOLE_REJECT;
511 }
512 break;
513 }
514
515 if (nh->snh_label.num_labels) {
516 int i;
517
518 SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL);
519 api_nh->label_num = nh->snh_label.num_labels;
520 for (i = 0; i < api_nh->label_num; i++)
521 api_nh->labels[i] = nh->snh_label.label[i];
522 }
523 nh_num++;
524 }
525
526 api.nexthop_num = nh_num;
527
528 /*
529 * If we have been given an install but nothing is valid
530 * go ahead and delete the route for double plus fun
531 */
532 if (!nh_num && install)
533 install = false;
534
535 zclient_route_send(install ?
536 ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE,
537 zclient, &api);
538 }
539
540 static zclient_handler *const static_handlers[] = {
541 [ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add,
542 [ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete,
543 [ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner,
544 [ZEBRA_NEXTHOP_UPDATE] = static_zebra_nexthop_update,
545 };
546
547 void static_zebra_init(void)
548 {
549 struct zclient_options opt = { .receive_notify = true };
550
551 if_zapi_callbacks(static_ifp_create, static_ifp_up,
552 static_ifp_down, static_ifp_destroy);
553
554 zclient = zclient_new(master, &opt, static_handlers,
555 array_size(static_handlers));
556
557 zclient_init(zclient, ZEBRA_ROUTE_STATIC, 0, &static_privs);
558 zclient->zebra_capabilities = static_zebra_capabilities;
559 zclient->zebra_connected = zebra_connected;
560
561 static_nht_hash_init(static_nht_hash);
562 }
563
564 /* static_zebra_stop used by tests/lib/test_grpc.cpp */
565 void static_zebra_stop(void)
566 {
567 static_nht_hash_clear();
568 static_nht_hash_fini(static_nht_hash);
569
570 if (!zclient)
571 return;
572 zclient_stop(zclient);
573 zclient_free(zclient);
574 zclient = NULL;
575 }
576
577 void static_zebra_vrf_register(struct vrf *vrf)
578 {
579 if (vrf->vrf_id == VRF_DEFAULT)
580 return;
581 zclient_send_reg_requests(zclient, vrf->vrf_id);
582 }
583
584 void static_zebra_vrf_unregister(struct vrf *vrf)
585 {
586 if (vrf->vrf_id == VRF_DEFAULT)
587 return;
588 zclient_send_dereg_requests(zclient, vrf->vrf_id);
589 }