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