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