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