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