2 * Nexthop Group structure definition.
3 * Copyright (C) 2018 Cumulus Networks, Inc.
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)
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
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
23 #include <sockunion.h>
25 #include <nexthop_group.h>
26 #include <nexthop_group_private.h>
31 #ifndef VTYSH_EXTRACT_PL
32 #include "lib/nexthop_group_clippy.c"
35 DEFINE_MTYPE_STATIC(LIB
, NEXTHOP_GROUP
, "Nexthop Group")
38 * Internal struct used to hold nhg config strings
42 union sockunion
*addr
;
48 struct nexthop_group_hooks
{
49 void (*new)(const char *name
);
50 void (*add_nexthop
)(const struct nexthop_group_cmd
*nhg
,
51 const struct nexthop
*nhop
);
52 void (*del_nexthop
)(const struct nexthop_group_cmd
*nhg
,
53 const struct nexthop
*nhop
);
54 void (*delete)(const char *name
);
57 static struct nexthop_group_hooks nhg_hooks
;
60 nexthop_group_cmd_compare(const struct nexthop_group_cmd
*nhgc1
,
61 const struct nexthop_group_cmd
*nhgc2
);
62 RB_GENERATE(nhgc_entry_head
, nexthop_group_cmd
, nhgc_entry
,
63 nexthop_group_cmd_compare
)
65 static struct nhgc_entry_head nhgc_entries
;
68 nexthop_group_cmd_compare(const struct nexthop_group_cmd
*nhgc1
,
69 const struct nexthop_group_cmd
*nhgc2
)
71 return strcmp(nhgc1
->name
, nhgc2
->name
);
74 static struct nexthop
*nexthop_group_tail(const struct nexthop_group
*nhg
)
76 struct nexthop
*nexthop
= nhg
->nexthop
;
78 while (nexthop
&& nexthop
->next
)
79 nexthop
= nexthop
->next
;
84 uint8_t nexthop_group_nexthop_num(const struct nexthop_group
*nhg
)
89 for (ALL_NEXTHOPS_PTR(nhg
, nhop
))
95 uint8_t nexthop_group_nexthop_num_no_recurse(const struct nexthop_group
*nhg
)
100 for (nhop
= nhg
->nexthop
; nhop
; nhop
= nhop
->next
)
106 uint8_t nexthop_group_active_nexthop_num(const struct nexthop_group
*nhg
)
108 struct nexthop
*nhop
;
111 for (ALL_NEXTHOPS_PTR(nhg
, nhop
)) {
112 if (CHECK_FLAG(nhop
->flags
, NEXTHOP_FLAG_ACTIVE
))
120 nexthop_group_active_nexthop_num_no_recurse(const struct nexthop_group
*nhg
)
122 struct nexthop
*nhop
;
125 for (nhop
= nhg
->nexthop
; nhop
; nhop
= nhop
->next
) {
126 if (CHECK_FLAG(nhop
->flags
, NEXTHOP_FLAG_ACTIVE
))
133 struct nexthop
*nexthop_exists(const struct nexthop_group
*nhg
,
134 const struct nexthop
*nh
)
136 struct nexthop
*nexthop
;
138 for (nexthop
= nhg
->nexthop
; nexthop
; nexthop
= nexthop
->next
) {
139 if (nexthop_same(nh
, nexthop
))
147 nexthop_group_equal_common(const struct nexthop_group
*nhg1
,
148 const struct nexthop_group
*nhg2
,
149 uint8_t (*nexthop_group_nexthop_num_func
)(
150 const struct nexthop_group
*nhg
))
161 if (nexthop_group_nexthop_num_func(nhg1
)
162 != nexthop_group_nexthop_num_func(nhg2
))
168 /* This assumes ordered */
169 bool nexthop_group_equal_no_recurse(const struct nexthop_group
*nhg1
,
170 const struct nexthop_group
*nhg2
)
172 struct nexthop
*nh1
= NULL
;
173 struct nexthop
*nh2
= NULL
;
175 if (!nexthop_group_equal_common(nhg1
, nhg2
,
176 &nexthop_group_nexthop_num_no_recurse
))
179 for (nh1
= nhg1
->nexthop
, nh2
= nhg2
->nexthop
; nh1
|| nh2
;
180 nh1
= nh1
->next
, nh2
= nh2
->next
) {
185 if (!nexthop_same(nh1
, nh2
))
192 /* This assumes ordered */
193 bool nexthop_group_equal(const struct nexthop_group
*nhg1
,
194 const struct nexthop_group
*nhg2
)
196 struct nexthop
*nh1
= NULL
;
197 struct nexthop
*nh2
= NULL
;
199 if (!nexthop_group_equal_common(nhg1
, nhg2
, &nexthop_group_nexthop_num
))
202 for (nh1
= nhg1
->nexthop
, nh2
= nhg2
->nexthop
; nh1
|| nh2
;
203 nh1
= nexthop_next(nh1
), nh2
= nexthop_next(nh2
)) {
208 if (!nexthop_same(nh1
, nh2
))
214 struct nexthop_group
*nexthop_group_new(void)
216 return XCALLOC(MTYPE_NEXTHOP_GROUP
, sizeof(struct nexthop_group
));
219 void nexthop_group_copy(struct nexthop_group
*to
, struct nexthop_group
*from
)
221 /* Copy everything, including recursive info */
222 copy_nexthops(&to
->nexthop
, from
->nexthop
, NULL
);
225 void nexthop_group_delete(struct nexthop_group
**nhg
)
228 nexthops_free((*nhg
)->nexthop
);
230 XFREE(MTYPE_NEXTHOP_GROUP
, *nhg
);
233 /* Add nexthop to the end of a nexthop list. */
234 void _nexthop_add(struct nexthop
**target
, struct nexthop
*nexthop
)
236 struct nexthop
*last
;
238 for (last
= *target
; last
&& last
->next
; last
= last
->next
)
241 last
->next
= nexthop
;
244 nexthop
->prev
= last
;
247 /* Add nexthop to sorted list of nexthops */
248 static void _nexthop_add_sorted(struct nexthop
**head
,
249 struct nexthop
*nexthop
)
251 struct nexthop
*position
, *prev
;
253 /* Ensure this gets set */
254 nexthop
->next
= NULL
;
256 for (position
= *head
, prev
= NULL
; position
;
257 prev
= position
, position
= position
->next
) {
258 if (nexthop_cmp(position
, nexthop
) > 0) {
259 nexthop
->next
= position
;
260 nexthop
->prev
= prev
;
263 nexthop
->prev
->next
= nexthop
;
267 position
->prev
= nexthop
;
272 nexthop
->prev
= prev
;
274 prev
->next
= nexthop
;
279 void nexthop_group_add_sorted(struct nexthop_group
*nhg
,
280 struct nexthop
*nexthop
)
282 struct nexthop
*tail
;
284 /* Try to just append to the end first;
285 * trust the list is already sorted
287 tail
= nexthop_group_tail(nhg
);
289 if (tail
&& (nexthop_cmp(tail
, nexthop
) < 0)) {
290 tail
->next
= nexthop
;
291 nexthop
->prev
= tail
;
296 _nexthop_add_sorted(&nhg
->nexthop
, nexthop
);
299 /* Delete nexthop from a nexthop list. */
300 void _nexthop_del(struct nexthop_group
*nhg
, struct nexthop
*nh
)
302 struct nexthop
*nexthop
;
304 for (nexthop
= nhg
->nexthop
; nexthop
; nexthop
= nexthop
->next
) {
305 if (nexthop_same(nh
, nexthop
))
312 nexthop
->prev
->next
= nexthop
->next
;
314 nhg
->nexthop
= nexthop
->next
;
317 nexthop
->next
->prev
= nexthop
->prev
;
324 * Copy a list of nexthops in 'nh' to an nhg, enforcing canonical sort order
326 void nexthop_group_copy_nh_sorted(struct nexthop_group
*nhg
,
327 const struct nexthop
*nh
)
329 struct nexthop
*nexthop
, *tail
;
330 const struct nexthop
*nh1
;
332 /* We'll try to append to the end of the new list;
333 * if the original list in nh is already sorted, this eliminates
334 * lots of comparison operations.
336 tail
= nexthop_group_tail(nhg
);
338 for (nh1
= nh
; nh1
; nh1
= nh1
->next
) {
339 nexthop
= nexthop_dup(nh1
, NULL
);
341 if (tail
&& (nexthop_cmp(tail
, nexthop
) < 0)) {
342 tail
->next
= nexthop
;
343 nexthop
->prev
= tail
;
349 _nexthop_add_sorted(&nhg
->nexthop
, nexthop
);
356 /* Copy a list of nexthops, no effort made to sort or order them. */
357 void copy_nexthops(struct nexthop
**tnh
, const struct nexthop
*nh
,
358 struct nexthop
*rparent
)
360 struct nexthop
*nexthop
;
361 const struct nexthop
*nh1
;
363 for (nh1
= nh
; nh1
; nh1
= nh1
->next
) {
364 nexthop
= nexthop_dup(nh1
, rparent
);
365 _nexthop_add(tnh
, nexthop
);
367 if (CHECK_FLAG(nh1
->flags
, NEXTHOP_FLAG_RECURSIVE
))
368 copy_nexthops(&nexthop
->resolved
, nh1
->resolved
,
373 uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group
*nhg
)
379 * We are not interested in hashing over any recursively
382 for (nh
= nhg
->nexthop
; nh
; nh
= nh
->next
)
383 key
= jhash_1word(nexthop_hash(nh
), key
);
388 uint32_t nexthop_group_hash(const struct nexthop_group
*nhg
)
393 for (ALL_NEXTHOPS_PTR(nhg
, nh
))
394 key
= jhash_1word(nexthop_hash(nh
), key
);
399 void nexthop_group_mark_duplicates(struct nexthop_group
*nhg
)
401 struct nexthop
*nexthop
, *prev
;
403 for (ALL_NEXTHOPS_PTR(nhg
, nexthop
)) {
404 UNSET_FLAG(nexthop
->flags
, NEXTHOP_FLAG_DUPLICATE
);
405 for (ALL_NEXTHOPS_PTR(nhg
, prev
)) {
408 if (nexthop_same_firsthop(nexthop
, prev
)) {
409 SET_FLAG(nexthop
->flags
,
410 NEXTHOP_FLAG_DUPLICATE
);
417 static void nhgc_delete_nexthops(struct nexthop_group_cmd
*nhgc
)
419 struct nexthop
*nexthop
;
421 nexthop
= nhgc
->nhg
.nexthop
;
423 struct nexthop
*next
= nexthop_next(nexthop
);
425 _nexthop_del(&nhgc
->nhg
, nexthop
);
426 if (nhg_hooks
.del_nexthop
)
427 nhg_hooks
.del_nexthop(nhgc
, nexthop
);
429 nexthop_free(nexthop
);
435 struct nexthop_group_cmd
*nhgc_find(const char *name
)
437 struct nexthop_group_cmd find
;
439 strlcpy(find
.name
, name
, sizeof(find
.name
));
441 return RB_FIND(nhgc_entry_head
, &nhgc_entries
, &find
);
444 static int nhgc_cmp_helper(const char *a
, const char *b
)
458 static int nhgc_addr_cmp_helper(const union sockunion
*a
, const union sockunion
*b
)
469 return sockunion_cmp(a
, b
);
472 static int nhgl_cmp(struct nexthop_hold
*nh1
, struct nexthop_hold
*nh2
)
476 ret
= nhgc_addr_cmp_helper(nh1
->addr
, nh2
->addr
);
480 ret
= nhgc_cmp_helper(nh1
->intf
, nh2
->intf
);
484 ret
= nhgc_cmp_helper(nh1
->nhvrf_name
, nh2
->nhvrf_name
);
488 return nhgc_cmp_helper(nh1
->labels
, nh2
->labels
);
491 static void nhgl_delete(struct nexthop_hold
*nh
)
493 XFREE(MTYPE_TMP
, nh
->intf
);
495 XFREE(MTYPE_TMP
, nh
->nhvrf_name
);
498 sockunion_free(nh
->addr
);
500 XFREE(MTYPE_TMP
, nh
->labels
);
502 XFREE(MTYPE_TMP
, nh
);
505 static struct nexthop_group_cmd
*nhgc_get(const char *name
)
507 struct nexthop_group_cmd
*nhgc
;
509 nhgc
= nhgc_find(name
);
511 nhgc
= XCALLOC(MTYPE_TMP
, sizeof(*nhgc
));
512 strlcpy(nhgc
->name
, name
, sizeof(nhgc
->name
));
514 QOBJ_REG(nhgc
, nexthop_group_cmd
);
515 RB_INSERT(nhgc_entry_head
, &nhgc_entries
, nhgc
);
517 nhgc
->nhg_list
= list_new();
518 nhgc
->nhg_list
->cmp
= (int (*)(void *, void *))nhgl_cmp
;
519 nhgc
->nhg_list
->del
= (void (*)(void *))nhgl_delete
;
528 static void nhgc_delete(struct nexthop_group_cmd
*nhgc
)
530 nhgc_delete_nexthops(nhgc
);
532 if (nhg_hooks
.delete)
533 nhg_hooks
.delete(nhgc
->name
);
535 RB_REMOVE(nhgc_entry_head
, &nhgc_entries
, nhgc
);
537 list_delete(&nhgc
->nhg_list
);
539 XFREE(MTYPE_TMP
, nhgc
);
542 DEFINE_QOBJ_TYPE(nexthop_group_cmd
)
544 DEFUN_NOSH(nexthop_group
, nexthop_group_cmd
, "nexthop-group NHGNAME",
545 "Enter into the nexthop-group submode\n"
546 "Specify the NAME of the nexthop-group\n")
548 const char *nhg_name
= argv
[1]->arg
;
549 struct nexthop_group_cmd
*nhgc
= NULL
;
551 nhgc
= nhgc_get(nhg_name
);
552 VTY_PUSH_CONTEXT(NH_GROUP_NODE
, nhgc
);
557 DEFUN_NOSH(no_nexthop_group
, no_nexthop_group_cmd
, "no nexthop-group NHGNAME",
559 "Delete the nexthop-group\n"
560 "Specify the NAME of the nexthop-group\n")
562 const char *nhg_name
= argv
[2]->arg
;
563 struct nexthop_group_cmd
*nhgc
= NULL
;
565 nhgc
= nhgc_find(nhg_name
);
572 static void nexthop_group_save_nhop(struct nexthop_group_cmd
*nhgc
,
573 const char *nhvrf_name
,
574 const union sockunion
*addr
,
575 const char *intf
, const char *labels
,
576 const uint32_t weight
)
578 struct nexthop_hold
*nh
;
580 nh
= XCALLOC(MTYPE_TMP
, sizeof(*nh
));
583 nh
->nhvrf_name
= XSTRDUP(MTYPE_TMP
, nhvrf_name
);
585 nh
->intf
= XSTRDUP(MTYPE_TMP
, intf
);
587 nh
->addr
= sockunion_dup(addr
);
589 nh
->labels
= XSTRDUP(MTYPE_TMP
, labels
);
593 listnode_add_sort(nhgc
->nhg_list
, nh
);
596 static void nexthop_group_unsave_nhop(struct nexthop_group_cmd
*nhgc
,
597 const char *nhvrf_name
,
598 const union sockunion
*addr
,
599 const char *intf
, const char *labels
,
600 const uint32_t weight
)
602 struct nexthop_hold
*nh
;
603 struct listnode
*node
;
605 for (ALL_LIST_ELEMENTS_RO(nhgc
->nhg_list
, node
, nh
)) {
606 if (nhgc_cmp_helper(nhvrf_name
, nh
->nhvrf_name
) == 0
607 && nhgc_addr_cmp_helper(addr
, nh
->addr
) == 0
608 && nhgc_cmp_helper(intf
, nh
->intf
) == 0
609 && nhgc_cmp_helper(labels
, nh
->labels
) == 0
610 && weight
== nh
->weight
)
615 * Something has gone seriously wrong, fail gracefully
620 list_delete_node(nhgc
->nhg_list
, node
);
625 * Parse the config strings we support for a single nexthop. This gets used
626 * in a couple of different ways, and we distinguish between transient
627 * failures - such as a still-unprocessed interface - and fatal errors
628 * from label-string parsing.
630 static bool nexthop_group_parse_nexthop(struct nexthop
*nhop
,
631 const union sockunion
*addr
,
632 const char *intf
, const char *name
,
633 const char *labels
, int *lbl_ret
,
639 memset(nhop
, 0, sizeof(*nhop
));
642 vrf
= vrf_lookup_by_name(name
);
644 vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
649 nhop
->vrf_id
= vrf
->vrf_id
;
652 nhop
->ifindex
= ifname2ifindex(intf
, vrf
->vrf_id
);
653 if (nhop
->ifindex
== IFINDEX_INTERNAL
)
658 if (addr
->sa
.sa_family
== AF_INET
) {
659 nhop
->gate
.ipv4
.s_addr
= addr
->sin
.sin_addr
.s_addr
;
661 nhop
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
663 nhop
->type
= NEXTHOP_TYPE_IPV4
;
665 nhop
->gate
.ipv6
= addr
->sin6
.sin6_addr
;
667 nhop
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
669 nhop
->type
= NEXTHOP_TYPE_IPV6
;
672 nhop
->type
= NEXTHOP_TYPE_IFINDEX
;
676 mpls_label_t larray
[MPLS_MAX_LABELS
];
678 ret
= mpls_str2label(labels
, &num
, larray
);
680 /* Return label parse result */
687 nexthop_add_labels(nhop
, ZEBRA_LSP_NONE
,
691 nhop
->weight
= weight
;
697 * Wrapper to parse the strings in a 'nexthop_hold'
699 static bool nexthop_group_parse_nhh(struct nexthop
*nhop
,
700 const struct nexthop_hold
*nhh
)
702 return (nexthop_group_parse_nexthop(nhop
, nhh
->addr
, nhh
->intf
,
703 nhh
->nhvrf_name
, nhh
->labels
, NULL
,
707 DEFPY(ecmp_nexthops
, ecmp_nexthops_cmd
,
710 <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\
714 nexthop-vrf NAME$vrf_name \
719 "Specify one of the nexthops in this ECMP group\n"
724 "If the nexthop is in a different vrf tell us\n"
725 "The nexthop-vrf Name\n"
726 "Specify label(s) for this nexthop\n"
727 "One or more labels in the range (16-1048575) separated by '/'\n"
728 "Weight to be used by the nexthop for purposes of ECMP\n"
729 "Weight value to be used\n")
731 VTY_DECLVAR_CONTEXT(nexthop_group_cmd
, nhgc
);
737 legal
= nexthop_group_parse_nexthop(&nhop
, addr
, intf
, vrf_name
, label
,
740 if (nhop
.type
== NEXTHOP_TYPE_IPV6
741 && IN6_IS_ADDR_LINKLOCAL(&nhop
.gate
.ipv6
)) {
743 "Specified a v6 LL with no interface, rejecting\n");
744 return CMD_WARNING_CONFIG_FAILED
;
747 /* Handle label-string errors */
748 if (!legal
&& lbl_ret
< 0) {
751 vty_out(vty
, "%% Malformed label(s)\n");
755 "%% Cannot use reserved label(s) (%d-%d)\n",
756 MPLS_LABEL_RESERVED_MIN
,
757 MPLS_LABEL_RESERVED_MAX
);
761 "%% Too many labels. Enter %d or fewer\n",
765 return CMD_WARNING_CONFIG_FAILED
;
768 nh
= nexthop_exists(&nhgc
->nhg
, &nhop
);
771 nexthop_group_unsave_nhop(nhgc
, vrf_name
, addr
, intf
, label
,
774 _nexthop_del(&nhgc
->nhg
, nh
);
776 if (nhg_hooks
.del_nexthop
)
777 nhg_hooks
.del_nexthop(nhgc
, nh
);
782 /* must be adding new nexthop since !no and !nexthop_exists */
786 memcpy(nh
, &nhop
, sizeof(nhop
));
787 _nexthop_add(&nhgc
->nhg
.nexthop
, nh
);
790 nexthop_group_save_nhop(nhgc
, vrf_name
, addr
, intf
, label
,
793 if (legal
&& nhg_hooks
.add_nexthop
)
794 nhg_hooks
.add_nexthop(nhgc
, nh
);
800 static struct cmd_node nexthop_group_node
= {
802 "%s(config-nh-group)# ",
806 void nexthop_group_write_nexthop(struct vty
*vty
, struct nexthop
*nh
)
811 vty_out(vty
, "nexthop ");
814 case NEXTHOP_TYPE_IFINDEX
:
815 vty_out(vty
, "%s", ifindex2ifname(nh
->ifindex
, nh
->vrf_id
));
817 case NEXTHOP_TYPE_IPV4
:
818 vty_out(vty
, "%s", inet_ntoa(nh
->gate
.ipv4
));
820 case NEXTHOP_TYPE_IPV4_IFINDEX
:
821 vty_out(vty
, "%s %s", inet_ntoa(nh
->gate
.ipv4
),
822 ifindex2ifname(nh
->ifindex
, nh
->vrf_id
));
824 case NEXTHOP_TYPE_IPV6
:
826 inet_ntop(AF_INET6
, &nh
->gate
.ipv6
, buf
, sizeof(buf
)));
828 case NEXTHOP_TYPE_IPV6_IFINDEX
:
829 vty_out(vty
, "%s %s",
830 inet_ntop(AF_INET6
, &nh
->gate
.ipv6
, buf
, sizeof(buf
)),
831 ifindex2ifname(nh
->ifindex
, nh
->vrf_id
));
833 case NEXTHOP_TYPE_BLACKHOLE
:
837 if (nh
->vrf_id
!= VRF_DEFAULT
) {
838 vrf
= vrf_lookup_by_id(nh
->vrf_id
);
839 vty_out(vty
, " nexthop-vrf %s", vrf
->name
);
842 if (nh
->nh_label
&& nh
->nh_label
->num_labels
> 0) {
845 mpls_label2str(nh
->nh_label
->num_labels
,
847 buf
, sizeof(buf
), 0);
848 vty_out(vty
, " label %s", buf
);
852 vty_out(vty
, " weight %u", nh
->weight
);
857 static void nexthop_group_write_nexthop_internal(struct vty
*vty
,
858 struct nexthop_hold
*nh
)
862 vty_out(vty
, "nexthop");
865 vty_out(vty
, " %s", sockunion2str(nh
->addr
, buf
, sizeof(buf
)));
868 vty_out(vty
, " %s", nh
->intf
);
871 vty_out(vty
, " nexthop-vrf %s", nh
->nhvrf_name
);
874 vty_out(vty
, " label %s", nh
->labels
);
877 vty_out(vty
, " weight %u", nh
->weight
);
882 static int nexthop_group_write(struct vty
*vty
)
884 struct nexthop_group_cmd
*nhgc
;
885 struct nexthop_hold
*nh
;
887 RB_FOREACH (nhgc
, nhgc_entry_head
, &nhgc_entries
) {
888 struct listnode
*node
;
890 vty_out(vty
, "nexthop-group %s\n", nhgc
->name
);
892 for (ALL_LIST_ELEMENTS_RO(nhgc
->nhg_list
, node
, nh
)) {
894 nexthop_group_write_nexthop_internal(vty
, nh
);
903 void nexthop_group_enable_vrf(struct vrf
*vrf
)
905 struct nexthop_group_cmd
*nhgc
;
906 struct nexthop_hold
*nhh
;
908 RB_FOREACH (nhgc
, nhgc_entry_head
, &nhgc_entries
) {
909 struct listnode
*node
;
911 for (ALL_LIST_ELEMENTS_RO(nhgc
->nhg_list
, node
, nhh
)) {
915 if (!nexthop_group_parse_nhh(&nhop
, nhh
))
918 nh
= nexthop_exists(&nhgc
->nhg
, &nhop
);
923 if (nhop
.vrf_id
!= vrf
->vrf_id
)
928 memcpy(nh
, &nhop
, sizeof(nhop
));
929 _nexthop_add(&nhgc
->nhg
.nexthop
, nh
);
931 if (nhg_hooks
.add_nexthop
)
932 nhg_hooks
.add_nexthop(nhgc
, nh
);
937 void nexthop_group_disable_vrf(struct vrf
*vrf
)
939 struct nexthop_group_cmd
*nhgc
;
940 struct nexthop_hold
*nhh
;
942 RB_FOREACH (nhgc
, nhgc_entry_head
, &nhgc_entries
) {
943 struct listnode
*node
;
945 for (ALL_LIST_ELEMENTS_RO(nhgc
->nhg_list
, node
, nhh
)) {
949 if (!nexthop_group_parse_nhh(&nhop
, nhh
))
952 nh
= nexthop_exists(&nhgc
->nhg
, &nhop
);
957 if (nh
->vrf_id
!= vrf
->vrf_id
)
960 _nexthop_del(&nhgc
->nhg
, nh
);
962 if (nhg_hooks
.del_nexthop
)
963 nhg_hooks
.del_nexthop(nhgc
, nh
);
970 void nexthop_group_interface_state_change(struct interface
*ifp
,
971 ifindex_t oldifindex
)
973 struct nexthop_group_cmd
*nhgc
;
974 struct nexthop_hold
*nhh
;
976 RB_FOREACH (nhgc
, nhgc_entry_head
, &nhgc_entries
) {
977 struct listnode
*node
;
981 for (ALL_LIST_ELEMENTS_RO(nhgc
->nhg_list
, node
, nhh
)) {
984 if (!nexthop_group_parse_nhh(&nhop
, nhh
))
988 case NEXTHOP_TYPE_IPV4
:
989 case NEXTHOP_TYPE_IPV6
:
990 case NEXTHOP_TYPE_BLACKHOLE
:
992 case NEXTHOP_TYPE_IFINDEX
:
993 case NEXTHOP_TYPE_IPV4_IFINDEX
:
994 case NEXTHOP_TYPE_IPV6_IFINDEX
:
997 nh
= nexthop_exists(&nhgc
->nhg
, &nhop
);
1002 if (ifp
->ifindex
!= nhop
.ifindex
)
1007 memcpy(nh
, &nhop
, sizeof(nhop
));
1008 _nexthop_add(&nhgc
->nhg
.nexthop
, nh
);
1010 if (nhg_hooks
.add_nexthop
)
1011 nhg_hooks
.add_nexthop(nhgc
, nh
);
1014 struct nexthop
*next_nh
;
1016 for (nh
= nhgc
->nhg
.nexthop
; nh
; nh
= next_nh
) {
1019 case NEXTHOP_TYPE_IPV4
:
1020 case NEXTHOP_TYPE_IPV6
:
1021 case NEXTHOP_TYPE_BLACKHOLE
:
1023 case NEXTHOP_TYPE_IFINDEX
:
1024 case NEXTHOP_TYPE_IPV4_IFINDEX
:
1025 case NEXTHOP_TYPE_IPV6_IFINDEX
:
1029 if (oldifindex
!= nh
->ifindex
)
1032 _nexthop_del(&nhgc
->nhg
, nh
);
1034 if (nhg_hooks
.del_nexthop
)
1035 nhg_hooks
.del_nexthop(nhgc
, nh
);
1043 static void nhg_name_autocomplete(vector comps
, struct cmd_token
*token
)
1045 struct nexthop_group_cmd
*nhgc
;
1047 RB_FOREACH (nhgc
, nhgc_entry_head
, &nhgc_entries
) {
1048 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, nhgc
->name
));
1052 static const struct cmd_variable_handler nhg_name_handlers
[] = {
1053 {.tokenname
= "NHGNAME", .completions
= nhg_name_autocomplete
},
1054 {.completions
= NULL
}};
1056 void nexthop_group_init(void (*new)(const char *name
),
1057 void (*add_nexthop
)(const struct nexthop_group_cmd
*nhg
,
1058 const struct nexthop
*nhop
),
1059 void (*del_nexthop
)(const struct nexthop_group_cmd
*nhg
,
1060 const struct nexthop
*nhop
),
1061 void (*delete)(const char *name
))
1063 RB_INIT(nhgc_entry_head
, &nhgc_entries
);
1065 cmd_variable_handler_register(nhg_name_handlers
);
1067 install_node(&nexthop_group_node
, nexthop_group_write
);
1068 install_element(CONFIG_NODE
, &nexthop_group_cmd
);
1069 install_element(CONFIG_NODE
, &no_nexthop_group_cmd
);
1071 install_default(NH_GROUP_NODE
);
1072 install_element(NH_GROUP_NODE
, &ecmp_nexthops_cmd
);
1074 memset(&nhg_hooks
, 0, sizeof(nhg_hooks
));
1077 nhg_hooks
.new = new;
1079 nhg_hooks
.add_nexthop
= add_nexthop
;
1081 nhg_hooks
.del_nexthop
= del_nexthop
;
1083 nhg_hooks
.delete = delete;