]>
Commit | Line | Data |
---|---|---|
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 | 35 | DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop") |
36 | DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label") | |
4a1ab8e4 | 37 | |
fb018d25 | 38 | /* check if nexthops are same, non-recursive */ |
fd36be7e DL |
39 | int 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 | 74 | int 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 | 108 | const 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 | 123 | int 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 | 141 | struct 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 | 147 | void 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 | 160 | void 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 | 190 | void 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 | 199 | void 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 | 210 | void 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 | 227 | void 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 | 235 | const 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 | 281 | struct 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 | 296 | unsigned 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 | } |