]> git.proxmox.com Git - mirror_frr.git/blame - lib/nexthop_group.c
Merge pull request #4841 from rtrlib/2019-08-16-bugfix-master
[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
454192f4
DS
63uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg)
64{
65 struct nexthop *nhop;
66 uint8_t num = 0;
67
68 for (ALL_NEXTHOPS_PTR(nhg, nhop))
69 num++;
70
71 return num;
72}
73
74uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group *nhg)
75{
76 struct nexthop *nhop;
77 uint8_t num = 0;
78
79 for (ALL_NEXTHOPS_PTR(nhg, nhop)) {
80 if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_ACTIVE))
81 num++;
82 }
83
84 return num;
85}
86
31919191
DS
87struct nexthop *nexthop_exists(struct nexthop_group *nhg, struct nexthop *nh)
88{
89 struct nexthop *nexthop;
90
91 for (nexthop = nhg->nexthop; nexthop; nexthop = nexthop->next) {
92 if (nexthop_same(nh, nexthop))
93 return nexthop;
94 }
95
96 return NULL;
97}
98
99struct nexthop_group *nexthop_group_new(void)
100{
101 return XCALLOC(MTYPE_NEXTHOP_GROUP, sizeof(struct nexthop_group));
102}
103
6c8b51e1
DS
104void nexthop_group_copy(struct nexthop_group *to, struct nexthop_group *from)
105{
106 /* Copy everything, including recursive info */
107 copy_nexthops(&to->nexthop, from->nexthop, NULL);
108}
109
31919191
DS
110void nexthop_group_delete(struct nexthop_group **nhg)
111{
112 XFREE(MTYPE_NEXTHOP_GROUP, *nhg);
113}
114
7ee30f28 115/* Add nexthop to the end of a nexthop list. */
50d89650 116void _nexthop_add(struct nexthop **target, struct nexthop *nexthop)
7ee30f28
DS
117{
118 struct nexthop *last;
119
120 for (last = *target; last && last->next; last = last->next)
121 ;
122 if (last)
123 last->next = nexthop;
124 else
125 *target = nexthop;
126 nexthop->prev = last;
127}
128
50d89650
SW
129void _nexthop_group_add_sorted(struct nexthop_group *nhg,
130 struct nexthop *nexthop)
6c8b51e1
DS
131{
132 struct nexthop *position, *prev;
133
134 for (position = nhg->nexthop, prev = NULL; position;
135 prev = position, position = position->next) {
136 if (nexthop_cmp(position, nexthop) > 0) {
137 nexthop->next = position;
138 nexthop->prev = prev;
139
140 if (nexthop->prev)
141 nexthop->prev->next = nexthop;
142 else
143 nhg->nexthop = nexthop;
144
145 position->prev = nexthop;
146 return;
147 }
148 }
149
150 nexthop->prev = prev;
151 if (prev)
152 prev->next = nexthop;
153 else
154 nhg->nexthop = nexthop;
6c8b51e1
DS
155}
156
31919191 157/* Delete nexthop from a nexthop list. */
50d89650 158void _nexthop_del(struct nexthop_group *nhg, struct nexthop *nh)
31919191
DS
159{
160 struct nexthop *nexthop;
161
162 for (nexthop = nhg->nexthop; nexthop; nexthop = nexthop->next) {
163 if (nexthop_same(nh, nexthop))
164 break;
165 }
166
167 assert(nexthop);
168
169 if (nexthop->prev)
170 nexthop->prev->next = nexthop->next;
171 else
172 nhg->nexthop = nexthop->next;
173
174 if (nexthop->next)
175 nexthop->next->prev = nexthop->prev;
ebee2bc4
DS
176
177 nh->prev = NULL;
178 nh->next = NULL;
31919191
DS
179}
180
deff170e 181void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh,
7ee30f28
DS
182 struct nexthop *rparent)
183{
184 struct nexthop *nexthop;
deff170e 185 const struct nexthop *nh1;
7ee30f28
DS
186
187 for (nh1 = nh; nh1; nh1 = nh1->next) {
504d0a40 188 nexthop = nexthop_dup(nh1, rparent);
50d89650 189 _nexthop_add(tnh, nexthop);
7ee30f28
DS
190
191 if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE))
192 copy_nexthops(&nexthop->resolved, nh1->resolved,
193 nexthop);
194 }
195}
dba32923 196
1b1fe1c4
SW
197uint32_t nexthop_group_hash(const struct nexthop_group *nhg)
198{
199 struct nexthop *nh;
200 uint32_t key = 0;
201
202 /*
203 * We are not interested in hashing over any recursively
204 * resolved nexthops
205 */
206 for (nh = nhg->nexthop; nh; nh = nh->next)
207 key = jhash_1word(nexthop_hash(nh), key);
208
209 return key;
210}
211
31919191
DS
212static void nhgc_delete_nexthops(struct nexthop_group_cmd *nhgc)
213{
214 struct nexthop *nexthop;
215
216 nexthop = nhgc->nhg.nexthop;
217 while (nexthop) {
218 struct nexthop *next = nexthop_next(nexthop);
219
50d89650 220 _nexthop_del(&nhgc->nhg, nexthop);
31919191
DS
221 if (nhg_hooks.del_nexthop)
222 nhg_hooks.del_nexthop(nhgc, nexthop);
223
224 nexthop_free(nexthop);
225
226 nexthop = next;
227 }
228}
229
d604266c 230struct nexthop_group_cmd *nhgc_find(const char *name)
31919191
DS
231{
232 struct nexthop_group_cmd find;
233
234 strlcpy(find.name, name, sizeof(find.name));
235
236 return RB_FIND(nhgc_entry_head, &nhgc_entries, &find);
237}
238
c57bd6bb
DS
239static int nhgc_cmp_helper(const char *a, const char *b)
240{
241 if (!a && !b)
242 return 0;
243
244 if (a && !b)
245 return -1;
246
247 if (!a && b)
248 return 1;
249
250 return strcmp(a, b);
251}
252
1c869b64
RW
253static int nhgc_addr_cmp_helper(const union sockunion *a, const union sockunion *b)
254{
255 if (!a && !b)
256 return 0;
257
258 if (a && !b)
259 return -1;
260
261 if (!a && b)
262 return 1;
263
264 return sockunion_cmp(a, b);
265}
266
c57bd6bb
DS
267static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)
268{
269 int ret;
270
1c869b64 271 ret = nhgc_addr_cmp_helper(nh1->addr, nh2->addr);
c57bd6bb
DS
272 if (ret)
273 return ret;
274
275 ret = nhgc_cmp_helper(nh1->intf, nh2->intf);
276 if (ret)
277 return ret;
278
279 return nhgc_cmp_helper(nh1->nhvrf_name, nh2->nhvrf_name);
280}
281
282static void nhgl_delete(struct nexthop_hold *nh)
283{
0a22ddfb 284 XFREE(MTYPE_TMP, nh->intf);
c57bd6bb 285
0a22ddfb 286 XFREE(MTYPE_TMP, nh->nhvrf_name);
c57bd6bb 287
1c869b64
RW
288 if (nh->addr)
289 sockunion_free(nh->addr);
b43bb64f 290
c57bd6bb
DS
291 XFREE(MTYPE_TMP, nh);
292}
293
31919191
DS
294static struct nexthop_group_cmd *nhgc_get(const char *name)
295{
296 struct nexthop_group_cmd *nhgc;
297
298 nhgc = nhgc_find(name);
299 if (!nhgc) {
300 nhgc = XCALLOC(MTYPE_TMP, sizeof(*nhgc));
301 strlcpy(nhgc->name, name, sizeof(nhgc->name));
302
303 QOBJ_REG(nhgc, nexthop_group_cmd);
304 RB_INSERT(nhgc_entry_head, &nhgc_entries, nhgc);
305
c57bd6bb
DS
306 nhgc->nhg_list = list_new();
307 nhgc->nhg_list->cmp = (int (*)(void *, void *))nhgl_cmp;
308 nhgc->nhg_list->del = (void (*)(void *))nhgl_delete;
309
31919191
DS
310 if (nhg_hooks.new)
311 nhg_hooks.new(name);
312 }
313
314 return nhgc;
315}
316
317static void nhgc_delete(struct nexthop_group_cmd *nhgc)
dba32923 318{
31919191
DS
319 nhgc_delete_nexthops(nhgc);
320
321 if (nhg_hooks.delete)
322 nhg_hooks.delete(nhgc->name);
323
324 RB_REMOVE(nhgc_entry_head, &nhgc_entries, nhgc);
c57bd6bb 325
6a154c88 326 list_delete(&nhgc->nhg_list);
c57bd6bb
DS
327
328 XFREE(MTYPE_TMP, nhgc);
31919191
DS
329}
330
331DEFINE_QOBJ_TYPE(nexthop_group_cmd)
332
868ee86c 333DEFUN_NOSH(nexthop_group, nexthop_group_cmd, "nexthop-group NHGNAME",
31919191
DS
334 "Enter into the nexthop-group submode\n"
335 "Specify the NAME of the nexthop-group\n")
336{
337 const char *nhg_name = argv[1]->arg;
338 struct nexthop_group_cmd *nhgc = NULL;
339
340 nhgc = nhgc_get(nhg_name);
341 VTY_PUSH_CONTEXT(NH_GROUP_NODE, nhgc);
342
343 return CMD_SUCCESS;
344}
345
868ee86c 346DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NHGNAME",
31919191
DS
347 NO_STR
348 "Delete the nexthop-group\n"
349 "Specify the NAME of the nexthop-group\n")
350{
351 const char *nhg_name = argv[2]->arg;
352 struct nexthop_group_cmd *nhgc = NULL;
353
354 nhgc = nhgc_find(nhg_name);
355 if (nhgc)
356 nhgc_delete(nhgc);
357
358 return CMD_SUCCESS;
359}
360
c57bd6bb
DS
361static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
362 const char *nhvrf_name,
363 const union sockunion *addr,
364 const char *intf)
365{
366 struct nexthop_hold *nh;
367
368 nh = XCALLOC(MTYPE_TMP, sizeof(*nh));
369
370 if (nhvrf_name)
371 nh->nhvrf_name = XSTRDUP(MTYPE_TMP, nhvrf_name);
372 if (intf)
373 nh->intf = XSTRDUP(MTYPE_TMP, intf);
1c869b64
RW
374 if (addr)
375 nh->addr = sockunion_dup(addr);
c57bd6bb
DS
376
377 listnode_add_sort(nhgc->nhg_list, nh);
378}
379
380static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,
381 const char *nhvrf_name,
382 const union sockunion *addr,
383 const char *intf)
384{
385 struct nexthop_hold *nh;
386 struct listnode *node;
387
388 for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
389 if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 &&
1c869b64 390 nhgc_addr_cmp_helper(addr, nh->addr) == 0 &&
c57bd6bb
DS
391 nhgc_cmp_helper(intf, nh->intf) == 0)
392 break;
393 }
394
395 /*
396 * Something has gone seriously wrong, fail gracefully
397 */
398 if (!nh)
399 return;
400
401 list_delete_node(nhgc->nhg_list, node);
e5a501c2 402 nhgl_delete(nh);
c57bd6bb
DS
403}
404
98cbbaea
DS
405static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
406 const union sockunion *addr,
407 const char *intf, const char *name)
31919191 408{
31919191 409 struct vrf *vrf;
98cbbaea
DS
410
411 memset(nhop, 0, sizeof(*nhop));
31919191
DS
412
413 if (name)
414 vrf = vrf_lookup_by_name(name);
415 else
416 vrf = vrf_lookup_by_id(VRF_DEFAULT);
417
98cbbaea
DS
418 if (!vrf)
419 return false;
31919191 420
98cbbaea 421 nhop->vrf_id = vrf->vrf_id;
31919191 422
1c869b64
RW
423 if (intf) {
424 nhop->ifindex = ifname2ifindex(intf, vrf->vrf_id);
425 if (nhop->ifindex == IFINDEX_INTERNAL)
426 return false;
98cbbaea
DS
427 }
428
1c869b64
RW
429 if (addr) {
430 if (addr->sa.sa_family == AF_INET) {
431 nhop->gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
432 if (intf)
433 nhop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
434 else
435 nhop->type = NEXTHOP_TYPE_IPV4;
436 } else {
437 nhop->gate.ipv6 = addr->sin6.sin6_addr;
438 if (intf)
439 nhop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
440 else
441 nhop->type = NEXTHOP_TYPE_IPV6;
442 }
443 } else
444 nhop->type = NEXTHOP_TYPE_IFINDEX;
445
98cbbaea
DS
446 return true;
447}
448
449DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
1c869b64
RW
450 "[no] nexthop\
451 <\
452 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
453 |INTERFACE$intf\
454 >\
455 [nexthop-vrf NAME$name]",
98cbbaea
DS
456 NO_STR
457 "Specify one of the nexthops in this ECMP group\n"
458 "v4 Address\n"
459 "v6 Address\n"
460 "Interface to use\n"
1c869b64 461 "Interface to use\n"
98cbbaea
DS
462 "If the nexthop is in a different vrf tell us\n"
463 "The nexthop-vrf Name\n")
464{
465 VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
466 struct nexthop nhop;
467 struct nexthop *nh;
468 bool legal;
469
470 legal = nexthop_group_parse_nexthop(&nhop, addr, intf, name);
471
472 if (nhop.type == NEXTHOP_TYPE_IPV6
473 && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
474 vty_out(vty,
475 "Specified a v6 LL with no interface, rejecting\n");
476 return CMD_WARNING_CONFIG_FAILED;
31919191
DS
477 }
478
479 nh = nexthop_exists(&nhgc->nhg, &nhop);
480
481 if (no) {
98cbbaea 482 nexthop_group_unsave_nhop(nhgc, name, addr, intf);
31919191 483 if (nh) {
50d89650 484 _nexthop_del(&nhgc->nhg, nh);
31919191
DS
485
486 if (nhg_hooks.del_nexthop)
487 nhg_hooks.del_nexthop(nhgc, nh);
488
489 nexthop_free(nh);
490 }
491 } else if (!nh) {
492 /* must be adding new nexthop since !no and !nexthop_exists */
98cbbaea
DS
493 if (legal) {
494 nh = nexthop_new();
31919191 495
98cbbaea 496 memcpy(nh, &nhop, sizeof(nhop));
50d89650 497 _nexthop_add(&nhgc->nhg.nexthop, nh);
98cbbaea 498 }
31919191 499
c57bd6bb
DS
500 nexthop_group_save_nhop(nhgc, name, addr, intf);
501
98cbbaea 502 if (legal && nhg_hooks.add_nexthop)
31919191
DS
503 nhg_hooks.add_nexthop(nhgc, nh);
504 }
505
dba32923
DS
506 return CMD_SUCCESS;
507}
508
509struct cmd_node nexthop_group_node = {
510 NH_GROUP_NODE,
511 "%s(config-nh-group)# ",
512 1
513};
514
1b7bce04
DS
515void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
516{
517 char buf[100];
518 struct vrf *vrf;
519
57cdafc4 520 vty_out(vty, "nexthop ");
1b7bce04
DS
521
522 switch (nh->type) {
523 case NEXTHOP_TYPE_IFINDEX:
524 vty_out(vty, "%s", ifindex2ifname(nh->ifindex, nh->vrf_id));
525 break;
526 case NEXTHOP_TYPE_IPV4:
527 vty_out(vty, "%s", inet_ntoa(nh->gate.ipv4));
528 break;
529 case NEXTHOP_TYPE_IPV4_IFINDEX:
530 vty_out(vty, "%s %s", inet_ntoa(nh->gate.ipv4),
531 ifindex2ifname(nh->ifindex, nh->vrf_id));
532 break;
533 case NEXTHOP_TYPE_IPV6:
534 vty_out(vty, "%s",
535 inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf)));
536 break;
537 case NEXTHOP_TYPE_IPV6_IFINDEX:
538 vty_out(vty, "%s %s",
539 inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf)),
540 ifindex2ifname(nh->ifindex, nh->vrf_id));
541 break;
542 case NEXTHOP_TYPE_BLACKHOLE:
543 break;
544 }
545
546 if (nh->vrf_id != VRF_DEFAULT) {
547 vrf = vrf_lookup_by_id(nh->vrf_id);
548 vty_out(vty, " nexthop-vrf %s", vrf->name);
549 }
550 vty_out(vty, "\n");
551}
552
c57bd6bb
DS
553static void nexthop_group_write_nexthop_internal(struct vty *vty,
554 struct nexthop_hold *nh)
555{
556 char buf[100];
557
1c869b64 558 vty_out(vty, "nexthop");
c57bd6bb 559
1c869b64
RW
560 if (nh->addr)
561 vty_out(vty, " %s", sockunion2str(nh->addr, buf, sizeof(buf)));
c57bd6bb
DS
562
563 if (nh->intf)
564 vty_out(vty, " %s", nh->intf);
565
566 if (nh->nhvrf_name)
567 vty_out(vty, " nexthop-vrf %s", nh->nhvrf_name);
568
569 vty_out(vty, "\n");
570}
571
dba32923
DS
572static int nexthop_group_write(struct vty *vty)
573{
31919191 574 struct nexthop_group_cmd *nhgc;
c57bd6bb 575 struct nexthop_hold *nh;
31919191
DS
576
577 RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
c57bd6bb
DS
578 struct listnode *node;
579
31919191
DS
580 vty_out(vty, "nexthop-group %s\n", nhgc->name);
581
c57bd6bb 582 for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
7dce96f0 583 vty_out(vty, " ");
c57bd6bb 584 nexthop_group_write_nexthop_internal(vty, nh);
811f859f 585 }
31919191 586
31919191
DS
587 vty_out(vty, "!\n");
588 }
dba32923
DS
589
590 return 1;
591}
592
98cbbaea
DS
593void nexthop_group_enable_vrf(struct vrf *vrf)
594{
595 struct nexthop_group_cmd *nhgc;
596 struct nexthop_hold *nhh;
597
598 RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
599 struct listnode *node;
600
601 for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
602 struct nexthop nhop;
603 struct nexthop *nh;
604
b43bb64f 605 if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
98cbbaea
DS
606 nhh->intf,
607 nhh->nhvrf_name))
608 continue;
609
610 nh = nexthop_exists(&nhgc->nhg, &nhop);
611
612 if (nh)
613 continue;
614
615 if (nhop.vrf_id != vrf->vrf_id)
616 continue;
617
618 nh = nexthop_new();
619
620 memcpy(nh, &nhop, sizeof(nhop));
50d89650 621 _nexthop_add(&nhgc->nhg.nexthop, nh);
98cbbaea
DS
622
623 if (nhg_hooks.add_nexthop)
624 nhg_hooks.add_nexthop(nhgc, nh);
625 }
626 }
627}
628
629void nexthop_group_disable_vrf(struct vrf *vrf)
630{
631 struct nexthop_group_cmd *nhgc;
632 struct nexthop_hold *nhh;
633
634 RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
635 struct listnode *node;
636
637 for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
638 struct nexthop nhop;
639 struct nexthop *nh;
640
b43bb64f 641 if (!nexthop_group_parse_nexthop(&nhop, nhh->addr,
98cbbaea
DS
642 nhh->intf,
643 nhh->nhvrf_name))
644 continue;
645
646 nh = nexthop_exists(&nhgc->nhg, &nhop);
647
648 if (!nh)
649 continue;
650
651 if (nh->vrf_id != vrf->vrf_id)
652 continue;
653
50d89650 654 _nexthop_del(&nhgc->nhg, nh);
98cbbaea
DS
655
656 if (nhg_hooks.del_nexthop)
657 nhg_hooks.del_nexthop(nhgc, nh);
658
659 nexthop_free(nh);
660 }
661 }
662}
663
664void nexthop_group_interface_state_change(struct interface *ifp,
665 ifindex_t oldifindex)
666{
667 struct nexthop_group_cmd *nhgc;
668 struct nexthop_hold *nhh;
669
670 RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
671 struct listnode *node;
672 struct nexthop *nh;
673
674 if (if_is_up(ifp)) {
675 for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {
676 struct nexthop nhop;
677
678 if (!nexthop_group_parse_nexthop(
b43bb64f 679 &nhop, nhh->addr, nhh->intf,
98cbbaea
DS
680 nhh->nhvrf_name))
681 continue;
682
683 switch (nhop.type) {
684 case NEXTHOP_TYPE_IPV4:
685 case NEXTHOP_TYPE_IPV6:
686 case NEXTHOP_TYPE_BLACKHOLE:
687 continue;
688 case NEXTHOP_TYPE_IFINDEX:
689 case NEXTHOP_TYPE_IPV4_IFINDEX:
690 case NEXTHOP_TYPE_IPV6_IFINDEX:
691 break;
692 }
693 nh = nexthop_exists(&nhgc->nhg, &nhop);
694
695 if (nh)
696 continue;
697
698 if (ifp->ifindex != nhop.ifindex)
699 continue;
700
701 nh = nexthop_new();
702
703 memcpy(nh, &nhop, sizeof(nhop));
50d89650 704 _nexthop_add(&nhgc->nhg.nexthop, nh);
98cbbaea
DS
705
706 if (nhg_hooks.add_nexthop)
707 nhg_hooks.add_nexthop(nhgc, nh);
708 }
709 } else {
710 struct nexthop *next_nh;
711
712 for (nh = nhgc->nhg.nexthop; nh; nh = next_nh) {
713 next_nh = nh->next;
714 switch (nh->type) {
715 case NEXTHOP_TYPE_IPV4:
716 case NEXTHOP_TYPE_IPV6:
717 case NEXTHOP_TYPE_BLACKHOLE:
718 continue;
719 case NEXTHOP_TYPE_IFINDEX:
720 case NEXTHOP_TYPE_IPV4_IFINDEX:
721 case NEXTHOP_TYPE_IPV6_IFINDEX:
722 break;
723 }
724
725 if (oldifindex != nh->ifindex)
726 continue;
727
50d89650 728 _nexthop_del(&nhgc->nhg, nh);
98cbbaea
DS
729
730 if (nhg_hooks.del_nexthop)
731 nhg_hooks.del_nexthop(nhgc, nh);
732
733 nexthop_free(nh);
734 }
735 }
736 }
737}
738
868ee86c
DS
739static void nhg_name_autocomplete(vector comps, struct cmd_token *token)
740{
741 struct nexthop_group_cmd *nhgc;
742
743 RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
744 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, nhgc->name));
745 }
746}
747
748static const struct cmd_variable_handler nhg_name_handlers[] = {
749 {.tokenname = "NHGNAME", .completions = nhg_name_autocomplete},
750 {.completions = NULL}};
751
31919191
DS
752void nexthop_group_init(void (*new)(const char *name),
753 void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
754 const struct nexthop *nhop),
755 void (*del_nexthop)(const struct nexthop_group_cmd *nhg,
756 const struct nexthop *nhop),
757 void (*delete)(const char *name))
dba32923 758{
31919191
DS
759 RB_INIT(nhgc_entry_head, &nhgc_entries);
760
868ee86c
DS
761 cmd_variable_handler_register(nhg_name_handlers);
762
dba32923
DS
763 install_node(&nexthop_group_node, nexthop_group_write);
764 install_element(CONFIG_NODE, &nexthop_group_cmd);
31919191
DS
765 install_element(CONFIG_NODE, &no_nexthop_group_cmd);
766
767 install_default(NH_GROUP_NODE);
768 install_element(NH_GROUP_NODE, &ecmp_nexthops_cmd);
769
770 memset(&nhg_hooks, 0, sizeof(nhg_hooks));
771
772 if (new)
773 nhg_hooks.new = new;
774 if (add_nexthop)
775 nhg_hooks.add_nexthop = add_nexthop;
776 if (del_nexthop)
777 nhg_hooks.del_nexthop = del_nexthop;
778 if (delete)
779 nhg_hooks.delete = delete;
dba32923 780}