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