]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_zebra.c
isisd: update struct isis_sr_psid_info with algorithm id
[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,
330 struct isis_route_info *rinfo,
331 struct isis_sr_psid_info *psid)
26f6acaf
RW
332{
333 struct zapi_labels zl;
c951ee6e 334 int count = 0;
26f6acaf 335
7f8dddf4
HS
336 sr_debug("ISIS-Sr (%s): update label %u for prefix %pFX algorithm %u",
337 area->area_tag, psid->label, prefix, psid->algorithm);
d47d6089 338
26f6acaf
RW
339 /* Prepare message. */
340 memset(&zl, 0, sizeof(zl));
341 zl.type = ZEBRA_LSP_ISIS_SR;
d47d6089
RW
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;
26f6acaf 348
26f6acaf
RW
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",
d47d6089 353 __func__, prefix);
26f6acaf
RW
354 return;
355 }
356
357 znh = &zl.nexthops[zl.nexthop_num++];
358 znh->type = NEXTHOP_TYPE_IFINDEX;
359 znh->ifindex = ifp->ifindex;
e0e8a84f
OD
360 znh->label_num = 1;
361 znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
d47d6089 362 } else {
c951ee6e
RW
363 /* Add backup nexthops first. */
364 if (rinfo->backup) {
365 count = isis_zebra_add_nexthops(
d47d6089
RW
366 area->isis, rinfo->backup->nexthops,
367 zl.backup_nexthops, ISIS_NEXTHOP_BACKUP, true,
c951ee6e
RW
368 0);
369 if (count > 0) {
370 SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS);
371 zl.backup_nexthop_num = count;
372 }
26f6acaf 373 }
c951ee6e
RW
374
375 /* Add primary nexthops. */
d47d6089
RW
376 count = isis_zebra_add_nexthops(area->isis, rinfo->nexthops,
377 zl.nexthops, ISIS_NEXTHOP_MAIN,
378 true, count);
c951ee6e
RW
379 if (!count)
380 return;
381 zl.nexthop_num = count;
26f6acaf
RW
382 }
383
384 /* Send message to zebra. */
385 (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_REPLACE, &zl);
386}
387
f2333421 388/**
d47d6089 389 * Uninstall Prefix-SID label entry from the forwarding plane through Zebra.
f2333421 390 *
d47d6089
RW
391 * @param area IS-IS area
392 * @param prefix Route prefix
393 * @param rinfo Route information
394 * @param psid Prefix-SID information
f2333421 395 */
d47d6089
RW
396void 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)
26f6acaf
RW
400{
401 struct zapi_labels zl;
402
7f8dddf4
HS
403 sr_debug("ISIS-Sr (%s): delete label %u for prefix %pFX algorithm %u",
404 area->area_tag, psid->label, prefix, psid->algorithm);
d47d6089 405
26f6acaf
RW
406 /* Prepare message. */
407 memset(&zl, 0, sizeof(zl));
408 zl.type = ZEBRA_LSP_ISIS_SR;
d47d6089 409 zl.local_label = psid->label;
26f6acaf
RW
410
411 /* Send message to zebra. */
412 (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_DELETE, &zl);
413}
414
f2333421
OD
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 */
c3f7b406
OD
421void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
422{
054fda12 423 struct isis *isis = sra->adj->circuit->area->isis;
c3f7b406
OD
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",
054fda12 435 sra->input_label, sra->adj->circuit->interface->name);
c3f7b406
OD
436
437 memset(&zl, 0, sizeof(zl));
438 zl.type = ZEBRA_LSP_ISIS_SR;
054fda12 439 zl.local_label = sra->input_label;
c3f7b406
OD
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
054fda12
RW
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,
d47d6089 456 ISIS_NEXTHOP_BACKUP, true, 0);
054fda12
RW
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
c3f7b406
OD
468 (void)zebra_send_mpls_labels(zclient, cmd, &zl);
469}
470
121f9dee 471static int isis_zebra_read(ZAPI_CALLBACK_ARGS)
eb5d44eb 472{
74489921 473 struct zapi_route api;
eab88f36
K
474 struct isis *isis = NULL;
475
476 isis = isis_lookup_by_vrfid(vrf_id);
477
478 if (isis == NULL)
479 return -1;
d62a17ae 480
74489921
RW
481 if (zapi_route_decode(zclient->ibuf, &api) < 0)
482 return -1;
d62a17ae 483
9fb2b879
DS
484 if (api.prefix.family == AF_INET6
485 && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
486 return 0;
487
d62a17ae 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 */
d43d2df5
CF
494 if (api.prefix.prefixlen == 0
495 && api.src_prefix.prefixlen == 0
7c0cbd0e 496 && api.type == PROTO_TYPE) {
121f9dee 497 cmd = ZEBRA_REDISTRIBUTE_ROUTE_DEL;
d43d2df5 498 }
d62a17ae 499
121f9dee 500 if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
eab88f36 501 isis_redist_add(isis, api.type, &api.prefix, &api.src_prefix,
3b1e3aab 502 api.distance, api.metric, api.tag);
d62a17ae 503 else
eab88f36
K
504 isis_redist_delete(isis, api.type, &api.prefix,
505 &api.src_prefix);
d62a17ae 506
507 return 0;
eb5d44eb 508}
eb5d44eb 509
d62a17ae 510int isis_distribute_list_update(int routetype)
eb5d44eb 511{
d62a17ae 512 return 0;
eb5d44eb 513}
514
8c6482db 515void isis_zebra_redistribute_set(afi_t afi, int type, vrf_id_t vrf_id)
eb5d44eb 516{
d62a17ae 517 if (type == DEFAULT_ROUTE)
518 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
8c6482db 519 zclient, afi, vrf_id);
d62a17ae 520 else
521 zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type,
8c6482db 522 0, vrf_id);
f3ccedaa
CF
523}
524
8c6482db 525void isis_zebra_redistribute_unset(afi_t afi, int type, vrf_id_t vrf_id)
f3ccedaa 526{
d62a17ae 527 if (type == DEFAULT_ROUTE)
528 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
8c6482db 529 zclient, afi, vrf_id);
d62a17ae 530 else
531 zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi,
8c6482db 532 type, 0, vrf_id);
eb5d44eb 533}
534
16fe8cff
RW
535/**
536 * Register RLFA with LDP.
537 */
538int 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 */
574void 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
774e3570
OD
601/* Label Manager Functions */
602
58fbcdf2
OD
603/**
604 * Check if Label Manager is Ready or not.
605 *
606 * @return True if Label Manager is ready, False otherwise
607 */
608bool isis_zebra_label_manager_ready(void)
609{
610 return (zclient_sync->sock > 0);
611}
612
774e3570
OD
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 */
26f6acaf
RW
621int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
622{
623 int ret;
624 uint32_t start, end;
625
58fbcdf2
OD
626 if (zclient_sync->sock < 0)
627 return -1;
26f6acaf
RW
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
774e3570
OD
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
774e3570 644 *
58fbcdf2 645 * @return 0 on success, -1 otherwise
774e3570 646 */
58fbcdf2 647int isis_zebra_release_label_range(uint32_t start, uint32_t end)
26f6acaf
RW
648{
649 int ret;
26f6acaf 650
58fbcdf2 651 if (zclient_sync->sock < 0)
26f6acaf 652 return -1;
26f6acaf
RW
653
654 ret = lm_release_label_chunk(zclient_sync, start, end);
655 if (ret < 0) {
26f6acaf 656 zlog_warn("%s: error releasing label range!", __func__);
26f6acaf
RW
657 return -1;
658 }
659
660 return 0;
661}
662
774e3570
OD
663/**
664 * Connect to the Label Manager.
58fbcdf2
OD
665 *
666 * @return 0 on success, -1 otherwise
774e3570 667 */
58fbcdf2 668int isis_zebra_label_manager_connect(void)
26f6acaf
RW
669{
670 /* Connect to label manager. */
58fbcdf2
OD
671 if (zclient_socket_connect(zclient_sync) < 0) {
672 zlog_warn("%s: failed connecting synchronous zclient!",
26f6acaf 673 __func__);
58fbcdf2 674 return -1;
26f6acaf 675 }
774e3570 676 /* make socket non-blocking */
26f6acaf 677 set_nonblocking(zclient_sync->sock);
774e3570
OD
678
679 /* Send hello to notify zebra this is a synchronous client */
7cfdb485 680 if (zclient_send_hello(zclient_sync) == ZCLIENT_SEND_FAILURE) {
58fbcdf2
OD
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;
774e3570
OD
686 }
687
688 /* Connect to label manager */
58fbcdf2
OD
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;
26f6acaf
RW
696 }
697
58fbcdf2
OD
698 sr_debug("ISIS-Sr: Successfully connected to the Label Manager");
699
700 return 0;
26f6acaf
RW
701}
702
65251ce8 703void 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
164ab896
IR
716void 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}
65251ce8 728
d62a17ae 729static void isis_zebra_connected(struct zclient *zclient)
7076bb2f 730{
d62a17ae 731 zclient_send_reg_requests(zclient, VRF_DEFAULT);
16fe8cff 732 zclient_register_opaque(zclient, LDP_RLFA_LABELS);
ec62fbaa
IR
733 zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
734 zclient_register_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
13bf3830 735 bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
7076bb2f
FL
736}
737
d9884a75
OD
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 */
745int 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
1cbf96a8 757/*
758 * opaque messages between processes
759 */
760static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
761{
762 struct stream *s;
763 struct zapi_opaque_msg info;
d9884a75 764 struct zapi_opaque_reg_info dst;
1cbf96a8 765 struct ldp_igp_sync_if_state state;
766 struct ldp_igp_sync_announce announce;
16fe8cff 767 struct zapi_rlfa_response rlfa;
1cbf96a8 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) {
d9884a75
OD
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;
1cbf96a8 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;
16fe8cff
RW
790 case LDP_RLFA_LABELS:
791 STREAM_GET(&rlfa, s, sizeof(rlfa));
792 isis_rlfa_process_ldp_response(&rlfa);
793 break;
1cbf96a8 794 default:
795 break;
796 }
797
798stream_failure:
799
800 return ret;
801}
802
cb135cc9
KS
803static 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);
16fe8cff 813 isis_ldp_rlfa_handle_client_close(&info);
cb135cc9
KS
814
815 return ret;
816}
817
a243d1db
DL
818static 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
cd9d0537 831void isis_zebra_init(struct event_loop *master, int instance)
eb5d44eb 832{
26f6acaf 833 /* Initialize asynchronous zclient. */
a243d1db
DL
834 zclient = zclient_new(master, &zclient_options_default, isis_handlers,
835 array_size(isis_handlers));
7c0cbd0e 836 zclient_init(zclient, PROTO_TYPE, 0, &isisd_privs);
d62a17ae 837 zclient->zebra_connected = isis_zebra_connected;
d62a17ae 838
26f6acaf 839 /* Initialize special zclient for synchronous message exchanges. */
774e3570
OD
840 struct zclient_options options = zclient_options_default;
841 options.synchronous = true;
a243d1db 842 zclient_sync = zclient_new(master, &options, NULL, 0);
26f6acaf
RW
843 zclient_sync->sock = -1;
844 zclient_sync->redist_default = ZEBRA_ROUTE_ISIS;
845 zclient_sync->instance = instance;
774e3570
OD
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;
26f6acaf 851 zclient_sync->privs = &isisd_privs;
eb5d44eb 852}
8d429559 853
d62a17ae 854void isis_zebra_stop(void)
8d429559 855{
16fe8cff 856 zclient_unregister_opaque(zclient, LDP_RLFA_LABELS);
ec62fbaa
IR
857 zclient_unregister_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
858 zclient_unregister_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
58fbcdf2
OD
859 zclient_stop(zclient_sync);
860 zclient_free(zclient_sync);
d62a17ae 861 zclient_stop(zclient);
862 zclient_free(zclient);
8879bd22 863 frr_fini();
8d429559 864}