]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_circuit.c
Merge pull request #410 from dslicenc/rdnbrd-vrr
[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; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 #ifndef ETHER_ADDR_LEN
30 #define ETHER_ADDR_LEN ETHERADDRL
31 #endif
32
33 #include "log.h"
34 #include "memory.h"
35 #include "vrf.h"
36 #include "if.h"
37 #include "linklist.h"
38 #include "command.h"
39 #include "thread.h"
40 #include "vty.h"
41 #include "hash.h"
42 #include "prefix.h"
43 #include "stream.h"
44 #include "qobj.h"
45
46 #include "isisd/dict.h"
47 #include "isisd/isis_constants.h"
48 #include "isisd/isis_common.h"
49 #include "isisd/isis_flags.h"
50 #include "isisd/isis_circuit.h"
51 #include "isisd/isis_tlv.h"
52 #include "isisd/isis_lsp.h"
53 #include "isisd/isis_pdu.h"
54 #include "isisd/isis_network.h"
55 #include "isisd/isis_misc.h"
56 #include "isisd/isis_constants.h"
57 #include "isisd/isis_adjacency.h"
58 #include "isisd/isis_dr.h"
59 #include "isisd/isisd.h"
60 #include "isisd/isis_csm.h"
61 #include "isisd/isis_events.h"
62 #include "isisd/isis_te.h"
63 #include "isisd/isis_mt.h"
64
65 DEFINE_QOBJ_TYPE(isis_circuit)
66
67 /*
68 * Prototypes.
69 */
70 int isis_interface_config_write(struct vty *);
71 int isis_if_new_hook(struct interface *);
72 int isis_if_delete_hook(struct interface *);
73
74 struct isis_circuit *
75 isis_circuit_new ()
76 {
77 struct isis_circuit *circuit;
78 int i;
79
80 circuit = XCALLOC (MTYPE_ISIS_CIRCUIT, sizeof (struct isis_circuit));
81 if (circuit == NULL)
82 {
83 zlog_err ("Can't malloc isis circuit");
84 return NULL;
85 }
86
87 /*
88 * Default values
89 */
90 circuit->is_type = IS_LEVEL_1_AND_2;
91 circuit->flags = 0;
92 circuit->pad_hellos = 1;
93 for (i = 0; i < 2; i++)
94 {
95 circuit->hello_interval[i] = DEFAULT_HELLO_INTERVAL;
96 circuit->hello_multiplier[i] = DEFAULT_HELLO_MULTIPLIER;
97 circuit->csnp_interval[i] = DEFAULT_CSNP_INTERVAL;
98 circuit->psnp_interval[i] = DEFAULT_PSNP_INTERVAL;
99 circuit->priority[i] = DEFAULT_PRIORITY;
100 circuit->metric[i] = DEFAULT_CIRCUIT_METRIC;
101 circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC;
102 }
103
104 circuit->mtc = mpls_te_circuit_new();
105
106 circuit_mt_init(circuit);
107
108 QOBJ_REG (circuit, isis_circuit);
109
110 return circuit;
111 }
112
113 void
114 isis_circuit_del (struct isis_circuit *circuit)
115 {
116 if (!circuit)
117 return;
118
119 QOBJ_UNREG (circuit);
120
121 isis_circuit_if_unbind (circuit, circuit->interface);
122
123 circuit_mt_finish(circuit);
124
125 /* and lastly the circuit itself */
126 XFREE (MTYPE_ISIS_CIRCUIT, circuit);
127
128 return;
129 }
130
131 void
132 isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area)
133 {
134 assert (area);
135 circuit->area = area;
136
137 /*
138 * Whenever the is-type of an area is changed, the is-type of each circuit
139 * in that area is updated to a non-empty subset of the area is-type.
140 * Inversely, when configuring a new circuit, this property should be
141 * ensured as well.
142 */
143 if (area->is_type != IS_LEVEL_1_AND_2)
144 circuit->is_type = area->is_type;
145
146 /*
147 * Add the circuit into area
148 */
149 listnode_add (area->circuit_list, circuit);
150
151 circuit->idx = flags_get_index (&area->flags);
152
153 return;
154 }
155
156 void
157 isis_circuit_deconfigure (struct isis_circuit *circuit, struct isis_area *area)
158 {
159 /* Free the index of SRM and SSN flags */
160 flags_free_index (&area->flags, circuit->idx);
161 circuit->idx = 0;
162 /* Remove circuit from area */
163 assert (circuit->area == area);
164 listnode_delete (area->circuit_list, circuit);
165 circuit->area = NULL;
166
167 return;
168 }
169
170 struct isis_circuit *
171 circuit_lookup_by_ifp (struct interface *ifp, struct list *list)
172 {
173 struct isis_circuit *circuit = NULL;
174 struct listnode *node;
175
176 if (!list)
177 return NULL;
178
179 for (ALL_LIST_ELEMENTS_RO (list, node, circuit))
180 if (circuit->interface == ifp)
181 {
182 assert (ifp->info == circuit);
183 return circuit;
184 }
185
186 return NULL;
187 }
188
189 struct isis_circuit *
190 circuit_scan_by_ifp (struct interface *ifp)
191 {
192 struct isis_area *area;
193 struct listnode *node;
194 struct isis_circuit *circuit;
195
196 if (ifp->info)
197 return (struct isis_circuit *)ifp->info;
198
199 if (isis->area_list)
200 {
201 for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area))
202 {
203 circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
204 if (circuit)
205 return circuit;
206 }
207 }
208 return circuit_lookup_by_ifp (ifp, isis->init_circ_list);
209 }
210
211 void
212 isis_circuit_add_addr (struct isis_circuit *circuit,
213 struct connected *connected)
214 {
215 struct listnode *node;
216 struct prefix_ipv4 *ipv4;
217 #if defined(EXTREME_DEBUG)
218 char buf[PREFIX2STR_BUFFER];
219 #endif
220 struct prefix_ipv6 *ipv6;
221
222 if (connected->address->family == AF_INET)
223 {
224 u_int32_t addr = connected->address->u.prefix4.s_addr;
225 addr = ntohl (addr);
226 if (IPV4_NET0(addr) ||
227 IPV4_NET127(addr) ||
228 IN_CLASSD(addr) ||
229 IPV4_LINKLOCAL(addr))
230 return;
231
232 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ipv4))
233 if (prefix_same ((struct prefix *) ipv4, connected->address))
234 return;
235
236 ipv4 = prefix_ipv4_new ();
237 ipv4->prefixlen = connected->address->prefixlen;
238 ipv4->prefix = connected->address->u.prefix4;
239 listnode_add (circuit->ip_addrs, ipv4);
240
241 /* Update MPLS TE Local IP address parameter */
242 set_circuitparams_local_ipaddr (circuit->mtc, ipv4->prefix);
243
244 if (circuit->area)
245 lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
246
247 #ifdef EXTREME_DEBUG
248 prefix2str (connected->address, buf, sizeof (buf));
249 zlog_debug ("Added IP address %s to circuit %d", buf,
250 circuit->circuit_id);
251 #endif /* EXTREME_DEBUG */
252 }
253 if (connected->address->family == AF_INET6)
254 {
255 if (IN6_IS_ADDR_LOOPBACK(&connected->address->u.prefix6))
256 return;
257
258 for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_link, node, ipv6))
259 if (prefix_same ((struct prefix *) ipv6, connected->address))
260 return;
261 for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, node, ipv6))
262 if (prefix_same ((struct prefix *) ipv6, connected->address))
263 return;
264
265 ipv6 = prefix_ipv6_new ();
266 ipv6->prefixlen = connected->address->prefixlen;
267 ipv6->prefix = connected->address->u.prefix6;
268
269 if (IN6_IS_ADDR_LINKLOCAL (&ipv6->prefix))
270 listnode_add (circuit->ipv6_link, ipv6);
271 else
272 listnode_add (circuit->ipv6_non_link, ipv6);
273 if (circuit->area)
274 lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
275
276 #ifdef EXTREME_DEBUG
277 prefix2str (connected->address, buf, sizeof (buf));
278 zlog_debug ("Added IPv6 address %s to circuit %d", buf,
279 circuit->circuit_id);
280 #endif /* EXTREME_DEBUG */
281 }
282 return;
283 }
284
285 void
286 isis_circuit_del_addr (struct isis_circuit *circuit,
287 struct connected *connected)
288 {
289 struct prefix_ipv4 *ipv4, *ip = NULL;
290 struct listnode *node;
291 char buf[PREFIX2STR_BUFFER];
292 struct prefix_ipv6 *ipv6, *ip6 = NULL;
293 int found = 0;
294
295 if (connected->address->family == AF_INET)
296 {
297 ipv4 = prefix_ipv4_new ();
298 ipv4->prefixlen = connected->address->prefixlen;
299 ipv4->prefix = connected->address->u.prefix4;
300
301 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip))
302 if (prefix_same ((struct prefix *) ip, (struct prefix *) ipv4))
303 break;
304
305 if (ip)
306 {
307 listnode_delete (circuit->ip_addrs, ip);
308 if (circuit->area)
309 lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
310 }
311 else
312 {
313 prefix2str (connected->address, buf, sizeof (buf));
314 zlog_warn ("Nonexistant ip address %s removal attempt from \
315 circuit %d", buf, circuit->circuit_id);
316 zlog_warn ("Current ip addresses on %s:", circuit->interface->name);
317 for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ip))
318 {
319 prefix2str(ip, buf, sizeof(buf));
320 zlog_warn(" %s", buf);
321 }
322 zlog_warn("End of addresses");
323 }
324
325 prefix_ipv4_free (ipv4);
326 }
327 if (connected->address->family == AF_INET6)
328 {
329 ipv6 = prefix_ipv6_new ();
330 ipv6->prefixlen = connected->address->prefixlen;
331 ipv6->prefix = connected->address->u.prefix6;
332
333 if (IN6_IS_ADDR_LINKLOCAL (&ipv6->prefix))
334 {
335 for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_link, node, ip6))
336 {
337 if (prefix_same ((struct prefix *) ip6, (struct prefix *) ipv6))
338 break;
339 }
340 if (ip6)
341 {
342 listnode_delete (circuit->ipv6_link, ip6);
343 found = 1;
344 }
345 }
346 else
347 {
348 for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, node, ip6))
349 {
350 if (prefix_same ((struct prefix *) ip6, (struct prefix *) ipv6))
351 break;
352 }
353 if (ip6)
354 {
355 listnode_delete (circuit->ipv6_non_link, ip6);
356 found = 1;
357 }
358 }
359
360 if (!found)
361 {
362 prefix2str (connected->address, buf, sizeof (buf));
363 zlog_warn ("Nonexitant ip address %s removal attempt from \
364 circuit %d", buf, circuit->circuit_id);
365 zlog_warn ("Current ip addresses on %s:", circuit->interface->name);
366 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ip6))
367 {
368 prefix2str((struct prefix*)ip6, (char *)buf, BUFSIZ);
369 zlog_warn(" %s", buf);
370 }
371 zlog_warn(" -----");
372 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ip6))
373 {
374 prefix2str((struct prefix*)ip6, (char *)buf, BUFSIZ);
375 zlog_warn(" %s", buf);
376 }
377 zlog_warn("End of addresses");
378 }
379 else if (circuit->area)
380 lsp_regenerate_schedule (circuit->area, circuit->is_type, 0);
381
382 prefix_ipv6_free (ipv6);
383 }
384 return;
385 }
386
387 static u_char
388 isis_circuit_id_gen (struct interface *ifp)
389 {
390 u_char id = 0;
391 char ifname[16];
392 unsigned int i;
393 int start = -1, end = -1;
394
395 /*
396 * Get a stable circuit id from ifname. This makes
397 * the ifindex from flapping when netdevs are created
398 * and deleted on the fly. Note that this circuit id
399 * is used in pseudo lsps so it is better to be stable.
400 * The following code works on any reasonanle ifname
401 * like: eth1 or trk-1.1 etc.
402 */
403 for (i = 0; i < strlen (ifp->name); i++)
404 {
405 if (isdigit((unsigned char)ifp->name[i]))
406 {
407 if (start < 0)
408 {
409 start = i;
410 end = i + 1;
411 }
412 else
413 {
414 end = i + 1;
415 }
416 }
417 else if (start >= 0)
418 break;
419 }
420
421 if ((start >= 0) && (end >= start) && (end - start) < 16)
422 {
423 memset (ifname, 0, 16);
424 strncpy (ifname, &ifp->name[start], end - start);
425 id = (u_char)atoi(ifname);
426 }
427
428 /* Try to be unique. */
429 if (!id)
430 id = (u_char)((ifp->ifindex & 0xff) | 0x80);
431
432 return id;
433 }
434
435 void
436 isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp)
437 {
438 struct listnode *node, *nnode;
439 struct connected *conn;
440
441 circuit->circuit_id = isis_circuit_id_gen (ifp);
442
443 isis_circuit_if_bind (circuit, ifp);
444 /* isis_circuit_update_addrs (circuit, ifp); */
445
446 if (if_is_broadcast (ifp))
447 {
448 if (circuit->circ_type_config == CIRCUIT_T_P2P)
449 circuit->circ_type = CIRCUIT_T_P2P;
450 else
451 circuit->circ_type = CIRCUIT_T_BROADCAST;
452 }
453 else if (if_is_pointopoint (ifp))
454 {
455 circuit->circ_type = CIRCUIT_T_P2P;
456 }
457 else if (if_is_loopback (ifp))
458 {
459 circuit->circ_type = CIRCUIT_T_LOOPBACK;
460 circuit->is_passive = 1;
461 }
462 else
463 {
464 /* It's normal in case of loopback etc. */
465 if (isis->debugs & DEBUG_EVENTS)
466 zlog_debug ("isis_circuit_if_add: unsupported media");
467 circuit->circ_type = CIRCUIT_T_UNKNOWN;
468 }
469
470 circuit->ip_addrs = list_new ();
471 circuit->ipv6_link = list_new ();
472 circuit->ipv6_non_link = list_new ();
473
474 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn))
475 isis_circuit_add_addr (circuit, conn);
476
477 return;
478 }
479
480 void
481 isis_circuit_if_del (struct isis_circuit *circuit, struct interface *ifp)
482 {
483 struct listnode *node, *nnode;
484 struct connected *conn;
485
486 assert (circuit->interface == ifp);
487
488 /* destroy addresses */
489 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn))
490 isis_circuit_del_addr (circuit, conn);
491
492 if (circuit->ip_addrs)
493 {
494 assert (listcount(circuit->ip_addrs) == 0);
495 list_delete (circuit->ip_addrs);
496 circuit->ip_addrs = NULL;
497 }
498
499 if (circuit->ipv6_link)
500 {
501 assert (listcount(circuit->ipv6_link) == 0);
502 list_delete (circuit->ipv6_link);
503 circuit->ipv6_link = NULL;
504 }
505
506 if (circuit->ipv6_non_link)
507 {
508 assert (listcount(circuit->ipv6_non_link) == 0);
509 list_delete (circuit->ipv6_non_link);
510 circuit->ipv6_non_link = NULL;
511 }
512
513 circuit->circ_type = CIRCUIT_T_UNKNOWN;
514 circuit->circuit_id = 0;
515
516 return;
517 }
518
519 void
520 isis_circuit_if_bind (struct isis_circuit *circuit, struct interface *ifp)
521 {
522 assert (circuit != NULL);
523 assert (ifp != NULL);
524 if (circuit->interface)
525 assert (circuit->interface == ifp);
526 else
527 circuit->interface = ifp;
528 if (ifp->info)
529 assert (ifp->info == circuit);
530 else
531 ifp->info = circuit;
532 isis_link_params_update (circuit, ifp);
533 }
534
535 void
536 isis_circuit_if_unbind (struct isis_circuit *circuit, struct interface *ifp)
537 {
538 assert (circuit != NULL);
539 assert (ifp != NULL);
540 assert (circuit->interface == ifp);
541 assert (ifp->info == circuit);
542 circuit->interface = NULL;
543 ifp->info = NULL;
544 }
545
546 static void
547 isis_circuit_update_all_srmflags (struct isis_circuit *circuit, int is_set)
548 {
549 struct isis_area *area;
550 struct isis_lsp *lsp;
551 dnode_t *dnode, *dnode_next;
552 int level;
553
554 assert (circuit);
555 area = circuit->area;
556 assert (area);
557 for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++)
558 {
559 if (level & circuit->is_type)
560 {
561 if (area->lspdb[level - 1] &&
562 dict_count (area->lspdb[level - 1]) > 0)
563 {
564 for (dnode = dict_first (area->lspdb[level - 1]);
565 dnode != NULL; dnode = dnode_next)
566 {
567 dnode_next = dict_next (area->lspdb[level - 1], dnode);
568 lsp = dnode_get (dnode);
569 if (is_set)
570 {
571 ISIS_SET_FLAG (lsp->SRMflags, circuit);
572 }
573 else
574 {
575 ISIS_CLEAR_FLAG (lsp->SRMflags, circuit);
576 }
577 }
578 }
579 }
580 }
581 }
582
583 size_t
584 isis_circuit_pdu_size(struct isis_circuit *circuit)
585 {
586 return ISO_MTU(circuit);
587 }
588
589 void
590 isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream)
591 {
592 size_t stream_size = isis_circuit_pdu_size(circuit);
593
594 if (!*stream)
595 {
596 *stream = stream_new(stream_size);
597 }
598 else
599 {
600 if (STREAM_SIZE(*stream) != stream_size)
601 stream_resize(*stream, stream_size);
602 stream_reset(*stream);
603 }
604 }
605
606 void
607 isis_circuit_prepare (struct isis_circuit *circuit)
608 {
609 #ifdef GNU_LINUX
610 THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit,
611 circuit->fd);
612 #else
613 THREAD_TIMER_MSEC_ON (master, circuit->t_read, isis_receive, circuit,
614 listcount (circuit->area->circuit_list) * 100);
615 #endif
616 }
617
618 int
619 isis_circuit_up (struct isis_circuit *circuit)
620 {
621 int retv;
622
623 /* Set the flags for all the lsps of the circuit. */
624 isis_circuit_update_all_srmflags (circuit, 1);
625
626 if (circuit->state == C_STATE_UP)
627 return ISIS_OK;
628
629 if (circuit->is_passive)
630 return ISIS_OK;
631
632 if (circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit))
633 {
634 zlog_err("Interface MTU %zu on %s is too low to support area lsp mtu %u!",
635 isis_circuit_pdu_size(circuit), circuit->interface->name,
636 circuit->area->lsp_mtu);
637 isis_circuit_update_all_srmflags(circuit, 0);
638 return ISIS_ERROR;
639 }
640
641 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
642 {
643 /*
644 * Get the Hardware Address
645 */
646 if (circuit->interface->hw_addr_len != ETH_ALEN)
647 {
648 zlog_warn ("unsupported link layer");
649 }
650 else
651 {
652 memcpy (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN);
653 }
654 #ifdef EXTREME_DEGUG
655 zlog_debug ("isis_circuit_if_add: if_id %d, isomtu %d snpa %s",
656 circuit->interface->ifindex, ISO_MTU (circuit),
657 snpa_print (circuit->u.bc.snpa));
658 #endif /* EXTREME_DEBUG */
659
660 circuit->u.bc.adjdb[0] = list_new ();
661 circuit->u.bc.adjdb[1] = list_new ();
662
663 /*
664 * ISO 10589 - 8.4.1 Enabling of broadcast circuits
665 */
666
667 /* initilizing the hello sending threads
668 * for a broadcast IF
669 */
670
671 /* 8.4.1 a) commence sending of IIH PDUs */
672
673 if (circuit->is_type & IS_LEVEL_1)
674 {
675 thread_add_event (master, send_lan_l1_hello, circuit, 0);
676 circuit->u.bc.lan_neighs[0] = list_new ();
677 }
678
679 if (circuit->is_type & IS_LEVEL_2)
680 {
681 thread_add_event (master, send_lan_l2_hello, circuit, 0);
682 circuit->u.bc.lan_neighs[1] = list_new ();
683 }
684
685 /* 8.4.1 b) FIXME: solicit ES - 8.4.6 */
686 /* 8.4.1 c) FIXME: listen for ESH PDUs */
687
688 /* 8.4.1 d) */
689 /* dr election will commence in... */
690 if (circuit->is_type & IS_LEVEL_1)
691 THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1,
692 circuit, 2 * circuit->hello_interval[0]);
693 if (circuit->is_type & IS_LEVEL_2)
694 THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2,
695 circuit, 2 * circuit->hello_interval[1]);
696 }
697 else
698 {
699 /* initializing the hello send threads
700 * for a ptp IF
701 */
702 circuit->u.p2p.neighbor = NULL;
703 thread_add_event (master, send_p2p_hello, circuit, 0);
704 }
705
706 /* initializing PSNP timers */
707 if (circuit->is_type & IS_LEVEL_1)
708 THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit,
709 isis_jitter (circuit->psnp_interval[0], PSNP_JITTER));
710
711 if (circuit->is_type & IS_LEVEL_2)
712 THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit,
713 isis_jitter (circuit->psnp_interval[1], PSNP_JITTER));
714
715 /* unified init for circuits; ignore warnings below this level */
716 retv = isis_sock_init (circuit);
717 if (retv != ISIS_OK)
718 {
719 isis_circuit_down (circuit);
720 return retv;
721 }
722
723 /* initialize the circuit streams after opening connection */
724 isis_circuit_stream(circuit, &circuit->rcv_stream);
725 isis_circuit_stream(circuit, &circuit->snd_stream);
726
727 isis_circuit_prepare (circuit);
728
729 circuit->lsp_queue = list_new ();
730 circuit->lsp_queue_last_cleared = time (NULL);
731
732 return ISIS_OK;
733 }
734
735 void
736 isis_circuit_down (struct isis_circuit *circuit)
737 {
738 if (circuit->state != C_STATE_UP)
739 return;
740
741 /* Clear the flags for all the lsps of the circuit. */
742 isis_circuit_update_all_srmflags (circuit, 0);
743
744 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
745 {
746 /* destroy neighbour lists */
747 if (circuit->u.bc.lan_neighs[0])
748 {
749 list_delete (circuit->u.bc.lan_neighs[0]);
750 circuit->u.bc.lan_neighs[0] = NULL;
751 }
752 if (circuit->u.bc.lan_neighs[1])
753 {
754 list_delete (circuit->u.bc.lan_neighs[1]);
755 circuit->u.bc.lan_neighs[1] = NULL;
756 }
757 /* destroy adjacency databases */
758 if (circuit->u.bc.adjdb[0])
759 {
760 circuit->u.bc.adjdb[0]->del = isis_delete_adj;
761 list_delete (circuit->u.bc.adjdb[0]);
762 circuit->u.bc.adjdb[0] = NULL;
763 }
764 if (circuit->u.bc.adjdb[1])
765 {
766 circuit->u.bc.adjdb[1]->del = isis_delete_adj;
767 list_delete (circuit->u.bc.adjdb[1]);
768 circuit->u.bc.adjdb[1] = NULL;
769 }
770 if (circuit->u.bc.is_dr[0])
771 {
772 isis_dr_resign (circuit, 1);
773 circuit->u.bc.is_dr[0] = 0;
774 }
775 memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1);
776 if (circuit->u.bc.is_dr[1])
777 {
778 isis_dr_resign (circuit, 2);
779 circuit->u.bc.is_dr[1] = 0;
780 }
781 memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
782 memset (circuit->u.bc.snpa, 0, ETH_ALEN);
783
784 THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[0]);
785 THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[1]);
786 THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]);
787 THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]);
788 THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[0]);
789 THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[1]);
790 circuit->lsp_regenerate_pending[0] = 0;
791 circuit->lsp_regenerate_pending[1] = 0;
792 }
793 else if (circuit->circ_type == CIRCUIT_T_P2P)
794 {
795 isis_delete_adj (circuit->u.p2p.neighbor);
796 circuit->u.p2p.neighbor = NULL;
797 THREAD_TIMER_OFF (circuit->u.p2p.t_send_p2p_hello);
798 }
799
800 /* Cancel all active threads */
801 THREAD_TIMER_OFF (circuit->t_send_csnp[0]);
802 THREAD_TIMER_OFF (circuit->t_send_csnp[1]);
803 THREAD_TIMER_OFF (circuit->t_send_psnp[0]);
804 THREAD_TIMER_OFF (circuit->t_send_psnp[1]);
805 THREAD_OFF (circuit->t_read);
806
807 if (circuit->lsp_queue)
808 {
809 circuit->lsp_queue->del = NULL;
810 list_delete (circuit->lsp_queue);
811 circuit->lsp_queue = NULL;
812 }
813
814 /* send one gratuitous hello to spead up convergence */
815 if (circuit->is_type & IS_LEVEL_1)
816 send_hello (circuit, IS_LEVEL_1);
817 if (circuit->is_type & IS_LEVEL_2)
818 send_hello (circuit, IS_LEVEL_2);
819
820 circuit->upadjcount[0] = 0;
821 circuit->upadjcount[1] = 0;
822
823 /* close the socket */
824 if (circuit->fd)
825 {
826 close (circuit->fd);
827 circuit->fd = 0;
828 }
829
830 if (circuit->rcv_stream != NULL)
831 {
832 stream_free (circuit->rcv_stream);
833 circuit->rcv_stream = NULL;
834 }
835
836 if (circuit->snd_stream != NULL)
837 {
838 stream_free (circuit->snd_stream);
839 circuit->snd_stream = NULL;
840 }
841
842 thread_cancel_event (master, circuit);
843
844 return;
845 }
846
847 void
848 circuit_update_nlpids (struct isis_circuit *circuit)
849 {
850 circuit->nlpids.count = 0;
851
852 if (circuit->ip_router)
853 {
854 circuit->nlpids.nlpids[0] = NLPID_IP;
855 circuit->nlpids.count++;
856 }
857 if (circuit->ipv6_router)
858 {
859 circuit->nlpids.nlpids[circuit->nlpids.count] = NLPID_IPV6;
860 circuit->nlpids.count++;
861 }
862 return;
863 }
864
865 void
866 isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty,
867 char detail)
868 {
869 if (detail == ISIS_UI_LEVEL_BRIEF)
870 {
871 vty_out (vty, " %-12s", circuit->interface->name);
872 vty_out (vty, "0x%-7x", circuit->circuit_id);
873 vty_out (vty, "%-9s", circuit_state2string (circuit->state));
874 vty_out (vty, "%-9s", circuit_type2string (circuit->circ_type));
875 vty_out (vty, "%-9s", circuit_t2string (circuit->is_type));
876 vty_out (vty, "%s", VTY_NEWLINE);
877 }
878
879 if (detail == ISIS_UI_LEVEL_DETAIL)
880 {
881 struct listnode *node;
882 struct prefix *ip_addr;
883 char buf[BUFSIZ];
884
885 vty_out (vty, " Interface: %s", circuit->interface->name);
886 vty_out (vty, ", State: %s", circuit_state2string (circuit->state));
887 if (circuit->is_passive)
888 vty_out (vty, ", Passive");
889 else
890 vty_out (vty, ", Active");
891 vty_out (vty, ", Circuit Id: 0x%x", circuit->circuit_id);
892 vty_out (vty, "%s", VTY_NEWLINE);
893 vty_out (vty, " Type: %s", circuit_type2string (circuit->circ_type));
894 vty_out (vty, ", Level: %s", circuit_t2string (circuit->is_type));
895 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
896 vty_out (vty, ", SNPA: %-10s", snpa_print (circuit->u.bc.snpa));
897 vty_out (vty, "%s", VTY_NEWLINE);
898 if (circuit->is_type & IS_LEVEL_1)
899 {
900 vty_out (vty, " Level-1 Information:%s", VTY_NEWLINE);
901 if (circuit->area->newmetric)
902 vty_out (vty, " Metric: %d", circuit->te_metric[0]);
903 else
904 vty_out (vty, " Metric: %d",
905 circuit->metric[0]);
906 if (!circuit->is_passive)
907 {
908 vty_out (vty, ", Active neighbors: %u%s",
909 circuit->upadjcount[0], VTY_NEWLINE);
910 vty_out (vty, " Hello interval: %u, "
911 "Holddown count: %u %s%s",
912 circuit->hello_interval[0],
913 circuit->hello_multiplier[0],
914 (circuit->pad_hellos ? "(pad)" : "(no-pad)"),
915 VTY_NEWLINE);
916 vty_out (vty, " CNSP interval: %u, "
917 "PSNP interval: %u%s",
918 circuit->csnp_interval[0],
919 circuit->psnp_interval[0], VTY_NEWLINE);
920 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
921 vty_out (vty, " LAN Priority: %u, %s%s",
922 circuit->priority[0],
923 (circuit->u.bc.is_dr[0] ? \
924 "is DIS" : "is not DIS"), VTY_NEWLINE);
925 }
926 else
927 {
928 vty_out (vty, "%s", VTY_NEWLINE);
929 }
930 }
931 if (circuit->is_type & IS_LEVEL_2)
932 {
933 vty_out (vty, " Level-2 Information:%s", VTY_NEWLINE);
934 if (circuit->area->newmetric)
935 vty_out (vty, " Metric: %d", circuit->te_metric[1]);
936 else
937 vty_out (vty, " Metric: %d",
938 circuit->metric[1]);
939 if (!circuit->is_passive)
940 {
941 vty_out (vty, ", Active neighbors: %u%s",
942 circuit->upadjcount[1], VTY_NEWLINE);
943 vty_out (vty, " Hello interval: %u, "
944 "Holddown count: %u %s%s",
945 circuit->hello_interval[1],
946 circuit->hello_multiplier[1],
947 (circuit->pad_hellos ? "(pad)" : "(no-pad)"),
948 VTY_NEWLINE);
949 vty_out (vty, " CNSP interval: %u, "
950 "PSNP interval: %u%s",
951 circuit->csnp_interval[1],
952 circuit->psnp_interval[1], VTY_NEWLINE);
953 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
954 vty_out (vty, " LAN Priority: %u, %s%s",
955 circuit->priority[1],
956 (circuit->u.bc.is_dr[1] ? \
957 "is DIS" : "is not DIS"), VTY_NEWLINE);
958 }
959 else
960 {
961 vty_out (vty, "%s", VTY_NEWLINE);
962 }
963 }
964 if (circuit->ip_addrs && listcount (circuit->ip_addrs) > 0)
965 {
966 vty_out (vty, " IP Prefix(es):%s", VTY_NEWLINE);
967 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip_addr))
968 {
969 prefix2str (ip_addr, buf, sizeof (buf)),
970 vty_out (vty, " %s%s", buf, VTY_NEWLINE);
971 }
972 }
973 if (circuit->ipv6_link && listcount(circuit->ipv6_link) > 0)
974 {
975 vty_out(vty, " IPv6 Link-Locals:%s", VTY_NEWLINE);
976 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ip_addr))
977 {
978 prefix2str(ip_addr, (char*)buf, BUFSIZ),
979 vty_out(vty, " %s%s", buf, VTY_NEWLINE);
980 }
981 }
982 if (circuit->ipv6_non_link && listcount(circuit->ipv6_non_link) > 0)
983 {
984 vty_out(vty, " IPv6 Prefixes:%s", VTY_NEWLINE);
985 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ip_addr))
986 {
987 prefix2str(ip_addr, (char*)buf, BUFSIZ),
988 vty_out(vty, " %s%s", buf, VTY_NEWLINE);
989 }
990 }
991
992 vty_out (vty, "%s", VTY_NEWLINE);
993 }
994 return;
995 }
996
997 int
998 isis_interface_config_write (struct vty *vty)
999 {
1000 int write = 0;
1001 struct listnode *node, *node2;
1002 struct interface *ifp;
1003 struct isis_area *area;
1004 struct isis_circuit *circuit;
1005 int i;
1006
1007 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
1008 {
1009 if (ifp->ifindex == IFINDEX_DELETED)
1010 continue;
1011
1012 /* IF name */
1013 vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE);
1014 write++;
1015 /* IF desc */
1016 if (ifp->desc)
1017 {
1018 vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE);
1019 write++;
1020 }
1021 /* ISIS Circuit */
1022 for (ALL_LIST_ELEMENTS_RO (isis->area_list, node2, area))
1023 {
1024 circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
1025 if (circuit == NULL)
1026 continue;
1027 if (circuit->ip_router)
1028 {
1029 vty_out (vty, " ip router isis %s%s", area->area_tag,
1030 VTY_NEWLINE);
1031 write++;
1032 }
1033 if (circuit->is_passive)
1034 {
1035 vty_out (vty, " isis passive%s", VTY_NEWLINE);
1036 write++;
1037 }
1038 if (circuit->circ_type_config == CIRCUIT_T_P2P)
1039 {
1040 vty_out (vty, " isis network point-to-point%s", VTY_NEWLINE);
1041 write++;
1042 }
1043 if (circuit->ipv6_router)
1044 {
1045 vty_out (vty, " ipv6 router isis %s%s", area->area_tag,
1046 VTY_NEWLINE);
1047 write++;
1048 }
1049
1050 /* ISIS - circuit type */
1051 if (circuit->is_type == IS_LEVEL_1)
1052 {
1053 vty_out (vty, " isis circuit-type level-1%s", VTY_NEWLINE);
1054 write++;
1055 }
1056 else
1057 {
1058 if (circuit->is_type == IS_LEVEL_2)
1059 {
1060 vty_out (vty, " isis circuit-type level-2-only%s",
1061 VTY_NEWLINE);
1062 write++;
1063 }
1064 }
1065
1066 /* ISIS - CSNP interval */
1067 if (circuit->csnp_interval[0] == circuit->csnp_interval[1])
1068 {
1069 if (circuit->csnp_interval[0] != DEFAULT_CSNP_INTERVAL)
1070 {
1071 vty_out (vty, " isis csnp-interval %d%s",
1072 circuit->csnp_interval[0], VTY_NEWLINE);
1073 write++;
1074 }
1075 }
1076 else
1077 {
1078 for (i = 0; i < 2; i++)
1079 {
1080 if (circuit->csnp_interval[i] != DEFAULT_CSNP_INTERVAL)
1081 {
1082 vty_out (vty, " isis csnp-interval %d level-%d%s",
1083 circuit->csnp_interval[i], i + 1, VTY_NEWLINE);
1084 write++;
1085 }
1086 }
1087 }
1088
1089 /* ISIS - PSNP interval */
1090 if (circuit->psnp_interval[0] == circuit->psnp_interval[1])
1091 {
1092 if (circuit->psnp_interval[0] != DEFAULT_PSNP_INTERVAL)
1093 {
1094 vty_out (vty, " isis psnp-interval %d%s",
1095 circuit->psnp_interval[0], VTY_NEWLINE);
1096 write++;
1097 }
1098 }
1099 else
1100 {
1101 for (i = 0; i < 2; i++)
1102 {
1103 if (circuit->psnp_interval[i] != DEFAULT_PSNP_INTERVAL)
1104 {
1105 vty_out (vty, " isis psnp-interval %d level-%d%s",
1106 circuit->psnp_interval[i], i + 1, VTY_NEWLINE);
1107 write++;
1108 }
1109 }
1110 }
1111
1112 /* ISIS - Hello padding - Defaults to true so only display if false */
1113 if (circuit->pad_hellos == 0)
1114 {
1115 vty_out (vty, " no isis hello padding%s", VTY_NEWLINE);
1116 write++;
1117 }
1118
1119 /* ISIS - Hello interval */
1120 if (circuit->hello_interval[0] == circuit->hello_interval[1])
1121 {
1122 if (circuit->hello_interval[0] != DEFAULT_HELLO_INTERVAL)
1123 {
1124 vty_out (vty, " isis hello-interval %d%s",
1125 circuit->hello_interval[0], VTY_NEWLINE);
1126 write++;
1127 }
1128 }
1129 else
1130 {
1131 for (i = 0; i < 2; i++)
1132 {
1133 if (circuit->hello_interval[i] != DEFAULT_HELLO_INTERVAL)
1134 {
1135 vty_out (vty, " isis hello-interval %d level-%d%s",
1136 circuit->hello_interval[i], i + 1, VTY_NEWLINE);
1137 write++;
1138 }
1139 }
1140 }
1141
1142 /* ISIS - Hello Multiplier */
1143 if (circuit->hello_multiplier[0] == circuit->hello_multiplier[1])
1144 {
1145 if (circuit->hello_multiplier[0] != DEFAULT_HELLO_MULTIPLIER)
1146 {
1147 vty_out (vty, " isis hello-multiplier %d%s",
1148 circuit->hello_multiplier[0], VTY_NEWLINE);
1149 write++;
1150 }
1151 }
1152 else
1153 {
1154 for (i = 0; i < 2; i++)
1155 {
1156 if (circuit->hello_multiplier[i] != DEFAULT_HELLO_MULTIPLIER)
1157 {
1158 vty_out (vty, " isis hello-multiplier %d level-%d%s",
1159 circuit->hello_multiplier[i], i + 1,
1160 VTY_NEWLINE);
1161 write++;
1162 }
1163 }
1164 }
1165
1166 /* ISIS - Priority */
1167 if (circuit->priority[0] == circuit->priority[1])
1168 {
1169 if (circuit->priority[0] != DEFAULT_PRIORITY)
1170 {
1171 vty_out (vty, " isis priority %d%s",
1172 circuit->priority[0], VTY_NEWLINE);
1173 write++;
1174 }
1175 }
1176 else
1177 {
1178 for (i = 0; i < 2; i++)
1179 {
1180 if (circuit->priority[i] != DEFAULT_PRIORITY)
1181 {
1182 vty_out (vty, " isis priority %d level-%d%s",
1183 circuit->priority[i], i + 1, VTY_NEWLINE);
1184 write++;
1185 }
1186 }
1187 }
1188
1189 /* ISIS - Metric */
1190 if (circuit->te_metric[0] == circuit->te_metric[1])
1191 {
1192 if (circuit->te_metric[0] != DEFAULT_CIRCUIT_METRIC)
1193 {
1194 vty_out (vty, " isis metric %d%s", circuit->te_metric[0],
1195 VTY_NEWLINE);
1196 write++;
1197 }
1198 }
1199 else
1200 {
1201 for (i = 0; i < 2; i++)
1202 {
1203 if (circuit->te_metric[i] != DEFAULT_CIRCUIT_METRIC)
1204 {
1205 vty_out (vty, " isis metric %d level-%d%s",
1206 circuit->te_metric[i], i + 1, VTY_NEWLINE);
1207 write++;
1208 }
1209 }
1210 }
1211 if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
1212 {
1213 vty_out (vty, " isis password md5 %s%s", circuit->passwd.passwd,
1214 VTY_NEWLINE);
1215 write++;
1216 }
1217 else if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT)
1218 {
1219 vty_out (vty, " isis password clear %s%s", circuit->passwd.passwd,
1220 VTY_NEWLINE);
1221 write++;
1222 }
1223 write += circuit_write_mt_settings(circuit, vty);
1224 }
1225 vty_out (vty, "!%s", VTY_NEWLINE);
1226 }
1227
1228 return write;
1229 }
1230
1231 struct isis_circuit *
1232 isis_circuit_create (struct isis_area *area, struct interface *ifp)
1233 {
1234 struct isis_circuit *circuit = circuit_scan_by_ifp (ifp);
1235 if (circuit && circuit->area)
1236 return NULL;
1237 circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area);
1238 if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP)
1239 return circuit;
1240 isis_circuit_if_bind (circuit, ifp);
1241 return circuit;
1242 }
1243
1244 void
1245 isis_circuit_af_set (struct isis_circuit *circuit, bool ip_router, bool ipv6_router)
1246 {
1247 struct isis_area *area = circuit->area;
1248 bool change = circuit->ip_router != ip_router || circuit->ipv6_router != ipv6_router;
1249 bool was_enabled = !!circuit->area;
1250
1251 area->ip_circuits += ip_router - circuit->ip_router;
1252 area->ipv6_circuits += ipv6_router - circuit->ipv6_router;
1253 circuit->ip_router = ip_router;
1254 circuit->ipv6_router = ipv6_router;
1255
1256 if (!change)
1257 return;
1258
1259 circuit_update_nlpids (circuit);
1260
1261 if (!ip_router && !ipv6_router)
1262 isis_csm_state_change (ISIS_DISABLE, circuit, area);
1263 else if (!was_enabled)
1264 isis_csm_state_change (ISIS_ENABLE, circuit, area);
1265 else
1266 lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
1267 }
1268
1269 int
1270 isis_circuit_passive_set (struct isis_circuit *circuit, bool passive)
1271 {
1272 if (circuit->is_passive == passive)
1273 return 0;
1274
1275 if (if_is_loopback (circuit->interface) && !passive)
1276 return -1;
1277
1278 if (circuit->state != C_STATE_UP)
1279 {
1280 circuit->is_passive = passive;
1281 }
1282 else
1283 {
1284 struct isis_area *area = circuit->area;
1285 isis_csm_state_change (ISIS_DISABLE, circuit, area);
1286 circuit->is_passive = passive;
1287 isis_csm_state_change (ISIS_ENABLE, circuit, area);
1288 }
1289
1290 return 0;
1291 }
1292
1293 int
1294 isis_circuit_metric_set (struct isis_circuit *circuit, int level, int metric)
1295 {
1296 assert (level == IS_LEVEL_1 || level == IS_LEVEL_2);
1297 if (metric > MAX_WIDE_LINK_METRIC)
1298 return -1;
1299 if (circuit->area && circuit->area->oldmetric
1300 && metric > MAX_NARROW_LINK_METRIC)
1301 return -1;
1302
1303 circuit->te_metric[level - 1] = metric;
1304 circuit->metric[level - 1] = metric;
1305
1306 if (circuit->area)
1307 lsp_regenerate_schedule (circuit->area, level, 0);
1308 return 0;
1309 }
1310
1311 int
1312 isis_circuit_passwd_unset (struct isis_circuit *circuit)
1313 {
1314 memset(&circuit->passwd, 0, sizeof(circuit->passwd));
1315 return 0;
1316 }
1317
1318 static int
1319 isis_circuit_passwd_set (struct isis_circuit *circuit, u_char passwd_type, const char *passwd)
1320 {
1321 int len;
1322
1323 if (!passwd)
1324 return -1;
1325
1326 len = strlen(passwd);
1327 if (len > 254)
1328 return -1;
1329
1330 circuit->passwd.len = len;
1331 strncpy((char *)circuit->passwd.passwd, passwd, 255);
1332 circuit->passwd.type = passwd_type;
1333 return 0;
1334 }
1335
1336 int
1337 isis_circuit_passwd_cleartext_set (struct isis_circuit *circuit, const char *passwd)
1338 {
1339 return isis_circuit_passwd_set (circuit, ISIS_PASSWD_TYPE_CLEARTXT, passwd);
1340 }
1341
1342 int
1343 isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *passwd)
1344 {
1345 return isis_circuit_passwd_set (circuit, ISIS_PASSWD_TYPE_HMAC_MD5, passwd);
1346 }
1347 struct cmd_node interface_node = {
1348 INTERFACE_NODE,
1349 "%s(config-if)# ",
1350 1,
1351 };
1352
1353 int
1354 isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type)
1355 {
1356 /* Changing the network type to/of loopback or unknown interfaces
1357 * is not supported. */
1358 if (circ_type == CIRCUIT_T_UNKNOWN
1359 || circ_type == CIRCUIT_T_LOOPBACK
1360 || circuit->circ_type == CIRCUIT_T_LOOPBACK)
1361 {
1362 if (circuit->circ_type != circ_type)
1363 return -1;
1364 else
1365 return 0;
1366 }
1367
1368 if (circuit->circ_type == circ_type)
1369 return 0;
1370
1371 if (circuit->state != C_STATE_UP)
1372 {
1373 circuit->circ_type = circ_type;
1374 circuit->circ_type_config = circ_type;
1375 }
1376 else
1377 {
1378 struct isis_area *area = circuit->area;
1379 if (circ_type == CIRCUIT_T_BROADCAST
1380 && !if_is_broadcast(circuit->interface))
1381 return -1;
1382
1383 isis_csm_state_change(ISIS_DISABLE, circuit, area);
1384 circuit->circ_type = circ_type;
1385 circuit->circ_type_config = circ_type;
1386 isis_csm_state_change(ISIS_ENABLE, circuit, area);
1387 }
1388 return 0;
1389 }
1390
1391 int
1392 isis_circuit_mt_enabled_set (struct isis_circuit *circuit, uint16_t mtid,
1393 bool enabled)
1394 {
1395 struct isis_circuit_mt_setting *setting;
1396
1397 setting = circuit_get_mt_setting(circuit, mtid);
1398 if (setting->enabled != enabled)
1399 {
1400 setting->enabled = enabled;
1401 lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
1402 }
1403
1404 return CMD_SUCCESS;
1405 }
1406
1407 int
1408 isis_if_new_hook (struct interface *ifp)
1409 {
1410 return 0;
1411 }
1412
1413 int
1414 isis_if_delete_hook (struct interface *ifp)
1415 {
1416 struct isis_circuit *circuit;
1417 /* Clean up the circuit data */
1418 if (ifp && ifp->info)
1419 {
1420 circuit = ifp->info;
1421 isis_csm_state_change (IF_DOWN_FROM_Z, circuit, circuit->area);
1422 isis_csm_state_change (ISIS_DISABLE, circuit, circuit->area);
1423 }
1424
1425 return 0;
1426 }
1427
1428 void
1429 isis_circuit_init ()
1430 {
1431 /* Initialize Zebra interface data structure */
1432 if_add_hook (IF_NEW_HOOK, isis_if_new_hook);
1433 if_add_hook (IF_DELETE_HOOK, isis_if_delete_hook);
1434
1435 /* Install interface node */
1436 install_node (&interface_node, isis_interface_config_write);
1437 if_cmd_init ();
1438
1439 isis_vty_init ();
1440 }