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
24 #include <nexthop_group.h>
28 #ifndef VTYSH_EXTRACT_PL
29 #include "lib/nexthop_group_clippy.c"
32 DEFINE_MTYPE_STATIC(LIB
, NEXTHOP_GROUP
, "Nexthop Group")
34 struct nexthop_group_hooks
{
35 void (*new)(const char *name
);
36 void (*add_nexthop
)(const struct nexthop_group_cmd
*nhg
,
37 const struct nexthop
*nhop
);
38 void (*del_nexthop
)(const struct nexthop_group_cmd
*nhg
,
39 const struct nexthop
*nhop
);
40 void (*delete)(const char *name
);
43 static struct nexthop_group_hooks nhg_hooks
;
46 nexthop_group_cmd_compare(const struct nexthop_group_cmd
*nhgc1
,
47 const struct nexthop_group_cmd
*nhgc2
);
48 RB_GENERATE(nhgc_entry_head
, nexthop_group_cmd
, nhgc_entry
,
49 nexthop_group_cmd_compare
)
51 struct nhgc_entry_head nhgc_entries
;
54 nexthop_group_cmd_compare(const struct nexthop_group_cmd
*nhgc1
,
55 const struct nexthop_group_cmd
*nhgc2
)
57 return strcmp(nhgc1
->name
, nhgc2
->name
);
60 struct nexthop
*nexthop_exists(struct nexthop_group
*nhg
, struct nexthop
*nh
)
62 struct nexthop
*nexthop
;
64 for (nexthop
= nhg
->nexthop
; nexthop
; nexthop
= nexthop
->next
) {
65 if (nexthop_same(nh
, nexthop
))
72 struct nexthop_group
*nexthop_group_new(void)
74 return XCALLOC(MTYPE_NEXTHOP_GROUP
, sizeof(struct nexthop_group
));
77 void nexthop_group_delete(struct nexthop_group
**nhg
)
79 XFREE(MTYPE_NEXTHOP_GROUP
, *nhg
);
82 /* Add nexthop to the end of a nexthop list. */
83 void nexthop_add(struct nexthop
**target
, struct nexthop
*nexthop
)
87 for (last
= *target
; last
&& last
->next
; last
= last
->next
)
96 /* Delete nexthop from a nexthop list. */
97 void nexthop_del(struct nexthop_group
*nhg
, struct nexthop
*nh
)
99 struct nexthop
*nexthop
;
101 for (nexthop
= nhg
->nexthop
; nexthop
; nexthop
= nexthop
->next
) {
102 if (nexthop_same(nh
, nexthop
))
109 nexthop
->prev
->next
= nexthop
->next
;
111 nhg
->nexthop
= nexthop
->next
;
114 nexthop
->next
->prev
= nexthop
->prev
;
117 void copy_nexthops(struct nexthop
**tnh
, struct nexthop
*nh
,
118 struct nexthop
*rparent
)
120 struct nexthop
*nexthop
;
123 for (nh1
= nh
; nh1
; nh1
= nh1
->next
) {
124 nexthop
= nexthop_new();
125 nexthop
->vrf_id
= nh1
->vrf_id
;
126 nexthop
->ifindex
= nh1
->ifindex
;
127 nexthop
->type
= nh1
->type
;
128 nexthop
->flags
= nh1
->flags
;
129 memcpy(&nexthop
->gate
, &nh1
->gate
, sizeof(nh1
->gate
));
130 memcpy(&nexthop
->src
, &nh1
->src
, sizeof(nh1
->src
));
131 memcpy(&nexthop
->rmap_src
, &nh1
->rmap_src
,
132 sizeof(nh1
->rmap_src
));
133 nexthop
->rparent
= rparent
;
135 nexthop_add_labels(nexthop
, nh1
->nh_label_type
,
136 nh1
->nh_label
->num_labels
,
137 &nh1
->nh_label
->label
[0]);
138 nexthop_add(tnh
, nexthop
);
140 if (CHECK_FLAG(nh1
->flags
, NEXTHOP_FLAG_RECURSIVE
))
141 copy_nexthops(&nexthop
->resolved
, nh1
->resolved
,
146 static void nhgc_delete_nexthops(struct nexthop_group_cmd
*nhgc
)
148 struct nexthop
*nexthop
;
150 nexthop
= nhgc
->nhg
.nexthop
;
152 struct nexthop
*next
= nexthop_next(nexthop
);
154 if (nhg_hooks
.del_nexthop
)
155 nhg_hooks
.del_nexthop(nhgc
, nexthop
);
157 nexthop_free(nexthop
);
163 struct nexthop_group_cmd
*nhgc_find(const char *name
)
165 struct nexthop_group_cmd find
;
167 strlcpy(find
.name
, name
, sizeof(find
.name
));
169 return RB_FIND(nhgc_entry_head
, &nhgc_entries
, &find
);
172 static struct nexthop_group_cmd
*nhgc_get(const char *name
)
174 struct nexthop_group_cmd
*nhgc
;
176 nhgc
= nhgc_find(name
);
178 nhgc
= XCALLOC(MTYPE_TMP
, sizeof(*nhgc
));
179 strlcpy(nhgc
->name
, name
, sizeof(nhgc
->name
));
181 QOBJ_REG(nhgc
, nexthop_group_cmd
);
182 RB_INSERT(nhgc_entry_head
, &nhgc_entries
, nhgc
);
191 static void nhgc_delete(struct nexthop_group_cmd
*nhgc
)
193 nhgc_delete_nexthops(nhgc
);
195 if (nhg_hooks
.delete)
196 nhg_hooks
.delete(nhgc
->name
);
198 RB_REMOVE(nhgc_entry_head
, &nhgc_entries
, nhgc
);
201 DEFINE_QOBJ_TYPE(nexthop_group_cmd
)
203 DEFUN_NOSH(nexthop_group
, nexthop_group_cmd
, "nexthop-group NAME",
204 "Enter into the nexthop-group submode\n"
205 "Specify the NAME of the nexthop-group\n")
207 const char *nhg_name
= argv
[1]->arg
;
208 struct nexthop_group_cmd
*nhgc
= NULL
;
210 nhgc
= nhgc_get(nhg_name
);
211 VTY_PUSH_CONTEXT(NH_GROUP_NODE
, nhgc
);
216 DEFUN_NOSH(no_nexthop_group
, no_nexthop_group_cmd
, "no nexthop-group NAME",
218 "Delete the nexthop-group\n"
219 "Specify the NAME of the nexthop-group\n")
221 const char *nhg_name
= argv
[2]->arg
;
222 struct nexthop_group_cmd
*nhgc
= NULL
;
224 nhgc
= nhgc_find(nhg_name
);
231 DEFPY(ecmp_nexthops
, ecmp_nexthops_cmd
,
232 "[no] nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
234 "Specify one of the nexthops in this ECMP group\n"
238 "If the nexthop is in a different vrf tell us\n"
239 "The nexthop-vrf Name\n")
241 VTY_DECLVAR_CONTEXT(nexthop_group_cmd
, nhgc
);
247 vrf
= vrf_lookup_by_name(name
);
249 vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
252 vty_out(vty
, "Specified: %s is non-existent\n", name
);
256 memset(&nhop
, 0, sizeof(nhop
));
257 nhop
.vrf_id
= vrf
->vrf_id
;
259 if (addr
->sa
.sa_family
== AF_INET
) {
260 nhop
.gate
.ipv4
.s_addr
= addr
->sin
.sin_addr
.s_addr
;
262 nhop
.type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
263 nhop
.ifindex
= ifname2ifindex(intf
, vrf
->vrf_id
);
264 if (nhop
.ifindex
== IFINDEX_INTERNAL
) {
266 "Specified Intf %s does not exist in vrf: %s\n",
271 nhop
.type
= NEXTHOP_TYPE_IPV4
;
273 memcpy(&nhop
.gate
.ipv6
, &addr
->sin6
.sin6_addr
, 16);
275 nhop
.type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
276 nhop
.ifindex
= ifname2ifindex(intf
, vrf
->vrf_id
);
277 if (nhop
.ifindex
== IFINDEX_INTERNAL
) {
279 "Specified Intf %s does not exist in vrf: %s\n",
284 nhop
.type
= NEXTHOP_TYPE_IPV6
;
287 nh
= nexthop_exists(&nhgc
->nhg
, &nhop
);
291 nexthop_del(&nhgc
->nhg
, nh
);
293 if (nhg_hooks
.del_nexthop
)
294 nhg_hooks
.del_nexthop(nhgc
, nh
);
299 /* must be adding new nexthop since !no and !nexthop_exists */
302 memcpy(nh
, &nhop
, sizeof(nhop
));
303 nexthop_add(&nhgc
->nhg
.nexthop
, nh
);
305 if (nhg_hooks
.add_nexthop
)
306 nhg_hooks
.add_nexthop(nhgc
, nh
);
312 struct cmd_node nexthop_group_node
= {
314 "%s(config-nh-group)# ",
318 void nexthop_group_write_nexthop(struct vty
*vty
, struct nexthop
*nh
)
323 vty_out(vty
, "nexthop ");
326 case NEXTHOP_TYPE_IFINDEX
:
327 vty_out(vty
, "%s", ifindex2ifname(nh
->ifindex
, nh
->vrf_id
));
329 case NEXTHOP_TYPE_IPV4
:
330 vty_out(vty
, "%s", inet_ntoa(nh
->gate
.ipv4
));
332 case NEXTHOP_TYPE_IPV4_IFINDEX
:
333 vty_out(vty
, "%s %s", inet_ntoa(nh
->gate
.ipv4
),
334 ifindex2ifname(nh
->ifindex
, nh
->vrf_id
));
336 case NEXTHOP_TYPE_IPV6
:
338 inet_ntop(AF_INET6
, &nh
->gate
.ipv6
, buf
, sizeof(buf
)));
340 case NEXTHOP_TYPE_IPV6_IFINDEX
:
341 vty_out(vty
, "%s %s",
342 inet_ntop(AF_INET6
, &nh
->gate
.ipv6
, buf
, sizeof(buf
)),
343 ifindex2ifname(nh
->ifindex
, nh
->vrf_id
));
345 case NEXTHOP_TYPE_BLACKHOLE
:
349 if (nh
->vrf_id
!= VRF_DEFAULT
) {
350 vrf
= vrf_lookup_by_id(nh
->vrf_id
);
351 vty_out(vty
, " nexthop-vrf %s", vrf
->name
);
356 static int nexthop_group_write(struct vty
*vty
)
358 struct nexthop_group_cmd
*nhgc
;
361 RB_FOREACH (nhgc
, nhgc_entry_head
, &nhgc_entries
) {
362 vty_out(vty
, "nexthop-group %s\n", nhgc
->name
);
364 for (nh
= nhgc
->nhg
.nexthop
; nh
; nh
= nh
->next
) {
366 nexthop_group_write_nexthop(vty
, nh
);
375 void nexthop_group_init(void (*new)(const char *name
),
376 void (*add_nexthop
)(const struct nexthop_group_cmd
*nhg
,
377 const struct nexthop
*nhop
),
378 void (*del_nexthop
)(const struct nexthop_group_cmd
*nhg
,
379 const struct nexthop
*nhop
),
380 void (*delete)(const char *name
))
382 RB_INIT(nhgc_entry_head
, &nhgc_entries
);
384 install_node(&nexthop_group_node
, nexthop_group_write
);
385 install_element(CONFIG_NODE
, &nexthop_group_cmd
);
386 install_element(CONFIG_NODE
, &no_nexthop_group_cmd
);
388 install_default(NH_GROUP_NODE
);
389 install_element(NH_GROUP_NODE
, &ecmp_nexthops_cmd
);
391 memset(&nhg_hooks
, 0, sizeof(nhg_hooks
));
396 nhg_hooks
.add_nexthop
= add_nexthop
;
398 nhg_hooks
.del_nexthop
= del_nexthop
;
400 nhg_hooks
.delete = delete;