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");
25 DEFINE_MTYPE_STATIC(NHRPD
, NHRP_IF_GRE
, "NHRP GRE interface");
27 struct hash
*nhrp_gre_list
;
29 static void nhrp_interface_update_cache_config(struct interface
*ifp
,
33 static unsigned int nhrp_gre_info_key(const void *data
)
35 const struct nhrp_gre_info
*r
= data
;
40 static bool nhrp_gre_info_cmp(const void *data
, const void *key
)
42 const struct nhrp_gre_info
*a
= data
, *b
= key
;
44 if (a
->ifindex
== b
->ifindex
)
49 static void *nhrp_interface_gre_alloc(void *data
)
51 struct nhrp_gre_info
*a
;
52 struct nhrp_gre_info
*b
= data
;
54 a
= XMALLOC(MTYPE_NHRP_IF_GRE
, sizeof(struct nhrp_gre_info
));
55 memcpy(a
, b
, sizeof(struct nhrp_gre_info
));
59 struct nhrp_gre_info
*nhrp_gre_info_alloc(struct nhrp_gre_info
*p
)
61 struct nhrp_gre_info
*a
;
63 a
= (struct nhrp_gre_info
*)hash_get(nhrp_gre_list
, p
,
64 nhrp_interface_gre_alloc
);
68 static int nhrp_if_new_hook(struct interface
*ifp
)
70 struct nhrp_interface
*nifp
;
73 nifp
= XCALLOC(MTYPE_NHRP_IF
, sizeof(struct nhrp_interface
));
78 notifier_init(&nifp
->notifier_list
);
79 for (afi
= 0; afi
< AFI_MAX
; afi
++) {
80 struct nhrp_afi_data
*ad
= &nifp
->afi
[afi
];
81 ad
->holdtime
= NHRPD_DEFAULT_HOLDTIME
;
82 list_init(&ad
->nhslist_head
);
83 list_init(&ad
->mcastlist_head
);
89 static int nhrp_if_delete_hook(struct interface
*ifp
)
91 struct nhrp_interface
*nifp
= ifp
->info
;
93 debugf(NHRP_DEBUG_IF
, "Deleted interface (%s)", ifp
->name
);
95 nhrp_cache_interface_del(ifp
);
96 nhrp_nhs_interface_del(ifp
);
97 nhrp_multicast_interface_del(ifp
);
98 nhrp_peer_interface_del(ifp
);
100 if (nifp
->ipsec_profile
)
101 free(nifp
->ipsec_profile
);
102 if (nifp
->ipsec_fallback_profile
)
103 free(nifp
->ipsec_fallback_profile
);
107 XFREE(MTYPE_NHRP_IF
, ifp
->info
);
111 void nhrp_interface_init(void)
113 hook_register_prio(if_add
, 0, nhrp_if_new_hook
);
114 hook_register_prio(if_del
, 0, nhrp_if_delete_hook
);
116 nhrp_gre_list
= hash_create(nhrp_gre_info_key
, nhrp_gre_info_cmp
,
117 "NHRP GRE list Hash");
120 void nhrp_interface_update_mtu(struct interface
*ifp
, afi_t afi
)
122 struct nhrp_interface
*nifp
= ifp
->info
;
123 struct nhrp_afi_data
*if_ad
= &nifp
->afi
[afi
];
124 unsigned short new_mtu
;
126 if (if_ad
->configured_mtu
< 0)
127 new_mtu
= nifp
->nbmaifp
? nifp
->nbmaifp
->mtu
: 0;
129 new_mtu
= if_ad
->configured_mtu
;
133 if (new_mtu
!= if_ad
->mtu
) {
134 debugf(NHRP_DEBUG_IF
, "%s: MTU changed to %d", ifp
->name
,
136 if_ad
->mtu
= new_mtu
;
137 notifier_call(&nifp
->notifier_list
,
138 NOTIFY_INTERFACE_MTU_CHANGED
);
142 static void nhrp_interface_update_source(struct interface
*ifp
)
144 struct nhrp_interface
*nifp
= ifp
->info
;
146 if (!nifp
->source
|| !nifp
->nbmaifp
||
147 ((ifindex_t
)nifp
->link_idx
== nifp
->nbmaifp
->ifindex
&&
148 (nifp
->link_vrf_id
== nifp
->nbmaifp
->vrf_id
)))
151 nifp
->link_idx
= nifp
->nbmaifp
->ifindex
;
152 nifp
->link_vrf_id
= nifp
->nbmaifp
->vrf_id
;
153 debugf(NHRP_DEBUG_IF
, "%s: bound device index changed to %d, vr %u",
154 ifp
->name
, nifp
->link_idx
, nifp
->link_vrf_id
);
155 nhrp_send_zebra_gre_source_set(ifp
, nifp
->link_idx
, nifp
->link_vrf_id
);
158 static void nhrp_interface_interface_notifier(struct notifier_block
*n
,
161 struct nhrp_interface
*nifp
=
162 container_of(n
, struct nhrp_interface
, nbmanifp_notifier
);
163 struct interface
*nbmaifp
= nifp
->nbmaifp
;
164 struct nhrp_interface
*nbmanifp
= nbmaifp
->info
;
167 case NOTIFY_INTERFACE_CHANGED
:
168 nhrp_interface_update_mtu(nifp
->ifp
, AFI_IP
);
169 nhrp_interface_update_source(nifp
->ifp
);
171 case NOTIFY_INTERFACE_ADDRESS_CHANGED
:
172 nifp
->nbma
= nbmanifp
->afi
[AFI_IP
].addr
;
173 nhrp_interface_update(nifp
->ifp
);
174 notifier_call(&nifp
->notifier_list
,
175 NOTIFY_INTERFACE_NBMA_CHANGED
);
176 debugf(NHRP_DEBUG_IF
, "%s: NBMA change: address %pSU",
177 nifp
->ifp
->name
, &nifp
->nbma
);
182 void nhrp_interface_update_nbma(struct interface
*ifp
,
183 struct nhrp_gre_info
*gre_info
)
185 struct nhrp_interface
*nifp
= ifp
->info
, *nbmanifp
= NULL
;
186 struct interface
*nbmaifp
= NULL
;
187 union sockunion nbma
;
189 sockunion_family(&nbma
) = AF_UNSPEC
;
192 nbmaifp
= if_lookup_by_name(nifp
->source
, nifp
->link_vrf_id
);
194 switch (ifp
->ll_type
) {
195 case ZEBRA_LLT_IPGRE
: {
196 struct in_addr saddr
= {0};
199 nhrp_send_zebra_gre_request(ifp
);
202 nifp
->i_grekey
= gre_info
->ikey
;
203 nifp
->o_grekey
= gre_info
->okey
;
204 nifp
->link_idx
= gre_info
->ifindex_link
;
205 nifp
->link_vrf_id
= gre_info
->vrfid_link
;
206 saddr
.s_addr
= gre_info
->vtep_ip
.s_addr
;
208 debugf(NHRP_DEBUG_IF
, "%s: GRE: %x %x %x", ifp
->name
,
209 nifp
->i_grekey
, nifp
->link_idx
, saddr
.s_addr
);
211 sockunion_set(&nbma
, AF_INET
,
212 (uint8_t *)&saddr
.s_addr
,
213 sizeof(saddr
.s_addr
));
214 else if (!nbmaifp
&& nifp
->link_idx
!= IFINDEX_INTERNAL
)
216 if_lookup_by_index(nifp
->link_idx
,
224 nbmanifp
= nbmaifp
->info
;
226 if (nbmaifp
!= nifp
->nbmaifp
) {
228 notifier_del(&nifp
->nbmanifp_notifier
);
229 nifp
->nbmaifp
= nbmaifp
;
231 notifier_add(&nifp
->nbmanifp_notifier
,
232 &nbmanifp
->notifier_list
,
233 nhrp_interface_interface_notifier
);
234 debugf(NHRP_DEBUG_IF
, "%s: bound to %s", ifp
->name
,
240 if (sockunion_family(&nbma
) == AF_UNSPEC
)
241 nbma
= nbmanifp
->afi
[AFI_IP
].addr
;
242 nhrp_interface_update_mtu(ifp
, AFI_IP
);
243 nhrp_interface_update_source(ifp
);
246 if (!sockunion_same(&nbma
, &nifp
->nbma
)) {
248 nhrp_interface_update(nifp
->ifp
);
249 debugf(NHRP_DEBUG_IF
, "%s: NBMA address changed", ifp
->name
);
250 notifier_call(&nifp
->notifier_list
,
251 NOTIFY_INTERFACE_NBMA_CHANGED
);
254 nhrp_interface_update(ifp
);
257 static void nhrp_interface_update_address(struct interface
*ifp
, afi_t afi
,
260 const int family
= afi2family(afi
);
261 struct nhrp_interface
*nifp
= ifp
->info
;
262 struct nhrp_afi_data
*if_ad
= &nifp
->afi
[afi
];
263 struct nhrp_cache
*nc
;
264 struct connected
*c
, *best
;
265 struct listnode
*cnode
;
266 union sockunion addr
;
267 char buf
[PREFIX_STRLEN
];
269 /* Select new best match preferring primary address */
271 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
272 if (PREFIX_FAMILY(c
->address
) != family
)
278 if ((best
->flags
& ZEBRA_IFA_SECONDARY
)
279 && !(c
->flags
& ZEBRA_IFA_SECONDARY
)) {
283 if (!(best
->flags
& ZEBRA_IFA_SECONDARY
)
284 && (c
->flags
& ZEBRA_IFA_SECONDARY
))
286 if (best
->address
->prefixlen
> c
->address
->prefixlen
) {
290 if (best
->address
->prefixlen
< c
->address
->prefixlen
)
294 /* On NHRP interfaces a host prefix is required */
295 if (best
&& if_ad
->configured
296 && best
->address
->prefixlen
!= 8 * prefix_blen(best
->address
)) {
297 zlog_notice("%s: %pFX is not a host prefix", ifp
->name
,
302 /* Update address if it changed */
304 prefix2sockunion(best
->address
, &addr
);
306 memset(&addr
, 0, sizeof(addr
));
308 if (!force
&& sockunion_same(&if_ad
->addr
, &addr
))
311 if (sockunion_family(&if_ad
->addr
) != AF_UNSPEC
) {
312 nc
= nhrp_cache_get(ifp
, &if_ad
->addr
, 0);
314 nhrp_cache_update_binding(nc
, NHRP_CACHE_LOCAL
, -1,
315 NULL
, 0, NULL
, NULL
);
318 debugf(NHRP_DEBUG_KERNEL
, "%s: IPv%d address changed to %s", ifp
->name
,
319 afi
== AFI_IP
? 4 : 6,
320 best
? prefix2str(best
->address
, buf
, sizeof(buf
)) : "(none)");
323 if (if_ad
->configured
&& sockunion_family(&if_ad
->addr
) != AF_UNSPEC
) {
324 nc
= nhrp_cache_get(ifp
, &addr
, 1);
326 nhrp_cache_update_binding(nc
, NHRP_CACHE_LOCAL
, 0, NULL
,
330 notifier_call(&nifp
->notifier_list
, NOTIFY_INTERFACE_ADDRESS_CHANGED
);
333 void nhrp_interface_update(struct interface
*ifp
)
335 struct nhrp_interface
*nifp
= ifp
->info
;
336 struct nhrp_afi_data
*if_ad
;
340 notifier_call(&nifp
->notifier_list
, NOTIFY_INTERFACE_CHANGED
);
342 for (afi
= 0; afi
< AFI_MAX
; afi
++) {
343 if_ad
= &nifp
->afi
[afi
];
345 if (sockunion_family(&nifp
->nbma
) == AF_UNSPEC
346 || ifp
->ifindex
== IFINDEX_INTERNAL
|| !if_is_up(ifp
)
347 || !if_ad
->network_id
) {
348 if (if_ad
->configured
) {
349 if_ad
->configured
= 0;
350 nhrp_interface_update_address(ifp
, afi
, 1);
355 if (!if_ad
->configured
) {
356 os_configure_dmvpn(ifp
->ifindex
, ifp
->name
,
358 nhrp_send_zebra_configure_arp(ifp
, afi2family(afi
));
359 if_ad
->configured
= 1;
360 nhrp_interface_update_address(ifp
, afi
, 1);
366 if (enabled
!= nifp
->enabled
) {
367 nifp
->enabled
= enabled
;
368 notifier_call(&nifp
->notifier_list
,
369 enabled
? NOTIFY_INTERFACE_UP
370 : NOTIFY_INTERFACE_DOWN
);
374 int nhrp_ifp_create(struct interface
*ifp
)
376 debugf(NHRP_DEBUG_IF
, "if-add: %s, ifindex: %u, hw_type: %d %s",
377 ifp
->name
, ifp
->ifindex
, ifp
->ll_type
,
378 if_link_type_str(ifp
->ll_type
));
380 nhrp_interface_update_nbma(ifp
, NULL
);
385 int nhrp_ifp_destroy(struct interface
*ifp
)
387 debugf(NHRP_DEBUG_IF
, "if-delete: %s", ifp
->name
);
389 nhrp_interface_update_cache_config(ifp
, false, AF_INET
);
390 nhrp_interface_update_cache_config(ifp
, false, AF_INET6
);
391 nhrp_interface_update(ifp
);
401 static void interface_config_update_nhrp_map(struct nhrp_cache_config
*cc
,
404 struct map_ctx
*ctx
= data
;
405 struct interface
*ifp
= cc
->ifp
;
406 struct nhrp_cache
*c
;
407 union sockunion nbma_addr
;
409 if (sockunion_family(&cc
->remote_addr
) != ctx
->family
)
412 /* gre layer not ready */
413 if (ifp
->vrf_id
== VRF_UNKNOWN
)
416 c
= nhrp_cache_get(ifp
, &cc
->remote_addr
, ctx
->enabled
? 1 : 0);
417 if (!c
&& !ctx
->enabled
)
423 nhrp_cache_update_binding(
425 nhrp_peer_get(ifp
, &nbma_addr
), 0, NULL
, NULL
);
434 if (cc
->type
== NHRP_CACHE_LOCAL
)
435 nhrp_cache_update_binding(c
, NHRP_CACHE_LOCAL
, 0, NULL
, 0,
438 nhrp_cache_update_binding(c
, NHRP_CACHE_STATIC
, 0,
439 nhrp_peer_get(ifp
, &cc
->nbma
), 0,
444 static void nhrp_interface_update_cache_config(struct interface
*ifp
, bool available
, uint8_t family
)
446 struct map_ctx mapctx
;
448 mapctx
= (struct map_ctx
){
452 nhrp_cache_config_foreach(ifp
, interface_config_update_nhrp_map
,
457 int nhrp_ifp_up(struct interface
*ifp
)
459 debugf(NHRP_DEBUG_IF
, "if-up: %s", ifp
->name
);
460 nhrp_interface_update_nbma(ifp
, NULL
);
465 int nhrp_ifp_down(struct interface
*ifp
)
467 debugf(NHRP_DEBUG_IF
, "if-down: %s", ifp
->name
);
468 nhrp_interface_update(ifp
);
473 int nhrp_interface_address_add(ZAPI_CALLBACK_ARGS
)
475 struct connected
*ifc
;
477 ifc
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
481 debugf(NHRP_DEBUG_IF
, "if-addr-add: %s: %pFX", ifc
->ifp
->name
,
484 nhrp_interface_update_address(
485 ifc
->ifp
, family2afi(PREFIX_FAMILY(ifc
->address
)), 0);
486 nhrp_interface_update_cache_config(ifc
->ifp
, true, PREFIX_FAMILY(ifc
->address
));
490 int nhrp_interface_address_delete(ZAPI_CALLBACK_ARGS
)
492 struct connected
*ifc
;
494 ifc
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
498 debugf(NHRP_DEBUG_IF
, "if-addr-del: %s: %pFX", ifc
->ifp
->name
,
501 nhrp_interface_update_address(
502 ifc
->ifp
, family2afi(PREFIX_FAMILY(ifc
->address
)), 0);
503 connected_free(&ifc
);
508 void nhrp_interface_notify_add(struct interface
*ifp
, struct notifier_block
*n
,
511 struct nhrp_interface
*nifp
= ifp
->info
;
512 notifier_add(n
, &nifp
->notifier_list
, fn
);
515 void nhrp_interface_notify_del(struct interface
*ifp
, struct notifier_block
*n
)
520 void nhrp_interface_set_protection(struct interface
*ifp
, const char *profile
,
521 const char *fallback_profile
)
523 struct nhrp_interface
*nifp
= ifp
->info
;
525 if (nifp
->ipsec_profile
) {
526 vici_terminate_vc_by_profile_name(nifp
->ipsec_profile
);
528 free(nifp
->ipsec_profile
);
530 nifp
->ipsec_profile
= profile
? strdup(profile
) : NULL
;
532 if (nifp
->ipsec_fallback_profile
) {
533 vici_terminate_vc_by_profile_name(nifp
->ipsec_fallback_profile
);
535 free(nifp
->ipsec_fallback_profile
);
537 nifp
->ipsec_fallback_profile
=
538 fallback_profile
? strdup(fallback_profile
) : NULL
;
540 notifier_call(&nifp
->notifier_list
, NOTIFY_INTERFACE_IPSEC_CHANGED
);
543 void nhrp_interface_set_source(struct interface
*ifp
, const char *ifname
)
545 struct nhrp_interface
*nifp
= ifp
->info
;
549 nifp
->source
= ifname
? strdup(ifname
) : NULL
;
551 nhrp_interface_update_nbma(ifp
, NULL
);