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