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.
17 DEFINE_MTYPE_STATIC(NHRPD
, NHRP_ROUTE
, "NHRP routing entry")
19 static struct zclient
*zclient
;
20 static struct route_table
*zebra_rib
[AFI_MAX
];
24 struct interface
*ifp
;
25 struct interface
*nhrp_ifp
;
28 static struct route_node
*nhrp_route_update_get(const struct prefix
*p
, int create
)
30 struct route_node
*rn
;
31 afi_t afi
= family2afi(PREFIX_FAMILY(p
));
37 rn
= route_node_get(zebra_rib
[afi
], p
);
39 rn
->info
= XCALLOC(MTYPE_NHRP_ROUTE
, sizeof(struct route_info
));
44 return route_node_lookup(zebra_rib
[afi
], p
);
48 static void nhrp_route_update_put(struct route_node
*rn
)
50 struct route_info
*ri
= rn
->info
;
52 if (!ri
->ifp
&& !ri
->nhrp_ifp
&& sockunion_family(&ri
->via
) == AF_UNSPEC
) {
53 XFREE(MTYPE_NHRP_ROUTE
, rn
->info
);
55 route_unlock_node(rn
);
57 route_unlock_node(rn
);
60 static void nhrp_route_update_zebra(const struct prefix
*p
, union sockunion
*nexthop
, struct interface
*ifp
)
62 struct route_node
*rn
;
63 struct route_info
*ri
;
65 rn
= nhrp_route_update_get(p
, (sockunion_family(nexthop
) != AF_UNSPEC
) || ifp
);
70 nhrp_route_update_put(rn
);
74 void nhrp_route_update_nhrp(const struct prefix
*p
, struct interface
*ifp
)
76 struct route_node
*rn
;
77 struct route_info
*ri
;
79 rn
= nhrp_route_update_get(p
, ifp
!= NULL
);
83 nhrp_route_update_put(rn
);
87 void nhrp_route_announce(int add
, enum nhrp_cache_type type
, const struct prefix
*p
, struct interface
*ifp
, const union sockunion
*nexthop
, uint32_t mtu
)
89 struct zapi_route api
;
90 struct zapi_nexthop
*api_nh
;
92 if (zclient
->sock
< 0)
95 memset(&api
, 0, sizeof(api
));
96 api
.type
= ZEBRA_ROUTE_NHRP
;
97 api
.safi
= SAFI_UNICAST
;
98 api
.vrf_id
= VRF_DEFAULT
;
102 case NHRP_CACHE_NEGATIVE
:
103 zapi_route_set_blackhole(&api
, BLACKHOLE_REJECT
);
107 case NHRP_CACHE_DYNAMIC
:
109 case NHRP_CACHE_STATIC
:
110 /* Regular route, so these are announced
111 * to other routing daemons */
114 SET_FLAG(api
.flags
, ZEBRA_FLAG_FIB_OVERRIDE
);
117 SET_FLAG(api
.flags
, ZEBRA_FLAG_INTERNAL
);
119 SET_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
);
121 api_nh
= &api
.nexthops
[0];
122 api_nh
->vrf_id
= VRF_DEFAULT
;
124 switch (api
.prefix
.family
) {
127 api_nh
->gate
.ipv4
= nexthop
->sin
.sin_addr
;
128 api_nh
->type
= NEXTHOP_TYPE_IPV4
;
131 api_nh
->ifindex
= ifp
->ifindex
;
132 if (api_nh
->type
== NEXTHOP_TYPE_IPV4
)
133 api_nh
->type
= NEXTHOP_TYPE_IPV4_IFINDEX
;
135 api_nh
->type
= NEXTHOP_TYPE_IFINDEX
;
140 api_nh
->gate
.ipv6
= nexthop
->sin6
.sin6_addr
;
141 api_nh
->type
= NEXTHOP_TYPE_IPV6
;
144 api_nh
->ifindex
= ifp
->ifindex
;
145 if (api_nh
->type
== NEXTHOP_TYPE_IPV6
)
146 api_nh
->type
= NEXTHOP_TYPE_IPV6_IFINDEX
;
148 api_nh
->type
= NEXTHOP_TYPE_IFINDEX
;
153 SET_FLAG(api
.message
, ZAPI_MESSAGE_MTU
);
157 if (unlikely(debug_flags
& NHRP_DEBUG_ROUTE
)) {
158 char buf
[2][PREFIX_STRLEN
];
160 prefix2str(&api
.prefix
, buf
[0], sizeof(buf
[0]));
161 zlog_debug("Zebra send: route %s %s nexthop %s metric %u"
163 add
? "add" : "del", buf
[0],
164 nexthop
? inet_ntop(api
.prefix
.family
, &api_nh
->gate
, buf
[1], sizeof(buf
[1])) : "<onlink>",
165 api
.metric
, api
.nexthop_num
, ifp
? ifp
->name
: "none");
168 zclient_route_send(add
? ZEBRA_ROUTE_ADD
: ZEBRA_ROUTE_DELETE
, zclient
,
172 int nhrp_route_read(int cmd
, struct zclient
*zclient
, zebra_size_t length
, vrf_id_t vrf_id
)
174 struct zapi_route api
;
175 struct zapi_nexthop
*api_nh
;
176 struct interface
*ifp
= NULL
;
177 union sockunion nexthop_addr
;
178 char buf
[2][PREFIX_STRLEN
];
181 if (zapi_route_decode(zclient
->ibuf
, &api
) < 0)
184 /* we completely ignore srcdest routes for now. */
185 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_SRCPFX
))
188 sockunion_family(&nexthop_addr
) = AF_UNSPEC
;
189 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
)) {
190 api_nh
= &api
.nexthops
[0];
192 nexthop_addr
.sa
.sa_family
= api
.prefix
.family
;
193 switch (nexthop_addr
.sa
.sa_family
) {
195 nexthop_addr
.sin
.sin_addr
= api_nh
->gate
.ipv4
;
198 nexthop_addr
.sin6
.sin6_addr
= api_nh
->gate
.ipv6
;
202 if (api_nh
->ifindex
!= IFINDEX_INTERNAL
)
203 ifp
= if_lookup_by_index(api_nh
->ifindex
, VRF_DEFAULT
);
206 added
= (cmd
== ZEBRA_REDISTRIBUTE_ROUTE_ADD
);
207 debugf(NHRP_DEBUG_ROUTE
, "if-route-%s: %s via %s dev %s",
208 added
? "add" : "del",
209 prefix2str(&api
.prefix
, buf
[0], sizeof buf
[0]),
210 sockunion2str(&nexthop_addr
, buf
[1], sizeof buf
[1]),
211 ifp
? ifp
->name
: "(none)");
213 nhrp_route_update_zebra(&api
.prefix
, &nexthop_addr
, ifp
);
214 nhrp_shortcut_prefix_change(&api
.prefix
, !added
);
219 int nhrp_route_get_nexthop(const union sockunion
*addr
, struct prefix
*p
, union sockunion
*via
, struct interface
**ifp
)
221 struct route_node
*rn
;
222 struct route_info
*ri
;
223 struct prefix lookup
;
224 afi_t afi
= family2afi(sockunion_family(addr
));
225 char buf
[PREFIX_STRLEN
];
227 sockunion2hostprefix(addr
, &lookup
);
229 rn
= route_node_match(zebra_rib
[afi
], &lookup
);
234 debugf(NHRP_DEBUG_ROUTE
, "lookup %s: nhrp_if=%s",
235 prefix2str(&lookup
, buf
, sizeof buf
),
238 if (via
) sockunion_family(via
) = AF_UNSPEC
;
239 if (ifp
) *ifp
= ri
->nhrp_ifp
;
241 debugf(NHRP_DEBUG_ROUTE
, "lookup %s: zebra route dev %s",
242 prefix2str(&lookup
, buf
, sizeof buf
),
243 ri
->ifp
? ri
->ifp
->name
: "(none)");
245 if (via
) *via
= ri
->via
;
246 if (ifp
) *ifp
= ri
->ifp
;
249 route_unlock_node(rn
);
253 enum nhrp_route_type
nhrp_route_address(struct interface
*in_ifp
, union sockunion
*addr
, struct prefix
*p
, struct nhrp_peer
**peer
)
255 struct interface
*ifp
= in_ifp
;
256 struct nhrp_interface
*nifp
;
257 struct nhrp_cache
*c
;
258 union sockunion via
[4];
259 uint32_t network_id
= 0;
260 afi_t afi
= family2afi(sockunion_family(addr
));
265 network_id
= nifp
->afi
[afi
].network_id
;
267 c
= nhrp_cache_get(ifp
, addr
, 0);
268 if (c
&& c
->cur
.type
== NHRP_CACHE_LOCAL
) {
269 if (p
) memset(p
, 0, sizeof(*p
));
270 return NHRP_ROUTE_LOCAL
;
274 for (i
= 0; i
< 4; i
++) {
275 if (!nhrp_route_get_nexthop(addr
, p
, &via
[i
], &ifp
))
276 return NHRP_ROUTE_BLACKHOLE
;
278 /* Departing from nbma network? */
280 if (network_id
&& network_id
!= nifp
->afi
[afi
].network_id
)
281 return NHRP_ROUTE_OFF_NBMA
;
283 if (sockunion_family(&via
[i
]) == AF_UNSPEC
)
285 /* Resolve via node, but return the prefix of first match */
291 c
= nhrp_cache_get(ifp
, addr
, 0);
292 if (c
&& c
->cur
.type
>= NHRP_CACHE_DYNAMIC
) {
293 if (p
) memset(p
, 0, sizeof(*p
));
294 if (c
->cur
.type
== NHRP_CACHE_LOCAL
)
295 return NHRP_ROUTE_LOCAL
;
296 if (peer
) *peer
= nhrp_peer_ref(c
->cur
.peer
);
297 return NHRP_ROUTE_NBMA_NEXTHOP
;
301 return NHRP_ROUTE_BLACKHOLE
;
305 nhrp_zebra_connected (struct zclient
*zclient
)
307 zclient_send_reg_requests(zclient
, VRF_DEFAULT
);
308 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD
, zclient
, AFI_IP
,
309 ZEBRA_ROUTE_ALL
, 0, VRF_DEFAULT
);
310 zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD
, zclient
, AFI_IP6
,
311 ZEBRA_ROUTE_ALL
, 0, VRF_DEFAULT
);
314 void nhrp_zebra_init(void)
316 zebra_rib
[AFI_IP
] = route_table_init();
317 zebra_rib
[AFI_IP6
] = route_table_init();
319 zclient
= zclient_new_notify(master
, &zclient_options_default
);
320 zclient
->zebra_connected
= nhrp_zebra_connected
;
321 zclient
->interface_add
= nhrp_interface_add
;
322 zclient
->interface_delete
= nhrp_interface_delete
;
323 zclient
->interface_up
= nhrp_interface_up
;
324 zclient
->interface_down
= nhrp_interface_down
;
325 zclient
->interface_address_add
= nhrp_interface_address_add
;
326 zclient
->interface_address_delete
= nhrp_interface_address_delete
;
327 zclient
->redistribute_route_add
= nhrp_route_read
;
328 zclient
->redistribute_route_del
= nhrp_route_read
;
330 zclient_init(zclient
, ZEBRA_ROUTE_NHRP
, 0, &nhrpd_privs
);
333 void nhrp_zebra_terminate(void)
335 zclient_stop(zclient
);
336 zclient_free(zclient
);
337 route_table_finish(zebra_rib
[AFI_IP
]);
338 route_table_finish(zebra_rib
[AFI_IP6
]);