1 /*
2  * IS-IS Rout(e)ing protocol - isis_zebra.c
3  *
4  * Copyright (C) 2001,2002   Sampo Saaristo
5  *                           Tampere University of Technology
6  *                           Institute of Communications Engineering
7  * Copyright (C) 2013-2015   Christian Franke <chris@opensourcerouting.org>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public Licenseas published by the Free
11  * Software Foundation; either version 2 of the License, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17  * more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; see the file COPYING; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23 
24 #include <zebra.h>
25 
26 #include "thread.h"
27 #include "command.h"
28 #include "memory.h"
29 #include "log.h"
30 #include "lib_errors.h"
31 #include "if.h"
32 #include "network.h"
33 #include "prefix.h"
34 #include "zclient.h"
35 #include "stream.h"
36 #include "linklist.h"
37 #include "nexthop.h"
38 #include "vrf.h"
39 #include "libfrr.h"
40 
41 #include "isisd/isis_constants.h"
42 #include "isisd/isis_common.h"
43 #include "isisd/isis_flags.h"
44 #include "isisd/isis_misc.h"
45 #include "isisd/isis_circuit.h"
46 #include "isisd/isisd.h"
47 #include "isisd/isis_circuit.h"
48 #include "isisd/isis_csm.h"
49 #include "isisd/isis_lsp.h"
50 #include "isisd/isis_route.h"
51 #include "isisd/isis_zebra.h"
52 #include "isisd/isis_adjacency.h"
53 #include "isisd/isis_te.h"
54 #include "isisd/isis_sr.h"
55 
56 struct zclient *zclient;
57 static struct zclient *zclient_sync;
58 
59 /* Router-id update message from zebra. */
isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)60 static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
61 {
62 	struct isis_area *area;
63 	struct listnode *node;
64 	struct prefix router_id;
65 	struct isis *isis = NULL;
66 
67 	isis = isis_lookup_by_vrfid(vrf_id);
68 
69 	if (isis == NULL) {
70 		return -1;
71 	}
72 
73 	zebra_router_id_update_read(zclient->ibuf, &router_id);
74 	if (isis->router_id == router_id.u.prefix4.s_addr)
75 		return 0;
76 
77 	isis->router_id = router_id.u.prefix4.s_addr;
78 	for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
79 		if (listcount(area->area_addrs) > 0)
80 			lsp_regenerate_schedule(area, area->is_type, 0);
81 
82 	return 0;
83 }
84 
isis_zebra_if_address_add(ZAPI_CALLBACK_ARGS)85 static int isis_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
86 {
87 	struct isis_circuit *circuit;
88 	struct connected *c;
89 #ifdef EXTREME_DEBUG
90 	struct prefix *p;
91 	char buf[PREFIX2STR_BUFFER];
92 #endif /* EXTREME_DEBUG */
93 
94 	c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD,
95 					 zclient->ibuf, vrf_id);
96 
97 	if (c == NULL)
98 		return 0;
99 
100 #ifdef EXTREME_DEBUG
101 	p = c->address;
102 	prefix2str(p, buf, sizeof(buf));
103 
104 	if (p->family == AF_INET)
105 		zlog_debug("connected IP address %s", buf);
106 	if (p->family == AF_INET6)
107 		zlog_debug("connected IPv6 address %s", buf);
108 #endif /* EXTREME_DEBUG */
109 
110 	if (if_is_operative(c->ifp)) {
111 		circuit = circuit_scan_by_ifp(c->ifp);
112 		if (circuit)
113 			isis_circuit_add_addr(circuit, c);
114 	}
115 
116 	return 0;
117 }
118 
isis_zebra_if_address_del(ZAPI_CALLBACK_ARGS)119 static int isis_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
120 {
121 	struct isis_circuit *circuit;
122 	struct connected *c;
123 #ifdef EXTREME_DEBUG
124 	struct prefix *p;
125 	char buf[PREFIX2STR_BUFFER];
126 #endif /* EXTREME_DEBUG */
127 
128 	c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE,
129 					 zclient->ibuf, vrf_id);
130 
131 	if (c == NULL)
132 		return 0;
133 
134 #ifdef EXTREME_DEBUG
135 	p = c->address;
136 	prefix2str(p, buf, sizeof(buf));
137 
138 	if (p->family == AF_INET)
139 		zlog_debug("disconnected IP address %s", buf);
140 	if (p->family == AF_INET6)
141 		zlog_debug("disconnected IPv6 address %s", buf);
142 #endif /* EXTREME_DEBUG */
143 
144 	if (if_is_operative(c->ifp)) {
145 		circuit = circuit_scan_by_ifp(c->ifp);
146 		if (circuit)
147 			isis_circuit_del_addr(circuit, c);
148 	}
149 
150 	connected_free(&c);
151 
152 	return 0;
153 }
154 
isis_zebra_link_params(ZAPI_CALLBACK_ARGS)155 static int isis_zebra_link_params(ZAPI_CALLBACK_ARGS)
156 {
157 	struct interface *ifp;
158 
159 	ifp = zebra_interface_link_params_read(zclient->ibuf, vrf_id);
160 
161 	if (ifp == NULL)
162 		return 0;
163 
164 	/* Update TE TLV */
165 	isis_mpls_te_update(ifp);
166 
167 	return 0;
168 }
169 
isis_zebra_route_add_route(struct isis * isis,struct prefix * prefix,struct prefix_ipv6 * src_p,struct isis_route_info * route_info)170 void isis_zebra_route_add_route(struct isis *isis,
171 				struct prefix *prefix,
172 				struct prefix_ipv6 *src_p,
173 				struct isis_route_info *route_info)
174 {
175 	struct zapi_route api;
176 	struct zapi_nexthop *api_nh;
177 	struct isis_nexthop *nexthop;
178 	struct listnode *node;
179 	int count = 0;
180 
181 	if (zclient->sock < 0)
182 		return;
183 
184 	memset(&api, 0, sizeof(api));
185 	api.vrf_id = isis->vrf_id;
186 	api.type = PROTO_TYPE;
187 	api.safi = SAFI_UNICAST;
188 	api.prefix = *prefix;
189 	if (src_p && src_p->prefixlen) {
190 		api.src_prefix = *src_p;
191 		SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
192 	}
193 	SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
194 	SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
195 	api.metric = route_info->cost;
196 #if 0
197 	SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
198 	api.distance = route_info->depth;
199 #endif
200 
201 	/* Nexthops */
202 	for (ALL_LIST_ELEMENTS_RO(route_info->nexthops, node, nexthop)) {
203 		if (count >= MULTIPATH_NUM)
204 			break;
205 		api_nh = &api.nexthops[count];
206 		if (fabricd)
207 			SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
208 		api_nh->vrf_id = isis->vrf_id;
209 
210 		switch (nexthop->family) {
211 		case AF_INET:
212 			/* FIXME: can it be ? */
213 			if (nexthop->ip.ipv4.s_addr != INADDR_ANY) {
214 				api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
215 				api_nh->gate.ipv4 = nexthop->ip.ipv4;
216 			} else {
217 				api_nh->type = NEXTHOP_TYPE_IFINDEX;
218 			}
219 			break;
220 		case AF_INET6:
221 			if (!IN6_IS_ADDR_LINKLOCAL(&nexthop->ip.ipv6)
222 			    && !IN6_IS_ADDR_UNSPECIFIED(&nexthop->ip.ipv6)) {
223 				continue;
224 			}
225 			api_nh->gate.ipv6 = nexthop->ip.ipv6;
226 			api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
227 			break;
228 		default:
229 			flog_err(EC_LIB_DEVELOPMENT,
230 				 "%s: unknown address family [%d]", __func__,
231 				 nexthop->family);
232 			exit(1);
233 		}
234 
235 		api_nh->ifindex = nexthop->ifindex;
236 		count++;
237 	}
238 	if (!count)
239 		return;
240 
241 	api.nexthop_num = count;
242 
243 	zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
244 }
245 
isis_zebra_route_del_route(struct isis * isis,struct prefix * prefix,struct prefix_ipv6 * src_p,struct isis_route_info * route_info)246 void isis_zebra_route_del_route(struct isis *isis,
247 				struct prefix *prefix,
248 				struct prefix_ipv6 *src_p,
249 				struct isis_route_info *route_info)
250 {
251 	struct zapi_route api;
252 
253 	if (zclient->sock < 0)
254 		return;
255 
256 	memset(&api, 0, sizeof(api));
257 	api.vrf_id = isis->vrf_id;
258 	api.type = PROTO_TYPE;
259 	api.safi = SAFI_UNICAST;
260 	api.prefix = *prefix;
261 	if (src_p && src_p->prefixlen) {
262 		api.src_prefix = *src_p;
263 		SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
264 	}
265 
266 	zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
267 }
268 
269 /**
270  * Install Prefix-SID in the forwarding plane through Zebra.
271  *
272  * @param srp	Segment Routing Prefix-SID
273  */
isis_zebra_prefix_install_prefix_sid(const struct sr_prefix * srp)274 static void isis_zebra_prefix_install_prefix_sid(const struct sr_prefix *srp)
275 {
276 	struct zapi_labels zl;
277 	struct zapi_nexthop *znh;
278 	struct listnode *node;
279 	struct isis_nexthop *nexthop;
280 	struct interface *ifp;
281 
282 	/* Prepare message. */
283 	memset(&zl, 0, sizeof(zl));
284 	zl.type = ZEBRA_LSP_ISIS_SR;
285 	zl.local_label = srp->input_label;
286 
287 	switch (srp->type) {
288 	case ISIS_SR_PREFIX_LOCAL:
289 		ifp = if_lookup_by_name("lo", VRF_DEFAULT);
290 		if (!ifp) {
291 			zlog_warn(
292 				"%s: couldn't install Prefix-SID %pFX: loopback interface not found",
293 				__func__, &srp->prefix);
294 			return;
295 		}
296 
297 		znh = &zl.nexthops[zl.nexthop_num++];
298 		znh->type = NEXTHOP_TYPE_IFINDEX;
299 		znh->ifindex = ifp->ifindex;
300 		znh->label_num = 1;
301 		znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
302 		break;
303 	case ISIS_SR_PREFIX_REMOTE:
304 		/* Update route in the RIB too. */
305 		SET_FLAG(zl.message, ZAPI_LABELS_FTN);
306 		zl.route.prefix = srp->prefix;
307 		zl.route.type = ZEBRA_ROUTE_ISIS;
308 		zl.route.instance = 0;
309 
310 		for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops, node,
311 					  nexthop)) {
312 			if (nexthop->sr.label == MPLS_INVALID_LABEL)
313 				continue;
314 
315 			if (zl.nexthop_num >= MULTIPATH_NUM)
316 				break;
317 
318 			znh = &zl.nexthops[zl.nexthop_num++];
319 			znh->type = (srp->prefix.family == AF_INET)
320 					    ? NEXTHOP_TYPE_IPV4_IFINDEX
321 					    : NEXTHOP_TYPE_IPV6_IFINDEX;
322 			znh->gate = nexthop->ip;
323 			znh->ifindex = nexthop->ifindex;
324 			znh->label_num = 1;
325 			znh->labels[0] = nexthop->sr.label;
326 		}
327 		break;
328 	}
329 
330 	/* Send message to zebra. */
331 	(void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_REPLACE, &zl);
332 }
333 
334 /**
335  * Uninstall Prefix-SID from the forwarding plane through Zebra.
336  *
337  * @param srp	Segment Routing Prefix-SID
338  */
isis_zebra_uninstall_prefix_sid(const struct sr_prefix * srp)339 static void isis_zebra_uninstall_prefix_sid(const struct sr_prefix *srp)
340 {
341 	struct zapi_labels zl;
342 
343 	/* Prepare message. */
344 	memset(&zl, 0, sizeof(zl));
345 	zl.type = ZEBRA_LSP_ISIS_SR;
346 	zl.local_label = srp->input_label;
347 
348 	if (srp->type == ISIS_SR_PREFIX_REMOTE) {
349 		/* Update route in the RIB too. */
350 		SET_FLAG(zl.message, ZAPI_LABELS_FTN);
351 		zl.route.prefix = srp->prefix;
352 		zl.route.type = ZEBRA_ROUTE_ISIS;
353 		zl.route.instance = 0;
354 	}
355 
356 	/* Send message to zebra. */
357 	(void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_DELETE, &zl);
358 }
359 
360 /**
361  * Send Prefix-SID to ZEBRA for installation or deletion.
362  *
363  * @param cmd	ZEBRA_MPLS_LABELS_REPLACE or ZEBRA_ROUTE_DELETE
364  * @param srp	Segment Routing Prefix-SID
365  */
isis_zebra_send_prefix_sid(int cmd,const struct sr_prefix * srp)366 void isis_zebra_send_prefix_sid(int cmd, const struct sr_prefix *srp)
367 {
368 
369 	if (cmd != ZEBRA_MPLS_LABELS_REPLACE
370 	    && cmd != ZEBRA_MPLS_LABELS_DELETE) {
371 		flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command",
372 			  __func__);
373 		return;
374 	}
375 
376 	sr_debug("  |- %s label %u for prefix %pFX",
377 		 cmd == ZEBRA_MPLS_LABELS_REPLACE ? "Update" : "Delete",
378 		 srp->input_label, &srp->prefix);
379 
380 	if (cmd == ZEBRA_MPLS_LABELS_REPLACE)
381 		isis_zebra_prefix_install_prefix_sid(srp);
382 	else
383 		isis_zebra_uninstall_prefix_sid(srp);
384 }
385 
386 /**
387  * Send (LAN)-Adjacency-SID to ZEBRA for installation or deletion.
388  *
389  * @param cmd	ZEBRA_MPLS_LABELS_ADD or ZEBRA_ROUTE_DELETE
390  * @param sra	Segment Routing Adjacency-SID
391  */
isis_zebra_send_adjacency_sid(int cmd,const struct sr_adjacency * sra)392 void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
393 {
394 	struct zapi_labels zl;
395 	struct zapi_nexthop *znh;
396 
397 	if (cmd != ZEBRA_MPLS_LABELS_ADD && cmd != ZEBRA_MPLS_LABELS_DELETE) {
398 		flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command",
399 			  __func__);
400 		return;
401 	}
402 
403 	sr_debug("  |- %s label %u for interface %s",
404 		 cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete",
405 		 sra->nexthop.label, sra->adj->circuit->interface->name);
406 
407 	memset(&zl, 0, sizeof(zl));
408 	zl.type = ZEBRA_LSP_ISIS_SR;
409 	zl.local_label = sra->nexthop.label;
410 	zl.nexthop_num = 1;
411 	znh = &zl.nexthops[0];
412 	znh->gate = sra->nexthop.address;
413 	znh->type = (sra->nexthop.family == AF_INET)
414 			    ? NEXTHOP_TYPE_IPV4_IFINDEX
415 			    : NEXTHOP_TYPE_IPV6_IFINDEX;
416 	znh->ifindex = sra->adj->circuit->interface->ifindex;
417 	znh->label_num = 1;
418 	znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
419 
420 	(void)zebra_send_mpls_labels(zclient, cmd, &zl);
421 }
422 
isis_zebra_read(ZAPI_CALLBACK_ARGS)423 static int isis_zebra_read(ZAPI_CALLBACK_ARGS)
424 {
425 	struct zapi_route api;
426 	struct isis *isis = NULL;
427 
428 	isis = isis_lookup_by_vrfid(vrf_id);
429 
430 	if (isis == NULL)
431 		return -1;
432 
433 	if (zapi_route_decode(zclient->ibuf, &api) < 0)
434 		return -1;
435 
436 	if (api.prefix.family == AF_INET6
437 	    && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
438 		return 0;
439 
440 	/*
441 	 * Avoid advertising a false default reachability. (A default
442 	 * route installed by IS-IS gets redistributed from zebra back
443 	 * into IS-IS causing us to start advertising default reachabity
444 	 * without this check)
445 	 */
446 	if (api.prefix.prefixlen == 0
447 	    && api.src_prefix.prefixlen == 0
448 	    && api.type == PROTO_TYPE) {
449 		cmd = ZEBRA_REDISTRIBUTE_ROUTE_DEL;
450 	}
451 
452 	if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
453 		isis_redist_add(isis, api.type, &api.prefix, &api.src_prefix,
454 				api.distance, api.metric);
455 	else
456 		isis_redist_delete(isis, api.type, &api.prefix,
457 				   &api.src_prefix);
458 
459 	return 0;
460 }
461 
isis_distribute_list_update(int routetype)462 int isis_distribute_list_update(int routetype)
463 {
464 	return 0;
465 }
466 
isis_zebra_redistribute_set(afi_t afi,int type)467 void isis_zebra_redistribute_set(afi_t afi, int type)
468 {
469 	if (type == DEFAULT_ROUTE)
470 		zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
471 					     zclient, afi, VRF_DEFAULT);
472 	else
473 		zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type,
474 				     0, VRF_DEFAULT);
475 }
476 
isis_zebra_redistribute_unset(afi_t afi,int type)477 void isis_zebra_redistribute_unset(afi_t afi, int type)
478 {
479 	if (type == DEFAULT_ROUTE)
480 		zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
481 					     zclient, afi, VRF_DEFAULT);
482 	else
483 		zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi,
484 				     type, 0, VRF_DEFAULT);
485 }
486 
487 /* Label Manager Functions */
488 
489 /**
490  * Check if Label Manager is Ready or not.
491  *
492  * @return	True if Label Manager is ready, False otherwise
493  */
isis_zebra_label_manager_ready(void)494 bool isis_zebra_label_manager_ready(void)
495 {
496 	return (zclient_sync->sock > 0);
497 }
498 
499 /**
500  * Request Label Range to the Label Manager.
501  *
502  * @param base		base label of the label range to request
503  * @param chunk_size	size of the label range to request
504  *
505  * @return 	0 on success, -1 on failure
506  */
isis_zebra_request_label_range(uint32_t base,uint32_t chunk_size)507 int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
508 {
509 	int ret;
510 	uint32_t start, end;
511 
512 	if (zclient_sync->sock < 0)
513 		return -1;
514 
515 	ret = lm_get_label_chunk(zclient_sync, 0, base, chunk_size, &start,
516 				 &end);
517 	if (ret < 0) {
518 		zlog_warn("%s: error getting label range!", __func__);
519 		return -1;
520 	}
521 
522 	return 0;
523 }
524 
525 /**
526  * Release Label Range to the Label Manager.
527  *
528  * @param start		start of label range to release
529  * @param end		end of label range to release
530  *
531  * @return		0 on success, -1 otherwise
532  */
isis_zebra_release_label_range(uint32_t start,uint32_t end)533 int isis_zebra_release_label_range(uint32_t start, uint32_t end)
534 {
535 	int ret;
536 
537 	if (zclient_sync->sock < 0)
538 		return -1;
539 
540 	ret = lm_release_label_chunk(zclient_sync, start, end);
541 	if (ret < 0) {
542 		zlog_warn("%s: error releasing label range!", __func__);
543 		return -1;
544 	}
545 
546 	return 0;
547 }
548 
549 /**
550  * Connect to the Label Manager.
551  *
552  * @return	0 on success, -1 otherwise
553  */
isis_zebra_label_manager_connect(void)554 int isis_zebra_label_manager_connect(void)
555 {
556 	/* Connect to label manager. */
557 	if (zclient_socket_connect(zclient_sync) < 0) {
558 		zlog_warn("%s: failed connecting synchronous zclient!",
559 			  __func__);
560 		return -1;
561 	}
562 	/* make socket non-blocking */
563 	set_nonblocking(zclient_sync->sock);
564 
565 	/* Send hello to notify zebra this is a synchronous client */
566 	if (zclient_send_hello(zclient_sync) < 0) {
567 		zlog_warn("%s: failed sending hello for synchronous zclient!",
568 			  __func__);
569 		close(zclient_sync->sock);
570 		zclient_sync->sock = -1;
571 		return -1;
572 	}
573 
574 	/* Connect to label manager */
575 	if (lm_label_manager_connect(zclient_sync, 0) != 0) {
576 		zlog_warn("%s: failed connecting to label manager!", __func__);
577 		if (zclient_sync->sock > 0) {
578 			close(zclient_sync->sock);
579 			zclient_sync->sock = -1;
580 		}
581 		return -1;
582 	}
583 
584 	sr_debug("ISIS-Sr: Successfully connected to the Label Manager");
585 
586 	return 0;
587 }
588 
isis_zebra_vrf_register(struct isis * isis)589 void isis_zebra_vrf_register(struct isis *isis)
590 {
591 	if (!zclient || zclient->sock < 0 || !isis)
592 		return;
593 
594 	if (isis->vrf_id != VRF_UNKNOWN) {
595 		if (IS_DEBUG_EVENTS)
596 			zlog_debug("%s: Register VRF %s id %u", __func__,
597 				   isis->name, isis->vrf_id);
598 		zclient_send_reg_requests(zclient, isis->vrf_id);
599 	}
600 }
601 
602 
isis_zebra_connected(struct zclient * zclient)603 static void isis_zebra_connected(struct zclient *zclient)
604 {
605 	zclient_send_reg_requests(zclient, VRF_DEFAULT);
606 }
607 
isis_zebra_init(struct thread_master * master,int instance)608 void isis_zebra_init(struct thread_master *master, int instance)
609 {
610 	/* Initialize asynchronous zclient. */
611 	zclient = zclient_new(master, &zclient_options_default);
612 	zclient_init(zclient, PROTO_TYPE, 0, &isisd_privs);
613 	zclient->zebra_connected = isis_zebra_connected;
614 	zclient->router_id_update = isis_router_id_update_zebra;
615 	zclient->interface_address_add = isis_zebra_if_address_add;
616 	zclient->interface_address_delete = isis_zebra_if_address_del;
617 	zclient->interface_link_params = isis_zebra_link_params;
618 	zclient->redistribute_route_add = isis_zebra_read;
619 	zclient->redistribute_route_del = isis_zebra_read;
620 
621 	/* Initialize special zclient for synchronous message exchanges. */
622 	struct zclient_options options = zclient_options_default;
623 	options.synchronous = true;
624 	zclient_sync = zclient_new(master, &options);
625 	zclient_sync->sock = -1;
626 	zclient_sync->redist_default = ZEBRA_ROUTE_ISIS;
627 	zclient_sync->instance = instance;
628 	/*
629 	 * session_id must be different from default value (0) to distinguish
630 	 * the asynchronous socket from the synchronous one
631 	 */
632 	zclient_sync->session_id = 1;
633 	zclient_sync->privs = &isisd_privs;
634 }
635 
isis_zebra_stop(void)636 void isis_zebra_stop(void)
637 {
638 	zclient_stop(zclient_sync);
639 	zclient_free(zclient_sync);
640 	zclient_stop(zclient);
641 	zclient_free(zclient);
642 	frr_fini();
643 }
644