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