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