1 /* A generic nexthop structure
2 * Copyright (C) 2013 Cumulus Networks, Inc.
4 * This file is part of Quagga.
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
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.
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
28 #include "sockunion.h"
36 DEFINE_MTYPE_STATIC(LIB
, NEXTHOP
, "Nexthop")
37 DEFINE_MTYPE_STATIC(LIB
, NH_LABEL
, "Nexthop label")
39 int nexthop_cmp(const struct nexthop
*next1
, const struct nexthop
*next2
)
44 if (next1
->vrf_id
< next2
->vrf_id
)
47 if (next1
->vrf_id
> next2
->vrf_id
)
50 if (next1
->type
< next2
->type
)
53 if (next1
->type
> next2
->type
)
57 case NEXTHOP_TYPE_IPV4
:
58 n1
= ntohl(next1
->gate
.ipv4
.s_addr
);
59 n2
= ntohl(next2
->gate
.ipv4
.s_addr
);
65 case NEXTHOP_TYPE_IPV6
:
66 ret
= memcmp(&next1
->gate
, &next2
->gate
, sizeof(union g_addr
));
70 case NEXTHOP_TYPE_IPV4_IFINDEX
:
71 case NEXTHOP_TYPE_IPV6_IFINDEX
:
72 ret
= memcmp(&next1
->gate
, &next2
->gate
, sizeof(union g_addr
));
75 /* Intentional Fall-Through */
76 case NEXTHOP_TYPE_IFINDEX
:
77 if (next1
->ifindex
< next2
->ifindex
)
80 if (next1
->ifindex
> next2
->ifindex
)
83 case NEXTHOP_TYPE_BLACKHOLE
:
84 if (next1
->bh_type
< next2
->bh_type
)
87 if (next1
->bh_type
> next2
->bh_type
)
92 ret
= memcmp(&next1
->src
, &next2
->src
, sizeof(union g_addr
));
96 /* check if nexthops are same, non-recursive */
97 int nexthop_same_no_recurse(const struct nexthop
*next1
,
98 const struct nexthop
*next2
)
100 if (next1
->type
!= next2
->type
)
103 switch (next1
->type
) {
104 case NEXTHOP_TYPE_IPV4
:
105 case NEXTHOP_TYPE_IPV4_IFINDEX
:
106 if (!IPV4_ADDR_SAME(&next1
->gate
.ipv4
, &next2
->gate
.ipv4
))
108 if (next1
->ifindex
&& (next1
->ifindex
!= next2
->ifindex
))
111 case NEXTHOP_TYPE_IFINDEX
:
112 if (next1
->ifindex
!= next2
->ifindex
)
115 case NEXTHOP_TYPE_IPV6
:
116 if (!IPV6_ADDR_SAME(&next1
->gate
.ipv6
, &next2
->gate
.ipv6
))
119 case NEXTHOP_TYPE_IPV6_IFINDEX
:
120 if (!IPV6_ADDR_SAME(&next1
->gate
.ipv6
, &next2
->gate
.ipv6
))
122 if (next1
->ifindex
!= next2
->ifindex
)
132 int nexthop_same_firsthop(struct nexthop
*next1
, struct nexthop
*next2
)
134 int type1
= NEXTHOP_FIRSTHOPTYPE(next1
->type
);
135 int type2
= NEXTHOP_FIRSTHOPTYPE(next2
->type
);
140 case NEXTHOP_TYPE_IPV4_IFINDEX
:
141 if (!IPV4_ADDR_SAME(&next1
->gate
.ipv4
, &next2
->gate
.ipv4
))
143 if (next1
->ifindex
!= next2
->ifindex
)
146 case NEXTHOP_TYPE_IFINDEX
:
147 if (next1
->ifindex
!= next2
->ifindex
)
150 case NEXTHOP_TYPE_IPV6_IFINDEX
:
151 if (!IPV6_ADDR_SAME(&next1
->gate
.ipv6
, &next2
->gate
.ipv6
))
153 if (next1
->ifindex
!= next2
->ifindex
)
164 * nexthop_type_to_str
166 const char *nexthop_type_to_str(enum nexthop_types_t nh_type
)
168 static const char *desc
[] = {
169 "none", "Directly connected",
170 "IPv4 nexthop", "IPv4 nexthop with ifindex",
171 "IPv6 nexthop", "IPv6 nexthop with ifindex",
175 return desc
[nh_type
];
179 * Check if the labels match for the 2 nexthops specified.
181 int nexthop_labels_match(const struct nexthop
*nh1
, const struct nexthop
*nh2
)
183 const struct mpls_label_stack
*nhl1
, *nhl2
;
185 nhl1
= nh1
->nh_label
;
186 nhl2
= nh2
->nh_label
;
188 /* No labels is a match */
195 if (nhl1
->num_labels
!= nhl2
->num_labels
)
198 if (memcmp(nhl1
->label
, nhl2
->label
, nhl1
->num_labels
))
204 struct nexthop
*nexthop_new(void)
206 return XCALLOC(MTYPE_NEXTHOP
, sizeof(struct nexthop
));
210 void nexthop_free(struct nexthop
*nexthop
)
212 nexthop_del_labels(nexthop
);
213 if (nexthop
->resolved
)
214 nexthops_free(nexthop
->resolved
);
215 XFREE(MTYPE_NEXTHOP
, nexthop
);
218 /* Frees a list of nexthops */
219 void nexthops_free(struct nexthop
*nexthop
)
221 struct nexthop
*nh
, *next
;
223 for (nh
= nexthop
; nh
; nh
= next
) {
229 bool nexthop_same(const struct nexthop
*nh1
, const struct nexthop
*nh2
)
240 if (nh1
->vrf_id
!= nh2
->vrf_id
)
243 if (nh1
->type
!= nh2
->type
)
247 case NEXTHOP_TYPE_IFINDEX
:
248 if (nh1
->ifindex
!= nh2
->ifindex
)
251 case NEXTHOP_TYPE_IPV4
:
252 if (nh1
->gate
.ipv4
.s_addr
!= nh2
->gate
.ipv4
.s_addr
)
255 case NEXTHOP_TYPE_IPV4_IFINDEX
:
256 if (nh1
->gate
.ipv4
.s_addr
!= nh2
->gate
.ipv4
.s_addr
)
258 if (nh1
->ifindex
!= nh2
->ifindex
)
261 case NEXTHOP_TYPE_IPV6
:
262 if (memcmp(&nh1
->gate
.ipv6
, &nh2
->gate
.ipv6
, 16))
265 case NEXTHOP_TYPE_IPV6_IFINDEX
:
266 if (memcmp(&nh1
->gate
.ipv6
, &nh2
->gate
.ipv6
, 16))
268 if (nh1
->ifindex
!= nh2
->ifindex
)
271 case NEXTHOP_TYPE_BLACKHOLE
:
272 if (nh1
->bh_type
!= nh2
->bh_type
)
277 /* Compare labels too (if present) */
278 return (!!nexthop_labels_match(nh1
, nh2
));
281 /* Update nexthop with label information. */
282 void nexthop_add_labels(struct nexthop
*nexthop
, enum lsp_types_t type
,
283 uint8_t num_labels
, mpls_label_t
*label
)
285 struct mpls_label_stack
*nh_label
;
288 nexthop
->nh_label_type
= type
;
289 nh_label
= XCALLOC(MTYPE_NH_LABEL
,
290 sizeof(struct mpls_label_stack
)
291 + num_labels
* sizeof(mpls_label_t
));
292 nh_label
->num_labels
= num_labels
;
293 for (i
= 0; i
< num_labels
; i
++)
294 nh_label
->label
[i
] = *(label
+ i
);
295 nexthop
->nh_label
= nh_label
;
298 /* Free label information of nexthop, if present. */
299 void nexthop_del_labels(struct nexthop
*nexthop
)
301 if (nexthop
->nh_label
) {
302 XFREE(MTYPE_NH_LABEL
, nexthop
->nh_label
);
303 nexthop
->nh_label_type
= ZEBRA_LSP_NONE
;
307 const char *nexthop2str(const struct nexthop
*nexthop
, char *str
, int size
)
309 switch (nexthop
->type
) {
310 case NEXTHOP_TYPE_IFINDEX
:
311 snprintf(str
, size
, "if %u", nexthop
->ifindex
);
313 case NEXTHOP_TYPE_IPV4
:
314 case NEXTHOP_TYPE_IPV4_IFINDEX
:
315 snprintf(str
, size
, "%s if %u", inet_ntoa(nexthop
->gate
.ipv4
),
318 case NEXTHOP_TYPE_IPV6
:
319 case NEXTHOP_TYPE_IPV6_IFINDEX
:
320 snprintf(str
, size
, "%s if %u", inet6_ntoa(nexthop
->gate
.ipv6
),
323 case NEXTHOP_TYPE_BLACKHOLE
:
324 snprintf(str
, size
, "blackhole");
327 snprintf(str
, size
, "unknown");
335 * Iteration step for ALL_NEXTHOPS macro:
336 * This is the tricky part. Check if `nexthop' has
337 * NEXTHOP_FLAG_RECURSIVE set. If yes, this implies that `nexthop' has
338 * at least one nexthop attached to `nexthop->resolved', which will be
341 * If NEXTHOP_FLAG_RECURSIVE is not set, `nexthop' will progress in its
342 * current chain. In case its current chain end is reached, it will move
343 * upwards in the recursion levels and progress there. Whenever a step
344 * forward in a chain is done, recursion will be checked again.
345 * In a nustshell, it's equivalent to a pre-traversal order assuming that
346 * left branch is 'resolved' and right branch is 'next':
347 * https://en.wikipedia.org/wiki/Tree_traversal#/media/File:Sorted_binary_tree_preorder.svg
349 struct nexthop
*nexthop_next(struct nexthop
*nexthop
)
351 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
352 return nexthop
->resolved
;
355 return nexthop
->next
;
357 for (struct nexthop
*par
= nexthop
->rparent
; par
; par
= par
->rparent
)
364 unsigned int nexthop_level(struct nexthop
*nexthop
)
368 for (struct nexthop
*par
= nexthop
->rparent
; par
; par
= par
->rparent
)
374 uint32_t nexthop_hash(const struct nexthop
*nexthop
)
376 uint32_t key
= 0x45afe398;
378 key
= jhash_3words(nexthop
->type
, nexthop
->vrf_id
,
379 nexthop
->nh_label_type
, key
);
380 /* gate and blackhole are together in a union */
381 key
= jhash(&nexthop
->gate
, sizeof(nexthop
->gate
), key
);
382 key
= jhash(&nexthop
->src
, sizeof(nexthop
->src
), key
);
383 key
= jhash(&nexthop
->rmap_src
, sizeof(nexthop
->rmap_src
), key
);
385 if (nexthop
->nh_label
) {
386 int labels
= nexthop
->nh_label
->num_labels
;
389 while (labels
>= 3) {
390 key
= jhash_3words(nexthop
->nh_label
->label
[i
],
391 nexthop
->nh_label
->label
[i
+ 1],
392 nexthop
->nh_label
->label
[i
+ 2],
399 key
= jhash_2words(nexthop
->nh_label
->label
[i
],
400 nexthop
->nh_label
->label
[i
+ 1],
407 key
= jhash_1word(nexthop
->nh_label
->label
[i
], key
);
410 switch (nexthop
->type
) {
411 case NEXTHOP_TYPE_IPV4_IFINDEX
:
412 case NEXTHOP_TYPE_IPV6_IFINDEX
:
413 case NEXTHOP_TYPE_IFINDEX
:
414 key
= jhash_1word(nexthop
->ifindex
, key
);
416 case NEXTHOP_TYPE_BLACKHOLE
:
417 case NEXTHOP_TYPE_IPV4
:
418 case NEXTHOP_TYPE_IPV6
: