]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/ldp_zebra.c
*: Add infrastructure to support zapi interface callbacks
[mirror_frr.git] / ldpd / ldp_zebra.c
CommitLineData
eac6e3f0
RW
1/*
2 * Copyright (C) 2016 by Open Source Routing.
3 *
180fc2cd
RW
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
eac6e3f0 8 *
180fc2cd 9 * This program is distributed in the hope that it will be useful, but
eac6e3f0
RW
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
180fc2cd
RW
14 * You should have received a copy of the GNU General Public License
15 * along with this program; see the file COPYING; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
17 * MA 02110-1301 USA
eac6e3f0
RW
18 */
19
20#include <zebra.h>
21
22#include "prefix.h"
23#include "stream.h"
24#include "memory.h"
25#include "zclient.h"
26#include "command.h"
27#include "network.h"
28#include "linklist.h"
ce549947 29#include "mpls.h"
eac6e3f0
RW
30
31#include "ldpd.h"
32#include "ldpe.h"
33#include "lde.h"
34#include "log.h"
35#include "ldp_debug.h"
36
37static void ifp2kif(struct interface *, struct kif *);
38static void ifc2kaddr(struct interface *, struct connected *,
39 struct kaddr *);
bad6b0e7 40static int ldp_zebra_send_mpls_labels(int, struct kroute *);
121f9dee
QY
41static int ldp_router_id_update(ZAPI_CALLBACK_ARGS);
42static int ldp_interface_add(ZAPI_CALLBACK_ARGS);
43static int ldp_interface_delete(ZAPI_CALLBACK_ARGS);
44static int ldp_interface_status_change(ZAPI_CALLBACK_ARGS);
45static int ldp_interface_address_add(ZAPI_CALLBACK_ARGS);
46static int ldp_interface_address_delete(ZAPI_CALLBACK_ARGS);
47static int ldp_zebra_read_route(ZAPI_CALLBACK_ARGS);
48static int ldp_zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS);
eac6e3f0
RW
49static void ldp_zebra_connected(struct zclient *);
50
51static struct zclient *zclient;
52
53static void
54ifp2kif(struct interface *ifp, struct kif *kif)
55{
56 memset(kif, 0, sizeof(*kif));
57 strlcpy(kif->ifname, ifp->name, sizeof(kif->ifname));
58 kif->ifindex = ifp->ifindex;
988ded8d 59 kif->operative = if_is_operative(ifp);
26519d8c 60 if (ifp->ll_type == ZEBRA_LLT_ETHER)
9bff8057 61 memcpy(kif->mac, ifp->hw_addr, ETH_ALEN);
eac6e3f0
RW
62}
63
64static void
65ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka)
66{
67 memset(ka, 0, sizeof(*ka));
9cf67225 68 strlcpy(ka->ifname, ifp->name, sizeof(ka->ifname));
eac6e3f0
RW
69 ka->ifindex = ifp->ifindex;
70 ka->af = ifc->address->family;
71 ka->prefixlen = ifc->address->prefixlen;
72
73 switch (ka->af) {
74 case AF_INET:
75 ka->addr.v4 = ifc->address->u.prefix4;
76 if (ifc->destination)
77 ka->dstbrd.v4 = ifc->destination->u.prefix4;
78 break;
79 case AF_INET6:
80 ka->addr.v6 = ifc->address->u.prefix6;
81 if (ifc->destination)
82 ka->dstbrd.v6 = ifc->destination->u.prefix6;
83 break;
84 default:
85 break;
86 }
87}
88
87b5f1b7
RW
89void
90pw2zpw(struct l2vpn_pw *pw, struct zapi_pw *zpw)
91{
92 memset(zpw, 0, sizeof(*zpw));
93 strlcpy(zpw->ifname, pw->ifname, sizeof(zpw->ifname));
94 zpw->ifindex = pw->ifindex;
95 zpw->type = pw->l2vpn->pw_type;
96 zpw->af = pw->af;
97 zpw->nexthop.ipv6 = pw->addr.v6;
98 zpw->local_label = NO_LABEL;
99 zpw->remote_label = NO_LABEL;
100 if (pw->flags & F_PW_CWORD)
101 zpw->flags = F_PSEUDOWIRE_CWORD;
102 zpw->data.ldp.lsr_id = pw->lsr_id;
103 zpw->data.ldp.pwid = pw->pwid;
104 strlcpy(zpw->data.ldp.vpn_name, pw->l2vpn->name,
105 sizeof(zpw->data.ldp.vpn_name));
106}
107
ce549947 108static int
bad6b0e7 109ldp_zebra_send_mpls_labels(int cmd, struct kroute *kr)
ce549947 110{
bad6b0e7 111 struct zapi_labels zl = {};
ea6b290b 112 struct zapi_nexthop_label *znh;
ce549947
RW
113
114 if (kr->local_label < MPLS_LABEL_RESERVED_MAX ||
115 kr->remote_label == NO_LABEL)
116 return (0);
117
88d88a9c 118 debug_zebra_out("prefix %s/%u nexthop %s ifindex %u labels %s/%s (%s)",
ce549947 119 log_addr(kr->af, &kr->prefix), kr->prefixlen,
88d88a9c
RW
120 log_addr(kr->af, &kr->nexthop), kr->ifindex,
121 log_label(kr->local_label), log_label(kr->remote_label),
ce549947
RW
122 (cmd == ZEBRA_MPLS_LABELS_ADD) ? "add" : "delete");
123
bad6b0e7 124 zl.type = ZEBRA_LSP_LDP;
b3c49d0e
RW
125 zl.local_label = kr->local_label;
126
127 /* Set prefix. */
128 SET_FLAG(zl.message, ZAPI_LABELS_FTN);
129 zl.route.prefix.family = kr->af;
ce549947
RW
130 switch (kr->af) {
131 case AF_INET:
b3c49d0e 132 zl.route.prefix.u.prefix4 = kr->prefix.v4;
ce549947
RW
133 break;
134 case AF_INET6:
b3c49d0e 135 zl.route.prefix.u.prefix6 = kr->prefix.v6;
ce549947
RW
136 break;
137 default:
b3c49d0e 138 fatalx("ldp_zebra_send_mpls_labels: unknown af");
ce549947 139 }
b3c49d0e
RW
140 zl.route.prefix.prefixlen = kr->prefixlen;
141 zl.route.type = kr->route_type;
142 zl.route.instance = kr->route_instance;
143
144 /* Set nexthop. */
ea6b290b
RW
145 zl.nexthop_num = 1;
146 znh = &zl.nexthops[0];
b3c49d0e
RW
147 switch (kr->af) {
148 case AF_INET:
ea6b290b
RW
149 znh->family = AF_INET;
150 znh->address.ipv4 = kr->nexthop.v4;
b3c49d0e 151 if (kr->ifindex)
ea6b290b 152 znh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
b3c49d0e 153 else
ea6b290b 154 znh->type = NEXTHOP_TYPE_IPV4;
b3c49d0e
RW
155 break;
156 case AF_INET6:
ea6b290b
RW
157 znh->family = AF_INET6;
158 znh->address.ipv6 = kr->nexthop.v6;
b3c49d0e 159 if (kr->ifindex)
ea6b290b 160 znh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
b3c49d0e 161 else
ea6b290b 162 znh->type = NEXTHOP_TYPE_IPV6;
b3c49d0e
RW
163 break;
164 default:
165 break;
166 }
ea6b290b
RW
167 znh->ifindex = kr->ifindex;
168 znh->label = kr->remote_label;
ce549947 169
bad6b0e7 170 return zebra_send_mpls_labels(zclient, cmd, &zl);
ce549947
RW
171}
172
eac6e3f0
RW
173int
174kr_change(struct kroute *kr)
175{
bad6b0e7 176 return (ldp_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_ADD, kr));
eac6e3f0
RW
177}
178
179int
180kr_delete(struct kroute *kr)
181{
bad6b0e7 182 return (ldp_zebra_send_mpls_labels(ZEBRA_MPLS_LABELS_DELETE, kr));
eac6e3f0
RW
183}
184
185int
87b5f1b7 186kmpw_add(struct zapi_pw *zpw)
eac6e3f0 187{
87b5f1b7
RW
188 debug_zebra_out("pseudowire %s nexthop %s (add)",
189 zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
190
191 return (zebra_send_pw(zclient, ZEBRA_PW_ADD, zpw));
eac6e3f0
RW
192}
193
194int
87b5f1b7 195kmpw_del(struct zapi_pw *zpw)
eac6e3f0 196{
87b5f1b7
RW
197 debug_zebra_out("pseudowire %s nexthop %s (del)",
198 zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
199
200 return (zebra_send_pw(zclient, ZEBRA_PW_DELETE, zpw));
201}
202
203int
204kmpw_set(struct zapi_pw *zpw)
205{
206 debug_zebra_out("pseudowire %s nexthop %s labels %u/%u (set)",
207 zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop),
208 zpw->local_label, zpw->remote_label);
209
210 return (zebra_send_pw(zclient, ZEBRA_PW_SET, zpw));
211}
212
213int
214kmpw_unset(struct zapi_pw *zpw)
215{
216 debug_zebra_out("pseudowire %s nexthop %s (unset)",
217 zpw->ifname, log_addr(zpw->af, (union ldpd_addr *)&zpw->nexthop));
218
219 return (zebra_send_pw(zclient, ZEBRA_PW_UNSET, zpw));
eac6e3f0
RW
220}
221
222void
223kif_redistribute(const char *ifname)
224{
f4e14fdb
RW
225 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
226 struct listnode *cnode;
eac6e3f0
RW
227 struct interface *ifp;
228 struct connected *ifc;
229 struct kif kif;
230 struct kaddr ka;
231
451fda4f 232 FOR_ALL_INTERFACES (vrf, ifp) {
eac6e3f0
RW
233 if (ifname && strcmp(ifname, ifp->name) != 0)
234 continue;
235
236 ifp2kif(ifp, &kif);
52b530fc 237 main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif));
eac6e3f0
RW
238
239 for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, ifc)) {
240 ifc2kaddr(ifp, ifc, &ka);
241 main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka,
242 sizeof(ka));
243 }
244 }
245}
246
247static int
121f9dee 248ldp_router_id_update(ZAPI_CALLBACK_ARGS)
eac6e3f0
RW
249{
250 struct prefix router_id;
251
252 zebra_router_id_update_read(zclient->ibuf, &router_id);
253
254 if (bad_addr_v4(router_id.u.prefix4))
255 return (0);
256
257 debug_zebra_in("router-id update %s", inet_ntoa(router_id.u.prefix4));
258
259 global.rtr_id.s_addr = router_id.u.prefix4.s_addr;
260 main_imsg_compose_ldpe(IMSG_RTRID_UPDATE, 0, &global.rtr_id,
261 sizeof(global.rtr_id));
262
263 return (0);
264}
265
266static int
121f9dee 267ldp_interface_add(ZAPI_CALLBACK_ARGS)
eac6e3f0
RW
268{
269 struct interface *ifp;
270 struct kif kif;
271
272 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
273 debug_zebra_in("interface add %s index %d mtu %d", ifp->name,
274 ifp->ifindex, ifp->mtu);
275
276 ifp2kif(ifp, &kif);
52b530fc 277 main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif));
eac6e3f0
RW
278
279 return (0);
280}
281
282static int
121f9dee 283ldp_interface_delete(ZAPI_CALLBACK_ARGS)
eac6e3f0
RW
284{
285 struct interface *ifp;
9cf67225 286 struct kif kif;
eac6e3f0
RW
287
288 /* zebra_interface_state_read() updates interface structure in iflist */
289 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
290 if (ifp == NULL)
291 return (0);
292
293 debug_zebra_in("interface delete %s index %d mtu %d", ifp->name,
294 ifp->ifindex, ifp->mtu);
295
296 /* To support pseudo interface do not free interface structure. */
297 /* if_delete(ifp); */
ff880b78 298 if_set_index(ifp, IFINDEX_INTERNAL);
9cf67225
RW
299
300 ifp2kif(ifp, &kif);
301 main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif));
eac6e3f0
RW
302
303 return (0);
304}
305
306static int
121f9dee 307ldp_interface_status_change(ZAPI_CALLBACK_ARGS)
eac6e3f0
RW
308{
309 struct interface *ifp;
310 struct listnode *node;
311 struct connected *ifc;
312 struct kif kif;
313 struct kaddr ka;
eac6e3f0
RW
314
315 /*
316 * zebra_interface_state_read() updates interface structure in
317 * iflist.
318 */
319 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
320 if (ifp == NULL)
321 return (0);
322
323 debug_zebra_in("interface %s state update", ifp->name);
324
325 ifp2kif(ifp, &kif);
52b530fc 326 main_imsg_compose_both(IMSG_IFSTATUS, &kif, sizeof(kif));
eac6e3f0 327
988ded8d 328 if (if_is_operative(ifp)) {
eac6e3f0
RW
329 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
330 ifc2kaddr(ifp, ifc, &ka);
331 main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka,
332 sizeof(ka));
333 }
334 } else {
335 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
336 ifc2kaddr(ifp, ifc, &ka);
337 main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka,
338 sizeof(ka));
339 }
340 }
341
342 return (0);
343}
344
345static int
121f9dee 346ldp_interface_address_add(ZAPI_CALLBACK_ARGS)
eac6e3f0
RW
347{
348 struct connected *ifc;
349 struct interface *ifp;
350 struct kaddr ka;
351
121f9dee 352 ifc = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
eac6e3f0
RW
353 if (ifc == NULL)
354 return (0);
355
356 ifp = ifc->ifp;
357 ifc2kaddr(ifp, ifc, &ka);
358
359 /* Filter invalid addresses. */
360 if (bad_addr(ka.af, &ka.addr))
361 return (0);
362
9cf67225
RW
363 debug_zebra_in("address add %s/%u interface %s",
364 log_addr(ka.af, &ka.addr), ka.prefixlen, ifp->name);
eac6e3f0
RW
365
366 /* notify ldpe about new address */
367 main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka, sizeof(ka));
368
369 return (0);
370}
371
372static int
121f9dee 373ldp_interface_address_delete(ZAPI_CALLBACK_ARGS)
eac6e3f0
RW
374{
375 struct connected *ifc;
376 struct interface *ifp;
377 struct kaddr ka;
378
121f9dee 379 ifc = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
eac6e3f0
RW
380 if (ifc == NULL)
381 return (0);
382
383 ifp = ifc->ifp;
384 ifc2kaddr(ifp, ifc, &ka);
385 connected_free(ifc);
386
387 /* Filter invalid addresses. */
388 if (bad_addr(ka.af, &ka.addr))
389 return (0);
390
9cf67225
RW
391 debug_zebra_in("address delete %s/%u interface %s",
392 log_addr(ka.af, &ka.addr), ka.prefixlen, ifp->name);
eac6e3f0
RW
393
394 /* notify ldpe about removed address */
395 main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka, sizeof(ka));
396
397 return (0);
398}
399
400static int
121f9dee 401ldp_zebra_read_route(ZAPI_CALLBACK_ARGS)
eac6e3f0 402{
74489921
RW
403 struct zapi_route api;
404 struct zapi_nexthop *api_nh;
eac6e3f0 405 struct kroute kr;
74489921
RW
406 int i, add = 0;
407
408 if (zapi_route_decode(zclient->ibuf, &api) < 0)
409 return -1;
410
411 /* we completely ignore srcdest routes for now. */
412 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
413 return (0);
eac6e3f0
RW
414
415 memset(&kr, 0, sizeof(kr));
74489921
RW
416 kr.af = api.prefix.family;
417 switch (kr.af) {
418 case AF_INET:
419 kr.prefix.v4 = api.prefix.u.prefix4;
420 break;
421 case AF_INET6:
422 kr.prefix.v6 = api.prefix.u.prefix6;
423 break;
424 default:
425 break;
426 }
427 kr.prefixlen = api.prefix.prefixlen;
e132dea0
RW
428 kr.route_type = api.type;
429 kr.route_instance = api.instance;
eac6e3f0 430
74489921 431 switch (api.type) {
a695cc7b 432 case ZEBRA_ROUTE_CONNECT:
eac6e3f0 433 kr.flags |= F_CONNECTED;
a695cc7b
RW
434 break;
435 case ZEBRA_ROUTE_BGP:
436 /* LDP should follow the IGP and ignore BGP routes */
437 return (0);
438 default:
439 break;
440 }
441
eac6e3f0
RW
442 if (bad_addr(kr.af, &kr.prefix) ||
443 (kr.af == AF_INET6 && IN6_IS_SCOPE_EMBED(&kr.prefix.v6)))
444 return (0);
445
121f9dee 446 if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
1f2ff5b5
RW
447 add = 1;
448
74489921 449 if (api.nexthop_num == 0)
1f2ff5b5
RW
450 debug_zebra_in("route %s %s/%d (%s)", (add) ? "add" : "delete",
451 log_addr(kr.af, &kr.prefix), kr.prefixlen,
74489921 452 zebra_route_string(api.type));
eac6e3f0
RW
453
454 /* loop through all the nexthops */
74489921
RW
455 for (i = 0; i < api.nexthop_num; i++) {
456 api_nh = &api.nexthops[i];
cddef813
RW
457 switch (api_nh->type) {
458 case NEXTHOP_TYPE_IPV4:
459 if (kr.af != AF_INET)
460 continue;
461 kr.nexthop.v4 = api_nh->gate.ipv4;
462 kr.ifindex = 0;
463 break;
464 case NEXTHOP_TYPE_IPV4_IFINDEX:
465 if (kr.af != AF_INET)
466 continue;
74489921 467 kr.nexthop.v4 = api_nh->gate.ipv4;
cddef813 468 kr.ifindex = api_nh->ifindex;
eac6e3f0 469 break;
cddef813
RW
470 case NEXTHOP_TYPE_IPV6:
471 if (kr.af != AF_INET6)
472 continue;
74489921 473 kr.nexthop.v6 = api_nh->gate.ipv6;
cddef813 474 kr.ifindex = 0;
eac6e3f0 475 break;
cddef813
RW
476 case NEXTHOP_TYPE_IPV6_IFINDEX:
477 if (kr.af != AF_INET6)
478 continue;
479 kr.nexthop.v6 = api_nh->gate.ipv6;
480 kr.ifindex = api_nh->ifindex;
481 break;
482 case NEXTHOP_TYPE_IFINDEX:
483 if (!(kr.flags & F_CONNECTED))
484 continue;
eac6e3f0 485 break;
cddef813
RW
486 default:
487 continue;
eac6e3f0 488 }
eac6e3f0 489
1f2ff5b5
RW
490 debug_zebra_in("route %s %s/%d nexthop %s ifindex %u (%s)",
491 (add) ? "add" : "delete", log_addr(kr.af, &kr.prefix),
492 kr.prefixlen, log_addr(kr.af, &kr.nexthop), kr.ifindex,
74489921 493 zebra_route_string(api.type));
1f2ff5b5
RW
494
495 if (add)
eac6e3f0
RW
496 main_imsg_compose_lde(IMSG_NETWORK_ADD, 0, &kr,
497 sizeof(kr));
eac6e3f0
RW
498 }
499
8cb1fc45 500 main_imsg_compose_lde(IMSG_NETWORK_UPDATE, 0, &kr, sizeof(kr));
134970a2 501
eac6e3f0
RW
502 return (0);
503}
504
87b5f1b7
RW
505/*
506 * Receive PW status update from Zebra and send it to LDE process.
507 */
508static int
121f9dee 509ldp_zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS)
87b5f1b7
RW
510{
511 struct zapi_pw_status zpw;
512
121f9dee 513 zebra_read_pw_status_update(cmd, zclient, length, vrf_id, &zpw);
87b5f1b7
RW
514
515 debug_zebra_in("pseudowire %s status %s", zpw.ifname,
516 (zpw.status == PW_STATUS_UP) ? "up" : "down");
517
518 main_imsg_compose_lde(IMSG_PW_UPDATE, 0, &zpw, sizeof(zpw));
519
520 return (0);
521}
522
eac6e3f0
RW
523static void
524ldp_zebra_connected(struct zclient *zclient)
525{
eac6e3f0 526 zclient_send_reg_requests(zclient, VRF_DEFAULT);
a695cc7b
RW
527 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP,
528 ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
529 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6,
530 ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
eac6e3f0
RW
531}
532
342213ea
DS
533extern struct zebra_privs_t ldpd_privs;
534
138c5a74
DS
535static int ldp_ifp_create(struct interface *ifp)
536{
537 return 0;
538}
539
540static int ldp_ifp_up(struct interface *ifp)
541{
542 return 0;
543}
544
545static int ldp_ifp_down(struct interface *ifp)
546{
547 return 0;
548}
549
550static int ldp_ifp_destroy(struct interface *ifp)
551{
552 return 0;
553}
554
eac6e3f0
RW
555void
556ldp_zebra_init(struct thread_master *master)
557{
138c5a74
DS
558 if_zapi_callbacks(ldp_ifp_create, ldp_ifp_up,
559 ldp_ifp_down, ldp_ifp_destroy);
560
eac6e3f0 561 /* Set default values. */
26f63a1e 562 zclient = zclient_new(master, &zclient_options_default);
342213ea 563 zclient_init(zclient, ZEBRA_ROUTE_LDP, 0, &ldpd_privs);
eac6e3f0
RW
564
565 /* set callbacks */
566 zclient->zebra_connected = ldp_zebra_connected;
567 zclient->router_id_update = ldp_router_id_update;
568 zclient->interface_add = ldp_interface_add;
569 zclient->interface_delete = ldp_interface_delete;
570 zclient->interface_up = ldp_interface_status_change;
571 zclient->interface_down = ldp_interface_status_change;
572 zclient->interface_address_add = ldp_interface_address_add;
573 zclient->interface_address_delete = ldp_interface_address_delete;
74489921
RW
574 zclient->redistribute_route_add = ldp_zebra_read_route;
575 zclient->redistribute_route_del = ldp_zebra_read_route;
87b5f1b7 576 zclient->pw_status_update = ldp_zebra_read_pw_status_update;
eac6e3f0 577}
64dffe25
RW
578
579void
580ldp_zebra_destroy(void)
581{
582 zclient_stop(zclient);
583 zclient_free(zclient);
584 zclient = NULL;
585}