]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_zebra.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[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 "thread.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_route_info *rinfo,
331 struct isis_sr_psid_info *psid)
332 {
333 struct zapi_labels zl;
334 int count = 0;
335
336 sr_debug("ISIS-Sr (%s): update label %u for prefix %pFX",
337 area->area_tag, psid->label, prefix);
338
339 /* Prepare message. */
340 memset(&zl, 0, sizeof(zl));
341 zl.type = ZEBRA_LSP_ISIS_SR;
342 zl.local_label = psid->label;
343
344 /* Local routes don't have any nexthop and require special handling. */
345 if (list_isempty(rinfo->nexthops)) {
346 struct zapi_nexthop *znh;
347 struct interface *ifp;
348
349 ifp = if_lookup_by_name("lo", VRF_DEFAULT);
350 if (!ifp) {
351 zlog_warn(
352 "%s: couldn't install Prefix-SID %pFX: loopback interface not found",
353 __func__, prefix);
354 return;
355 }
356
357 znh = &zl.nexthops[zl.nexthop_num++];
358 znh->type = NEXTHOP_TYPE_IFINDEX;
359 znh->ifindex = ifp->ifindex;
360 znh->label_num = 1;
361 znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
362 } else {
363 /* Add backup nexthops first. */
364 if (rinfo->backup) {
365 count = isis_zebra_add_nexthops(
366 area->isis, rinfo->backup->nexthops,
367 zl.backup_nexthops, ISIS_NEXTHOP_BACKUP, true,
368 0);
369 if (count > 0) {
370 SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS);
371 zl.backup_nexthop_num = count;
372 }
373 }
374
375 /* Add primary nexthops. */
376 count = isis_zebra_add_nexthops(area->isis, rinfo->nexthops,
377 zl.nexthops, ISIS_NEXTHOP_MAIN,
378 true, count);
379 if (!count)
380 return;
381 zl.nexthop_num = count;
382 }
383
384 /* Send message to zebra. */
385 (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_REPLACE, &zl);
386 }
387
388 /**
389 * Uninstall Prefix-SID label entry from the forwarding plane through Zebra.
390 *
391 * @param area IS-IS area
392 * @param prefix Route prefix
393 * @param rinfo Route information
394 * @param psid Prefix-SID information
395 */
396 void isis_zebra_prefix_sid_uninstall(struct isis_area *area,
397 struct prefix *prefix,
398 struct isis_route_info *rinfo,
399 struct isis_sr_psid_info *psid)
400 {
401 struct zapi_labels zl;
402
403 sr_debug("ISIS-Sr (%s): delete label %u for prefix %pFX",
404 area->area_tag, psid->label, prefix);
405
406 /* Prepare message. */
407 memset(&zl, 0, sizeof(zl));
408 zl.type = ZEBRA_LSP_ISIS_SR;
409 zl.local_label = psid->label;
410
411 /* Send message to zebra. */
412 (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_DELETE, &zl);
413 }
414
415 /**
416 * Send (LAN)-Adjacency-SID to ZEBRA for installation or deletion.
417 *
418 * @param cmd ZEBRA_MPLS_LABELS_ADD or ZEBRA_ROUTE_DELETE
419 * @param sra Segment Routing Adjacency-SID
420 */
421 void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
422 {
423 struct isis *isis = sra->adj->circuit->area->isis;
424 struct zapi_labels zl;
425 struct zapi_nexthop *znh;
426
427 if (cmd != ZEBRA_MPLS_LABELS_ADD && cmd != ZEBRA_MPLS_LABELS_DELETE) {
428 flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command",
429 __func__);
430 return;
431 }
432
433 sr_debug(" |- %s label %u for interface %s",
434 cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete",
435 sra->input_label, sra->adj->circuit->interface->name);
436
437 memset(&zl, 0, sizeof(zl));
438 zl.type = ZEBRA_LSP_ISIS_SR;
439 zl.local_label = sra->input_label;
440 zl.nexthop_num = 1;
441 znh = &zl.nexthops[0];
442 znh->gate = sra->nexthop.address;
443 znh->type = (sra->nexthop.family == AF_INET)
444 ? NEXTHOP_TYPE_IPV4_IFINDEX
445 : NEXTHOP_TYPE_IPV6_IFINDEX;
446 znh->ifindex = sra->adj->circuit->interface->ifindex;
447 znh->label_num = 1;
448 znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
449
450 /* Set backup nexthops. */
451 if (sra->type == ISIS_SR_LAN_BACKUP) {
452 int count;
453
454 count = isis_zebra_add_nexthops(isis, sra->backup_nexthops,
455 zl.backup_nexthops,
456 ISIS_NEXTHOP_BACKUP, true, 0);
457 if (count > 0) {
458 SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS);
459 zl.backup_nexthop_num = count;
460
461 SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
462 znh->backup_num = count;
463 for (int i = 0; i < count; i++)
464 znh->backup_idx[i] = i;
465 }
466 }
467
468 (void)zebra_send_mpls_labels(zclient, cmd, &zl);
469 }
470
471 static int isis_zebra_read(ZAPI_CALLBACK_ARGS)
472 {
473 struct zapi_route api;
474 struct isis *isis = NULL;
475
476 isis = isis_lookup_by_vrfid(vrf_id);
477
478 if (isis == NULL)
479 return -1;
480
481 if (zapi_route_decode(zclient->ibuf, &api) < 0)
482 return -1;
483
484 if (api.prefix.family == AF_INET6
485 && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
486 return 0;
487
488 /*
489 * Avoid advertising a false default reachability. (A default
490 * route installed by IS-IS gets redistributed from zebra back
491 * into IS-IS causing us to start advertising default reachabity
492 * without this check)
493 */
494 if (api.prefix.prefixlen == 0
495 && api.src_prefix.prefixlen == 0
496 && api.type == PROTO_TYPE) {
497 cmd = ZEBRA_REDISTRIBUTE_ROUTE_DEL;
498 }
499
500 if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
501 isis_redist_add(isis, api.type, &api.prefix, &api.src_prefix,
502 api.distance, api.metric, api.tag);
503 else
504 isis_redist_delete(isis, api.type, &api.prefix,
505 &api.src_prefix);
506
507 return 0;
508 }
509
510 int isis_distribute_list_update(int routetype)
511 {
512 return 0;
513 }
514
515 void isis_zebra_redistribute_set(afi_t afi, int type, vrf_id_t vrf_id)
516 {
517 if (type == DEFAULT_ROUTE)
518 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
519 zclient, afi, vrf_id);
520 else
521 zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type,
522 0, vrf_id);
523 }
524
525 void isis_zebra_redistribute_unset(afi_t afi, int type, vrf_id_t vrf_id)
526 {
527 if (type == DEFAULT_ROUTE)
528 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
529 zclient, afi, vrf_id);
530 else
531 zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi,
532 type, 0, vrf_id);
533 }
534
535 /**
536 * Register RLFA with LDP.
537 */
538 int isis_zebra_rlfa_register(struct isis_spftree *spftree, struct rlfa *rlfa)
539 {
540 struct isis_area *area = spftree->area;
541 struct zapi_rlfa_request zr = {};
542 int ret;
543
544 if (!zclient)
545 return 0;
546
547 zr.igp.vrf_id = area->isis->vrf_id;
548 zr.igp.protocol = ZEBRA_ROUTE_ISIS;
549 strlcpy(zr.igp.isis.area_tag, area->area_tag,
550 sizeof(zr.igp.isis.area_tag));
551 zr.igp.isis.spf.tree_id = spftree->tree_id;
552 zr.igp.isis.spf.level = spftree->level;
553 zr.igp.isis.spf.run_id = spftree->runcount;
554 zr.destination = rlfa->prefix;
555 zr.pq_address = rlfa->pq_address;
556
557 zlog_debug("ISIS-LFA: registering RLFA %pFX@%pI4 with LDP",
558 &rlfa->prefix, &rlfa->pq_address);
559
560 ret = zclient_send_opaque_unicast(zclient, LDP_RLFA_REGISTER,
561 ZEBRA_ROUTE_LDP, 0, 0,
562 (const uint8_t *)&zr, sizeof(zr));
563 if (ret == ZCLIENT_SEND_FAILURE) {
564 zlog_warn("ISIS-LFA: failed to register RLFA with LDP");
565 return -1;
566 }
567
568 return 0;
569 }
570
571 /**
572 * Unregister all RLFAs from the given SPF tree with LDP.
573 */
574 void isis_zebra_rlfa_unregister_all(struct isis_spftree *spftree)
575 {
576 struct isis_area *area = spftree->area;
577 struct zapi_rlfa_igp igp = {};
578 int ret;
579
580 if (!zclient || spftree->type != SPF_TYPE_FORWARD
581 || CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
582 return;
583
584 if (IS_DEBUG_LFA)
585 zlog_debug("ISIS-LFA: unregistering all RLFAs with LDP");
586
587 igp.vrf_id = area->isis->vrf_id;
588 igp.protocol = ZEBRA_ROUTE_ISIS;
589 strlcpy(igp.isis.area_tag, area->area_tag, sizeof(igp.isis.area_tag));
590 igp.isis.spf.tree_id = spftree->tree_id;
591 igp.isis.spf.level = spftree->level;
592 igp.isis.spf.run_id = spftree->runcount;
593
594 ret = zclient_send_opaque_unicast(zclient, LDP_RLFA_UNREGISTER_ALL,
595 ZEBRA_ROUTE_LDP, 0, 0,
596 (const uint8_t *)&igp, sizeof(igp));
597 if (ret == ZCLIENT_SEND_FAILURE)
598 zlog_warn("ISIS-LFA: failed to unregister RLFA with LDP");
599 }
600
601 /* Label Manager Functions */
602
603 /**
604 * Check if Label Manager is Ready or not.
605 *
606 * @return True if Label Manager is ready, False otherwise
607 */
608 bool isis_zebra_label_manager_ready(void)
609 {
610 return (zclient_sync->sock > 0);
611 }
612
613 /**
614 * Request Label Range to the Label Manager.
615 *
616 * @param base base label of the label range to request
617 * @param chunk_size size of the label range to request
618 *
619 * @return 0 on success, -1 on failure
620 */
621 int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
622 {
623 int ret;
624 uint32_t start, end;
625
626 if (zclient_sync->sock < 0)
627 return -1;
628
629 ret = lm_get_label_chunk(zclient_sync, 0, base, chunk_size, &start,
630 &end);
631 if (ret < 0) {
632 zlog_warn("%s: error getting label range!", __func__);
633 return -1;
634 }
635
636 return 0;
637 }
638
639 /**
640 * Release Label Range to the Label Manager.
641 *
642 * @param start start of label range to release
643 * @param end end of label range to release
644 *
645 * @return 0 on success, -1 otherwise
646 */
647 int isis_zebra_release_label_range(uint32_t start, uint32_t end)
648 {
649 int ret;
650
651 if (zclient_sync->sock < 0)
652 return -1;
653
654 ret = lm_release_label_chunk(zclient_sync, start, end);
655 if (ret < 0) {
656 zlog_warn("%s: error releasing label range!", __func__);
657 return -1;
658 }
659
660 return 0;
661 }
662
663 /**
664 * Connect to the Label Manager.
665 *
666 * @return 0 on success, -1 otherwise
667 */
668 int isis_zebra_label_manager_connect(void)
669 {
670 /* Connect to label manager. */
671 if (zclient_socket_connect(zclient_sync) < 0) {
672 zlog_warn("%s: failed connecting synchronous zclient!",
673 __func__);
674 return -1;
675 }
676 /* make socket non-blocking */
677 set_nonblocking(zclient_sync->sock);
678
679 /* Send hello to notify zebra this is a synchronous client */
680 if (zclient_send_hello(zclient_sync) == ZCLIENT_SEND_FAILURE) {
681 zlog_warn("%s: failed sending hello for synchronous zclient!",
682 __func__);
683 close(zclient_sync->sock);
684 zclient_sync->sock = -1;
685 return -1;
686 }
687
688 /* Connect to label manager */
689 if (lm_label_manager_connect(zclient_sync, 0) != 0) {
690 zlog_warn("%s: failed connecting to label manager!", __func__);
691 if (zclient_sync->sock > 0) {
692 close(zclient_sync->sock);
693 zclient_sync->sock = -1;
694 }
695 return -1;
696 }
697
698 sr_debug("ISIS-Sr: Successfully connected to the Label Manager");
699
700 return 0;
701 }
702
703 void isis_zebra_vrf_register(struct isis *isis)
704 {
705 if (!zclient || zclient->sock < 0 || !isis)
706 return;
707
708 if (isis->vrf_id != VRF_UNKNOWN) {
709 if (IS_DEBUG_EVENTS)
710 zlog_debug("%s: Register VRF %s id %u", __func__,
711 isis->name, isis->vrf_id);
712 zclient_send_reg_requests(zclient, isis->vrf_id);
713 }
714 }
715
716 void isis_zebra_vrf_deregister(struct isis *isis)
717 {
718 if (!zclient || zclient->sock < 0 || !isis)
719 return;
720
721 if (isis->vrf_id != VRF_UNKNOWN) {
722 if (IS_DEBUG_EVENTS)
723 zlog_debug("%s: Deregister VRF %s id %u", __func__,
724 isis->name, isis->vrf_id);
725 zclient_send_dereg_requests(zclient, isis->vrf_id);
726 }
727 }
728
729 static void isis_zebra_connected(struct zclient *zclient)
730 {
731 zclient_send_reg_requests(zclient, VRF_DEFAULT);
732 zclient_register_opaque(zclient, LDP_RLFA_LABELS);
733 zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
734 zclient_register_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
735 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
736 }
737
738 /**
739 * Register / unregister Link State ZAPI Opaque Message
740 *
741 * @param up True to register, false to unregister
742 *
743 * @return 0 if success, -1 otherwise
744 */
745 int isis_zebra_ls_register(bool up)
746 {
747 int rc;
748
749 if (up)
750 rc = ls_register(zclient, true);
751 else
752 rc = ls_unregister(zclient, true);
753
754 return rc;
755 }
756
757 /*
758 * opaque messages between processes
759 */
760 static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
761 {
762 struct stream *s;
763 struct zapi_opaque_msg info;
764 struct zapi_opaque_reg_info dst;
765 struct ldp_igp_sync_if_state state;
766 struct ldp_igp_sync_announce announce;
767 struct zapi_rlfa_response rlfa;
768 int ret = 0;
769
770 s = zclient->ibuf;
771 if (zclient_opaque_decode(s, &info) != 0)
772 return -1;
773
774 switch (info.type) {
775 case LINK_STATE_SYNC:
776 STREAM_GETC(s, dst.proto);
777 STREAM_GETW(s, dst.instance);
778 STREAM_GETL(s, dst.session_id);
779 dst.type = LINK_STATE_SYNC;
780 ret = isis_te_sync_ted(dst);
781 break;
782 case LDP_IGP_SYNC_IF_STATE_UPDATE:
783 STREAM_GET(&state, s, sizeof(state));
784 ret = isis_ldp_sync_state_update(state);
785 break;
786 case LDP_IGP_SYNC_ANNOUNCE_UPDATE:
787 STREAM_GET(&announce, s, sizeof(announce));
788 ret = isis_ldp_sync_announce_update(announce);
789 break;
790 case LDP_RLFA_LABELS:
791 STREAM_GET(&rlfa, s, sizeof(rlfa));
792 isis_rlfa_process_ldp_response(&rlfa);
793 break;
794 default:
795 break;
796 }
797
798 stream_failure:
799
800 return ret;
801 }
802
803 static int isis_zebra_client_close_notify(ZAPI_CALLBACK_ARGS)
804 {
805 int ret = 0;
806
807 struct zapi_client_close_info info;
808
809 if (zapi_client_close_notify_decode(zclient->ibuf, &info) < 0)
810 return -1;
811
812 isis_ldp_sync_handle_client_close(&info);
813 isis_ldp_rlfa_handle_client_close(&info);
814
815 return ret;
816 }
817
818 static zclient_handler *const isis_handlers[] = {
819 [ZEBRA_ROUTER_ID_UPDATE] = isis_router_id_update_zebra,
820 [ZEBRA_INTERFACE_ADDRESS_ADD] = isis_zebra_if_address_add,
821 [ZEBRA_INTERFACE_ADDRESS_DELETE] = isis_zebra_if_address_del,
822 [ZEBRA_INTERFACE_LINK_PARAMS] = isis_zebra_link_params,
823 [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = isis_zebra_read,
824 [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = isis_zebra_read,
825
826 [ZEBRA_OPAQUE_MESSAGE] = isis_opaque_msg_handler,
827
828 [ZEBRA_CLIENT_CLOSE_NOTIFY] = isis_zebra_client_close_notify,
829 };
830
831 void isis_zebra_init(struct thread_master *master, int instance)
832 {
833 /* Initialize asynchronous zclient. */
834 zclient = zclient_new(master, &zclient_options_default, isis_handlers,
835 array_size(isis_handlers));
836 zclient_init(zclient, PROTO_TYPE, 0, &isisd_privs);
837 zclient->zebra_connected = isis_zebra_connected;
838
839 /* Initialize special zclient for synchronous message exchanges. */
840 struct zclient_options options = zclient_options_default;
841 options.synchronous = true;
842 zclient_sync = zclient_new(master, &options, NULL, 0);
843 zclient_sync->sock = -1;
844 zclient_sync->redist_default = ZEBRA_ROUTE_ISIS;
845 zclient_sync->instance = instance;
846 /*
847 * session_id must be different from default value (0) to distinguish
848 * the asynchronous socket from the synchronous one
849 */
850 zclient_sync->session_id = 1;
851 zclient_sync->privs = &isisd_privs;
852 }
853
854 void isis_zebra_stop(void)
855 {
856 zclient_unregister_opaque(zclient, LDP_RLFA_LABELS);
857 zclient_unregister_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
858 zclient_unregister_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
859 zclient_stop(zclient_sync);
860 zclient_free(zclient_sync);
861 zclient_stop(zclient);
862 zclient_free(zclient);
863 frr_fini();
864 }