]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/nhrp_interface.c
rmap: Minor changes in comments regarding match ip[v6] next-hop type
[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 "netlink.h"
23
24 DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF, "NHRP interface")
25
26 static 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));
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
46 static int nhrp_if_delete_hook(struct interface *ifp)
47 {
48 XFREE(MTYPE_NHRP_IF, ifp->info);
49 return 0;
50 }
51
52 void nhrp_interface_init(void)
53 {
54 hook_register_prio(if_add, 0, nhrp_if_new_hook);
55 hook_register_prio(if_del, 0, nhrp_if_delete_hook);
56 }
57
58 void 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) {
72 debugf(NHRP_DEBUG_IF, "%s: MTU changed to %d", ifp->name,
73 new_mtu);
74 if_ad->mtu = new_mtu;
75 notifier_call(&nifp->notifier_list,
76 NOTIFY_INTERFACE_MTU_CHANGED);
77 }
78 }
79
80 static void nhrp_interface_update_source(struct interface *ifp)
81 {
82 struct nhrp_interface *nifp = ifp->info;
83
84 if (!nifp->source || !nifp->nbmaifp
85 || (ifindex_t)nifp->linkidx == nifp->nbmaifp->ifindex)
86 return;
87
88 nifp->linkidx = nifp->nbmaifp->ifindex;
89 debugf(NHRP_DEBUG_IF, "%s: bound device index changed to %d", ifp->name,
90 nifp->linkidx);
91 netlink_gre_set_link(ifp->ifindex, nifp->linkidx);
92 }
93
94 static void nhrp_interface_interface_notifier(struct notifier_block *n,
95 unsigned long cmd)
96 {
97 struct nhrp_interface *nifp =
98 container_of(n, struct nhrp_interface, nbmanifp_notifier);
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);
111 notifier_call(&nifp->notifier_list,
112 NOTIFY_INTERFACE_NBMA_CHANGED);
113 debugf(NHRP_DEBUG_IF, "%s: NBMA change: address %s",
114 nifp->ifp->name,
115 sockunion2str(&nifp->nbma, buf, sizeof buf));
116 break;
117 }
118 }
119
120 static 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)
129 nbmaifp = if_lookup_by_name(nifp->source, VRF_DEFAULT);
130
131 switch (ifp->ll_type) {
132 case ZEBRA_LLT_IPGRE: {
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)
139 sockunion_set(&nbma, AF_INET, (uint8_t *)&saddr.s_addr,
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;
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) {
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);
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);
176 notifier_call(&nifp->notifier_list,
177 NOTIFY_INTERFACE_NBMA_CHANGED);
178 }
179
180 nhrp_interface_update(ifp);
181 }
182
183 static void nhrp_interface_update_address(struct interface *ifp, afi_t afi,
184 int force)
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 }
204 if ((best->flags & ZEBRA_IFA_SECONDARY)
205 && !(c->flags & ZEBRA_IFA_SECONDARY)) {
206 best = c;
207 continue;
208 }
209 if (!(best->flags & ZEBRA_IFA_SECONDARY)
210 && (c->flags & ZEBRA_IFA_SECONDARY))
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 */
221 if (best && if_ad->configured
222 && best->address->prefixlen != 8 * prefix_blen(best->address)) {
223 zlog_notice("%s: %s is not a host prefix", ifp->name,
224 prefix2str(best->address, buf, sizeof buf));
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);
239 if (nc)
240 nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, -1,
241 NULL, 0, NULL);
242 }
243
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)");
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);
251 if (nc)
252 nhrp_cache_update_binding(nc, NHRP_CACHE_LOCAL, 0, NULL,
253 0, NULL);
254 }
255
256 notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED);
257 }
258
259 void 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
271 if (sockunion_family(&nifp->nbma) == AF_UNSPEC
272 || ifp->ifindex == IFINDEX_INTERNAL || !if_is_up(ifp)
273 || !if_ad->network_id) {
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) {
282 os_configure_dmvpn(ifp->ifindex, ifp->name,
283 afi2family(afi));
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;
293 notifier_call(&nifp->notifier_list,
294 enabled ? NOTIFY_INTERFACE_UP
295 : NOTIFY_INTERFACE_DOWN);
296 }
297 }
298
299 int nhrp_interface_add(ZAPI_CALLBACK_ARGS)
300 {
301 struct interface *ifp;
302
303 /* read and add the interface in the iflist. */
304 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
305 if (ifp == NULL)
306 return 0;
307
308 debugf(NHRP_DEBUG_IF, "if-add: %s, ifindex: %u, hw_type: %d %s",
309 ifp->name, ifp->ifindex, ifp->ll_type,
310 if_link_type_str(ifp->ll_type));
311
312 nhrp_interface_update_nbma(ifp);
313
314 return 0;
315 }
316
317 int nhrp_interface_delete(ZAPI_CALLBACK_ARGS)
318 {
319 struct interface *ifp;
320 struct stream *s;
321
322 s = zclient->ibuf;
323 ifp = zebra_interface_state_read(s, vrf_id);
324 if (ifp == NULL)
325 return 0;
326
327 debugf(NHRP_DEBUG_IF, "if-delete: %s", ifp->name);
328
329 nhrp_interface_update(ifp);
330
331 if_set_index(ifp, IFINDEX_INTERNAL);
332
333 return 0;
334 }
335
336 int nhrp_interface_up(ZAPI_CALLBACK_ARGS)
337 {
338 struct interface *ifp;
339
340 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
341 if (ifp == NULL)
342 return 0;
343
344 debugf(NHRP_DEBUG_IF, "if-up: %s", ifp->name);
345 nhrp_interface_update_nbma(ifp);
346
347 return 0;
348 }
349
350 int nhrp_interface_down(ZAPI_CALLBACK_ARGS)
351 {
352 struct interface *ifp;
353
354 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
355 if (ifp == NULL)
356 return 0;
357
358 debugf(NHRP_DEBUG_IF, "if-down: %s", ifp->name);
359 nhrp_interface_update(ifp);
360 return 0;
361 }
362
363 int nhrp_interface_address_add(ZAPI_CALLBACK_ARGS)
364 {
365 struct connected *ifc;
366 char buf[PREFIX_STRLEN];
367
368 ifc = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
369 if (ifc == NULL)
370 return 0;
371
372 debugf(NHRP_DEBUG_IF, "if-addr-add: %s: %s", ifc->ifp->name,
373 prefix2str(ifc->address, buf, sizeof buf));
374
375 nhrp_interface_update_address(
376 ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0);
377
378 return 0;
379 }
380
381 int nhrp_interface_address_delete(ZAPI_CALLBACK_ARGS)
382 {
383 struct connected *ifc;
384 char buf[PREFIX_STRLEN];
385
386 ifc = zebra_interface_address_read(cmd, zclient->ibuf, vrf_id);
387 if (ifc == NULL)
388 return 0;
389
390 debugf(NHRP_DEBUG_IF, "if-addr-del: %s: %s", ifc->ifp->name,
391 prefix2str(ifc->address, buf, sizeof buf));
392
393 nhrp_interface_update_address(
394 ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0);
395 connected_free(ifc);
396
397 return 0;
398 }
399
400 void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n,
401 notifier_fn_t fn)
402 {
403 struct nhrp_interface *nifp = ifp->info;
404 notifier_add(n, &nifp->notifier_list, fn);
405 }
406
407 void nhrp_interface_notify_del(struct interface *ifp, struct notifier_block *n)
408 {
409 notifier_del(n);
410 }
411
412 void nhrp_interface_set_protection(struct interface *ifp, const char *profile,
413 const char *fallback_profile)
414 {
415 struct nhrp_interface *nifp = ifp->info;
416
417 if (nifp->ipsec_profile)
418 free(nifp->ipsec_profile);
419 nifp->ipsec_profile = profile ? strdup(profile) : NULL;
420
421 if (nifp->ipsec_fallback_profile)
422 free(nifp->ipsec_fallback_profile);
423 nifp->ipsec_fallback_profile =
424 fallback_profile ? strdup(fallback_profile) : NULL;
425
426 notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED);
427 }
428
429 void nhrp_interface_set_source(struct interface *ifp, const char *ifname)
430 {
431 struct nhrp_interface *nifp = ifp->info;
432
433 if (nifp->source)
434 free(nifp->source);
435 nifp->source = ifname ? strdup(ifname) : NULL;
436
437 nhrp_interface_update_nbma(ifp);
438 }