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