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