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