]> git.proxmox.com Git - mirror_frr.git/blob - lib/nexthop.c
zebra, lib: fix the ZEBRA_INTERFACE_VRF_UPDATE zapi message
[mirror_frr.git] / lib / nexthop.c
1 /* A generic nexthop structure
2 * Copyright (C) 2013 Cumulus Networks, Inc.
3 *
4 * This file is part of Quagga.
5 *
6 * Quagga 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
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * Quagga is distributed in the hope that it will be useful, but
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 *
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 "prefix.h"
23 #include "table.h"
24 #include "memory.h"
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"
33 #include "mpls.h"
34 #include "jhash.h"
35
36 DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop")
37 DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label")
38
39 /* check if nexthops are same, non-recursive */
40 int nexthop_same_no_recurse(const struct nexthop *next1,
41 const struct nexthop *next2)
42 {
43 if (next1->type != next2->type)
44 return 0;
45
46 switch (next1->type) {
47 case NEXTHOP_TYPE_IPV4:
48 case NEXTHOP_TYPE_IPV4_IFINDEX:
49 if (!IPV4_ADDR_SAME(&next1->gate.ipv4, &next2->gate.ipv4))
50 return 0;
51 if (next1->ifindex && (next1->ifindex != next2->ifindex))
52 return 0;
53 break;
54 case NEXTHOP_TYPE_IFINDEX:
55 if (next1->ifindex != next2->ifindex)
56 return 0;
57 break;
58 case NEXTHOP_TYPE_IPV6:
59 if (!IPV6_ADDR_SAME(&next1->gate.ipv6, &next2->gate.ipv6))
60 return 0;
61 break;
62 case NEXTHOP_TYPE_IPV6_IFINDEX:
63 if (!IPV6_ADDR_SAME(&next1->gate.ipv6, &next2->gate.ipv6))
64 return 0;
65 if (next1->ifindex != next2->ifindex)
66 return 0;
67 break;
68 default:
69 /* do nothing */
70 break;
71 }
72 return 1;
73 }
74
75 int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2)
76 {
77 int type1 = NEXTHOP_FIRSTHOPTYPE(next1->type);
78 int type2 = NEXTHOP_FIRSTHOPTYPE(next2->type);
79
80 if (type1 != type2)
81 return 0;
82 switch (type1) {
83 case NEXTHOP_TYPE_IPV4_IFINDEX:
84 if (!IPV4_ADDR_SAME(&next1->gate.ipv4, &next2->gate.ipv4))
85 return 0;
86 if (next1->ifindex != next2->ifindex)
87 return 0;
88 break;
89 case NEXTHOP_TYPE_IFINDEX:
90 if (next1->ifindex != next2->ifindex)
91 return 0;
92 break;
93 case NEXTHOP_TYPE_IPV6_IFINDEX:
94 if (!IPV6_ADDR_SAME(&next1->gate.ipv6, &next2->gate.ipv6))
95 return 0;
96 if (next1->ifindex != next2->ifindex)
97 return 0;
98 break;
99 default:
100 /* do nothing */
101 break;
102 }
103 return 1;
104 }
105
106 /*
107 * nexthop_type_to_str
108 */
109 const char *nexthop_type_to_str(enum nexthop_types_t nh_type)
110 {
111 static const char *desc[] = {
112 "none", "Directly connected",
113 "IPv4 nexthop", "IPv4 nexthop with ifindex",
114 "IPv6 nexthop", "IPv6 nexthop with ifindex",
115 "Null0 nexthop",
116 };
117
118 return desc[nh_type];
119 }
120
121 /*
122 * Check if the labels match for the 2 nexthops specified.
123 */
124 int nexthop_labels_match(struct nexthop *nh1, struct nexthop *nh2)
125 {
126 struct mpls_label_stack *nhl1, *nhl2;
127
128 nhl1 = nh1->nh_label;
129 nhl2 = nh2->nh_label;
130 if (!nhl1 || !nhl2)
131 return 0;
132
133 if (nhl1->num_labels != nhl2->num_labels)
134 return 0;
135
136 if (memcmp(nhl1->label, nhl2->label, nhl1->num_labels))
137 return 0;
138
139 return 1;
140 }
141
142 struct nexthop *nexthop_new(void)
143 {
144 return XCALLOC(MTYPE_NEXTHOP, sizeof(struct nexthop));
145 }
146
147 /* Free nexthop. */
148 void nexthop_free(struct nexthop *nexthop)
149 {
150 nexthop_del_labels(nexthop);
151 if (nexthop->resolved)
152 nexthops_free(nexthop->resolved);
153 XFREE(MTYPE_NEXTHOP, nexthop);
154 }
155
156 /* Frees a list of nexthops */
157 void nexthops_free(struct nexthop *nexthop)
158 {
159 struct nexthop *nh, *next;
160
161 for (nh = nexthop; nh; nh = next) {
162 next = nh->next;
163 nexthop_free(nh);
164 }
165 }
166
167 bool nexthop_same(const struct nexthop *nh1, const struct nexthop *nh2)
168 {
169 if (nh1 && !nh2)
170 return false;
171
172 if (!nh1 && nh2)
173 return false;
174
175 if (nh1 == nh2)
176 return true;
177
178 if (nh1->vrf_id != nh2->vrf_id)
179 return false;
180
181 if (nh1->type != nh2->type)
182 return false;
183
184 switch (nh1->type) {
185 case NEXTHOP_TYPE_IFINDEX:
186 if (nh1->ifindex != nh2->ifindex)
187 return false;
188 break;
189 case NEXTHOP_TYPE_IPV4:
190 if (nh1->gate.ipv4.s_addr != nh2->gate.ipv4.s_addr)
191 return false;
192 break;
193 case NEXTHOP_TYPE_IPV4_IFINDEX:
194 if (nh1->gate.ipv4.s_addr != nh2->gate.ipv4.s_addr)
195 return false;
196 if (nh1->ifindex != nh2->ifindex)
197 return false;
198 break;
199 case NEXTHOP_TYPE_IPV6:
200 if (memcmp(&nh1->gate.ipv6, &nh2->gate.ipv6, 16))
201 return false;
202 break;
203 case NEXTHOP_TYPE_IPV6_IFINDEX:
204 if (memcmp(&nh1->gate.ipv6, &nh2->gate.ipv6, 16))
205 return false;
206 if (nh1->ifindex != nh2->ifindex)
207 return false;
208 break;
209 case NEXTHOP_TYPE_BLACKHOLE:
210 if (nh1->bh_type != nh2->bh_type)
211 return false;
212 break;
213 }
214
215 return true;
216 }
217
218 /* Update nexthop with label information. */
219 void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
220 uint8_t num_labels, mpls_label_t *label)
221 {
222 struct mpls_label_stack *nh_label;
223 int i;
224
225 nexthop->nh_label_type = type;
226 nh_label = XCALLOC(MTYPE_NH_LABEL,
227 sizeof(struct mpls_label_stack)
228 + num_labels * sizeof(mpls_label_t));
229 nh_label->num_labels = num_labels;
230 for (i = 0; i < num_labels; i++)
231 nh_label->label[i] = *(label + i);
232 nexthop->nh_label = nh_label;
233 }
234
235 /* Free label information of nexthop, if present. */
236 void nexthop_del_labels(struct nexthop *nexthop)
237 {
238 if (nexthop->nh_label) {
239 XFREE(MTYPE_NH_LABEL, nexthop->nh_label);
240 nexthop->nh_label_type = ZEBRA_LSP_NONE;
241 }
242 }
243
244 const char *nexthop2str(const struct nexthop *nexthop, char *str, int size)
245 {
246 switch (nexthop->type) {
247 case NEXTHOP_TYPE_IFINDEX:
248 snprintf(str, size, "if %u", nexthop->ifindex);
249 break;
250 case NEXTHOP_TYPE_IPV4:
251 case NEXTHOP_TYPE_IPV4_IFINDEX:
252 snprintf(str, size, "%s if %u", inet_ntoa(nexthop->gate.ipv4),
253 nexthop->ifindex);
254 break;
255 case NEXTHOP_TYPE_IPV6:
256 case NEXTHOP_TYPE_IPV6_IFINDEX:
257 snprintf(str, size, "%s if %u", inet6_ntoa(nexthop->gate.ipv6),
258 nexthop->ifindex);
259 break;
260 case NEXTHOP_TYPE_BLACKHOLE:
261 snprintf(str, size, "blackhole");
262 break;
263 default:
264 snprintf(str, size, "unknown");
265 break;
266 }
267
268 return str;
269 }
270
271 /*
272 * Iteration step for ALL_NEXTHOPS macro:
273 * This is the tricky part. Check if `nexthop' has
274 * NEXTHOP_FLAG_RECURSIVE set. If yes, this implies that `nexthop' has
275 * at least one nexthop attached to `nexthop->resolved', which will be
276 * the next one.
277 *
278 * If NEXTHOP_FLAG_RECURSIVE is not set, `nexthop' will progress in its
279 * current chain. In case its current chain end is reached, it will move
280 * upwards in the recursion levels and progress there. Whenever a step
281 * forward in a chain is done, recursion will be checked again.
282 * In a nustshell, it's equivalent to a pre-traversal order assuming that
283 * left branch is 'resolved' and right branch is 'next':
284 * https://en.wikipedia.org/wiki/Tree_traversal#/media/File:Sorted_binary_tree_preorder.svg
285 */
286 struct nexthop *nexthop_next(struct nexthop *nexthop)
287 {
288 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
289 return nexthop->resolved;
290
291 if (nexthop->next)
292 return nexthop->next;
293
294 for (struct nexthop *par = nexthop->rparent; par; par = par->rparent)
295 if (par->next)
296 return par->next;
297
298 return NULL;
299 }
300
301 unsigned int nexthop_level(struct nexthop *nexthop)
302 {
303 unsigned int rv = 0;
304
305 for (struct nexthop *par = nexthop->rparent; par; par = par->rparent)
306 rv++;
307
308 return rv;
309 }
310
311 uint32_t nexthop_hash(struct nexthop *nexthop)
312 {
313 uint32_t key;
314
315 key = jhash_1word(nexthop->vrf_id, 0x45afe398);
316 key = jhash_1word(nexthop->ifindex, key);
317 key = jhash_1word(nexthop->type, key);
318 key = jhash(&nexthop->gate, sizeof(union g_addr), key);
319
320 return key;
321 }