]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/nhrp_route.c
Merge pull request #8598 from idryzhov/fix-topotest-bgp-auth
[mirror_frr.git] / nhrpd / nhrp_route.c
1 /* NHRP routing functions
2 * Copyright (c) 2014-2015 Timo Teräs
3 *
4 * This file is free software: you may copy, redistribute and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #include "nhrpd.h"
15 #include "table.h"
16 #include "memory.h"
17 #include "stream.h"
18 #include "log.h"
19 #include "zclient.h"
20
21 DEFINE_MTYPE_STATIC(NHRPD, NHRP_ROUTE, "NHRP routing entry");
22
23 static struct zclient *zclient;
24 static struct route_table *zebra_rib[AFI_MAX];
25
26 struct route_info {
27 union sockunion via;
28 struct interface *ifp;
29 struct interface *nhrp_ifp;
30 };
31
32 static struct route_node *nhrp_route_update_get(const struct prefix *p,
33 int create)
34 {
35 struct route_node *rn;
36 afi_t afi = family2afi(PREFIX_FAMILY(p));
37
38 if (!zebra_rib[afi])
39 return NULL;
40
41 if (create) {
42 rn = route_node_get(zebra_rib[afi], p);
43 if (!rn->info) {
44 rn->info = XCALLOC(MTYPE_NHRP_ROUTE,
45 sizeof(struct route_info));
46 route_lock_node(rn);
47 }
48 return rn;
49 } else {
50 return route_node_lookup(zebra_rib[afi], p);
51 }
52 }
53
54 static void nhrp_route_update_put(struct route_node *rn)
55 {
56 struct route_info *ri = rn->info;
57
58 if (!ri->ifp && !ri->nhrp_ifp
59 && sockunion_is_null(&ri->via)) {
60 XFREE(MTYPE_NHRP_ROUTE, rn->info);
61 route_unlock_node(rn);
62 }
63 route_unlock_node(rn);
64 }
65
66 static void nhrp_route_update_zebra(const struct prefix *p,
67 union sockunion *nexthop,
68 struct interface *ifp)
69 {
70 struct route_node *rn;
71 struct route_info *ri;
72
73 rn = nhrp_route_update_get(p, !sockunion_is_null(nexthop) || ifp);
74 if (rn) {
75 ri = rn->info;
76 ri->via = *nexthop;
77 ri->ifp = ifp;
78 nhrp_route_update_put(rn);
79 }
80 }
81
82 static void nhrp_zebra_register_neigh(vrf_id_t vrf_id, afi_t afi, bool reg)
83 {
84 struct stream *s;
85
86 if (!zclient || zclient->sock < 0)
87 return;
88
89 s = zclient->obuf;
90 stream_reset(s);
91
92 zclient_create_header(s, reg ? ZEBRA_NHRP_NEIGH_REGISTER :
93 ZEBRA_NHRP_NEIGH_UNREGISTER,
94 vrf_id);
95 stream_putw(s, afi);
96 stream_putw_at(s, 0, stream_get_endp(s));
97 zclient_send_message(zclient);
98 }
99
100 void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp)
101 {
102 struct route_node *rn;
103 struct route_info *ri;
104
105 rn = nhrp_route_update_get(p, ifp != NULL);
106 if (rn) {
107 ri = rn->info;
108 ri->nhrp_ifp = ifp;
109 nhrp_route_update_put(rn);
110 }
111 }
112
113 void nhrp_route_announce(int add, enum nhrp_cache_type type,
114 const struct prefix *p, struct interface *ifp,
115 const union sockunion *nexthop, uint32_t mtu)
116 {
117 struct zapi_route api;
118 struct zapi_nexthop *api_nh;
119 union sockunion *nexthop_ref = (union sockunion *)nexthop;
120
121 if (zclient->sock < 0)
122 return;
123
124 memset(&api, 0, sizeof(api));
125 api.type = ZEBRA_ROUTE_NHRP;
126 api.safi = SAFI_UNICAST;
127 api.vrf_id = VRF_DEFAULT;
128 api.prefix = *p;
129
130 switch (type) {
131 case NHRP_CACHE_NEGATIVE:
132 zapi_route_set_blackhole(&api, BLACKHOLE_REJECT);
133 ifp = NULL;
134 nexthop = NULL;
135 break;
136 case NHRP_CACHE_DYNAMIC:
137 case NHRP_CACHE_NHS:
138 case NHRP_CACHE_STATIC:
139 /* Regular route, so these are announced
140 * to other routing daemons */
141 break;
142 default:
143 SET_FLAG(api.flags, ZEBRA_FLAG_FIB_OVERRIDE);
144 break;
145 }
146 SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
147
148 SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
149 api.nexthop_num = 1;
150 api_nh = &api.nexthops[0];
151 api_nh->vrf_id = VRF_DEFAULT;
152
153 switch (api.prefix.family) {
154 case AF_INET:
155 if (api.prefix.prefixlen == IPV4_MAX_BITLEN &&
156 nexthop_ref &&
157 memcmp(&nexthop_ref->sin.sin_addr, &api.prefix.u.prefix4,
158 sizeof(struct in_addr)) == 0) {
159 nexthop_ref = NULL;
160 }
161 if (nexthop_ref) {
162 api_nh->gate.ipv4 = nexthop_ref->sin.sin_addr;
163 api_nh->type = NEXTHOP_TYPE_IPV4;
164 }
165 if (ifp) {
166 api_nh->ifindex = ifp->ifindex;
167 if (api_nh->type == NEXTHOP_TYPE_IPV4)
168 api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
169 else
170 api_nh->type = NEXTHOP_TYPE_IFINDEX;
171 }
172 break;
173 case AF_INET6:
174 if (api.prefix.prefixlen == IPV6_MAX_BITLEN &&
175 nexthop_ref &&
176 memcmp(&nexthop_ref->sin6.sin6_addr, &api.prefix.u.prefix6,
177 sizeof(struct in6_addr)) == 0) {
178 nexthop_ref = NULL;
179 }
180 if (nexthop_ref) {
181 api_nh->gate.ipv6 = nexthop_ref->sin6.sin6_addr;
182 api_nh->type = NEXTHOP_TYPE_IPV6;
183 }
184 if (ifp) {
185 api_nh->ifindex = ifp->ifindex;
186 if (api_nh->type == NEXTHOP_TYPE_IPV6)
187 api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
188 else
189 api_nh->type = NEXTHOP_TYPE_IFINDEX;
190 }
191 break;
192 }
193 if (mtu) {
194 SET_FLAG(api.message, ZAPI_MESSAGE_MTU);
195 api.mtu = mtu;
196 }
197
198 if (unlikely(debug_flags & NHRP_DEBUG_ROUTE)) {
199 char buf[PREFIX_STRLEN];
200
201 zlog_debug(
202 "Zebra send: route %s %pFX nexthop %s metric %u count %d dev %s",
203 add ? "add" : "del", &api.prefix,
204 nexthop_ref ? inet_ntop(api.prefix.family,
205 &api_nh->gate,
206 buf, sizeof(buf))
207 : "<onlink>",
208 api.metric, api.nexthop_num, ifp ? ifp->name : "none");
209 }
210
211 zclient_route_send(add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, zclient,
212 &api);
213 }
214
215 int nhrp_route_read(ZAPI_CALLBACK_ARGS)
216 {
217 struct zapi_route api;
218 struct zapi_nexthop *api_nh;
219 struct interface *ifp = NULL;
220 union sockunion nexthop_addr;
221 int added;
222
223 if (zapi_route_decode(zclient->ibuf, &api) < 0)
224 return -1;
225
226 /* we completely ignore srcdest routes for now. */
227 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
228 return 0;
229
230 /* ignore our routes */
231 if (api.type == ZEBRA_ROUTE_NHRP)
232 return 0;
233
234 sockunion_family(&nexthop_addr) = AF_UNSPEC;
235 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
236 api_nh = &api.nexthops[0];
237
238 nexthop_addr.sa.sa_family = api.prefix.family;
239 switch (nexthop_addr.sa.sa_family) {
240 case AF_INET:
241 nexthop_addr.sin.sin_addr = api_nh->gate.ipv4;
242 break;
243 case AF_INET6:
244 nexthop_addr.sin6.sin6_addr = api_nh->gate.ipv6;
245 break;
246 }
247
248 if (api_nh->ifindex != IFINDEX_INTERNAL)
249 ifp = if_lookup_by_index(api_nh->ifindex, VRF_DEFAULT);
250 }
251
252 added = (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD);
253 debugf(NHRP_DEBUG_ROUTE, "if-route-%s: %pFX via %pSU dev %s",
254 added ? "add" : "del", &api.prefix, &nexthop_addr,
255 ifp ? ifp->name : "(none)");
256
257 nhrp_route_update_zebra(&api.prefix, &nexthop_addr, added ? ifp : NULL);
258 nhrp_shortcut_prefix_change(&api.prefix, !added);
259
260 return 0;
261 }
262
263 int nhrp_route_get_nexthop(const union sockunion *addr, struct prefix *p,
264 union sockunion *via, struct interface **ifp)
265 {
266 struct route_node *rn;
267 struct route_info *ri;
268 struct prefix lookup;
269 afi_t afi = family2afi(sockunion_family(addr));
270
271 sockunion2hostprefix(addr, &lookup);
272
273 rn = route_node_match(zebra_rib[afi], &lookup);
274 if (!rn)
275 return 0;
276
277 ri = rn->info;
278 if (ri->nhrp_ifp) {
279 debugf(NHRP_DEBUG_ROUTE, "lookup %pFX: nhrp_if=%s", &lookup,
280 ri->nhrp_ifp->name);
281
282 if (via)
283 sockunion_family(via) = AF_UNSPEC;
284 if (ifp)
285 *ifp = ri->nhrp_ifp;
286 } else {
287 debugf(NHRP_DEBUG_ROUTE, "lookup %pFX: zebra route dev %s",
288 &lookup, ri->ifp ? ri->ifp->name : "(none)");
289
290 if (via)
291 *via = ri->via;
292 if (ifp)
293 *ifp = ri->ifp;
294 }
295 if (p)
296 *p = rn->p;
297 route_unlock_node(rn);
298 return 1;
299 }
300
301 enum nhrp_route_type nhrp_route_address(struct interface *in_ifp,
302 union sockunion *addr, struct prefix *p,
303 struct nhrp_peer **peer)
304 {
305 struct interface *ifp = in_ifp;
306 struct nhrp_interface *nifp;
307 struct nhrp_cache *c;
308 union sockunion via[4];
309 uint32_t network_id = 0;
310 afi_t afi = family2afi(sockunion_family(addr));
311 int i;
312
313 if (ifp) {
314 nifp = ifp->info;
315 network_id = nifp->afi[afi].network_id;
316
317 c = nhrp_cache_get(ifp, addr, 0);
318 if (c && c->cur.type == NHRP_CACHE_LOCAL) {
319 if (p)
320 memset(p, 0, sizeof(*p));
321 return NHRP_ROUTE_LOCAL;
322 }
323 }
324
325 for (i = 0; i < 4; i++) {
326 if (!nhrp_route_get_nexthop(addr, p, &via[i], &ifp))
327 return NHRP_ROUTE_BLACKHOLE;
328 if (ifp) {
329 /* Departing from nbma network? */
330 nifp = ifp->info;
331 if (network_id
332 && network_id != nifp->afi[afi].network_id)
333 return NHRP_ROUTE_OFF_NBMA;
334 }
335 if (sockunion_family(&via[i]) == AF_UNSPEC)
336 break;
337 /* Resolve via node, but return the prefix of first match */
338 addr = &via[i];
339 p = NULL;
340 }
341
342 if (ifp) {
343 c = nhrp_cache_get(ifp, addr, 0);
344 if (c && c->cur.type >= NHRP_CACHE_DYNAMIC) {
345 if (p)
346 memset(p, 0, sizeof(*p));
347 if (c->cur.type == NHRP_CACHE_LOCAL)
348 return NHRP_ROUTE_LOCAL;
349 if (peer)
350 *peer = nhrp_peer_ref(c->cur.peer);
351 return NHRP_ROUTE_NBMA_NEXTHOP;
352 }
353 }
354
355 return NHRP_ROUTE_BLACKHOLE;
356 }
357
358 static void nhrp_zebra_connected(struct zclient *zclient)
359 {
360 zclient_send_reg_requests(zclient, VRF_DEFAULT);
361 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP,
362 ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
363 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6,
364 ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
365 nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, true);
366 nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, true);
367 }
368
369 void nhrp_zebra_init(void)
370 {
371 zebra_rib[AFI_IP] = route_table_init();
372 zebra_rib[AFI_IP6] = route_table_init();
373
374 zclient = zclient_new(master, &zclient_options_default);
375 zclient->zebra_connected = nhrp_zebra_connected;
376 zclient->interface_address_add = nhrp_interface_address_add;
377 zclient->interface_address_delete = nhrp_interface_address_delete;
378 zclient->redistribute_route_add = nhrp_route_read;
379 zclient->redistribute_route_del = nhrp_route_read;
380 zclient->neighbor_added = nhrp_neighbor_operation;
381 zclient->neighbor_removed = nhrp_neighbor_operation;
382 zclient->neighbor_get = nhrp_neighbor_operation;
383 zclient->gre_update = nhrp_gre_update;
384 zclient_init(zclient, ZEBRA_ROUTE_NHRP, 0, &nhrpd_privs);
385 }
386
387 static void nhrp_table_node_cleanup(struct route_table *table,
388 struct route_node *node)
389 {
390 if (!node->info)
391 return;
392
393 XFREE(MTYPE_NHRP_ROUTE, node->info);
394 }
395
396 void nhrp_send_zebra_configure_arp(struct interface *ifp, int family)
397 {
398 struct stream *s;
399
400 if (!zclient || zclient->sock < 0) {
401 debugf(NHRP_DEBUG_COMMON, "%s() : zclient not ready",
402 __func__);
403 return;
404 }
405 s = zclient->obuf;
406 stream_reset(s);
407 zclient_create_header(s,
408 ZEBRA_CONFIGURE_ARP,
409 ifp->vrf_id);
410 stream_putc(s, family);
411 stream_putl(s, ifp->ifindex);
412 stream_putw_at(s, 0, stream_get_endp(s));
413 zclient_send_message(zclient);
414 }
415
416 void nhrp_send_zebra_gre_source_set(struct interface *ifp,
417 unsigned int link_idx,
418 vrf_id_t link_vrf_id)
419 {
420 struct stream *s;
421
422 if (!zclient || zclient->sock < 0) {
423 zlog_err("%s : zclient not ready", __func__);
424 return;
425 }
426 if (link_idx == IFINDEX_INTERNAL || link_vrf_id == VRF_UNKNOWN) {
427 /* silently ignore */
428 return;
429 }
430 s = zclient->obuf;
431 stream_reset(s);
432 zclient_create_header(s,
433 ZEBRA_GRE_SOURCE_SET,
434 ifp->vrf_id);
435 stream_putl(s, ifp->ifindex);
436 stream_putl(s, link_idx);
437 stream_putl(s, link_vrf_id);
438 stream_putl(s, 0); /* mtu provisioning */
439 stream_putw_at(s, 0, stream_get_endp(s));
440 zclient_send_message(zclient);
441 }
442
443 void nhrp_send_zebra_nbr(union sockunion *in,
444 union sockunion *out,
445 struct interface *ifp)
446 {
447 struct stream *s;
448
449 if (!zclient || zclient->sock < 0)
450 return;
451 s = zclient->obuf;
452 stream_reset(s);
453 zclient_neigh_ip_encode(s, out ? ZEBRA_NEIGH_IP_ADD :
454 ZEBRA_NEIGH_IP_DEL, in, out,
455 ifp);
456 stream_putw_at(s, 0, stream_get_endp(s));
457 zclient_send_message(zclient);
458 }
459
460 int nhrp_send_zebra_gre_request(struct interface *ifp)
461 {
462 return zclient_send_zebra_gre_request(zclient, ifp);
463 }
464
465 void nhrp_zebra_terminate(void)
466 {
467 nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, false);
468 nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, false);
469 zclient_stop(zclient);
470 zclient_free(zclient);
471
472 zebra_rib[AFI_IP]->cleanup = nhrp_table_node_cleanup;
473 zebra_rib[AFI_IP6]->cleanup = nhrp_table_node_cleanup;
474 route_table_finish(zebra_rib[AFI_IP]);
475 route_table_finish(zebra_rib[AFI_IP6]);
476 }
477
478 void nhrp_gre_update(ZAPI_CALLBACK_ARGS)
479 {
480 struct stream *s;
481 struct nhrp_gre_info gre_info, *val;
482 struct interface *ifp;
483
484 /* result */
485 s = zclient->ibuf;
486 if (vrf_id != VRF_DEFAULT)
487 return;
488
489 /* read GRE information */
490 STREAM_GETL(s, gre_info.ifindex);
491 STREAM_GETL(s, gre_info.ikey);
492 STREAM_GETL(s, gre_info.okey);
493 STREAM_GETL(s, gre_info.ifindex_link);
494 STREAM_GETL(s, gre_info.vrfid_link);
495 STREAM_GETL(s, gre_info.vtep_ip.s_addr);
496 STREAM_GETL(s, gre_info.vtep_ip_remote.s_addr);
497 if (gre_info.ifindex == IFINDEX_INTERNAL)
498 val = NULL;
499 else
500 val = hash_lookup(nhrp_gre_list, &gre_info);
501 if (val) {
502 if (gre_info.vtep_ip.s_addr != val->vtep_ip.s_addr ||
503 gre_info.vrfid_link != val->vrfid_link ||
504 gre_info.ifindex_link != val->ifindex_link ||
505 gre_info.ikey != val->ikey ||
506 gre_info.okey != val->okey) {
507 /* update */
508 memcpy(val, &gre_info, sizeof(struct nhrp_gre_info));
509 }
510 } else {
511 val = nhrp_gre_info_alloc(&gre_info);
512 }
513 ifp = if_lookup_by_index(gre_info.ifindex, vrf_id);
514 debugf(NHRP_DEBUG_EVENT, "%s: gre interface %d vr %d obtained from system",
515 ifp ? ifp->name : "<none>", gre_info.ifindex, vrf_id);
516 if (ifp)
517 nhrp_interface_update_nbma(ifp, val);
518 return;
519 stream_failure:
520 zlog_err("%s(): error reading response ..", __func__);
521 }