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