2 * Copyright (c) 2014-2015 Timo Teräs
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.
14 #include <net/if_arp.h>
24 DEFINE_MTYPE_STATIC(NHRPD
, NHRP_IF
, "NHRP interface");
26 static void nhrp_interface_update_cache_config(struct interface
*ifp
,
30 static int nhrp_if_new_hook(struct interface
*ifp
)
32 struct nhrp_interface
*nifp
;
35 nifp
= XCALLOC(MTYPE_NHRP_IF
, sizeof(struct nhrp_interface
));
40 notifier_init(&nifp
->notifier_list
);
41 for (afi
= 0; afi
< AFI_MAX
; afi
++) {
42 struct nhrp_afi_data
*ad
= &nifp
->afi
[afi
];
43 ad
->holdtime
= NHRPD_DEFAULT_HOLDTIME
;
44 list_init(&ad
->nhslist_head
);
50 static int nhrp_if_delete_hook(struct interface
*ifp
)
52 struct nhrp_interface
*nifp
= ifp
->info
;
54 debugf(NHRP_DEBUG_IF
, "Deleted interface (%s)", ifp
->name
);
56 nhrp_cache_interface_del(ifp
);
57 nhrp_nhs_interface_del(ifp
);
58 nhrp_peer_interface_del(ifp
);
60 if (nifp
->ipsec_profile
)
61 free(nifp
->ipsec_profile
);
62 if (nifp
->ipsec_fallback_profile
)
63 free(nifp
->ipsec_fallback_profile
);
67 XFREE(MTYPE_NHRP_IF
, ifp
->info
);
71 void nhrp_interface_init(void)
73 hook_register_prio(if_add
, 0, nhrp_if_new_hook
);
74 hook_register_prio(if_del
, 0, nhrp_if_delete_hook
);
77 void nhrp_interface_update_mtu(struct interface
*ifp
, afi_t afi
)
79 struct nhrp_interface
*nifp
= ifp
->info
;
80 struct nhrp_afi_data
*if_ad
= &nifp
->afi
[afi
];
81 unsigned short new_mtu
;
83 if (if_ad
->configured_mtu
< 0)
84 new_mtu
= nifp
->nbmaifp
? nifp
->nbmaifp
->mtu
: 0;
86 new_mtu
= if_ad
->configured_mtu
;
90 if (new_mtu
!= if_ad
->mtu
) {
91 debugf(NHRP_DEBUG_IF
, "%s: MTU changed to %d", ifp
->name
,
94 notifier_call(&nifp
->notifier_list
,
95 NOTIFY_INTERFACE_MTU_CHANGED
);
99 static void nhrp_interface_update_source(struct interface
*ifp
)
101 struct nhrp_interface
*nifp
= ifp
->info
;
103 if (!nifp
->source
|| !nifp
->nbmaifp
104 || (ifindex_t
)nifp
->linkidx
== nifp
->nbmaifp
->ifindex
)
107 nifp
->linkidx
= nifp
->nbmaifp
->ifindex
;
108 debugf(NHRP_DEBUG_IF
, "%s: bound device index changed to %d", ifp
->name
,
110 netlink_gre_set_link(ifp
->ifindex
, nifp
->linkidx
);
113 static void nhrp_interface_interface_notifier(struct notifier_block
*n
,
116 struct nhrp_interface
*nifp
=
117 container_of(n
, struct nhrp_interface
, nbmanifp_notifier
);
118 struct interface
*nbmaifp
= nifp
->nbmaifp
;
119 struct nhrp_interface
*nbmanifp
= nbmaifp
->info
;
122 case NOTIFY_INTERFACE_CHANGED
:
123 nhrp_interface_update_mtu(nifp
->ifp
, AFI_IP
);
124 nhrp_interface_update_source(nifp
->ifp
);
126 case NOTIFY_INTERFACE_ADDRESS_CHANGED
:
127 nifp
->nbma
= nbmanifp
->afi
[AFI_IP
].addr
;
128 nhrp_interface_update(nifp
->ifp
);
129 notifier_call(&nifp
->notifier_list
,
130 NOTIFY_INTERFACE_NBMA_CHANGED
);
131 debugf(NHRP_DEBUG_IF
, "%s: NBMA change: address %pSU",
132 nifp
->ifp
->name
, &nifp
->nbma
);
137 static void nhrp_interface_update_nbma(struct interface
*ifp
)
139 struct nhrp_interface
*nifp
= ifp
->info
, *nbmanifp
= NULL
;
140 struct interface
*nbmaifp
= NULL
;
141 union sockunion nbma
;
143 sockunion_family(&nbma
) = AF_UNSPEC
;
146 nbmaifp
= if_lookup_by_name(nifp
->source
, VRF_DEFAULT
);
148 switch (ifp
->ll_type
) {
149 case ZEBRA_LLT_IPGRE
: {
150 struct in_addr saddr
= {0};
151 netlink_gre_get_info(ifp
->ifindex
, &nifp
->grekey
,
152 &nifp
->linkidx
, &saddr
);
153 debugf(NHRP_DEBUG_IF
, "%s: GRE: %x %x %x", ifp
->name
,
154 nifp
->grekey
, nifp
->linkidx
, saddr
.s_addr
);
155 if (saddr
.s_addr
!= INADDR_ANY
)
156 sockunion_set(&nbma
, AF_INET
, (uint8_t *)&saddr
.s_addr
,
157 sizeof(saddr
.s_addr
));
158 else if (!nbmaifp
&& nifp
->linkidx
!= IFINDEX_INTERNAL
)
160 if_lookup_by_index(nifp
->linkidx
, VRF_DEFAULT
);
167 nbmanifp
= nbmaifp
->info
;
169 if (nbmaifp
!= nifp
->nbmaifp
) {
171 notifier_del(&nifp
->nbmanifp_notifier
);
172 nifp
->nbmaifp
= nbmaifp
;
174 notifier_add(&nifp
->nbmanifp_notifier
,
175 &nbmanifp
->notifier_list
,
176 nhrp_interface_interface_notifier
);
177 debugf(NHRP_DEBUG_IF
, "%s: bound to %s", ifp
->name
,
183 if (sockunion_family(&nbma
) == AF_UNSPEC
)
184 nbma
= nbmanifp
->afi
[AFI_IP
].addr
;
185 nhrp_interface_update_mtu(ifp
, AFI_IP
);
186 nhrp_interface_update_source(ifp
);
189 if (!sockunion_same(&nbma
, &nifp
->nbma
)) {
191 nhrp_interface_update(nifp
->ifp
);
192 debugf(NHRP_DEBUG_IF
, "%s: NBMA address changed", ifp
->name
);
193 notifier_call(&nifp
->notifier_list
,
194 NOTIFY_INTERFACE_NBMA_CHANGED
);
197 nhrp_interface_update(ifp
);
200 static void nhrp_interface_update_address(struct interface
*ifp
, afi_t afi
,
203 const int family
= afi2family(afi
);
204 struct nhrp_interface
*nifp
= ifp
->info
;
205 struct nhrp_afi_data
*if_ad
= &nifp
->afi
[afi
];
206 struct nhrp_cache
*nc
;
207 struct connected
*c
, *best
;
208 struct listnode
*cnode
;
209 union sockunion addr
;
210 char buf
[PREFIX_STRLEN
];
212 /* Select new best match preferring primary address */
214 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
215 if (PREFIX_FAMILY(c
->address
) != family
)
221 if ((best
->flags
& ZEBRA_IFA_SECONDARY
)
222 && !(c
->flags
& ZEBRA_IFA_SECONDARY
)) {
226 if (!(best
->flags
& ZEBRA_IFA_SECONDARY
)
227 && (c
->flags
& ZEBRA_IFA_SECONDARY
))
229 if (best
->address
->prefixlen
> c
->address
->prefixlen
) {
233 if (best
->address
->prefixlen
< c
->address
->prefixlen
)
237 /* On NHRP interfaces a host prefix is required */
238 if (best
&& if_ad
->configured
239 && best
->address
->prefixlen
!= 8 * prefix_blen(best
->address
)) {
240 zlog_notice("%s: %pFX is not a host prefix", ifp
->name
,
245 /* Update address if it changed */
247 prefix2sockunion(best
->address
, &addr
);
249 memset(&addr
, 0, sizeof(addr
));
251 if (!force
&& sockunion_same(&if_ad
->addr
, &addr
))
254 if (sockunion_family(&if_ad
->addr
) != AF_UNSPEC
) {
255 nc
= nhrp_cache_get(ifp
, &if_ad
->addr
, 0);
257 nhrp_cache_update_binding(nc
, NHRP_CACHE_LOCAL
, -1,
258 NULL
, 0, NULL
, NULL
);
261 debugf(NHRP_DEBUG_KERNEL
, "%s: IPv%d address changed to %s", ifp
->name
,
262 afi
== AFI_IP
? 4 : 6,
263 best
? prefix2str(best
->address
, buf
, sizeof(buf
)) : "(none)");
266 if (if_ad
->configured
&& sockunion_family(&if_ad
->addr
) != AF_UNSPEC
) {
267 nc
= nhrp_cache_get(ifp
, &addr
, 1);
269 nhrp_cache_update_binding(nc
, NHRP_CACHE_LOCAL
, 0, NULL
,
273 notifier_call(&nifp
->notifier_list
, NOTIFY_INTERFACE_ADDRESS_CHANGED
);
276 void nhrp_interface_update(struct interface
*ifp
)
278 struct nhrp_interface
*nifp
= ifp
->info
;
279 struct nhrp_afi_data
*if_ad
;
283 notifier_call(&nifp
->notifier_list
, NOTIFY_INTERFACE_CHANGED
);
285 for (afi
= 0; afi
< AFI_MAX
; afi
++) {
286 if_ad
= &nifp
->afi
[afi
];
288 if (sockunion_family(&nifp
->nbma
) == AF_UNSPEC
289 || ifp
->ifindex
== IFINDEX_INTERNAL
|| !if_is_up(ifp
)
290 || !if_ad
->network_id
) {
291 if (if_ad
->configured
) {
292 if_ad
->configured
= 0;
293 nhrp_interface_update_address(ifp
, afi
, 1);
298 if (!if_ad
->configured
) {
299 os_configure_dmvpn(ifp
->ifindex
, ifp
->name
,
301 if_ad
->configured
= 1;
302 nhrp_interface_update_address(ifp
, afi
, 1);
308 if (enabled
!= nifp
->enabled
) {
309 nifp
->enabled
= enabled
;
310 notifier_call(&nifp
->notifier_list
,
311 enabled
? NOTIFY_INTERFACE_UP
312 : NOTIFY_INTERFACE_DOWN
);
316 int nhrp_ifp_create(struct interface
*ifp
)
318 debugf(NHRP_DEBUG_IF
, "if-add: %s, ifindex: %u, hw_type: %d %s",
319 ifp
->name
, ifp
->ifindex
, ifp
->ll_type
,
320 if_link_type_str(ifp
->ll_type
));
322 nhrp_interface_update_nbma(ifp
);
327 int nhrp_ifp_destroy(struct interface
*ifp
)
329 debugf(NHRP_DEBUG_IF
, "if-delete: %s", ifp
->name
);
331 nhrp_interface_update_cache_config(ifp
, false, AF_INET
);
332 nhrp_interface_update_cache_config(ifp
, false, AF_INET6
);
333 nhrp_interface_update(ifp
);
343 static void interface_config_update_nhrp_map(struct nhrp_cache_config
*cc
,
346 struct map_ctx
*ctx
= data
;
347 struct interface
*ifp
= cc
->ifp
;
348 struct nhrp_cache
*c
;
349 union sockunion nbma_addr
;
351 if (sockunion_family(&cc
->remote_addr
) != ctx
->family
)
354 /* gre layer not ready */
355 if (ifp
->vrf_id
== VRF_UNKNOWN
)
358 c
= nhrp_cache_get(ifp
, &cc
->remote_addr
, ctx
->enabled
? 1 : 0);
359 if (!c
&& !ctx
->enabled
)
365 nhrp_cache_update_binding(
367 nhrp_peer_get(ifp
, &nbma_addr
), 0, NULL
, NULL
);
376 if (cc
->type
== NHRP_CACHE_LOCAL
)
377 nhrp_cache_update_binding(c
, NHRP_CACHE_LOCAL
, 0, NULL
, 0,
380 nhrp_cache_update_binding(c
, NHRP_CACHE_STATIC
, 0,
381 nhrp_peer_get(ifp
, &cc
->nbma
), 0,
386 static void nhrp_interface_update_cache_config(struct interface
*ifp
, bool available
, uint8_t family
)
388 struct map_ctx mapctx
;
390 mapctx
= (struct map_ctx
){
394 nhrp_cache_config_foreach(ifp
, interface_config_update_nhrp_map
,
399 int nhrp_ifp_up(struct interface
*ifp
)
401 debugf(NHRP_DEBUG_IF
, "if-up: %s", ifp
->name
);
402 nhrp_interface_update_nbma(ifp
);
407 int nhrp_ifp_down(struct interface
*ifp
)
409 debugf(NHRP_DEBUG_IF
, "if-down: %s", ifp
->name
);
410 nhrp_interface_update(ifp
);
415 int nhrp_interface_address_add(ZAPI_CALLBACK_ARGS
)
417 struct connected
*ifc
;
419 ifc
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
423 debugf(NHRP_DEBUG_IF
, "if-addr-add: %s: %pFX", ifc
->ifp
->name
,
426 nhrp_interface_update_address(
427 ifc
->ifp
, family2afi(PREFIX_FAMILY(ifc
->address
)), 0);
428 nhrp_interface_update_cache_config(ifc
->ifp
, true, PREFIX_FAMILY(ifc
->address
));
432 int nhrp_interface_address_delete(ZAPI_CALLBACK_ARGS
)
434 struct connected
*ifc
;
436 ifc
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
440 debugf(NHRP_DEBUG_IF
, "if-addr-del: %s: %pFX", ifc
->ifp
->name
,
443 nhrp_interface_update_address(
444 ifc
->ifp
, family2afi(PREFIX_FAMILY(ifc
->address
)), 0);
445 connected_free(&ifc
);
450 void nhrp_interface_notify_add(struct interface
*ifp
, struct notifier_block
*n
,
453 struct nhrp_interface
*nifp
= ifp
->info
;
454 notifier_add(n
, &nifp
->notifier_list
, fn
);
457 void nhrp_interface_notify_del(struct interface
*ifp
, struct notifier_block
*n
)
462 void nhrp_interface_set_protection(struct interface
*ifp
, const char *profile
,
463 const char *fallback_profile
)
465 struct nhrp_interface
*nifp
= ifp
->info
;
467 if (nifp
->ipsec_profile
) {
468 vici_terminate_vc_by_profile_name(nifp
->ipsec_profile
);
470 free(nifp
->ipsec_profile
);
472 nifp
->ipsec_profile
= profile
? strdup(profile
) : NULL
;
474 if (nifp
->ipsec_fallback_profile
) {
475 vici_terminate_vc_by_profile_name(nifp
->ipsec_fallback_profile
);
477 free(nifp
->ipsec_fallback_profile
);
479 nifp
->ipsec_fallback_profile
=
480 fallback_profile
? strdup(fallback_profile
) : NULL
;
482 notifier_call(&nifp
->notifier_list
, NOTIFY_INTERFACE_IPSEC_CHANGED
);
485 void nhrp_interface_set_source(struct interface
*ifp
, const char *ifname
)
487 struct nhrp_interface
*nifp
= ifp
->info
;
491 nifp
->source
= ifname
? strdup(ifname
) : NULL
;
493 nhrp_interface_update_nbma(ifp
);