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