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