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 void nhrp_route_update_nhrp(const struct prefix
*p
, struct interface
*ifp
)
84 struct route_node
*rn
;
85 struct route_info
*ri
;
87 rn
= nhrp_route_update_get(p
, ifp
!= NULL
);
91 nhrp_route_update_put(rn
);
95 void nhrp_route_announce(int add
, enum nhrp_cache_type type
,
96 const struct prefix
*p
, struct interface
*ifp
,
97 const union sockunion
*nexthop
, uint32_t mtu
)
99 struct zapi_route api
;
100 struct zapi_nexthop
*api_nh
;
101 union sockunion
*nexthop_ref
= (union sockunion
*)nexthop
;
103 if (zclient
->sock
< 0)
106 memset(&api
, 0, sizeof(api
));
107 api
.type
= ZEBRA_ROUTE_NHRP
;
108 api
.safi
= SAFI_UNICAST
;
109 api
.vrf_id
= VRF_DEFAULT
;
113 case NHRP_CACHE_NEGATIVE
:
114 zapi_route_set_blackhole(&api
, BLACKHOLE_REJECT
);
118 case NHRP_CACHE_DYNAMIC
:
120 case NHRP_CACHE_STATIC
:
121 /* Regular route, so these are announced
122 * to other routing daemons */
125 SET_FLAG(api
.flags
, ZEBRA_FLAG_FIB_OVERRIDE
);
128 SET_FLAG(api
.flags
, ZEBRA_FLAG_ALLOW_RECURSION
);
130 SET_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
);
132 api_nh
= &api
.nexthops
[0];
133 api_nh
->vrf_id
= VRF_DEFAULT
;
135 switch (api
.prefix
.family
) {
137 if (api
.prefix
.prefixlen
== IPV4_MAX_BITLEN
&&
139 memcmp(&nexthop_ref
->sin
.sin_addr
, &api
.prefix
.u
.prefix4
,
140 sizeof(struct in_addr
)) == 0) {
144 api_nh
->gate
.ipv4
= nexthop_ref
->sin
.sin_addr
;
145 api_nh
->type
= NEXTHOP_TYPE_IPV4
;
148 api_nh
->ifindex
= ifp
->ifindex
;
149 if (api_nh
->type
== NEXTHOP_TYPE_IPV4
)
150 api_nh
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
152 api_nh
->type
= NEXTHOP_TYPE_IFINDEX
;
156 if (api
.prefix
.prefixlen
== IPV6_MAX_BITLEN
&&
158 memcmp(&nexthop_ref
->sin6
.sin6_addr
, &api
.prefix
.u
.prefix6
,
159 sizeof(struct in6_addr
)) == 0) {
163 api_nh
->gate
.ipv6
= nexthop_ref
->sin6
.sin6_addr
;
164 api_nh
->type
= NEXTHOP_TYPE_IPV6
;
167 api_nh
->ifindex
= ifp
->ifindex
;
168 if (api_nh
->type
== NEXTHOP_TYPE_IPV6
)
169 api_nh
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
171 api_nh
->type
= NEXTHOP_TYPE_IFINDEX
;
176 SET_FLAG(api
.message
, ZAPI_MESSAGE_MTU
);
180 if (unlikely(debug_flags
& NHRP_DEBUG_ROUTE
)) {
181 char buf
[PREFIX_STRLEN
];
184 "Zebra send: route %s %pFX nexthop %s metric %u count %d dev %s",
185 add
? "add" : "del", &api
.prefix
,
186 nexthop_ref
? inet_ntop(api
.prefix
.family
,
190 api
.metric
, api
.nexthop_num
, ifp
? ifp
->name
: "none");
193 zclient_route_send(add
? ZEBRA_ROUTE_ADD
: ZEBRA_ROUTE_DELETE
, zclient
,
197 int nhrp_route_read(ZAPI_CALLBACK_ARGS
)
199 struct zapi_route api
;
200 struct zapi_nexthop
*api_nh
;
201 struct interface
*ifp
= NULL
;
202 union sockunion nexthop_addr
;
205 if (zapi_route_decode(zclient
->ibuf
, &api
) < 0)
208 /* we completely ignore srcdest routes for now. */
209 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_SRCPFX
))
212 /* ignore our routes */
213 if (api
.type
== ZEBRA_ROUTE_NHRP
)
216 sockunion_family(&nexthop_addr
) = AF_UNSPEC
;
217 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
)) {
218 api_nh
= &api
.nexthops
[0];
220 nexthop_addr
.sa
.sa_family
= api
.prefix
.family
;
221 switch (nexthop_addr
.sa
.sa_family
) {
223 nexthop_addr
.sin
.sin_addr
= api_nh
->gate
.ipv4
;
226 nexthop_addr
.sin6
.sin6_addr
= api_nh
->gate
.ipv6
;
230 if (api_nh
->ifindex
!= IFINDEX_INTERNAL
)
231 ifp
= if_lookup_by_index(api_nh
->ifindex
, VRF_DEFAULT
);
234 added
= (cmd
== ZEBRA_REDISTRIBUTE_ROUTE_ADD
);
235 debugf(NHRP_DEBUG_ROUTE
, "if-route-%s: %pFX via %pSU dev %s",
236 added
? "add" : "del", &api
.prefix
, &nexthop_addr
,
237 ifp
? ifp
->name
: "(none)");
239 nhrp_route_update_zebra(&api
.prefix
, &nexthop_addr
, added
? ifp
: NULL
);
240 nhrp_shortcut_prefix_change(&api
.prefix
, !added
);
245 int nhrp_route_get_nexthop(const union sockunion
*addr
, struct prefix
*p
,
246 union sockunion
*via
, struct interface
**ifp
)
248 struct route_node
*rn
;
249 struct route_info
*ri
;
250 struct prefix lookup
;
251 afi_t afi
= family2afi(sockunion_family(addr
));
253 sockunion2hostprefix(addr
, &lookup
);
255 rn
= route_node_match(zebra_rib
[afi
], &lookup
);
261 debugf(NHRP_DEBUG_ROUTE
, "lookup %pFX: nhrp_if=%s", &lookup
,
265 sockunion_family(via
) = AF_UNSPEC
;
269 debugf(NHRP_DEBUG_ROUTE
, "lookup %pFX: zebra route dev %s",
270 &lookup
, ri
->ifp
? ri
->ifp
->name
: "(none)");
279 route_unlock_node(rn
);
283 enum nhrp_route_type
nhrp_route_address(struct interface
*in_ifp
,
284 union sockunion
*addr
, struct prefix
*p
,
285 struct nhrp_peer
**peer
)
287 struct interface
*ifp
= in_ifp
;
288 struct nhrp_interface
*nifp
;
289 struct nhrp_cache
*c
;
290 union sockunion via
[4];
291 uint32_t network_id
= 0;
292 afi_t afi
= family2afi(sockunion_family(addr
));
297 network_id
= nifp
->afi
[afi
].network_id
;
299 c
= nhrp_cache_get(ifp
, addr
, 0);
300 if (c
&& c
->cur
.type
== NHRP_CACHE_LOCAL
) {
302 memset(p
, 0, sizeof(*p
));
303 return NHRP_ROUTE_LOCAL
;
307 for (i
= 0; i
< 4; i
++) {
308 if (!nhrp_route_get_nexthop(addr
, p
, &via
[i
], &ifp
))
309 return NHRP_ROUTE_BLACKHOLE
;
311 /* Departing from nbma network? */
314 && network_id
!= nifp
->afi
[afi
].network_id
)
315 return NHRP_ROUTE_OFF_NBMA
;
317 if (sockunion_family(&via
[i
]) == AF_UNSPEC
)
319 /* Resolve via node, but return the prefix of first match */
325 c
= nhrp_cache_get(ifp
, addr
, 0);
326 if (c
&& c
->cur
.type
>= NHRP_CACHE_DYNAMIC
) {
328 memset(p
, 0, sizeof(*p
));
329 if (c
->cur
.type
== NHRP_CACHE_LOCAL
)
330 return NHRP_ROUTE_LOCAL
;
332 *peer
= nhrp_peer_ref(c
->cur
.peer
);
333 return NHRP_ROUTE_NBMA_NEXTHOP
;
337 return NHRP_ROUTE_BLACKHOLE
;
340 static void nhrp_zebra_connected(struct zclient
*zclient
)
342 zclient_send_reg_requests(zclient
, VRF_DEFAULT
);
343 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD
, zclient
, AFI_IP
,
344 ZEBRA_ROUTE_ALL
, 0, VRF_DEFAULT
);
345 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD
, zclient
, AFI_IP6
,
346 ZEBRA_ROUTE_ALL
, 0, VRF_DEFAULT
);
349 void nhrp_zebra_init(void)
351 zebra_rib
[AFI_IP
] = route_table_init();
352 zebra_rib
[AFI_IP6
] = route_table_init();
354 zclient
= zclient_new(master
, &zclient_options_default
);
355 zclient
->zebra_connected
= nhrp_zebra_connected
;
356 zclient
->interface_address_add
= nhrp_interface_address_add
;
357 zclient
->interface_address_delete
= nhrp_interface_address_delete
;
358 zclient
->redistribute_route_add
= nhrp_route_read
;
359 zclient
->redistribute_route_del
= nhrp_route_read
;
361 zclient_init(zclient
, ZEBRA_ROUTE_NHRP
, 0, &nhrpd_privs
);
364 static void nhrp_table_node_cleanup(struct route_table
*table
,
365 struct route_node
*node
)
370 XFREE(MTYPE_NHRP_ROUTE
, node
->info
);
373 void nhrp_zebra_terminate(void)
375 zclient_stop(zclient
);
376 zclient_free(zclient
);
378 zebra_rib
[AFI_IP
]->cleanup
= nhrp_table_node_cleanup
;
379 zebra_rib
[AFI_IP6
]->cleanup
= nhrp_table_node_cleanup
;
380 route_table_finish(zebra_rib
[AFI_IP
]);
381 route_table_finish(zebra_rib
[AFI_IP6
]);