]> git.proxmox.com Git - mirror_frr.git/blame - lib/nexthop_group.c
zebra: Check active count first in nhg_hash_equal
[mirror_frr.git] / lib / nexthop_group.c
CommitLineData
7ee30f28
DS
1/*
2 * Nexthop Group structure definition.
3 * Copyright (C) 2018 Cumulus Networks, Inc.
4 * Donald Sharp
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20#include <zebra.h>
21
31919191 22#include <vrf.h>
c57bd6bb 23#include <sockunion.h>
7ee30f28
DS
24#include <nexthop.h>
25#include <nexthop_group.h>
50d89650 26#include <nexthop_group_private.h>
dba32923
DS
27#include <vty.h>
28#include <command.h>
1b1fe1c4 29#include <jhash.h>
dba32923
DS
30
31#ifndef VTYSH_EXTRACT_PL
32#include "lib/nexthop_group_clippy.c"
33#endif
7ee30f28 34
31919191
DS
35DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group")
36
37struct nexthop_group_hooks {
38 void (*new)(const char *name);
39 void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
40 const struct nexthop *nhop);
41 void (*del_nexthop)(const struct nexthop_group_cmd *nhg,
42 const struct nexthop *nhop);
43 void (*delete)(const char *name);
44};
45
46static struct nexthop_group_hooks nhg_hooks;
47
48static inline int
49nexthop_group_cmd_compare(const struct nexthop_group_cmd *nhgc1,
50 const struct nexthop_group_cmd *nhgc2);
51RB_GENERATE(nhgc_entry_head, nexthop_group_cmd, nhgc_entry,
52 nexthop_group_cmd_compare)
53
c17faa4b 54static struct nhgc_entry_head nhgc_entries;
31919191
DS
55
56static inline int
57nexthop_group_cmd_compare(const struct nexthop_group_cmd *nhgc1,
58 const struct nexthop_group_cmd *nhgc2)
59{
60 return strcmp(nhgc1->name, nhgc2->name);
61}
62
8c15fa95
SW
63static struct nexthop *nexthop_group_tail(const struct nexthop_group *nhg)
64{
65 struct nexthop *nexthop = nhg->nexthop;
66
67 while (nexthop && nexthop->next)
68 nexthop = nexthop->next;
69
70 return nexthop;
71}
72
454192f4
DS
73uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg)
74{
75 struct nexthop *nhop;
76 uint8_t num = 0;
77
78 for (ALL_NEXTHOPS_PTR(nhg, nhop))
79 num++;
80
81 return num;
82}
83
98cda54a
SW
84uint8_t nexthop_group_nexthop_num_no_recurse(const struct nexthop_group *nhg)
85{
86 struct nexthop *nhop;
87 uint8_t num = 0;
88
89 for (nhop = nhg->nexthop; nhop; nhop = nhop->next)
90 num++;
91
92 return num;
93}
94
454192f4
DS
95uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg)
96{
97 struct nexthop *nhop;
98 uint8_t num = 0;
99
100 for (ALL_NEXTHOPS_PTR(nhg, nhop)) {
101 if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_ACTIVE))
102 num++;
103 }
104
105 return num;
106}
107
98cda54a
SW
108uint8_t
109nexthop_group_active_nexthop_num_no_recurse(const struct nexthop_group *nhg)
110{
111 struct nexthop *nhop;
112 uint8_t num = 0;
113
114 for (nhop = nhg->nexthop; nhop; nhop = nhop->next) {
115 if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_ACTIVE))
116 num++;
117 }
118
119 return num;
120}
121
8f8d9845
SW
122struct nexthop *nexthop_exists(const struct nexthop_group *nhg,
123 const struct nexthop *nh)
31919191
DS
124{
125 struct nexthop *nexthop;
126
127 for (nexthop = nhg->nexthop; nexthop; nexthop = nexthop->next) {
128 if (nexthop_same(nh, nexthop))
129 return nexthop;
130 }
131
132 return NULL;
133}
134
8f8d9845
SW
135bool nexthop_group_equal(const struct nexthop_group *nhg1,
136 const struct nexthop_group *nhg2)
137{
138 struct nexthop *nh = NULL;
139
140 if (nhg1 && !nhg2)
141 return false;
142
143 if (!nhg1 && !nhg2)
144 return false;
145
98cda54a
SW
146 if (nexthop_group_nexthop_num_no_recurse(nhg1)
147 != nexthop_group_nexthop_num_no_recurse(nhg2))
8f8d9845
SW
148 return false;
149
98cda54a 150 for (nh = nhg1->nexthop; nh; nh = nh->next) {
8f8d9845
SW
151 if (!nexthop_exists(nhg2, nh))
152 return false;
153 }
154
155 return true;
156}
157
31919191
DS
158struct nexthop_group *nexthop_group_new(void)
159{
160 return XCALLOC(MTYPE_NEXTHOP_GROUP, sizeof(struct nexthop_group));
161}
162
6c8b51e1
DS
163void nexthop_group_copy(struct nexthop_group *to, struct nexthop_group *from)
164{
165 /* Copy everything, including recursive info */
166 copy_nexthops(&to->nexthop, from->nexthop, NULL);
167}
168
31919191
DS
169void nexthop_group_delete(struct nexthop_group **nhg)
170{
171 XFREE(MTYPE_NEXTHOP_GROUP, *nhg);
172}
173
0c8215cb
SW
174void nexthop_group_free_delete(struct nexthop_group **nhg)
175{
176 if ((*nhg)->nexthop)
177 nexthops_free((*nhg)->nexthop);
178 nexthop_group_delete(nhg);
179}
180
7ee30f28 181/* Add nexthop to the end of a nexthop list. */
50d89650 182void _nexthop_add(struct nexthop **target, struct nexthop *nexthop)
7ee30f28
DS
183{
184 struct nexthop *last;
185
186 for (last = *target; last && last->next; last = last->next)
187 ;
188 if (last)
189 last->next = nexthop;
190 else
191 *target = nexthop;
192 nexthop->prev = last;
193}
194
50d89650
SW
195void _nexthop_group_add_sorted(struct nexthop_group *nhg,
196 struct nexthop *nexthop)
6c8b51e1 197{
8c15fa95
SW
198 struct nexthop *position, *prev, *tail;
199
200 /* Try to just append to the end first
201 * This trust it is already sorted
202 */
203
204 tail = nexthop_group_tail(nhg);
205
206 if (tail && (nexthop_cmp(tail, nexthop) < 0)) {
207 tail->next = nexthop;
208 nexthop->prev = tail;
209
210 return;
211 }
6c8b51e1
DS
212
213 for (position = nhg->nexthop, prev = NULL; position;
214 prev = position, position = position->next) {
215 if (nexthop_cmp(position, nexthop) > 0) {
216 nexthop->next = position;
217 nexthop->prev = prev;
218
219 if (nexthop->prev)
220 nexthop->prev->next = nexthop;
221 else
222 nhg->nexthop = nexthop;
223
224 position->prev = nexthop;
225 return;
226 }
227 }
228
229 nexthop->prev = prev;
230 if (prev)
231 prev->next = nexthop;
232 else
233 nhg->nexthop = nexthop;
6c8b51e1
DS
234}
235
31919191 236/* Delete nexthop from a nexthop list. */
50d89650 237void _nexthop_del(struct nexthop_group *nhg, struct nexthop *nh)
31919191
DS
238{
239 struct nexthop *nexthop;
240
241 for (nexthop = nhg->nexthop; nexthop; nexthop = nexthop->next) {
242 if (nexthop_same(nh, nexthop))
243 break;
244 }
245
246 assert(nexthop);
247
248 if (nexthop->prev)
249 nexthop->prev->next = nexthop->next;
250 else
251 nhg->nexthop = nexthop->next;
252
253 if (nexthop->next)
254 nexthop->next->prev = nexthop->prev;
ebee2bc4
DS
255
256 nh->prev = NULL;
257 nh->next = NULL;
31919191
DS
258}
259
deff170e 260void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh,
7ee30f28
DS
261 struct nexthop *rparent)
262{
263 struct nexthop *nexthop;
deff170e 264 const struct nexthop *nh1;
7ee30f28
DS
265
266 for (nh1 = nh; nh1; nh1 = nh1->next) {
504d0a40 267 nexthop = nexthop_dup(nh1, rparent);
50d89650 268 _nexthop_add(tnh, nexthop);
7ee30f28
DS
269
270 if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE))
271 copy_nexthops(&nexthop->resolved, nh1->resolved,
272 nexthop);
273 }
274}
dba32923 275
2f000944 276uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group *nhg)
1b1fe1c4
SW
277{
278 struct nexthop *nh;
279 uint32_t key = 0;
280
281 /*
282 * We are not interested in hashing over any recursively
283 * resolved nexthops
284 */
285 for (nh = nhg->nexthop; nh; nh = nh->next)
286 key = jhash_1word(nexthop_hash(nh), key);
287
288 return key;
2f000944
SW
289}
290
291uint32_t nexthop_group_hash(const struct nexthop_group *nhg)
292{
293 struct nexthop *nh;
294 uint32_t key = 0;
295
296 for (ALL_NEXTHOPS_PTR(nhg, nh))
297 key = jhash_1word(nexthop_hash(nh), key);
298
299 return key;
1b1fe1c4
SW
300}
301
31919191
DS
302static void nhgc_delete_nexthops(struct nexthop_group_cmd *nhgc)
303{
304 struct nexthop *nexthop;
305
306 nexthop = nhgc->nhg.nexthop;
307 while (nexthop) {
308 struct nexthop *next = nexthop_next(nexthop);
309
50d89650 310 _nexthop_del(&nhgc->nhg, nexthop);
31919191
DS
311 if (nhg_hooks.del_nexthop)
312 nhg_hooks.del_nexthop(nhgc, nexthop);
313
314 nexthop_free(nexthop);
315
316 nexthop = next;
317 }
318}
319
d604266c 320struct nexthop_group_cmd *nhgc_find(const char *name)
31919191
DS
321{
322 struct nexthop_group_cmd find;
323
324 strlcpy(find.name, name, sizeof(find.name));
325
326 return RB_FIND(nhgc_entry_head, &nhgc_entries, &find);
327}
328
c57bd6bb
DS
329static int nhgc_cmp_helper(const char *a, const char *b)
330{
331 if (!a && !b)
332 return 0;
333
334 if (a && !b)
335 return -1;
336
337 if (!a && b)
338 return 1;
339
340 return strcmp(a, b);
341}
342
1c869b64
RW
343static int nhgc_addr_cmp_helper(const union sockunion *a, const union sockunion *b)
344{
345 if (!a && !b)
346 return 0;
347
348 if (a && !b)
349 return -1;
350
351 if (!a && b)
352 return 1;
353
354 return sockunion_cmp(a, b);
355}
356
c57bd6bb
DS
357static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
358{
359 int ret;
360
1c869b64 361 ret = nhgc_addr_cmp_helper(nh1->addr, nh2->addr);
c57bd6bb
DS
362 if (ret)
363 return ret;
364
365 ret = nhgc_cmp_helper(nh1->intf, nh2->intf);
366 if (ret)
367 return ret;
368
369 return nhgc_cmp_helper(nh1->nhvrf_name, nh2->nhvrf_name);
370}
371
372static void nhgl_delete(struct nexthop_hold *nh)
373{
0a22ddfb 374 XFREE(MTYPE_TMP, nh->intf);
c57bd6bb 375
0a22ddfb 376 XFREE(MTYPE_TMP, nh->nhvrf_name);
c57bd6bb 377
1c869b64
RW
378 if (nh->addr)
379 sockunion_free(nh->addr);
b43bb64f 380
c57bd6bb
DS
381 XFREE(MTYPE_TMP, nh);
382}
383
31919191
DS
384static struct nexthop_group_cmd *nhgc_get(const char *name)
385{
386 struct nexthop_group_cmd *nhgc;
387
388 nhgc = nhgc_find(name);
389 if (!nhgc) {
390 nhgc = XCALLOC(MTYPE_TMP, sizeof(*nhgc));
391 strlcpy(nhgc->name, name, sizeof(nhgc->name));
392
393 QOBJ_REG(nhgc, nexthop_group_cmd);
394 RB_INSERT(nhgc_entry_head, &nhgc_entries, nhgc);
395
c57bd6bb
DS
396 nhgc->nhg_list = list_new();
397 nhgc->nhg_list->cmp = (int (*)(void *, void *))nhgl_cmp;
398 nhgc->nhg_list->del = (void (*)(void *))nhgl_delete;
399
31919191
DS
400 if (nhg_hooks.new)
401 nhg_hooks.new(name);
402 }
403
404 return nhgc;
405}
406
407static void nhgc_delete(struct nexthop_group_cmd *nhgc)
dba32923 408{
31919191
DS
409 nhgc_delete_nexthops(nhgc);
410
411 if (nhg_hooks.delete)
412 nhg_hooks.delete(nhgc->name);
413
414 RB_REMOVE(nhgc_entry_head, &nhgc_entries, nhgc);
c57bd6bb 415
6a154c88 416 list_delete(&nhgc->nhg_list);
c57bd6bb
DS
417
418 XFREE(MTYPE_TMP, nhgc);
31919191
DS
419}
420
421DEFINE_QOBJ_TYPE(nexthop_group_cmd)
422
868ee86c 423DEFUN_NOSH(nexthop_group, nexthop_group_cmd, "nexthop-group NHGNAME",
31919191
DS
424 "Enter into the nexthop-group submode\n"
425 "Specify the NAME of the nexthop-group\n")
426{
427 const char *nhg_name = argv[1]->arg;
428 struct nexthop_group_cmd *nhgc = NULL;
429
430 nhgc = nhgc_get(nhg_name);
431 VTY_PUSH_CONTEXT(NH_GROUP_NODE, nhgc);
432
433 return CMD_SUCCESS;
434}
435
868ee86c 436DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NHGNAME",
31919191
DS
437 NO_STR
438 "Delete the nexthop-group\n"
439 "Specify the NAME of the nexthop-group\n")
440{
441 const char *nhg_name = argv[2]->arg;
442 struct nexthop_group_cmd *nhgc = NULL;
443
444 nhgc = nhgc_find(nhg_name);
445 if (nhgc)
446 nhgc_delete(nhgc);
447
448 return CMD_SUCCESS;
449}
450
c57bd6bb
DS
451static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
452 const char *nhvrf_name,
453 const union sockunion *addr,
454 const char *intf)
455{
456 struct nexthop_hold *nh;
457
458 nh = XCALLOC(MTYPE_TMP, sizeof(*nh));
459
460 if (nhvrf_name)
461 nh->nhvrf_name = XSTRDUP(MTYPE_TMP, nhvrf_name);
462 if (intf)
463 nh->intf = XSTRDUP(MTYPE_TMP, intf);
1c869b64
RW
464 if (addr)
465 nh->addr = sockunion_dup(addr);
c57bd6bb
DS
466
467 listnode_add_sort(nhgc->nhg_list, nh);
468}
469
470static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
471 const char *nhvrf_name,
472 const union sockunion *addr,
473 const char *intf)
474{
475 struct nexthop_hold *nh;
476 struct listnode *node;
477
478 for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
479 if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 &&
1c869b64 480 nhgc_addr_cmp_helper(addr, nh->addr) == 0 &&
c57bd6bb
DS
481 nhgc_cmp_helper(intf, nh->intf) == 0)
482 break;
483 }
484
485 /*
486 * Something has gone seriously wrong, fail gracefully
487 */
488 if (!nh)
489 return;
490
491 list_delete_node(nhgc->nhg_list, node);
e5a501c2 492 nhgl_delete(nh);
c57bd6bb
DS
493}
494
98cbbaea
DS
495static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
496 const union sockunion *addr,
497 const char *intf, const char *name)
31919191 498{
31919191 499 struct vrf *vrf;
98cbbaea
DS
500
501 memset(nhop, 0, sizeof(*nhop));
31919191
DS
502
503 if (name)
504 vrf = vrf_lookup_by_name(name);
505 else
506 vrf = vrf_lookup_by_id(VRF_DEFAULT);
507
98cbbaea
DS
508 if (!vrf)
509 return false;
31919191 510
98cbbaea 511 nhop->vrf_id = vrf->vrf_id;
31919191 512
1c869b64
RW
513 if (intf) {
514 nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
515 if (nhop->ifindex == IFINDEX_INTERNAL)
516 return false;
98cbbaea
DS
517 }
518
1c869b64
RW
519 if (addr) {
520 if (addr->sa.sa_family == AF_INET) {
521 nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
522 if (intf)
523 nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
524 else
525 nhop->type = NEXTHOP_TYPE_IPV4;
526 } else {
527 nhop->gate.ipv6 = addr->sin6.sin6_addr;
528 if (intf)
529 nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
530 else
531 nhop->type = NEXTHOP_TYPE_IPV6;
532 }
533 } else
534 nhop->type = NEXTHOP_TYPE_IFINDEX;
535
98cbbaea
DS
536 return true;
537}
538
539DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
1c869b64
RW
540 "[no] nexthop\
541 <\
542 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
543 |INTERFACE$intf\
544 >\
e429a2a0 545 [nexthop-vrf NAME$vrf_name]",
98cbbaea
DS
546 NO_STR
547 "Specify one of the nexthops in this ECMP group\n"
548 "v4 Address\n"
549 "v6 Address\n"
550 "Interface to use\n"
1c869b64 551 "Interface to use\n"
98cbbaea
DS
552 "If the nexthop is in a different vrf tell us\n"
553 "The nexthop-vrf Name\n")
554{
555 VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
556 struct nexthop nhop;
557 struct nexthop *nh;
558 bool legal;
559
e429a2a0 560 legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name);
98cbbaea
DS
561
562 if (nhop.type == NEXTHOP_TYPE_IPV6
563 && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
564 vty_out(vty,
565 "Specified a v6 LL with no interface, rejecting\n");
566 return CMD_WARNING_CONFIG_FAILED;
31919191
DS
567 }
568
569 nh = nexthop_exists(&nhgc->nhg, &nhop);
570
571 if (no) {
e429a2a0 572 nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf);
31919191 573 if (nh) {
50d89650 574 _nexthop_del(&nhgc->nhg, nh);
31919191
DS
575
576 if (nhg_hooks.del_nexthop)
577 nhg_hooks.del_nexthop(nhgc, nh);
578
579 nexthop_free(nh);
580 }
581 } else if (!nh) {
582 /* must be adding new nexthop since !no and !nexthop_exists */
98cbbaea
DS
583 if (legal) {
584 nh = nexthop_new();
31919191 585
98cbbaea 586 memcpy(nh, &nhop, sizeof(nhop));
50d89650 587 _nexthop_add(&nhgc->nhg.nexthop, nh);
98cbbaea 588 }
31919191 589
e429a2a0 590 nexthop_group_save_nhop(nhgc, vrf_name, addr, intf);
c57bd6bb 591
98cbbaea 592 if (legal && nhg_hooks.add_nexthop)
31919191
DS
593 nhg_hooks.add_nexthop(nhgc, nh);
594 }
595
dba32923
DS
596 return CMD_SUCCESS;
597}
598
599struct cmd_node nexthop_group_node = {
600 NH_GROUP_NODE,
601 "%s(config-nh-group)# ",
602 1
603};
604
1b7bce04
DS
605void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
606{
607 char buf[100];
608 struct vrf *vrf;
609
57cdafc4 610 vty_out(vty, "nexthop ");
1b7bce04
DS
611
612 switch (nh->type) {
613 case NEXTHOP_TYPE_IFINDEX:
614 vty_out(vty, "%s", ifindex2ifname(nh->ifindex, nh->vrf_id));
615 break;
616 case NEXTHOP_TYPE_IPV4:
617 vty_out(vty, "%s", inet_ntoa(nh->gate.ipv4));
618 break;
619 case NEXTHOP_TYPE_IPV4_IFINDEX:
620 vty_out(vty, "%s %s", inet_ntoa(nh->gate.ipv4),
621 ifindex2ifname(nh->ifindex, nh->vrf_id));
622 break;
623 case NEXTHOP_TYPE_IPV6:
624 vty_out(vty, "%s",
625 inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf)));
626 break;
627 case NEXTHOP_TYPE_IPV6_IFINDEX:
628 vty_out(vty, "%s %s",
629 inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf)),
630 ifindex2ifname(nh->ifindex, nh->vrf_id));
631 break;
632 case NEXTHOP_TYPE_BLACKHOLE:
633 break;
634 }
635
636 if (nh->vrf_id != VRF_DEFAULT) {
637 vrf = vrf_lookup_by_id(nh->vrf_id);
638 vty_out(vty, " nexthop-vrf %s", vrf->name);
639 }
640 vty_out(vty, "\n");
641}
642
c57bd6bb
DS
643static void nexthop_group_write_nexthop_internal(struct vty *vty,
644 struct nexthop_hold *nh)
645{
646 char buf[100];
647
1c869b64 648 vty_out(vty, "nexthop");
c57bd6bb 649
1c869b64
RW
650 if (nh->addr)
651 vty_out(vty, " %s", sockunion2str(nh->addr, buf, sizeof(buf)));
c57bd6bb
DS
652
653 if (nh->intf)
654 vty_out(vty, " %s", nh->intf);
655
656 if (nh->nhvrf_name)
657 vty_out(vty, " nexthop-vrf %s", nh->nhvrf_name);
658
659 vty_out(vty, "\n");
660}
661
dba32923
DS
662static int nexthop_group_write(struct vty *vty)
663{
31919191 664 struct nexthop_group_cmd *nhgc;
c57bd6bb 665 struct nexthop_hold *nh;
31919191
DS
666
667 RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
c57bd6bb
DS
668 struct listnode *node;
669
31919191
DS
670 vty_out(vty, "nexthop-group %s\n", nhgc->name);
671
c57bd6bb 672 for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
7dce96f0 673 vty_out(vty, " ");
c57bd6bb 674 nexthop_group_write_nexthop_internal(vty, nh);
811f859f 675 }
31919191 676
31919191
DS
677 vty_out(vty, "!\n");
678 }
dba32923
DS
679
680 return 1;
681}
682
98cbbaea
DS
683void nexthop_group_enable_vrf(struct vrf *vrf)
684{
685 struct nexthop_group_cmd *nhgc;
686 struct nexthop_hold *nhh;
687
688 RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
689 struct listnode *node;
690
691 for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
692 struct nexthop nhop;
693 struct nexthop *nh;
694
b43bb64f 695 if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
98cbbaea
DS
696 nhh->intf,
697 nhh->nhvrf_name))
698 continue;
699
700 nh = nexthop_exists(&nhgc->nhg, &nhop);
701
702 if (nh)
703 continue;
704
705 if (nhop.vrf_id != vrf->vrf_id)
706 continue;
707
708 nh = nexthop_new();
709
710 memcpy(nh, &nhop, sizeof(nhop));
50d89650 711 _nexthop_add(&nhgc->nhg.nexthop, nh);
98cbbaea
DS
712
713 if (nhg_hooks.add_nexthop)
714 nhg_hooks.add_nexthop(nhgc, nh);
715 }
716 }
717}
718
719void nexthop_group_disable_vrf(struct vrf *vrf)
720{
721 struct nexthop_group_cmd *nhgc;
722 struct nexthop_hold *nhh;
723
724 RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
725 struct listnode *node;
726
727 for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
728 struct nexthop nhop;
729 struct nexthop *nh;
730
b43bb64f 731 if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
98cbbaea
DS
732 nhh->intf,
733 nhh->nhvrf_name))
734 continue;
735
736 nh = nexthop_exists(&nhgc->nhg, &nhop);
737
738 if (!nh)
739 continue;
740
741 if (nh->vrf_id != vrf->vrf_id)
742 continue;
743
50d89650 744 _nexthop_del(&nhgc->nhg, nh);
98cbbaea
DS
745
746 if (nhg_hooks.del_nexthop)
747 nhg_hooks.del_nexthop(nhgc, nh);
748
749 nexthop_free(nh);
750 }
751 }
752}
753
754void nexthop_group_interface_state_change(struct interface *ifp,
755 ifindex_t oldifindex)
756{
757 struct nexthop_group_cmd *nhgc;
758 struct nexthop_hold *nhh;
759
760 RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
761 struct listnode *node;
762 struct nexthop *nh;
763
764 if (if_is_up(ifp)) {
765 for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
766 struct nexthop nhop;
767
768 if (!nexthop_group_parse_nexthop(
b43bb64f 769 &nhop, nhh->addr, nhh->intf,
98cbbaea
DS
770 nhh->nhvrf_name))
771 continue;
772
773 switch (nhop.type) {
774 case NEXTHOP_TYPE_IPV4:
775 case NEXTHOP_TYPE_IPV6:
776 case NEXTHOP_TYPE_BLACKHOLE:
777 continue;
778 case NEXTHOP_TYPE_IFINDEX:
779 case NEXTHOP_TYPE_IPV4_IFINDEX:
780 case NEXTHOP_TYPE_IPV6_IFINDEX:
781 break;
782 }
783 nh = nexthop_exists(&nhgc->nhg, &nhop);
784
785 if (nh)
786 continue;
787
788 if (ifp->ifindex != nhop.ifindex)
789 continue;
790
791 nh = nexthop_new();
792
793 memcpy(nh, &nhop, sizeof(nhop));
50d89650 794 _nexthop_add(&nhgc->nhg.nexthop, nh);
98cbbaea
DS
795
796 if (nhg_hooks.add_nexthop)
797 nhg_hooks.add_nexthop(nhgc, nh);
798 }
799 } else {
800 struct nexthop *next_nh;
801
802 for (nh = nhgc->nhg.nexthop; nh; nh = next_nh) {
803 next_nh = nh->next;
804 switch (nh->type) {
805 case NEXTHOP_TYPE_IPV4:
806 case NEXTHOP_TYPE_IPV6:
807 case NEXTHOP_TYPE_BLACKHOLE:
808 continue;
809 case NEXTHOP_TYPE_IFINDEX:
810 case NEXTHOP_TYPE_IPV4_IFINDEX:
811 case NEXTHOP_TYPE_IPV6_IFINDEX:
812 break;
813 }
814
815 if (oldifindex != nh->ifindex)
816 continue;
817
50d89650 818 _nexthop_del(&nhgc->nhg, nh);
98cbbaea
DS
819
820 if (nhg_hooks.del_nexthop)
821 nhg_hooks.del_nexthop(nhgc, nh);
822
823 nexthop_free(nh);
824 }
825 }
826 }
827}
828
868ee86c
DS
829static void nhg_name_autocomplete(vector comps, struct cmd_token *token)
830{
831 struct nexthop_group_cmd *nhgc;
832
833 RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
834 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, nhgc->name));
835 }
836}
837
838static const struct cmd_variable_handler nhg_name_handlers[] = {
839 {.tokenname = "NHGNAME", .completions = nhg_name_autocomplete},
840 {.completions = NULL}};
841
31919191
DS
842void nexthop_group_init(void (*new)(const char *name),
843 void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
844 const struct nexthop *nhop),
845 void (*del_nexthop)(const struct nexthop_group_cmd *nhg,
846 const struct nexthop *nhop),
847 void (*delete)(const char *name))
dba32923 848{
31919191
DS
849 RB_INIT(nhgc_entry_head, &nhgc_entries);
850
868ee86c
DS
851 cmd_variable_handler_register(nhg_name_handlers);
852
dba32923
DS
853 install_node(&nexthop_group_node, nexthop_group_write);
854 install_element(CONFIG_NODE, &nexthop_group_cmd);
31919191
DS
855 install_element(CONFIG_NODE, &no_nexthop_group_cmd);
856
857 install_default(NH_GROUP_NODE);
858 install_element(NH_GROUP_NODE, &ecmp_nexthops_cmd);
859
860 memset(&nhg_hooks, 0, sizeof(nhg_hooks));
861
862 if (new)
863 nhg_hooks.new = new;
864 if (add_nexthop)
865 nhg_hooks.add_nexthop = add_nexthop;
866 if (del_nexthop)
867 nhg_hooks.del_nexthop = del_nexthop;
868 if (delete)
869 nhg_hooks.delete = delete;
dba32923 870}