summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuiz Otavio O Souza <luiz@netgate.com>2016-12-20 09:18:17 -0600
committerLuiz Souza <luiz@netgate.com>2017-07-17 20:56:05 -0500
commitded5357984b1ce3d00b141005e695e1113a1169b (patch)
treed57505a94e90169c146219a93b160da80b71db54
parent233f97b8df53e8ade7e9e05116ffd5357b8eaca0 (diff)
downloadFreeBSD-src-ded5357984b1ce3d00b141005e695e1113a1169b.zip
FreeBSD-src-ded5357984b1ce3d00b141005e695e1113a1169b.tar.gz
Fix a bug where existing CARP alias addresses cannot be changed.
When a existent address is delete with carp_detach() if it is the last address for that CARP vhid, the CARP vhid will be destroyed and the subsequent carp_attach() to add the new IP will fail. Ticket #6892 (cherry picked from commit 77805aa5fa51dbd2ed0b6c363c6235c892caee76)
-rw-r--r--sys/net/if.c2
-rw-r--r--sys/netinet/in.c13
-rw-r--r--sys/netinet/ip_carp.c7
-rw-r--r--sys/netinet/ip_carp.h4
-rw-r--r--sys/netinet6/in6.c4
5 files changed, 16 insertions, 14 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 85fe24e..6e897d0 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -144,7 +144,7 @@ int (*carp_output_p)(struct ifnet *ifp, struct mbuf *m,
const struct sockaddr *sa);
int (*carp_ioctl_p)(struct ifreq *, u_long, struct thread *);
int (*carp_attach_p)(struct ifaddr *, int);
-void (*carp_detach_p)(struct ifaddr *);
+void (*carp_detach_p)(struct ifaddr *, bool);
#endif
#ifdef INET
int (*carp_iamatch_p)(struct ifaddr *, uint8_t **);
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index f42375b..4e4108f 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -71,7 +71,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/udp_var.h>
static int in_aifaddr_ioctl(u_long, caddr_t, struct ifnet *, struct thread *);
-static int in_difaddr_ioctl(caddr_t, struct ifnet *, struct thread *);
+static int in_difaddr_ioctl(u_long, caddr_t, struct ifnet *, struct thread *);
static void in_socktrim(struct sockaddr_in *);
static void in_purgemaddrs(struct ifnet *);
@@ -245,7 +245,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
break;
case SIOCDIFADDR:
sx_xlock(&in_control_sx);
- error = in_difaddr_ioctl(data, ifp, td);
+ error = in_difaddr_ioctl(cmd, data, ifp, td);
sx_xunlock(&in_control_sx);
return (error);
case OSIOCAIFADDR: /* 9.x compat */
@@ -390,7 +390,7 @@ in_aifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td)
IF_ADDR_RUNLOCK(ifp);
if (ia != NULL)
- (void )in_difaddr_ioctl(data, ifp, td);
+ (void )in_difaddr_ioctl(cmd, data, ifp, td);
ifa = ifa_alloc(sizeof(struct in_ifaddr), M_WAITOK);
ia = (struct in_ifaddr *)ifa;
@@ -528,7 +528,7 @@ fail2:
fail1:
if (ia->ia_ifa.ifa_carp)
- (*carp_detach_p)(&ia->ia_ifa);
+ (*carp_detach_p)(&ia->ia_ifa, true);
IF_ADDR_WLOCK(ifp);
TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
@@ -545,7 +545,7 @@ fail1:
}
static int
-in_difaddr_ioctl(caddr_t data, struct ifnet *ifp, struct thread *td)
+in_difaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td)
{
const struct ifreq *ifr = (struct ifreq *)data;
const struct sockaddr_in *addr = (const struct sockaddr_in *)
@@ -618,7 +618,8 @@ in_difaddr_ioctl(caddr_t data, struct ifnet *ifp, struct thread *td)
in_ifadown(&ia->ia_ifa, 1);
if (ia->ia_ifa.ifa_carp)
- (*carp_detach_p)(&ia->ia_ifa);
+ (*carp_detach_p)(&ia->ia_ifa,
+ (cmd == SIOCDIFADDR) ? true : false);
/*
* If this is the last IPv4 address configured on this
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index b6af698..86e6a10 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -1880,7 +1880,7 @@ carp_attach(struct ifaddr *ifa, int vhid)
}
void
-carp_detach(struct ifaddr *ifa)
+carp_detach(struct ifaddr *ifa, bool destroy)
{
struct ifnet *ifp = ifa->ifa_ifp;
struct carp_if *cif = ifp->if_carp;
@@ -1926,12 +1926,13 @@ carp_detach(struct ifaddr *ifa)
carp_hmac_prepare(sc);
carp_sc_state(sc);
- if (sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0)
+ if (destroy && sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0)
carp_destroy(sc);
else
CARP_UNLOCK(sc);
- CIF_FREE(cif);
+ if (destroy)
+ CIF_FREE(cif);
sx_xunlock(&carp_sx);
}
diff --git a/sys/netinet/ip_carp.h b/sys/netinet/ip_carp.h
index 5b7e506..9c6edf6 100644
--- a/sys/netinet/ip_carp.h
+++ b/sys/netinet/ip_carp.h
@@ -138,7 +138,7 @@ struct carpreq {
#ifdef _KERNEL
int carp_ioctl(struct ifreq *, u_long, struct thread *);
int carp_attach(struct ifaddr *, int);
-void carp_detach(struct ifaddr *);
+void carp_detach(struct ifaddr *, bool);
void carp_carpdev_state(struct ifnet *);
int carp_input(struct mbuf **, int *, int);
int carp6_input (struct mbuf **, int *, int);
@@ -154,7 +154,7 @@ int carp_forus(struct ifnet *, u_char *);
/* net/if.c */
extern int (*carp_ioctl_p)(struct ifreq *, u_long, struct thread *);
extern int (*carp_attach_p)(struct ifaddr *, int);
-extern void (*carp_detach_p)(struct ifaddr *);
+extern void (*carp_detach_p)(struct ifaddr *, bool);
extern void (*carp_linkstate_p)(struct ifnet *);
extern void (*carp_demote_adj_p)(int, char *);
extern int (*carp_master_p)(struct ifaddr *);
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 4df3564..d473995 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -624,7 +624,7 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
*/
if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) {
if (carp_attached)
- (*carp_detach_p)(&ia->ia_ifa);
+ (*carp_detach_p)(&ia->ia_ifa, false);
goto out;
}
}
@@ -1245,7 +1245,7 @@ in6_purgeaddr(struct ifaddr *ifa)
int plen, error;
if (ifa->ifa_carp)
- (*carp_detach_p)(ifa);
+ (*carp_detach_p)(ifa, true);
/*
* Remove the loopback route to the interface address.
OpenPOWER on IntegriCloud