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