]>
Commit | Line | Data |
---|---|---|
eb5d44eb | 1 | /* |
2 | * IS-IS Rout(e)ing protocol - isis_circuit.h | |
3 | * | |
4 | * Copyright (C) 2001,2002 Sampo Saaristo | |
d62a17ae | 5 | * Tampere University of Technology |
eb5d44eb | 6 | * Institute of Communications Engineering |
7 | * | |
d62a17ae | 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) | |
eb5d44eb | 11 | * any later version. |
12 | * | |
d62a17ae | 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 | |
eb5d44eb | 16 | * more details. |
896014f4 DL |
17 | * |
18 | * You should have received a copy of the GNU General Public License along | |
19 | * with this program; see the file COPYING; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
eb5d44eb | 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 | |
29 | #include "log.h" | |
30 | #include "memory.h" | |
b2d7c082 | 31 | #include "vrf.h" |
eb5d44eb | 32 | #include "if.h" |
33 | #include "linklist.h" | |
34 | #include "command.h" | |
35 | #include "thread.h" | |
f8c06e2c | 36 | #include "vty.h" |
eb5d44eb | 37 | #include "hash.h" |
38 | #include "prefix.h" | |
39 | #include "stream.h" | |
676a4ea3 | 40 | #include "qobj.h" |
20600086 | 41 | #include "lib/northbound_cli.h" |
eb5d44eb | 42 | |
eb5d44eb | 43 | #include "isisd/isis_constants.h" |
44 | #include "isisd/isis_common.h" | |
3f045a08 | 45 | #include "isisd/isis_flags.h" |
eb5d44eb | 46 | #include "isisd/isis_circuit.h" |
eb5d44eb | 47 | #include "isisd/isis_lsp.h" |
48 | #include "isisd/isis_pdu.h" | |
49 | #include "isisd/isis_network.h" | |
50 | #include "isisd/isis_misc.h" | |
51 | #include "isisd/isis_constants.h" | |
52 | #include "isisd/isis_adjacency.h" | |
53 | #include "isisd/isis_dr.h" | |
eb5d44eb | 54 | #include "isisd/isisd.h" |
55 | #include "isisd/isis_csm.h" | |
56 | #include "isisd/isis_events.h" | |
f8c06e2c | 57 | #include "isisd/isis_te.h" |
064f4896 | 58 | #include "isisd/isis_mt.h" |
54ece698 | 59 | #include "isisd/isis_errors.h" |
9b39405f | 60 | #include "isisd/isis_tx_queue.h" |
2a1c520e | 61 | #include "isisd/isis_nb.h" |
1cbf96a8 | 62 | #include "isisd/isis_ldp_sync.h" |
eb5d44eb | 63 | |
66b9a381 DL |
64 | DEFINE_MTYPE_STATIC(ISISD, ISIS_CIRCUIT, "ISIS circuit"); |
65 | ||
96244aca | 66 | DEFINE_QOBJ_TYPE(isis_circuit); |
676a4ea3 | 67 | |
8451921b | 68 | DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp)); |
ef7bd2a3 | 69 | |
41b36e90 PJ |
70 | /* |
71 | * Prototypes. | |
72 | */ | |
41b36e90 PJ |
73 | int isis_if_new_hook(struct interface *); |
74 | int isis_if_delete_hook(struct interface *); | |
75 | ||
e2b5b7d6 IR |
76 | DEFINE_HOOK(isis_circuit_new_hook, (struct isis_circuit *circuit), (circuit)); |
77 | DEFINE_HOOK(isis_circuit_del_hook, (struct isis_circuit *circuit), (circuit)); | |
1ee746d9 | 78 | |
bcf22081 IR |
79 | static void isis_circuit_enable(struct isis_circuit *circuit) |
80 | { | |
3ae43012 | 81 | struct isis_area *area = circuit->area; |
bcf22081 IR |
82 | struct interface *ifp = circuit->interface; |
83 | ||
3ae43012 | 84 | if (!area) { |
096f7609 | 85 | area = isis_area_lookup(circuit->tag, ifp->vrf->vrf_id); |
3ae43012 IR |
86 | if (area) |
87 | isis_area_add_circuit(area, circuit); | |
88 | } | |
bcf22081 IR |
89 | |
90 | if (if_is_operative(ifp)) | |
91 | isis_csm_state_change(IF_UP_FROM_Z, circuit, ifp); | |
92 | } | |
93 | ||
94 | static void isis_circuit_disable(struct isis_circuit *circuit) | |
95 | { | |
96 | struct isis_area *area = circuit->area; | |
97 | struct interface *ifp = circuit->interface; | |
98 | ||
99 | if (if_is_operative(ifp)) | |
100 | isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp); | |
101 | ||
102 | if (area) | |
103 | isis_area_del_circuit(area, circuit); | |
104 | } | |
105 | ||
106 | struct isis_circuit *isis_circuit_new(struct interface *ifp, const char *tag) | |
eb5d44eb | 107 | { |
d62a17ae | 108 | struct isis_circuit *circuit; |
109 | int i; | |
110 | ||
111 | circuit = XCALLOC(MTYPE_ISIS_CIRCUIT, sizeof(struct isis_circuit)); | |
d62a17ae | 112 | |
bcf22081 | 113 | circuit->tag = XSTRDUP(MTYPE_ISIS_CIRCUIT, tag); |
1ee746d9 | 114 | |
d62a17ae | 115 | /* |
116 | * Default values | |
117 | */ | |
cc50ddb2 | 118 | #ifndef FABRICD |
2f9a06f0 | 119 | circuit->is_type_config = yang_get_default_enum( |
cc50ddb2 EDP |
120 | "/frr-interface:lib/interface/frr-isisd:isis/circuit-type"); |
121 | circuit->flags = 0; | |
122 | ||
123 | circuit->pad_hellos = yang_get_default_bool( | |
124 | "/frr-interface:lib/interface/frr-isisd:isis/hello/padding"); | |
125 | circuit->hello_interval[0] = yang_get_default_uint32( | |
126 | "/frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-1"); | |
127 | circuit->hello_interval[1] = yang_get_default_uint32( | |
128 | "/frr-interface:lib/interface/frr-isisd:isis/hello/interval/level-2"); | |
129 | circuit->hello_multiplier[0] = yang_get_default_uint32( | |
130 | "/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-1"); | |
131 | circuit->hello_multiplier[1] = yang_get_default_uint32( | |
132 | "/frr-interface:lib/interface/frr-isisd:isis/hello/multiplier/level-2"); | |
133 | circuit->csnp_interval[0] = yang_get_default_uint16( | |
134 | "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-1"); | |
135 | circuit->csnp_interval[1] = yang_get_default_uint16( | |
136 | "/frr-interface:lib/interface/frr-isisd:isis/csnp-interval/level-2"); | |
137 | circuit->psnp_interval[0] = yang_get_default_uint16( | |
138 | "/frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-1"); | |
139 | circuit->psnp_interval[1] = yang_get_default_uint16( | |
140 | "/frr-interface:lib/interface/frr-isisd:isis/psnp-interval/level-2"); | |
141 | circuit->priority[0] = yang_get_default_uint8( | |
142 | "/frr-interface:lib/interface/frr-isisd:isis/priority/level-1"); | |
143 | circuit->priority[1] = yang_get_default_uint8( | |
144 | "/frr-interface:lib/interface/frr-isisd:isis/priority/level-2"); | |
145 | circuit->metric[0] = yang_get_default_uint32( | |
146 | "/frr-interface:lib/interface/frr-isisd:isis/metric/level-1"); | |
147 | circuit->metric[1] = yang_get_default_uint32( | |
148 | "/frr-interface:lib/interface/frr-isisd:isis/metric/level-2"); | |
149 | circuit->te_metric[0] = yang_get_default_uint32( | |
150 | "/frr-interface:lib/interface/frr-isisd:isis/metric/level-1"); | |
151 | circuit->te_metric[1] = yang_get_default_uint32( | |
152 | "/frr-interface:lib/interface/frr-isisd:isis/metric/level-2"); | |
153 | ||
154 | for (i = 0; i < 2; i++) { | |
155 | circuit->level_arg[i].level = i + 1; | |
156 | circuit->level_arg[i].circuit = circuit; | |
157 | } | |
158 | #else | |
2f9a06f0 | 159 | circuit->is_type_config = IS_LEVEL_1_AND_2; |
d62a17ae | 160 | circuit->flags = 0; |
161 | circuit->pad_hellos = 1; | |
162 | for (i = 0; i < 2; i++) { | |
163 | circuit->hello_interval[i] = DEFAULT_HELLO_INTERVAL; | |
164 | circuit->hello_multiplier[i] = DEFAULT_HELLO_MULTIPLIER; | |
165 | circuit->csnp_interval[i] = DEFAULT_CSNP_INTERVAL; | |
166 | circuit->psnp_interval[i] = DEFAULT_PSNP_INTERVAL; | |
167 | circuit->priority[i] = DEFAULT_PRIORITY; | |
168 | circuit->metric[i] = DEFAULT_CIRCUIT_METRIC; | |
169 | circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC; | |
7da4aa3c CF |
170 | circuit->level_arg[i].level = i + 1; |
171 | circuit->level_arg[i].circuit = circuit; | |
d62a17ae | 172 | } |
cc50ddb2 | 173 | #endif /* ifndef FABRICD */ |
d62a17ae | 174 | |
2f9a06f0 IR |
175 | circuit->is_type = circuit->is_type_config; |
176 | ||
d62a17ae | 177 | circuit_mt_init(circuit); |
e886416f RW |
178 | isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL1); |
179 | isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL2); | |
d62a17ae | 180 | |
ec62fbaa IR |
181 | circuit->ldp_sync_info = ldp_sync_info_create(); |
182 | circuit->ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED; | |
183 | ||
d62a17ae | 184 | QOBJ_REG(circuit, isis_circuit); |
185 | ||
bcf22081 IR |
186 | isis_circuit_if_bind(circuit, ifp); |
187 | ||
91a5bbc4 DS |
188 | circuit->ip_addrs = list_new(); |
189 | circuit->ipv6_link = list_new(); | |
190 | circuit->ipv6_non_link = list_new(); | |
191 | ||
bcf22081 IR |
192 | if (ifp->ifindex != IFINDEX_INTERNAL) |
193 | isis_circuit_enable(circuit); | |
194 | ||
d62a17ae | 195 | return circuit; |
eb5d44eb | 196 | } |
197 | ||
d62a17ae | 198 | void isis_circuit_del(struct isis_circuit *circuit) |
3f045a08 | 199 | { |
d62a17ae | 200 | if (!circuit) |
201 | return; | |
3f045a08 | 202 | |
bcf22081 IR |
203 | if (circuit->interface->ifindex != IFINDEX_INTERNAL) |
204 | isis_circuit_disable(circuit); | |
1ee746d9 | 205 | |
d62a17ae | 206 | isis_circuit_if_unbind(circuit, circuit->interface); |
3f045a08 | 207 | |
bcf22081 IR |
208 | QOBJ_UNREG(circuit); |
209 | ||
ec62fbaa IR |
210 | ldp_sync_info_free(&circuit->ldp_sync_info); |
211 | ||
d62a17ae | 212 | circuit_mt_finish(circuit); |
e886416f RW |
213 | isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL1); |
214 | isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL2); | |
064f4896 | 215 | |
91a5bbc4 DS |
216 | list_delete(&circuit->ip_addrs); |
217 | list_delete(&circuit->ipv6_link); | |
218 | list_delete(&circuit->ipv6_non_link); | |
219 | ||
13bf3830 | 220 | XFREE(MTYPE_TMP, circuit->bfd_config.profile); |
bcf22081 IR |
221 | XFREE(MTYPE_ISIS_CIRCUIT, circuit->tag); |
222 | ||
d62a17ae | 223 | /* and lastly the circuit itself */ |
224 | XFREE(MTYPE_ISIS_CIRCUIT, circuit); | |
3f045a08 | 225 | |
d62a17ae | 226 | return; |
3f045a08 JB |
227 | } |
228 | ||
d62a17ae | 229 | void isis_circuit_configure(struct isis_circuit *circuit, |
230 | struct isis_area *area) | |
eb5d44eb | 231 | { |
d62a17ae | 232 | assert(area); |
bcf22081 | 233 | circuit->isis = area->isis; |
d62a17ae | 234 | circuit->area = area; |
235 | ||
236 | /* | |
237 | * Whenever the is-type of an area is changed, the is-type of each | |
238 | * circuit | |
239 | * in that area is updated to a non-empty subset of the area is-type. | |
240 | * Inversely, when configuring a new circuit, this property should be | |
241 | * ensured as well. | |
242 | */ | |
243 | if (area->is_type != IS_LEVEL_1_AND_2) | |
244 | circuit->is_type = area->is_type; | |
245 | ||
246 | /* | |
247 | * Add the circuit into area | |
248 | */ | |
249 | listnode_add(area->circuit_list, circuit); | |
250 | ||
251 | circuit->idx = flags_get_index(&area->flags); | |
252 | ||
bcf22081 IR |
253 | hook_call(isis_circuit_new_hook, circuit); |
254 | ||
d62a17ae | 255 | return; |
eb5d44eb | 256 | } |
257 | ||
d62a17ae | 258 | void isis_circuit_deconfigure(struct isis_circuit *circuit, |
259 | struct isis_area *area) | |
eb5d44eb | 260 | { |
bcf22081 IR |
261 | hook_call(isis_circuit_del_hook, circuit); |
262 | ||
d62a17ae | 263 | /* Free the index of SRM and SSN flags */ |
264 | flags_free_index(&area->flags, circuit->idx); | |
265 | circuit->idx = 0; | |
2f9a06f0 IR |
266 | |
267 | /* Reset IS type to configured */ | |
268 | circuit->is_type = circuit->is_type_config; | |
269 | ||
d62a17ae | 270 | /* Remove circuit from area */ |
271 | assert(circuit->area == area); | |
272 | listnode_delete(area->circuit_list, circuit); | |
273 | circuit->area = NULL; | |
bcf22081 | 274 | circuit->isis = NULL; |
d62a17ae | 275 | |
276 | return; | |
eb5d44eb | 277 | } |
278 | ||
d62a17ae | 279 | struct isis_circuit *circuit_scan_by_ifp(struct interface *ifp) |
eb5d44eb | 280 | { |
bcf22081 | 281 | return (struct isis_circuit *)ifp->info; |
eb5d44eb | 282 | } |
283 | ||
2bec0447 | 284 | DEFINE_HOOK(isis_circuit_add_addr_hook, (struct isis_circuit *circuit), |
8451921b | 285 | (circuit)); |
2bec0447 | 286 | |
d62a17ae | 287 | void isis_circuit_add_addr(struct isis_circuit *circuit, |
288 | struct connected *connected) | |
eb5d44eb | 289 | { |
d62a17ae | 290 | struct listnode *node; |
291 | struct prefix_ipv4 *ipv4; | |
d62a17ae | 292 | struct prefix_ipv6 *ipv6; |
f891f443 | 293 | |
d62a17ae | 294 | if (connected->address->family == AF_INET) { |
d7c0a89a | 295 | uint32_t addr = connected->address->u.prefix4.s_addr; |
d62a17ae | 296 | addr = ntohl(addr); |
297 | if (IPV4_NET0(addr) || IPV4_NET127(addr) || IN_CLASSD(addr) | |
298 | || IPV4_LINKLOCAL(addr)) | |
299 | return; | |
3f045a08 | 300 | |
d62a17ae | 301 | for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ipv4)) |
302 | if (prefix_same((struct prefix *)ipv4, | |
303 | connected->address)) | |
304 | return; | |
3f045a08 | 305 | |
d62a17ae | 306 | ipv4 = prefix_ipv4_new(); |
307 | ipv4->prefixlen = connected->address->prefixlen; | |
308 | ipv4->prefix = connected->address->u.prefix4; | |
309 | listnode_add(circuit->ip_addrs, ipv4); | |
f8c06e2c | 310 | |
1b3f47d0 | 311 | /* Update Local IP address parameter if MPLS TE is enable */ |
d80e23f8 EDP |
312 | if (circuit->ext && circuit->area |
313 | && IS_MPLS_TE(circuit->area->mta)) { | |
1b3f47d0 OD |
314 | circuit->ext->local_addr.s_addr = ipv4->prefix.s_addr; |
315 | SET_SUBTLV(circuit->ext, EXT_LOCAL_ADDR); | |
316 | } | |
f8c06e2c | 317 | |
d62a17ae | 318 | if (circuit->area) |
319 | lsp_regenerate_schedule(circuit->area, circuit->is_type, | |
320 | 0); | |
f891f443 | 321 | |
eb5d44eb | 322 | #ifdef EXTREME_DEBUG |
b0814935 PG |
323 | if (IS_DEBUG_EVENTS) |
324 | zlog_debug("Added IP address %pFX to circuit %s", | |
325 | connected->address, | |
326 | circuit->interface->name); | |
f390d2c7 | 327 | #endif /* EXTREME_DEBUG */ |
d62a17ae | 328 | } |
329 | if (connected->address->family == AF_INET6) { | |
330 | if (IN6_IS_ADDR_LOOPBACK(&connected->address->u.prefix6)) | |
331 | return; | |
332 | ||
333 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, ipv6)) | |
334 | if (prefix_same((struct prefix *)ipv6, | |
335 | connected->address)) | |
336 | return; | |
337 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, ipv6)) | |
338 | if (prefix_same((struct prefix *)ipv6, | |
339 | connected->address)) | |
340 | return; | |
341 | ||
342 | ipv6 = prefix_ipv6_new(); | |
343 | ipv6->prefixlen = connected->address->prefixlen; | |
344 | ipv6->prefix = connected->address->u.prefix6; | |
345 | ||
346 | if (IN6_IS_ADDR_LINKLOCAL(&ipv6->prefix)) | |
347 | listnode_add(circuit->ipv6_link, ipv6); | |
173f8887 | 348 | else { |
d62a17ae | 349 | listnode_add(circuit->ipv6_non_link, ipv6); |
173f8887 OD |
350 | /* Update Local IPv6 address param. if MPLS TE is on */ |
351 | if (circuit->ext && circuit->area | |
352 | && IS_MPLS_TE(circuit->area->mta)) { | |
353 | IPV6_ADDR_COPY(&circuit->ext->local_addr6, | |
354 | &ipv6->prefix); | |
355 | SET_SUBTLV(circuit->ext, EXT_LOCAL_ADDR6); | |
356 | } | |
357 | } | |
d62a17ae | 358 | if (circuit->area) |
359 | lsp_regenerate_schedule(circuit->area, circuit->is_type, | |
360 | 0); | |
f891f443 | 361 | |
eb5d44eb | 362 | #ifdef EXTREME_DEBUG |
b0814935 PG |
363 | if (IS_DEBUG_EVENTS) |
364 | zlog_debug("Added IPv6 address %pFX to circuit %s", | |
365 | connected->address, | |
366 | circuit->interface->name); | |
f390d2c7 | 367 | #endif /* EXTREME_DEBUG */ |
d62a17ae | 368 | } |
2bec0447 KS |
369 | |
370 | hook_call(isis_circuit_add_addr_hook, circuit); | |
371 | ||
d62a17ae | 372 | return; |
eb5d44eb | 373 | } |
374 | ||
d62a17ae | 375 | void isis_circuit_del_addr(struct isis_circuit *circuit, |
376 | struct connected *connected) | |
eb5d44eb | 377 | { |
d62a17ae | 378 | struct prefix_ipv4 *ipv4, *ip = NULL; |
379 | struct listnode *node; | |
d62a17ae | 380 | struct prefix_ipv6 *ipv6, *ip6 = NULL; |
381 | int found = 0; | |
382 | ||
383 | if (connected->address->family == AF_INET) { | |
384 | ipv4 = prefix_ipv4_new(); | |
385 | ipv4->prefixlen = connected->address->prefixlen; | |
386 | ipv4->prefix = connected->address->u.prefix4; | |
387 | ||
388 | for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, ip)) | |
389 | if (prefix_same((struct prefix *)ip, | |
390 | (struct prefix *)ipv4)) | |
391 | break; | |
392 | ||
393 | if (ip) { | |
394 | listnode_delete(circuit->ip_addrs, ip); | |
63265b5c | 395 | prefix_ipv4_free(&ip); |
d62a17ae | 396 | if (circuit->area) |
397 | lsp_regenerate_schedule(circuit->area, | |
398 | circuit->is_type, 0); | |
399 | } else { | |
d62a17ae | 400 | zlog_warn( |
2dbe669b DA |
401 | "Nonexistent ip address %pFX removal attempt from circuit %s", |
402 | connected->address, circuit->interface->name); | |
d62a17ae | 403 | zlog_warn("Current ip addresses on %s:", |
404 | circuit->interface->name); | |
405 | for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, | |
406 | ip)) { | |
2dbe669b | 407 | zlog_warn(" %pFX", ip); |
d62a17ae | 408 | } |
409 | zlog_warn("End of addresses"); | |
410 | } | |
411 | ||
63265b5c | 412 | prefix_ipv4_free(&ipv4); |
f891f443 | 413 | } |
d62a17ae | 414 | if (connected->address->family == AF_INET6) { |
415 | ipv6 = prefix_ipv6_new(); | |
416 | ipv6->prefixlen = connected->address->prefixlen; | |
417 | ipv6->prefix = connected->address->u.prefix6; | |
418 | ||
419 | if (IN6_IS_ADDR_LINKLOCAL(&ipv6->prefix)) { | |
420 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, | |
421 | ip6)) { | |
422 | if (prefix_same((struct prefix *)ip6, | |
423 | (struct prefix *)ipv6)) | |
424 | break; | |
425 | } | |
426 | if (ip6) { | |
427 | listnode_delete(circuit->ipv6_link, ip6); | |
63265b5c | 428 | prefix_ipv6_free(&ip6); |
d62a17ae | 429 | found = 1; |
430 | } | |
431 | } else { | |
432 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, | |
433 | ip6)) { | |
434 | if (prefix_same((struct prefix *)ip6, | |
435 | (struct prefix *)ipv6)) | |
436 | break; | |
437 | } | |
438 | if (ip6) { | |
439 | listnode_delete(circuit->ipv6_non_link, ip6); | |
63265b5c | 440 | prefix_ipv6_free(&ip6); |
d62a17ae | 441 | found = 1; |
442 | } | |
443 | } | |
444 | ||
445 | if (!found) { | |
d62a17ae | 446 | zlog_warn( |
2dbe669b DA |
447 | "Nonexistent ip address %pFX removal attempt from circuit %s", |
448 | connected->address, circuit->interface->name); | |
d62a17ae | 449 | zlog_warn("Current ip addresses on %s:", |
450 | circuit->interface->name); | |
451 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, | |
2dbe669b DA |
452 | ip6)) |
453 | zlog_warn(" %pFX", (struct prefix *)ip6); | |
d62a17ae | 454 | zlog_warn(" -----"); |
455 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, | |
2dbe669b DA |
456 | ip6)) |
457 | zlog_warn(" %pFX", (struct prefix *)ip6); | |
d62a17ae | 458 | zlog_warn("End of addresses"); |
459 | } else if (circuit->area) | |
460 | lsp_regenerate_schedule(circuit->area, circuit->is_type, | |
461 | 0); | |
462 | ||
63265b5c | 463 | prefix_ipv6_free(&ipv6); |
f891f443 | 464 | } |
d62a17ae | 465 | return; |
466 | } | |
e8aca32f | 467 | |
0849c75e | 468 | static uint8_t isis_circuit_id_gen(struct isis *isis, struct interface *ifp) |
d62a17ae | 469 | { |
068c8222 CF |
470 | /* Circuit ids MUST be unique for any broadcast circuits. Otherwise, |
471 | * Pseudo-Node LSPs cannot be generated correctly. | |
472 | * | |
98c5bc15 | 473 | * Currently, allocate one circuit ID for any circuit, limiting the total |
068c8222 CF |
474 | * numer of circuits IS-IS can run on to 255. |
475 | * | |
98c5bc15 | 476 | * We should revisit this when implementing 3-way adjacencies for p2p, since |
068c8222 CF |
477 | * we then have extended interface IDs available. |
478 | */ | |
479 | uint8_t id = ifp->ifindex; | |
d62a17ae | 480 | unsigned int i; |
d62a17ae | 481 | |
068c8222 CF |
482 | for (i = 0; i < 256; i++) { |
483 | if (id && !_ISIS_CHECK_FLAG(isis->circuit_ids_used, id)) | |
d62a17ae | 484 | break; |
068c8222 | 485 | id++; |
f891f443 | 486 | } |
487 | ||
068c8222 | 488 | if (i == 256) { |
996c9314 LB |
489 | zlog_warn("Could not allocate a circuit id for '%s'", |
490 | ifp->name); | |
068c8222 | 491 | return 0; |
f891f443 | 492 | } |
e8aca32f | 493 | |
0849c75e | 494 | _ISIS_SET_FLAG(isis->circuit_ids_used, id); |
d62a17ae | 495 | return id; |
3f045a08 JB |
496 | } |
497 | ||
d62a17ae | 498 | void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp) |
eb5d44eb | 499 | { |
d62a17ae | 500 | struct listnode *node, *nnode; |
501 | struct connected *conn; | |
502 | ||
d62a17ae | 503 | if (if_is_broadcast(ifp)) { |
65f18157 | 504 | if (fabricd || circuit->circ_type_config == CIRCUIT_T_P2P) |
d62a17ae | 505 | circuit->circ_type = CIRCUIT_T_P2P; |
506 | else | |
507 | circuit->circ_type = CIRCUIT_T_BROADCAST; | |
508 | } else if (if_is_pointopoint(ifp)) { | |
509 | circuit->circ_type = CIRCUIT_T_P2P; | |
608c8870 | 510 | } else if (if_is_loopback(ifp)) { |
d62a17ae | 511 | circuit->circ_type = CIRCUIT_T_LOOPBACK; |
512 | circuit->is_passive = 1; | |
513 | } else { | |
514 | /* It's normal in case of loopback etc. */ | |
e740f9c1 | 515 | if (IS_DEBUG_EVENTS) |
1f46f33f | 516 | zlog_debug("%s: unsupported media", __func__); |
d62a17ae | 517 | circuit->circ_type = CIRCUIT_T_UNKNOWN; |
518 | } | |
519 | ||
d62a17ae | 520 | for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, conn)) |
521 | isis_circuit_add_addr(circuit, conn); | |
1b3f47d0 | 522 | |
eb5d44eb | 523 | } |
524 | ||
d62a17ae | 525 | void isis_circuit_if_del(struct isis_circuit *circuit, struct interface *ifp) |
eb5d44eb | 526 | { |
d62a17ae | 527 | struct listnode *node, *nnode; |
528 | struct connected *conn; | |
529 | ||
530 | assert(circuit->interface == ifp); | |
531 | ||
532 | /* destroy addresses */ | |
533 | for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, conn)) | |
534 | isis_circuit_del_addr(circuit, conn); | |
535 | ||
d62a17ae | 536 | circuit->circ_type = CIRCUIT_T_UNKNOWN; |
eb5d44eb | 537 | } |
538 | ||
d62a17ae | 539 | void isis_circuit_if_bind(struct isis_circuit *circuit, struct interface *ifp) |
3f045a08 | 540 | { |
d62a17ae | 541 | assert(circuit != NULL); |
542 | assert(ifp != NULL); | |
543 | if (circuit->interface) | |
544 | assert(circuit->interface == ifp); | |
545 | else | |
546 | circuit->interface = ifp; | |
547 | if (ifp->info) | |
548 | assert(ifp->info == circuit); | |
549 | else | |
550 | ifp->info = circuit; | |
3f045a08 JB |
551 | } |
552 | ||
d62a17ae | 553 | void isis_circuit_if_unbind(struct isis_circuit *circuit, struct interface *ifp) |
eb5d44eb | 554 | { |
d62a17ae | 555 | assert(circuit != NULL); |
556 | assert(ifp != NULL); | |
557 | assert(circuit->interface == ifp); | |
558 | assert(ifp->info == circuit); | |
559 | circuit->interface = NULL; | |
560 | ifp->info = NULL; | |
3f045a08 | 561 | } |
f390d2c7 | 562 | |
d62a17ae | 563 | static void isis_circuit_update_all_srmflags(struct isis_circuit *circuit, |
564 | int is_set) | |
3f045a08 | 565 | { |
d62a17ae | 566 | struct isis_area *area; |
567 | struct isis_lsp *lsp; | |
d62a17ae | 568 | int level; |
569 | ||
570 | assert(circuit); | |
571 | area = circuit->area; | |
572 | assert(area); | |
573 | for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { | |
9b39405f CF |
574 | if (!(level & circuit->is_type)) |
575 | continue; | |
576 | ||
4bef0ec4 | 577 | if (!lspdb_count(&area->lspdb[level - 1])) |
9b39405f CF |
578 | continue; |
579 | ||
81fddbe7 | 580 | frr_each (lspdb, &area->lspdb[level - 1], lsp) { |
9b39405f CF |
581 | if (is_set) { |
582 | isis_tx_queue_add(circuit->tx_queue, lsp, | |
583 | TX_LSP_NORMAL); | |
584 | } else { | |
585 | isis_tx_queue_del(circuit->tx_queue, lsp); | |
d62a17ae | 586 | } |
587 | } | |
588 | } | |
eb5d44eb | 589 | } |
590 | ||
d62a17ae | 591 | size_t isis_circuit_pdu_size(struct isis_circuit *circuit) |
b20ccb3a | 592 | { |
d62a17ae | 593 | return ISO_MTU(circuit); |
b20ccb3a CF |
594 | } |
595 | ||
d62a17ae | 596 | void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream) |
b20ccb3a | 597 | { |
d62a17ae | 598 | size_t stream_size = isis_circuit_pdu_size(circuit); |
599 | ||
600 | if (!*stream) { | |
601 | *stream = stream_new(stream_size); | |
602 | } else { | |
603 | if (STREAM_SIZE(*stream) != stream_size) | |
db3c830a | 604 | stream_resize_inplace(stream, stream_size); |
d62a17ae | 605 | stream_reset(*stream); |
606 | } | |
b20ccb3a CF |
607 | } |
608 | ||
d62a17ae | 609 | void isis_circuit_prepare(struct isis_circuit *circuit) |
5904f19f | 610 | { |
b0dd98e7 | 611 | #if ISIS_METHOD != ISIS_METHOD_DLPI |
d62a17ae | 612 | thread_add_read(master, isis_receive, circuit, circuit->fd, |
613 | &circuit->t_read); | |
5904f19f | 614 | #else |
d62a17ae | 615 | thread_add_timer_msec(master, isis_receive, circuit, |
616 | listcount(circuit->area->circuit_list) * 100, | |
617 | &circuit->t_read); | |
5904f19f RW |
618 | #endif |
619 | } | |
620 | ||
d62a17ae | 621 | int isis_circuit_up(struct isis_circuit *circuit) |
eb5d44eb | 622 | { |
d62a17ae | 623 | int retv; |
624 | ||
625 | /* Set the flags for all the lsps of the circuit. */ | |
626 | isis_circuit_update_all_srmflags(circuit, 1); | |
627 | ||
628 | if (circuit->state == C_STATE_UP) | |
629 | return ISIS_OK; | |
630 | ||
93bdc367 | 631 | if (circuit->is_passive) { |
1ee746d9 | 632 | circuit->last_uptime = time(NULL); |
93bdc367 EDP |
633 | /* make sure the union fields are initialized, else we |
634 | * could end with garbage values from a previous circuit | |
635 | * type, which would then cause a segfault when building | |
636 | * LSPs or computing the SPF tree | |
637 | */ | |
638 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) { | |
639 | circuit->u.bc.adjdb[0] = list_new(); | |
640 | circuit->u.bc.adjdb[1] = list_new(); | |
641 | } else if (circuit->circ_type == CIRCUIT_T_P2P) { | |
642 | circuit->u.p2p.neighbor = NULL; | |
643 | } | |
d62a17ae | 644 | return ISIS_OK; |
93bdc367 | 645 | } |
d62a17ae | 646 | |
647 | if (circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit)) { | |
af4c2728 | 648 | flog_err( |
1a7ecb96 | 649 | EC_ISIS_CONFIG, |
d62a17ae | 650 | "Interface MTU %zu on %s is too low to support area lsp mtu %u!", |
651 | isis_circuit_pdu_size(circuit), | |
652 | circuit->interface->name, circuit->area->lsp_mtu); | |
c7b253d0 | 653 | |
654 | /* Allow ISIS to continue configuration. With this | |
655 | * configuration failure ISIS will attempt to send lsp | |
656 | * packets but will fail until the mtu is configured properly | |
657 | */ | |
d62a17ae | 658 | } |
659 | ||
660 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) { | |
99e5d4af DS |
661 | circuit->circuit_id = |
662 | isis_circuit_id_gen(circuit->isis, circuit->interface); | |
0849c75e | 663 | if (!circuit->circuit_id) { |
af4c2728 | 664 | flog_err( |
1a7ecb96 | 665 | EC_ISIS_CONFIG, |
54ece698 | 666 | "There are already 255 broadcast circuits active!"); |
0849c75e CF |
667 | return ISIS_ERROR; |
668 | } | |
669 | ||
d62a17ae | 670 | /* |
671 | * Get the Hardware Address | |
672 | */ | |
673 | if (circuit->interface->hw_addr_len != ETH_ALEN) { | |
674 | zlog_warn("unsupported link layer"); | |
675 | } else { | |
676 | memcpy(circuit->u.bc.snpa, circuit->interface->hw_addr, | |
677 | ETH_ALEN); | |
678 | } | |
3f045a08 | 679 | #ifdef EXTREME_DEGUG |
b0814935 | 680 | if (IS_DEBUG_EVENTS) |
1f46f33f | 681 | zlog_debug("%s: if_id %d, isomtu %d snpa %s", __func__, |
682 | circuit->interface->ifindex, | |
683 | ISO_MTU(circuit), | |
684 | snpa_print(circuit->u.bc.snpa)); | |
3f045a08 | 685 | #endif /* EXTREME_DEBUG */ |
3f045a08 | 686 | |
d62a17ae | 687 | circuit->u.bc.adjdb[0] = list_new(); |
688 | circuit->u.bc.adjdb[1] = list_new(); | |
689 | ||
690 | /* | |
691 | * ISO 10589 - 8.4.1 Enabling of broadcast circuits | |
692 | */ | |
693 | ||
694 | /* initilizing the hello sending threads | |
695 | * for a broadcast IF | |
696 | */ | |
697 | ||
698 | /* 8.4.1 a) commence sending of IIH PDUs */ | |
699 | ||
7c4f7aab CF |
700 | for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { |
701 | if (!(circuit->is_type & level)) | |
702 | continue; | |
703 | ||
a0a707ee | 704 | send_hello_sched(circuit, level, TRIGGERED_IIH_DELAY); |
7c4f7aab CF |
705 | circuit->u.bc.lan_neighs[level - 1] = list_new(); |
706 | ||
707 | thread_add_timer(master, isis_run_dr, | |
708 | &circuit->level_arg[level - 1], | |
709 | 2 * circuit->hello_interval[level - 1], | |
710 | &circuit->u.bc.t_run_dr[level - 1]); | |
d62a17ae | 711 | } |
712 | ||
713 | /* 8.4.1 b) FIXME: solicit ES - 8.4.6 */ | |
714 | /* 8.4.1 c) FIXME: listen for ESH PDUs */ | |
d4670f51 | 715 | } else if (circuit->circ_type == CIRCUIT_T_P2P) { |
d62a17ae | 716 | /* initializing the hello send threads |
717 | * for a ptp IF | |
718 | */ | |
719 | circuit->u.p2p.neighbor = NULL; | |
a0a707ee | 720 | send_hello_sched(circuit, 0, TRIGGERED_IIH_DELAY); |
d62a17ae | 721 | } |
722 | ||
723 | /* initializing PSNP timers */ | |
724 | if (circuit->is_type & IS_LEVEL_1) | |
725 | thread_add_timer( | |
726 | master, send_l1_psnp, circuit, | |
727 | isis_jitter(circuit->psnp_interval[0], PSNP_JITTER), | |
728 | &circuit->t_send_psnp[0]); | |
729 | ||
730 | if (circuit->is_type & IS_LEVEL_2) | |
731 | thread_add_timer( | |
732 | master, send_l2_psnp, circuit, | |
733 | isis_jitter(circuit->psnp_interval[1], PSNP_JITTER), | |
734 | &circuit->t_send_psnp[1]); | |
735 | ||
736 | /* unified init for circuits; ignore warnings below this level */ | |
737 | retv = isis_sock_init(circuit); | |
738 | if (retv != ISIS_OK) { | |
739 | isis_circuit_down(circuit); | |
740 | return retv; | |
741 | } | |
742 | ||
743 | /* initialize the circuit streams after opening connection */ | |
744 | isis_circuit_stream(circuit, &circuit->rcv_stream); | |
745 | isis_circuit_stream(circuit, &circuit->snd_stream); | |
746 | ||
747 | isis_circuit_prepare(circuit); | |
748 | ||
9b39405f | 749 | circuit->tx_queue = isis_tx_queue_new(circuit, send_lsp); |
d62a17ae | 750 | |
1ee746d9 | 751 | circuit->last_uptime = time(NULL); |
752 | ||
0fdd8b2b IR |
753 | if (circuit->area->mta && circuit->area->mta->status) |
754 | isis_link_params_update(circuit, circuit->interface); | |
755 | ||
ec62fbaa IR |
756 | isis_if_ldp_sync_enable(circuit); |
757 | ||
392b89f3 EDP |
758 | #ifndef FABRICD |
759 | /* send northbound notification */ | |
760 | isis_notif_if_state_change(circuit, false); | |
761 | #endif /* ifndef FABRICD */ | |
762 | ||
d62a17ae | 763 | return ISIS_OK; |
eb5d44eb | 764 | } |
765 | ||
d62a17ae | 766 | void isis_circuit_down(struct isis_circuit *circuit) |
eb5d44eb | 767 | { |
392b89f3 EDP |
768 | #ifndef FABRICD |
769 | /* send northbound notification */ | |
770 | isis_notif_if_state_change(circuit, true); | |
771 | #endif /* ifndef FABRICD */ | |
772 | ||
ec62fbaa IR |
773 | isis_if_ldp_sync_disable(circuit); |
774 | ||
7145d5bb | 775 | /* log adjacency changes if configured to do so */ |
5e69d308 | 776 | if (circuit->area->log_adj_changes) { |
7145d5bb EDP |
777 | struct isis_adjacency *adj = NULL; |
778 | if (circuit->circ_type == CIRCUIT_T_P2P) { | |
779 | adj = circuit->u.p2p.neighbor; | |
780 | if (adj) | |
781 | isis_log_adj_change( | |
782 | adj, adj->adj_state, ISIS_ADJ_DOWN, | |
783 | "circuit is being brought down"); | |
784 | } else if (circuit->circ_type == CIRCUIT_T_BROADCAST) { | |
785 | struct list *adj_list; | |
786 | struct listnode *node; | |
787 | if (circuit->u.bc.adjdb[0]) { | |
788 | adj_list = list_new(); | |
789 | isis_adj_build_up_list(circuit->u.bc.adjdb[0], | |
790 | adj_list); | |
791 | for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) | |
792 | isis_log_adj_change( | |
793 | adj, adj->adj_state, | |
794 | ISIS_ADJ_DOWN, | |
795 | "circuit is being brought down"); | |
796 | list_delete(&adj_list); | |
797 | } | |
798 | if (circuit->u.bc.adjdb[1]) { | |
799 | adj_list = list_new(); | |
800 | isis_adj_build_up_list(circuit->u.bc.adjdb[1], | |
801 | adj_list); | |
802 | for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) | |
803 | isis_log_adj_change( | |
804 | adj, adj->adj_state, | |
805 | ISIS_ADJ_DOWN, | |
806 | "circuit is being brought down"); | |
807 | list_delete(&adj_list); | |
808 | } | |
809 | } | |
810 | } | |
811 | ||
d62a17ae | 812 | /* Clear the flags for all the lsps of the circuit. */ |
813 | isis_circuit_update_all_srmflags(circuit, 0); | |
814 | ||
815 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) { | |
816 | /* destroy neighbour lists */ | |
817 | if (circuit->u.bc.lan_neighs[0]) { | |
6a154c88 | 818 | list_delete(&circuit->u.bc.lan_neighs[0]); |
d62a17ae | 819 | circuit->u.bc.lan_neighs[0] = NULL; |
820 | } | |
821 | if (circuit->u.bc.lan_neighs[1]) { | |
6a154c88 | 822 | list_delete(&circuit->u.bc.lan_neighs[1]); |
d62a17ae | 823 | circuit->u.bc.lan_neighs[1] = NULL; |
824 | } | |
825 | /* destroy adjacency databases */ | |
826 | if (circuit->u.bc.adjdb[0]) { | |
827 | circuit->u.bc.adjdb[0]->del = isis_delete_adj; | |
6a154c88 | 828 | list_delete(&circuit->u.bc.adjdb[0]); |
d62a17ae | 829 | circuit->u.bc.adjdb[0] = NULL; |
830 | } | |
831 | if (circuit->u.bc.adjdb[1]) { | |
832 | circuit->u.bc.adjdb[1]->del = isis_delete_adj; | |
6a154c88 | 833 | list_delete(&circuit->u.bc.adjdb[1]); |
d62a17ae | 834 | circuit->u.bc.adjdb[1] = NULL; |
835 | } | |
836 | if (circuit->u.bc.is_dr[0]) { | |
837 | isis_dr_resign(circuit, 1); | |
838 | circuit->u.bc.is_dr[0] = 0; | |
839 | } | |
840 | memset(circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1); | |
841 | if (circuit->u.bc.is_dr[1]) { | |
842 | isis_dr_resign(circuit, 2); | |
843 | circuit->u.bc.is_dr[1] = 0; | |
844 | } | |
845 | memset(circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1); | |
846 | memset(circuit->u.bc.snpa, 0, ETH_ALEN); | |
847 | ||
fa935aa7 DS |
848 | THREAD_OFF(circuit->u.bc.t_send_lan_hello[0]); |
849 | THREAD_OFF(circuit->u.bc.t_send_lan_hello[1]); | |
850 | THREAD_OFF(circuit->u.bc.t_run_dr[0]); | |
851 | THREAD_OFF(circuit->u.bc.t_run_dr[1]); | |
852 | THREAD_OFF(circuit->u.bc.t_refresh_pseudo_lsp[0]); | |
853 | THREAD_OFF(circuit->u.bc.t_refresh_pseudo_lsp[1]); | |
d62a17ae | 854 | circuit->lsp_regenerate_pending[0] = 0; |
855 | circuit->lsp_regenerate_pending[1] = 0; | |
0849c75e | 856 | |
99e5d4af | 857 | _ISIS_CLEAR_FLAG(circuit->isis->circuit_ids_used, |
eab88f36 | 858 | circuit->circuit_id); |
0849c75e | 859 | circuit->circuit_id = 0; |
d62a17ae | 860 | } else if (circuit->circ_type == CIRCUIT_T_P2P) { |
861 | isis_delete_adj(circuit->u.p2p.neighbor); | |
862 | circuit->u.p2p.neighbor = NULL; | |
fa935aa7 | 863 | THREAD_OFF(circuit->u.p2p.t_send_p2p_hello); |
d62a17ae | 864 | } |
865 | ||
1ee746d9 | 866 | /* |
867 | * All adjacencies have to be gone, delete snmp list | |
868 | * and reset snmpd idx generator | |
869 | */ | |
870 | if (circuit->snmp_adj_list != NULL) | |
871 | list_delete(&circuit->snmp_adj_list); | |
872 | ||
873 | circuit->snmp_adj_idx_gen = 0; | |
874 | ||
d62a17ae | 875 | /* Cancel all active threads */ |
fa935aa7 DS |
876 | THREAD_OFF(circuit->t_send_csnp[0]); |
877 | THREAD_OFF(circuit->t_send_csnp[1]); | |
878 | THREAD_OFF(circuit->t_send_psnp[0]); | |
879 | THREAD_OFF(circuit->t_send_psnp[1]); | |
880 | THREAD_OFF(circuit->t_read); | |
d62a17ae | 881 | |
9b39405f CF |
882 | if (circuit->tx_queue) { |
883 | isis_tx_queue_free(circuit->tx_queue); | |
884 | circuit->tx_queue = NULL; | |
58e16237 CF |
885 | } |
886 | ||
d62a17ae | 887 | /* send one gratuitous hello to spead up convergence */ |
d4670f51 CF |
888 | if (circuit->state == C_STATE_UP) { |
889 | if (circuit->is_type & IS_LEVEL_1) | |
890 | send_hello(circuit, IS_LEVEL_1); | |
891 | if (circuit->is_type & IS_LEVEL_2) | |
892 | send_hello(circuit, IS_LEVEL_2); | |
893 | } | |
d62a17ae | 894 | |
895 | circuit->upadjcount[0] = 0; | |
896 | circuit->upadjcount[1] = 0; | |
897 | ||
898 | /* close the socket */ | |
899 | if (circuit->fd) { | |
900 | close(circuit->fd); | |
901 | circuit->fd = 0; | |
902 | } | |
903 | ||
904 | if (circuit->rcv_stream != NULL) { | |
905 | stream_free(circuit->rcv_stream); | |
906 | circuit->rcv_stream = NULL; | |
907 | } | |
908 | ||
909 | if (circuit->snd_stream != NULL) { | |
910 | stream_free(circuit->snd_stream); | |
911 | circuit->snd_stream = NULL; | |
912 | } | |
913 | ||
914 | thread_cancel_event(master, circuit); | |
915 | ||
916 | return; | |
eb5d44eb | 917 | } |
918 | ||
d62a17ae | 919 | void circuit_update_nlpids(struct isis_circuit *circuit) |
eb5d44eb | 920 | { |
d62a17ae | 921 | circuit->nlpids.count = 0; |
922 | ||
923 | if (circuit->ip_router) { | |
924 | circuit->nlpids.nlpids[0] = NLPID_IP; | |
925 | circuit->nlpids.count++; | |
926 | } | |
927 | if (circuit->ipv6_router) { | |
928 | circuit->nlpids.nlpids[circuit->nlpids.count] = NLPID_IPV6; | |
929 | circuit->nlpids.count++; | |
930 | } | |
931 | return; | |
eb5d44eb | 932 | } |
933 | ||
9fee4d4c JG |
934 | void isis_circuit_print_json(struct isis_circuit *circuit, |
935 | struct json_object *json, char detail) | |
936 | { | |
937 | int level; | |
938 | json_object *iface_json, *ipv4_addr_json, *ipv6_link_json, | |
939 | *ipv6_non_link_json, *hold_json, *lan_prio_json, *levels_json, | |
940 | *level_json; | |
941 | char buf_prx[INET6_BUFSIZ]; | |
942 | char buf[255]; | |
943 | ||
944 | snprintfrr(buf, sizeof(buf), "0x%x", circuit->circuit_id); | |
945 | if (detail == ISIS_UI_LEVEL_BRIEF) { | |
946 | iface_json = json_object_new_object(); | |
947 | json_object_object_add(json, "interface", iface_json); | |
948 | json_object_string_add(iface_json, "name", | |
949 | circuit->interface->name); | |
950 | json_object_string_add(iface_json, "circuit-id", buf); | |
951 | json_object_string_add(iface_json, "state", | |
952 | circuit_state2string(circuit->state)); | |
953 | json_object_string_add(iface_json, "type", | |
954 | circuit_type2string(circuit->circ_type)); | |
955 | json_object_string_add(iface_json, "level", | |
956 | circuit_t2string(circuit->is_type)); | |
957 | } | |
958 | ||
959 | if (detail == ISIS_UI_LEVEL_DETAIL) { | |
960 | struct listnode *node; | |
961 | struct prefix *ip_addr; | |
962 | ||
963 | iface_json = json_object_new_object(); | |
964 | json_object_object_add(json, "interface", iface_json); | |
965 | json_object_string_add(iface_json, "name", | |
966 | circuit->interface->name); | |
967 | json_object_string_add(iface_json, "state", | |
968 | circuit_state2string(circuit->state)); | |
969 | if (circuit->is_passive) | |
970 | json_object_string_add(iface_json, "is-passive", | |
971 | "passive"); | |
972 | else | |
973 | json_object_string_add(iface_json, "is-passive", | |
974 | "active"); | |
975 | json_object_string_add(iface_json, "circuit-id", buf); | |
976 | json_object_string_add(iface_json, "type", | |
977 | circuit_type2string(circuit->circ_type)); | |
978 | json_object_string_add(iface_json, "level", | |
979 | circuit_t2string(circuit->is_type)); | |
980 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) | |
981 | json_object_string_add(iface_json, "snpa", | |
982 | snpa_print(circuit->u.bc.snpa)); | |
983 | ||
984 | ||
985 | levels_json = json_object_new_array(); | |
986 | json_object_object_add(iface_json, "levels", levels_json); | |
987 | for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { | |
988 | if ((circuit->is_type & level) == 0) | |
989 | continue; | |
990 | level_json = json_object_new_object(); | |
991 | json_object_string_add(level_json, "level", | |
992 | circuit_t2string(level)); | |
993 | if (circuit->area->newmetric) | |
994 | json_object_int_add(level_json, "metric", | |
995 | circuit->te_metric[0]); | |
996 | else | |
997 | json_object_int_add(level_json, "metric", | |
998 | circuit->metric[0]); | |
999 | if (!circuit->is_passive) { | |
1000 | json_object_int_add(level_json, | |
1001 | "active-neighbors", | |
1002 | circuit->upadjcount[0]); | |
1003 | json_object_int_add(level_json, | |
1004 | "hello-interval", | |
1005 | circuit->hello_interval[0]); | |
1006 | hold_json = json_object_new_object(); | |
1007 | json_object_object_add(level_json, "holddown", | |
1008 | hold_json); | |
1009 | json_object_int_add( | |
1010 | hold_json, "count", | |
1011 | circuit->hello_multiplier[0]); | |
1012 | json_object_string_add( | |
1013 | hold_json, "pad", | |
1014 | (circuit->pad_hellos ? "yes" : "no")); | |
1015 | json_object_int_add(level_json, "cnsp-interval", | |
1016 | circuit->csnp_interval[0]); | |
1017 | json_object_int_add(level_json, "psnp-interval", | |
1018 | circuit->psnp_interval[0]); | |
1019 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) { | |
1020 | lan_prio_json = | |
1021 | json_object_new_object(); | |
1022 | json_object_object_add(level_json, | |
1023 | "lan", | |
1024 | lan_prio_json); | |
1025 | json_object_int_add( | |
1026 | lan_prio_json, "priority", | |
1027 | circuit->priority[0]); | |
1028 | json_object_string_add( | |
1029 | lan_prio_json, "is-dis", | |
1030 | (circuit->u.bc.is_dr[0] | |
1031 | ? "yes" | |
1032 | : "no")); | |
1033 | } | |
1034 | } | |
1035 | json_object_array_add(levels_json, level_json); | |
1036 | } | |
1037 | ||
91a5bbc4 | 1038 | if (listcount(circuit->ip_addrs) > 0) { |
9fee4d4c JG |
1039 | ipv4_addr_json = json_object_new_object(); |
1040 | json_object_object_add(iface_json, "ip-prefix", | |
1041 | ipv4_addr_json); | |
1042 | for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, | |
1043 | ip_addr)) { | |
1044 | snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX", | |
1045 | ip_addr); | |
1046 | json_object_string_add(ipv4_addr_json, "ip", | |
1047 | buf_prx); | |
1048 | } | |
1049 | } | |
91a5bbc4 | 1050 | if (listcount(circuit->ipv6_link) > 0) { |
9fee4d4c JG |
1051 | ipv6_link_json = json_object_new_object(); |
1052 | json_object_object_add(iface_json, "ipv6-link-locals", | |
1053 | ipv6_link_json); | |
1054 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, | |
1055 | ip_addr)) { | |
1056 | snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX", | |
1057 | ip_addr); | |
1058 | json_object_string_add(ipv6_link_json, "ipv6", | |
1059 | buf_prx); | |
1060 | } | |
1061 | } | |
91a5bbc4 | 1062 | if (listcount(circuit->ipv6_non_link) > 0) { |
9fee4d4c JG |
1063 | ipv6_non_link_json = json_object_new_object(); |
1064 | json_object_object_add(iface_json, "ipv6-prefixes", | |
1065 | ipv6_non_link_json); | |
1066 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, | |
1067 | ip_addr)) { | |
1068 | snprintfrr(buf_prx, INET6_BUFSIZ, "%pFX", | |
1069 | ip_addr); | |
1070 | json_object_string_add(ipv6_non_link_json, | |
1071 | "ipv6", buf_prx); | |
1072 | } | |
1073 | } | |
1074 | } | |
1075 | return; | |
1076 | } | |
1077 | ||
d62a17ae | 1078 | void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty, |
1079 | char detail) | |
3f045a08 | 1080 | { |
d62a17ae | 1081 | if (detail == ISIS_UI_LEVEL_BRIEF) { |
1082 | vty_out(vty, " %-12s", circuit->interface->name); | |
1083 | vty_out(vty, "0x%-7x", circuit->circuit_id); | |
1084 | vty_out(vty, "%-9s", circuit_state2string(circuit->state)); | |
1085 | vty_out(vty, "%-9s", circuit_type2string(circuit->circ_type)); | |
1086 | vty_out(vty, "%-9s", circuit_t2string(circuit->is_type)); | |
1087 | vty_out(vty, "\n"); | |
1088 | } | |
1089 | ||
1090 | if (detail == ISIS_UI_LEVEL_DETAIL) { | |
1091 | struct listnode *node; | |
1092 | struct prefix *ip_addr; | |
d62a17ae | 1093 | |
1094 | vty_out(vty, " Interface: %s", circuit->interface->name); | |
1095 | vty_out(vty, ", State: %s", | |
1096 | circuit_state2string(circuit->state)); | |
1097 | if (circuit->is_passive) | |
1098 | vty_out(vty, ", Passive"); | |
1099 | else | |
1100 | vty_out(vty, ", Active"); | |
1101 | vty_out(vty, ", Circuit Id: 0x%x", circuit->circuit_id); | |
1102 | vty_out(vty, "\n"); | |
1103 | vty_out(vty, " Type: %s", | |
1104 | circuit_type2string(circuit->circ_type)); | |
1105 | vty_out(vty, ", Level: %s", circuit_t2string(circuit->is_type)); | |
1106 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) | |
1107 | vty_out(vty, ", SNPA: %-10s", | |
1108 | snpa_print(circuit->u.bc.snpa)); | |
1109 | vty_out(vty, "\n"); | |
1110 | if (circuit->is_type & IS_LEVEL_1) { | |
1111 | vty_out(vty, " Level-1 Information:\n"); | |
1112 | if (circuit->area->newmetric) | |
1113 | vty_out(vty, " Metric: %d", | |
1114 | circuit->te_metric[0]); | |
1115 | else | |
1116 | vty_out(vty, " Metric: %d", | |
1117 | circuit->metric[0]); | |
1118 | if (!circuit->is_passive) { | |
1119 | vty_out(vty, ", Active neighbors: %u\n", | |
1120 | circuit->upadjcount[0]); | |
1121 | vty_out(vty, | |
3efd0893 | 1122 | " Hello interval: %u, Holddown count: %u %s\n", |
d62a17ae | 1123 | circuit->hello_interval[0], |
1124 | circuit->hello_multiplier[0], | |
1125 | (circuit->pad_hellos ? "(pad)" | |
1126 | : "(no-pad)")); | |
1127 | vty_out(vty, | |
3efd0893 | 1128 | " CNSP interval: %u, PSNP interval: %u\n", |
d62a17ae | 1129 | circuit->csnp_interval[0], |
1130 | circuit->psnp_interval[0]); | |
1131 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) | |
1132 | vty_out(vty, | |
1133 | " LAN Priority: %u, %s\n", | |
1134 | circuit->priority[0], | |
1135 | (circuit->u.bc.is_dr[0] | |
1136 | ? "is DIS" | |
1137 | : "is not DIS")); | |
1138 | } else { | |
1139 | vty_out(vty, "\n"); | |
1140 | } | |
1141 | } | |
1142 | if (circuit->is_type & IS_LEVEL_2) { | |
1143 | vty_out(vty, " Level-2 Information:\n"); | |
1144 | if (circuit->area->newmetric) | |
1145 | vty_out(vty, " Metric: %d", | |
1146 | circuit->te_metric[1]); | |
1147 | else | |
1148 | vty_out(vty, " Metric: %d", | |
1149 | circuit->metric[1]); | |
1150 | if (!circuit->is_passive) { | |
1151 | vty_out(vty, ", Active neighbors: %u\n", | |
1152 | circuit->upadjcount[1]); | |
1153 | vty_out(vty, | |
3efd0893 | 1154 | " Hello interval: %u, Holddown count: %u %s\n", |
d62a17ae | 1155 | circuit->hello_interval[1], |
1156 | circuit->hello_multiplier[1], | |
1157 | (circuit->pad_hellos ? "(pad)" | |
1158 | : "(no-pad)")); | |
1159 | vty_out(vty, | |
3efd0893 | 1160 | " CNSP interval: %u, PSNP interval: %u\n", |
d62a17ae | 1161 | circuit->csnp_interval[1], |
1162 | circuit->psnp_interval[1]); | |
1163 | if (circuit->circ_type == CIRCUIT_T_BROADCAST) | |
1164 | vty_out(vty, | |
1165 | " LAN Priority: %u, %s\n", | |
1166 | circuit->priority[1], | |
1167 | (circuit->u.bc.is_dr[1] | |
1168 | ? "is DIS" | |
1169 | : "is not DIS")); | |
1170 | } else { | |
1171 | vty_out(vty, "\n"); | |
1172 | } | |
1173 | } | |
91a5bbc4 | 1174 | if (listcount(circuit->ip_addrs) > 0) { |
d62a17ae | 1175 | vty_out(vty, " IP Prefix(es):\n"); |
1176 | for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, node, | |
2dbe669b DA |
1177 | ip_addr)) |
1178 | vty_out(vty, " %pFX\n", ip_addr); | |
d62a17ae | 1179 | } |
91a5bbc4 | 1180 | if (listcount(circuit->ipv6_link) > 0) { |
d62a17ae | 1181 | vty_out(vty, " IPv6 Link-Locals:\n"); |
1182 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_link, node, | |
2dbe669b DA |
1183 | ip_addr)) |
1184 | vty_out(vty, " %pFX\n", ip_addr); | |
d62a17ae | 1185 | } |
91a5bbc4 | 1186 | if (listcount(circuit->ipv6_non_link) > 0) { |
d62a17ae | 1187 | vty_out(vty, " IPv6 Prefixes:\n"); |
1188 | for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link, node, | |
2dbe669b DA |
1189 | ip_addr)) |
1190 | vty_out(vty, " %pFX\n", ip_addr); | |
d62a17ae | 1191 | } |
1192 | ||
1193 | vty_out(vty, "\n"); | |
1194 | } | |
1195 | return; | |
3f045a08 JB |
1196 | } |
1197 | ||
05e4ec37 | 1198 | #ifdef FABRICD |
d56afe53 CF |
1199 | DEFINE_HOOK(isis_circuit_config_write, |
1200 | (struct isis_circuit *circuit, struct vty *vty), | |
8451921b | 1201 | (circuit, vty)); |
d56afe53 | 1202 | |
612c2c15 | 1203 | static int isis_interface_config_write(struct vty *vty) |
eb5d44eb | 1204 | { |
f4e14fdb | 1205 | struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); |
d62a17ae | 1206 | int write = 0; |
d62a17ae | 1207 | struct interface *ifp; |
d62a17ae | 1208 | struct isis_circuit *circuit; |
1209 | int i; | |
1210 | ||
451fda4f | 1211 | FOR_ALL_INTERFACES (vrf, ifp) { |
d62a17ae | 1212 | /* IF name */ |
788a036f | 1213 | if_vty_config_start(vty, ifp); |
d62a17ae | 1214 | write++; |
1215 | /* IF desc */ | |
1216 | if (ifp->desc) { | |
1217 | vty_out(vty, " description %s\n", ifp->desc); | |
1218 | write++; | |
1219 | } | |
1220 | /* ISIS Circuit */ | |
88ae0963 IR |
1221 | do { |
1222 | circuit = circuit_scan_by_ifp(ifp); | |
d62a17ae | 1223 | if (circuit == NULL) |
88ae0963 | 1224 | break; |
d62a17ae | 1225 | if (circuit->ip_router) { |
7c0cbd0e | 1226 | vty_out(vty, " ip router " PROTO_NAME " %s\n", |
88ae0963 | 1227 | circuit->tag); |
d62a17ae | 1228 | write++; |
1229 | } | |
1230 | if (circuit->is_passive) { | |
7c0cbd0e | 1231 | vty_out(vty, " " PROTO_NAME " passive\n"); |
d62a17ae | 1232 | write++; |
1233 | } | |
1234 | if (circuit->circ_type_config == CIRCUIT_T_P2P) { | |
7c0cbd0e | 1235 | vty_out(vty, " " PROTO_NAME " network point-to-point\n"); |
d62a17ae | 1236 | write++; |
1237 | } | |
1238 | if (circuit->ipv6_router) { | |
7c0cbd0e | 1239 | vty_out(vty, " ipv6 router " PROTO_NAME " %s\n", |
88ae0963 | 1240 | circuit->tag); |
d62a17ae | 1241 | write++; |
1242 | } | |
1243 | ||
1244 | /* ISIS - circuit type */ | |
65f18157 CF |
1245 | if (!fabricd) { |
1246 | if (circuit->is_type == IS_LEVEL_1) { | |
1247 | vty_out(vty, " " PROTO_NAME " circuit-type level-1\n"); | |
d62a17ae | 1248 | write++; |
65f18157 CF |
1249 | } else { |
1250 | if (circuit->is_type == IS_LEVEL_2) { | |
1251 | vty_out(vty, | |
1252 | " " PROTO_NAME " circuit-type level-2-only\n"); | |
1253 | write++; | |
1254 | } | |
d62a17ae | 1255 | } |
1256 | } | |
1257 | ||
1258 | /* ISIS - CSNP interval */ | |
1259 | if (circuit->csnp_interval[0] | |
1260 | == circuit->csnp_interval[1]) { | |
1261 | if (circuit->csnp_interval[0] | |
1262 | != DEFAULT_CSNP_INTERVAL) { | |
7c0cbd0e | 1263 | vty_out(vty, " " PROTO_NAME " csnp-interval %d\n", |
d62a17ae | 1264 | circuit->csnp_interval[0]); |
1265 | write++; | |
1266 | } | |
1267 | } else { | |
1268 | for (i = 0; i < 2; i++) { | |
1269 | if (circuit->csnp_interval[i] | |
1270 | != DEFAULT_CSNP_INTERVAL) { | |
1271 | vty_out(vty, | |
7c0cbd0e | 1272 | " " PROTO_NAME " csnp-interval %d level-%d\n", |
d62a17ae | 1273 | circuit->csnp_interval |
1274 | [i], | |
1275 | i + 1); | |
1276 | write++; | |
1277 | } | |
1278 | } | |
1279 | } | |
1280 | ||
1281 | /* ISIS - PSNP interval */ | |
1282 | if (circuit->psnp_interval[0] | |
1283 | == circuit->psnp_interval[1]) { | |
1284 | if (circuit->psnp_interval[0] | |
1285 | != DEFAULT_PSNP_INTERVAL) { | |
7c0cbd0e | 1286 | vty_out(vty, " " PROTO_NAME " psnp-interval %d\n", |
d62a17ae | 1287 | circuit->psnp_interval[0]); |
1288 | write++; | |
1289 | } | |
1290 | } else { | |
1291 | for (i = 0; i < 2; i++) { | |
1292 | if (circuit->psnp_interval[i] | |
1293 | != DEFAULT_PSNP_INTERVAL) { | |
1294 | vty_out(vty, | |
7c0cbd0e | 1295 | " " PROTO_NAME " psnp-interval %d level-%d\n", |
d62a17ae | 1296 | circuit->psnp_interval |
1297 | [i], | |
1298 | i + 1); | |
1299 | write++; | |
1300 | } | |
1301 | } | |
1302 | } | |
1303 | ||
1304 | /* ISIS - Hello padding - Defaults to true so only | |
1305 | * display if false */ | |
1306 | if (circuit->pad_hellos == 0) { | |
7c0cbd0e | 1307 | vty_out(vty, " no " PROTO_NAME " hello padding\n"); |
d62a17ae | 1308 | write++; |
1309 | } | |
1310 | ||
58e5d748 CF |
1311 | if (circuit->disable_threeway_adj) { |
1312 | vty_out(vty, " no isis three-way-handshake\n"); | |
1313 | write++; | |
1314 | } | |
1315 | ||
d62a17ae | 1316 | /* ISIS - Hello interval */ |
1317 | if (circuit->hello_interval[0] | |
1318 | == circuit->hello_interval[1]) { | |
1319 | if (circuit->hello_interval[0] | |
1320 | != DEFAULT_HELLO_INTERVAL) { | |
1321 | vty_out(vty, | |
7c0cbd0e | 1322 | " " PROTO_NAME " hello-interval %d\n", |
d62a17ae | 1323 | circuit->hello_interval[0]); |
1324 | write++; | |
1325 | } | |
1326 | } else { | |
1327 | for (i = 0; i < 2; i++) { | |
1328 | if (circuit->hello_interval[i] | |
1329 | != DEFAULT_HELLO_INTERVAL) { | |
1330 | vty_out(vty, | |
7c0cbd0e | 1331 | " " PROTO_NAME " hello-interval %d level-%d\n", |
d62a17ae | 1332 | circuit->hello_interval |
1333 | [i], | |
1334 | i + 1); | |
1335 | write++; | |
1336 | } | |
1337 | } | |
1338 | } | |
1339 | ||
1340 | /* ISIS - Hello Multiplier */ | |
1341 | if (circuit->hello_multiplier[0] | |
1342 | == circuit->hello_multiplier[1]) { | |
1343 | if (circuit->hello_multiplier[0] | |
1344 | != DEFAULT_HELLO_MULTIPLIER) { | |
1345 | vty_out(vty, | |
7c0cbd0e | 1346 | " " PROTO_NAME " hello-multiplier %d\n", |
d62a17ae | 1347 | circuit->hello_multiplier[0]); |
1348 | write++; | |
1349 | } | |
1350 | } else { | |
1351 | for (i = 0; i < 2; i++) { | |
1352 | if (circuit->hello_multiplier[i] | |
1353 | != DEFAULT_HELLO_MULTIPLIER) { | |
1354 | vty_out(vty, | |
7c0cbd0e | 1355 | " " PROTO_NAME " hello-multiplier %d level-%d\n", |
d62a17ae | 1356 | circuit->hello_multiplier |
1357 | [i], | |
1358 | i + 1); | |
1359 | write++; | |
1360 | } | |
1361 | } | |
1362 | } | |
1363 | ||
1364 | /* ISIS - Priority */ | |
1365 | if (circuit->priority[0] == circuit->priority[1]) { | |
1366 | if (circuit->priority[0] != DEFAULT_PRIORITY) { | |
7c0cbd0e | 1367 | vty_out(vty, " " PROTO_NAME " priority %d\n", |
d62a17ae | 1368 | circuit->priority[0]); |
1369 | write++; | |
1370 | } | |
1371 | } else { | |
1372 | for (i = 0; i < 2; i++) { | |
1373 | if (circuit->priority[i] | |
1374 | != DEFAULT_PRIORITY) { | |
1375 | vty_out(vty, | |
7c0cbd0e | 1376 | " " PROTO_NAME " priority %d level-%d\n", |
d62a17ae | 1377 | circuit->priority[i], |
1378 | i + 1); | |
1379 | write++; | |
1380 | } | |
1381 | } | |
1382 | } | |
1383 | ||
1384 | /* ISIS - Metric */ | |
1385 | if (circuit->te_metric[0] == circuit->te_metric[1]) { | |
1386 | if (circuit->te_metric[0] | |
1387 | != DEFAULT_CIRCUIT_METRIC) { | |
7c0cbd0e | 1388 | vty_out(vty, " " PROTO_NAME " metric %d\n", |
d62a17ae | 1389 | circuit->te_metric[0]); |
1390 | write++; | |
1391 | } | |
1392 | } else { | |
1393 | for (i = 0; i < 2; i++) { | |
1394 | if (circuit->te_metric[i] | |
1395 | != DEFAULT_CIRCUIT_METRIC) { | |
1396 | vty_out(vty, | |
7c0cbd0e | 1397 | " " PROTO_NAME " metric %d level-%d\n", |
d62a17ae | 1398 | circuit->te_metric[i], |
1399 | i + 1); | |
1400 | write++; | |
1401 | } | |
1402 | } | |
1403 | } | |
1404 | if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { | |
7c0cbd0e | 1405 | vty_out(vty, " " PROTO_NAME " password md5 %s\n", |
d62a17ae | 1406 | circuit->passwd.passwd); |
1407 | write++; | |
1408 | } else if (circuit->passwd.type | |
1409 | == ISIS_PASSWD_TYPE_CLEARTXT) { | |
7c0cbd0e | 1410 | vty_out(vty, " " PROTO_NAME " password clear %s\n", |
d62a17ae | 1411 | circuit->passwd.passwd); |
1412 | write++; | |
1413 | } | |
13bf3830 IR |
1414 | if (circuit->bfd_config.enabled) { |
1415 | vty_out(vty, " " PROTO_NAME " bfd\n"); | |
1416 | write++; | |
1417 | } | |
5489eb45 CF |
1418 | write += hook_call(isis_circuit_config_write, |
1419 | circuit, vty); | |
88ae0963 | 1420 | } while (0); |
788a036f | 1421 | if_vty_config_end(vty); |
d62a17ae | 1422 | } |
1423 | ||
1424 | return write; | |
eb5d44eb | 1425 | } |
20600086 | 1426 | #endif /* ifdef FABRICD */ |
eb5d44eb | 1427 | |
d62a17ae | 1428 | void isis_circuit_af_set(struct isis_circuit *circuit, bool ip_router, |
1429 | bool ipv6_router) | |
eb5d44eb | 1430 | { |
d62a17ae | 1431 | struct isis_area *area = circuit->area; |
e8cff6d1 EDP |
1432 | int old_ipr = circuit->ip_router; |
1433 | int old_ipv6r = circuit->ipv6_router; | |
1434 | ||
1435 | /* is there something to do? */ | |
1436 | if (old_ipr == ip_router && old_ipv6r == ipv6_router) | |
1437 | return; | |
d62a17ae | 1438 | |
d62a17ae | 1439 | circuit->ip_router = ip_router; |
1440 | circuit->ipv6_router = ipv6_router; | |
e8cff6d1 | 1441 | circuit_update_nlpids(circuit); |
d62a17ae | 1442 | |
bcf22081 IR |
1443 | if (area) { |
1444 | area->ip_circuits += ip_router - old_ipr; | |
1445 | area->ipv6_circuits += ipv6_router - old_ipv6r; | |
d62a17ae | 1446 | |
bcf22081 IR |
1447 | if (ip_router || ipv6_router) |
1448 | lsp_regenerate_schedule(area, circuit->is_type, 0); | |
1449 | } | |
3f045a08 | 1450 | } |
eb5d44eb | 1451 | |
64dd3ffe | 1452 | ferr_r isis_circuit_passive_set(struct isis_circuit *circuit, bool passive) |
3f045a08 | 1453 | { |
d62a17ae | 1454 | if (circuit->is_passive == passive) |
64dd3ffe | 1455 | return ferr_ok(); |
d62a17ae | 1456 | |
608c8870 | 1457 | if (if_is_loopback(circuit->interface) && !passive) |
64dd3ffe | 1458 | return ferr_cfg_invalid("loopback is always passive"); |
d62a17ae | 1459 | |
1460 | if (circuit->state != C_STATE_UP) { | |
1461 | circuit->is_passive = passive; | |
1462 | } else { | |
1463 | struct isis_area *area = circuit->area; | |
1464 | isis_csm_state_change(ISIS_DISABLE, circuit, area); | |
1465 | circuit->is_passive = passive; | |
1466 | isis_csm_state_change(ISIS_ENABLE, circuit, area); | |
1467 | } | |
1468 | ||
64dd3ffe | 1469 | return ferr_ok(); |
eb5d44eb | 1470 | } |
1471 | ||
64dd3ffe DL |
1472 | ferr_r isis_circuit_metric_set(struct isis_circuit *circuit, int level, |
1473 | int metric) | |
3f045a08 | 1474 | { |
d62a17ae | 1475 | assert(level == IS_LEVEL_1 || level == IS_LEVEL_2); |
1476 | if (metric > MAX_WIDE_LINK_METRIC) | |
64dd3ffe DL |
1477 | return ferr_cfg_invalid("metric %d too large for wide metric", |
1478 | metric); | |
d62a17ae | 1479 | if (circuit->area && circuit->area->oldmetric |
1480 | && metric > MAX_NARROW_LINK_METRIC) | |
64dd3ffe DL |
1481 | return ferr_cfg_invalid("metric %d too large for narrow metric", |
1482 | metric); | |
d62a17ae | 1483 | |
1cbf96a8 | 1484 | /* inform ldp-sync of metric change |
1485 | * if ldp-sync is running need to save metric | |
1486 | * and restore new values after ldp-sync completion. | |
1487 | */ | |
1488 | if (isis_ldp_sync_if_metric_config(circuit, level, metric)) { | |
1489 | circuit->te_metric[level - 1] = metric; | |
1490 | circuit->metric[level - 1] = metric; | |
1491 | if (circuit->area) | |
1492 | lsp_regenerate_schedule(circuit->area, level, 0); | |
1493 | } | |
64dd3ffe | 1494 | return ferr_ok(); |
eb5d44eb | 1495 | } |
1496 | ||
64dd3ffe | 1497 | ferr_r isis_circuit_passwd_unset(struct isis_circuit *circuit) |
eb5d44eb | 1498 | { |
d62a17ae | 1499 | memset(&circuit->passwd, 0, sizeof(circuit->passwd)); |
64dd3ffe | 1500 | return ferr_ok(); |
3f045a08 JB |
1501 | } |
1502 | ||
e28544ed QY |
1503 | ferr_r isis_circuit_passwd_set(struct isis_circuit *circuit, |
1504 | uint8_t passwd_type, const char *passwd) | |
3f045a08 | 1505 | { |
d62a17ae | 1506 | int len; |
f390d2c7 | 1507 | |
d62a17ae | 1508 | if (!passwd) |
64dd3ffe | 1509 | return ferr_code_bug("no circuit password given"); |
50c7d14a | 1510 | |
d62a17ae | 1511 | len = strlen(passwd); |
1512 | if (len > 254) | |
64dd3ffe DL |
1513 | return ferr_code_bug( |
1514 | "circuit password too long (max 254 chars)"); | |
f390d2c7 | 1515 | |
d62a17ae | 1516 | circuit->passwd.len = len; |
e28544ed QY |
1517 | strlcpy((char *)circuit->passwd.passwd, passwd, |
1518 | sizeof(circuit->passwd.passwd)); | |
d62a17ae | 1519 | circuit->passwd.type = passwd_type; |
64dd3ffe | 1520 | return ferr_ok(); |
eb5d44eb | 1521 | } |
1522 | ||
64dd3ffe DL |
1523 | ferr_r isis_circuit_passwd_cleartext_set(struct isis_circuit *circuit, |
1524 | const char *passwd) | |
eb5d44eb | 1525 | { |
d62a17ae | 1526 | return isis_circuit_passwd_set(circuit, ISIS_PASSWD_TYPE_CLEARTXT, |
1527 | passwd); | |
50c7d14a | 1528 | } |
f390d2c7 | 1529 | |
64dd3ffe DL |
1530 | ferr_r isis_circuit_passwd_hmac_md5_set(struct isis_circuit *circuit, |
1531 | const char *passwd) | |
50c7d14a | 1532 | { |
d62a17ae | 1533 | return isis_circuit_passwd_set(circuit, ISIS_PASSWD_TYPE_HMAC_MD5, |
1534 | passwd); | |
eb5d44eb | 1535 | } |
64dd3ffe | 1536 | |
d0820765 | 1537 | void isis_circuit_circ_type_set(struct isis_circuit *circuit, int circ_type) |
3f045a08 | 1538 | { |
64dd3ffe | 1539 | if (circuit->circ_type == circ_type) |
d0820765 | 1540 | return; |
d62a17ae | 1541 | |
d62a17ae | 1542 | if (circuit->state != C_STATE_UP) { |
1543 | circuit->circ_type = circ_type; | |
1544 | circuit->circ_type_config = circ_type; | |
1545 | } else { | |
1546 | struct isis_area *area = circuit->area; | |
d62a17ae | 1547 | |
1548 | isis_csm_state_change(ISIS_DISABLE, circuit, area); | |
1549 | circuit->circ_type = circ_type; | |
1550 | circuit->circ_type_config = circ_type; | |
1551 | isis_csm_state_change(ISIS_ENABLE, circuit, area); | |
1552 | } | |
3f045a08 JB |
1553 | } |
1554 | ||
d62a17ae | 1555 | int isis_circuit_mt_enabled_set(struct isis_circuit *circuit, uint16_t mtid, |
1556 | bool enabled) | |
064f4896 | 1557 | { |
d62a17ae | 1558 | struct isis_circuit_mt_setting *setting; |
064f4896 | 1559 | |
d62a17ae | 1560 | setting = circuit_get_mt_setting(circuit, mtid); |
1561 | if (setting->enabled != enabled) { | |
1562 | setting->enabled = enabled; | |
bcf22081 IR |
1563 | if (circuit->area) |
1564 | lsp_regenerate_schedule(circuit->area, | |
1565 | IS_LEVEL_1 | IS_LEVEL_2, 0); | |
d62a17ae | 1566 | } |
064f4896 | 1567 | |
d62a17ae | 1568 | return CMD_SUCCESS; |
064f4896 CF |
1569 | } |
1570 | ||
d62a17ae | 1571 | int isis_if_new_hook(struct interface *ifp) |
eb5d44eb | 1572 | { |
d62a17ae | 1573 | return 0; |
eb5d44eb | 1574 | } |
1575 | ||
d62a17ae | 1576 | int isis_if_delete_hook(struct interface *ifp) |
eb5d44eb | 1577 | { |
bcf22081 IR |
1578 | if (ifp->info) |
1579 | isis_circuit_del(ifp->info); | |
d62a17ae | 1580 | |
1581 | return 0; | |
eb5d44eb | 1582 | } |
1583 | ||
138c5a74 DS |
1584 | static int isis_ifp_create(struct interface *ifp) |
1585 | { | |
bcf22081 IR |
1586 | struct isis_circuit *circuit = ifp->info; |
1587 | ||
1588 | if (circuit) | |
1589 | isis_circuit_enable(circuit); | |
65251ce8 | 1590 | |
ef7bd2a3 DS |
1591 | hook_call(isis_if_new_hook, ifp); |
1592 | ||
138c5a74 DS |
1593 | return 0; |
1594 | } | |
1595 | ||
1596 | static int isis_ifp_up(struct interface *ifp) | |
1597 | { | |
bcf22081 IR |
1598 | struct isis_circuit *circuit = ifp->info; |
1599 | ||
c179a46b | 1600 | if (circuit) |
bcf22081 | 1601 | isis_csm_state_change(IF_UP_FROM_Z, circuit, ifp); |
ddbf3e60 | 1602 | |
138c5a74 DS |
1603 | return 0; |
1604 | } | |
1605 | ||
1606 | static int isis_ifp_down(struct interface *ifp) | |
1607 | { | |
bcf22081 IR |
1608 | struct isis_circuit *circuit = ifp->info; |
1609 | ||
2ba9ccf7 | 1610 | if (circuit) { |
bcf22081 | 1611 | isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp); |
b0b69e59 | 1612 | |
b0b69e59 | 1613 | SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); |
bcf22081 | 1614 | } |
b0b69e59 | 1615 | |
138c5a74 DS |
1616 | return 0; |
1617 | } | |
1618 | ||
1619 | static int isis_ifp_destroy(struct interface *ifp) | |
1620 | { | |
bcf22081 | 1621 | struct isis_circuit *circuit = ifp->info; |
3c3c3252 | 1622 | |
bcf22081 IR |
1623 | if (circuit) |
1624 | isis_circuit_disable(circuit); | |
3c3c3252 | 1625 | |
138c5a74 DS |
1626 | return 0; |
1627 | } | |
1628 | ||
4d762f26 | 1629 | void isis_circuit_init(void) |
eb5d44eb | 1630 | { |
d62a17ae | 1631 | /* Initialize Zebra interface data structure */ |
ce19a04a DL |
1632 | hook_register_prio(if_add, 0, isis_if_new_hook); |
1633 | hook_register_prio(if_del, 0, isis_if_delete_hook); | |
eb5d44eb | 1634 | |
d62a17ae | 1635 | /* Install interface node */ |
104fd767 | 1636 | #ifdef FABRICD |
9da01b0b | 1637 | if_cmd_init(isis_interface_config_write); |
104fd767 IR |
1638 | #else |
1639 | if_cmd_init_default(); | |
1640 | #endif | |
138c5a74 DS |
1641 | if_zapi_callbacks(isis_ifp_create, isis_ifp_up, |
1642 | isis_ifp_down, isis_ifp_destroy); | |
eb5d44eb | 1643 | } |