]> git.proxmox.com Git - mirror_frr.git/blame - nhrpd/nhrp_interface.c
nhrpd: implement next hop resolution protocol
[mirror_frr.git] / nhrpd / nhrp_interface.c
CommitLineData
2fb975da
TT
1/* NHRP interface
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#include <net/if_arp.h>
11#include "zebra.h"
12#include "linklist.h"
13#include "memory.h"
14#include "thread.h"
15
16#include "nhrpd.h"
17#include "os.h"
18#include "netlink.h"
19
20static int nhrp_if_new_hook(struct interface *ifp)
21{
22 struct nhrp_interface *nifp;
23 afi_t afi;
24
25 nifp = XCALLOC(MTYPE_NHRP_IF, sizeof(struct nhrp_interface));
26 if (!nifp) return 0;
27
28 ifp->info = nifp;
29 nifp->ifp = ifp;
30
31 notifier_init(&nifp->notifier_list);
32 for (afi = 0; afi < AFI_MAX; afi++) {
33 struct nhrp_afi_data *ad = &nifp->afi[afi];
34 ad->holdtime = NHRPD_DEFAULT_HOLDTIME;
35 list_init(&ad->nhslist_head);
36 }
37
38 return 0;
39}
40
41static int nhrp_if_delete_hook(struct interface *ifp)
42{
43 XFREE(MTYPE_NHRP_IF, ifp->info);
44 return 0;
45}
46
47void nhrp_interface_init(void)
48{
49 if_add_hook(IF_NEW_HOOK, nhrp_if_new_hook);
50 if_add_hook(IF_DELETE_HOOK, nhrp_if_delete_hook);
51}
52
53void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi)
54{
55 struct nhrp_interface *nifp = ifp->info;
56 struct nhrp_afi_data *if_ad = &nifp->afi[afi];
57 unsigned short new_mtu;
58
59 if (if_ad->configured_mtu < 0)
60 new_mtu = nifp->nbmaifp ? nifp->nbmaifp->mtu : 0;
61 else
62 new_mtu = if_ad->configured_mtu;
63 if (new_mtu >= 1500)
64 new_mtu = 0;
65
66 if (new_mtu != if_ad->mtu) {
67 debugf(NHRP_DEBUG_IF, "%s: MTU changed to %d", ifp->name, new_mtu);
68 if_ad->mtu = new_mtu;
69 notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_MTU_CHANGED);
70 }
71}
72
73static void nhrp_interface_update_source(struct interface *ifp)
74{
75 struct nhrp_interface *nifp = ifp->info;
76
77 if (!nifp->source || !nifp->nbmaifp ||
78 nifp->linkidx == nifp->nbmaifp->ifindex)
79 return;
80
81 nifp->linkidx = nifp->nbmaifp->ifindex;
82 debugf(NHRP_DEBUG_IF, "%s: bound device index changed to %d", ifp->name, nifp->linkidx);
83 netlink_gre_set_link(ifp->ifindex, nifp->linkidx);
84}
85
86static void nhrp_interface_interface_notifier(struct notifier_block *n, unsigned long cmd)
87{
88 struct nhrp_interface *nifp = container_of(n, struct nhrp_interface, nbmanifp_notifier);
89 struct interface *nbmaifp = nifp->nbmaifp;
90 struct nhrp_interface *nbmanifp = nbmaifp->info;
91 char buf[SU_ADDRSTRLEN];
92
93 switch (cmd) {
94 case NOTIFY_INTERFACE_CHANGED:
95 nhrp_interface_update_mtu(nifp->ifp, AFI_IP);
96 nhrp_interface_update_source(nifp->ifp);
97 break;
98 case NOTIFY_INTERFACE_ADDRESS_CHANGED:
99 nifp->nbma = nbmanifp->afi[AFI_IP].addr;
100 nhrp_interface_update(nifp->ifp);
101 notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_NBMA_CHANGED);
102 debugf(NHRP_DEBUG_IF, "%s: NBMA change: address %s",
103 nifp->ifp->name,
104 sockunion2str(&nifp->nbma, buf, sizeof buf));
105 break;
106 }
107}
108
109static void nhrp_interface_update_nbma(struct interface *ifp)
110{
111 struct nhrp_interface *nifp = ifp->info, *nbmanifp = NULL;
112 struct interface *nbmaifp = NULL;
113 union sockunion nbma;
114
115 sockunion_family(&nbma) = AF_UNSPEC;
116
117 if (nifp->source)
118 nbmaifp = if_lookup_by_name(nifp->source);
119
120 switch (ifp->ll_type) {
121 case ZEBRA_LLT_IPGRE: {
122 struct in_addr saddr = {0};
123 netlink_gre_get_info(ifp->ifindex, &nifp->grekey, &nifp->linkidx, &saddr);
124 debugf(NHRP_DEBUG_IF, "%s: GRE: %x %x %x", ifp->name, nifp->grekey, nifp->linkidx, saddr.s_addr);
125 if (saddr.s_addr)
126 sockunion_set(&nbma, AF_INET, (u_char *) &saddr.s_addr, sizeof(saddr.s_addr));
127 else if (!nbmaifp && nifp->linkidx != IFINDEX_INTERNAL)
128 nbmaifp = if_lookup_by_index(nifp->linkidx);
129 }
130 break;
131 default:
132 break;
133 }
134
135 if (nbmaifp)
136 nbmanifp = nbmaifp->info;
137
138 if (nbmaifp != nifp->nbmaifp) {
139 if (nifp->nbmaifp)
140 notifier_del(&nifp->nbmanifp_notifier);
141 nifp->nbmaifp = nbmaifp;
142 if (nbmaifp) {
143 notifier_add(&nifp->nbmanifp_notifier, &nbmanifp->notifier_list, nhrp_interface_interface_notifier);
144 debugf(NHRP_DEBUG_IF, "%s: bound to %s", ifp->name, nbmaifp->name);
145 }
146 }
147
148 if (nbmaifp) {
149 if (sockunion_family(&nbma) == AF_UNSPEC)
150 nbma = nbmanifp->afi[AFI_IP].addr;
151 nhrp_interface_update_mtu(ifp, AFI_IP);
152 nhrp_interface_update_source(ifp);
153 }
154
155 if (!sockunion_same(&nbma, &nifp->nbma)) {
156 nifp->nbma = nbma;
157 nhrp_interface_update(nifp->ifp);
158 debugf(NHRP_DEBUG_IF, "%s: NBMA address changed", ifp->name);
159 notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_NBMA_CHANGED);
160 }
161
162 nhrp_interface_update(ifp);
163}
164
165static void nhrp_interface_update_address(struct interface *ifp, afi_t afi, int force)
166{
167 const int family = afi2family(afi);
168 struct nhrp_interface *nifp = ifp->info;
169 struct nhrp_afi_data *if_ad = &nifp->afi[afi];
170 struct nhrp_cache *nc;
171 struct connected *c, *best;
172 struct listnode *cnode;
173 union sockunion addr;
174 char buf[PREFIX_STRLEN];
175
176 /* Select new best match preferring primary address */
177 best = NULL;
178 for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
179 if (PREFIX_FAMILY(c->address) != family)
180 continue;
181 if (best == NULL) {
182 best = c;
183 continue;
184 }
185 if ((best->flags & ZEBRA_IFA_SECONDARY) && !(c->flags & ZEBRA_IFA_SECONDARY)) {
186 best = c;
187 continue;
188 }
189 if (!(best->flags & ZEBRA_IFA_SECONDARY) && (c->flags & ZEBRA_IFA_SECONDARY))
190 continue;
191 if (best->address->prefixlen > c->address->prefixlen) {
192 best = c;
193 continue;
194 }
195 if (best->address->prefixlen < c->address->prefixlen)
196 continue;
197 }
198
199 /* On NHRP interfaces a host prefix is required */
200 if (best && if_ad->configured && best->address->prefixlen != 8 * prefix_blen(best->address)) {
201 zlog_notice("%s: %s is not a host prefix", ifp->name,
202 prefix2str(best->address, buf, sizeof buf));
203 best = NULL;
204 }
205
206 /* Update address if it changed */
207 if (best)
208 prefix2sockunion(best->address, &addr);
209 else
210 memset(&addr, 0, sizeof(addr));
211
212 if (!force && sockunion_same(&if_ad->addr, &addr))
213 return;
214
215 if (sockunion_family(&if_ad->addr) != AF_UNSPEC) {
216 nc = nhrp_cache_get(ifp, &if_ad->addr, 0);
217 if (nc) nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, -1, NULL, 0, NULL);
218 }
219
220 debugf(NHRP_DEBUG_KERNEL, "%s: IPv%d address changed to %s",
221 ifp->name, afi == AFI_IP ? 4 : 6,
222 best ? prefix2str(best->address, buf, sizeof buf) : "(none)");
223 if_ad->addr = addr;
224
225 if (if_ad->configured && sockunion_family(&if_ad->addr) != AF_UNSPEC) {
226 nc = nhrp_cache_get(ifp, &addr, 1);
227 if (nc) nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, 0, NULL, 0, NULL);
228 }
229
230 notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED);
231}
232
233void nhrp_interface_update(struct interface *ifp)
234{
235 struct nhrp_interface *nifp = ifp->info;
236 struct nhrp_afi_data *if_ad;
237 afi_t afi;
238 int enabled = 0;
239
240 notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_CHANGED);
241
242 for (afi = 0; afi < AFI_MAX; afi++) {
243 if_ad = &nifp->afi[afi];
244
245 if (sockunion_family(&nifp->nbma) == AF_UNSPEC ||
246 ifp->ifindex == IFINDEX_INTERNAL || !if_is_up(ifp) ||
247 !if_ad->network_id) {
248 if (if_ad->configured) {
249 if_ad->configured = 0;
250 nhrp_interface_update_address(ifp, afi, 1);
251 }
252 continue;
253 }
254
255 if (!if_ad->configured) {
256 os_configure_dmvpn(ifp->ifindex, ifp->name, afi2family(afi));
257 if_ad->configured = 1;
258 nhrp_interface_update_address(ifp, afi, 1);
259 }
260
261 enabled = 1;
262 }
263
264 if (enabled != nifp->enabled) {
265 nifp->enabled = enabled;
266 notifier_call(&nifp->notifier_list, enabled ? NOTIFY_INTERFACE_UP : NOTIFY_INTERFACE_DOWN);
267 }
268}
269
270int nhrp_interface_add(int cmd, struct zclient *client, zebra_size_t length, vrf_id_t vrf_id)
271{
272 struct interface *ifp;
273
274 /* read and add the interface in the iflist. */
275 ifp = zebra_interface_add_read(client->ibuf, vrf_id);
276 if (ifp == NULL)
277 return 0;
278
279 debugf(NHRP_DEBUG_IF, "if-add: %s, ifindex: %u, hw_type: %d %s",
280 ifp->name, ifp->ifindex,
281 ifp->ll_type, if_link_type_str(ifp->ll_type));
282
283 nhrp_interface_update_nbma(ifp);
284
285 return 0;
286}
287
288int nhrp_interface_delete(int cmd, struct zclient *client,
289 zebra_size_t length, vrf_id_t vrf_id)
290{
291 struct interface *ifp;
292 struct stream *s;
293
294 s = client->ibuf;
295 ifp = zebra_interface_state_read(s, vrf_id);
296 if (ifp == NULL)
297 return 0;
298
299 debugf(NHRP_DEBUG_IF, "if-delete: %s", ifp->name);
300 ifp->ifindex = IFINDEX_INTERNAL;
301 nhrp_interface_update(ifp);
302 /* if_delete(ifp); */
303 return 0;
304}
305
306int nhrp_interface_up(int cmd, struct zclient *client,
307 zebra_size_t length, vrf_id_t vrf_id)
308{
309 struct interface *ifp;
310
311 ifp = zebra_interface_state_read(client->ibuf, vrf_id);
312 if (ifp == NULL)
313 return 0;
314
315 debugf(NHRP_DEBUG_IF, "if-up: %s", ifp->name);
316 nhrp_interface_update_nbma(ifp);
317
318 return 0;
319}
320
321int nhrp_interface_down(int cmd, struct zclient *client,
322 zebra_size_t length, vrf_id_t vrf_id)
323{
324 struct interface *ifp;
325
326 ifp = zebra_interface_state_read(client->ibuf, vrf_id);
327 if (ifp == NULL)
328 return 0;
329
330 debugf(NHRP_DEBUG_IF, "if-down: %s", ifp->name);
331 nhrp_interface_update(ifp);
332 return 0;
333}
334
335int nhrp_interface_address_add(int cmd, struct zclient *client,
336 zebra_size_t length, vrf_id_t vrf_id)
337{
338 struct connected *ifc;
339 char buf[PREFIX_STRLEN];
340
341 ifc = zebra_interface_address_read(cmd, client->ibuf, vrf_id);
342 if (ifc == NULL)
343 return 0;
344
345 debugf(NHRP_DEBUG_IF, "if-addr-add: %s: %s",
346 ifc->ifp->name,
347 prefix2str(ifc->address, buf, sizeof buf));
348
349 nhrp_interface_update_address(ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0);
350
351 return 0;
352}
353
354int nhrp_interface_address_delete(int cmd, struct zclient *client,
355 zebra_size_t length, vrf_id_t vrf_id)
356{
357 struct connected *ifc;
358 char buf[PREFIX_STRLEN];
359
360 ifc = zebra_interface_address_read(cmd, client->ibuf, vrf_id);
361 if (ifc == NULL)
362 return 0;
363
364 debugf(NHRP_DEBUG_IF, "if-addr-del: %s: %s",
365 ifc->ifp->name,
366 prefix2str(ifc->address, buf, sizeof buf));
367
368 nhrp_interface_update_address(ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0);
369 connected_free(ifc);
370
371 return 0;
372}
373
374void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n, notifier_fn_t fn)
375{
376 struct nhrp_interface *nifp = ifp->info;
377 notifier_add(n, &nifp->notifier_list, fn);
378}
379
380void nhrp_interface_notify_del(struct interface *ifp, struct notifier_block *n)
381{
382 notifier_del(n);
383}
384
385void nhrp_interface_set_protection(struct interface *ifp, const char *profile, const char *fallback_profile)
386{
387 struct nhrp_interface *nifp = ifp->info;
388
389 if (nifp->ipsec_profile) free(nifp->ipsec_profile);
390 nifp->ipsec_profile = profile ? strdup(profile) : NULL;
391
392 if (nifp->ipsec_fallback_profile) free(nifp->ipsec_fallback_profile);
393 nifp->ipsec_fallback_profile = fallback_profile ? strdup(fallback_profile) : NULL;
394}
395
396void nhrp_interface_set_source(struct interface *ifp, const char *ifname)
397{
398 struct nhrp_interface *nifp = ifp->info;
399
400 if (nifp->source) free(nifp->source);
401 nifp->source = ifname ? strdup(ifname) : NULL;
402
403 nhrp_interface_update_nbma(ifp);
404}