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