]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_circuit.c
Merge remote-tracking branch 'origin/stable/2.0'
[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 #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_add_read(master, isis_receive, circuit, circuit->fd,
611 &circuit->t_read);
612 #else
613 thread_add_timer_msec(master, isis_receive, circuit,
614 listcount(circuit->area->circuit_list) * 100,
615 &circuit->t_read);
616 #endif
617 }
618
619 int
620 isis_circuit_up (struct isis_circuit *circuit)
621 {
622 int retv;
623
624 /* Set the flags for all the lsps of the circuit. */
625 isis_circuit_update_all_srmflags (circuit, 1);
626
627 if (circuit->state == C_STATE_UP)
628 return ISIS_OK;
629
630 if (circuit->is_passive)
631 return ISIS_OK;
632
633 if (circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit))
634 {
635 zlog_err("Interface MTU %zu on %s is too low to support area lsp mtu %u!",
636 isis_circuit_pdu_size(circuit), circuit->interface->name,
637 circuit->area->lsp_mtu);
638 isis_circuit_update_all_srmflags(circuit, 0);
639 return ISIS_ERROR;
640 }
641
642 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
643 {
644 /*
645 * Get the Hardware Address
646 */
647 if (circuit->interface->hw_addr_len != ETH_ALEN)
648 {
649 zlog_warn ("unsupported link layer");
650 }
651 else
652 {
653 memcpy (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN);
654 }
655 #ifdef EXTREME_DEGUG
656 zlog_debug ("isis_circuit_if_add: if_id %d, isomtu %d snpa %s",
657 circuit->interface->ifindex, ISO_MTU (circuit),
658 snpa_print (circuit->u.bc.snpa));
659 #endif /* EXTREME_DEBUG */
660
661 circuit->u.bc.adjdb[0] = list_new ();
662 circuit->u.bc.adjdb[1] = list_new ();
663
664 /*
665 * ISO 10589 - 8.4.1 Enabling of broadcast circuits
666 */
667
668 /* initilizing the hello sending threads
669 * for a broadcast IF
670 */
671
672 /* 8.4.1 a) commence sending of IIH PDUs */
673
674 if (circuit->is_type & IS_LEVEL_1)
675 {
676 thread_add_event(master, send_lan_l1_hello, circuit, 0, NULL);
677 circuit->u.bc.lan_neighs[0] = list_new ();
678 }
679
680 if (circuit->is_type & IS_LEVEL_2)
681 {
682 thread_add_event(master, send_lan_l2_hello, circuit, 0, NULL);
683 circuit->u.bc.lan_neighs[1] = list_new ();
684 }
685
686 /* 8.4.1 b) FIXME: solicit ES - 8.4.6 */
687 /* 8.4.1 c) FIXME: listen for ESH PDUs */
688
689 /* 8.4.1 d) */
690 /* dr election will commence in... */
691 if (circuit->is_type & IS_LEVEL_1)
692 thread_add_timer(master, isis_run_dr_l1, circuit,
693 2 * circuit->hello_interval[0],
694 &circuit->u.bc.t_run_dr[0]);
695 if (circuit->is_type & IS_LEVEL_2)
696 thread_add_timer(master, isis_run_dr_l2, circuit,
697 2 * circuit->hello_interval[1],
698 &circuit->u.bc.t_run_dr[1]);
699 }
700 else
701 {
702 /* initializing the hello send threads
703 * for a ptp IF
704 */
705 circuit->u.p2p.neighbor = NULL;
706 thread_add_event(master, send_p2p_hello, circuit, 0, NULL);
707 }
708
709 /* initializing PSNP timers */
710 if (circuit->is_type & IS_LEVEL_1)
711 thread_add_timer(master, send_l1_psnp, circuit,
712 isis_jitter(circuit->psnp_interval[0], PSNP_JITTER),
713 &circuit->t_send_psnp[0]);
714
715 if (circuit->is_type & IS_LEVEL_2)
716 thread_add_timer(master, send_l2_psnp, circuit,
717 isis_jitter(circuit->psnp_interval[1], PSNP_JITTER),
718 &circuit->t_send_psnp[1]);
719
720 /* unified init for circuits; ignore warnings below this level */
721 retv = isis_sock_init (circuit);
722 if (retv != ISIS_OK)
723 {
724 isis_circuit_down (circuit);
725 return retv;
726 }
727
728 /* initialize the circuit streams after opening connection */
729 isis_circuit_stream(circuit, &circuit->rcv_stream);
730 isis_circuit_stream(circuit, &circuit->snd_stream);
731
732 isis_circuit_prepare (circuit);
733
734 circuit->lsp_queue = list_new ();
735 circuit->lsp_queue_last_cleared = time (NULL);
736
737 return ISIS_OK;
738 }
739
740 void
741 isis_circuit_down (struct isis_circuit *circuit)
742 {
743 if (circuit->state != C_STATE_UP)
744 return;
745
746 /* Clear the flags for all the lsps of the circuit. */
747 isis_circuit_update_all_srmflags (circuit, 0);
748
749 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
750 {
751 /* destroy neighbour lists */
752 if (circuit->u.bc.lan_neighs[0])
753 {
754 list_delete (circuit->u.bc.lan_neighs[0]);
755 circuit->u.bc.lan_neighs[0] = NULL;
756 }
757 if (circuit->u.bc.lan_neighs[1])
758 {
759 list_delete (circuit->u.bc.lan_neighs[1]);
760 circuit->u.bc.lan_neighs[1] = NULL;
761 }
762 /* destroy adjacency databases */
763 if (circuit->u.bc.adjdb[0])
764 {
765 circuit->u.bc.adjdb[0]->del = isis_delete_adj;
766 list_delete (circuit->u.bc.adjdb[0]);
767 circuit->u.bc.adjdb[0] = NULL;
768 }
769 if (circuit->u.bc.adjdb[1])
770 {
771 circuit->u.bc.adjdb[1]->del = isis_delete_adj;
772 list_delete (circuit->u.bc.adjdb[1]);
773 circuit->u.bc.adjdb[1] = NULL;
774 }
775 if (circuit->u.bc.is_dr[0])
776 {
777 isis_dr_resign (circuit, 1);
778 circuit->u.bc.is_dr[0] = 0;
779 }
780 memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1);
781 if (circuit->u.bc.is_dr[1])
782 {
783 isis_dr_resign (circuit, 2);
784 circuit->u.bc.is_dr[1] = 0;
785 }
786 memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1);
787 memset (circuit->u.bc.snpa, 0, ETH_ALEN);
788
789 THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[0]);
790 THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[1]);
791 THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]);
792 THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]);
793 THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[0]);
794 THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[1]);
795 circuit->lsp_regenerate_pending[0] = 0;
796 circuit->lsp_regenerate_pending[1] = 0;
797 }
798 else if (circuit->circ_type == CIRCUIT_T_P2P)
799 {
800 isis_delete_adj (circuit->u.p2p.neighbor);
801 circuit->u.p2p.neighbor = NULL;
802 THREAD_TIMER_OFF (circuit->u.p2p.t_send_p2p_hello);
803 }
804
805 /* Cancel all active threads */
806 THREAD_TIMER_OFF (circuit->t_send_csnp[0]);
807 THREAD_TIMER_OFF (circuit->t_send_csnp[1]);
808 THREAD_TIMER_OFF (circuit->t_send_psnp[0]);
809 THREAD_TIMER_OFF (circuit->t_send_psnp[1]);
810 THREAD_OFF (circuit->t_read);
811
812 if (circuit->lsp_queue)
813 {
814 circuit->lsp_queue->del = NULL;
815 list_delete (circuit->lsp_queue);
816 circuit->lsp_queue = NULL;
817 }
818
819 /* send one gratuitous hello to spead up convergence */
820 if (circuit->is_type & IS_LEVEL_1)
821 send_hello (circuit, IS_LEVEL_1);
822 if (circuit->is_type & IS_LEVEL_2)
823 send_hello (circuit, IS_LEVEL_2);
824
825 circuit->upadjcount[0] = 0;
826 circuit->upadjcount[1] = 0;
827
828 /* close the socket */
829 if (circuit->fd)
830 {
831 close (circuit->fd);
832 circuit->fd = 0;
833 }
834
835 if (circuit->rcv_stream != NULL)
836 {
837 stream_free (circuit->rcv_stream);
838 circuit->rcv_stream = NULL;
839 }
840
841 if (circuit->snd_stream != NULL)
842 {
843 stream_free (circuit->snd_stream);
844 circuit->snd_stream = NULL;
845 }
846
847 thread_cancel_event (master, circuit);
848
849 return;
850 }
851
852 void
853 circuit_update_nlpids (struct isis_circuit *circuit)
854 {
855 circuit->nlpids.count = 0;
856
857 if (circuit->ip_router)
858 {
859 circuit->nlpids.nlpids[0] = NLPID_IP;
860 circuit->nlpids.count++;
861 }
862 if (circuit->ipv6_router)
863 {
864 circuit->nlpids.nlpids[circuit->nlpids.count] = NLPID_IPV6;
865 circuit->nlpids.count++;
866 }
867 return;
868 }
869
870 void
871 isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty,
872 char detail)
873 {
874 if (detail == ISIS_UI_LEVEL_BRIEF)
875 {
876 vty_out (vty, " %-12s", circuit->interface->name);
877 vty_out (vty, "0x%-7x", circuit->circuit_id);
878 vty_out (vty, "%-9s", circuit_state2string (circuit->state));
879 vty_out (vty, "%-9s", circuit_type2string (circuit->circ_type));
880 vty_out (vty, "%-9s", circuit_t2string (circuit->is_type));
881 vty_out (vty, "%s", VTY_NEWLINE);
882 }
883
884 if (detail == ISIS_UI_LEVEL_DETAIL)
885 {
886 struct listnode *node;
887 struct prefix *ip_addr;
888 char buf[BUFSIZ];
889
890 vty_out (vty, " Interface: %s", circuit->interface->name);
891 vty_out (vty, ", State: %s", circuit_state2string (circuit->state));
892 if (circuit->is_passive)
893 vty_out (vty, ", Passive");
894 else
895 vty_out (vty, ", Active");
896 vty_out (vty, ", Circuit Id: 0x%x", circuit->circuit_id);
897 vty_out (vty, "%s", VTY_NEWLINE);
898 vty_out (vty, " Type: %s", circuit_type2string (circuit->circ_type));
899 vty_out (vty, ", Level: %s", circuit_t2string (circuit->is_type));
900 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
901 vty_out (vty, ", SNPA: %-10s", snpa_print (circuit->u.bc.snpa));
902 vty_out (vty, "%s", VTY_NEWLINE);
903 if (circuit->is_type & IS_LEVEL_1)
904 {
905 vty_out (vty, " Level-1 Information:%s", VTY_NEWLINE);
906 if (circuit->area->newmetric)
907 vty_out (vty, " Metric: %d", circuit->te_metric[0]);
908 else
909 vty_out (vty, " Metric: %d",
910 circuit->metric[0]);
911 if (!circuit->is_passive)
912 {
913 vty_out (vty, ", Active neighbors: %u%s",
914 circuit->upadjcount[0], VTY_NEWLINE);
915 vty_out (vty, " Hello interval: %u, "
916 "Holddown count: %u %s%s",
917 circuit->hello_interval[0],
918 circuit->hello_multiplier[0],
919 (circuit->pad_hellos ? "(pad)" : "(no-pad)"),
920 VTY_NEWLINE);
921 vty_out (vty, " CNSP interval: %u, "
922 "PSNP interval: %u%s",
923 circuit->csnp_interval[0],
924 circuit->psnp_interval[0], VTY_NEWLINE);
925 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
926 vty_out (vty, " LAN Priority: %u, %s%s",
927 circuit->priority[0],
928 (circuit->u.bc.is_dr[0] ? \
929 "is DIS" : "is not DIS"), VTY_NEWLINE);
930 }
931 else
932 {
933 vty_out (vty, "%s", VTY_NEWLINE);
934 }
935 }
936 if (circuit->is_type & IS_LEVEL_2)
937 {
938 vty_out (vty, " Level-2 Information:%s", VTY_NEWLINE);
939 if (circuit->area->newmetric)
940 vty_out (vty, " Metric: %d", circuit->te_metric[1]);
941 else
942 vty_out (vty, " Metric: %d",
943 circuit->metric[1]);
944 if (!circuit->is_passive)
945 {
946 vty_out (vty, ", Active neighbors: %u%s",
947 circuit->upadjcount[1], VTY_NEWLINE);
948 vty_out (vty, " Hello interval: %u, "
949 "Holddown count: %u %s%s",
950 circuit->hello_interval[1],
951 circuit->hello_multiplier[1],
952 (circuit->pad_hellos ? "(pad)" : "(no-pad)"),
953 VTY_NEWLINE);
954 vty_out (vty, " CNSP interval: %u, "
955 "PSNP interval: %u%s",
956 circuit->csnp_interval[1],
957 circuit->psnp_interval[1], VTY_NEWLINE);
958 if (circuit->circ_type == CIRCUIT_T_BROADCAST)
959 vty_out (vty, " LAN Priority: %u, %s%s",
960 circuit->priority[1],
961 (circuit->u.bc.is_dr[1] ? \
962 "is DIS" : "is not DIS"), VTY_NEWLINE);
963 }
964 else
965 {
966 vty_out (vty, "%s", VTY_NEWLINE);
967 }
968 }
969 if (circuit->ip_addrs && listcount (circuit->ip_addrs) > 0)
970 {
971 vty_out (vty, " IP Prefix(es):%s", VTY_NEWLINE);
972 for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip_addr))
973 {
974 prefix2str (ip_addr, buf, sizeof (buf)),
975 vty_out (vty, " %s%s", buf, VTY_NEWLINE);
976 }
977 }
978 if (circuit->ipv6_link && listcount(circuit->ipv6_link) > 0)
979 {
980 vty_out(vty, " IPv6 Link-Locals:%s", VTY_NEWLINE);
981 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ip_addr))
982 {
983 prefix2str(ip_addr, (char*)buf, BUFSIZ),
984 vty_out(vty, " %s%s", buf, VTY_NEWLINE);
985 }
986 }
987 if (circuit->ipv6_non_link && listcount(circuit->ipv6_non_link) > 0)
988 {
989 vty_out(vty, " IPv6 Prefixes:%s", VTY_NEWLINE);
990 for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ip_addr))
991 {
992 prefix2str(ip_addr, (char*)buf, BUFSIZ),
993 vty_out(vty, " %s%s", buf, VTY_NEWLINE);
994 }
995 }
996
997 vty_out (vty, "%s", VTY_NEWLINE);
998 }
999 return;
1000 }
1001
1002 int
1003 isis_interface_config_write (struct vty *vty)
1004 {
1005 int write = 0;
1006 struct listnode *node, *node2;
1007 struct interface *ifp;
1008 struct isis_area *area;
1009 struct isis_circuit *circuit;
1010 int i;
1011
1012 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), node, ifp))
1013 {
1014 if (ifp->ifindex == IFINDEX_DELETED)
1015 continue;
1016
1017 /* IF name */
1018 vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE);
1019 write++;
1020 /* IF desc */
1021 if (ifp->desc)
1022 {
1023 vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE);
1024 write++;
1025 }
1026 /* ISIS Circuit */
1027 for (ALL_LIST_ELEMENTS_RO (isis->area_list, node2, area))
1028 {
1029 circuit = circuit_lookup_by_ifp (ifp, area->circuit_list);
1030 if (circuit == NULL)
1031 continue;
1032 if (circuit->ip_router)
1033 {
1034 vty_out (vty, " ip router isis %s%s", area->area_tag,
1035 VTY_NEWLINE);
1036 write++;
1037 }
1038 if (circuit->is_passive)
1039 {
1040 vty_out (vty, " isis passive%s", VTY_NEWLINE);
1041 write++;
1042 }
1043 if (circuit->circ_type_config == CIRCUIT_T_P2P)
1044 {
1045 vty_out (vty, " isis network point-to-point%s", VTY_NEWLINE);
1046 write++;
1047 }
1048 if (circuit->ipv6_router)
1049 {
1050 vty_out (vty, " ipv6 router isis %s%s", area->area_tag,
1051 VTY_NEWLINE);
1052 write++;
1053 }
1054
1055 /* ISIS - circuit type */
1056 if (circuit->is_type == IS_LEVEL_1)
1057 {
1058 vty_out (vty, " isis circuit-type level-1%s", VTY_NEWLINE);
1059 write++;
1060 }
1061 else
1062 {
1063 if (circuit->is_type == IS_LEVEL_2)
1064 {
1065 vty_out (vty, " isis circuit-type level-2-only%s",
1066 VTY_NEWLINE);
1067 write++;
1068 }
1069 }
1070
1071 /* ISIS - CSNP interval */
1072 if (circuit->csnp_interval[0] == circuit->csnp_interval[1])
1073 {
1074 if (circuit->csnp_interval[0] != DEFAULT_CSNP_INTERVAL)
1075 {
1076 vty_out (vty, " isis csnp-interval %d%s",
1077 circuit->csnp_interval[0], VTY_NEWLINE);
1078 write++;
1079 }
1080 }
1081 else
1082 {
1083 for (i = 0; i < 2; i++)
1084 {
1085 if (circuit->csnp_interval[i] != DEFAULT_CSNP_INTERVAL)
1086 {
1087 vty_out (vty, " isis csnp-interval %d level-%d%s",
1088 circuit->csnp_interval[i], i + 1, VTY_NEWLINE);
1089 write++;
1090 }
1091 }
1092 }
1093
1094 /* ISIS - PSNP interval */
1095 if (circuit->psnp_interval[0] == circuit->psnp_interval[1])
1096 {
1097 if (circuit->psnp_interval[0] != DEFAULT_PSNP_INTERVAL)
1098 {
1099 vty_out (vty, " isis psnp-interval %d%s",
1100 circuit->psnp_interval[0], VTY_NEWLINE);
1101 write++;
1102 }
1103 }
1104 else
1105 {
1106 for (i = 0; i < 2; i++)
1107 {
1108 if (circuit->psnp_interval[i] != DEFAULT_PSNP_INTERVAL)
1109 {
1110 vty_out (vty, " isis psnp-interval %d level-%d%s",
1111 circuit->psnp_interval[i], i + 1, VTY_NEWLINE);
1112 write++;
1113 }
1114 }
1115 }
1116
1117 /* ISIS - Hello padding - Defaults to true so only display if false */
1118 if (circuit->pad_hellos == 0)
1119 {
1120 vty_out (vty, " no isis hello padding%s", VTY_NEWLINE);
1121 write++;
1122 }
1123
1124 /* ISIS - Hello interval */
1125 if (circuit->hello_interval[0] == circuit->hello_interval[1])
1126 {
1127 if (circuit->hello_interval[0] != DEFAULT_HELLO_INTERVAL)
1128 {
1129 vty_out (vty, " isis hello-interval %d%s",
1130 circuit->hello_interval[0], VTY_NEWLINE);
1131 write++;
1132 }
1133 }
1134 else
1135 {
1136 for (i = 0; i < 2; i++)
1137 {
1138 if (circuit->hello_interval[i] != DEFAULT_HELLO_INTERVAL)
1139 {
1140 vty_out (vty, " isis hello-interval %d level-%d%s",
1141 circuit->hello_interval[i], i + 1, VTY_NEWLINE);
1142 write++;
1143 }
1144 }
1145 }
1146
1147 /* ISIS - Hello Multiplier */
1148 if (circuit->hello_multiplier[0] == circuit->hello_multiplier[1])
1149 {
1150 if (circuit->hello_multiplier[0] != DEFAULT_HELLO_MULTIPLIER)
1151 {
1152 vty_out (vty, " isis hello-multiplier %d%s",
1153 circuit->hello_multiplier[0], VTY_NEWLINE);
1154 write++;
1155 }
1156 }
1157 else
1158 {
1159 for (i = 0; i < 2; i++)
1160 {
1161 if (circuit->hello_multiplier[i] != DEFAULT_HELLO_MULTIPLIER)
1162 {
1163 vty_out (vty, " isis hello-multiplier %d level-%d%s",
1164 circuit->hello_multiplier[i], i + 1,
1165 VTY_NEWLINE);
1166 write++;
1167 }
1168 }
1169 }
1170
1171 /* ISIS - Priority */
1172 if (circuit->priority[0] == circuit->priority[1])
1173 {
1174 if (circuit->priority[0] != DEFAULT_PRIORITY)
1175 {
1176 vty_out (vty, " isis priority %d%s",
1177 circuit->priority[0], VTY_NEWLINE);
1178 write++;
1179 }
1180 }
1181 else
1182 {
1183 for (i = 0; i < 2; i++)
1184 {
1185 if (circuit->priority[i] != DEFAULT_PRIORITY)
1186 {
1187 vty_out (vty, " isis priority %d level-%d%s",
1188 circuit->priority[i], i + 1, VTY_NEWLINE);
1189 write++;
1190 }
1191 }
1192 }
1193
1194 /* ISIS - Metric */
1195 if (circuit->te_metric[0] == circuit->te_metric[1])
1196 {
1197 if (circuit->te_metric[0] != DEFAULT_CIRCUIT_METRIC)
1198 {
1199 vty_out (vty, " isis metric %d%s", circuit->te_metric[0],
1200 VTY_NEWLINE);
1201 write++;
1202 }
1203 }
1204 else
1205 {
1206 for (i = 0; i < 2; i++)
1207 {
1208 if (circuit->te_metric[i] != DEFAULT_CIRCUIT_METRIC)
1209 {
1210 vty_out (vty, " isis metric %d level-%d%s",
1211 circuit->te_metric[i], i + 1, VTY_NEWLINE);
1212 write++;
1213 }
1214 }
1215 }
1216 if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
1217 {
1218 vty_out (vty, " isis password md5 %s%s", circuit->passwd.passwd,
1219 VTY_NEWLINE);
1220 write++;
1221 }
1222 else if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT)
1223 {
1224 vty_out (vty, " isis password clear %s%s", circuit->passwd.passwd,
1225 VTY_NEWLINE);
1226 write++;
1227 }
1228 write += circuit_write_mt_settings(circuit, vty);
1229 }
1230 vty_out (vty, "!%s", VTY_NEWLINE);
1231 }
1232
1233 return write;
1234 }
1235
1236 struct isis_circuit *
1237 isis_circuit_create (struct isis_area *area, struct interface *ifp)
1238 {
1239 struct isis_circuit *circuit = circuit_scan_by_ifp (ifp);
1240 if (circuit && circuit->area)
1241 return NULL;
1242 circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area);
1243 if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP)
1244 return circuit;
1245 isis_circuit_if_bind (circuit, ifp);
1246 return circuit;
1247 }
1248
1249 void
1250 isis_circuit_af_set (struct isis_circuit *circuit, bool ip_router, bool ipv6_router)
1251 {
1252 struct isis_area *area = circuit->area;
1253 bool change = circuit->ip_router != ip_router || circuit->ipv6_router != ipv6_router;
1254 bool was_enabled = !!circuit->area;
1255
1256 area->ip_circuits += ip_router - circuit->ip_router;
1257 area->ipv6_circuits += ipv6_router - circuit->ipv6_router;
1258 circuit->ip_router = ip_router;
1259 circuit->ipv6_router = ipv6_router;
1260
1261 if (!change)
1262 return;
1263
1264 circuit_update_nlpids (circuit);
1265
1266 if (!ip_router && !ipv6_router)
1267 isis_csm_state_change (ISIS_DISABLE, circuit, area);
1268 else if (!was_enabled)
1269 isis_csm_state_change (ISIS_ENABLE, circuit, area);
1270 else
1271 lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
1272 }
1273
1274 int
1275 isis_circuit_passive_set (struct isis_circuit *circuit, bool passive)
1276 {
1277 if (circuit->is_passive == passive)
1278 return 0;
1279
1280 if (if_is_loopback (circuit->interface) && !passive)
1281 return -1;
1282
1283 if (circuit->state != C_STATE_UP)
1284 {
1285 circuit->is_passive = passive;
1286 }
1287 else
1288 {
1289 struct isis_area *area = circuit->area;
1290 isis_csm_state_change (ISIS_DISABLE, circuit, area);
1291 circuit->is_passive = passive;
1292 isis_csm_state_change (ISIS_ENABLE, circuit, area);
1293 }
1294
1295 return 0;
1296 }
1297
1298 int
1299 isis_circuit_metric_set (struct isis_circuit *circuit, int level, int metric)
1300 {
1301 assert (level == IS_LEVEL_1 || level == IS_LEVEL_2);
1302 if (metric > MAX_WIDE_LINK_METRIC)
1303 return -1;
1304 if (circuit->area && circuit->area->oldmetric
1305 && metric > MAX_NARROW_LINK_METRIC)
1306 return -1;
1307
1308 circuit->te_metric[level - 1] = metric;
1309 circuit->metric[level - 1] = metric;
1310
1311 if (circuit->area)
1312 lsp_regenerate_schedule (circuit->area, level, 0);
1313 return 0;
1314 }
1315
1316 int
1317 isis_circuit_passwd_unset (struct isis_circuit *circuit)
1318 {
1319 memset(&circuit->passwd, 0, sizeof(circuit->passwd));
1320 return 0;
1321 }
1322
1323 static int
1324 isis_circuit_passwd_set (struct isis_circuit *circuit, u_char passwd_type, const char *passwd)
1325 {
1326 int len;
1327
1328 if (!passwd)
1329 return -1;
1330
1331 len = strlen(passwd);
1332 if (len > 254)
1333 return -1;
1334
1335 circuit->passwd.len = len;
1336 strncpy((char *)circuit->passwd.passwd, passwd, 255);
1337 circuit->passwd.type = passwd_type;
1338 return 0;
1339 }
1340
1341 int
1342 isis_circuit_passwd_cleartext_set (struct isis_circuit *circuit, const char *passwd)
1343 {
1344 return isis_circuit_passwd_set (circuit, ISIS_PASSWD_TYPE_CLEARTXT, passwd);
1345 }
1346
1347 int
1348 isis_circuit_passwd_hmac_md5_set (struct isis_circuit *circuit, const char *passwd)
1349 {
1350 return isis_circuit_passwd_set (circuit, ISIS_PASSWD_TYPE_HMAC_MD5, passwd);
1351 }
1352 struct cmd_node interface_node = {
1353 INTERFACE_NODE,
1354 "%s(config-if)# ",
1355 1,
1356 };
1357
1358 int
1359 isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type)
1360 {
1361 /* Changing the network type to/of loopback or unknown interfaces
1362 * is not supported. */
1363 if (circ_type == CIRCUIT_T_UNKNOWN
1364 || circ_type == CIRCUIT_T_LOOPBACK
1365 || circuit->circ_type == CIRCUIT_T_LOOPBACK)
1366 {
1367 if (circuit->circ_type != circ_type)
1368 return -1;
1369 else
1370 return 0;
1371 }
1372
1373 if (circuit->circ_type == circ_type)
1374 return 0;
1375
1376 if (circuit->state != C_STATE_UP)
1377 {
1378 circuit->circ_type = circ_type;
1379 circuit->circ_type_config = circ_type;
1380 }
1381 else
1382 {
1383 struct isis_area *area = circuit->area;
1384 if (circ_type == CIRCUIT_T_BROADCAST
1385 && !if_is_broadcast(circuit->interface))
1386 return -1;
1387
1388 isis_csm_state_change(ISIS_DISABLE, circuit, area);
1389 circuit->circ_type = circ_type;
1390 circuit->circ_type_config = circ_type;
1391 isis_csm_state_change(ISIS_ENABLE, circuit, area);
1392 }
1393 return 0;
1394 }
1395
1396 int
1397 isis_circuit_mt_enabled_set (struct isis_circuit *circuit, uint16_t mtid,
1398 bool enabled)
1399 {
1400 struct isis_circuit_mt_setting *setting;
1401
1402 setting = circuit_get_mt_setting(circuit, mtid);
1403 if (setting->enabled != enabled)
1404 {
1405 setting->enabled = enabled;
1406 lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0);
1407 }
1408
1409 return CMD_SUCCESS;
1410 }
1411
1412 int
1413 isis_if_new_hook (struct interface *ifp)
1414 {
1415 return 0;
1416 }
1417
1418 int
1419 isis_if_delete_hook (struct interface *ifp)
1420 {
1421 struct isis_circuit *circuit;
1422 /* Clean up the circuit data */
1423 if (ifp && ifp->info)
1424 {
1425 circuit = ifp->info;
1426 isis_csm_state_change (IF_DOWN_FROM_Z, circuit, circuit->area);
1427 isis_csm_state_change (ISIS_DISABLE, circuit, circuit->area);
1428 }
1429
1430 return 0;
1431 }
1432
1433 void
1434 isis_circuit_init ()
1435 {
1436 /* Initialize Zebra interface data structure */
1437 if_add_hook (IF_NEW_HOOK, isis_if_new_hook);
1438 if_add_hook (IF_DELETE_HOOK, isis_if_delete_hook);
1439
1440 /* Install interface node */
1441 install_node (&interface_node, isis_interface_config_write);
1442 if_cmd_init ();
1443
1444 isis_vty_init ();
1445 }