]>
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 | ||
74 | int | |
75 | 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 | { | |
84 | case NEXTHOP_TYPE_IPV4_IFINDEX: | |
85 | if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4)) | |
86 | return 0; | |
87 | if (next1->ifindex != next2->ifindex) | |
88 | return 0; | |
89 | break; | |
90 | case NEXTHOP_TYPE_IFINDEX: | |
91 | if (next1->ifindex != next2->ifindex) | |
92 | return 0; | |
93 | break; | |
94 | case NEXTHOP_TYPE_IPV6_IFINDEX: | |
95 | if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) | |
96 | return 0; | |
97 | if (next1->ifindex != next2->ifindex) | |
98 | return 0; | |
d62a17ae | 99 | break; |
100 | default: | |
101 | /* do nothing */ | |
102 | break; | |
103 | } | |
104 | return 1; | |
fb018d25 DS |
105 | } |
106 | ||
107 | /* | |
108 | * nexthop_type_to_str | |
109 | */ | |
d62a17ae | 110 | const char *nexthop_type_to_str(enum nexthop_types_t nh_type) |
fb018d25 | 111 | { |
d62a17ae | 112 | static const char *desc[] = { |
113 | "none", "Directly connected", | |
114 | "IPv4 nexthop", "IPv4 nexthop with ifindex", | |
115 | "IPv6 nexthop", "IPv6 nexthop with ifindex", | |
116 | "Null0 nexthop", | |
117 | }; | |
118 | ||
119 | return desc[nh_type]; | |
fb018d25 | 120 | } |
a399694f | 121 | |
a64448ba DS |
122 | /* |
123 | * Check if the labels match for the 2 nexthops specified. | |
124 | */ | |
d62a17ae | 125 | int nexthop_labels_match(struct nexthop *nh1, struct nexthop *nh2) |
a64448ba | 126 | { |
8ecdb26e | 127 | struct mpls_label_stack *nhl1, *nhl2; |
a64448ba | 128 | |
d62a17ae | 129 | nhl1 = nh1->nh_label; |
130 | nhl2 = nh2->nh_label; | |
3f58e1b3 | 131 | if (!nhl1 || !nhl2) |
d62a17ae | 132 | return 0; |
a64448ba | 133 | |
d62a17ae | 134 | if (nhl1->num_labels != nhl2->num_labels) |
135 | return 0; | |
a64448ba | 136 | |
d62a17ae | 137 | if (memcmp(nhl1->label, nhl2->label, nhl1->num_labels)) |
138 | return 0; | |
a64448ba | 139 | |
d62a17ae | 140 | return 1; |
a64448ba DS |
141 | } |
142 | ||
d62a17ae | 143 | struct nexthop *nexthop_new(void) |
a399694f | 144 | { |
d62a17ae | 145 | return XCALLOC(MTYPE_NEXTHOP, sizeof(struct nexthop)); |
a399694f DS |
146 | } |
147 | ||
148 | /* Add nexthop to the end of a nexthop list. */ | |
d62a17ae | 149 | void nexthop_add(struct nexthop **target, struct nexthop *nexthop) |
a399694f | 150 | { |
d62a17ae | 151 | struct nexthop *last; |
152 | ||
153 | for (last = *target; last && last->next; last = last->next) | |
154 | ; | |
155 | if (last) | |
156 | last->next = nexthop; | |
157 | else | |
158 | *target = nexthop; | |
159 | nexthop->prev = last; | |
a399694f DS |
160 | } |
161 | ||
d62a17ae | 162 | void copy_nexthops(struct nexthop **tnh, struct nexthop *nh, |
163 | struct nexthop *rparent) | |
a399694f | 164 | { |
d62a17ae | 165 | struct nexthop *nexthop; |
166 | struct nexthop *nh1; | |
167 | ||
168 | for (nh1 = nh; nh1; nh1 = nh1->next) { | |
169 | nexthop = nexthop_new(); | |
4a7371e9 | 170 | nexthop->vrf_id = nh1->vrf_id; |
87440283 DW |
171 | nexthop->ifindex = nh1->ifindex; |
172 | nexthop->type = nh1->type; | |
173 | nexthop->flags = nh1->flags; | |
174 | memcpy(&nexthop->gate, &nh1->gate, sizeof(nh1->gate)); | |
175 | memcpy(&nexthop->src, &nh1->src, sizeof(nh1->src)); | |
176 | memcpy(&nexthop->rmap_src, &nh1->rmap_src, sizeof(nh1->rmap_src)); | |
d62a17ae | 177 | nexthop->rparent = rparent; |
87440283 DW |
178 | if (nh1->nh_label) |
179 | nexthop_add_labels(nexthop, nh1->nh_label_type, | |
180 | nh1->nh_label->num_labels, | |
181 | &nh1->nh_label->label[0]); | |
d62a17ae | 182 | nexthop_add(tnh, nexthop); |
183 | ||
184 | if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE)) | |
185 | copy_nexthops(&nexthop->resolved, nh1->resolved, | |
186 | nexthop); | |
187 | } | |
a399694f DS |
188 | } |
189 | ||
190 | /* Free nexthop. */ | |
d62a17ae | 191 | void nexthop_free(struct nexthop *nexthop) |
a399694f | 192 | { |
d62a17ae | 193 | nexthop_del_labels(nexthop); |
194 | if (nexthop->resolved) | |
195 | nexthops_free(nexthop->resolved); | |
196 | XFREE(MTYPE_NEXTHOP, nexthop); | |
a399694f DS |
197 | } |
198 | ||
199 | /* Frees a list of nexthops */ | |
d62a17ae | 200 | void nexthops_free(struct nexthop *nexthop) |
a399694f | 201 | { |
d62a17ae | 202 | struct nexthop *nh, *next; |
a399694f | 203 | |
d62a17ae | 204 | for (nh = nexthop; nh; nh = next) { |
205 | next = nh->next; | |
206 | nexthop_free(nh); | |
207 | } | |
a399694f | 208 | } |
80c2442a | 209 | |
40c7bdb0 | 210 | /* Update nexthop with label information. */ |
d62a17ae | 211 | void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type, |
212 | u_int8_t num_labels, mpls_label_t *label) | |
40c7bdb0 | 213 | { |
8ecdb26e | 214 | struct mpls_label_stack *nh_label; |
d62a17ae | 215 | int i; |
216 | ||
217 | nexthop->nh_label_type = type; | |
218 | nh_label = XCALLOC(MTYPE_NH_LABEL, | |
8ecdb26e | 219 | sizeof(struct mpls_label_stack) |
d62a17ae | 220 | + num_labels * sizeof(mpls_label_t)); |
221 | nh_label->num_labels = num_labels; | |
222 | for (i = 0; i < num_labels; i++) | |
223 | nh_label->label[i] = *(label + i); | |
224 | nexthop->nh_label = nh_label; | |
40c7bdb0 | 225 | } |
226 | ||
227 | /* Free label information of nexthop, if present. */ | |
d62a17ae | 228 | void nexthop_del_labels(struct nexthop *nexthop) |
40c7bdb0 | 229 | { |
d62a17ae | 230 | if (nexthop->nh_label) { |
231 | XFREE(MTYPE_NH_LABEL, nexthop->nh_label); | |
232 | nexthop->nh_label_type = ZEBRA_LSP_NONE; | |
233 | } | |
40c7bdb0 | 234 | } |
235 | ||
d62a17ae | 236 | const char *nexthop2str(struct nexthop *nexthop, char *str, int size) |
80c2442a | 237 | { |
d62a17ae | 238 | switch (nexthop->type) { |
239 | case NEXTHOP_TYPE_IFINDEX: | |
240 | snprintf(str, size, "if %u", nexthop->ifindex); | |
241 | break; | |
242 | case NEXTHOP_TYPE_IPV4: | |
243 | snprintf(str, size, "%s", inet_ntoa(nexthop->gate.ipv4)); | |
244 | break; | |
245 | case NEXTHOP_TYPE_IPV4_IFINDEX: | |
246 | snprintf(str, size, "%s if %u", inet_ntoa(nexthop->gate.ipv4), | |
247 | nexthop->ifindex); | |
248 | break; | |
249 | case NEXTHOP_TYPE_IPV6: | |
250 | snprintf(str, size, "%s", inet6_ntoa(nexthop->gate.ipv6)); | |
251 | break; | |
252 | case NEXTHOP_TYPE_IPV6_IFINDEX: | |
253 | snprintf(str, size, "%s if %u", inet6_ntoa(nexthop->gate.ipv6), | |
254 | nexthop->ifindex); | |
255 | break; | |
256 | case NEXTHOP_TYPE_BLACKHOLE: | |
257 | snprintf(str, size, "blackhole"); | |
258 | break; | |
259 | default: | |
260 | snprintf(str, size, "unknown"); | |
261 | break; | |
262 | } | |
263 | ||
264 | return str; | |
80c2442a | 265 | } |
9fb47c05 CF |
266 | |
267 | /* | |
268 | * Iteration step for ALL_NEXTHOPS macro: | |
269 | * This is the tricky part. Check if `nexthop' has | |
270 | * NEXTHOP_FLAG_RECURSIVE set. If yes, this implies that `nexthop' has | |
271 | * at least one nexthop attached to `nexthop->resolved', which will be | |
272 | * the next one. | |
273 | * | |
274 | * If NEXTHOP_FLAG_RECURSIVE is not set, `nexthop' will progress in its | |
275 | * current chain. In case its current chain end is reached, it will move | |
276 | * upwards in the recursion levels and progress there. Whenever a step | |
277 | * forward in a chain is done, recursion will be checked again. | |
278 | * In a nustshell, it's equivalent to a pre-traversal order assuming that | |
279 | * left branch is 'resolved' and right branch is 'next': | |
280 | * https://en.wikipedia.org/wiki/Tree_traversal#/media/File:Sorted_binary_tree_preorder.svg | |
281 | */ | |
d62a17ae | 282 | struct nexthop *nexthop_next(struct nexthop *nexthop) |
9fb47c05 | 283 | { |
d62a17ae | 284 | if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) |
285 | return nexthop->resolved; | |
9fb47c05 | 286 | |
d62a17ae | 287 | if (nexthop->next) |
288 | return nexthop->next; | |
9fb47c05 | 289 | |
d62a17ae | 290 | for (struct nexthop *par = nexthop->rparent; par; par = par->rparent) |
291 | if (par->next) | |
292 | return par->next; | |
9fb47c05 | 293 | |
d62a17ae | 294 | return NULL; |
9fb47c05 | 295 | } |
e3054ee9 | 296 | |
d62a17ae | 297 | unsigned int nexthop_level(struct nexthop *nexthop) |
e3054ee9 | 298 | { |
d62a17ae | 299 | unsigned int rv = 0; |
e3054ee9 | 300 | |
d62a17ae | 301 | for (struct nexthop *par = nexthop->rparent; par; par = par->rparent) |
302 | rv++; | |
e3054ee9 | 303 | |
d62a17ae | 304 | return rv; |
e3054ee9 | 305 | } |