]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_zebra.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / isisd / isis_zebra.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
eb5d44eb 2/*
d62a17ae 3 * IS-IS Rout(e)ing protocol - isis_zebra.c
eb5d44eb 4 *
5 * Copyright (C) 2001,2002 Sampo Saaristo
d62a17ae 6 * Tampere University of Technology
eb5d44eb 7 * Institute of Communications Engineering
f3ccedaa 8 * Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org>
eb5d44eb 9 */
10
11#include <zebra.h>
eb5d44eb 12
24a58196 13#include "frrevent.h"
eb5d44eb 14#include "command.h"
15#include "memory.h"
16#include "log.h"
363be4dd 17#include "lib_errors.h"
eb5d44eb 18#include "if.h"
19#include "network.h"
20#include "prefix.h"
21#include "zclient.h"
22#include "stream.h"
23#include "linklist.h"
f3ccedaa 24#include "nexthop.h"
7076bb2f 25#include "vrf.h"
8879bd22 26#include "libfrr.h"
13bf3830 27#include "bfd.h"
d9884a75 28#include "link_state.h"
eb5d44eb 29
30#include "isisd/isis_constants.h"
31#include "isisd/isis_common.h"
3f045a08
JB
32#include "isisd/isis_flags.h"
33#include "isisd/isis_misc.h"
34#include "isisd/isis_circuit.h"
c89c05dd 35#include "isisd/isisd.h"
eb5d44eb 36#include "isisd/isis_circuit.h"
37#include "isisd/isis_csm.h"
3f045a08 38#include "isisd/isis_lsp.h"
16fe8cff
RW
39#include "isisd/isis_spf.h"
40#include "isisd/isis_spf_private.h"
eb5d44eb 41#include "isisd/isis_route.h"
42#include "isisd/isis_zebra.h"
c3f7b406 43#include "isisd/isis_adjacency.h"
f8c06e2c 44#include "isisd/isis_te.h"
26f6acaf 45#include "isisd/isis_sr.h"
1cbf96a8 46#include "isisd/isis_ldp_sync.h"
eb5d44eb 47
26f6acaf
RW
48struct zclient *zclient;
49static struct zclient *zclient_sync;
50
18a6dce6 51/* Router-id update message from zebra. */
121f9dee 52static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
18a6dce6 53{
d62a17ae 54 struct isis_area *area;
55 struct listnode *node;
56 struct prefix router_id;
eab88f36
K
57 struct isis *isis = NULL;
58
59 isis = isis_lookup_by_vrfid(vrf_id);
60
61 if (isis == NULL) {
62 return -1;
63 }
d62a17ae 64
d62a17ae 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;
18a6dce6 75}
eb5d44eb 76
121f9dee 77static int isis_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
eb5d44eb 78{
115f8f56 79 struct isis_circuit *circuit;
d62a17ae 80 struct connected *c;
eb5d44eb 81
d62a17ae 82 c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD,
83 zclient->ibuf, vrf_id);
f390d2c7 84
d62a17ae 85 if (c == NULL)
86 return 0;
f390d2c7 87
62f30dcc 88#ifdef EXTREME_DEBUG
28315916 89 if (c->address->family == AF_INET)
2dbe669b 90 zlog_debug("connected IP address %pFX", c->address);
28315916 91 if (c->address->family == AF_INET6)
2dbe669b 92 zlog_debug("connected IPv6 address %pFX", c->address);
eb5d44eb 93#endif /* EXTREME_DEBUG */
115f8f56
IR
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 }
eb5d44eb 100
d62a17ae 101 return 0;
eb5d44eb 102}
103
121f9dee 104static int isis_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
eb5d44eb 105{
115f8f56 106 struct isis_circuit *circuit;
d62a17ae 107 struct connected *c;
eb5d44eb 108
d62a17ae 109 c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE,
110 zclient->ibuf, vrf_id);
f390d2c7 111
d62a17ae 112 if (c == NULL)
113 return 0;
f390d2c7 114
f891f443 115#ifdef EXTREME_DEBUG
28315916 116 if (c->address->family == AF_INET)
2dbe669b 117 zlog_debug("disconnected IP address %pFX", c->address);
28315916 118 if (c->address->family == AF_INET6)
2dbe669b 119 zlog_debug("disconnected IPv6 address %pFX", c->address);
f891f443 120#endif /* EXTREME_DEBUG */
f390d2c7 121
115f8f56
IR
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
721c0857 128 connected_free(&c);
f390d2c7 129
d62a17ae 130 return 0;
eb5d44eb 131}
132
121f9dee 133static int isis_zebra_link_params(ZAPI_CALLBACK_ARGS)
f8c06e2c 134{
d62a17ae 135 struct interface *ifp;
0b4124c1 136 bool changed = false;
f8c06e2c 137
0b4124c1 138 ifp = zebra_interface_link_params_read(zclient->ibuf, vrf_id, &changed);
f8c06e2c 139
0b4124c1 140 if (ifp == NULL || !changed)
d62a17ae 141 return 0;
f8c06e2c 142
d62a17ae 143 /* Update TE TLV */
144 isis_mpls_te_update(ifp);
f8c06e2c 145
d62a17ae 146 return 0;
f8c06e2c
OD
147}
148
c951ee6e 149enum isis_zebra_nexthop_type {
d47d6089
RW
150 ISIS_NEXTHOP_MAIN = 0,
151 ISIS_NEXTHOP_BACKUP,
c951ee6e
RW
152};
153
154static int isis_zebra_add_nexthops(struct isis *isis, struct list *nexthops,
155 struct zapi_nexthop zapi_nexthops[],
156 enum isis_zebra_nexthop_type type,
d47d6089 157 bool mpls_lsp, uint8_t backup_nhs)
eb5d44eb 158{
d62a17ae 159 struct isis_nexthop *nexthop;
160 struct listnode *node;
c0721de4 161 int count = 0;
d62a17ae 162
f80dd32b 163 /* Nexthops */
c951ee6e
RW
164 for (ALL_LIST_ELEMENTS_RO(nexthops, node, nexthop)) {
165 struct zapi_nexthop *api_nh;
166
363be4dd
RW
167 if (count >= MULTIPATH_NUM)
168 break;
c951ee6e 169 api_nh = &zapi_nexthops[count];
363be4dd 170 if (fabricd)
68a02e06 171 SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
dc18b3b0 172 api_nh->vrf_id = isis->vrf_id;
363be4dd
RW
173
174 switch (nexthop->family) {
175 case AF_INET:
f80dd32b 176 /* FIXME: can it be ? */
363be4dd 177 if (nexthop->ip.ipv4.s_addr != INADDR_ANY) {
f80dd32b 178 api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
363be4dd 179 api_nh->gate.ipv4 = nexthop->ip.ipv4;
f80dd32b
RW
180 } else {
181 api_nh->type = NEXTHOP_TYPE_IFINDEX;
182 }
363be4dd
RW
183 break;
184 case AF_INET6:
185 if (!IN6_IS_ADDR_LINKLOCAL(&nexthop->ip.ipv6)
186 && !IN6_IS_ADDR_UNSPECIFIED(&nexthop->ip.ipv6)) {
f80dd32b
RW
187 continue;
188 }
363be4dd 189 api_nh->gate.ipv6 = nexthop->ip.ipv6;
f80dd32b 190 api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
363be4dd
RW
191 break;
192 default:
193 flog_err(EC_LIB_DEVELOPMENT,
194 "%s: unknown address family [%d]", __func__,
195 nexthop->family);
196 exit(1);
d62a17ae 197 }
363be4dd
RW
198
199 api_nh->ifindex = nexthop->ifindex;
c951ee6e
RW
200
201 /* Add MPLS label(s). */
50ec2185
RW
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:
d47d6089
RW
212 /*
213 * Do not use non-SR enabled nexthops to prevent
214 * broken LSPs from being formed.
215 */
216 continue;
50ec2185 217 case ISIS_NEXTHOP_BACKUP:
d47d6089
RW
218 /*
219 * This is necessary because zebra requires
220 * the nexthops of MPLS LSPs to be labeled.
221 */
c951ee6e
RW
222 api_nh->label_num = 1;
223 api_nh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
50ec2185 224 break;
c951ee6e 225 }
c951ee6e
RW
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 }
363be4dd 240 count++;
d62a17ae 241 }
c951ee6e
RW
242
243 return count;
244}
245
246void 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
e33b95b4 253 if (zclient->sock < 0)
c0721de4 254 return;
f390d2c7 255
e33b95b4
RW
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
c951ee6e
RW
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,
d47d6089 279 ISIS_NEXTHOP_BACKUP, false, 0);
c951ee6e
RW
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,
d47d6089 288 api.nexthops, ISIS_NEXTHOP_MAIN, false,
c951ee6e
RW
289 count);
290 if (!count)
291 return;
c0721de4 292 api.nexthop_num = count;
f390d2c7 293
c0721de4 294 zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
eb5d44eb 295}
296
dc18b3b0
K
297void isis_zebra_route_del_route(struct isis *isis,
298 struct prefix *prefix,
0a5f3f4f
RW
299 struct prefix_ipv6 *src_p,
300 struct isis_route_info *route_info)
eb5d44eb 301{
c0721de4 302 struct zapi_route api;
d62a17ae 303
0a5f3f4f 304 if (zclient->sock < 0)
d62a17ae 305 return;
306
c0721de4 307 memset(&api, 0, sizeof(api));
dc18b3b0 308 api.vrf_id = isis->vrf_id;
7c0cbd0e 309 api.type = PROTO_TYPE;
d62a17ae 310 api.safi = SAFI_UNICAST;
c0721de4 311 api.prefix = *prefix;
321c1bbb
CF
312 if (src_p && src_p->prefixlen) {
313 api.src_prefix = *src_p;
314 SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
315 }
f390d2c7 316
c0721de4 317 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
eb5d44eb 318}
319
f2333421 320/**
d47d6089 321 * Install Prefix-SID label entry in the forwarding plane through Zebra.
f2333421 322 *
d47d6089
RW
323 * @param area IS-IS area
324 * @param prefix Route prefix
325 * @param rinfo Route information
326 * @param psid Prefix-SID information
f2333421 327 */
d47d6089
RW
328void isis_zebra_prefix_sid_install(struct isis_area *area,
329 struct prefix *prefix,
d47d6089 330 struct isis_sr_psid_info *psid)
26f6acaf
RW
331{
332 struct zapi_labels zl;
c951ee6e 333 int count = 0;
26f6acaf 334
7f8dddf4
HS
335 sr_debug("ISIS-Sr (%s): update label %u for prefix %pFX algorithm %u",
336 area->area_tag, psid->label, prefix, psid->algorithm);
d47d6089 337
26f6acaf
RW
338 /* Prepare message. */
339 memset(&zl, 0, sizeof(zl));
340 zl.type = ZEBRA_LSP_ISIS_SR;
d47d6089
RW
341 zl.local_label = psid->label;
342
343 /* Local routes don't have any nexthop and require special handling. */
bdaafbf8 344 if (list_isempty(psid->nexthops)) {
d47d6089
RW
345 struct zapi_nexthop *znh;
346 struct interface *ifp;
26f6acaf 347
26f6acaf
RW
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",
d47d6089 352 __func__, prefix);
26f6acaf
RW
353 return;
354 }
355
356 znh = &zl.nexthops[zl.nexthop_num++];
357 znh->type = NEXTHOP_TYPE_IFINDEX;
358 znh->ifindex = ifp->ifindex;
e0e8a84f
OD
359 znh->label_num = 1;
360 znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
d47d6089 361 } else {
c951ee6e 362 /* Add backup nexthops first. */
bdaafbf8 363 if (psid->nexthops_backup) {
c951ee6e 364 count = isis_zebra_add_nexthops(
bdaafbf8 365 area->isis, psid->nexthops_backup,
d47d6089 366 zl.backup_nexthops, ISIS_NEXTHOP_BACKUP, true,
c951ee6e
RW
367 0);
368 if (count > 0) {
369 SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS);
370 zl.backup_nexthop_num = count;
371 }
26f6acaf 372 }
c951ee6e
RW
373
374 /* Add primary nexthops. */
bdaafbf8 375 count = isis_zebra_add_nexthops(area->isis, psid->nexthops,
d47d6089
RW
376 zl.nexthops, ISIS_NEXTHOP_MAIN,
377 true, count);
c951ee6e
RW
378 if (!count)
379 return;
380 zl.nexthop_num = count;
26f6acaf
RW
381 }
382
383 /* Send message to zebra. */
384 (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_REPLACE, &zl);
385}
386
f2333421 387/**
d47d6089 388 * Uninstall Prefix-SID label entry from the forwarding plane through Zebra.
f2333421 389 *
d47d6089
RW
390 * @param area IS-IS area
391 * @param prefix Route prefix
392 * @param rinfo Route information
393 * @param psid Prefix-SID information
f2333421 394 */
d47d6089
RW
395void 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)
26f6acaf
RW
399{
400 struct zapi_labels zl;
401
7f8dddf4
HS
402 sr_debug("ISIS-Sr (%s): delete label %u for prefix %pFX algorithm %u",
403 area->area_tag, psid->label, prefix, psid->algorithm);
d47d6089 404
26f6acaf
RW
405 /* Prepare message. */
406 memset(&zl, 0, sizeof(zl));
407 zl.type = ZEBRA_LSP_ISIS_SR;
d47d6089 408 zl.local_label = psid->label;
26f6acaf
RW
409
410 /* Send message to zebra. */
411 (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_DELETE, &zl);
412}
413
f2333421
OD
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 */
c3f7b406
OD
420void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
421{
054fda12 422 struct isis *isis = sra->adj->circuit->area->isis;
c3f7b406
OD
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",
054fda12 434 sra->input_label, sra->adj->circuit->interface->name);
c3f7b406
OD
435
436 memset(&zl, 0, sizeof(zl));
437 zl.type = ZEBRA_LSP_ISIS_SR;
054fda12 438 zl.local_label = sra->input_label;
c3f7b406
OD
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
054fda12
RW
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,
d47d6089 455 ISIS_NEXTHOP_BACKUP, true, 0);
054fda12
RW
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
c3f7b406
OD
467 (void)zebra_send_mpls_labels(zclient, cmd, &zl);
468}
469
121f9dee 470static int isis_zebra_read(ZAPI_CALLBACK_ARGS)
eb5d44eb 471{
74489921 472 struct zapi_route api;
eab88f36
K
473 struct isis *isis = NULL;
474
475 isis = isis_lookup_by_vrfid(vrf_id);
476
477 if (isis == NULL)
478 return -1;
d62a17ae 479
74489921
RW
480 if (zapi_route_decode(zclient->ibuf, &api) < 0)
481 return -1;
d62a17ae 482
9fb2b879
DS
483 if (api.prefix.family == AF_INET6
484 && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
485 return 0;
486
d62a17ae 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 */
d43d2df5
CF
493 if (api.prefix.prefixlen == 0
494 && api.src_prefix.prefixlen == 0
7c0cbd0e 495 && api.type == PROTO_TYPE) {
121f9dee 496 cmd = ZEBRA_REDISTRIBUTE_ROUTE_DEL;
d43d2df5 497 }
d62a17ae 498
121f9dee 499 if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
eab88f36 500 isis_redist_add(isis, api.type, &api.prefix, &api.src_prefix,
3b1e3aab 501 api.distance, api.metric, api.tag);
d62a17ae 502 else
eab88f36
K
503 isis_redist_delete(isis, api.type, &api.prefix,
504 &api.src_prefix);
d62a17ae 505
506 return 0;
eb5d44eb 507}
eb5d44eb 508
d62a17ae 509int isis_distribute_list_update(int routetype)
eb5d44eb 510{
d62a17ae 511 return 0;
eb5d44eb 512}
513
8c6482db 514void isis_zebra_redistribute_set(afi_t afi, int type, vrf_id_t vrf_id)
eb5d44eb 515{
d62a17ae 516 if (type == DEFAULT_ROUTE)
517 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
8c6482db 518 zclient, afi, vrf_id);
d62a17ae 519 else
520 zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type,
8c6482db 521 0, vrf_id);
f3ccedaa
CF
522}
523
8c6482db 524void isis_zebra_redistribute_unset(afi_t afi, int type, vrf_id_t vrf_id)
f3ccedaa 525{
d62a17ae 526 if (type == DEFAULT_ROUTE)
527 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
8c6482db 528 zclient, afi, vrf_id);
d62a17ae 529 else
530 zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi,
8c6482db 531 type, 0, vrf_id);
eb5d44eb 532}
533
16fe8cff
RW
534/**
535 * Register RLFA with LDP.
536 */
537int 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 */
573void 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
774e3570
OD
600/* Label Manager Functions */
601
58fbcdf2
OD
602/**
603 * Check if Label Manager is Ready or not.
604 *
605 * @return True if Label Manager is ready, False otherwise
606 */
607bool isis_zebra_label_manager_ready(void)
608{
609 return (zclient_sync->sock > 0);
610}
611
774e3570
OD
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 */
26f6acaf
RW
620int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
621{
622 int ret;
623 uint32_t start, end;
624
58fbcdf2
OD
625 if (zclient_sync->sock < 0)
626 return -1;
26f6acaf
RW
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
774e3570
OD
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
774e3570 643 *
58fbcdf2 644 * @return 0 on success, -1 otherwise
774e3570 645 */
58fbcdf2 646int isis_zebra_release_label_range(uint32_t start, uint32_t end)
26f6acaf
RW
647{
648 int ret;
26f6acaf 649
58fbcdf2 650 if (zclient_sync->sock < 0)
26f6acaf 651 return -1;
26f6acaf
RW
652
653 ret = lm_release_label_chunk(zclient_sync, start, end);
654 if (ret < 0) {
26f6acaf 655 zlog_warn("%s: error releasing label range!", __func__);
26f6acaf
RW
656 return -1;
657 }
658
659 return 0;
660}
661
774e3570
OD
662/**
663 * Connect to the Label Manager.
58fbcdf2
OD
664 *
665 * @return 0 on success, -1 otherwise
774e3570 666 */
58fbcdf2 667int isis_zebra_label_manager_connect(void)
26f6acaf
RW
668{
669 /* Connect to label manager. */
58fbcdf2
OD
670 if (zclient_socket_connect(zclient_sync) < 0) {
671 zlog_warn("%s: failed connecting synchronous zclient!",
26f6acaf 672 __func__);
58fbcdf2 673 return -1;
26f6acaf 674 }
774e3570 675 /* make socket non-blocking */
26f6acaf 676 set_nonblocking(zclient_sync->sock);
774e3570
OD
677
678 /* Send hello to notify zebra this is a synchronous client */
7cfdb485 679 if (zclient_send_hello(zclient_sync) == ZCLIENT_SEND_FAILURE) {
58fbcdf2
OD
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;
774e3570
OD
685 }
686
687 /* Connect to label manager */
58fbcdf2
OD
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;
26f6acaf
RW
695 }
696
58fbcdf2
OD
697 sr_debug("ISIS-Sr: Successfully connected to the Label Manager");
698
699 return 0;
26f6acaf
RW
700}
701
65251ce8 702void 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
164ab896
IR
715void 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}
65251ce8 727
d62a17ae 728static void isis_zebra_connected(struct zclient *zclient)
7076bb2f 729{
d62a17ae 730 zclient_send_reg_requests(zclient, VRF_DEFAULT);
16fe8cff 731 zclient_register_opaque(zclient, LDP_RLFA_LABELS);
ec62fbaa
IR
732 zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
733 zclient_register_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
13bf3830 734 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
7076bb2f
FL
735}
736
d9884a75
OD
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 */
744int 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
1cbf96a8 756/*
757 * opaque messages between processes
758 */
759static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
760{
761 struct stream *s;
762 struct zapi_opaque_msg info;
d9884a75 763 struct zapi_opaque_reg_info dst;
1cbf96a8 764 struct ldp_igp_sync_if_state state;
765 struct ldp_igp_sync_announce announce;
16fe8cff 766 struct zapi_rlfa_response rlfa;
1cbf96a8 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) {
d9884a75
OD
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;
1cbf96a8 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;
16fe8cff
RW
789 case LDP_RLFA_LABELS:
790 STREAM_GET(&rlfa, s, sizeof(rlfa));
791 isis_rlfa_process_ldp_response(&rlfa);
792 break;
1cbf96a8 793 default:
794 break;
795 }
796
797stream_failure:
798
799 return ret;
800}
801
cb135cc9
KS
802static 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);
16fe8cff 812 isis_ldp_rlfa_handle_client_close(&info);
cb135cc9
KS
813
814 return ret;
815}
816
a243d1db
DL
817static 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
cd9d0537 830void isis_zebra_init(struct event_loop *master, int instance)
eb5d44eb 831{
26f6acaf 832 /* Initialize asynchronous zclient. */
a243d1db
DL
833 zclient = zclient_new(master, &zclient_options_default, isis_handlers,
834 array_size(isis_handlers));
7c0cbd0e 835 zclient_init(zclient, PROTO_TYPE, 0, &isisd_privs);
d62a17ae 836 zclient->zebra_connected = isis_zebra_connected;
d62a17ae 837
26f6acaf 838 /* Initialize special zclient for synchronous message exchanges. */
774e3570
OD
839 struct zclient_options options = zclient_options_default;
840 options.synchronous = true;
a243d1db 841 zclient_sync = zclient_new(master, &options, NULL, 0);
26f6acaf
RW
842 zclient_sync->sock = -1;
843 zclient_sync->redist_default = ZEBRA_ROUTE_ISIS;
844 zclient_sync->instance = instance;
774e3570
OD
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;
26f6acaf 850 zclient_sync->privs = &isisd_privs;
eb5d44eb 851}
8d429559 852
d62a17ae 853void isis_zebra_stop(void)
8d429559 854{
16fe8cff 855 zclient_unregister_opaque(zclient, LDP_RLFA_LABELS);
ec62fbaa
IR
856 zclient_unregister_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
857 zclient_unregister_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
58fbcdf2
OD
858 zclient_stop(zclient_sync);
859 zclient_free(zclient_sync);
d62a17ae 860 zclient_stop(zclient);
861 zclient_free(zclient);
8879bd22 862 frr_fini();
8d429559 863}