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