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