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