summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_carp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/ip_carp.c')
-rw-r--r--sys/netinet/ip_carp.c107
1 files changed, 57 insertions, 50 deletions
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index c5fea16..f85a322 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -115,7 +115,6 @@ struct carp_softc {
int sc_sendad_success;
#define CARP_SENDAD_MIN_SUCCESS 3
- int sc_init_counter;
uint64_t sc_counter;
/* authentication */
@@ -143,7 +142,7 @@ struct carp_if {
struct ip6_moptions cif_im6o;
#endif
struct ifnet *cif_ifp;
- struct mtx cif_mtx;
+ struct rwlock cif_mtx;
};
#define CARP_INET 0
@@ -247,18 +246,19 @@ SYSCTL_VNET_PCPUSTAT(_net_inet_carp, OID_AUTO, stats, struct carpstats,
#define CARP_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED)
#define CARP_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
#define CARP_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
-#define CIF_LOCK_INIT(cif) mtx_init(&(cif)->cif_mtx, "carp_if", \
- NULL, MTX_DEF)
-#define CIF_LOCK_DESTROY(cif) mtx_destroy(&(cif)->cif_mtx)
-#define CIF_LOCK_ASSERT(cif) mtx_assert(&(cif)->cif_mtx, MA_OWNED)
-#define CIF_LOCK(cif) mtx_lock(&(cif)->cif_mtx)
-#define CIF_UNLOCK(cif) mtx_unlock(&(cif)->cif_mtx)
+#define CIF_LOCK_INIT(cif) rw_init(&(cif)->cif_mtx, "carp_if")
+#define CIF_LOCK_DESTROY(cif) rw_destroy(&(cif)->cif_mtx)
+#define CIF_LOCK_ASSERT(cif) rw_assert(&(cif)->cif_mtx, MA_OWNED)
+#define CIF_RLOCK(cif) rw_rlock(&(cif)->cif_mtx)
+#define CIF_RUNLOCK(cif) rw_runlock(&(cif)->cif_mtx)
+#define CIF_WLOCK(cif) rw_wlock(&(cif)->cif_mtx)
+#define CIF_WUNLOCK(cif) rw_wunlock(&(cif)->cif_mtx)
#define CIF_FREE(cif) do { \
CIF_LOCK_ASSERT(cif); \
if (TAILQ_EMPTY(&(cif)->cif_vrs)) \
carp_free_if(cif); \
else \
- CIF_UNLOCK(cif); \
+ CIF_WUNLOCK(cif); \
} while (0)
#define CARP_LOG(...) do { \
@@ -579,7 +579,6 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
struct ifnet *ifp = m->m_pkthdr.rcvif;
struct ifaddr *ifa;
struct carp_softc *sc;
- uint64_t tmp_counter;
struct timeval sc_tv, ch_tv;
/* verify that the VHID is valid on the receiving interface */
@@ -619,14 +618,20 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
goto out;
}
- tmp_counter = ntohl(ch->carp_counter[0]);
- tmp_counter = tmp_counter<<32;
- tmp_counter += ntohl(ch->carp_counter[1]);
-
- /* XXX Replay protection goes here */
-
- sc->sc_init_counter = 0;
- sc->sc_counter = tmp_counter;
+ if (!bcmp(&sc->sc_counter, ch->carp_counter,
+ sizeof(ch->carp_counter))) {
+ /* Do not log duplicates from non simplex interfaces */
+ if (sc->sc_carpdev->if_flags & IFF_SIMPLEX) {
+ CARPSTATS_INC(carps_badauth);
+ ifp->if_ierrors++;
+ CARP_UNLOCK(sc);
+ CARP_LOG("%s, replay or network loop detected.\n",
+ ifp->if_xname);
+ } else
+ CARP_UNLOCK(sc);
+ m_freem(m);
+ return;
+ }
sc_tv.tv_sec = sc->sc_advbase;
sc_tv.tv_usec = DEMOTE_ADVSKEW(sc) * 1000000 / 256;
@@ -700,13 +705,12 @@ carp_prepare_ad(struct mbuf *m, struct carp_softc *sc, struct carp_header *ch)
{
struct m_tag *mtag;
- if (sc->sc_init_counter) {
+ if (!sc->sc_counter) {
/* this could also be seconds since unix epoch */
sc->sc_counter = arc4random();
sc->sc_counter = sc->sc_counter << 32;
sc->sc_counter += arc4random();
- } else
- sc->sc_counter++;
+ }
ch->carp_counter[0] = htonl((sc->sc_counter>>32)&0xffffffff);
ch->carp_counter[1] = htonl(sc->sc_counter&0xffffffff);
@@ -772,7 +776,8 @@ carp_send_ad_error(struct carp_softc *sc, int error)
char msg[sizeof(fmt) + IFNAMSIZ];
sprintf(msg, fmt, error, sc->sc_carpdev->if_xname);
- carp_demote_adj(V_carp_senderr_adj, msg);
+ if (V_carp_senderr_adj > 0)
+ carp_demote_adj(V_carp_senderr_adj, msg);
}
sc->sc_sendad_success = 0;
} else {
@@ -782,7 +787,8 @@ carp_send_ad_error(struct carp_softc *sc, int error)
char msg[sizeof(fmt) + IFNAMSIZ];
sprintf(msg, fmt, sc->sc_carpdev->if_xname);
- carp_demote_adj(-V_carp_senderr_adj, msg);
+ if (V_carp_senderr_adj > 0)
+ carp_demote_adj(-V_carp_senderr_adj, msg);
sc->sc_sendad_errors = 0;
} else
sc->sc_sendad_errors = 0;
@@ -1117,18 +1123,17 @@ carp_forus(struct ifnet *ifp, u_char *dhost)
if (ena[0] || ena[1] || ena[2] != 0x5e || ena[3] || ena[4] != 1)
return (0);
- CIF_LOCK(ifp->if_carp);
+ CIF_RLOCK(ifp->if_carp);
IFNET_FOREACH_CARP(ifp, sc) {
- CARP_LOCK(sc);
- if (sc->sc_state == MASTER && !bcmp(dhost, LLADDR(&sc->sc_addr),
- ETHER_ADDR_LEN)) {
- CARP_UNLOCK(sc);
- CIF_UNLOCK(ifp->if_carp);
+ //CARP_LOCK(sc);
+ if (sc->sc_state == MASTER && ena[5] == sc->sc_vhid) {
+ //CARP_UNLOCK(sc);
+ CIF_RUNLOCK(ifp->if_carp);
return (1);
}
- CARP_UNLOCK(sc);
+ //CARP_UNLOCK(sc);
}
- CIF_UNLOCK(ifp->if_carp);
+ CIF_RUNLOCK(ifp->if_carp);
return (0);
}
@@ -1485,9 +1490,9 @@ carp_alloc(struct ifnet *ifp)
sc = malloc(sizeof(*sc), M_CARP, M_WAITOK|M_ZERO);
+ sc->sc_counter = 0;
sc->sc_advbase = CARP_DFLTINTV;
sc->sc_vhid = -1; /* required setting */
- sc->sc_init_counter = 1;
sc->sc_state = INIT;
sc->sc_ifasiz = sizeof(struct ifaddr *);
@@ -1503,9 +1508,9 @@ carp_alloc(struct ifnet *ifp)
#endif
callout_init_mtx(&sc->sc_ad_tmo, &sc->sc_mtx, CALLOUT_RETURNUNLOCKED);
- CIF_LOCK(cif);
+ CIF_WLOCK(cif);
TAILQ_INSERT_TAIL(&cif->cif_vrs, sc, sc_list);
- CIF_UNLOCK(cif);
+ CIF_WUNLOCK(cif);
mtx_lock(&carp_mtx);
LIST_INSERT_HEAD(&carp_list, sc, sc_next);
@@ -1669,11 +1674,11 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
}
if (ifp->if_carp) {
- CIF_LOCK(ifp->if_carp);
+ CIF_RLOCK(ifp->if_carp);
IFNET_FOREACH_CARP(ifp, sc)
if (sc->sc_vhid == carpr.carpr_vhid)
break;
- CIF_UNLOCK(ifp->if_carp);
+ CIF_RUNLOCK(ifp->if_carp);
}
if (sc == NULL) {
sc = carp_alloc(ifp);
@@ -1747,11 +1752,11 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
priveleged = (priv_check(td, PRIV_NETINET_CARP) == 0);
if (carpr.carpr_vhid != 0) {
- CIF_LOCK(ifp->if_carp);
+ CIF_RLOCK(ifp->if_carp);
IFNET_FOREACH_CARP(ifp, sc)
if (sc->sc_vhid == carpr.carpr_vhid)
break;
- CIF_UNLOCK(ifp->if_carp);
+ CIF_RUNLOCK(ifp->if_carp);
if (sc == NULL) {
error = ENOENT;
break;
@@ -1762,12 +1767,12 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
int i, count;
count = 0;
- CIF_LOCK(ifp->if_carp);
+ CIF_RLOCK(ifp->if_carp);
IFNET_FOREACH_CARP(ifp, sc)
count++;
if (count > carpr.carpr_count) {
- CIF_UNLOCK(ifp->if_carp);
+ CIF_RUNLOCK(ifp->if_carp);
error = EMSGSIZE;
break;
}
@@ -1779,12 +1784,12 @@ carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
error = copyout(&carpr, ifr->ifr_data +
(i * sizeof(carpr)), sizeof(carpr));
if (error) {
- CIF_UNLOCK(ifp->if_carp);
+ CIF_RUNLOCK(ifp->if_carp);
break;
}
i++;
}
- CIF_UNLOCK(ifp->if_carp);
+ CIF_RUNLOCK(ifp->if_carp);
}
break;
}
@@ -1833,12 +1838,12 @@ carp_attach(struct ifaddr *ifa, int vhid)
return (EPROTOTYPE);
}
- CIF_LOCK(cif);
+ CIF_WLOCK(cif);
IFNET_FOREACH_CARP(ifp, sc)
if (sc->sc_vhid == vhid)
break;
if (sc == NULL) {
- CIF_UNLOCK(cif);
+ CIF_WUNLOCK(cif);
return (ENOENT);
}
@@ -1846,7 +1851,7 @@ carp_attach(struct ifaddr *ifa, int vhid)
if (ifa->ifa_carp->sc_vhid != vhid)
carp_detach_locked(ifa);
else {
- CIF_UNLOCK(cif);
+ CIF_WUNLOCK(cif);
return (0);
}
}
@@ -1891,7 +1896,7 @@ carp_attach(struct ifaddr *ifa, int vhid)
carp_sc_state(sc);
CARP_UNLOCK(sc);
- CIF_UNLOCK(cif);
+ CIF_WUNLOCK(cif);
return (0);
}
@@ -1902,7 +1907,7 @@ carp_detach(struct ifaddr *ifa)
struct ifnet *ifp = ifa->ifa_ifp;
struct carp_if *cif = ifp->if_carp;
- CIF_LOCK(cif);
+ CIF_WLOCK(cif);
carp_detach_locked(ifa);
CIF_FREE(cif);
}
@@ -1984,13 +1989,13 @@ carp_linkstate(struct ifnet *ifp)
{
struct carp_softc *sc;
- CIF_LOCK(ifp->if_carp);
+ CIF_RLOCK(ifp->if_carp);
IFNET_FOREACH_CARP(ifp, sc) {
CARP_LOCK(sc);
carp_sc_state(sc);
CARP_UNLOCK(sc);
}
- CIF_UNLOCK(ifp->if_carp);
+ CIF_RUNLOCK(ifp->if_carp);
}
static void
@@ -2025,9 +2030,11 @@ carp_sc_state(struct carp_softc *sc)
static void
carp_demote_adj(int adj, char *reason)
{
+ if (adj == 0)
+ return;
atomic_add_int(&V_carp_demotion, adj);
CARP_LOG("demoted by %d to %d (%s)\n", adj, V_carp_demotion, reason);
- taskqueue_enqueue(taskqueue_swi, &carp_sendall_task);
+ taskqueue_enqueue(taskqueue_thread, &carp_sendall_task);
}
static int
OpenPOWER on IntegriCloud