]> git.proxmox.com Git - mirror_frr.git/blame - lib/nexthop.c
*: conform with COMMUNITY.md formatting rules, via 'make indent'
[mirror_frr.git] / lib / nexthop.c
CommitLineData
fb018d25
DS
1/* A generic nexthop structure
2 * Copyright (C) 2013 Cumulus Networks, Inc.
3 *
a399694f 4 * This file is part of Quagga.
fb018d25 5 *
a399694f 6 * Quagga is free software; you can redistribute it and/or modify it
fb018d25
DS
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
a399694f 11 * Quagga is distributed in the hope that it will be useful, but
fb018d25
DS
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
896014f4
DL
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
fb018d25
DS
19 */
20#include <zebra.h>
21
22#include "prefix.h"
23#include "table.h"
24#include "memory.h"
fb018d25
DS
25#include "command.h"
26#include "if.h"
27#include "log.h"
28#include "sockunion.h"
29#include "linklist.h"
30#include "thread.h"
31#include "prefix.h"
32#include "nexthop.h"
40c7bdb0 33#include "mpls.h"
fb018d25 34
d62a17ae 35DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop")
36DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label")
4a1ab8e4 37
fb018d25 38/* check if nexthops are same, non-recursive */
fd36be7e
DL
39int nexthop_same_no_recurse(const struct nexthop *next1,
40 const struct nexthop *next2)
fb018d25 41{
d62a17ae 42 if (next1->type != next2->type)
43 return 0;
44
45 switch (next1->type) {
46 case NEXTHOP_TYPE_IPV4:
47 case NEXTHOP_TYPE_IPV4_IFINDEX:
48 if (!IPV4_ADDR_SAME(&next1->gate.ipv4, &next2->gate.ipv4))
49 return 0;
50 if (next1->ifindex && (next1->ifindex != next2->ifindex))
51 return 0;
52 break;
53 case NEXTHOP_TYPE_IFINDEX:
54 if (next1->ifindex != next2->ifindex)
55 return 0;
56 break;
57 case NEXTHOP_TYPE_IPV6:
58 if (!IPV6_ADDR_SAME(&next1->gate.ipv6, &next2->gate.ipv6))
59 return 0;
60 break;
61 case NEXTHOP_TYPE_IPV6_IFINDEX:
62 if (!IPV6_ADDR_SAME(&next1->gate.ipv6, &next2->gate.ipv6))
63 return 0;
64 if (next1->ifindex != next2->ifindex)
65 return 0;
25b9cb0c
DL
66 break;
67 default:
68 /* do nothing */
69 break;
70 }
71 return 1;
72}
73
996c9314 74int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2)
25b9cb0c
DL
75{
76 int type1 = NEXTHOP_FIRSTHOPTYPE(next1->type);
77 int type2 = NEXTHOP_FIRSTHOPTYPE(next2->type);
78
79 if (type1 != type2)
80 return 0;
996c9314 81 switch (type1) {
25b9cb0c 82 case NEXTHOP_TYPE_IPV4_IFINDEX:
996c9314 83 if (!IPV4_ADDR_SAME(&next1->gate.ipv4, &next2->gate.ipv4))
25b9cb0c
DL
84 return 0;
85 if (next1->ifindex != next2->ifindex)
86 return 0;
87 break;
88 case NEXTHOP_TYPE_IFINDEX:
89 if (next1->ifindex != next2->ifindex)
90 return 0;
91 break;
92 case NEXTHOP_TYPE_IPV6_IFINDEX:
996c9314 93 if (!IPV6_ADDR_SAME(&next1->gate.ipv6, &next2->gate.ipv6))
25b9cb0c
DL
94 return 0;
95 if (next1->ifindex != next2->ifindex)
96 return 0;
d62a17ae 97 break;
98 default:
99 /* do nothing */
100 break;
101 }
102 return 1;
fb018d25
DS
103}
104
105/*
106 * nexthop_type_to_str
107 */
d62a17ae 108const char *nexthop_type_to_str(enum nexthop_types_t nh_type)
fb018d25 109{
d62a17ae 110 static const char *desc[] = {
111 "none", "Directly connected",
112 "IPv4 nexthop", "IPv4 nexthop with ifindex",
113 "IPv6 nexthop", "IPv6 nexthop with ifindex",
114 "Null0 nexthop",
115 };
116
117 return desc[nh_type];
fb018d25 118}
a399694f 119
a64448ba
DS
120/*
121 * Check if the labels match for the 2 nexthops specified.
122 */
d62a17ae 123int nexthop_labels_match(struct nexthop *nh1, struct nexthop *nh2)
a64448ba 124{
8ecdb26e 125 struct mpls_label_stack *nhl1, *nhl2;
a64448ba 126
d62a17ae 127 nhl1 = nh1->nh_label;
128 nhl2 = nh2->nh_label;
3f58e1b3 129 if (!nhl1 || !nhl2)
d62a17ae 130 return 0;
a64448ba 131
d62a17ae 132 if (nhl1->num_labels != nhl2->num_labels)
133 return 0;
a64448ba 134
d62a17ae 135 if (memcmp(nhl1->label, nhl2->label, nhl1->num_labels))
136 return 0;
a64448ba 137
d62a17ae 138 return 1;
a64448ba
DS
139}
140
d62a17ae 141struct nexthop *nexthop_new(void)
a399694f 142{
d62a17ae 143 return XCALLOC(MTYPE_NEXTHOP, sizeof(struct nexthop));
a399694f
DS
144}
145
146/* Add nexthop to the end of a nexthop list. */
d62a17ae 147void nexthop_add(struct nexthop **target, struct nexthop *nexthop)
a399694f 148{
d62a17ae 149 struct nexthop *last;
150
151 for (last = *target; last && last->next; last = last->next)
152 ;
153 if (last)
154 last->next = nexthop;
155 else
156 *target = nexthop;
157 nexthop->prev = last;
a399694f
DS
158}
159
d62a17ae 160void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
161 struct nexthop *rparent)
a399694f 162{
d62a17ae 163 struct nexthop *nexthop;
164 struct nexthop *nh1;
165
166 for (nh1 = nh; nh1; nh1 = nh1->next) {
167 nexthop = nexthop_new();
4a7371e9 168 nexthop->vrf_id = nh1->vrf_id;
87440283
DW
169 nexthop->ifindex = nh1->ifindex;
170 nexthop->type = nh1->type;
171 nexthop->flags = nh1->flags;
172 memcpy(&nexthop->gate, &nh1->gate, sizeof(nh1->gate));
173 memcpy(&nexthop->src, &nh1->src, sizeof(nh1->src));
996c9314
LB
174 memcpy(&nexthop->rmap_src, &nh1->rmap_src,
175 sizeof(nh1->rmap_src));
d62a17ae 176 nexthop->rparent = rparent;
87440283
DW
177 if (nh1->nh_label)
178 nexthop_add_labels(nexthop, nh1->nh_label_type,
179 nh1->nh_label->num_labels,
180 &nh1->nh_label->label[0]);
d62a17ae 181 nexthop_add(tnh, nexthop);
182
183 if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE))
184 copy_nexthops(&nexthop->resolved, nh1->resolved,
185 nexthop);
186 }
a399694f
DS
187}
188
189/* Free nexthop. */
d62a17ae 190void nexthop_free(struct nexthop *nexthop)
a399694f 191{
d62a17ae 192 nexthop_del_labels(nexthop);
193 if (nexthop->resolved)
194 nexthops_free(nexthop->resolved);
195 XFREE(MTYPE_NEXTHOP, nexthop);
a399694f
DS
196}
197
198/* Frees a list of nexthops */
d62a17ae 199void nexthops_free(struct nexthop *nexthop)
a399694f 200{
d62a17ae 201 struct nexthop *nh, *next;
a399694f 202
d62a17ae 203 for (nh = nexthop; nh; nh = next) {
204 next = nh->next;
205 nexthop_free(nh);
206 }
a399694f 207}
80c2442a 208
40c7bdb0 209/* Update nexthop with label information. */
d62a17ae 210void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
211 u_int8_t num_labels, mpls_label_t *label)
40c7bdb0 212{
8ecdb26e 213 struct mpls_label_stack *nh_label;
d62a17ae 214 int i;
215
216 nexthop->nh_label_type = type;
217 nh_label = XCALLOC(MTYPE_NH_LABEL,
8ecdb26e 218 sizeof(struct mpls_label_stack)
d62a17ae 219 + num_labels * sizeof(mpls_label_t));
220 nh_label->num_labels = num_labels;
221 for (i = 0; i < num_labels; i++)
222 nh_label->label[i] = *(label + i);
223 nexthop->nh_label = nh_label;
40c7bdb0 224}
225
226/* Free label information of nexthop, if present. */
d62a17ae 227void nexthop_del_labels(struct nexthop *nexthop)
40c7bdb0 228{
d62a17ae 229 if (nexthop->nh_label) {
230 XFREE(MTYPE_NH_LABEL, nexthop->nh_label);
231 nexthop->nh_label_type = ZEBRA_LSP_NONE;
232 }
40c7bdb0 233}
234
d62a17ae 235const char *nexthop2str(struct nexthop *nexthop, char *str, int size)
80c2442a 236{
d62a17ae 237 switch (nexthop->type) {
238 case NEXTHOP_TYPE_IFINDEX:
239 snprintf(str, size, "if %u", nexthop->ifindex);
240 break;
241 case NEXTHOP_TYPE_IPV4:
242 snprintf(str, size, "%s", inet_ntoa(nexthop->gate.ipv4));
243 break;
244 case NEXTHOP_TYPE_IPV4_IFINDEX:
245 snprintf(str, size, "%s if %u", inet_ntoa(nexthop->gate.ipv4),
246 nexthop->ifindex);
247 break;
248 case NEXTHOP_TYPE_IPV6:
249 snprintf(str, size, "%s", inet6_ntoa(nexthop->gate.ipv6));
250 break;
251 case NEXTHOP_TYPE_IPV6_IFINDEX:
252 snprintf(str, size, "%s if %u", inet6_ntoa(nexthop->gate.ipv6),
253 nexthop->ifindex);
254 break;
255 case NEXTHOP_TYPE_BLACKHOLE:
256 snprintf(str, size, "blackhole");
257 break;
258 default:
259 snprintf(str, size, "unknown");
260 break;
261 }
262
263 return str;
80c2442a 264}
9fb47c05
CF
265
266/*
267 * Iteration step for ALL_NEXTHOPS macro:
268 * This is the tricky part. Check if `nexthop' has
269 * NEXTHOP_FLAG_RECURSIVE set. If yes, this implies that `nexthop' has
270 * at least one nexthop attached to `nexthop->resolved', which will be
271 * the next one.
272 *
273 * If NEXTHOP_FLAG_RECURSIVE is not set, `nexthop' will progress in its
274 * current chain. In case its current chain end is reached, it will move
275 * upwards in the recursion levels and progress there. Whenever a step
276 * forward in a chain is done, recursion will be checked again.
277 * In a nustshell, it's equivalent to a pre-traversal order assuming that
278 * left branch is 'resolved' and right branch is 'next':
279 * https://en.wikipedia.org/wiki/Tree_traversal#/media/File:Sorted_binary_tree_preorder.svg
280 */
d62a17ae 281struct nexthop *nexthop_next(struct nexthop *nexthop)
9fb47c05 282{
d62a17ae 283 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
284 return nexthop->resolved;
9fb47c05 285
d62a17ae 286 if (nexthop->next)
287 return nexthop->next;
9fb47c05 288
d62a17ae 289 for (struct nexthop *par = nexthop->rparent; par; par = par->rparent)
290 if (par->next)
291 return par->next;
9fb47c05 292
d62a17ae 293 return NULL;
9fb47c05 294}
e3054ee9 295
d62a17ae 296unsigned int nexthop_level(struct nexthop *nexthop)
e3054ee9 297{
d62a17ae 298 unsigned int rv = 0;
e3054ee9 299
d62a17ae 300 for (struct nexthop *par = nexthop->rparent; par; par = par->rparent)
301 rv++;
e3054ee9 302
d62a17ae 303 return rv;
e3054ee9 304}