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