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