]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_zebra.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / isisd / isis_zebra.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * IS-IS Rout(e)ing protocol - isis_zebra.c
4 *
5 * Copyright (C) 2001,2002 Sampo Saaristo
6 * Tampere University of Technology
7 * Institute of Communications Engineering
8 * Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org>
9 */
10
11 #include <zebra.h>
12
13 #include "frrevent.h"
14 #include "command.h"
15 #include "memory.h"
16 #include "log.h"
17 #include "lib_errors.h"
18 #include "if.h"
19 #include "network.h"
20 #include "prefix.h"
21 #include "zclient.h"
22 #include "stream.h"
23 #include "linklist.h"
24 #include "nexthop.h"
25 #include "vrf.h"
26 #include "libfrr.h"
27 #include "bfd.h"
28 #include "link_state.h"
29
30 #include "isisd/isis_constants.h"
31 #include "isisd/isis_common.h"
32 #include "isisd/isis_flags.h"
33 #include "isisd/isis_misc.h"
34 #include "isisd/isis_circuit.h"
35 #include "isisd/isisd.h"
36 #include "isisd/isis_circuit.h"
37 #include "isisd/isis_csm.h"
38 #include "isisd/isis_lsp.h"
39 #include "isisd/isis_spf.h"
40 #include "isisd/isis_spf_private.h"
41 #include "isisd/isis_route.h"
42 #include "isisd/isis_zebra.h"
43 #include "isisd/isis_adjacency.h"
44 #include "isisd/isis_te.h"
45 #include "isisd/isis_sr.h"
46 #include "isisd/isis_ldp_sync.h"
47
48 struct zclient *zclient;
49 static struct zclient *zclient_sync;
50
51 /* Router-id update message from zebra. */
52 static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
53 {
54 struct isis_area *area;
55 struct listnode *node;
56 struct prefix router_id;
57 struct isis *isis = NULL;
58
59 isis = isis_lookup_by_vrfid(vrf_id);
60
61 if (isis == NULL) {
62 return -1;
63 }
64
65 zebra_router_id_update_read(zclient->ibuf, &router_id);
66 if (isis->router_id == router_id.u.prefix4.s_addr)
67 return 0;
68
69 isis->router_id = router_id.u.prefix4.s_addr;
70 for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
71 if (listcount(area->area_addrs) > 0)
72 lsp_regenerate_schedule(area, area->is_type, 0);
73
74 return 0;
75 }
76
77 static int isis_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
78 {
79 struct isis_circuit *circuit;
80 struct connected *c;
81
82 c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD,
83 zclient->ibuf, vrf_id);
84
85 if (c == NULL)
86 return 0;
87
88 #ifdef EXTREME_DEBUG
89 if (c->address->family == AF_INET)
90 zlog_debug("connected IP address %pFX", c->address);
91 if (c->address->family == AF_INET6)
92 zlog_debug("connected IPv6 address %pFX", c->address);
93 #endif /* EXTREME_DEBUG */
94
95 if (if_is_operative(c->ifp)) {
96 circuit = circuit_scan_by_ifp(c->ifp);
97 if (circuit)
98 isis_circuit_add_addr(circuit, c);
99 }
100
101 return 0;
102 }
103
104 static int isis_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
105 {
106 struct isis_circuit *circuit;
107 struct connected *c;
108
109 c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE,
110 zclient->ibuf, vrf_id);
111
112 if (c == NULL)
113 return 0;
114
115 #ifdef EXTREME_DEBUG
116 if (c->address->family == AF_INET)
117 zlog_debug("disconnected IP address %pFX", c->address);
118 if (c->address->family == AF_INET6)
119 zlog_debug("disconnected IPv6 address %pFX", c->address);
120 #endif /* EXTREME_DEBUG */
121
122 if (if_is_operative(c->ifp)) {
123 circuit = circuit_scan_by_ifp(c->ifp);
124 if (circuit)
125 isis_circuit_del_addr(circuit, c);
126 }
127
128 connected_free(&c);
129
130 return 0;
131 }
132
133 static int isis_zebra_link_params(ZAPI_CALLBACK_ARGS)
134 {
135 struct interface *ifp;
136 bool changed = false;
137
138 ifp = zebra_interface_link_params_read(zclient->ibuf, vrf_id, &changed);
139
140 if (ifp == NULL || !changed)
141 return 0;
142
143 /* Update TE TLV */
144 isis_mpls_te_update(ifp);
145
146 return 0;
147 }
148
149 enum isis_zebra_nexthop_type {
150 ISIS_NEXTHOP_MAIN = 0,
151 ISIS_NEXTHOP_BACKUP,
152 };
153
154 static int isis_zebra_add_nexthops(struct isis *isis, struct list *nexthops,
155 struct zapi_nexthop zapi_nexthops[],
156 enum isis_zebra_nexthop_type type,
157 bool mpls_lsp, uint8_t backup_nhs)
158 {
159 struct isis_nexthop *nexthop;
160 struct listnode *node;
161 int count = 0;
162
163 /* Nexthops */
164 for (ALL_LIST_ELEMENTS_RO(nexthops, node, nexthop)) {
165 struct zapi_nexthop *api_nh;
166
167 if (count >= MULTIPATH_NUM)
168 break;
169 api_nh = &zapi_nexthops[count];
170 if (fabricd)
171 SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
172 api_nh->vrf_id = isis->vrf_id;
173
174 switch (nexthop->family) {
175 case AF_INET:
176 /* FIXME: can it be ? */
177 if (nexthop->ip.ipv4.s_addr != INADDR_ANY) {
178 api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
179 api_nh->gate.ipv4 = nexthop->ip.ipv4;
180 } else {
181 api_nh->type = NEXTHOP_TYPE_IFINDEX;
182 }
183 break;
184 case AF_INET6:
185 if (!IN6_IS_ADDR_LINKLOCAL(&nexthop->ip.ipv6)
186 && !IN6_IS_ADDR_UNSPECIFIED(&nexthop->ip.ipv6)) {
187 continue;
188 }
189 api_nh->gate.ipv6 = nexthop->ip.ipv6;
190 api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
191 break;
192 default:
193 flog_err(EC_LIB_DEVELOPMENT,
194 "%s: unknown address family [%d]", __func__,
195 nexthop->family);
196 exit(1);
197 }
198
199 api_nh->ifindex = nexthop->ifindex;
200
201 /* Add MPLS label(s). */
202 if (nexthop->label_stack) {
203 api_nh->label_num = nexthop->label_stack->num_labels;
204 memcpy(api_nh->labels, nexthop->label_stack->label,
205 sizeof(mpls_label_t) * api_nh->label_num);
206 } else if (nexthop->sr.present) {
207 api_nh->label_num = 1;
208 api_nh->labels[0] = nexthop->sr.label;
209 } else if (mpls_lsp) {
210 switch (type) {
211 case ISIS_NEXTHOP_MAIN:
212 /*
213 * Do not use non-SR enabled nexthops to prevent
214 * broken LSPs from being formed.
215 */
216 continue;
217 case ISIS_NEXTHOP_BACKUP:
218 /*
219 * This is necessary because zebra requires
220 * the nexthops of MPLS LSPs to be labeled.
221 */
222 api_nh->label_num = 1;
223 api_nh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
224 break;
225 }
226 }
227
228 /* Backup nexthop handling. */
229 if (backup_nhs) {
230 SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
231 /*
232 * If the backup has multiple nexthops, all of them
233 * protect the same primary nexthop since ECMP routes
234 * have no backups.
235 */
236 api_nh->backup_num = backup_nhs;
237 for (int i = 0; i < backup_nhs; i++)
238 api_nh->backup_idx[i] = i;
239 }
240 count++;
241 }
242
243 return count;
244 }
245
246 void isis_zebra_route_add_route(struct isis *isis, struct prefix *prefix,
247 struct prefix_ipv6 *src_p,
248 struct isis_route_info *route_info)
249 {
250 struct zapi_route api;
251 int count = 0;
252
253 if (zclient->sock < 0)
254 return;
255
256 /* Uninstall the route if it doesn't have any valid nexthop. */
257 if (list_isempty(route_info->nexthops)) {
258 isis_zebra_route_del_route(isis, prefix, src_p, route_info);
259 return;
260 }
261
262 memset(&api, 0, sizeof(api));
263 api.vrf_id = isis->vrf_id;
264 api.type = PROTO_TYPE;
265 api.safi = SAFI_UNICAST;
266 api.prefix = *prefix;
267 if (src_p && src_p->prefixlen) {
268 api.src_prefix = *src_p;
269 SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
270 }
271 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
272 SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
273 api.metric = route_info->cost;
274
275 /* Add backup nexthops first. */
276 if (route_info->backup) {
277 count = isis_zebra_add_nexthops(
278 isis, route_info->backup->nexthops, api.backup_nexthops,
279 ISIS_NEXTHOP_BACKUP, false, 0);
280 if (count > 0) {
281 SET_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS);
282 api.backup_nexthop_num = count;
283 }
284 }
285
286 /* Add primary nexthops. */
287 count = isis_zebra_add_nexthops(isis, route_info->nexthops,
288 api.nexthops, ISIS_NEXTHOP_MAIN, false,
289 count);
290 if (!count)
291 return;
292 api.nexthop_num = count;
293
294 zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
295 }
296
297 void isis_zebra_route_del_route(struct isis *isis,
298 struct prefix *prefix,
299 struct prefix_ipv6 *src_p,
300 struct isis_route_info *route_info)
301 {
302 struct zapi_route api;
303
304 if (zclient->sock < 0)
305 return;
306
307 memset(&api, 0, sizeof(api));
308 api.vrf_id = isis->vrf_id;
309 api.type = PROTO_TYPE;
310 api.safi = SAFI_UNICAST;
311 api.prefix = *prefix;
312 if (src_p && src_p->prefixlen) {
313 api.src_prefix = *src_p;
314 SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
315 }
316
317 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
318 }
319
320 /**
321 * Install Prefix-SID label entry in the forwarding plane through Zebra.
322 *
323 * @param area IS-IS area
324 * @param prefix Route prefix
325 * @param rinfo Route information
326 * @param psid Prefix-SID information
327 */
328 void isis_zebra_prefix_sid_install(struct isis_area *area,
329 struct prefix *prefix,
330 struct isis_sr_psid_info *psid)
331 {
332 struct zapi_labels zl;
333 int count = 0;
334
335 sr_debug("ISIS-Sr (%s): update label %u for prefix %pFX algorithm %u",
336 area->area_tag, psid->label, prefix, psid->algorithm);
337
338 /* Prepare message. */
339 memset(&zl, 0, sizeof(zl));
340 zl.type = ZEBRA_LSP_ISIS_SR;
341 zl.local_label = psid->label;
342
343 /* Local routes don't have any nexthop and require special handling. */
344 if (list_isempty(psid->nexthops)) {
345 struct zapi_nexthop *znh;
346 struct interface *ifp;
347
348 ifp = if_lookup_by_name("lo", VRF_DEFAULT);
349 if (!ifp) {
350 zlog_warn(
351 "%s: couldn't install Prefix-SID %pFX: loopback interface not found",
352 __func__, prefix);
353 return;
354 }
355
356 znh = &zl.nexthops[zl.nexthop_num++];
357 znh->type = NEXTHOP_TYPE_IFINDEX;
358 znh->ifindex = ifp->ifindex;
359 znh->label_num = 1;
360 znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
361 } else {
362 /* Add backup nexthops first. */
363 if (psid->nexthops_backup) {
364 count = isis_zebra_add_nexthops(
365 area->isis, psid->nexthops_backup,
366 zl.backup_nexthops, ISIS_NEXTHOP_BACKUP, true,
367 0);
368 if (count > 0) {
369 SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS);
370 zl.backup_nexthop_num = count;
371 }
372 }
373
374 /* Add primary nexthops. */
375 count = isis_zebra_add_nexthops(area->isis, psid->nexthops,
376 zl.nexthops, ISIS_NEXTHOP_MAIN,
377 true, count);
378 if (!count)
379 return;
380 zl.nexthop_num = count;
381 }
382
383 /* Send message to zebra. */
384 (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_REPLACE, &zl);
385 }
386
387 /**
388 * Uninstall Prefix-SID label entry from the forwarding plane through Zebra.
389 *
390 * @param area IS-IS area
391 * @param prefix Route prefix
392 * @param rinfo Route information
393 * @param psid Prefix-SID information
394 */
395 void isis_zebra_prefix_sid_uninstall(struct isis_area *area,
396 struct prefix *prefix,
397 struct isis_route_info *rinfo,
398 struct isis_sr_psid_info *psid)
399 {
400 struct zapi_labels zl;
401
402 sr_debug("ISIS-Sr (%s): delete label %u for prefix %pFX algorithm %u",
403 area->area_tag, psid->label, prefix, psid->algorithm);
404
405 /* Prepare message. */
406 memset(&zl, 0, sizeof(zl));
407 zl.type = ZEBRA_LSP_ISIS_SR;
408 zl.local_label = psid->label;
409
410 /* Send message to zebra. */
411 (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_DELETE, &zl);
412 }
413
414 /**
415 * Send (LAN)-Adjacency-SID to ZEBRA for installation or deletion.
416 *
417 * @param cmd ZEBRA_MPLS_LABELS_ADD or ZEBRA_ROUTE_DELETE
418 * @param sra Segment Routing Adjacency-SID
419 */
420 void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
421 {
422 struct isis *isis = sra->adj->circuit->area->isis;
423 struct zapi_labels zl;
424 struct zapi_nexthop *znh;
425
426 if (cmd != ZEBRA_MPLS_LABELS_ADD && cmd != ZEBRA_MPLS_LABELS_DELETE) {
427 flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command",
428 __func__);
429 return;
430 }
431
432 sr_debug(" |- %s label %u for interface %s",
433 cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete",
434 sra->input_label, sra->adj->circuit->interface->name);
435
436 memset(&zl, 0, sizeof(zl));
437 zl.type = ZEBRA_LSP_ISIS_SR;
438 zl.local_label = sra->input_label;
439 zl.nexthop_num = 1;
440 znh = &zl.nexthops[0];
441 znh->gate = sra->nexthop.address;
442 znh->type = (sra->nexthop.family == AF_INET)
443 ? NEXTHOP_TYPE_IPV4_IFINDEX
444 : NEXTHOP_TYPE_IPV6_IFINDEX;
445 znh->ifindex = sra->adj->circuit->interface->ifindex;
446 znh->label_num = 1;
447 znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
448
449 /* Set backup nexthops. */
450 if (sra->type == ISIS_SR_LAN_BACKUP) {
451 int count;
452
453 count = isis_zebra_add_nexthops(isis, sra->backup_nexthops,
454 zl.backup_nexthops,
455 ISIS_NEXTHOP_BACKUP, true, 0);
456 if (count > 0) {
457 SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS);
458 zl.backup_nexthop_num = count;
459
460 SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
461 znh->backup_num = count;
462 for (int i = 0; i < count; i++)
463 znh->backup_idx[i] = i;
464 }
465 }
466
467 (void)zebra_send_mpls_labels(zclient, cmd, &zl);
468 }
469
470 static int isis_zebra_read(ZAPI_CALLBACK_ARGS)
471 {
472 struct zapi_route api;
473 struct isis *isis = NULL;
474
475 isis = isis_lookup_by_vrfid(vrf_id);
476
477 if (isis == NULL)
478 return -1;
479
480 if (zapi_route_decode(zclient->ibuf, &api) < 0)
481 return -1;
482
483 if (api.prefix.family == AF_INET6
484 && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
485 return 0;
486
487 /*
488 * Avoid advertising a false default reachability. (A default
489 * route installed by IS-IS gets redistributed from zebra back
490 * into IS-IS causing us to start advertising default reachabity
491 * without this check)
492 */
493 if (api.prefix.prefixlen == 0
494 && api.src_prefix.prefixlen == 0
495 && api.type == PROTO_TYPE) {
496 cmd = ZEBRA_REDISTRIBUTE_ROUTE_DEL;
497 }
498
499 if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
500 isis_redist_add(isis, api.type, &api.prefix, &api.src_prefix,
501 api.distance, api.metric, api.tag);
502 else
503 isis_redist_delete(isis, api.type, &api.prefix,
504 &api.src_prefix);
505
506 return 0;
507 }
508
509 int isis_distribute_list_update(int routetype)
510 {
511 return 0;
512 }
513
514 void isis_zebra_redistribute_set(afi_t afi, int type, vrf_id_t vrf_id)
515 {
516 if (type == DEFAULT_ROUTE)
517 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
518 zclient, afi, vrf_id);
519 else
520 zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type,
521 0, vrf_id);
522 }
523
524 void isis_zebra_redistribute_unset(afi_t afi, int type, vrf_id_t vrf_id)
525 {
526 if (type == DEFAULT_ROUTE)
527 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
528 zclient, afi, vrf_id);
529 else
530 zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi,
531 type, 0, vrf_id);
532 }
533
534 /**
535 * Register RLFA with LDP.
536 */
537 int isis_zebra_rlfa_register(struct isis_spftree *spftree, struct rlfa *rlfa)
538 {
539 struct isis_area *area = spftree->area;
540 struct zapi_rlfa_request zr = {};
541 int ret;
542
543 if (!zclient)
544 return 0;
545
546 zr.igp.vrf_id = area->isis->vrf_id;
547 zr.igp.protocol = ZEBRA_ROUTE_ISIS;
548 strlcpy(zr.igp.isis.area_tag, area->area_tag,
549 sizeof(zr.igp.isis.area_tag));
550 zr.igp.isis.spf.tree_id = spftree->tree_id;
551 zr.igp.isis.spf.level = spftree->level;
552 zr.igp.isis.spf.run_id = spftree->runcount;
553 zr.destination = rlfa->prefix;
554 zr.pq_address = rlfa->pq_address;
555
556 zlog_debug("ISIS-LFA: registering RLFA %pFX@%pI4 with LDP",
557 &rlfa->prefix, &rlfa->pq_address);
558
559 ret = zclient_send_opaque_unicast(zclient, LDP_RLFA_REGISTER,
560 ZEBRA_ROUTE_LDP, 0, 0,
561 (const uint8_t *)&zr, sizeof(zr));
562 if (ret == ZCLIENT_SEND_FAILURE) {
563 zlog_warn("ISIS-LFA: failed to register RLFA with LDP");
564 return -1;
565 }
566
567 return 0;
568 }
569
570 /**
571 * Unregister all RLFAs from the given SPF tree with LDP.
572 */
573 void isis_zebra_rlfa_unregister_all(struct isis_spftree *spftree)
574 {
575 struct isis_area *area = spftree->area;
576 struct zapi_rlfa_igp igp = {};
577 int ret;
578
579 if (!zclient || spftree->type != SPF_TYPE_FORWARD
580 || CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
581 return;
582
583 if (IS_DEBUG_LFA)
584 zlog_debug("ISIS-LFA: unregistering all RLFAs with LDP");
585
586 igp.vrf_id = area->isis->vrf_id;
587 igp.protocol = ZEBRA_ROUTE_ISIS;
588 strlcpy(igp.isis.area_tag, area->area_tag, sizeof(igp.isis.area_tag));
589 igp.isis.spf.tree_id = spftree->tree_id;
590 igp.isis.spf.level = spftree->level;
591 igp.isis.spf.run_id = spftree->runcount;
592
593 ret = zclient_send_opaque_unicast(zclient, LDP_RLFA_UNREGISTER_ALL,
594 ZEBRA_ROUTE_LDP, 0, 0,
595 (const uint8_t *)&igp, sizeof(igp));
596 if (ret == ZCLIENT_SEND_FAILURE)
597 zlog_warn("ISIS-LFA: failed to unregister RLFA with LDP");
598 }
599
600 /* Label Manager Functions */
601
602 /**
603 * Check if Label Manager is Ready or not.
604 *
605 * @return True if Label Manager is ready, False otherwise
606 */
607 bool isis_zebra_label_manager_ready(void)
608 {
609 return (zclient_sync->sock > 0);
610 }
611
612 /**
613 * Request Label Range to the Label Manager.
614 *
615 * @param base base label of the label range to request
616 * @param chunk_size size of the label range to request
617 *
618 * @return 0 on success, -1 on failure
619 */
620 int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
621 {
622 int ret;
623 uint32_t start, end;
624
625 if (zclient_sync->sock < 0)
626 return -1;
627
628 ret = lm_get_label_chunk(zclient_sync, 0, base, chunk_size, &start,
629 &end);
630 if (ret < 0) {
631 zlog_warn("%s: error getting label range!", __func__);
632 return -1;
633 }
634
635 return 0;
636 }
637
638 /**
639 * Release Label Range to the Label Manager.
640 *
641 * @param start start of label range to release
642 * @param end end of label range to release
643 *
644 * @return 0 on success, -1 otherwise
645 */
646 int isis_zebra_release_label_range(uint32_t start, uint32_t end)
647 {
648 int ret;
649
650 if (zclient_sync->sock < 0)
651 return -1;
652
653 ret = lm_release_label_chunk(zclient_sync, start, end);
654 if (ret < 0) {
655 zlog_warn("%s: error releasing label range!", __func__);
656 return -1;
657 }
658
659 return 0;
660 }
661
662 /**
663 * Connect to the Label Manager.
664 *
665 * @return 0 on success, -1 otherwise
666 */
667 int isis_zebra_label_manager_connect(void)
668 {
669 /* Connect to label manager. */
670 if (zclient_socket_connect(zclient_sync) < 0) {
671 zlog_warn("%s: failed connecting synchronous zclient!",
672 __func__);
673 return -1;
674 }
675 /* make socket non-blocking */
676 set_nonblocking(zclient_sync->sock);
677
678 /* Send hello to notify zebra this is a synchronous client */
679 if (zclient_send_hello(zclient_sync) == ZCLIENT_SEND_FAILURE) {
680 zlog_warn("%s: failed sending hello for synchronous zclient!",
681 __func__);
682 close(zclient_sync->sock);
683 zclient_sync->sock = -1;
684 return -1;
685 }
686
687 /* Connect to label manager */
688 if (lm_label_manager_connect(zclient_sync, 0) != 0) {
689 zlog_warn("%s: failed connecting to label manager!", __func__);
690 if (zclient_sync->sock > 0) {
691 close(zclient_sync->sock);
692 zclient_sync->sock = -1;
693 }
694 return -1;
695 }
696
697 sr_debug("ISIS-Sr: Successfully connected to the Label Manager");
698
699 return 0;
700 }
701
702 void isis_zebra_vrf_register(struct isis *isis)
703 {
704 if (!zclient || zclient->sock < 0 || !isis)
705 return;
706
707 if (isis->vrf_id != VRF_UNKNOWN) {
708 if (IS_DEBUG_EVENTS)
709 zlog_debug("%s: Register VRF %s id %u", __func__,
710 isis->name, isis->vrf_id);
711 zclient_send_reg_requests(zclient, isis->vrf_id);
712 }
713 }
714
715 void isis_zebra_vrf_deregister(struct isis *isis)
716 {
717 if (!zclient || zclient->sock < 0 || !isis)
718 return;
719
720 if (isis->vrf_id != VRF_UNKNOWN) {
721 if (IS_DEBUG_EVENTS)
722 zlog_debug("%s: Deregister VRF %s id %u", __func__,
723 isis->name, isis->vrf_id);
724 zclient_send_dereg_requests(zclient, isis->vrf_id);
725 }
726 }
727
728 static void isis_zebra_connected(struct zclient *zclient)
729 {
730 zclient_send_reg_requests(zclient, VRF_DEFAULT);
731 zclient_register_opaque(zclient, LDP_RLFA_LABELS);
732 zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
733 zclient_register_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
734 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
735 }
736
737 /**
738 * Register / unregister Link State ZAPI Opaque Message
739 *
740 * @param up True to register, false to unregister
741 *
742 * @return 0 if success, -1 otherwise
743 */
744 int isis_zebra_ls_register(bool up)
745 {
746 int rc;
747
748 if (up)
749 rc = ls_register(zclient, true);
750 else
751 rc = ls_unregister(zclient, true);
752
753 return rc;
754 }
755
756 /*
757 * opaque messages between processes
758 */
759 static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
760 {
761 struct stream *s;
762 struct zapi_opaque_msg info;
763 struct zapi_opaque_reg_info dst;
764 struct ldp_igp_sync_if_state state;
765 struct ldp_igp_sync_announce announce;
766 struct zapi_rlfa_response rlfa;
767 int ret = 0;
768
769 s = zclient->ibuf;
770 if (zclient_opaque_decode(s, &info) != 0)
771 return -1;
772
773 switch (info.type) {
774 case LINK_STATE_SYNC:
775 STREAM_GETC(s, dst.proto);
776 STREAM_GETW(s, dst.instance);
777 STREAM_GETL(s, dst.session_id);
778 dst.type = LINK_STATE_SYNC;
779 ret = isis_te_sync_ted(dst);
780 break;
781 case LDP_IGP_SYNC_IF_STATE_UPDATE:
782 STREAM_GET(&state, s, sizeof(state));
783 ret = isis_ldp_sync_state_update(state);
784 break;
785 case LDP_IGP_SYNC_ANNOUNCE_UPDATE:
786 STREAM_GET(&announce, s, sizeof(announce));
787 ret = isis_ldp_sync_announce_update(announce);
788 break;
789 case LDP_RLFA_LABELS:
790 STREAM_GET(&rlfa, s, sizeof(rlfa));
791 isis_rlfa_process_ldp_response(&rlfa);
792 break;
793 default:
794 break;
795 }
796
797 stream_failure:
798
799 return ret;
800 }
801
802 static int isis_zebra_client_close_notify(ZAPI_CALLBACK_ARGS)
803 {
804 int ret = 0;
805
806 struct zapi_client_close_info info;
807
808 if (zapi_client_close_notify_decode(zclient->ibuf, &info) < 0)
809 return -1;
810
811 isis_ldp_sync_handle_client_close(&info);
812 isis_ldp_rlfa_handle_client_close(&info);
813
814 return ret;
815 }
816
817 static zclient_handler *const isis_handlers[] = {
818 [ZEBRA_ROUTER_ID_UPDATE] = isis_router_id_update_zebra,
819 [ZEBRA_INTERFACE_ADDRESS_ADD] = isis_zebra_if_address_add,
820 [ZEBRA_INTERFACE_ADDRESS_DELETE] = isis_zebra_if_address_del,
821 [ZEBRA_INTERFACE_LINK_PARAMS] = isis_zebra_link_params,
822 [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = isis_zebra_read,
823 [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = isis_zebra_read,
824
825 [ZEBRA_OPAQUE_MESSAGE] = isis_opaque_msg_handler,
826
827 [ZEBRA_CLIENT_CLOSE_NOTIFY] = isis_zebra_client_close_notify,
828 };
829
830 void isis_zebra_init(struct event_loop *master, int instance)
831 {
832 /* Initialize asynchronous zclient. */
833 zclient = zclient_new(master, &zclient_options_default, isis_handlers,
834 array_size(isis_handlers));
835 zclient_init(zclient, PROTO_TYPE, 0, &isisd_privs);
836 zclient->zebra_connected = isis_zebra_connected;
837
838 /* Initialize special zclient for synchronous message exchanges. */
839 struct zclient_options options = zclient_options_default;
840 options.synchronous = true;
841 zclient_sync = zclient_new(master, &options, NULL, 0);
842 zclient_sync->sock = -1;
843 zclient_sync->redist_default = ZEBRA_ROUTE_ISIS;
844 zclient_sync->instance = instance;
845 /*
846 * session_id must be different from default value (0) to distinguish
847 * the asynchronous socket from the synchronous one
848 */
849 zclient_sync->session_id = 1;
850 zclient_sync->privs = &isisd_privs;
851 }
852
853 void isis_zebra_stop(void)
854 {
855 zclient_unregister_opaque(zclient, LDP_RLFA_LABELS);
856 zclient_unregister_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
857 zclient_unregister_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
858 zclient_stop(zclient_sync);
859 zclient_free(zclient_sync);
860 zclient_stop(zclient);
861 zclient_free(zclient);
862 frr_fini();
863 }