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