]>
Commit | Line | Data |
---|---|---|
1 | /* BGP Nexthop tracking | |
2 | * Copyright (C) 2013 Cumulus Networks, Inc. | |
3 | * | |
4 | * This file is part of GNU Zebra. | |
5 | * | |
6 | * GNU Zebra 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 | * GNU Zebra 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 | ||
21 | #include <zebra.h> | |
22 | ||
23 | #include "command.h" | |
24 | #include "thread.h" | |
25 | #include "prefix.h" | |
26 | #include "zclient.h" | |
27 | #include "stream.h" | |
28 | #include "network.h" | |
29 | #include "log.h" | |
30 | #include "memory.h" | |
31 | #include "nexthop.h" | |
32 | #include "vrf.h" | |
33 | #include "filter.h" | |
34 | ||
35 | #include "bgpd/bgpd.h" | |
36 | #include "bgpd/bgp_table.h" | |
37 | #include "bgpd/bgp_route.h" | |
38 | #include "bgpd/bgp_attr.h" | |
39 | #include "bgpd/bgp_nexthop.h" | |
40 | #include "bgpd/bgp_debug.h" | |
41 | #include "bgpd/bgp_nht.h" | |
42 | #include "bgpd/bgp_fsm.h" | |
43 | #include "bgpd/bgp_zebra.h" | |
44 | ||
45 | extern struct zclient *zclient; | |
46 | ||
47 | static void register_zebra_rnh(struct bgp_nexthop_cache *bnc, | |
48 | int is_bgp_static_route); | |
49 | static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc, | |
50 | int is_bgp_static_route); | |
51 | static void evaluate_paths(struct bgp_nexthop_cache *bnc); | |
52 | static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p); | |
53 | static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc, | |
54 | int keep); | |
55 | ||
56 | static int bgp_isvalid_nexthop(struct bgp_nexthop_cache *bnc) | |
57 | { | |
58 | return (bgp_zebra_num_connects() == 0 | |
59 | || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID))); | |
60 | } | |
61 | ||
62 | static int bgp_isvalid_labeled_nexthop(struct bgp_nexthop_cache *bnc) | |
63 | { | |
64 | return (bgp_zebra_num_connects() == 0 | |
65 | || (bnc && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID))); | |
66 | } | |
67 | ||
68 | int bgp_find_nexthop(struct bgp_info *path, int connected) | |
69 | { | |
70 | struct bgp_nexthop_cache *bnc = path->nexthop; | |
71 | ||
72 | if (!bnc) | |
73 | return 0; | |
74 | ||
75 | /* | |
76 | * We are cheating here. Views have no associated underlying | |
77 | * ability to detect nexthops. So when we have a view | |
78 | * just tell everyone the nexthop is valid | |
79 | */ | |
80 | if (path->peer && path->peer->bgp->inst_type == BGP_INSTANCE_TYPE_VIEW) | |
81 | return 1; | |
82 | ||
83 | if (connected && !(CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))) | |
84 | return 0; | |
85 | ||
86 | return (bgp_isvalid_nexthop(bnc)); | |
87 | } | |
88 | ||
89 | static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc) | |
90 | { | |
91 | if (LIST_EMPTY(&(bnc->paths)) && bnc->nht_info) { | |
92 | if (BGP_DEBUG(nht, NHT)) { | |
93 | char buf[PREFIX2STR_BUFFER]; | |
94 | zlog_debug("bgp_unlink_nexthop: freeing bnc %s", | |
95 | bnc_str(bnc, buf, PREFIX2STR_BUFFER)); | |
96 | } | |
97 | unregister_zebra_rnh(bnc, | |
98 | CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE)); | |
99 | bnc->node->info = NULL; | |
100 | bgp_unlock_node(bnc->node); | |
101 | bnc->node = NULL; | |
102 | bnc_free(bnc); | |
103 | } | |
104 | } | |
105 | ||
106 | void bgp_unlink_nexthop(struct bgp_info *path) | |
107 | { | |
108 | struct bgp_nexthop_cache *bnc = path->nexthop; | |
109 | ||
110 | if (!bnc) | |
111 | return; | |
112 | ||
113 | path_nh_map(path, NULL, 0); | |
114 | ||
115 | bgp_unlink_nexthop_check(bnc); | |
116 | } | |
117 | ||
118 | void bgp_unlink_nexthop_by_peer(struct peer *peer) | |
119 | { | |
120 | struct prefix p; | |
121 | struct bgp_node *rn; | |
122 | struct bgp_nexthop_cache *bnc; | |
123 | afi_t afi = family2afi(peer->su.sa.sa_family); | |
124 | ||
125 | if (!sockunion2hostprefix(&peer->su, &p)) | |
126 | return; | |
127 | ||
128 | rn = bgp_node_get(peer->bgp->nexthop_cache_table[afi], &p); | |
129 | ||
130 | if (!rn->info) | |
131 | return; | |
132 | ||
133 | bnc = rn->info; | |
134 | ||
135 | /* cleanup the peer reference */ | |
136 | bnc->nht_info = NULL; | |
137 | ||
138 | bgp_unlink_nexthop_check(bnc); | |
139 | } | |
140 | ||
141 | /* | |
142 | * A route and its nexthop might belong to different VRFs. Therefore, | |
143 | * we need both the bgp_route and bgp_nexthop pointers. | |
144 | */ | |
145 | int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, | |
146 | afi_t afi, struct bgp_info *ri, | |
147 | struct peer *peer, int connected) | |
148 | { | |
149 | struct bgp_node *rn; | |
150 | struct bgp_nexthop_cache *bnc; | |
151 | struct prefix p; | |
152 | int is_bgp_static_route = 0; | |
153 | ||
154 | if (ri) { | |
155 | is_bgp_static_route = ((ri->type == ZEBRA_ROUTE_BGP) | |
156 | && (ri->sub_type == BGP_ROUTE_STATIC)) | |
157 | ? 1 | |
158 | : 0; | |
159 | ||
160 | /* Since Extended Next-hop Encoding (RFC5549) support, we want | |
161 | to derive | |
162 | address-family from the next-hop. */ | |
163 | if (!is_bgp_static_route) | |
164 | afi = BGP_ATTR_NEXTHOP_AFI_IP6(ri->attr) ? AFI_IP6 | |
165 | : AFI_IP; | |
166 | ||
167 | /* This will return TRUE if the global IPv6 NH is a link local | |
168 | * addr */ | |
169 | if (make_prefix(afi, ri, &p) < 0) | |
170 | return 1; | |
171 | } else if (peer) { | |
172 | /* Don't register link local NH */ | |
173 | if (afi == AFI_IP6 | |
174 | && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) | |
175 | return 1; | |
176 | ||
177 | if (!sockunion2hostprefix(&peer->su, &p)) { | |
178 | if (BGP_DEBUG(nht, NHT)) { | |
179 | zlog_debug( | |
180 | "%s: Attempting to register with unknown AFI %d (not %d or %d)", | |
181 | __FUNCTION__, afi, AFI_IP, AFI_IP6); | |
182 | } | |
183 | return 0; | |
184 | } | |
185 | } else | |
186 | return 0; | |
187 | ||
188 | if (is_bgp_static_route) | |
189 | rn = bgp_node_get(bgp_nexthop->import_check_table[afi], &p); | |
190 | else | |
191 | rn = bgp_node_get(bgp_nexthop->nexthop_cache_table[afi], &p); | |
192 | ||
193 | if (!rn->info) { | |
194 | bnc = bnc_new(); | |
195 | rn->info = bnc; | |
196 | bnc->node = rn; | |
197 | bnc->bgp = bgp_nexthop; | |
198 | bgp_lock_node(rn); | |
199 | if (BGP_DEBUG(nht, NHT)) { | |
200 | char buf[PREFIX2STR_BUFFER]; | |
201 | ||
202 | zlog_debug("Allocated bnc %s peer %p", | |
203 | bnc_str(bnc, buf, PREFIX2STR_BUFFER), peer); | |
204 | } | |
205 | } | |
206 | ||
207 | bnc = rn->info; | |
208 | bgp_unlock_node(rn); | |
209 | if (is_bgp_static_route) { | |
210 | SET_FLAG(bnc->flags, BGP_STATIC_ROUTE); | |
211 | ||
212 | /* If we're toggling the type, re-register */ | |
213 | if ((bgp_flag_check(bgp_route, BGP_FLAG_IMPORT_CHECK)) | |
214 | && !CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)) { | |
215 | SET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH); | |
216 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
217 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
218 | } else if ((!bgp_flag_check(bgp_route, BGP_FLAG_IMPORT_CHECK)) | |
219 | && CHECK_FLAG(bnc->flags, | |
220 | BGP_STATIC_ROUTE_EXACT_MATCH)) { | |
221 | UNSET_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH); | |
222 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
223 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
224 | } | |
225 | } | |
226 | /* When nexthop is already known, but now requires 'connected' | |
227 | * resolution, | |
228 | * re-register it. The reverse scenario where the nexthop currently | |
229 | * requires | |
230 | * 'connected' resolution does not need a re-register (i.e., we treat | |
231 | * 'connected-required' as an override) except in the scenario where | |
232 | * this | |
233 | * is actually a case of tracking a peer for connectivity (e.g., after | |
234 | * disable connected-check). | |
235 | * NOTE: We don't track the number of paths separately for 'connected- | |
236 | * required' vs 'connected-not-required' as this change is not a common | |
237 | * scenario. | |
238 | */ | |
239 | else if (connected && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) { | |
240 | SET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); | |
241 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
242 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
243 | } else if (peer && !connected | |
244 | && CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) { | |
245 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED); | |
246 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
247 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
248 | } | |
249 | if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) { | |
250 | bnc->flags |= BGP_NEXTHOP_REGISTERED; | |
251 | bnc->flags |= BGP_NEXTHOP_VALID; | |
252 | } else if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) | |
253 | register_zebra_rnh(bnc, is_bgp_static_route); | |
254 | if (ri && ri->nexthop != bnc) { | |
255 | /* Unlink from existing nexthop cache, if any. This will also | |
256 | * free | |
257 | * the nexthop cache entry, if appropriate. | |
258 | */ | |
259 | bgp_unlink_nexthop(ri); | |
260 | ||
261 | path_nh_map(ri, bnc, 1); /* updates NHT ri list reference */ | |
262 | ||
263 | if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID) && bnc->metric) | |
264 | (bgp_info_extra_get(ri))->igpmetric = bnc->metric; | |
265 | else if (ri->extra) | |
266 | ri->extra->igpmetric = 0; | |
267 | } else if (peer) | |
268 | bnc->nht_info = (void *)peer; /* NHT peer reference */ | |
269 | ||
270 | /* | |
271 | * We are cheating here. Views have no associated underlying | |
272 | * ability to detect nexthops. So when we have a view | |
273 | * just tell everyone the nexthop is valid | |
274 | */ | |
275 | if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) | |
276 | return 1; | |
277 | else | |
278 | return (bgp_isvalid_nexthop(bnc)); | |
279 | } | |
280 | ||
281 | void bgp_delete_connected_nexthop(afi_t afi, struct peer *peer) | |
282 | { | |
283 | struct bgp_node *rn; | |
284 | struct bgp_nexthop_cache *bnc; | |
285 | struct prefix p; | |
286 | ||
287 | if (!peer) | |
288 | return; | |
289 | ||
290 | /* We don't register link local address for NHT */ | |
291 | if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr)) | |
292 | return; | |
293 | ||
294 | if (!sockunion2hostprefix(&peer->su, &p)) | |
295 | return; | |
296 | ||
297 | rn = bgp_node_lookup( | |
298 | peer->bgp->nexthop_cache_table[family2afi(p.family)], &p); | |
299 | if (!rn || !rn->info) { | |
300 | if (BGP_DEBUG(nht, NHT)) | |
301 | zlog_debug("Cannot find connected NHT node for peer %s", | |
302 | peer->host); | |
303 | if (rn) | |
304 | bgp_unlock_node(rn); | |
305 | return; | |
306 | } | |
307 | ||
308 | bnc = rn->info; | |
309 | bgp_unlock_node(rn); | |
310 | ||
311 | if (bnc->nht_info != peer) { | |
312 | if (BGP_DEBUG(nht, NHT)) | |
313 | zlog_debug( | |
314 | "Connected NHT %p node for peer %s points to %p", | |
315 | bnc, peer->host, bnc->nht_info); | |
316 | return; | |
317 | } | |
318 | ||
319 | bnc->nht_info = NULL; | |
320 | ||
321 | if (LIST_EMPTY(&(bnc->paths))) { | |
322 | if (BGP_DEBUG(nht, NHT)) | |
323 | zlog_debug("Freeing connected NHT node %p for peer %s", | |
324 | bnc, peer->host); | |
325 | unregister_zebra_rnh(bnc, 0); | |
326 | bnc->node->info = NULL; | |
327 | bgp_unlock_node(bnc->node); | |
328 | bnc_free(bnc); | |
329 | } | |
330 | } | |
331 | ||
332 | void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) | |
333 | { | |
334 | struct bgp_node *rn = NULL; | |
335 | struct bgp_nexthop_cache *bnc; | |
336 | struct nexthop *nexthop; | |
337 | struct nexthop *oldnh; | |
338 | struct nexthop *nhlist_head = NULL; | |
339 | struct nexthop *nhlist_tail = NULL; | |
340 | int i; | |
341 | struct bgp *bgp; | |
342 | struct zapi_route nhr; | |
343 | ||
344 | bgp = bgp_lookup_by_vrf_id(vrf_id); | |
345 | if (!bgp) { | |
346 | zlog_err( | |
347 | "parse nexthop update: instance not found for vrf_id %u", | |
348 | vrf_id); | |
349 | return; | |
350 | } | |
351 | ||
352 | if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) { | |
353 | if (BGP_DEBUG(nht, NHT)) | |
354 | zlog_debug("%s: Failure to decode nexthop update", | |
355 | __PRETTY_FUNCTION__); | |
356 | return; | |
357 | } | |
358 | ||
359 | if (command == ZEBRA_NEXTHOP_UPDATE) | |
360 | rn = bgp_node_lookup( | |
361 | bgp->nexthop_cache_table[family2afi(nhr.prefix.family)], | |
362 | &nhr.prefix); | |
363 | else if (command == ZEBRA_IMPORT_CHECK_UPDATE) | |
364 | rn = bgp_node_lookup( | |
365 | bgp->import_check_table[family2afi(nhr.prefix.family)], | |
366 | &nhr.prefix); | |
367 | ||
368 | if (!rn || !rn->info) { | |
369 | if (BGP_DEBUG(nht, NHT)) { | |
370 | char buf[PREFIX2STR_BUFFER]; | |
371 | prefix2str(&nhr.prefix, buf, sizeof(buf)); | |
372 | zlog_debug("parse nexthop update(%s): rn not found", | |
373 | buf); | |
374 | } | |
375 | if (rn) | |
376 | bgp_unlock_node(rn); | |
377 | return; | |
378 | } | |
379 | ||
380 | bnc = rn->info; | |
381 | bgp_unlock_node(rn); | |
382 | bnc->last_update = bgp_clock(); | |
383 | bnc->change_flags = 0; | |
384 | ||
385 | /* debug print the input */ | |
386 | if (BGP_DEBUG(nht, NHT)) { | |
387 | char buf[PREFIX2STR_BUFFER]; | |
388 | prefix2str(&nhr.prefix, buf, sizeof(buf)); | |
389 | zlog_debug( | |
390 | "%u: Rcvd NH update %s - metric %d/%d #nhops %d/%d flags 0x%x", | |
391 | vrf_id, buf, nhr.metric, bnc->metric, nhr.nexthop_num, | |
392 | bnc->nexthop_num, bnc->flags); | |
393 | } | |
394 | ||
395 | if (nhr.metric != bnc->metric) | |
396 | bnc->change_flags |= BGP_NEXTHOP_METRIC_CHANGED; | |
397 | ||
398 | if (nhr.nexthop_num != bnc->nexthop_num) | |
399 | bnc->change_flags |= BGP_NEXTHOP_CHANGED; | |
400 | ||
401 | if (nhr.nexthop_num) { | |
402 | /* notify bgp fsm if nbr ip goes from invalid->valid */ | |
403 | if (!bnc->nexthop_num) | |
404 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); | |
405 | ||
406 | bnc->flags |= BGP_NEXTHOP_VALID; | |
407 | bnc->metric = nhr.metric; | |
408 | bnc->nexthop_num = nhr.nexthop_num; | |
409 | ||
410 | bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; /* check below */ | |
411 | ||
412 | for (i = 0; i < nhr.nexthop_num; i++) { | |
413 | int num_labels = 0; | |
414 | ||
415 | nexthop = nexthop_from_zapi_nexthop(&nhr.nexthops[i]); | |
416 | ||
417 | /* There is at least one label-switched path */ | |
418 | if (nexthop->nh_label && | |
419 | nexthop->nh_label->num_labels) { | |
420 | ||
421 | bnc->flags |= BGP_NEXTHOP_LABELED_VALID; | |
422 | num_labels = nexthop->nh_label->num_labels; | |
423 | } | |
424 | ||
425 | if (BGP_DEBUG(nht, NHT)) { | |
426 | char buf[NEXTHOP_STRLEN]; | |
427 | zlog_debug( | |
428 | " nhop via %s (%d labels)", | |
429 | nexthop2str(nexthop, buf, sizeof(buf)), | |
430 | num_labels); | |
431 | } | |
432 | ||
433 | if (nhlist_tail) { | |
434 | nhlist_tail->next = nexthop; | |
435 | nhlist_tail = nexthop; | |
436 | } else { | |
437 | nhlist_tail = nexthop; | |
438 | nhlist_head = nexthop; | |
439 | } | |
440 | ||
441 | /* No need to evaluate the nexthop if we have already | |
442 | * determined | |
443 | * that there has been a change. | |
444 | */ | |
445 | if (bnc->change_flags & BGP_NEXTHOP_CHANGED) | |
446 | continue; | |
447 | ||
448 | for (oldnh = bnc->nexthop; oldnh; oldnh = oldnh->next) | |
449 | if (nexthop_same_no_recurse(oldnh, nexthop) && | |
450 | nexthop_labels_match(oldnh, nexthop)) | |
451 | break; | |
452 | ||
453 | if (!oldnh) | |
454 | bnc->change_flags |= BGP_NEXTHOP_CHANGED; | |
455 | } | |
456 | bnc_nexthop_free(bnc); | |
457 | bnc->nexthop = nhlist_head; | |
458 | } else { | |
459 | bnc->flags &= ~BGP_NEXTHOP_VALID; | |
460 | bnc->nexthop_num = nhr.nexthop_num; | |
461 | ||
462 | /* notify bgp fsm if nbr ip goes from valid->invalid */ | |
463 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); | |
464 | ||
465 | bnc_nexthop_free(bnc); | |
466 | bnc->nexthop = NULL; | |
467 | } | |
468 | ||
469 | evaluate_paths(bnc); | |
470 | } | |
471 | ||
472 | /* | |
473 | * Cleanup nexthop registration and status information for BGP nexthops | |
474 | * pertaining to this VRF. This is invoked upon VRF deletion. | |
475 | */ | |
476 | void bgp_cleanup_nexthops(struct bgp *bgp) | |
477 | { | |
478 | afi_t afi; | |
479 | struct bgp_node *rn; | |
480 | struct bgp_nexthop_cache *bnc; | |
481 | ||
482 | for (afi = AFI_IP; afi < AFI_MAX; afi++) { | |
483 | if (!bgp->nexthop_cache_table[afi]) | |
484 | continue; | |
485 | ||
486 | for (rn = bgp_table_top(bgp->nexthop_cache_table[afi]); rn; | |
487 | rn = bgp_route_next(rn)) { | |
488 | bnc = rn->info; | |
489 | if (!bnc) | |
490 | continue; | |
491 | ||
492 | /* Clear relevant flags. */ | |
493 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID); | |
494 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
495 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); | |
496 | } | |
497 | } | |
498 | } | |
499 | ||
500 | /** | |
501 | * make_prefix - make a prefix structure from the path (essentially | |
502 | * path's node. | |
503 | */ | |
504 | static int make_prefix(int afi, struct bgp_info *ri, struct prefix *p) | |
505 | { | |
506 | ||
507 | int is_bgp_static = ((ri->type == ZEBRA_ROUTE_BGP) | |
508 | && (ri->sub_type == BGP_ROUTE_STATIC)) | |
509 | ? 1 | |
510 | : 0; | |
511 | ||
512 | memset(p, 0, sizeof(struct prefix)); | |
513 | switch (afi) { | |
514 | case AFI_IP: | |
515 | p->family = AF_INET; | |
516 | if (is_bgp_static) { | |
517 | p->u.prefix4 = ri->net->p.u.prefix4; | |
518 | p->prefixlen = ri->net->p.prefixlen; | |
519 | } else { | |
520 | p->u.prefix4 = ri->attr->nexthop; | |
521 | p->prefixlen = IPV4_MAX_BITLEN; | |
522 | } | |
523 | break; | |
524 | case AFI_IP6: | |
525 | /* We don't register link local NH */ | |
526 | if (ri->attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV6_GLOBAL | |
527 | || IN6_IS_ADDR_LINKLOCAL(&ri->attr->mp_nexthop_global)) | |
528 | return -1; | |
529 | ||
530 | p->family = AF_INET6; | |
531 | ||
532 | if (is_bgp_static) { | |
533 | p->u.prefix6 = ri->net->p.u.prefix6; | |
534 | p->prefixlen = ri->net->p.prefixlen; | |
535 | } else { | |
536 | p->u.prefix6 = ri->attr->mp_nexthop_global; | |
537 | p->prefixlen = IPV6_MAX_BITLEN; | |
538 | } | |
539 | break; | |
540 | default: | |
541 | if (BGP_DEBUG(nht, NHT)) { | |
542 | zlog_debug( | |
543 | "%s: Attempting to make prefix with unknown AFI %d (not %d or %d)", | |
544 | __FUNCTION__, afi, AFI_IP, AFI_IP6); | |
545 | } | |
546 | break; | |
547 | } | |
548 | return 0; | |
549 | } | |
550 | ||
551 | /** | |
552 | * sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister | |
553 | * command to Zebra. | |
554 | * ARGUMENTS: | |
555 | * struct bgp_nexthop_cache *bnc -- the nexthop structure. | |
556 | * int command -- command to send to zebra | |
557 | * RETURNS: | |
558 | * void. | |
559 | */ | |
560 | static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) | |
561 | { | |
562 | struct prefix *p; | |
563 | bool exact_match = false; | |
564 | int ret; | |
565 | ||
566 | if (!zclient) | |
567 | return; | |
568 | ||
569 | /* Don't try to register if Zebra doesn't know of this instance. */ | |
570 | if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bnc->bgp)) | |
571 | return; | |
572 | ||
573 | p = &(bnc->node->p); | |
574 | if ((command == ZEBRA_NEXTHOP_REGISTER | |
575 | || command == ZEBRA_IMPORT_ROUTE_REGISTER) | |
576 | && (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED) | |
577 | || CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH))) | |
578 | exact_match = true; | |
579 | ||
580 | if (BGP_DEBUG(zebra, ZEBRA)) { | |
581 | char buf[PREFIX2STR_BUFFER]; | |
582 | ||
583 | prefix2str(p, buf, PREFIX2STR_BUFFER); | |
584 | zlog_debug("%s: sending cmd %s for %s (vrf %s)", | |
585 | __func__, zserv_command_string(command), buf, | |
586 | bnc->bgp->name); | |
587 | } | |
588 | ||
589 | ret = zclient_send_rnh(zclient, command, p, exact_match, | |
590 | bnc->bgp->vrf_id); | |
591 | /* TBD: handle the failure */ | |
592 | if (ret < 0) | |
593 | zlog_warn("sendmsg_nexthop: zclient_send_message() failed"); | |
594 | ||
595 | if ((command == ZEBRA_NEXTHOP_REGISTER) | |
596 | || (command == ZEBRA_IMPORT_ROUTE_REGISTER)) | |
597 | SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
598 | else if ((command == ZEBRA_NEXTHOP_UNREGISTER) | |
599 | || (command == ZEBRA_IMPORT_ROUTE_UNREGISTER)) | |
600 | UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); | |
601 | return; | |
602 | } | |
603 | ||
604 | /** | |
605 | * register_zebra_rnh - register a NH/route with Zebra for notification | |
606 | * when the route or the route to the nexthop changes. | |
607 | * ARGUMENTS: | |
608 | * struct bgp_nexthop_cache *bnc | |
609 | * RETURNS: | |
610 | * void. | |
611 | */ | |
612 | static void register_zebra_rnh(struct bgp_nexthop_cache *bnc, | |
613 | int is_bgp_import_route) | |
614 | { | |
615 | /* Check if we have already registered */ | |
616 | if (bnc->flags & BGP_NEXTHOP_REGISTERED) | |
617 | return; | |
618 | if (is_bgp_import_route) | |
619 | sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_REGISTER); | |
620 | else | |
621 | sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_REGISTER); | |
622 | } | |
623 | ||
624 | /** | |
625 | * unregister_zebra_rnh -- Unregister the route/nexthop from Zebra. | |
626 | * ARGUMENTS: | |
627 | * struct bgp_nexthop_cache *bnc | |
628 | * RETURNS: | |
629 | * void. | |
630 | */ | |
631 | static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc, | |
632 | int is_bgp_import_route) | |
633 | { | |
634 | /* Check if we have already registered */ | |
635 | if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) | |
636 | return; | |
637 | ||
638 | if (is_bgp_import_route) | |
639 | sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_UNREGISTER); | |
640 | else | |
641 | sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_UNREGISTER); | |
642 | } | |
643 | ||
644 | /** | |
645 | * evaluate_paths - Evaluate the paths/nets associated with a nexthop. | |
646 | * ARGUMENTS: | |
647 | * struct bgp_nexthop_cache *bnc -- the nexthop structure. | |
648 | * RETURNS: | |
649 | * void. | |
650 | */ | |
651 | static void evaluate_paths(struct bgp_nexthop_cache *bnc) | |
652 | { | |
653 | struct bgp_node *rn; | |
654 | struct bgp_info *path; | |
655 | int afi; | |
656 | struct peer *peer = (struct peer *)bnc->nht_info; | |
657 | struct bgp_table *table; | |
658 | safi_t safi; | |
659 | struct bgp *bgp_path; | |
660 | ||
661 | if (BGP_DEBUG(nht, NHT)) { | |
662 | char buf[PREFIX2STR_BUFFER]; | |
663 | bnc_str(bnc, buf, PREFIX2STR_BUFFER); | |
664 | zlog_debug( | |
665 | "NH update for %s - flags 0x%x chgflags 0x%x - evaluate paths", | |
666 | buf, bnc->flags, bnc->change_flags); | |
667 | } | |
668 | ||
669 | LIST_FOREACH (path, &(bnc->paths), nh_thread) { | |
670 | if (!(path->type == ZEBRA_ROUTE_BGP | |
671 | && ((path->sub_type == BGP_ROUTE_NORMAL) | |
672 | || (path->sub_type == BGP_ROUTE_STATIC) | |
673 | || (path->sub_type == BGP_ROUTE_IMPORTED)))) | |
674 | continue; | |
675 | ||
676 | rn = path->net; | |
677 | assert(rn && bgp_node_table(rn)); | |
678 | afi = family2afi(rn->p.family); | |
679 | table = bgp_node_table(rn); | |
680 | safi = table->safi; | |
681 | ||
682 | /* | |
683 | * handle routes from other VRFs (they can have a | |
684 | * nexthop in THIS VRF). bgp_path is the bgp instance | |
685 | * that owns the route referencing this nexthop. | |
686 | */ | |
687 | bgp_path = table->bgp; | |
688 | ||
689 | /* | |
690 | * Path becomes valid/invalid depending on whether the nexthop | |
691 | * reachable/unreachable. | |
692 | * | |
693 | * In case of unicast routes that were imported from vpn | |
694 | * and that have labels, they are valid only if there are | |
695 | * nexthops with labels | |
696 | */ | |
697 | ||
698 | int bnc_is_valid_nexthop = 0; | |
699 | ||
700 | if (safi == SAFI_UNICAST && | |
701 | path->sub_type == BGP_ROUTE_IMPORTED && | |
702 | path->extra && | |
703 | path->extra->num_labels) { | |
704 | ||
705 | bnc_is_valid_nexthop = | |
706 | bgp_isvalid_labeled_nexthop(bnc) ? 1 : 0; | |
707 | } else { | |
708 | bnc_is_valid_nexthop = | |
709 | bgp_isvalid_nexthop(bnc) ? 1 : 0; | |
710 | } | |
711 | ||
712 | if (BGP_DEBUG(nht, NHT)) { | |
713 | char buf[PREFIX_STRLEN]; | |
714 | ||
715 | prefix2str(&rn->p, buf, PREFIX_STRLEN); | |
716 | zlog_debug("%s: prefix %s (vrf %s) %svalid", | |
717 | __func__, buf, bgp_path->name, | |
718 | (bnc_is_valid_nexthop ? "" : "not ")); | |
719 | } | |
720 | ||
721 | if ((CHECK_FLAG(path->flags, BGP_INFO_VALID) ? 1 : 0) | |
722 | != bnc_is_valid_nexthop) { | |
723 | if (CHECK_FLAG(path->flags, BGP_INFO_VALID)) { | |
724 | bgp_aggregate_decrement(bgp_path, &rn->p, | |
725 | path, afi, safi); | |
726 | bgp_info_unset_flag(rn, path, BGP_INFO_VALID); | |
727 | } else { | |
728 | bgp_info_set_flag(rn, path, BGP_INFO_VALID); | |
729 | bgp_aggregate_increment(bgp_path, &rn->p, | |
730 | path, afi, safi); | |
731 | } | |
732 | } | |
733 | ||
734 | /* Copy the metric to the path. Will be used for bestpath | |
735 | * computation */ | |
736 | if (bgp_isvalid_nexthop(bnc) && bnc->metric) | |
737 | (bgp_info_extra_get(path))->igpmetric = bnc->metric; | |
738 | else if (path->extra) | |
739 | path->extra->igpmetric = 0; | |
740 | ||
741 | if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED) | |
742 | || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)) | |
743 | SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED); | |
744 | ||
745 | bgp_process(bgp_path, rn, afi, safi); | |
746 | } | |
747 | ||
748 | if (peer && !CHECK_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED)) { | |
749 | if (BGP_DEBUG(nht, NHT)) | |
750 | zlog_debug("%s: Updating peer (%s) status with NHT", | |
751 | __FUNCTION__, peer->host); | |
752 | bgp_fsm_nht_update(peer, bgp_isvalid_nexthop(bnc)); | |
753 | SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); | |
754 | } | |
755 | ||
756 | RESET_FLAG(bnc->change_flags); | |
757 | } | |
758 | ||
759 | /** | |
760 | * path_nh_map - make or break path-to-nexthop association. | |
761 | * ARGUMENTS: | |
762 | * path - pointer to the path structure | |
763 | * bnc - pointer to the nexthop structure | |
764 | * make - if set, make the association. if unset, just break the existing | |
765 | * association. | |
766 | */ | |
767 | static void path_nh_map(struct bgp_info *path, struct bgp_nexthop_cache *bnc, | |
768 | int make) | |
769 | { | |
770 | if (path->nexthop) { | |
771 | LIST_REMOVE(path, nh_thread); | |
772 | path->nexthop->path_count--; | |
773 | path->nexthop = NULL; | |
774 | } | |
775 | if (make) { | |
776 | LIST_INSERT_HEAD(&(bnc->paths), path, nh_thread); | |
777 | path->nexthop = bnc; | |
778 | path->nexthop->path_count++; | |
779 | } | |
780 | } |