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.
10 #include <net/if_arp.h>
20 DEFINE_MTYPE_STATIC(NHRPD
, NHRP_IF
, "NHRP interface")
22 static int nhrp_if_new_hook(struct interface
*ifp
)
24 struct nhrp_interface
*nifp
;
27 nifp
= XCALLOC(MTYPE_NHRP_IF
, sizeof(struct nhrp_interface
));
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
);
43 static int nhrp_if_delete_hook(struct interface
*ifp
)
45 XFREE(MTYPE_NHRP_IF
, ifp
->info
);
49 void nhrp_interface_init(void)
51 hook_register_prio(if_add
, 0, nhrp_if_new_hook
);
52 hook_register_prio(if_del
, 0, nhrp_if_delete_hook
);
55 void nhrp_interface_update_mtu(struct interface
*ifp
, afi_t afi
)
57 struct nhrp_interface
*nifp
= ifp
->info
;
58 struct nhrp_afi_data
*if_ad
= &nifp
->afi
[afi
];
59 unsigned short new_mtu
;
61 if (if_ad
->configured_mtu
< 0)
62 new_mtu
= nifp
->nbmaifp
? nifp
->nbmaifp
->mtu
: 0;
64 new_mtu
= if_ad
->configured_mtu
;
68 if (new_mtu
!= if_ad
->mtu
) {
69 debugf(NHRP_DEBUG_IF
, "%s: MTU changed to %d", ifp
->name
, new_mtu
);
71 notifier_call(&nifp
->notifier_list
, NOTIFY_INTERFACE_MTU_CHANGED
);
75 static void nhrp_interface_update_source(struct interface
*ifp
)
77 struct nhrp_interface
*nifp
= ifp
->info
;
79 if (!nifp
->source
|| !nifp
->nbmaifp
||
80 (ifindex_t
)nifp
->linkidx
== nifp
->nbmaifp
->ifindex
)
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
);
88 static void nhrp_interface_interface_notifier(struct notifier_block
*n
, unsigned long cmd
)
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
];
96 case NOTIFY_INTERFACE_CHANGED
:
97 nhrp_interface_update_mtu(nifp
->ifp
, AFI_IP
);
98 nhrp_interface_update_source(nifp
->ifp
);
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",
106 sockunion2str(&nifp
->nbma
, buf
, sizeof buf
));
111 static void nhrp_interface_update_nbma(struct interface
*ifp
)
113 struct nhrp_interface
*nifp
= ifp
->info
, *nbmanifp
= NULL
;
114 struct interface
*nbmaifp
= NULL
;
115 union sockunion nbma
;
117 sockunion_family(&nbma
) = AF_UNSPEC
;
120 nbmaifp
= if_lookup_by_name(nifp
->source
, VRF_DEFAULT
);
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
);
128 sockunion_set(&nbma
, AF_INET
, (u_char
*) &saddr
.s_addr
, sizeof(saddr
.s_addr
));
129 else if (!nbmaifp
&& nifp
->linkidx
!= IFINDEX_INTERNAL
)
130 nbmaifp
= if_lookup_by_index(nifp
->linkidx
, VRF_DEFAULT
);
138 nbmanifp
= nbmaifp
->info
;
140 if (nbmaifp
!= nifp
->nbmaifp
) {
142 notifier_del(&nifp
->nbmanifp_notifier
);
143 nifp
->nbmaifp
= 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
);
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
);
157 if (!sockunion_same(&nbma
, &nifp
->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
);
164 nhrp_interface_update(ifp
);
167 static void nhrp_interface_update_address(struct interface
*ifp
, afi_t afi
, int force
)
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
];
178 /* Select new best match preferring primary address */
180 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
181 if (PREFIX_FAMILY(c
->address
) != family
)
187 if ((best
->flags
& ZEBRA_IFA_SECONDARY
) && !(c
->flags
& ZEBRA_IFA_SECONDARY
)) {
191 if (!(best
->flags
& ZEBRA_IFA_SECONDARY
) && (c
->flags
& ZEBRA_IFA_SECONDARY
))
193 if (best
->address
->prefixlen
> c
->address
->prefixlen
) {
197 if (best
->address
->prefixlen
< c
->address
->prefixlen
)
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
));
208 /* Update address if it changed */
210 prefix2sockunion(best
->address
, &addr
);
212 memset(&addr
, 0, sizeof(addr
));
214 if (!force
&& sockunion_same(&if_ad
->addr
, &addr
))
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
);
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)");
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
);
232 notifier_call(&nifp
->notifier_list
, NOTIFY_INTERFACE_ADDRESS_CHANGED
);
235 void nhrp_interface_update(struct interface
*ifp
)
237 struct nhrp_interface
*nifp
= ifp
->info
;
238 struct nhrp_afi_data
*if_ad
;
242 notifier_call(&nifp
->notifier_list
, NOTIFY_INTERFACE_CHANGED
);
244 for (afi
= 0; afi
< AFI_MAX
; afi
++) {
245 if_ad
= &nifp
->afi
[afi
];
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);
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);
266 if (enabled
!= nifp
->enabled
) {
267 nifp
->enabled
= enabled
;
268 notifier_call(&nifp
->notifier_list
, enabled
? NOTIFY_INTERFACE_UP
: NOTIFY_INTERFACE_DOWN
);
272 int nhrp_interface_add(int cmd
, struct zclient
*client
, zebra_size_t length
, vrf_id_t vrf_id
)
274 struct interface
*ifp
;
276 /* read and add the interface in the iflist. */
277 ifp
= zebra_interface_add_read(client
->ibuf
, vrf_id
);
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
));
285 nhrp_interface_update_nbma(ifp
);
290 int nhrp_interface_delete(int cmd
, struct zclient
*client
,
291 zebra_size_t length
, vrf_id_t vrf_id
)
293 struct interface
*ifp
;
297 ifp
= zebra_interface_state_read(s
, vrf_id
);
301 debugf(NHRP_DEBUG_IF
, "if-delete: %s", ifp
->name
);
302 if_set_index(ifp
, ifp
->ifindex
);
303 nhrp_interface_update(ifp
);
304 /* if_delete(ifp); */
308 int nhrp_interface_up(int cmd
, struct zclient
*client
,
309 zebra_size_t length
, vrf_id_t vrf_id
)
311 struct interface
*ifp
;
313 ifp
= zebra_interface_state_read(client
->ibuf
, vrf_id
);
317 debugf(NHRP_DEBUG_IF
, "if-up: %s", ifp
->name
);
318 nhrp_interface_update_nbma(ifp
);
323 int nhrp_interface_down(int cmd
, struct zclient
*client
,
324 zebra_size_t length
, vrf_id_t vrf_id
)
326 struct interface
*ifp
;
328 ifp
= zebra_interface_state_read(client
->ibuf
, vrf_id
);
332 debugf(NHRP_DEBUG_IF
, "if-down: %s", ifp
->name
);
333 nhrp_interface_update(ifp
);
337 int nhrp_interface_address_add(int cmd
, struct zclient
*client
,
338 zebra_size_t length
, vrf_id_t vrf_id
)
340 struct connected
*ifc
;
341 char buf
[PREFIX_STRLEN
];
343 ifc
= zebra_interface_address_read(cmd
, client
->ibuf
, vrf_id
);
347 debugf(NHRP_DEBUG_IF
, "if-addr-add: %s: %s",
349 prefix2str(ifc
->address
, buf
, sizeof buf
));
351 nhrp_interface_update_address(ifc
->ifp
, family2afi(PREFIX_FAMILY(ifc
->address
)), 0);
356 int nhrp_interface_address_delete(int cmd
, struct zclient
*client
,
357 zebra_size_t length
, vrf_id_t vrf_id
)
359 struct connected
*ifc
;
360 char buf
[PREFIX_STRLEN
];
362 ifc
= zebra_interface_address_read(cmd
, client
->ibuf
, vrf_id
);
366 debugf(NHRP_DEBUG_IF
, "if-addr-del: %s: %s",
368 prefix2str(ifc
->address
, buf
, sizeof buf
));
370 nhrp_interface_update_address(ifc
->ifp
, family2afi(PREFIX_FAMILY(ifc
->address
)), 0);
376 void nhrp_interface_notify_add(struct interface
*ifp
, struct notifier_block
*n
, notifier_fn_t fn
)
378 struct nhrp_interface
*nifp
= ifp
->info
;
379 notifier_add(n
, &nifp
->notifier_list
, fn
);
382 void nhrp_interface_notify_del(struct interface
*ifp
, struct notifier_block
*n
)
387 void nhrp_interface_set_protection(struct interface
*ifp
, const char *profile
, const char *fallback_profile
)
389 struct nhrp_interface
*nifp
= ifp
->info
;
391 if (nifp
->ipsec_profile
) free(nifp
->ipsec_profile
);
392 nifp
->ipsec_profile
= profile
? strdup(profile
) : NULL
;
394 if (nifp
->ipsec_fallback_profile
) free(nifp
->ipsec_fallback_profile
);
395 nifp
->ipsec_fallback_profile
= fallback_profile
? strdup(fallback_profile
) : NULL
;
397 notifier_call(&nifp
->notifier_list
, NOTIFY_INTERFACE_ADDRESS_CHANGED
);
400 void nhrp_interface_set_source(struct interface
*ifp
, const char *ifname
)
402 struct nhrp_interface
*nifp
= ifp
->info
;
404 if (nifp
->source
) free(nifp
->source
);
405 nifp
->source
= ifname
? strdup(ifname
) : NULL
;
407 nhrp_interface_update_nbma(ifp
);