1 /* NHRP routing functions
2 * Copyright (c) 2014-2015 Timo Teräs
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.
21 DEFINE_MTYPE_STATIC(NHRPD
, NHRP_ROUTE
, "NHRP routing entry");
23 static struct zclient
*zclient
;
24 static struct route_table
*zebra_rib
[AFI_MAX
];
28 struct interface
*ifp
;
29 struct interface
*nhrp_ifp
;
32 static struct route_node
*nhrp_route_update_get(const struct prefix
*p
,
35 struct route_node
*rn
;
36 afi_t afi
= family2afi(PREFIX_FAMILY(p
));
42 rn
= route_node_get(zebra_rib
[afi
], p
);
44 rn
->info
= XCALLOC(MTYPE_NHRP_ROUTE
,
45 sizeof(struct route_info
));
50 return route_node_lookup(zebra_rib
[afi
], p
);
54 static void nhrp_route_update_put(struct route_node
*rn
)
56 struct route_info
*ri
= rn
->info
;
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
);
63 route_unlock_node(rn
);
66 static void nhrp_route_update_zebra(const struct prefix
*p
,
67 union sockunion
*nexthop
,
68 struct interface
*ifp
)
70 struct route_node
*rn
;
71 struct route_info
*ri
;
73 rn
= nhrp_route_update_get(p
, !sockunion_is_null(nexthop
) || ifp
);
78 nhrp_route_update_put(rn
);
82 static void nhrp_zebra_register_neigh(vrf_id_t vrf_id
, afi_t afi
, bool reg
)
86 if (!zclient
|| zclient
->sock
< 0)
92 zclient_create_header(s
, reg
? ZEBRA_NHRP_NEIGH_REGISTER
:
93 ZEBRA_NHRP_NEIGH_UNREGISTER
,
96 stream_putw_at(s
, 0, stream_get_endp(s
));
97 zclient_send_message(zclient
);
100 void nhrp_route_update_nhrp(const struct prefix
*p
, struct interface
*ifp
)
102 struct route_node
*rn
;
103 struct route_info
*ri
;
105 rn
= nhrp_route_update_get(p
, ifp
!= NULL
);
109 nhrp_route_update_put(rn
);
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
)
117 struct zapi_route api
;
118 struct zapi_nexthop
*api_nh
;
119 union sockunion
*nexthop_ref
= (union sockunion
*)nexthop
;
121 if (zclient
->sock
< 0)
124 memset(&api
, 0, sizeof(api
));
125 api
.type
= ZEBRA_ROUTE_NHRP
;
126 api
.safi
= SAFI_UNICAST
;
127 api
.vrf_id
= VRF_DEFAULT
;
131 case NHRP_CACHE_NEGATIVE
:
132 zapi_route_set_blackhole(&api
, BLACKHOLE_REJECT
);
136 case NHRP_CACHE_DYNAMIC
:
138 case NHRP_CACHE_STATIC
:
139 /* Regular route, so these are announced
140 * to other routing daemons */
142 case NHRP_CACHE_INVALID
:
143 case NHRP_CACHE_INCOMPLETE
:
145 * I cannot believe that we want to set a FIB_OVERRIDE
146 * for invalid state or incomplete. But this matches
147 * the original code. Someone will probably notice
148 * the problem eventually
150 case NHRP_CACHE_CACHED
:
151 case NHRP_CACHE_LOCAL
:
152 case NHRP_CACHE_NUM_TYPES
:
153 SET_FLAG(api
.flags
, ZEBRA_FLAG_FIB_OVERRIDE
);
156 SET_FLAG(api
.flags
, ZEBRA_FLAG_ALLOW_RECURSION
);
158 SET_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
);
160 api_nh
= &api
.nexthops
[0];
161 api_nh
->vrf_id
= VRF_DEFAULT
;
163 switch (api
.prefix
.family
) {
165 if (api
.prefix
.prefixlen
== IPV4_MAX_BITLEN
&&
167 memcmp(&nexthop_ref
->sin
.sin_addr
, &api
.prefix
.u
.prefix4
,
168 sizeof(struct in_addr
)) == 0) {
172 api_nh
->gate
.ipv4
= nexthop_ref
->sin
.sin_addr
;
173 api_nh
->type
= NEXTHOP_TYPE_IPV4
;
176 api_nh
->ifindex
= ifp
->ifindex
;
177 if (api_nh
->type
== NEXTHOP_TYPE_IPV4
)
178 api_nh
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
180 api_nh
->type
= NEXTHOP_TYPE_IFINDEX
;
184 if (api
.prefix
.prefixlen
== IPV6_MAX_BITLEN
&&
186 memcmp(&nexthop_ref
->sin6
.sin6_addr
, &api
.prefix
.u
.prefix6
,
187 sizeof(struct in6_addr
)) == 0) {
191 api_nh
->gate
.ipv6
= nexthop_ref
->sin6
.sin6_addr
;
192 api_nh
->type
= NEXTHOP_TYPE_IPV6
;
195 api_nh
->ifindex
= ifp
->ifindex
;
196 if (api_nh
->type
== NEXTHOP_TYPE_IPV6
)
197 api_nh
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
199 api_nh
->type
= NEXTHOP_TYPE_IFINDEX
;
204 SET_FLAG(api
.message
, ZAPI_MESSAGE_MTU
);
208 if (unlikely(debug_flags
& NHRP_DEBUG_ROUTE
)) {
209 char buf
[PREFIX_STRLEN
];
212 "Zebra send: route %s %pFX nexthop %s metric %u count %d dev %s",
213 add
? "add" : "del", &api
.prefix
,
214 nexthop_ref
? inet_ntop(api
.prefix
.family
,
218 api
.metric
, api
.nexthop_num
, ifp
? ifp
->name
: "none");
221 zclient_route_send(add
? ZEBRA_ROUTE_ADD
: ZEBRA_ROUTE_DELETE
, zclient
,
225 int nhrp_route_read(ZAPI_CALLBACK_ARGS
)
227 struct zapi_route api
;
228 struct zapi_nexthop
*api_nh
;
229 struct interface
*ifp
= NULL
;
230 union sockunion nexthop_addr
;
233 if (zapi_route_decode(zclient
->ibuf
, &api
) < 0)
236 /* we completely ignore srcdest routes for now. */
237 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_SRCPFX
))
240 /* ignore our routes */
241 if (api
.type
== ZEBRA_ROUTE_NHRP
)
244 sockunion_family(&nexthop_addr
) = AF_UNSPEC
;
245 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
)) {
246 api_nh
= &api
.nexthops
[0];
248 nexthop_addr
.sa
.sa_family
= api
.prefix
.family
;
249 switch (nexthop_addr
.sa
.sa_family
) {
251 nexthop_addr
.sin
.sin_addr
= api_nh
->gate
.ipv4
;
254 nexthop_addr
.sin6
.sin6_addr
= api_nh
->gate
.ipv6
;
258 if (api_nh
->ifindex
!= IFINDEX_INTERNAL
)
259 ifp
= if_lookup_by_index(api_nh
->ifindex
, VRF_DEFAULT
);
262 added
= (cmd
== ZEBRA_REDISTRIBUTE_ROUTE_ADD
);
263 debugf(NHRP_DEBUG_ROUTE
, "if-route-%s: %pFX via %pSU dev %s",
264 added
? "add" : "del", &api
.prefix
, &nexthop_addr
,
265 ifp
? ifp
->name
: "(none)");
267 nhrp_route_update_zebra(&api
.prefix
, &nexthop_addr
, added
? ifp
: NULL
);
268 nhrp_shortcut_prefix_change(&api
.prefix
, !added
);
273 int nhrp_route_get_nexthop(const union sockunion
*addr
, struct prefix
*p
,
274 union sockunion
*via
, struct interface
**ifp
)
276 struct route_node
*rn
;
277 struct route_info
*ri
;
278 struct prefix lookup
;
279 afi_t afi
= family2afi(sockunion_family(addr
));
281 sockunion2hostprefix(addr
, &lookup
);
283 rn
= route_node_match(zebra_rib
[afi
], &lookup
);
289 debugf(NHRP_DEBUG_ROUTE
, "lookup %pFX: nhrp_if=%s", &lookup
,
293 sockunion_family(via
) = AF_UNSPEC
;
297 debugf(NHRP_DEBUG_ROUTE
, "lookup %pFX: zebra route dev %s",
298 &lookup
, ri
->ifp
? ri
->ifp
->name
: "(none)");
307 route_unlock_node(rn
);
311 enum nhrp_route_type
nhrp_route_address(struct interface
*in_ifp
,
312 union sockunion
*addr
, struct prefix
*p
,
313 struct nhrp_peer
**peer
)
315 struct interface
*ifp
= in_ifp
;
316 struct nhrp_interface
*nifp
;
317 struct nhrp_cache
*c
;
318 union sockunion via
[4];
319 uint32_t network_id
= 0;
320 afi_t afi
= family2afi(sockunion_family(addr
));
325 network_id
= nifp
->afi
[afi
].network_id
;
327 c
= nhrp_cache_get(ifp
, addr
, 0);
328 if (c
&& c
->cur
.type
== NHRP_CACHE_LOCAL
) {
330 memset(p
, 0, sizeof(*p
));
331 return NHRP_ROUTE_LOCAL
;
335 for (i
= 0; i
< 4; i
++) {
336 if (!nhrp_route_get_nexthop(addr
, p
, &via
[i
], &ifp
))
337 return NHRP_ROUTE_BLACKHOLE
;
339 /* Departing from nbma network? */
342 && network_id
!= nifp
->afi
[afi
].network_id
)
343 return NHRP_ROUTE_OFF_NBMA
;
345 if (sockunion_family(&via
[i
]) == AF_UNSPEC
)
347 /* Resolve via node, but return the prefix of first match */
353 c
= nhrp_cache_get(ifp
, addr
, 0);
354 if (c
&& c
->cur
.type
>= NHRP_CACHE_DYNAMIC
) {
356 memset(p
, 0, sizeof(*p
));
357 if (c
->cur
.type
== NHRP_CACHE_LOCAL
)
358 return NHRP_ROUTE_LOCAL
;
360 *peer
= nhrp_peer_ref(c
->cur
.peer
);
361 return NHRP_ROUTE_NBMA_NEXTHOP
;
365 return NHRP_ROUTE_BLACKHOLE
;
368 static void nhrp_zebra_connected(struct zclient
*zclient
)
370 zclient_send_reg_requests(zclient
, VRF_DEFAULT
);
371 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD
, zclient
, AFI_IP
,
372 ZEBRA_ROUTE_ALL
, 0, VRF_DEFAULT
);
373 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD
, zclient
, AFI_IP6
,
374 ZEBRA_ROUTE_ALL
, 0, VRF_DEFAULT
);
375 nhrp_zebra_register_neigh(VRF_DEFAULT
, AFI_IP
, true);
376 nhrp_zebra_register_neigh(VRF_DEFAULT
, AFI_IP6
, true);
379 static zclient_handler
*const nhrp_handlers
[] = {
380 [ZEBRA_INTERFACE_ADDRESS_ADD
] = nhrp_interface_address_add
,
381 [ZEBRA_INTERFACE_ADDRESS_DELETE
] = nhrp_interface_address_delete
,
382 [ZEBRA_REDISTRIBUTE_ROUTE_ADD
] = nhrp_route_read
,
383 [ZEBRA_REDISTRIBUTE_ROUTE_DEL
] = nhrp_route_read
,
384 [ZEBRA_NHRP_NEIGH_ADDED
] = nhrp_neighbor_operation
,
385 [ZEBRA_NHRP_NEIGH_REMOVED
] = nhrp_neighbor_operation
,
386 [ZEBRA_NHRP_NEIGH_GET
] = nhrp_neighbor_operation
,
387 [ZEBRA_GRE_UPDATE
] = nhrp_gre_update
,
390 void nhrp_zebra_init(void)
392 zebra_rib
[AFI_IP
] = route_table_init();
393 zebra_rib
[AFI_IP6
] = route_table_init();
395 zclient
= zclient_new(master
, &zclient_options_default
, nhrp_handlers
,
396 array_size(nhrp_handlers
));
397 zclient
->zebra_connected
= nhrp_zebra_connected
;
398 zclient_init(zclient
, ZEBRA_ROUTE_NHRP
, 0, &nhrpd_privs
);
401 static void nhrp_table_node_cleanup(struct route_table
*table
,
402 struct route_node
*node
)
407 XFREE(MTYPE_NHRP_ROUTE
, node
->info
);
410 void nhrp_send_zebra_configure_arp(struct interface
*ifp
, int family
)
414 if (!zclient
|| zclient
->sock
< 0) {
415 debugf(NHRP_DEBUG_COMMON
, "%s() : zclient not ready",
421 zclient_create_header(s
, ZEBRA_CONFIGURE_ARP
, ifp
->vrf
->vrf_id
);
422 stream_putc(s
, family
);
423 stream_putl(s
, ifp
->ifindex
);
424 stream_putw_at(s
, 0, stream_get_endp(s
));
425 zclient_send_message(zclient
);
428 void nhrp_send_zebra_gre_source_set(struct interface
*ifp
,
429 unsigned int link_idx
,
430 vrf_id_t link_vrf_id
)
434 if (!zclient
|| zclient
->sock
< 0) {
435 zlog_err("%s : zclient not ready", __func__
);
438 if (link_idx
== IFINDEX_INTERNAL
|| link_vrf_id
== VRF_UNKNOWN
) {
439 /* silently ignore */
444 zclient_create_header(s
, ZEBRA_GRE_SOURCE_SET
, ifp
->vrf
->vrf_id
);
445 stream_putl(s
, ifp
->ifindex
);
446 stream_putl(s
, link_idx
);
447 stream_putl(s
, link_vrf_id
);
448 stream_putl(s
, 0); /* mtu provisioning */
449 stream_putw_at(s
, 0, stream_get_endp(s
));
450 zclient_send_message(zclient
);
453 void nhrp_send_zebra_nbr(union sockunion
*in
,
454 union sockunion
*out
,
455 struct interface
*ifp
)
459 if (!zclient
|| zclient
->sock
< 0)
463 zclient_neigh_ip_encode(s
, out
? ZEBRA_NEIGH_IP_ADD
:
464 ZEBRA_NEIGH_IP_DEL
, in
, out
,
465 ifp
, out
? ZEBRA_NEIGH_STATE_REACHABLE
466 : ZEBRA_NEIGH_STATE_FAILED
);
467 stream_putw_at(s
, 0, stream_get_endp(s
));
468 zclient_send_message(zclient
);
471 int nhrp_send_zebra_gre_request(struct interface
*ifp
)
473 return zclient_send_zebra_gre_request(zclient
, ifp
);
476 void nhrp_zebra_terminate(void)
478 nhrp_zebra_register_neigh(VRF_DEFAULT
, AFI_IP
, false);
479 nhrp_zebra_register_neigh(VRF_DEFAULT
, AFI_IP6
, false);
480 zclient_stop(zclient
);
481 zclient_free(zclient
);
483 zebra_rib
[AFI_IP
]->cleanup
= nhrp_table_node_cleanup
;
484 zebra_rib
[AFI_IP6
]->cleanup
= nhrp_table_node_cleanup
;
485 route_table_finish(zebra_rib
[AFI_IP
]);
486 route_table_finish(zebra_rib
[AFI_IP6
]);
489 int nhrp_gre_update(ZAPI_CALLBACK_ARGS
)
492 struct nhrp_gre_info gre_info
, *val
;
493 struct interface
*ifp
;
497 if (vrf_id
!= VRF_DEFAULT
)
500 /* read GRE information */
501 STREAM_GETL(s
, gre_info
.ifindex
);
502 STREAM_GETL(s
, gre_info
.ikey
);
503 STREAM_GETL(s
, gre_info
.okey
);
504 STREAM_GETL(s
, gre_info
.ifindex_link
);
505 STREAM_GETL(s
, gre_info
.vrfid_link
);
506 STREAM_GETL(s
, gre_info
.vtep_ip
.s_addr
);
507 STREAM_GETL(s
, gre_info
.vtep_ip_remote
.s_addr
);
508 if (gre_info
.ifindex
== IFINDEX_INTERNAL
)
511 val
= hash_lookup(nhrp_gre_list
, &gre_info
);
513 if (gre_info
.vtep_ip
.s_addr
!= val
->vtep_ip
.s_addr
||
514 gre_info
.vrfid_link
!= val
->vrfid_link
||
515 gre_info
.ifindex_link
!= val
->ifindex_link
||
516 gre_info
.ikey
!= val
->ikey
||
517 gre_info
.okey
!= val
->okey
) {
519 memcpy(val
, &gre_info
, sizeof(struct nhrp_gre_info
));
522 val
= nhrp_gre_info_alloc(&gre_info
);
524 ifp
= if_lookup_by_index(gre_info
.ifindex
, vrf_id
);
525 debugf(NHRP_DEBUG_EVENT
, "%s: gre interface %d vr %d obtained from system",
526 ifp
? ifp
->name
: "<none>", gre_info
.ifindex
, vrf_id
);
528 nhrp_interface_update_nbma(ifp
, val
);
532 zlog_err("%s(): error reading response ..", __func__
);