]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_circuit.c
isisd: apply fast-reroute when an interface falls down
[mirror_frr.git] / isisd / isis_circuit.c
1 /*
2 * IS-IS Rout(e)ing protocol - isis_circuit.h
3 *
4 * Copyright (C) 2001,2002 Sampo Saaristo
5 * Tampere University of Technology
6 * Institute of Communications Engineering
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public Licenseas published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22 #include <zebra.h>
23 #ifdef GNU_LINUX
24 #include <net/ethernet.h>
25 #else
26 #include <netinet/if_ether.h>
27 #endif
28
29 #include "log.h"
30 #include "memory.h"
31 #include "vrf.h"
32 #include "if.h"
33 #include "linklist.h"
34 #include "command.h"
35 #include "thread.h"
36 #include "vty.h"
37 #include "hash.h"
38 #include "prefix.h"
39 #include "stream.h"
40 #include "qobj.h"
41 #include "lib/northbound_cli.h"
42
43 #include "isisd/isis_constants.h"
44 #include "isisd/isis_common.h"
45 #include "isisd/isis_flags.h"
46 #include "isisd/isis_circuit.h"
47 #include "isisd/isis_lsp.h"
48 #include "isisd/isis_pdu.h"
49 #include "isisd/isis_network.h"
50 #include "isisd/isis_misc.h"
51 #include "isisd/isis_constants.h"
52 #include "isisd/isis_adjacency.h"
53 #include "isisd/isis_dr.h"
54 #include "isisd/isisd.h"
55 #include "isisd/isis_csm.h"
56 #include "isisd/isis_events.h"
57 #include "isisd/isis_te.h"
58 #include "isisd/isis_mt.h"
59 #include "isisd/isis_errors.h"
60 #include "isisd/isis_tx_queue.h"
61 #include "isisd/isis_nb.h"
62 #include "isisd/isis_ldp_sync.h"
63
64 DEFINE_MTYPE_STATIC(ISISD, ISIS_CIRCUIT, "ISIS circuit");
65
66 DEFINE_QOBJ_TYPE(isis_circuit);
67
68 DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp));
69
70 /*
71 * Prototypes.
72 */
73 int isis_if_new_hook(struct interface *);
74 int isis_if_delete_hook(struct interface *);
75
76 DEFINE_HOOK(isis_circuit_new_hook, (struct isis_circuit *circuit), (circuit));
77 DEFINE_HOOK(isis_circuit_del_hook, (struct isis_circuit *circuit), (circuit));
78
79 static void isis_circuit_enable(struct isis_circuit *circuit)
80 {
81 struct isis_area *area = circuit->area;
82 struct interface *ifp = circuit->interface;
83
84 if (!area) {
85 area = isis_area_lookup(circuit->tag, ifp->vrf->vrf_id);
86 if (area)
87 isis_area_add_circuit(area, circuit);
88 }
89
90 if (if_is_operative(ifp))
91 isis_csm_state_change(IF_UP_FROM_Z, circuit, ifp);
92 }
93
94 static void isis_circuit_disable(struct isis_circuit *circuit)
95 {
96 struct isis_area *area = circuit->area;
97 struct interface *ifp = circuit->interface;
98
99 if (if_is_operative(ifp))
100 isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp);
101
102 if (area)
103 isis_area_del_circuit(area, circuit);
104 }
105
106 struct isis_circuit *isis_circuit_new(struct interface *ifp, const char *tag)
107 {
108 struct isis_circuit *circuit;
109 int i;
110
111 circuit = XCALLOC(MTYPE_ISIS_CIRCUIT, sizeof(struct isis_circuit));
112
113 circuit->tag = XSTRDUP(MTYPE_ISIS_CIRCUIT, tag);
114
115 /*
116 * Default values
117 */
118 #ifndef FABRICD
119 circuit->is_type_config = yang_get_default_enum(
120 "/frr-interface:lib/interface/frr-isisd:isis/circuit-type");
121 circuit->flags = 0;
122
123 circuit->pad_hellos = yang_get_default_bool(
124 "/frr-interface:lib/interface/frr-isisd:isis/hello/padding");
125 circuit->hello_interval[0] = yang_get_default_uint32(
126 "/frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-1");
127 circuit->hello_interval[1] = yang_get_default_uint32(
128 "/frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-2");
129 circuit->hello_multiplier[0] = yang_get_default_uint32(
130 "/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-1");
131 circuit->hello_multiplier[1] = yang_get_default_uint32(
132 "/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-2");
133 circuit->csnp_interval[0] = yang_get_default_uint16(
134 "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-1");
135 circuit->csnp_interval[1] = yang_get_default_uint16(
136 "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-2");
137 circuit->psnp_interval[0] = yang_get_default_uint16(
138 "/frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-1");
139 circuit->psnp_interval[1] = yang_get_default_uint16(
140 "/frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-2");
141 circuit->priority[0] = yang_get_default_uint8(
142 "/frr-interface:lib/interface/frr-isisd:isis/priority/level-1");
143 circuit->priority[1] = yang_get_default_uint8(
144 "/frr-interface:lib/interface/frr-isisd:isis/priority/level-2");
145 circuit->metric[0] = yang_get_default_uint32(
146 "/frr-interface:lib/interface/frr-isisd:isis/metric/level-1");
147 circuit->metric[1] = yang_get_default_uint32(
148 "/frr-interface:lib/interface/frr-isisd:isis/metric/level-2");
149 circuit->te_metric[0] = yang_get_default_uint32(
150 "/frr-interface:lib/interface/frr-isisd:isis/metric/level-1");
151 circuit->te_metric[1] = yang_get_default_uint32(
152 "/frr-interface:lib/interface/frr-isisd:isis/metric/level-2");
153
154 for (i = 0; i < 2; i++) {
155 circuit->level_arg[i].level = i + 1;
156 circuit->level_arg[i].circuit = circuit;
157 }
158 #else
159 circuit->is_type_config = IS_LEVEL_1_AND_2;
160 circuit->flags = 0;
161 circuit->pad_hellos = 1;
162 for (i = 0; i < 2; i++) {
163 circuit->hello_interval[i] = DEFAULT_HELLO_INTERVAL;
164 circuit->hello_multiplier[i] = DEFAULT_HELLO_MULTIPLIER;
165 circuit->csnp_interval[i] = DEFAULT_CSNP_INTERVAL;
166 circuit->psnp_interval[i] = DEFAULT_PSNP_INTERVAL;
167 circuit->priority[i] = DEFAULT_PRIORITY;
168 circuit->metric[i] = DEFAULT_CIRCUIT_METRIC;
169 circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC;
170 circuit->level_arg[i].level = i + 1;
171 circuit->level_arg[i].circuit = circuit;
172 }
173 #endif /* ifndef FABRICD */
174
175 circuit->is_type = circuit->is_type_config;
176
177 circuit_mt_init(circuit);
178 isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL1);
179 isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL2);
180
181 circuit->ldp_sync_info = ldp_sync_info_create();
182 circuit->ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
183
184 QOBJ_REG(circuit, isis_circuit);
185
186 isis_circuit_if_bind(circuit, ifp);
187
188 if (ifp->ifindex != IFINDEX_INTERNAL)
189 isis_circuit_enable(circuit);
190
191 return circuit;
192 }
193
194 void isis_circuit_del(struct isis_circuit *circuit)
195 {
196 if (!circuit)
197 return;
198
199 if (circuit->interface->ifindex != IFINDEX_INTERNAL)
200 isis_circuit_disable(circuit);
201
202 isis_circuit_if_unbind(circuit, circuit->interface);
203
204 QOBJ_UNREG(circuit);
205
206 ldp_sync_info_free(&circuit->ldp_sync_info);
207
208 circuit_mt_finish(circuit);
209 isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL1);
210 isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL2);
211
212 XFREE(MTYPE_TMP, circuit->bfd_config.profile);
213 XFREE(MTYPE_ISIS_CIRCUIT, circuit->tag);
214
215 /* and lastly the circuit itself */
216 XFREE(MTYPE_ISIS_CIRCUIT, circuit);
217
218 return;
219 }
220
221 void isis_circuit_configure(struct isis_circuit *circuit,
222 struct isis_area *area)
223 {
224 assert(area);
225 circuit->isis = area->isis;
226 circuit->area = area;
227
228 /*
229 * Whenever the is-type of an area is changed, the is-type of each
230 * circuit
231 * in that area is updated to a non-empty subset of the area is-type.
232 * Inversely, when configuring a new circuit, this property should be
233 * ensured as well.
234 */
235 if (area->is_type != IS_LEVEL_1_AND_2)
236 circuit->is_type = area->is_type;
237
238 /*
239 * Add the circuit into area
240 */
241 listnode_add(area->circuit_list, circuit);
242
243 circuit->idx = flags_get_index(&area->flags);
244
245 hook_call(isis_circuit_new_hook, circuit);
246
247 return;
248 }
249
250 void isis_circuit_deconfigure(struct isis_circuit *circuit,
251 struct isis_area *area)
252 {
253 hook_call(isis_circuit_del_hook, circuit);
254
255 /* Free the index of SRM and SSN flags */
256 flags_free_index(&area->flags, circuit->idx);
257 circuit->idx = 0;
258
259 /* Reset IS type to configured */
260 circuit->is_type = circuit->is_type_config;
261
262 /* Remove circuit from area */
263 assert(circuit->area == area);
264 listnode_delete(area->circuit_list, circuit);
265 circuit->area = NULL;
266 circuit->isis = NULL;
267
268 return;
269 }
270
271 struct isis_circuit *circuit_scan_by_ifp(struct interface *ifp)
272 {
273 return (struct isis_circuit *)ifp->info;
274 }
275
276 DEFINE_HOOK(isis_circuit_add_addr_hook, (struct isis_circuit *circuit),
277 (circuit));
278
279 void isis_circuit_add_addr(struct isis_circuit *circuit,
280 struct connected *connected)
281 {
282 struct listnode *node;
283 struct prefix_ipv4 *ipv4;
284 struct prefix_ipv6 *ipv6;
285
286 if (connected->address->family == AF_INET) {
287 uint32_t addr = connected->address->u.prefix4.s_addr;
288 addr = ntohl(addr);
289 if (IPV4_NET0(addr) || IPV4_NET127(addr) || IN_CLASSD(addr)
290 || IPV4_LINKLOCAL(addr))
291 return;
292
293 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ipv4))
294 if (prefix_same((struct prefix *)ipv4,
295 connected->address))
296 return;
297
298 ipv4 = prefix_ipv4_new();
299 ipv4->prefixlen = connected->address->prefixlen;
300 ipv4->prefix = connected->address->u.prefix4;
301 listnode_add(circuit->ip_addrs, ipv4);
302
303 /* Update Local IP address parameter if MPLS TE is enable */
304 if (circuit->ext && circuit->area
305 && IS_MPLS_TE(circuit->area->mta)) {
306 circuit->ext->local_addr.s_addr = ipv4->prefix.s_addr;
307 SET_SUBTLV(circuit->ext, EXT_LOCAL_ADDR);
308 }
309
310 if (circuit->area)
311 lsp_regenerate_schedule(circuit->area, circuit->is_type,
312 0);
313
314 #ifdef EXTREME_DEBUG
315 if (IS_DEBUG_EVENTS)
316 zlog_debug("Added IP address %pFX to circuit %s",
317 connected->address,
318 circuit->interface->name);
319 #endif /* EXTREME_DEBUG */
320 }
321 if (connected->address->family == AF_INET6) {
322 if (IN6_IS_ADDR_LOOPBACK(&connected->address->u.prefix6))
323 return;
324
325 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ipv6))
326 if (prefix_same((struct prefix *)ipv6,
327 connected->address))
328 return;
329 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ipv6))
330 if (prefix_same((struct prefix *)ipv6,
331 connected->address))
332 return;
333
334 ipv6 = prefix_ipv6_new();
335 ipv6->prefixlen = connected->address->prefixlen;
336 ipv6->prefix = connected->address->u.prefix6;
337
338 if (IN6_IS_ADDR_LINKLOCAL(&ipv6->prefix))
339 listnode_add(circuit->ipv6_link, ipv6);
340 else {
341 listnode_add(circuit->ipv6_non_link, ipv6);
342 /* Update Local IPv6 address param. if MPLS TE is on */
343 if (circuit->ext && circuit->area
344 && IS_MPLS_TE(circuit->area->mta)) {
345 IPV6_ADDR_COPY(&circuit->ext->local_addr6,
346 &ipv6->prefix);
347 SET_SUBTLV(circuit->ext, EXT_LOCAL_ADDR6);
348 }
349 }
350 if (circuit->area)
351 lsp_regenerate_schedule(circuit->area, circuit->is_type,
352 0);
353
354 #ifdef EXTREME_DEBUG
355 if (IS_DEBUG_EVENTS)
356 zlog_debug("Added IPv6 address %pFX to circuit %s",
357 connected->address,
358 circuit->interface->name);
359 #endif /* EXTREME_DEBUG */
360 }
361
362 hook_call(isis_circuit_add_addr_hook, circuit);
363
364 return;
365 }
366
367 void isis_circuit_del_addr(struct isis_circuit *circuit,
368 struct connected *connected)
369 {
370 struct prefix_ipv4 *ipv4, *ip = NULL;
371 struct listnode *node;
372 struct prefix_ipv6 *ipv6, *ip6 = NULL;
373 int found = 0;
374
375 if (connected->address->family == AF_INET) {
376 ipv4 = prefix_ipv4_new();
377 ipv4->prefixlen = connected->address->prefixlen;
378 ipv4->prefix = connected->address->u.prefix4;
379
380 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ip))
381 if (prefix_same((struct prefix *)ip,
382 (struct prefix *)ipv4))
383 break;
384
385 if (ip) {
386 listnode_delete(circuit->ip_addrs, ip);
387 prefix_ipv4_free(&ip);
388 if (circuit->area)
389 lsp_regenerate_schedule(circuit->area,
390 circuit->is_type, 0);
391 } else {
392 zlog_warn(
393 "Nonexistent ip address %pFX removal attempt from circuit %s",
394 connected->address, circuit->interface->name);
395 zlog_warn("Current ip addresses on %s:",
396 circuit->interface->name);
397 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node,
398 ip)) {
399 zlog_warn(" %pFX", ip);
400 }
401 zlog_warn("End of addresses");
402 }
403
404 prefix_ipv4_free(&ipv4);
405 }
406 if (connected->address->family == AF_INET6) {
407 ipv6 = prefix_ipv6_new();
408 ipv6->prefixlen = connected->address->prefixlen;
409 ipv6->prefix = connected->address->u.prefix6;
410
411 if (IN6_IS_ADDR_LINKLOCAL(&ipv6->prefix)) {
412 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node,
413 ip6)) {
414 if (prefix_same((struct prefix *)ip6,
415 (struct prefix *)ipv6))
416 break;
417 }
418 if (ip6) {
419 listnode_delete(circuit->ipv6_link, ip6);
420 prefix_ipv6_free(&ip6);
421 found = 1;
422 }
423 } else {
424 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node,
425 ip6)) {
426 if (prefix_same((struct prefix *)ip6,
427 (struct prefix *)ipv6))
428 break;
429 }
430 if (ip6) {
431 listnode_delete(circuit->ipv6_non_link, ip6);
432 prefix_ipv6_free(&ip6);
433 found = 1;
434 }
435 }
436
437 if (!found) {
438 zlog_warn(
439 "Nonexistent ip address %pFX removal attempt from circuit %s",
440 connected->address, circuit->interface->name);
441 zlog_warn("Current ip addresses on %s:",
442 circuit->interface->name);
443 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node,
444 ip6))
445 zlog_warn(" %pFX", (struct prefix *)ip6);
446 zlog_warn(" -----");
447 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node,
448 ip6))
449 zlog_warn(" %pFX", (struct prefix *)ip6);
450 zlog_warn("End of addresses");
451 } else if (circuit->area)
452 lsp_regenerate_schedule(circuit->area, circuit->is_type,
453 0);
454
455 prefix_ipv6_free(&ipv6);
456 }
457 return;
458 }
459
460 static uint8_t isis_circuit_id_gen(struct isis *isis, struct interface *ifp)
461 {
462 /* Circuit ids MUST be unique for any broadcast circuits. Otherwise,
463 * Pseudo-Node LSPs cannot be generated correctly.
464 *
465 * Currently, allocate one circuit ID for any circuit, limiting the total
466 * numer of circuits IS-IS can run on to 255.
467 *
468 * We should revisit this when implementing 3-way adjacencies for p2p, since
469 * we then have extended interface IDs available.
470 */
471 uint8_t id = ifp->ifindex;
472 unsigned int i;
473
474 for (i = 0; i < 256; i++) {
475 if (id && !_ISIS_CHECK_FLAG(isis->circuit_ids_used, id))
476 break;
477 id++;
478 }
479
480 if (i == 256) {
481 zlog_warn("Could not allocate a circuit id for '%s'",
482 ifp->name);
483 return 0;
484 }
485
486 _ISIS_SET_FLAG(isis->circuit_ids_used, id);
487 return id;
488 }
489
490 void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp)
491 {
492 struct listnode *node, *nnode;
493 struct connected *conn;
494
495 if (if_is_broadcast(ifp)) {
496 if (fabricd || circuit->circ_type_config == CIRCUIT_T_P2P)
497 circuit->circ_type = CIRCUIT_T_P2P;
498 else
499 circuit->circ_type = CIRCUIT_T_BROADCAST;
500 } else if (if_is_pointopoint(ifp)) {
501 circuit->circ_type = CIRCUIT_T_P2P;
502 } else if (if_is_loopback(ifp)) {
503 circuit->circ_type = CIRCUIT_T_LOOPBACK;
504 circuit->is_passive = 1;
505 } else {
506 /* It's normal in case of loopback etc. */
507 if (IS_DEBUG_EVENTS)
508 zlog_debug("isis_circuit_if_add: unsupported media");
509 circuit->circ_type = CIRCUIT_T_UNKNOWN;
510 }
511
512 circuit->ip_addrs = list_new();
513 circuit->ipv6_link = list_new();
514 circuit->ipv6_non_link = list_new();
515
516 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, conn))
517 isis_circuit_add_addr(circuit, conn);
518
519 }
520
521 void isis_circuit_if_del(struct isis_circuit *circuit, struct interface *ifp)
522 {
523 struct listnode *node, *nnode;
524 struct connected *conn;
525
526 assert(circuit->interface == ifp);
527
528 /* destroy addresses */
529 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, conn))
530 isis_circuit_del_addr(circuit, conn);
531
532 if (circuit->ip_addrs) {
533 assert(listcount(circuit->ip_addrs) == 0);
534 list_delete(&circuit->ip_addrs);
535 }
536
537 if (circuit->ipv6_link) {
538 assert(listcount(circuit->ipv6_link) == 0);
539 list_delete(&circuit->ipv6_link);
540 }
541
542 if (circuit->ipv6_non_link) {
543 assert(listcount(circuit->ipv6_non_link) == 0);
544 list_delete(&circuit->ipv6_non_link);
545 }
546
547 circuit->circ_type = CIRCUIT_T_UNKNOWN;
548 }
549
550 void isis_circuit_if_bind(struct isis_circuit *circuit, struct interface *ifp)
551 {
552 assert(circuit != NULL);
553 assert(ifp != NULL);
554 if (circuit->interface)
555 assert(circuit->interface == ifp);
556 else
557 circuit->interface = ifp;
558 if (ifp->info)
559 assert(ifp->info == circuit);
560 else
561 ifp->info = circuit;
562 }
563
564 void isis_circuit_if_unbind(struct isis_circuit *circuit, struct interface *ifp)
565 {
566 assert(circuit != NULL);
567 assert(ifp != NULL);
568 assert(circuit->interface == ifp);
569 assert(ifp->info == circuit);
570 circuit->interface = NULL;
571 ifp->info = NULL;
572 }
573
574 static void isis_circuit_update_all_srmflags(struct isis_circuit *circuit,
575 int is_set)
576 {
577 struct isis_area *area;
578 struct isis_lsp *lsp;
579 int level;
580
581 assert(circuit);
582 area = circuit->area;
583 assert(area);
584 for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
585 if (!(level & circuit->is_type))
586 continue;
587
588 if (!lspdb_count(&area->lspdb[level - 1]))
589 continue;
590
591 frr_each (lspdb, &area->lspdb[level - 1], lsp) {
592 if (is_set) {
593 isis_tx_queue_add(circuit->tx_queue, lsp,
594 TX_LSP_NORMAL);
595 } else {
596 isis_tx_queue_del(circuit->tx_queue, lsp);
597 }
598 }
599 }
600 }
601
602 size_t isis_circuit_pdu_size(struct isis_circuit *circuit)
603 {
604 return ISO_MTU(circuit);
605 }
606
607 static bool isis_circuit_lfa_enabled(struct isis_circuit *circuit, int level)
608 {
609 return (circuit->lfa_protection[level - 1] ||
610 circuit->rlfa_protection[level - 1] ||
611 circuit->tilfa_protection[level - 1]);
612 }
613
614 void isis_circuit_switchover_routes(struct isis_circuit *circuit, int family,
615 union g_addr *nexthop_ip, ifindex_t ifindex)
616 {
617 char is_type = circuit->area->is_type;
618 if ((is_type == IS_LEVEL_1 || is_type == IS_LEVEL_1_AND_2) &&
619 isis_circuit_lfa_enabled(circuit, IS_LEVEL_1))
620 isis_area_switchover_routes(circuit->area, family, nexthop_ip,
621 ifindex, IS_LEVEL_1);
622 if ((is_type == IS_LEVEL_2 || is_type == IS_LEVEL_1_AND_2) &&
623 isis_circuit_lfa_enabled(circuit, IS_LEVEL_2))
624 isis_area_switchover_routes(circuit->area, family, nexthop_ip,
625 ifindex, IS_LEVEL_2);
626 }
627
628 void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream)
629 {
630 size_t stream_size = isis_circuit_pdu_size(circuit);
631
632 if (!*stream) {
633 *stream = stream_new(stream_size);
634 } else {
635 if (STREAM_SIZE(*stream) != stream_size)
636 stream_resize_inplace(stream, stream_size);
637 stream_reset(*stream);
638 }
639 }
640
641 void isis_circuit_prepare(struct isis_circuit *circuit)
642 {
643 #if ISIS_METHOD != ISIS_METHOD_DLPI
644 thread_add_read(master, isis_receive, circuit, circuit->fd,
645 &circuit->t_read);
646 #else
647 thread_add_timer_msec(master, isis_receive, circuit,
648 listcount(circuit->area->circuit_list) * 100,
649 &circuit->t_read);
650 #endif
651 }
652
653 int isis_circuit_up(struct isis_circuit *circuit)
654 {
655 int retv;
656
657 /* Set the flags for all the lsps of the circuit. */
658 isis_circuit_update_all_srmflags(circuit, 1);
659
660 if (circuit->state == C_STATE_UP)
661 return ISIS_OK;
662
663 if (circuit->is_passive) {
664 circuit->last_uptime = time(NULL);
665 /* make sure the union fields are initialized, else we
666 * could end with garbage values from a previous circuit
667 * type, which would then cause a segfault when building
668 * LSPs or computing the SPF tree
669 */
670 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
671 circuit->u.bc.adjdb[0] = list_new();
672 circuit->u.bc.adjdb[1] = list_new();
673 } else if (circuit->circ_type == CIRCUIT_T_P2P) {
674 circuit->u.p2p.neighbor = NULL;
675 }
676 return ISIS_OK;
677 }
678
679 if (circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit)) {
680 flog_err(
681 EC_ISIS_CONFIG,
682 "Interface MTU %zu on %s is too low to support area lsp mtu %u!",
683 isis_circuit_pdu_size(circuit),
684 circuit->interface->name, circuit->area->lsp_mtu);
685
686 /* Allow ISIS to continue configuration. With this
687 * configuration failure ISIS will attempt to send lsp
688 * packets but will fail until the mtu is configured properly
689 */
690 }
691
692 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
693 circuit->circuit_id =
694 isis_circuit_id_gen(circuit->isis, circuit->interface);
695 if (!circuit->circuit_id) {
696 flog_err(
697 EC_ISIS_CONFIG,
698 "There are already 255 broadcast circuits active!");
699 return ISIS_ERROR;
700 }
701
702 /*
703 * Get the Hardware Address
704 */
705 if (circuit->interface->hw_addr_len != ETH_ALEN) {
706 zlog_warn("unsupported link layer");
707 } else {
708 memcpy(circuit->u.bc.snpa, circuit->interface->hw_addr,
709 ETH_ALEN);
710 }
711 #ifdef EXTREME_DEGUG
712 if (IS_DEBUG_EVENTS)
713 zlog_debug(
714 "isis_circuit_if_add: if_id %d, isomtu %d snpa %s",
715 circuit->interface->ifindex, ISO_MTU(circuit),
716 snpa_print(circuit->u.bc.snpa));
717 #endif /* EXTREME_DEBUG */
718
719 circuit->u.bc.adjdb[0] = list_new();
720 circuit->u.bc.adjdb[1] = list_new();
721
722 /*
723 * ISO 10589 - 8.4.1 Enabling of broadcast circuits
724 */
725
726 /* initilizing the hello sending threads
727 * for a broadcast IF
728 */
729
730 /* 8.4.1 a) commence sending of IIH PDUs */
731
732 for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
733 if (!(circuit->is_type & level))
734 continue;
735
736 send_hello_sched(circuit, level, TRIGGERED_IIH_DELAY);
737 circuit->u.bc.lan_neighs[level - 1] = list_new();
738
739 thread_add_timer(master, isis_run_dr,
740 &circuit->level_arg[level - 1],
741 2 * circuit->hello_interval[level - 1],
742 &circuit->u.bc.t_run_dr[level - 1]);
743 }
744
745 /* 8.4.1 b) FIXME: solicit ES - 8.4.6 */
746 /* 8.4.1 c) FIXME: listen for ESH PDUs */
747 } else if (circuit->circ_type == CIRCUIT_T_P2P) {
748 /* initializing the hello send threads
749 * for a ptp IF
750 */
751 circuit->u.p2p.neighbor = NULL;
752 send_hello_sched(circuit, 0, TRIGGERED_IIH_DELAY);
753 }
754
755 /* initializing PSNP timers */
756 if (circuit->is_type & IS_LEVEL_1)
757 thread_add_timer(
758 master, send_l1_psnp, circuit,
759 isis_jitter(circuit->psnp_interval[0], PSNP_JITTER),
760 &circuit->t_send_psnp[0]);
761
762 if (circuit->is_type & IS_LEVEL_2)
763 thread_add_timer(
764 master, send_l2_psnp, circuit,
765 isis_jitter(circuit->psnp_interval[1], PSNP_JITTER),
766 &circuit->t_send_psnp[1]);
767
768 /* unified init for circuits; ignore warnings below this level */
769 retv = isis_sock_init(circuit);
770 if (retv != ISIS_OK) {
771 isis_circuit_down(circuit);
772 return retv;
773 }
774
775 /* initialize the circuit streams after opening connection */
776 isis_circuit_stream(circuit, &circuit->rcv_stream);
777 isis_circuit_stream(circuit, &circuit->snd_stream);
778
779 isis_circuit_prepare(circuit);
780
781 circuit->tx_queue = isis_tx_queue_new(circuit, send_lsp);
782
783 circuit->last_uptime = time(NULL);
784
785 if (circuit->area->mta && circuit->area->mta->status)
786 isis_link_params_update(circuit, circuit->interface);
787
788 isis_if_ldp_sync_enable(circuit);
789
790 #ifndef FABRICD
791 /* send northbound notification */
792 isis_notif_if_state_change(circuit, false);
793 #endif /* ifndef FABRICD */
794
795 return ISIS_OK;
796 }
797
798 void isis_circuit_down(struct isis_circuit *circuit)
799 {
800 #ifndef FABRICD
801 /* send northbound notification */
802 isis_notif_if_state_change(circuit, true);
803 #endif /* ifndef FABRICD */
804
805 isis_if_ldp_sync_disable(circuit);
806
807 /* log adjacency changes if configured to do so */
808 if (circuit->area->log_adj_changes) {
809 struct isis_adjacency *adj = NULL;
810 if (circuit->circ_type == CIRCUIT_T_P2P) {
811 adj = circuit->u.p2p.neighbor;
812 if (adj)
813 isis_log_adj_change(
814 adj, adj->adj_state, ISIS_ADJ_DOWN,
815 "circuit is being brought down");
816 } else if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
817 struct list *adj_list;
818 struct listnode *node;
819 if (circuit->u.bc.adjdb[0]) {
820 adj_list = list_new();
821 isis_adj_build_up_list(circuit->u.bc.adjdb[0],
822 adj_list);
823 for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj))
824 isis_log_adj_change(
825 adj, adj->adj_state,
826 ISIS_ADJ_DOWN,
827 "circuit is being brought down");
828 list_delete(&adj_list);
829 }
830 if (circuit->u.bc.adjdb[1]) {
831 adj_list = list_new();
832 isis_adj_build_up_list(circuit->u.bc.adjdb[1],
833 adj_list);
834 for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj))
835 isis_log_adj_change(
836 adj, adj->adj_state,
837 ISIS_ADJ_DOWN,
838 "circuit is being brought down");
839 list_delete(&adj_list);
840 }
841 }
842 }
843
844 /* Clear the flags for all the lsps of the circuit. */
845 isis_circuit_update_all_srmflags(circuit, 0);
846
847 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
848 /* destroy neighbour lists */
849 if (circuit->u.bc.lan_neighs[0]) {
850 list_delete(&circuit->u.bc.lan_neighs[0]);
851 circuit->u.bc.lan_neighs[0] = NULL;
852 }
853 if (circuit->u.bc.lan_neighs[1]) {
854 list_delete(&circuit->u.bc.lan_neighs[1]);
855 circuit->u.bc.lan_neighs[1] = NULL;
856 }
857 /* destroy adjacency databases */
858 if (circuit->u.bc.adjdb[0]) {
859 circuit->u.bc.adjdb[0]->del = isis_delete_adj;
860 list_delete(&circuit->u.bc.adjdb[0]);
861 circuit->u.bc.adjdb[0] = NULL;
862 }
863 if (circuit->u.bc.adjdb[1]) {
864 circuit->u.bc.adjdb[1]->del = isis_delete_adj;
865 list_delete(&circuit->u.bc.adjdb[1]);
866 circuit->u.bc.adjdb[1] = NULL;
867 }
868 if (circuit->u.bc.is_dr[0]) {
869 isis_dr_resign(circuit, 1);
870 circuit->u.bc.is_dr[0] = 0;
871 }
872 memset(circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1);
873 if (circuit->u.bc.is_dr[1]) {
874 isis_dr_resign(circuit, 2);
875 circuit->u.bc.is_dr[1] = 0;
876 }
877 memset(circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
878 memset(circuit->u.bc.snpa, 0, ETH_ALEN);
879
880 thread_cancel(&circuit->u.bc.t_send_lan_hello[0]);
881 thread_cancel(&circuit->u.bc.t_send_lan_hello[1]);
882 thread_cancel(&circuit->u.bc.t_run_dr[0]);
883 thread_cancel(&circuit->u.bc.t_run_dr[1]);
884 thread_cancel(&circuit->u.bc.t_refresh_pseudo_lsp[0]);
885 thread_cancel(&circuit->u.bc.t_refresh_pseudo_lsp[1]);
886 circuit->lsp_regenerate_pending[0] = 0;
887 circuit->lsp_regenerate_pending[1] = 0;
888
889 _ISIS_CLEAR_FLAG(circuit->isis->circuit_ids_used,
890 circuit->circuit_id);
891 circuit->circuit_id = 0;
892 } else if (circuit->circ_type == CIRCUIT_T_P2P) {
893 isis_delete_adj(circuit->u.p2p.neighbor);
894 circuit->u.p2p.neighbor = NULL;
895 thread_cancel(&circuit->u.p2p.t_send_p2p_hello);
896 }
897
898 /*
899 * All adjacencies have to be gone, delete snmp list
900 * and reset snmpd idx generator
901 */
902 if (circuit->snmp_adj_list != NULL)
903 list_delete(&circuit->snmp_adj_list);
904
905 circuit->snmp_adj_idx_gen = 0;
906
907 /* Cancel all active threads */
908 thread_cancel(&circuit->t_send_csnp[0]);
909 thread_cancel(&circuit->t_send_csnp[1]);
910 thread_cancel(&circuit->t_send_psnp[0]);
911 thread_cancel(&circuit->t_send_psnp[1]);
912 thread_cancel(&circuit->t_read);
913
914 if (circuit->tx_queue) {
915 isis_tx_queue_free(circuit->tx_queue);
916 circuit->tx_queue = NULL;
917 }
918
919 /* send one gratuitous hello to spead up convergence */
920 if (circuit->state == C_STATE_UP) {
921 if (circuit->is_type & IS_LEVEL_1)
922 send_hello(circuit, IS_LEVEL_1);
923 if (circuit->is_type & IS_LEVEL_2)
924 send_hello(circuit, IS_LEVEL_2);
925 }
926
927 circuit->upadjcount[0] = 0;
928 circuit->upadjcount[1] = 0;
929
930 /* close the socket */
931 if (circuit->fd) {
932 close(circuit->fd);
933 circuit->fd = 0;
934 }
935
936 if (circuit->rcv_stream != NULL) {
937 stream_free(circuit->rcv_stream);
938 circuit->rcv_stream = NULL;
939 }
940
941 if (circuit->snd_stream != NULL) {
942 stream_free(circuit->snd_stream);
943 circuit->snd_stream = NULL;
944 }
945
946 thread_cancel_event(master, circuit);
947
948 return;
949 }
950
951 void circuit_update_nlpids(struct isis_circuit *circuit)
952 {
953 circuit->nlpids.count = 0;
954
955 if (circuit->ip_router) {
956 circuit->nlpids.nlpids[0] = NLPID_IP;
957 circuit->nlpids.count++;
958 }
959 if (circuit->ipv6_router) {
960 circuit->nlpids.nlpids[circuit->nlpids.count] = NLPID_IPV6;
961 circuit->nlpids.count++;
962 }
963 return;
964 }
965
966 void isis_circuit_print_json(struct isis_circuit *circuit,
967 struct json_object *json, char detail)
968 {
969 int level;
970 json_object *iface_json, *ipv4_addr_json, *ipv6_link_json,
971 *ipv6_non_link_json, *hold_json, *lan_prio_json, *levels_json,
972 *level_json;
973 char buf_prx[INET6_BUFSIZ];
974 char buf[255];
975
976 snprintfrr(buf, sizeof(buf), "0x%x", circuit->circuit_id);
977 if (detail == ISIS_UI_LEVEL_BRIEF) {
978 iface_json = json_object_new_object();
979 json_object_object_add(json, "interface", iface_json);
980 json_object_string_add(iface_json, "name",
981 circuit->interface->name);
982 json_object_string_add(iface_json, "circuit-id", buf);
983 json_object_string_add(iface_json, "state",
984 circuit_state2string(circuit->state));
985 json_object_string_add(iface_json, "type",
986 circuit_type2string(circuit->circ_type));
987 json_object_string_add(iface_json, "level",
988 circuit_t2string(circuit->is_type));
989 }
990
991 if (detail == ISIS_UI_LEVEL_DETAIL) {
992 struct listnode *node;
993 struct prefix *ip_addr;
994
995 iface_json = json_object_new_object();
996 json_object_object_add(json, "interface", iface_json);
997 json_object_string_add(iface_json, "name",
998 circuit->interface->name);
999 json_object_string_add(iface_json, "state",
1000 circuit_state2string(circuit->state));
1001 if (circuit->is_passive)
1002 json_object_string_add(iface_json, "is-passive",
1003 "passive");
1004 else
1005 json_object_string_add(iface_json, "is-passive",
1006 "active");
1007 json_object_string_add(iface_json, "circuit-id", buf);
1008 json_object_string_add(iface_json, "type",
1009 circuit_type2string(circuit->circ_type));
1010 json_object_string_add(iface_json, "level",
1011 circuit_t2string(circuit->is_type));
1012 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
1013 json_object_string_add(iface_json, "snpa",
1014 snpa_print(circuit->u.bc.snpa));
1015
1016
1017 levels_json = json_object_new_array();
1018 json_object_object_add(iface_json, "levels", levels_json);
1019 for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
1020 if ((circuit->is_type & level) == 0)
1021 continue;
1022 level_json = json_object_new_object();
1023 json_object_string_add(level_json, "level",
1024 circuit_t2string(level));
1025 if (circuit->area->newmetric)
1026 json_object_int_add(level_json, "metric",
1027 circuit->te_metric[0]);
1028 else
1029 json_object_int_add(level_json, "metric",
1030 circuit->metric[0]);
1031 if (!circuit->is_passive) {
1032 json_object_int_add(level_json,
1033 "active-neighbors",
1034 circuit->upadjcount[0]);
1035 json_object_int_add(level_json,
1036 "hello-interval",
1037 circuit->hello_interval[0]);
1038 hold_json = json_object_new_object();
1039 json_object_object_add(level_json, "holddown",
1040 hold_json);
1041 json_object_int_add(
1042 hold_json, "count",
1043 circuit->hello_multiplier[0]);
1044 json_object_string_add(
1045 hold_json, "pad",
1046 (circuit->pad_hellos ? "yes" : "no"));
1047 json_object_int_add(level_json, "cnsp-interval",
1048 circuit->csnp_interval[0]);
1049 json_object_int_add(level_json, "psnp-interval",
1050 circuit->psnp_interval[0]);
1051 if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
1052 lan_prio_json =
1053 json_object_new_object();
1054 json_object_object_add(level_json,
1055 "lan",
1056 lan_prio_json);
1057 json_object_int_add(
1058 lan_prio_json, "priority",
1059 circuit->priority[0]);
1060 json_object_string_add(
1061 lan_prio_json, "is-dis",
1062 (circuit->u.bc.is_dr[0]
1063 ? "yes"
1064 : "no"));
1065 }
1066 }
1067 json_object_array_add(levels_json, level_json);
1068 }
1069
1070 if (circuit->ip_addrs && listcount(circuit->ip_addrs) > 0) {
1071 ipv4_addr_json = json_object_new_object();
1072 json_object_object_add(iface_json, "ip-prefix",
1073 ipv4_addr_json);
1074 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node,
1075 ip_addr)) {
1076 snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX",
1077 ip_addr);
1078 json_object_string_add(ipv4_addr_json, "ip",
1079 buf_prx);
1080 }
1081 }
1082 if (circuit->ipv6_link && listcount(circuit->ipv6_link) > 0) {
1083 ipv6_link_json = json_object_new_object();
1084 json_object_object_add(iface_json, "ipv6-link-locals",
1085 ipv6_link_json);
1086 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node,
1087 ip_addr)) {
1088 snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX",
1089 ip_addr);
1090 json_object_string_add(ipv6_link_json, "ipv6",
1091 buf_prx);
1092 }
1093 }
1094 if (circuit->ipv6_non_link &&
1095 listcount(circuit->ipv6_non_link) > 0) {
1096 ipv6_non_link_json = json_object_new_object();
1097 json_object_object_add(iface_json, "ipv6-prefixes",
1098 ipv6_non_link_json);
1099 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node,
1100 ip_addr)) {
1101 snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX",
1102 ip_addr);
1103 json_object_string_add(ipv6_non_link_json,
1104 "ipv6", buf_prx);
1105 }
1106 }
1107 }
1108 return;
1109 }
1110
1111 void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty,
1112 char detail)
1113 {
1114 if (detail == ISIS_UI_LEVEL_BRIEF) {
1115 vty_out(vty, " %-12s", circuit->interface->name);
1116 vty_out(vty, "0x%-7x", circuit->circuit_id);
1117 vty_out(vty, "%-9s", circuit_state2string(circuit->state));
1118 vty_out(vty, "%-9s", circuit_type2string(circuit->circ_type));
1119 vty_out(vty, "%-9s", circuit_t2string(circuit->is_type));
1120 vty_out(vty, "\n");
1121 }
1122
1123 if (detail == ISIS_UI_LEVEL_DETAIL) {
1124 struct listnode *node;
1125 struct prefix *ip_addr;
1126
1127 vty_out(vty, " Interface: %s", circuit->interface->name);
1128 vty_out(vty, ", State: %s",
1129 circuit_state2string(circuit->state));
1130 if (circuit->is_passive)
1131 vty_out(vty, ", Passive");
1132 else
1133 vty_out(vty, ", Active");
1134 vty_out(vty, ", Circuit Id: 0x%x", circuit->circuit_id);
1135 vty_out(vty, "\n");
1136 vty_out(vty, " Type: %s",
1137 circuit_type2string(circuit->circ_type));
1138 vty_out(vty, ", Level: %s", circuit_t2string(circuit->is_type));
1139 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
1140 vty_out(vty, ", SNPA: %-10s",
1141 snpa_print(circuit->u.bc.snpa));
1142 vty_out(vty, "\n");
1143 if (circuit->is_type & IS_LEVEL_1) {
1144 vty_out(vty, " Level-1 Information:\n");
1145 if (circuit->area->newmetric)
1146 vty_out(vty, " Metric: %d",
1147 circuit->te_metric[0]);
1148 else
1149 vty_out(vty, " Metric: %d",
1150 circuit->metric[0]);
1151 if (!circuit->is_passive) {
1152 vty_out(vty, ", Active neighbors: %u\n",
1153 circuit->upadjcount[0]);
1154 vty_out(vty,
1155 " Hello interval: %u, Holddown count: %u %s\n",
1156 circuit->hello_interval[0],
1157 circuit->hello_multiplier[0],
1158 (circuit->pad_hellos ? "(pad)"
1159 : "(no-pad)"));
1160 vty_out(vty,
1161 " CNSP interval: %u, PSNP interval: %u\n",
1162 circuit->csnp_interval[0],
1163 circuit->psnp_interval[0]);
1164 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
1165 vty_out(vty,
1166 " LAN Priority: %u, %s\n",
1167 circuit->priority[0],
1168 (circuit->u.bc.is_dr[0]
1169 ? "is DIS"
1170 : "is not DIS"));
1171 } else {
1172 vty_out(vty, "\n");
1173 }
1174 }
1175 if (circuit->is_type & IS_LEVEL_2) {
1176 vty_out(vty, " Level-2 Information:\n");
1177 if (circuit->area->newmetric)
1178 vty_out(vty, " Metric: %d",
1179 circuit->te_metric[1]);
1180 else
1181 vty_out(vty, " Metric: %d",
1182 circuit->metric[1]);
1183 if (!circuit->is_passive) {
1184 vty_out(vty, ", Active neighbors: %u\n",
1185 circuit->upadjcount[1]);
1186 vty_out(vty,
1187 " Hello interval: %u, Holddown count: %u %s\n",
1188 circuit->hello_interval[1],
1189 circuit->hello_multiplier[1],
1190 (circuit->pad_hellos ? "(pad)"
1191 : "(no-pad)"));
1192 vty_out(vty,
1193 " CNSP interval: %u, PSNP interval: %u\n",
1194 circuit->csnp_interval[1],
1195 circuit->psnp_interval[1]);
1196 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
1197 vty_out(vty,
1198 " LAN Priority: %u, %s\n",
1199 circuit->priority[1],
1200 (circuit->u.bc.is_dr[1]
1201 ? "is DIS"
1202 : "is not DIS"));
1203 } else {
1204 vty_out(vty, "\n");
1205 }
1206 }
1207 if (circuit->ip_addrs && listcount(circuit->ip_addrs) > 0) {
1208 vty_out(vty, " IP Prefix(es):\n");
1209 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node,
1210 ip_addr))
1211 vty_out(vty, " %pFX\n", ip_addr);
1212 }
1213 if (circuit->ipv6_link && listcount(circuit->ipv6_link) > 0) {
1214 vty_out(vty, " IPv6 Link-Locals:\n");
1215 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node,
1216 ip_addr))
1217 vty_out(vty, " %pFX\n", ip_addr);
1218 }
1219 if (circuit->ipv6_non_link
1220 && listcount(circuit->ipv6_non_link) > 0) {
1221 vty_out(vty, " IPv6 Prefixes:\n");
1222 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node,
1223 ip_addr))
1224 vty_out(vty, " %pFX\n", ip_addr);
1225 }
1226
1227 vty_out(vty, "\n");
1228 }
1229 return;
1230 }
1231
1232 #ifdef FABRICD
1233 DEFINE_HOOK(isis_circuit_config_write,
1234 (struct isis_circuit *circuit, struct vty *vty),
1235 (circuit, vty));
1236
1237 static int isis_interface_config_write(struct vty *vty)
1238 {
1239 struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
1240 int write = 0;
1241 struct interface *ifp;
1242 struct isis_circuit *circuit;
1243 int i;
1244
1245 FOR_ALL_INTERFACES (vrf, ifp) {
1246 /* IF name */
1247 if_vty_config_start(vty, ifp);
1248 write++;
1249 /* IF desc */
1250 if (ifp->desc) {
1251 vty_out(vty, " description %s\n", ifp->desc);
1252 write++;
1253 }
1254 /* ISIS Circuit */
1255 do {
1256 circuit = circuit_scan_by_ifp(ifp);
1257 if (circuit == NULL)
1258 break;
1259 if (circuit->ip_router) {
1260 vty_out(vty, " ip router " PROTO_NAME " %s\n",
1261 circuit->tag);
1262 write++;
1263 }
1264 if (circuit->is_passive) {
1265 vty_out(vty, " " PROTO_NAME " passive\n");
1266 write++;
1267 }
1268 if (circuit->circ_type_config == CIRCUIT_T_P2P) {
1269 vty_out(vty, " " PROTO_NAME " network point-to-point\n");
1270 write++;
1271 }
1272 if (circuit->ipv6_router) {
1273 vty_out(vty, " ipv6 router " PROTO_NAME " %s\n",
1274 circuit->tag);
1275 write++;
1276 }
1277
1278 /* ISIS - circuit type */
1279 if (!fabricd) {
1280 if (circuit->is_type == IS_LEVEL_1) {
1281 vty_out(vty, " " PROTO_NAME " circuit-type level-1\n");
1282 write++;
1283 } else {
1284 if (circuit->is_type == IS_LEVEL_2) {
1285 vty_out(vty,
1286 " " PROTO_NAME " circuit-type level-2-only\n");
1287 write++;
1288 }
1289 }
1290 }
1291
1292 /* ISIS - CSNP interval */
1293 if (circuit->csnp_interval[0]
1294 == circuit->csnp_interval[1]) {
1295 if (circuit->csnp_interval[0]
1296 != DEFAULT_CSNP_INTERVAL) {
1297 vty_out(vty, " " PROTO_NAME " csnp-interval %d\n",
1298 circuit->csnp_interval[0]);
1299 write++;
1300 }
1301 } else {
1302 for (i = 0; i < 2; i++) {
1303 if (circuit->csnp_interval[i]
1304 != DEFAULT_CSNP_INTERVAL) {
1305 vty_out(vty,
1306 " " PROTO_NAME " csnp-interval %d level-%d\n",
1307 circuit->csnp_interval
1308 [i],
1309 i + 1);
1310 write++;
1311 }
1312 }
1313 }
1314
1315 /* ISIS - PSNP interval */
1316 if (circuit->psnp_interval[0]
1317 == circuit->psnp_interval[1]) {
1318 if (circuit->psnp_interval[0]
1319 != DEFAULT_PSNP_INTERVAL) {
1320 vty_out(vty, " " PROTO_NAME " psnp-interval %d\n",
1321 circuit->psnp_interval[0]);
1322 write++;
1323 }
1324 } else {
1325 for (i = 0; i < 2; i++) {
1326 if (circuit->psnp_interval[i]
1327 != DEFAULT_PSNP_INTERVAL) {
1328 vty_out(vty,
1329 " " PROTO_NAME " psnp-interval %d level-%d\n",
1330 circuit->psnp_interval
1331 [i],
1332 i + 1);
1333 write++;
1334 }
1335 }
1336 }
1337
1338 /* ISIS - Hello padding - Defaults to true so only
1339 * display if false */
1340 if (circuit->pad_hellos == 0) {
1341 vty_out(vty, " no " PROTO_NAME " hello padding\n");
1342 write++;
1343 }
1344
1345 if (circuit->disable_threeway_adj) {
1346 vty_out(vty, " no isis three-way-handshake\n");
1347 write++;
1348 }
1349
1350 /* ISIS - Hello interval */
1351 if (circuit->hello_interval[0]
1352 == circuit->hello_interval[1]) {
1353 if (circuit->hello_interval[0]
1354 != DEFAULT_HELLO_INTERVAL) {
1355 vty_out(vty,
1356 " " PROTO_NAME " hello-interval %d\n",
1357 circuit->hello_interval[0]);
1358 write++;
1359 }
1360 } else {
1361 for (i = 0; i < 2; i++) {
1362 if (circuit->hello_interval[i]
1363 != DEFAULT_HELLO_INTERVAL) {
1364 vty_out(vty,
1365 " " PROTO_NAME " hello-interval %d level-%d\n",
1366 circuit->hello_interval
1367 [i],
1368 i + 1);
1369 write++;
1370 }
1371 }
1372 }
1373
1374 /* ISIS - Hello Multiplier */
1375 if (circuit->hello_multiplier[0]
1376 == circuit->hello_multiplier[1]) {
1377 if (circuit->hello_multiplier[0]
1378 != DEFAULT_HELLO_MULTIPLIER) {
1379 vty_out(vty,
1380 " " PROTO_NAME " hello-multiplier %d\n",
1381 circuit->hello_multiplier[0]);
1382 write++;
1383 }
1384 } else {
1385 for (i = 0; i < 2; i++) {
1386 if (circuit->hello_multiplier[i]
1387 != DEFAULT_HELLO_MULTIPLIER) {
1388 vty_out(vty,
1389 " " PROTO_NAME " hello-multiplier %d level-%d\n",
1390 circuit->hello_multiplier
1391 [i],
1392 i + 1);
1393 write++;
1394 }
1395 }
1396 }
1397
1398 /* ISIS - Priority */
1399 if (circuit->priority[0] == circuit->priority[1]) {
1400 if (circuit->priority[0] != DEFAULT_PRIORITY) {
1401 vty_out(vty, " " PROTO_NAME " priority %d\n",
1402 circuit->priority[0]);
1403 write++;
1404 }
1405 } else {
1406 for (i = 0; i < 2; i++) {
1407 if (circuit->priority[i]
1408 != DEFAULT_PRIORITY) {
1409 vty_out(vty,
1410 " " PROTO_NAME " priority %d level-%d\n",
1411 circuit->priority[i],
1412 i + 1);
1413 write++;
1414 }
1415 }
1416 }
1417
1418 /* ISIS - Metric */
1419 if (circuit->te_metric[0] == circuit->te_metric[1]) {
1420 if (circuit->te_metric[0]
1421 != DEFAULT_CIRCUIT_METRIC) {
1422 vty_out(vty, " " PROTO_NAME " metric %d\n",
1423 circuit->te_metric[0]);
1424 write++;
1425 }
1426 } else {
1427 for (i = 0; i < 2; i++) {
1428 if (circuit->te_metric[i]
1429 != DEFAULT_CIRCUIT_METRIC) {
1430 vty_out(vty,
1431 " " PROTO_NAME " metric %d level-%d\n",
1432 circuit->te_metric[i],
1433 i + 1);
1434 write++;
1435 }
1436 }
1437 }
1438 if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) {
1439 vty_out(vty, " " PROTO_NAME " password md5 %s\n",
1440 circuit->passwd.passwd);
1441 write++;
1442 } else if (circuit->passwd.type
1443 == ISIS_PASSWD_TYPE_CLEARTXT) {
1444 vty_out(vty, " " PROTO_NAME " password clear %s\n",
1445 circuit->passwd.passwd);
1446 write++;
1447 }
1448 if (circuit->bfd_config.enabled) {
1449 vty_out(vty, " " PROTO_NAME " bfd\n");
1450 write++;
1451 }
1452 write += hook_call(isis_circuit_config_write,
1453 circuit, vty);
1454 } while (0);
1455 if_vty_config_end(vty);
1456 }
1457
1458 return write;
1459 }
1460 #endif /* ifdef FABRICD */
1461
1462 void isis_circuit_af_set(struct isis_circuit *circuit, bool ip_router,
1463 bool ipv6_router)
1464 {
1465 struct isis_area *area = circuit->area;
1466 int old_ipr = circuit->ip_router;
1467 int old_ipv6r = circuit->ipv6_router;
1468
1469 /* is there something to do? */
1470 if (old_ipr == ip_router && old_ipv6r == ipv6_router)
1471 return;
1472
1473 circuit->ip_router = ip_router;
1474 circuit->ipv6_router = ipv6_router;
1475 circuit_update_nlpids(circuit);
1476
1477 if (area) {
1478 area->ip_circuits += ip_router - old_ipr;
1479 area->ipv6_circuits += ipv6_router - old_ipv6r;
1480
1481 if (ip_router || ipv6_router)
1482 lsp_regenerate_schedule(area, circuit->is_type, 0);
1483 }
1484 }
1485
1486 ferr_r isis_circuit_passive_set(struct isis_circuit *circuit, bool passive)
1487 {
1488 if (circuit->is_passive == passive)
1489 return ferr_ok();
1490
1491 if (if_is_loopback(circuit->interface) && !passive)
1492 return ferr_cfg_invalid("loopback is always passive");
1493
1494 if (circuit->state != C_STATE_UP) {
1495 circuit->is_passive = passive;
1496 } else {
1497 struct isis_area *area = circuit->area;
1498 isis_csm_state_change(ISIS_DISABLE, circuit, area);
1499 circuit->is_passive = passive;
1500 isis_csm_state_change(ISIS_ENABLE, circuit, area);
1501 }
1502
1503 return ferr_ok();
1504 }
1505
1506 ferr_r isis_circuit_metric_set(struct isis_circuit *circuit, int level,
1507 int metric)
1508 {
1509 assert(level == IS_LEVEL_1 || level == IS_LEVEL_2);
1510 if (metric > MAX_WIDE_LINK_METRIC)
1511 return ferr_cfg_invalid("metric %d too large for wide metric",
1512 metric);
1513 if (circuit->area && circuit->area->oldmetric
1514 && metric > MAX_NARROW_LINK_METRIC)
1515 return ferr_cfg_invalid("metric %d too large for narrow metric",
1516 metric);
1517
1518 /* inform ldp-sync of metric change
1519 * if ldp-sync is running need to save metric
1520 * and restore new values after ldp-sync completion.
1521 */
1522 if (isis_ldp_sync_if_metric_config(circuit, level, metric)) {
1523 circuit->te_metric[level - 1] = metric;
1524 circuit->metric[level - 1] = metric;
1525 if (circuit->area)
1526 lsp_regenerate_schedule(circuit->area, level, 0);
1527 }
1528 return ferr_ok();
1529 }
1530
1531 ferr_r isis_circuit_passwd_unset(struct isis_circuit *circuit)
1532 {
1533 memset(&circuit->passwd, 0, sizeof(circuit->passwd));
1534 return ferr_ok();
1535 }
1536
1537 ferr_r isis_circuit_passwd_set(struct isis_circuit *circuit,
1538 uint8_t passwd_type, const char *passwd)
1539 {
1540 int len;
1541
1542 if (!passwd)
1543 return ferr_code_bug("no circuit password given");
1544
1545 len = strlen(passwd);
1546 if (len > 254)
1547 return ferr_code_bug(
1548 "circuit password too long (max 254 chars)");
1549
1550 circuit->passwd.len = len;
1551 strlcpy((char *)circuit->passwd.passwd, passwd,
1552 sizeof(circuit->passwd.passwd));
1553 circuit->passwd.type = passwd_type;
1554 return ferr_ok();
1555 }
1556
1557 ferr_r isis_circuit_passwd_cleartext_set(struct isis_circuit *circuit,
1558 const char *passwd)
1559 {
1560 return isis_circuit_passwd_set(circuit, ISIS_PASSWD_TYPE_CLEARTXT,
1561 passwd);
1562 }
1563
1564 ferr_r isis_circuit_passwd_hmac_md5_set(struct isis_circuit *circuit,
1565 const char *passwd)
1566 {
1567 return isis_circuit_passwd_set(circuit, ISIS_PASSWD_TYPE_HMAC_MD5,
1568 passwd);
1569 }
1570
1571 void isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type)
1572 {
1573 if (circuit->circ_type == circ_type)
1574 return;
1575
1576 if (circuit->state != C_STATE_UP) {
1577 circuit->circ_type = circ_type;
1578 circuit->circ_type_config = circ_type;
1579 } else {
1580 struct isis_area *area = circuit->area;
1581
1582 isis_csm_state_change(ISIS_DISABLE, circuit, area);
1583 circuit->circ_type = circ_type;
1584 circuit->circ_type_config = circ_type;
1585 isis_csm_state_change(ISIS_ENABLE, circuit, area);
1586 }
1587 }
1588
1589 int isis_circuit_mt_enabled_set(struct isis_circuit *circuit, uint16_t mtid,
1590 bool enabled)
1591 {
1592 struct isis_circuit_mt_setting *setting;
1593
1594 setting = circuit_get_mt_setting(circuit, mtid);
1595 if (setting->enabled != enabled) {
1596 setting->enabled = enabled;
1597 if (circuit->area)
1598 lsp_regenerate_schedule(circuit->area,
1599 IS_LEVEL_1 | IS_LEVEL_2, 0);
1600 }
1601
1602 return CMD_SUCCESS;
1603 }
1604
1605 int isis_if_new_hook(struct interface *ifp)
1606 {
1607 return 0;
1608 }
1609
1610 int isis_if_delete_hook(struct interface *ifp)
1611 {
1612 if (ifp->info)
1613 isis_circuit_del(ifp->info);
1614
1615 return 0;
1616 }
1617
1618 static int isis_ifp_create(struct interface *ifp)
1619 {
1620 struct isis_circuit *circuit = ifp->info;
1621
1622 if (circuit)
1623 isis_circuit_enable(circuit);
1624
1625 hook_call(isis_if_new_hook, ifp);
1626
1627 return 0;
1628 }
1629
1630 static int isis_ifp_up(struct interface *ifp)
1631 {
1632 struct isis_circuit *circuit = ifp->info;
1633
1634 if (circuit)
1635 isis_csm_state_change(IF_UP_FROM_Z, circuit, ifp);
1636
1637 return 0;
1638 }
1639
1640 static int isis_ifp_down(struct interface *ifp)
1641 {
1642 afi_t afi;
1643 struct isis_circuit *circuit = ifp->info;
1644
1645 if (circuit) {
1646 for (afi = AFI_IP; afi <= AFI_IP6; afi++)
1647 isis_circuit_switchover_routes(
1648 circuit, afi == AFI_IP ? AF_INET : AF_INET6,
1649 NULL, ifp->ifindex);
1650 isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp);
1651
1652 SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
1653 }
1654
1655 return 0;
1656 }
1657
1658 static int isis_ifp_destroy(struct interface *ifp)
1659 {
1660 struct isis_circuit *circuit = ifp->info;
1661
1662 if (circuit)
1663 isis_circuit_disable(circuit);
1664
1665 return 0;
1666 }
1667
1668 void isis_circuit_init(void)
1669 {
1670 /* Initialize Zebra interface data structure */
1671 hook_register_prio(if_add, 0, isis_if_new_hook);
1672 hook_register_prio(if_del, 0, isis_if_delete_hook);
1673
1674 /* Install interface node */
1675 #ifdef FABRICD
1676 if_cmd_init(isis_interface_config_write);
1677 #else
1678 if_cmd_init_default();
1679 #endif
1680 if_zapi_callbacks(isis_ifp_create, isis_ifp_up,
1681 isis_ifp_down, isis_ifp_destroy);
1682 }