]> git.proxmox.com Git - mirror_frr.git/blob - lib/nexthop_group.c
Merge pull request #2036 from LabNConsulting/working/master/bgp-vpn-leak-labelmgr
[mirror_frr.git] / lib / nexthop_group.c
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
22 #include <vrf.h>
23 #include <nexthop.h>
24 #include <nexthop_group.h>
25 #include <vty.h>
26 #include <command.h>
27
28 #ifndef VTYSH_EXTRACT_PL
29 #include "lib/nexthop_group_clippy.c"
30 #endif
31
32 DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group")
33
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);
41 };
42
43 static struct nexthop_group_hooks nhg_hooks;
44
45 static inline int
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)
50
51 struct nhgc_entry_head nhgc_entries;
52
53 static inline int
54 nexthop_group_cmd_compare(const struct nexthop_group_cmd *nhgc1,
55 const struct nexthop_group_cmd *nhgc2)
56 {
57 return strcmp(nhgc1->name, nhgc2->name);
58 }
59
60 struct nexthop *nexthop_exists(struct nexthop_group *nhg, struct nexthop *nh)
61 {
62 struct nexthop *nexthop;
63
64 for (nexthop = nhg->nexthop; nexthop; nexthop = nexthop->next) {
65 if (nexthop_same(nh, nexthop))
66 return nexthop;
67 }
68
69 return NULL;
70 }
71
72 struct nexthop_group *nexthop_group_new(void)
73 {
74 return XCALLOC(MTYPE_NEXTHOP_GROUP, sizeof(struct nexthop_group));
75 }
76
77 void nexthop_group_delete(struct nexthop_group **nhg)
78 {
79 XFREE(MTYPE_NEXTHOP_GROUP, *nhg);
80 }
81
82 /* Add nexthop to the end of a nexthop list. */
83 void nexthop_add(struct nexthop **target, struct nexthop *nexthop)
84 {
85 struct nexthop *last;
86
87 for (last = *target; last && last->next; last = last->next)
88 ;
89 if (last)
90 last->next = nexthop;
91 else
92 *target = nexthop;
93 nexthop->prev = last;
94 }
95
96 /* Delete nexthop from a nexthop list. */
97 void nexthop_del(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 break;
104 }
105
106 assert(nexthop);
107
108 if (nexthop->prev)
109 nexthop->prev->next = nexthop->next;
110 else
111 nhg->nexthop = nexthop->next;
112
113 if (nexthop->next)
114 nexthop->next->prev = nexthop->prev;
115 }
116
117 void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
118 struct nexthop *rparent)
119 {
120 struct nexthop *nexthop;
121 struct nexthop *nh1;
122
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;
134 if (nh1->nh_label)
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);
139
140 if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE))
141 copy_nexthops(&nexthop->resolved, nh1->resolved,
142 nexthop);
143 }
144 }
145
146 static void nhgc_delete_nexthops(struct nexthop_group_cmd *nhgc)
147 {
148 struct nexthop *nexthop;
149
150 nexthop = nhgc->nhg.nexthop;
151 while (nexthop) {
152 struct nexthop *next = nexthop_next(nexthop);
153
154 if (nhg_hooks.del_nexthop)
155 nhg_hooks.del_nexthop(nhgc, nexthop);
156
157 nexthop_free(nexthop);
158
159 nexthop = next;
160 }
161 }
162
163 struct nexthop_group_cmd *nhgc_find(const char *name)
164 {
165 struct nexthop_group_cmd find;
166
167 strlcpy(find.name, name, sizeof(find.name));
168
169 return RB_FIND(nhgc_entry_head, &nhgc_entries, &find);
170 }
171
172 static struct nexthop_group_cmd *nhgc_get(const char *name)
173 {
174 struct nexthop_group_cmd *nhgc;
175
176 nhgc = nhgc_find(name);
177 if (!nhgc) {
178 nhgc = XCALLOC(MTYPE_TMP, sizeof(*nhgc));
179 strlcpy(nhgc->name, name, sizeof(nhgc->name));
180
181 QOBJ_REG(nhgc, nexthop_group_cmd);
182 RB_INSERT(nhgc_entry_head, &nhgc_entries, nhgc);
183
184 if (nhg_hooks.new)
185 nhg_hooks.new(name);
186 }
187
188 return nhgc;
189 }
190
191 static void nhgc_delete(struct nexthop_group_cmd *nhgc)
192 {
193 nhgc_delete_nexthops(nhgc);
194
195 if (nhg_hooks.delete)
196 nhg_hooks.delete(nhgc->name);
197
198 RB_REMOVE(nhgc_entry_head, &nhgc_entries, nhgc);
199 }
200
201 DEFINE_QOBJ_TYPE(nexthop_group_cmd)
202
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")
206 {
207 const char *nhg_name = argv[1]->arg;
208 struct nexthop_group_cmd *nhgc = NULL;
209
210 nhgc = nhgc_get(nhg_name);
211 VTY_PUSH_CONTEXT(NH_GROUP_NODE, nhgc);
212
213 return CMD_SUCCESS;
214 }
215
216 DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NAME",
217 NO_STR
218 "Delete the nexthop-group\n"
219 "Specify the NAME of the nexthop-group\n")
220 {
221 const char *nhg_name = argv[2]->arg;
222 struct nexthop_group_cmd *nhgc = NULL;
223
224 nhgc = nhgc_find(nhg_name);
225 if (nhgc)
226 nhgc_delete(nhgc);
227
228 return CMD_SUCCESS;
229 }
230
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]",
233 NO_STR
234 "Specify one of the nexthops in this ECMP group\n"
235 "v4 Address\n"
236 "v6 Address\n"
237 "Interface to use\n"
238 "If the nexthop is in a different vrf tell us\n"
239 "The nexthop-vrf Name\n")
240 {
241 VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
242 struct vrf *vrf;
243 struct nexthop nhop;
244 struct nexthop *nh;
245
246 if (name)
247 vrf = vrf_lookup_by_name(name);
248 else
249 vrf = vrf_lookup_by_id(VRF_DEFAULT);
250
251 if (!vrf) {
252 vty_out(vty, "Specified: %s is non-existent\n", name);
253 return CMD_WARNING;
254 }
255
256 memset(&nhop, 0, sizeof(nhop));
257 nhop.vrf_id = vrf->vrf_id;
258
259 if (addr->sa.sa_family == AF_INET) {
260 nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
261 if (intf) {
262 nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
263 nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
264 if (nhop.ifindex == IFINDEX_INTERNAL) {
265 vty_out(vty,
266 "Specified Intf %s does not exist in vrf: %s\n",
267 intf, vrf->name);
268 return CMD_WARNING;
269 }
270 } else
271 nhop.type = NEXTHOP_TYPE_IPV4;
272 } else {
273 memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16);
274 if (intf) {
275 nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
276 nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
277 if (nhop.ifindex == IFINDEX_INTERNAL) {
278 vty_out(vty,
279 "Specified Intf %s does not exist in vrf: %s\n",
280 intf, vrf->name);
281 return CMD_WARNING;
282 }
283 } else
284 nhop.type = NEXTHOP_TYPE_IPV6;
285 }
286
287 nh = nexthop_exists(&nhgc->nhg, &nhop);
288
289 if (no) {
290 if (nh) {
291 nexthop_del(&nhgc->nhg, nh);
292
293 if (nhg_hooks.del_nexthop)
294 nhg_hooks.del_nexthop(nhgc, nh);
295
296 nexthop_free(nh);
297 }
298 } else if (!nh) {
299 /* must be adding new nexthop since !no and !nexthop_exists */
300 nh = nexthop_new();
301
302 memcpy(nh, &nhop, sizeof(nhop));
303 nexthop_add(&nhgc->nhg.nexthop, nh);
304
305 if (nhg_hooks.add_nexthop)
306 nhg_hooks.add_nexthop(nhgc, nh);
307 }
308
309 return CMD_SUCCESS;
310 }
311
312 struct cmd_node nexthop_group_node = {
313 NH_GROUP_NODE,
314 "%s(config-nh-group)# ",
315 1
316 };
317
318 void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
319 {
320 char buf[100];
321 struct vrf *vrf;
322
323 vty_out(vty, "nexthop ");
324
325 switch (nh->type) {
326 case NEXTHOP_TYPE_IFINDEX:
327 vty_out(vty, "%s", ifindex2ifname(nh->ifindex, nh->vrf_id));
328 break;
329 case NEXTHOP_TYPE_IPV4:
330 vty_out(vty, "%s", inet_ntoa(nh->gate.ipv4));
331 break;
332 case NEXTHOP_TYPE_IPV4_IFINDEX:
333 vty_out(vty, "%s %s", inet_ntoa(nh->gate.ipv4),
334 ifindex2ifname(nh->ifindex, nh->vrf_id));
335 break;
336 case NEXTHOP_TYPE_IPV6:
337 vty_out(vty, "%s",
338 inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf)));
339 break;
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));
344 break;
345 case NEXTHOP_TYPE_BLACKHOLE:
346 break;
347 }
348
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);
352 }
353 vty_out(vty, "\n");
354 }
355
356 static int nexthop_group_write(struct vty *vty)
357 {
358 struct nexthop_group_cmd *nhgc;
359 struct nexthop *nh;
360
361 RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) {
362 vty_out(vty, "nexthop-group %s\n", nhgc->name);
363
364 for (nh = nhgc->nhg.nexthop; nh; nh = nh->next) {
365 vty_out(vty, " ");
366 nexthop_group_write_nexthop(vty, nh);
367 }
368
369 vty_out(vty, "!\n");
370 }
371
372 return 1;
373 }
374
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))
381 {
382 RB_INIT(nhgc_entry_head, &nhgc_entries);
383
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);
387
388 install_default(NH_GROUP_NODE);
389 install_element(NH_GROUP_NODE, &ecmp_nexthops_cmd);
390
391 memset(&nhg_hooks, 0, sizeof(nhg_hooks));
392
393 if (new)
394 nhg_hooks.new = new;
395 if (add_nexthop)
396 nhg_hooks.add_nexthop = add_nexthop;
397 if (del_nexthop)
398 nhg_hooks.del_nexthop = del_nexthop;
399 if (delete)
400 nhg_hooks.delete = delete;
401 }