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