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