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