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