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