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 int nhrp_if_new_hook(struct interface
*ifp
)
28 struct nhrp_interface
*nifp
;
31 nifp
= XCALLOC(MTYPE_NHRP_IF
, sizeof(struct nhrp_interface
));
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
);
46 static int nhrp_if_delete_hook(struct interface
*ifp
)
48 XFREE(MTYPE_NHRP_IF
, ifp
->info
);
52 void nhrp_interface_init(void)
54 hook_register_prio(if_add
, 0, nhrp_if_new_hook
);
55 hook_register_prio(if_del
, 0, nhrp_if_delete_hook
);
58 void nhrp_interface_update_mtu(struct interface
*ifp
, afi_t afi
)
60 struct nhrp_interface
*nifp
= ifp
->info
;
61 struct nhrp_afi_data
*if_ad
= &nifp
->afi
[afi
];
62 unsigned short new_mtu
;
64 if (if_ad
->configured_mtu
< 0)
65 new_mtu
= nifp
->nbmaifp
? nifp
->nbmaifp
->mtu
: 0;
67 new_mtu
= if_ad
->configured_mtu
;
71 if (new_mtu
!= if_ad
->mtu
) {
72 debugf(NHRP_DEBUG_IF
, "%s: MTU changed to %d", ifp
->name
,
75 notifier_call(&nifp
->notifier_list
,
76 NOTIFY_INTERFACE_MTU_CHANGED
);
80 static void nhrp_interface_update_source(struct interface
*ifp
)
82 struct nhrp_interface
*nifp
= ifp
->info
;
84 if (!nifp
->source
|| !nifp
->nbmaifp
85 || (ifindex_t
)nifp
->linkidx
== nifp
->nbmaifp
->ifindex
)
88 nifp
->linkidx
= nifp
->nbmaifp
->ifindex
;
89 debugf(NHRP_DEBUG_IF
, "%s: bound device index changed to %d", ifp
->name
,
91 netlink_gre_set_link(ifp
->ifindex
, nifp
->linkidx
);
94 static void nhrp_interface_interface_notifier(struct notifier_block
*n
,
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
];
104 case NOTIFY_INTERFACE_CHANGED
:
105 nhrp_interface_update_mtu(nifp
->ifp
, AFI_IP
);
106 nhrp_interface_update_source(nifp
->ifp
);
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",
115 sockunion2str(&nifp
->nbma
, buf
, sizeof buf
));
120 static void nhrp_interface_update_nbma(struct interface
*ifp
)
122 struct nhrp_interface
*nifp
= ifp
->info
, *nbmanifp
= NULL
;
123 struct interface
*nbmaifp
= NULL
;
124 union sockunion nbma
;
126 sockunion_family(&nbma
) = AF_UNSPEC
;
129 nbmaifp
= if_lookup_by_name(nifp
->source
, VRF_DEFAULT
);
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
!= INADDR_ANY
)
139 sockunion_set(&nbma
, AF_INET
, (uint8_t *)&saddr
.s_addr
,
140 sizeof(saddr
.s_addr
));
141 else if (!nbmaifp
&& nifp
->linkidx
!= IFINDEX_INTERNAL
)
143 if_lookup_by_index(nifp
->linkidx
, VRF_DEFAULT
);
150 nbmanifp
= nbmaifp
->info
;
152 if (nbmaifp
!= nifp
->nbmaifp
) {
154 notifier_del(&nifp
->nbmanifp_notifier
);
155 nifp
->nbmaifp
= 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
,
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
);
172 if (!sockunion_same(&nbma
, &nifp
->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
);
180 nhrp_interface_update(ifp
);
183 static void nhrp_interface_update_address(struct interface
*ifp
, afi_t afi
,
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
];
195 /* Select new best match preferring primary address */
197 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, cnode
, c
)) {
198 if (PREFIX_FAMILY(c
->address
) != family
)
204 if ((best
->flags
& ZEBRA_IFA_SECONDARY
)
205 && !(c
->flags
& ZEBRA_IFA_SECONDARY
)) {
209 if (!(best
->flags
& ZEBRA_IFA_SECONDARY
)
210 && (c
->flags
& ZEBRA_IFA_SECONDARY
))
212 if (best
->address
->prefixlen
> c
->address
->prefixlen
) {
216 if (best
->address
->prefixlen
< c
->address
->prefixlen
)
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
));
228 /* Update address if it changed */
230 prefix2sockunion(best
->address
, &addr
);
232 memset(&addr
, 0, sizeof(addr
));
234 if (!force
&& sockunion_same(&if_ad
->addr
, &addr
))
237 if (sockunion_family(&if_ad
->addr
) != AF_UNSPEC
) {
238 nc
= nhrp_cache_get(ifp
, &if_ad
->addr
, 0);
240 nhrp_cache_update_binding(nc
, NHRP_CACHE_LOCAL
, -1,
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)");
249 if (if_ad
->configured
&& sockunion_family(&if_ad
->addr
) != AF_UNSPEC
) {
250 nc
= nhrp_cache_get(ifp
, &addr
, 1);
252 nhrp_cache_update_binding(nc
, NHRP_CACHE_LOCAL
, 0, NULL
,
256 notifier_call(&nifp
->notifier_list
, NOTIFY_INTERFACE_ADDRESS_CHANGED
);
259 void nhrp_interface_update(struct interface
*ifp
)
261 struct nhrp_interface
*nifp
= ifp
->info
;
262 struct nhrp_afi_data
*if_ad
;
266 notifier_call(&nifp
->notifier_list
, NOTIFY_INTERFACE_CHANGED
);
268 for (afi
= 0; afi
< AFI_MAX
; afi
++) {
269 if_ad
= &nifp
->afi
[afi
];
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);
281 if (!if_ad
->configured
) {
282 os_configure_dmvpn(ifp
->ifindex
, ifp
->name
,
284 if_ad
->configured
= 1;
285 nhrp_interface_update_address(ifp
, afi
, 1);
291 if (enabled
!= nifp
->enabled
) {
292 nifp
->enabled
= enabled
;
293 notifier_call(&nifp
->notifier_list
,
294 enabled
? NOTIFY_INTERFACE_UP
295 : NOTIFY_INTERFACE_DOWN
);
299 int nhrp_ifp_create(struct interface
*ifp
)
301 debugf(NHRP_DEBUG_IF
, "if-add: %s, ifindex: %u, hw_type: %d %s",
302 ifp
->name
, ifp
->ifindex
, ifp
->ll_type
,
303 if_link_type_str(ifp
->ll_type
));
305 nhrp_interface_update_nbma(ifp
);
310 int nhrp_ifp_destroy(struct interface
*ifp
)
312 debugf(NHRP_DEBUG_IF
, "if-delete: %s", ifp
->name
);
314 nhrp_interface_update(ifp
);
319 int nhrp_ifp_up(struct interface
*ifp
)
321 debugf(NHRP_DEBUG_IF
, "if-up: %s", ifp
->name
);
322 nhrp_interface_update_nbma(ifp
);
327 int nhrp_ifp_down(struct interface
*ifp
)
329 debugf(NHRP_DEBUG_IF
, "if-down: %s", ifp
->name
);
330 nhrp_interface_update(ifp
);
335 int nhrp_interface_address_add(ZAPI_CALLBACK_ARGS
)
337 struct connected
*ifc
;
338 char buf
[PREFIX_STRLEN
];
340 ifc
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
344 debugf(NHRP_DEBUG_IF
, "if-addr-add: %s: %s", ifc
->ifp
->name
,
345 prefix2str(ifc
->address
, buf
, sizeof buf
));
347 nhrp_interface_update_address(
348 ifc
->ifp
, family2afi(PREFIX_FAMILY(ifc
->address
)), 0);
353 int nhrp_interface_address_delete(ZAPI_CALLBACK_ARGS
)
355 struct connected
*ifc
;
356 char buf
[PREFIX_STRLEN
];
358 ifc
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
362 debugf(NHRP_DEBUG_IF
, "if-addr-del: %s: %s", ifc
->ifp
->name
,
363 prefix2str(ifc
->address
, buf
, sizeof buf
));
365 nhrp_interface_update_address(
366 ifc
->ifp
, family2afi(PREFIX_FAMILY(ifc
->address
)), 0);
367 connected_free(&ifc
);
372 void nhrp_interface_notify_add(struct interface
*ifp
, struct notifier_block
*n
,
375 struct nhrp_interface
*nifp
= ifp
->info
;
376 notifier_add(n
, &nifp
->notifier_list
, fn
);
379 void nhrp_interface_notify_del(struct interface
*ifp
, struct notifier_block
*n
)
384 void nhrp_interface_set_protection(struct interface
*ifp
, const char *profile
,
385 const char *fallback_profile
)
387 struct nhrp_interface
*nifp
= ifp
->info
;
389 if (nifp
->ipsec_profile
)
390 free(nifp
->ipsec_profile
);
391 nifp
->ipsec_profile
= profile
? strdup(profile
) : NULL
;
393 if (nifp
->ipsec_fallback_profile
)
394 free(nifp
->ipsec_fallback_profile
);
395 nifp
->ipsec_fallback_profile
=
396 fallback_profile
? strdup(fallback_profile
) : NULL
;
398 notifier_call(&nifp
->notifier_list
, NOTIFY_INTERFACE_ADDRESS_CHANGED
);
401 void nhrp_interface_set_source(struct interface
*ifp
, const char *ifname
)
403 struct nhrp_interface
*nifp
= ifp
->info
;
407 nifp
->source
= ifname
? strdup(ifname
) : NULL
;
409 nhrp_interface_update_nbma(ifp
);