1 /*
2 * IS-IS Rout(e)ing protocol - isis_zebra.c
3 *
4 * Copyright (C) 2001,2002 Sampo Saaristo
5 * Tampere University of Technology
6 * Institute of Communications Engineering
7 * Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org>
8 *
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)
12 * any later version.
13 *
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
17 * more details.
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
22 */
23
24 #include <zebra.h>
25
26 #include "thread.h"
27 #include "command.h"
28 #include "memory.h"
29 #include "log.h"
30 #include "lib_errors.h"
31 #include "if.h"
32 #include "network.h"
33 #include "prefix.h"
34 #include "zclient.h"
35 #include "stream.h"
36 #include "linklist.h"
37 #include "nexthop.h"
38 #include "vrf.h"
39 #include "libfrr.h"
40
41 #include "isisd/isis_constants.h"
42 #include "isisd/isis_common.h"
43 #include "isisd/isis_flags.h"
44 #include "isisd/isis_misc.h"
45 #include "isisd/isis_circuit.h"
46 #include "isisd/isisd.h"
47 #include "isisd/isis_circuit.h"
48 #include "isisd/isis_csm.h"
49 #include "isisd/isis_lsp.h"
50 #include "isisd/isis_route.h"
51 #include "isisd/isis_zebra.h"
52 #include "isisd/isis_adjacency.h"
53 #include "isisd/isis_te.h"
54 #include "isisd/isis_sr.h"
55
56 struct zclient *zclient;
57 static struct zclient *zclient_sync;
58
59 /* Router-id update message from zebra. */
isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)60 static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
61 {
62 struct isis_area *area;
63 struct listnode *node;
64 struct prefix router_id;
65 struct isis *isis = NULL;
66
67 isis = isis_lookup_by_vrfid(vrf_id);
68
69 if (isis == NULL) {
70 return -1;
71 }
72
73 zebra_router_id_update_read(zclient->ibuf, &router_id);
74 if (isis->router_id == router_id.u.prefix4.s_addr)
75 return 0;
76
77 isis->router_id = router_id.u.prefix4.s_addr;
78 for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
79 if (listcount(area->area_addrs) > 0)
80 lsp_regenerate_schedule(area, area->is_type, 0);
81
82 return 0;
83 }
84
isis_zebra_if_address_add(ZAPI_CALLBACK_ARGS)85 static int isis_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
86 {
87 struct isis_circuit *circuit;
88 struct connected *c;
89 #ifdef EXTREME_DEBUG
90 struct prefix *p;
91 char buf[PREFIX2STR_BUFFER];
92 #endif /* EXTREME_DEBUG */
93
94 c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD,
95 zclient->ibuf, vrf_id);
96
97 if (c == NULL)
98 return 0;
99
100 #ifdef EXTREME_DEBUG
101 p = c->address;
102 prefix2str(p, buf, sizeof(buf));
103
104 if (p->family == AF_INET)
105 zlog_debug("connected IP address %s", buf);
106 if (p->family == AF_INET6)
107 zlog_debug("connected IPv6 address %s", buf);
108 #endif /* EXTREME_DEBUG */
109
110 if (if_is_operative(c->ifp)) {
111 circuit = circuit_scan_by_ifp(c->ifp);
112 if (circuit)
113 isis_circuit_add_addr(circuit, c);
114 }
115
116 return 0;
117 }
118
isis_zebra_if_address_del(ZAPI_CALLBACK_ARGS)119 static int isis_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
120 {
121 struct isis_circuit *circuit;
122 struct connected *c;
123 #ifdef EXTREME_DEBUG
124 struct prefix *p;
125 char buf[PREFIX2STR_BUFFER];
126 #endif /* EXTREME_DEBUG */
127
128 c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE,
129 zclient->ibuf, vrf_id);
130
131 if (c == NULL)
132 return 0;
133
134 #ifdef EXTREME_DEBUG
135 p = c->address;
136 prefix2str(p, buf, sizeof(buf));
137
138 if (p->family == AF_INET)
139 zlog_debug("disconnected IP address %s", buf);
140 if (p->family == AF_INET6)
141 zlog_debug("disconnected IPv6 address %s", buf);
142 #endif /* EXTREME_DEBUG */
143
144 if (if_is_operative(c->ifp)) {
145 circuit = circuit_scan_by_ifp(c->ifp);
146 if (circuit)
147 isis_circuit_del_addr(circuit, c);
148 }
149
150 connected_free(&c);
151
152 return 0;
153 }
154
isis_zebra_link_params(ZAPI_CALLBACK_ARGS)155 static int isis_zebra_link_params(ZAPI_CALLBACK_ARGS)
156 {
157 struct interface *ifp;
158
159 ifp = zebra_interface_link_params_read(zclient->ibuf, vrf_id);
160
161 if (ifp == NULL)
162 return 0;
163
164 /* Update TE TLV */
165 isis_mpls_te_update(ifp);
166
167 return 0;
168 }
169
isis_zebra_route_add_route(struct isis * isis,struct prefix * prefix,struct prefix_ipv6 * src_p,struct isis_route_info * route_info)170 void isis_zebra_route_add_route(struct isis *isis,
171 struct prefix *prefix,
172 struct prefix_ipv6 *src_p,
173 struct isis_route_info *route_info)
174 {
175 struct zapi_route api;
176 struct zapi_nexthop *api_nh;
177 struct isis_nexthop *nexthop;
178 struct listnode *node;
179 int count = 0;
180
181 if (zclient->sock < 0)
182 return;
183
184 memset(&api, 0, sizeof(api));
185 api.vrf_id = isis->vrf_id;
186 api.type = PROTO_TYPE;
187 api.safi = SAFI_UNICAST;
188 api.prefix = *prefix;
189 if (src_p && src_p->prefixlen) {
190 api.src_prefix = *src_p;
191 SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
192 }
193 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
194 SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
195 api.metric = route_info->cost;
196 #if 0
197 SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
198 api.distance = route_info->depth;
199 #endif
200
201 /* Nexthops */
202 for (ALL_LIST_ELEMENTS_RO(route_info->nexthops, node, nexthop)) {
203 if (count >= MULTIPATH_NUM)
204 break;
205 api_nh = &api.nexthops[count];
206 if (fabricd)
207 SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
208 api_nh->vrf_id = isis->vrf_id;
209
210 switch (nexthop->family) {
211 case AF_INET:
212 /* FIXME: can it be ? */
213 if (nexthop->ip.ipv4.s_addr != INADDR_ANY) {
214 api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
215 api_nh->gate.ipv4 = nexthop->ip.ipv4;
216 } else {
217 api_nh->type = NEXTHOP_TYPE_IFINDEX;
218 }
219 break;
220 case AF_INET6:
221 if (!IN6_IS_ADDR_LINKLOCAL(&nexthop->ip.ipv6)
222 && !IN6_IS_ADDR_UNSPECIFIED(&nexthop->ip.ipv6)) {
223 continue;
224 }
225 api_nh->gate.ipv6 = nexthop->ip.ipv6;
226 api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
227 break;
228 default:
229 flog_err(EC_LIB_DEVELOPMENT,
230 "%s: unknown address family [%d]", __func__,
231 nexthop->family);
232 exit(1);
233 }
234
235 api_nh->ifindex = nexthop->ifindex;
236 count++;
237 }
238 if (!count)
239 return;
240
241 api.nexthop_num = count;
242
243 zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
244 }
245
isis_zebra_route_del_route(struct isis * isis,struct prefix * prefix,struct prefix_ipv6 * src_p,struct isis_route_info * route_info)246 void isis_zebra_route_del_route(struct isis *isis,
247 struct prefix *prefix,
248 struct prefix_ipv6 *src_p,
249 struct isis_route_info *route_info)
250 {
251 struct zapi_route api;
252
253 if (zclient->sock < 0)
254 return;
255
256 memset(&api, 0, sizeof(api));
257 api.vrf_id = isis->vrf_id;
258 api.type = PROTO_TYPE;
259 api.safi = SAFI_UNICAST;
260 api.prefix = *prefix;
261 if (src_p && src_p->prefixlen) {
262 api.src_prefix = *src_p;
263 SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
264 }
265
266 zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
267 }
268
269 /**
270 * Install Prefix-SID in the forwarding plane through Zebra.
271 *
272 * @param srp Segment Routing Prefix-SID
273 */
isis_zebra_prefix_install_prefix_sid(const struct sr_prefix * srp)274 static void isis_zebra_prefix_install_prefix_sid(const struct sr_prefix *srp)
275 {
276 struct zapi_labels zl;
277 struct zapi_nexthop *znh;
278 struct listnode *node;
279 struct isis_nexthop *nexthop;
280 struct interface *ifp;
281
282 /* Prepare message. */
283 memset(&zl, 0, sizeof(zl));
284 zl.type = ZEBRA_LSP_ISIS_SR;
285 zl.local_label = srp->input_label;
286
287 switch (srp->type) {
288 case ISIS_SR_PREFIX_LOCAL:
289 ifp = if_lookup_by_name("lo", VRF_DEFAULT);
290 if (!ifp) {
291 zlog_warn(
292 "%s: couldn't install Prefix-SID %pFX: loopback interface not found",
293 __func__, &srp->prefix);
294 return;
295 }
296
297 znh = &zl.nexthops[zl.nexthop_num++];
298 znh->type = NEXTHOP_TYPE_IFINDEX;
299 znh->ifindex = ifp->ifindex;
300 znh->label_num = 1;
301 znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
302 break;
303 case ISIS_SR_PREFIX_REMOTE:
304 /* Update route in the RIB too. */
305 SET_FLAG(zl.message, ZAPI_LABELS_FTN);
306 zl.route.prefix = srp->prefix;
307 zl.route.type = ZEBRA_ROUTE_ISIS;
308 zl.route.instance = 0;
309
310 for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops, node,
311 nexthop)) {
312 if (nexthop->sr.label == MPLS_INVALID_LABEL)
313 continue;
314
315 if (zl.nexthop_num >= MULTIPATH_NUM)
316 break;
317
318 znh = &zl.nexthops[zl.nexthop_num++];
319 znh->type = (srp->prefix.family == AF_INET)
320 ? NEXTHOP_TYPE_IPV4_IFINDEX
321 : NEXTHOP_TYPE_IPV6_IFINDEX;
322 znh->gate = nexthop->ip;
323 znh->ifindex = nexthop->ifindex;
324 znh->label_num = 1;
325 znh->labels[0] = nexthop->sr.label;
326 }
327 break;
328 }
329
330 /* Send message to zebra. */
331 (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_REPLACE, &zl);
332 }
333
334 /**
335 * Uninstall Prefix-SID from the forwarding plane through Zebra.
336 *
337 * @param srp Segment Routing Prefix-SID
338 */
isis_zebra_uninstall_prefix_sid(const struct sr_prefix * srp)339 static void isis_zebra_uninstall_prefix_sid(const struct sr_prefix *srp)
340 {
341 struct zapi_labels zl;
342
343 /* Prepare message. */
344 memset(&zl, 0, sizeof(zl));
345 zl.type = ZEBRA_LSP_ISIS_SR;
346 zl.local_label = srp->input_label;
347
348 if (srp->type == ISIS_SR_PREFIX_REMOTE) {
349 /* Update route in the RIB too. */
350 SET_FLAG(zl.message, ZAPI_LABELS_FTN);
351 zl.route.prefix = srp->prefix;
352 zl.route.type = ZEBRA_ROUTE_ISIS;
353 zl.route.instance = 0;
354 }
355
356 /* Send message to zebra. */
357 (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_DELETE, &zl);
358 }
359
360 /**
361 * Send Prefix-SID to ZEBRA for installation or deletion.
362 *
363 * @param cmd ZEBRA_MPLS_LABELS_REPLACE or ZEBRA_ROUTE_DELETE
364 * @param srp Segment Routing Prefix-SID
365 */
isis_zebra_send_prefix_sid(int cmd,const struct sr_prefix * srp)366 void isis_zebra_send_prefix_sid(int cmd, const struct sr_prefix *srp)
367 {
368
369 if (cmd != ZEBRA_MPLS_LABELS_REPLACE
370 && cmd != ZEBRA_MPLS_LABELS_DELETE) {
371 flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command",
372 __func__);
373 return;
374 }
375
376 sr_debug(" |- %s label %u for prefix %pFX",
377 cmd == ZEBRA_MPLS_LABELS_REPLACE ? "Update" : "Delete",
378 srp->input_label, &srp->prefix);
379
380 if (cmd == ZEBRA_MPLS_LABELS_REPLACE)
381 isis_zebra_prefix_install_prefix_sid(srp);
382 else
383 isis_zebra_uninstall_prefix_sid(srp);
384 }
385
386 /**
387 * Send (LAN)-Adjacency-SID to ZEBRA for installation or deletion.
388 *
389 * @param cmd ZEBRA_MPLS_LABELS_ADD or ZEBRA_ROUTE_DELETE
390 * @param sra Segment Routing Adjacency-SID
391 */
isis_zebra_send_adjacency_sid(int cmd,const struct sr_adjacency * sra)392 void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
393 {
394 struct zapi_labels zl;
395 struct zapi_nexthop *znh;
396
397 if (cmd != ZEBRA_MPLS_LABELS_ADD && cmd != ZEBRA_MPLS_LABELS_DELETE) {
398 flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command",
399 __func__);
400 return;
401 }
402
403 sr_debug(" |- %s label %u for interface %s",
404 cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete",
405 sra->nexthop.label, sra->adj->circuit->interface->name);
406
407 memset(&zl, 0, sizeof(zl));
408 zl.type = ZEBRA_LSP_ISIS_SR;
409 zl.local_label = sra->nexthop.label;
410 zl.nexthop_num = 1;
411 znh = &zl.nexthops[0];
412 znh->gate = sra->nexthop.address;
413 znh->type = (sra->nexthop.family == AF_INET)
414 ? NEXTHOP_TYPE_IPV4_IFINDEX
415 : NEXTHOP_TYPE_IPV6_IFINDEX;
416 znh->ifindex = sra->adj->circuit->interface->ifindex;
417 znh->label_num = 1;
418 znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
419
420 (void)zebra_send_mpls_labels(zclient, cmd, &zl);
421 }
422
isis_zebra_read(ZAPI_CALLBACK_ARGS)423 static int isis_zebra_read(ZAPI_CALLBACK_ARGS)
424 {
425 struct zapi_route api;
426 struct isis *isis = NULL;
427
428 isis = isis_lookup_by_vrfid(vrf_id);
429
430 if (isis == NULL)
431 return -1;
432
433 if (zapi_route_decode(zclient->ibuf, &api) < 0)
434 return -1;
435
436 if (api.prefix.family == AF_INET6
437 && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
438 return 0;
439
440 /*
441 * Avoid advertising a false default reachability. (A default
442 * route installed by IS-IS gets redistributed from zebra back
443 * into IS-IS causing us to start advertising default reachabity
444 * without this check)
445 */
446 if (api.prefix.prefixlen == 0
447 && api.src_prefix.prefixlen == 0
448 && api.type == PROTO_TYPE) {
449 cmd = ZEBRA_REDISTRIBUTE_ROUTE_DEL;
450 }
451
452 if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
453 isis_redist_add(isis, api.type, &api.prefix, &api.src_prefix,
454 api.distance, api.metric);
455 else
456 isis_redist_delete(isis, api.type, &api.prefix,
457 &api.src_prefix);
458
459 return 0;
460 }
461
isis_distribute_list_update(int routetype)462 int isis_distribute_list_update(int routetype)
463 {
464 return 0;
465 }
466
isis_zebra_redistribute_set(afi_t afi,int type)467 void isis_zebra_redistribute_set(afi_t afi, int type)
468 {
469 if (type == DEFAULT_ROUTE)
470 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
471 zclient, afi, VRF_DEFAULT);
472 else
473 zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type,
474 0, VRF_DEFAULT);
475 }
476
isis_zebra_redistribute_unset(afi_t afi,int type)477 void isis_zebra_redistribute_unset(afi_t afi, int type)
478 {
479 if (type == DEFAULT_ROUTE)
480 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
481 zclient, afi, VRF_DEFAULT);
482 else
483 zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi,
484 type, 0, VRF_DEFAULT);
485 }
486
487 /* Label Manager Functions */
488
489 /**
490 * Check if Label Manager is Ready or not.
491 *
492 * @return True if Label Manager is ready, False otherwise
493 */
isis_zebra_label_manager_ready(void)494 bool isis_zebra_label_manager_ready(void)
495 {
496 return (zclient_sync->sock > 0);
497 }
498
499 /**
500 * Request Label Range to the Label Manager.
501 *
502 * @param base base label of the label range to request
503 * @param chunk_size size of the label range to request
504 *
505 * @return 0 on success, -1 on failure
506 */
isis_zebra_request_label_range(uint32_t base,uint32_t chunk_size)507 int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
508 {
509 int ret;
510 uint32_t start, end;
511
512 if (zclient_sync->sock < 0)
513 return -1;
514
515 ret = lm_get_label_chunk(zclient_sync, 0, base, chunk_size, &start,
516 &end);
517 if (ret < 0) {
518 zlog_warn("%s: error getting label range!", __func__);
519 return -1;
520 }
521
522 return 0;
523 }
524
525 /**
526 * Release Label Range to the Label Manager.
527 *
528 * @param start start of label range to release
529 * @param end end of label range to release
530 *
531 * @return 0 on success, -1 otherwise
532 */
isis_zebra_release_label_range(uint32_t start,uint32_t end)533 int isis_zebra_release_label_range(uint32_t start, uint32_t end)
534 {
535 int ret;
536
537 if (zclient_sync->sock < 0)
538 return -1;
539
540 ret = lm_release_label_chunk(zclient_sync, start, end);
541 if (ret < 0) {
542 zlog_warn("%s: error releasing label range!", __func__);
543 return -1;
544 }
545
546 return 0;
547 }
548
549 /**
550 * Connect to the Label Manager.
551 *
552 * @return 0 on success, -1 otherwise
553 */
isis_zebra_label_manager_connect(void)554 int isis_zebra_label_manager_connect(void)
555 {
556 /* Connect to label manager. */
557 if (zclient_socket_connect(zclient_sync) < 0) {
558 zlog_warn("%s: failed connecting synchronous zclient!",
559 __func__);
560 return -1;
561 }
562 /* make socket non-blocking */
563 set_nonblocking(zclient_sync->sock);
564
565 /* Send hello to notify zebra this is a synchronous client */
566 if (zclient_send_hello(zclient_sync) < 0) {
567 zlog_warn("%s: failed sending hello for synchronous zclient!",
568 __func__);
569 close(zclient_sync->sock);
570 zclient_sync->sock = -1;
571 return -1;
572 }
573
574 /* Connect to label manager */
575 if (lm_label_manager_connect(zclient_sync, 0) != 0) {
576 zlog_warn("%s: failed connecting to label manager!", __func__);
577 if (zclient_sync->sock > 0) {
578 close(zclient_sync->sock);
579 zclient_sync->sock = -1;
580 }
581 return -1;
582 }
583
584 sr_debug("ISIS-Sr: Successfully connected to the Label Manager");
585
586 return 0;
587 }
588
isis_zebra_vrf_register(struct isis * isis)589 void isis_zebra_vrf_register(struct isis *isis)
590 {
591 if (!zclient || zclient->sock < 0 || !isis)
592 return;
593
594 if (isis->vrf_id != VRF_UNKNOWN) {
595 if (IS_DEBUG_EVENTS)
596 zlog_debug("%s: Register VRF %s id %u", __func__,
597 isis->name, isis->vrf_id);
598 zclient_send_reg_requests(zclient, isis->vrf_id);
599 }
600 }
601
602
isis_zebra_connected(struct zclient * zclient)603 static void isis_zebra_connected(struct zclient *zclient)
604 {
605 zclient_send_reg_requests(zclient, VRF_DEFAULT);
606 }
607
isis_zebra_init(struct thread_master * master,int instance)608 void isis_zebra_init(struct thread_master *master, int instance)
609 {
610 /* Initialize asynchronous zclient. */
611 zclient = zclient_new(master, &zclient_options_default);
612 zclient_init(zclient, PROTO_TYPE, 0, &isisd_privs);
613 zclient->zebra_connected = isis_zebra_connected;
614 zclient->router_id_update = isis_router_id_update_zebra;
615 zclient->interface_address_add = isis_zebra_if_address_add;
616 zclient->interface_address_delete = isis_zebra_if_address_del;
617 zclient->interface_link_params = isis_zebra_link_params;
618 zclient->redistribute_route_add = isis_zebra_read;
619 zclient->redistribute_route_del = isis_zebra_read;
620
621 /* Initialize special zclient for synchronous message exchanges. */
622 struct zclient_options options = zclient_options_default;
623 options.synchronous = true;
624 zclient_sync = zclient_new(master, &options);
625 zclient_sync->sock = -1;
626 zclient_sync->redist_default = ZEBRA_ROUTE_ISIS;
627 zclient_sync->instance = instance;
628 /*
629 * session_id must be different from default value (0) to distinguish
630 * the asynchronous socket from the synchronous one
631 */
632 zclient_sync->session_id = 1;
633 zclient_sync->privs = &isisd_privs;
634 }
635
isis_zebra_stop(void)636 void isis_zebra_stop(void)
637 {
638 zclient_stop(zclient_sync);
639 zclient_free(zclient_sync);
640 zclient_stop(zclient);
641 zclient_free(zclient);
642 frr_fini();
643 }
644