]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_circuit.c
Merge pull request #11884 from mjstapp/fix_cancel_ptrs
[mirror_frr.git] / isisd / isis_circuit.c
CommitLineData
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
64DEFINE_MTYPE_STATIC(ISISD, ISIS_CIRCUIT, "ISIS circuit");
65
96244aca 66DEFINE_QOBJ_TYPE(isis_circuit);
676a4ea3 67
8451921b 68DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp));
ef7bd2a3 69
41b36e90
PJ
70/*
71 * Prototypes.
72 */
41b36e90
PJ
73int isis_if_new_hook(struct interface *);
74int isis_if_delete_hook(struct interface *);
75
e2b5b7d6
IR
76DEFINE_HOOK(isis_circuit_new_hook, (struct isis_circuit *circuit), (circuit));
77DEFINE_HOOK(isis_circuit_del_hook, (struct isis_circuit *circuit), (circuit));
1ee746d9 78
bcf22081
IR
79static 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
94static 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
106struct 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 198void 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 229void 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 258void 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 279struct isis_circuit *circuit_scan_by_ifp(struct interface *ifp)
eb5d44eb 280{
bcf22081 281 return (struct isis_circuit *)ifp->info;
eb5d44eb 282}
283
2bec0447 284DEFINE_HOOK(isis_circuit_add_addr_hook, (struct isis_circuit *circuit),
8451921b 285 (circuit));
2bec0447 286
d62a17ae 287void 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 375void 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 468static 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 498void 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 525void 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 539void 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 553void 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 563static 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 591size_t isis_circuit_pdu_size(struct isis_circuit *circuit)
b20ccb3a 592{
d62a17ae 593 return ISO_MTU(circuit);
b20ccb3a
CF
594}
595
d62a17ae 596void 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 609void 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 621int 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 766void 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 919void 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
934void 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 1078void 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
1199DEFINE_HOOK(isis_circuit_config_write,
1200 (struct isis_circuit *circuit, struct vty *vty),
8451921b 1201 (circuit, vty));
d56afe53 1202
612c2c15 1203static 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 1428void 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 1452ferr_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
1472ferr_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 1497ferr_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
1503ferr_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
1523ferr_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
1530ferr_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 1537void 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 1555int 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 1571int isis_if_new_hook(struct interface *ifp)
eb5d44eb 1572{
d62a17ae 1573 return 0;
eb5d44eb 1574}
1575
d62a17ae 1576int 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
1584static 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
1596static 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
1606static 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
1619static 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 1629void 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}