]> git.proxmox.com Git - mirror_frr.git/blob - lib/nexthop.c
Merge pull request #1736 from mkanjari/type5-with-asymm
[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
35 DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop")
36 DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label")
37
38 /* check if nexthops are same, non-recursive */
39 int nexthop_same_no_recurse(const struct nexthop *next1,
40 const struct nexthop *next2)
41 {
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;
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;
99 break;
100 default:
101 /* do nothing */
102 break;
103 }
104 return 1;
105 }
106
107 /*
108 * nexthop_type_to_str
109 */
110 const char *nexthop_type_to_str(enum nexthop_types_t nh_type)
111 {
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];
120 }
121
122 /*
123 * Check if the labels match for the 2 nexthops specified.
124 */
125 int nexthop_labels_match(struct nexthop *nh1, struct nexthop *nh2)
126 {
127 struct mpls_label_stack *nhl1, *nhl2;
128
129 nhl1 = nh1->nh_label;
130 nhl2 = nh2->nh_label;
131 if (!nhl1 || !nhl2)
132 return 0;
133
134 if (nhl1->num_labels != nhl2->num_labels)
135 return 0;
136
137 if (memcmp(nhl1->label, nhl2->label, nhl1->num_labels))
138 return 0;
139
140 return 1;
141 }
142
143 struct nexthop *nexthop_new(void)
144 {
145 return XCALLOC(MTYPE_NEXTHOP, sizeof(struct nexthop));
146 }
147
148 /* Add nexthop to the end of a nexthop list. */
149 void nexthop_add(struct nexthop **target, struct nexthop *nexthop)
150 {
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;
160 }
161
162 void copy_nexthops(struct nexthop **tnh, struct nexthop *nh,
163 struct nexthop *rparent)
164 {
165 struct nexthop *nexthop;
166 struct nexthop *nh1;
167
168 for (nh1 = nh; nh1; nh1 = nh1->next) {
169 nexthop = nexthop_new();
170 nexthop->vrf_id = nh1->vrf_id;
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));
177 nexthop->rparent = rparent;
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]);
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 }
188 }
189
190 /* Free nexthop. */
191 void nexthop_free(struct nexthop *nexthop)
192 {
193 nexthop_del_labels(nexthop);
194 if (nexthop->resolved)
195 nexthops_free(nexthop->resolved);
196 XFREE(MTYPE_NEXTHOP, nexthop);
197 }
198
199 /* Frees a list of nexthops */
200 void nexthops_free(struct nexthop *nexthop)
201 {
202 struct nexthop *nh, *next;
203
204 for (nh = nexthop; nh; nh = next) {
205 next = nh->next;
206 nexthop_free(nh);
207 }
208 }
209
210 /* Update nexthop with label information. */
211 void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
212 u_int8_t num_labels, mpls_label_t *label)
213 {
214 struct mpls_label_stack *nh_label;
215 int i;
216
217 nexthop->nh_label_type = type;
218 nh_label = XCALLOC(MTYPE_NH_LABEL,
219 sizeof(struct mpls_label_stack)
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;
225 }
226
227 /* Free label information of nexthop, if present. */
228 void nexthop_del_labels(struct nexthop *nexthop)
229 {
230 if (nexthop->nh_label) {
231 XFREE(MTYPE_NH_LABEL, nexthop->nh_label);
232 nexthop->nh_label_type = ZEBRA_LSP_NONE;
233 }
234 }
235
236 const char *nexthop2str(struct nexthop *nexthop, char *str, int size)
237 {
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;
265 }
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 */
282 struct nexthop *nexthop_next(struct nexthop *nexthop)
283 {
284 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
285 return nexthop->resolved;
286
287 if (nexthop->next)
288 return nexthop->next;
289
290 for (struct nexthop *par = nexthop->rparent; par; par = par->rparent)
291 if (par->next)
292 return par->next;
293
294 return NULL;
295 }
296
297 unsigned int nexthop_level(struct nexthop *nexthop)
298 {
299 unsigned int rv = 0;
300
301 for (struct nexthop *par = nexthop->rparent; par; par = par->rparent)
302 rv++;
303
304 return rv;
305 }