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