summaryrefslogtreecommitdiffstats
path: root/sys/contrib/pf/net/if_pfsync.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/pf/net/if_pfsync.c')
-rw-r--r--sys/contrib/pf/net/if_pfsync.c1010
1 files changed, 681 insertions, 329 deletions
diff --git a/sys/contrib/pf/net/if_pfsync.c b/sys/contrib/pf/net/if_pfsync.c
index 0f5c344..ea09731 100644
--- a/sys/contrib/pf/net/if_pfsync.c
+++ b/sys/contrib/pf/net/if_pfsync.c
@@ -1,5 +1,4 @@
-/* $FreeBSD$ */
-/* $OpenBSD: if_pfsync.c,v 1.46 2005/02/20 15:58:38 mcbride Exp $ */
+/* $OpenBSD: if_pfsync.c,v 1.73 2006/11/16 13:13:38 henning Exp $ */
/*
* Copyright (c) 2002 Michael Shalayeff
@@ -30,15 +29,13 @@
#ifdef __FreeBSD__
#include "opt_inet.h"
#include "opt_inet6.h"
-#endif
-
-#ifndef __FreeBSD__
-#include "bpfilter.h"
-#include "pfsync.h"
-#elif __FreeBSD__ >= 5
+#include "opt_carp.h"
#include "opt_bpf.h"
#include "opt_pf.h"
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#ifdef DEV_BPF
#define NBPFILTER DEV_BPF
#else
@@ -51,7 +48,12 @@
#define NPFSYNC 0
#endif
+#ifdef DEV_CARP
+#define NCARP DEV_CARP
+#else
+#define NCARP 0
#endif
+#endif /* __FreeBSD__ */
#include <sys/param.h>
#ifdef __FreeBSD__
@@ -62,12 +64,12 @@
#include <sys/time.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
-#include <sys/kernel.h>
#ifdef __FreeBSD__
#include <sys/endian.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/sockio.h>
+#include <sys/taskqueue.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
@@ -75,19 +77,21 @@
#include <sys/ioctl.h>
#include <sys/timeout.h>
#endif
+#include <sys/kernel.h>
#include <net/if.h>
-#if defined(__FreeBSD__)
+#ifdef __FreeBSD__
#include <net/if_clone.h>
#endif
#include <net/if_types.h>
#include <net/route.h>
#include <net/bpf.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
#include <netinet/tcp.h>
#include <netinet/tcp_seq.h>
#ifdef INET
-#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
@@ -95,31 +99,22 @@
#endif
#ifdef INET6
-#ifndef INET
-#include <netinet/in.h>
-#endif
#include <netinet6/nd6.h>
#endif /* INET6 */
-#ifdef __FreeBSD__
-#include "opt_carp.h"
-#ifdef DEV_CARP
-#define NCARP 1
-#else
-#define NCARP 0
-#endif
-#else
+#ifndef __FreeBSD__
#include "carp.h"
#endif
#if NCARP > 0
-extern int carp_suppress_preempt;
+#include <netinet/ip_carp.h>
#endif
#include <net/pfvar.h>
#include <net/if_pfsync.h>
-#ifdef __FreeBSD__
-#define PFSYNCNAME "pfsync"
+#ifndef __FreeBSD__
+#include "bpfilter.h"
+#include "pfsync.h"
#endif
#define PFSYNC_MINMTU \
@@ -132,32 +127,30 @@ int pfsyncdebug;
#define DPRINTF(x)
#endif
-#ifndef __FreeBSD__
-struct pfsync_softc pfsyncif;
-#endif
-struct pfsyncstats pfsyncstats;
+struct pfsync_softc *pfsyncif = NULL;
+struct pfsyncstats pfsyncstats;
#ifdef __FreeBSD__
SYSCTL_DECL(_net_inet_pfsync);
SYSCTL_STRUCT(_net_inet_pfsync, 0, stats, CTLFLAG_RW,
&pfsyncstats, pfsyncstats,
"PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)");
+#endif
-/*
- * Locking notes:
- * Whenever we really touch/look at the state table we have to hold the
- * PF_LOCK. Functions that do just the interface handling, grab the per
- * softc lock instead.
- *
- */
-
-static void pfsync_clone_destroy(struct ifnet *);
-static int pfsync_clone_create(struct if_clone *, int, caddr_t params);
-static void pfsync_senddef(void *);
-#else
void pfsyncattach(int);
+#ifdef __FreeBSD__
+int pfsync_clone_create(struct if_clone *, int, caddr_t);
+void pfsync_clone_destroy(struct ifnet *);
+#else
+int pfsync_clone_create(struct if_clone *, int);
+int pfsync_clone_destroy(struct ifnet *);
#endif
void pfsync_setmtu(struct pfsync_softc *, int);
-int pfsync_insert_net_state(struct pfsync_state *);
+int pfsync_alloc_scrub_memory(struct pfsync_state_peer *,
+ struct pf_state_peer *);
+int pfsync_insert_net_state(struct pfsync_state *, u_int8_t);
+#ifdef PFSYNC_TDB
+void pfsync_update_net_tdb(struct pfsync_tdb *);
+#endif
int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
int pfsyncioctl(struct ifnet *, u_long, caddr_t);
@@ -166,160 +159,193 @@ void pfsyncstart(struct ifnet *);
struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **);
int pfsync_request_update(struct pfsync_state_upd *, struct in_addr *);
int pfsync_sendout(struct pfsync_softc *);
+#ifdef PFSYNC_TDB
+int pfsync_tdb_sendout(struct pfsync_softc *);
+#endif
+int pfsync_sendout_mbuf(struct pfsync_softc *, struct mbuf *);
void pfsync_timeout(void *);
+#ifdef PFSYNC_TDB
+void pfsync_tdb_timeout(void *);
+#endif
void pfsync_send_bus(struct pfsync_softc *, u_int8_t);
void pfsync_bulk_update(void *);
void pfsync_bulkfail(void *);
+
#ifdef __FreeBSD__
-static void pfsync_ifdetach(void *, struct ifnet *);
+void pfsync_ifdetach(void *, struct ifnet *);
+void pfsync_senddef(void *, int);
+
+/* XXX: ugly */
+#define betoh64 (unsigned long long)be64toh
+#define timeout_del callout_stop
#endif
int pfsync_sync_ok;
#ifndef __FreeBSD__
extern int ifqmaxlen;
-extern struct timeval time;
-extern struct timeval mono_time;
-extern int hz;
#endif
#ifdef __FreeBSD__
-static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
-static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
-#define SCP2IFP(sc) ((sc)->sc_ifp)
IFC_SIMPLE_DECLARE(pfsync, 1);
-
-static void
-pfsync_clone_destroy(struct ifnet *ifp)
-{
- struct pfsync_softc *sc;
-
- sc = ifp->if_softc;
-#ifdef __FreeBSD__
- EVENTHANDLER_DEREGISTER(ifnet_departure_event, sc->sc_detachtag);
+#else
+struct if_clone pfsync_cloner =
+ IF_CLONE_INITIALIZER("pfsync", pfsync_clone_create, pfsync_clone_destroy);
#endif
- callout_stop(&sc->sc_tmo);
- callout_stop(&sc->sc_bulk_tmo);
- callout_stop(&sc->sc_bulkfail_tmo);
-
- callout_stop(&sc->sc_send_tmo);
-#if NBPFILTER > 0
- bpfdetach(ifp);
-#endif
- if_detach(ifp);
- if_free(ifp);
- LIST_REMOVE(sc, sc_next);
- free(sc->sc_imo.imo_membership, M_PFSYNC);
- free(sc, M_PFSYNC);
+void
+pfsyncattach(int npfsync)
+{
+ if_clone_attach(&pfsync_cloner);
}
-static int
+int
#ifdef __FreeBSD__
-pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t params)
+pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param)
#else
pfsync_clone_create(struct if_clone *ifc, int unit)
#endif
{
- struct pfsync_softc *sc;
struct ifnet *ifp;
- MALLOC(sc, struct pfsync_softc *, sizeof(*sc), M_PFSYNC,
- M_WAITOK|M_ZERO);
- ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC);
+ if (unit != 0)
+ return (EINVAL);
+
+ pfsync_sync_ok = 1;
+ if ((pfsyncif = malloc(sizeof(*pfsyncif), M_DEVBUF, M_NOWAIT)) == NULL)
+ return (ENOMEM);
+ bzero(pfsyncif, sizeof(*pfsyncif));
+#ifdef __FreeBSD__
+ if ((pfsyncif->sc_imo.imo_membership = (struct in_multi **)malloc(
+ (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_DEVBUF,
+ M_NOWAIT)) == NULL) {
+ free(pfsyncif, M_DEVBUF);
+ return (ENOSPC);
+ }
+ pfsyncif->sc_imo.imo_mfilters = NULL;
+ pfsyncif->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
+ pfsyncif->sc_imo.imo_multicast_vif = -1;
+
+ ifp = pfsyncif->sc_ifp = if_alloc(IFT_PFSYNC);
if (ifp == NULL) {
- free(sc, M_PFSYNC);
+ free(pfsyncif->sc_imo.imo_membership, M_DEVBUF);
+ free(pfsyncif, M_DEVBUF);
return (ENOSPC);
}
+ if_initname(ifp, ifc->ifc_name, unit);
-#ifdef __FreeBSD__
- sc->sc_detachtag = EVENTHANDLER_REGISTER(ifnet_departure_event,
- pfsync_ifdetach, sc, EVENTHANDLER_PRI_ANY);
- if (sc->sc_detachtag == NULL) {
+ pfsyncif->sc_detachtag = EVENTHANDLER_REGISTER(ifnet_departure_event,
+ pfsync_ifdetach, pfsyncif, EVENTHANDLER_PRI_ANY);
+ if (pfsyncif->sc_detachtag == NULL) {
if_free(ifp);
- free(sc, M_PFSYNC);
+ free(pfsyncif->sc_imo.imo_membership, M_DEVBUF);
+ free(pfsyncif, M_DEVBUF);
return (ENOSPC);
}
-#endif
- pfsync_sync_ok = 1;
- sc->sc_mbuf = NULL;
- sc->sc_mbuf_net = NULL;
- sc->sc_statep.s = NULL;
- sc->sc_statep_net.s = NULL;
- sc->sc_maxupdates = 128;
- sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
- sc->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
- sc->sc_ureq_received = 0;
- sc->sc_ureq_sent = 0;
- sc->sc_imo.imo_membership = (struct in_multi **)malloc(
- (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_PFSYNC,
- M_WAITOK);
- sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
-
- ifp = SCP2IFP(sc);
- if_initname(ifp, ifc->ifc_name, unit);
+ pfsyncif->sc_ifq.ifq_maxlen = ifqmaxlen;
+ mtx_init(&pfsyncif->sc_ifq.ifq_mtx, ifp->if_xname,
+ "pfsync send queue", MTX_DEF);
+ TASK_INIT(&pfsyncif->sc_send_task, 0, pfsync_senddef, pfsyncif);
+#endif
+ pfsyncif->sc_mbuf = NULL;
+ pfsyncif->sc_mbuf_net = NULL;
+#ifdef PFSYNC_TDB
+ pfsyncif->sc_mbuf_tdb = NULL;
+#endif
+ pfsyncif->sc_statep.s = NULL;
+ pfsyncif->sc_statep_net.s = NULL;
+#ifdef PFSYNC_TDB
+ pfsyncif->sc_statep_tdb.t = NULL;
+#endif
+ pfsyncif->sc_maxupdates = 128;
+#ifdef __FreeBSD__
+ pfsyncif->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
+ pfsyncif->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP);
+#else
+ pfsyncif->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
+ pfsyncif->sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
+#endif
+ pfsyncif->sc_ureq_received = 0;
+ pfsyncif->sc_ureq_sent = 0;
+ pfsyncif->sc_bulk_send_next = NULL;
+ pfsyncif->sc_bulk_terminator = NULL;
+#ifndef __FreeBSD__
+ ifp = &pfsyncif->sc_if;
+ snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit);
+#endif
+ ifp->if_softc = pfsyncif;
ifp->if_ioctl = pfsyncioctl;
ifp->if_output = pfsyncoutput;
ifp->if_start = pfsyncstart;
+ ifp->if_type = IFT_PFSYNC;
ifp->if_snd.ifq_maxlen = ifqmaxlen;
ifp->if_hdrlen = PFSYNC_HDRLEN;
- ifp->if_baudrate = IF_Mbps(100);
- ifp->if_softc = sc;
- pfsync_setmtu(sc, MCLBYTES);
- callout_init(&sc->sc_tmo, NET_CALLOUT_MPSAFE);
- callout_init(&sc->sc_bulk_tmo, NET_CALLOUT_MPSAFE);
- callout_init(&sc->sc_bulkfail_tmo, NET_CALLOUT_MPSAFE);
- callout_init(&sc->sc_send_tmo, NET_CALLOUT_MPSAFE);
- sc->sc_ifq.ifq_maxlen = ifqmaxlen;
- mtx_init(&sc->sc_ifq.ifq_mtx, ifp->if_xname, "pfsync send queue",
- MTX_DEF);
+ pfsync_setmtu(pfsyncif, ETHERMTU);
+#ifdef __FreeBSD__
+ callout_init(&pfsyncif->sc_tmo, NET_CALLOUT_MPSAFE);
+#ifdef PFSYNC_TDB
+ callout_init(&pfsyncif->sc_tdb_tmo, NET_CALLOUT_MPSAFE);
+#endif
+ callout_init(&pfsyncif->sc_bulk_tmo, NET_CALLOUT_MPSAFE);
+ callout_init(&pfsyncif->sc_bulkfail_tmo, NET_CALLOUT_MPSAFE);
+#else
+ timeout_set(&pfsyncif->sc_tmo, pfsync_timeout, pfsyncif);
+ timeout_set(&pfsyncif->sc_tdb_tmo, pfsync_tdb_timeout, pfsyncif);
+ timeout_set(&pfsyncif->sc_bulk_tmo, pfsync_bulk_update, pfsyncif);
+ timeout_set(&pfsyncif->sc_bulkfail_tmo, pfsync_bulkfail, pfsyncif);
+#endif
if_attach(ifp);
+#ifndef __FreeBSD__
+ if_alloc_sadl(ifp);
+#endif
+
+#if NCARP > 0
+ if_addgroup(ifp, "carp");
+#endif
- LIST_INSERT_HEAD(&pfsync_list, sc, sc_next);
#if NBPFILTER > 0
+#ifdef __FreeBSD__
bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
+#else
+ bpfattach(&pfsyncif->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
+#endif
#endif
return (0);
}
-#else /* !__FreeBSD__ */
+
+#ifdef __FreeBSD__
void
-pfsyncattach(int npfsync)
+#else
+int
+#endif
+pfsync_clone_destroy(struct ifnet *ifp)
{
- struct ifnet *ifp;
-
- pfsync_sync_ok = 1;
- bzero(&pfsyncif, sizeof(pfsyncif));
- pfsyncif.sc_mbuf = NULL;
- pfsyncif.sc_mbuf_net = NULL;
- pfsyncif.sc_statep.s = NULL;
- pfsyncif.sc_statep_net.s = NULL;
- pfsyncif.sc_maxupdates = 128;
- pfsyncif.sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP;
- pfsyncif.sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP;
- pfsyncif.sc_ureq_received = 0;
- pfsyncif.sc_ureq_sent = 0;
- ifp = &pfsyncif.sc_if;
- strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
- ifp->if_softc = &pfsyncif;
- ifp->if_ioctl = pfsyncioctl;
- ifp->if_output = pfsyncoutput;
- ifp->if_start = pfsyncstart;
- ifp->if_type = IFT_PFSYNC;
- ifp->if_snd.ifq_maxlen = ifqmaxlen;
- ifp->if_hdrlen = PFSYNC_HDRLEN;
- pfsync_setmtu(&pfsyncif, MCLBYTES);
- timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
- timeout_set(&pfsyncif.sc_bulk_tmo, pfsync_bulk_update, &pfsyncif);
- timeout_set(&pfsyncif.sc_bulkfail_tmo, pfsync_bulkfail, &pfsyncif);
- if_attach(ifp);
- if_alloc_sadl(ifp);
+#ifdef __FreeBSD__
+ EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfsyncif->sc_detachtag);
+ callout_stop(&pfsyncif->sc_tmo);
+#ifdef PFSYNC_TDB
+ callout_stop(&pfsyncif->sc_tdb_tmo);
+#endif
+ callout_stop(&pfsyncif->sc_bulk_tmo);
+ callout_stop(&pfsyncif->sc_bulkfail_tmo);
+ /* XXX: more? */
+#endif
#if NBPFILTER > 0
- bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
+ bpfdetach(ifp);
#endif
-}
+ if_detach(ifp);
+#ifdef __FreeBSD__
+ if_free(ifp);
+ free(pfsyncif->sc_imo.imo_membership, M_DEVBUF);
#endif
+ free(pfsyncif, M_DEVBUF);
+ pfsyncif = NULL;
+#ifndef __FreeBSD__
+ return (0);
+#endif
+}
/*
* Start output on the pfsync interface.
@@ -327,46 +353,59 @@ pfsyncattach(int npfsync)
void
pfsyncstart(struct ifnet *ifp)
{
-#ifdef __FreeBSD__
- IF_LOCK(&ifp->if_snd);
- _IF_DROP(&ifp->if_snd);
- _IF_DRAIN(&ifp->if_snd);
- IF_UNLOCK(&ifp->if_snd);
-#else
struct mbuf *m;
+#ifndef __FreeBSD__
int s;
+#endif
for (;;) {
- s = splimp();
+#ifdef __FreeBSD__
+ IF_LOCK(&ifp->if_snd);
+ _IF_DROP(&ifp->if_snd);
+ _IF_DEQUEUE(&ifp->if_snd, m);
+ IF_UNLOCK(&ifp->if_snd);
+#else
+ s = splnet();
IF_DROP(&ifp->if_snd);
IF_DEQUEUE(&ifp->if_snd, m);
splx(s);
+#endif
if (m == NULL)
return;
else
m_freem(m);
}
-#endif
}
int
-pfsync_insert_net_state(struct pfsync_state *sp)
+pfsync_alloc_scrub_memory(struct pfsync_state_peer *s,
+ struct pf_state_peer *d)
+{
+ if (s->scrub.scrub_flag && d->scrub == NULL) {
+ d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT);
+ if (d->scrub == NULL)
+ return (ENOMEM);
+ bzero(d->scrub, sizeof(*d->scrub));
+ }
+
+ return (0);
+}
+
+int
+pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag)
{
struct pf_state *st = NULL;
struct pf_rule *r = NULL;
struct pfi_kif *kif;
-#ifdef __FreeBSD__
- PF_ASSERT(MA_OWNED);
-#endif
if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) {
printf("pfsync_insert_net_state: invalid creator id:"
" %08x\n", ntohl(sp->creatorid));
return (EINVAL);
}
- kif = pfi_lookup_create(sp->ifname);
+ kif = pfi_kif_get(sp->ifname);
if (kif == NULL) {
if (pf_status.debug >= PF_DEBUG_MISC)
printf("pfsync_insert_net_state: "
@@ -376,19 +415,33 @@ pfsync_insert_net_state(struct pfsync_state *sp)
}
/*
- * Just use the default rule until we have infrastructure to find the
- * best matching rule.
+ * If the ruleset checksums match, it's safe to associate the state
+ * with the rule of that number.
*/
- r = &pf_default_rule;
+ if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && chksum_flag)
+ r = pf_main_ruleset.rules[
+ PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)];
+ else
+ r = &pf_default_rule;
if (!r->max_states || r->states < r->max_states)
st = pool_get(&pf_state_pl, PR_NOWAIT);
if (st == NULL) {
- pfi_maybe_destroy(kif);
+ pfi_kif_unref(kif, PFI_KIF_REF_NONE);
return (ENOMEM);
}
bzero(st, sizeof(*st));
+ /* allocate memory for scrub info */
+ if (pfsync_alloc_scrub_memory(&sp->src, &st->src) ||
+ pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) {
+ pfi_kif_unref(kif, PFI_KIF_REF_NONE);
+ if (st->src.scrub)
+ pool_put(&pf_state_scrub_pl, st->src.scrub);
+ pool_put(&pf_state_pl, st);
+ return (ENOMEM);
+ }
+
st->rule.ptr = r;
/* XXX get pointers to nat_rule and anchor */
@@ -418,11 +471,14 @@ pfsync_insert_net_state(struct pfsync_state *sp)
st->creatorid = sp->creatorid;
st->sync_flags = PFSTATE_FROMSYNC;
-
if (pf_insert_state(kif, st)) {
- pfi_maybe_destroy(kif);
+ pfi_kif_unref(kif, PFI_KIF_REF_NONE);
/* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */
r->states--;
+ if (st->dst.scrub)
+ pool_put(&pf_state_scrub_pl, st->dst.scrub);
+ if (st->src.scrub)
+ pool_put(&pf_state_scrub_pl, st->src.scrub);
pool_put(&pf_state_pl, st);
return (EINVAL);
}
@@ -439,26 +495,27 @@ pfsync_input(struct mbuf *m, ...)
{
struct ip *ip = mtod(m, struct ip *);
struct pfsync_header *ph;
-#ifdef __FreeBSD__
- struct pfsync_softc *sc = LIST_FIRST(&pfsync_list);
-#else
- struct pfsync_softc *sc = &pfsyncif;
-#endif
- struct pf_state *st, key;
+ struct pfsync_softc *sc = pfsyncif;
+ struct pf_state *st;
+ struct pf_state_cmp key;
struct pfsync_state *sp;
struct pfsync_state_upd *up;
struct pfsync_state_del *dp;
struct pfsync_state_clr *cp;
struct pfsync_state_upd_req *rup;
struct pfsync_state_bus *bus;
+#ifdef PFSYNC_TDB
+ struct pfsync_tdb *pt;
+#endif
struct in_addr src;
struct mbuf *mp;
int iplen, action, error, i, s, count, offp, sfail, stale = 0;
+ u_int8_t chksum_flag = 0;
pfsyncstats.pfsyncs_ipackets++;
/* verify that we have a sync interface configured */
- if (!sc->sc_sync_ifp || !pf_status.running) /* XXX PF_LOCK? */
+ if (!sc || !sc->sc_sync_ifp || !pf_status.running)
goto done;
/* verify that the packet came in on the right interface */
@@ -507,6 +564,9 @@ pfsync_input(struct mbuf *m, ...)
/* Cheaper to grab this now than having to mess with mbufs later */
src = ip->ip_src;
+ if (!bcmp(&ph->pf_chksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH))
+ chksum_flag++;
+
switch (action) {
case PFSYNC_ACT_CLR: {
struct pf_state *nexts;
@@ -527,31 +587,27 @@ pfsync_input(struct mbuf *m, ...)
if (cp->ifname[0] == '\0') {
for (st = RB_MIN(pf_state_tree_id, &tree_id);
st; st = nexts) {
- nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
+ nexts = RB_NEXT(pf_state_tree_id, &tree_id, st);
if (st->creatorid == creatorid) {
- st->timeout = PFTM_PURGE;
- pf_purge_expired_state(st);
+ st->sync_flags |= PFSTATE_FROMSYNC;
+ pf_unlink_state(st);
}
}
} else {
- kif = pfi_lookup_if(cp->ifname);
- if (kif == NULL) {
- if (pf_status.debug >= PF_DEBUG_MISC)
- printf("pfsync_input: PFSYNC_ACT_CLR "
- "bad interface: %s\n", cp->ifname);
- splx(s);
+ if ((kif = pfi_kif_get(cp->ifname)) == NULL) {
#ifdef __FreeBSD__
PF_UNLOCK();
#endif
- goto done;
+ splx(s);
+ return;
}
for (st = RB_MIN(pf_state_tree_lan_ext,
&kif->pfik_lan_ext); st; st = nexts) {
nexts = RB_NEXT(pf_state_tree_lan_ext,
&kif->pfik_lan_ext, st);
if (st->creatorid == creatorid) {
- st->timeout = PFTM_PURGE;
- pf_purge_expired_state(st);
+ st->sync_flags |= PFSTATE_FROMSYNC;
+ pf_unlink_state(st);
}
}
}
@@ -588,12 +644,13 @@ pfsync_input(struct mbuf *m, ...)
continue;
}
- if ((error = pfsync_insert_net_state(sp))) {
+ if ((error = pfsync_insert_net_state(sp,
+ chksum_flag))) {
if (error == ENOMEM) {
- splx(s);
#ifdef __FreeBSD__
PF_UNLOCK();
#endif
+ splx(s);
goto done;
}
continue;
@@ -636,7 +693,7 @@ pfsync_input(struct mbuf *m, ...)
st = pf_find_state_byid(&key);
if (st == NULL) {
/* insert the update */
- if (pfsync_insert_net_state(sp))
+ if (pfsync_insert_net_state(sp, chksum_flag))
pfsyncstats.pfsyncs_badstate++;
continue;
}
@@ -675,7 +732,7 @@ pfsync_input(struct mbuf *m, ...)
*/
if (st->src.state > sp->src.state)
sfail = 5;
- else if ( st->dst.state > sp->dst.state)
+ else if (st->dst.state > sp->dst.state)
sfail = 6;
}
if (sfail) {
@@ -685,11 +742,7 @@ pfsync_input(struct mbuf *m, ...)
"creatorid: %08x\n",
(sfail < 7 ? "ignoring"
: "partial"), sfail,
-#ifdef __FreeBSD__
- (unsigned long long)be64toh(st->id),
-#else
betoh64(st->id),
-#endif
ntohl(st->creatorid));
pfsyncstats.pfsyncs_badstate++;
@@ -704,6 +757,7 @@ pfsync_input(struct mbuf *m, ...)
}
continue;
}
+ pfsync_alloc_scrub_memory(&sp->dst, &st->dst);
pf_state_peer_ntoh(&sp->src, &st->src);
pf_state_peer_ntoh(&sp->dst, &st->dst);
st->expire = ntohl(sp->expire) + time_second;
@@ -741,9 +795,8 @@ pfsync_input(struct mbuf *m, ...)
pfsyncstats.pfsyncs_badstate++;
continue;
}
- st->timeout = PFTM_PURGE;
st->sync_flags |= PFSTATE_FROMSYNC;
- pf_purge_expired_state(st);
+ pf_unlink_state(st);
}
#ifdef __FreeBSD__
PF_UNLOCK();
@@ -785,6 +838,9 @@ pfsync_input(struct mbuf *m, ...)
/* We don't have this state. Ask for it. */
error = pfsync_request_update(up, &src);
if (error == ENOMEM) {
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
splx(s);
goto done;
}
@@ -826,11 +882,7 @@ pfsync_input(struct mbuf *m, ...)
printf("pfsync: ignoring stale update "
"(%d) id: %016llx "
"creatorid: %08x\n", sfail,
-#ifdef __FreeBSD__
- (unsigned long long)be64toh(st->id),
-#else
betoh64(st->id),
-#endif
ntohl(st->creatorid));
pfsyncstats.pfsyncs_badstate++;
@@ -846,6 +898,7 @@ pfsync_input(struct mbuf *m, ...)
PFSYNC_FLAG_STALE);
continue;
}
+ pfsync_alloc_scrub_memory(&up->dst, &st->dst);
pf_state_peer_ntoh(&up->src, &st->src);
pf_state_peer_ntoh(&up->dst, &st->dst);
st->expire = ntohl(up->expire) + time_second;
@@ -880,9 +933,8 @@ pfsync_input(struct mbuf *m, ...)
pfsyncstats.pfsyncs_badstate++;
continue;
}
- st->timeout = PFTM_PURGE;
st->sync_flags |= PFSTATE_FROMSYNC;
- pf_purge_expired_state(st);
+ pf_unlink_state(st);
}
#ifdef __FreeBSD__
PF_UNLOCK();
@@ -914,14 +966,17 @@ pfsync_input(struct mbuf *m, ...)
if (key.id == 0 && key.creatorid == 0) {
sc->sc_ureq_received = time_uptime;
+ if (sc->sc_bulk_send_next == NULL)
+ sc->sc_bulk_send_next =
+ TAILQ_FIRST(&state_list);
+ sc->sc_bulk_terminator = sc->sc_bulk_send_next;
if (pf_status.debug >= PF_DEBUG_MISC)
printf("pfsync: received "
"bulk update request\n");
pfsync_send_bus(sc, PFSYNC_BUS_START);
#ifdef __FreeBSD__
callout_reset(&sc->sc_bulk_tmo, 1 * hz,
- pfsync_bulk_update,
- LIST_FIRST(&pfsync_list));
+ pfsync_bulk_update, pfsyncif);
#else
timeout_add(&sc->sc_bulk_tmo, 1 * hz);
#endif
@@ -959,8 +1014,8 @@ pfsync_input(struct mbuf *m, ...)
#ifdef __FreeBSD__
callout_reset(&sc->sc_bulkfail_tmo,
pf_pool_limits[PF_LIMIT_STATES].limit /
- (PFSYNC_BULKPACKETS * sc->sc_maxcount),
- pfsync_bulkfail, LIST_FIRST(&pfsync_list));
+ (PFSYNC_BULKPACKETS * sc->sc_maxcount),
+ pfsync_bulkfail, pfsyncif);
#else
timeout_add(&sc->sc_bulkfail_tmo,
pf_pool_limits[PF_LIMIT_STATES].limit /
@@ -976,14 +1031,16 @@ pfsync_input(struct mbuf *m, ...)
/* that's it, we're happy */
sc->sc_ureq_sent = 0;
sc->sc_bulk_tries = 0;
+ timeout_del(&sc->sc_bulkfail_tmo);
+#if NCARP > 0
+ if (!pfsync_sync_ok)
#ifdef __FreeBSD__
- callout_stop(&sc->sc_bulkfail_tmo);
+#ifdef CARP_ADVANCED
+ carp_group_demote_adj(sc->sc_ifp, -1);
+#endif
#else
- timeout_del(&sc->sc_bulkfail_tmo);
+ carp_group_demote_adj(&sc->sc_if, -1);
#endif
-#if NCARP > 0 /* XXX_IMPORT */
- if (!pfsync_sync_ok)
- carp_suppress_preempt--;
#endif
pfsync_sync_ok = 1;
if (pf_status.debug >= PF_DEBUG_MISC)
@@ -997,6 +1054,26 @@ pfsync_input(struct mbuf *m, ...)
break;
}
break;
+#ifdef PFSYNC_TDB
+ case PFSYNC_ACT_TDB_UPD:
+ if ((mp = m_pulldown(m, iplen + sizeof(*ph),
+ count * sizeof(*pt), &offp)) == NULL) {
+ pfsyncstats.pfsyncs_badlen++;
+ return;
+ }
+ s = splsoftnet();
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
+ for (i = 0, pt = (struct pfsync_tdb *)(mp->m_data + offp);
+ i < count; i++, pt++)
+ pfsync_update_net_tdb(pt);
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
+ splx(s);
+ break;
+#endif
}
done:
@@ -1052,9 +1129,8 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
#ifdef __FreeBSD__
PF_LOCK();
#endif
- if (ifr->ifr_mtu < ifp->if_mtu) {
+ if (ifr->ifr_mtu < ifp->if_mtu)
pfsync_sendout(sc);
- }
pfsync_setmtu(sc, ifr->ifr_mtu);
#ifdef __FreeBSD__
PF_UNLOCK();
@@ -1062,9 +1138,6 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
splx(s);
break;
case SIOCGETPFSYNC:
-#ifdef __FreeBSD__
- /* XXX: read unlocked */
-#endif
bzero(&pfsyncr, sizeof(pfsyncr));
if (sc->sc_sync_ifp)
strlcpy(pfsyncr.pfsyncr_syncdev,
@@ -1084,6 +1157,9 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if ((error = copyin(ifr->ifr_data, &pfsyncr, sizeof(pfsyncr))))
return (error);
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
#ifdef __FreeBSD__
sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
@@ -1095,10 +1171,13 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
pfsyncr.pfsyncr_syncpeer.s_addr;
if (pfsyncr.pfsyncr_maxupdates > 255)
+#ifdef __FreeBSD__
+ {
+ PF_UNLOCK();
+#endif
return (EINVAL);
#ifdef __FreeBSD__
- callout_drain(&sc->sc_send_tmo);
- PF_LOCK();
+ }
#endif
sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
@@ -1112,26 +1191,28 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
sc->sc_statep_net.s = NULL;
splx(s);
}
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
if (imo->imo_num_memberships > 0) {
in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
imo->imo_multicast_ifp = NULL;
}
-#ifdef __FreeBSD__
- PF_UNLOCK();
-#endif
break;
}
- if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) {
#ifdef __FreeBSD__
- PF_UNLOCK();
+ PF_UNLOCK();
#endif
+ if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL)
return (EINVAL);
- }
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
s = splnet();
#ifdef __FreeBSD__
- if (sifp->if_mtu < SCP2IFP(sc)->if_mtu ||
+ if (sifp->if_mtu < sc->sc_ifp->if_mtu ||
#else
if (sifp->if_mtu < sc->sc_if.if_mtu ||
#endif
@@ -1142,13 +1223,19 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
sc->sc_sync_ifp = sifp;
#ifdef __FreeBSD__
- pfsync_setmtu(sc, SCP2IFP(sc)->if_mtu);
+ pfsync_setmtu(sc, sc->sc_ifp->if_mtu);
#else
pfsync_setmtu(sc, sc->sc_if.if_mtu);
#endif
if (imo->imo_num_memberships > 0) {
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
in_delmulti(imo->imo_membership[--imo->imo_num_memberships]);
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
imo->imo_multicast_ifp = NULL;
}
@@ -1168,26 +1255,29 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
splx(s);
return (EADDRNOTAVAIL);
}
+
#ifdef __FreeBSD__
- PF_UNLOCK(); /* addmulti mallocs w/ WAITOK */
addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
#else
addr.s_addr = INADDR_PFSYNC_GROUP;
#endif
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
if ((imo->imo_membership[0] =
in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) {
sc->sc_sync_ifp = NULL;
splx(s);
return (ENOBUFS);
}
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
imo->imo_num_memberships++;
imo->imo_multicast_ifp = sc->sc_sync_ifp;
imo->imo_multicast_ttl = PFSYNC_DFLTTL;
imo->imo_multicast_loop = 0;
-#ifdef __FreeBSD__
- PF_LOCK();
-#endif
}
if (sc->sc_sync_ifp ||
@@ -1200,14 +1290,20 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
sc->sc_ureq_sent = time_uptime;
#if NCARP > 0
if (pfsync_sync_ok)
- carp_suppress_preempt++;
+#ifdef __FreeBSD__
+#ifdef CARP_ADVANCED
+ carp_group_demote_adj(sc->sc_ifp, 1);
+#endif
+#else
+ carp_group_demote_adj(&sc->sc_if, 1);
+#endif
#endif
pfsync_sync_ok = 0;
if (pf_status.debug >= PF_DEBUG_MISC)
printf("pfsync: requesting bulk update\n");
#ifdef __FreeBSD__
callout_reset(&sc->sc_bulkfail_tmo, 5 * hz,
- pfsync_bulkfail, LIST_FIRST(&pfsync_list));
+ pfsync_bulkfail, pfsyncif);
#else
timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
#endif
@@ -1250,12 +1346,11 @@ pfsync_setmtu(struct pfsync_softc *sc, int mtu_req)
if (sc->sc_maxcount > 254)
sc->sc_maxcount = 254;
#ifdef __FreeBSD__
- SCP2IFP(sc)->if_mtu = sizeof(struct pfsync_header) +
- sc->sc_maxcount * sizeof(struct pfsync_state);
+ sc->sc_ifp->if_mtu = sizeof(struct pfsync_header) +
#else
sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
- sc->sc_maxcount * sizeof(struct pfsync_state);
#endif
+ sc->sc_maxcount * sizeof(struct pfsync_state);
}
struct mbuf *
@@ -1265,13 +1360,10 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
struct mbuf *m;
int len;
-#ifdef __FreeBSD__
- PF_ASSERT(MA_OWNED);
-#endif
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
#ifdef __FreeBSD__
- SCP2IFP(sc)->if_oerrors++;
+ sc->sc_ifp->if_oerrors++;
#else
sc->sc_if.if_oerrors++;
#endif
@@ -1299,6 +1391,12 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
len = sizeof(struct pfsync_header) +
sizeof(struct pfsync_state_bus);
break;
+#ifdef PFSYNC_TDB
+ case PFSYNC_ACT_TDB_UPD:
+ len = (sc->sc_maxcount * sizeof(struct pfsync_tdb)) +
+ sizeof(struct pfsync_header);
+ break;
+#endif
default:
len = (sc->sc_maxcount * sizeof(struct pfsync_state)) +
sizeof(struct pfsync_header);
@@ -1310,7 +1408,7 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
if ((m->m_flags & M_EXT) == 0) {
m_free(m);
#ifdef __FreeBSD__
- SCP2IFP(sc)->if_oerrors++;
+ sc->sc_ifp->if_oerrors++;
#else
sc->sc_if.if_oerrors++;
#endif
@@ -1327,13 +1425,27 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
h->af = 0;
h->count = 0;
h->action = action;
+#ifndef PFSYNC_TDB
+ if (action != PFSYNC_ACT_TDB_UPD)
+#endif
+ bcopy(&pf_status.pf_chksum, &h->pf_chksum,
+ PF_MD5_DIGEST_LENGTH);
*sp = (void *)((char *)h + PFSYNC_HDRLEN);
+#ifdef PFSYNC_TDB
+ if (action == PFSYNC_ACT_TDB_UPD)
#ifdef __FreeBSD__
- callout_reset(&sc->sc_tmo, hz, pfsync_timeout,
- LIST_FIRST(&pfsync_list));
+ callout_reset(&sc->sc_tdb_tmo, hz, pfsync_tdb_timeout,
+ pfsyncif);
#else
- timeout_add(&sc->sc_tmo, hz);
+ timeout_add(&sc->sc_tdb_tmo, hz);
+#endif
+ else
+#endif
+#ifdef __FreeBSD__
+ callout_reset(&sc->sc_tmo, hz, pfsync_timeout, pfsyncif);
+#else
+ timeout_add(&sc->sc_tmo, hz);
#endif
return (m);
}
@@ -1341,12 +1453,8 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp)
int
pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
{
-#ifdef __FreeBSD__
- struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
-#else
- struct ifnet *ifp = &pfsyncif.sc_if;
-#endif
- struct pfsync_softc *sc = ifp->if_softc;
+ struct ifnet *ifp = NULL;
+ struct pfsync_softc *sc = pfsyncif;
struct pfsync_header *h, *h_net;
struct pfsync_state *sp = NULL;
struct pfsync_state_upd *up = NULL;
@@ -1356,9 +1464,14 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
int s, ret = 0;
u_int8_t i = 255, newaction = 0;
+ if (sc == NULL)
+ return (0);
#ifdef __FreeBSD__
- PF_ASSERT(MA_OWNED);
+ ifp = sc->sc_ifp;
+#else
+ ifp = &sc->sc_if;
#endif
+
/*
* If a packet falls in the forest and there's nobody around to
* hear, does it make a sound?
@@ -1382,6 +1495,9 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
return (EINVAL);
s = splnet();
+#ifdef __FreeBSD__
+ PF_ASSERT(MA_OWNED);
+#endif
if (sc->sc_mbuf == NULL) {
if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action,
(void *)&sc->sc_statep.s)) == NULL) {
@@ -1425,8 +1541,6 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
secs = time_second;
st->pfsync_time = time_uptime;
- TAILQ_REMOVE(&state_updates, st, u.s.entry_updates);
- TAILQ_INSERT_TAIL(&state_updates, st, u.s.entry_updates);
if (sp == NULL) {
/* not a "duplicate" update */
@@ -1448,10 +1562,10 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
sp->creation = htonl(secs - st->creation);
- sp->packets[0] = htonl(st->packets[0]);
- sp->packets[1] = htonl(st->packets[1]);
- sp->bytes[0] = htonl(st->bytes[0]);
- sp->bytes[1] = htonl(st->bytes[1]);
+ pf_state_counter_hton(st->packets[0], sp->packets[0]);
+ pf_state_counter_hton(st->packets[1], sp->packets[1]);
+ pf_state_counter_hton(st->bytes[0], sp->bytes[0]);
+ pf_state_counter_hton(st->bytes[1], sp->bytes[1]);
if ((r = st->rule.ptr) == NULL)
sp->rule = htonl(-1);
else
@@ -1550,18 +1664,19 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags)
int
pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
{
-#ifdef __FreeBSD__
- struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
-#else
- struct ifnet *ifp = &pfsyncif.sc_if;
-#endif
+ struct ifnet *ifp = NULL;
struct pfsync_header *h;
- struct pfsync_softc *sc = ifp->if_softc;
+ struct pfsync_softc *sc = pfsyncif;
struct pfsync_state_upd_req *rup;
int ret = 0;
+ if (sc == NULL)
+ return (0);
+
#ifdef __FreeBSD__
- PF_ASSERT(MA_OWNED);
+ ifp = sc->sc_ifp;
+#else
+ ifp = &sc->sc_if;
#endif
if (sc->sc_mbuf == NULL) {
if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ,
@@ -1599,19 +1714,23 @@ pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src)
int
pfsync_clear_states(u_int32_t creatorid, char *ifname)
{
-#ifdef __FreeBSD__
- struct ifnet *ifp = SCP2IFP(LIST_FIRST(&pfsync_list));
-#else
- struct ifnet *ifp = &pfsyncif.sc_if;
-#endif
- struct pfsync_softc *sc = ifp->if_softc;
+ struct ifnet *ifp = NULL;
+ struct pfsync_softc *sc = pfsyncif;
struct pfsync_state_clr *cp;
int s, ret;
- s = splnet();
+ if (sc == NULL)
+ return (0);
+
+#ifdef __FreeBSD__
+ ifp = sc->sc_ifp;
+#else
+ ifp = &sc->sc_if;
+#endif
#ifdef __FreeBSD__
PF_ASSERT(MA_OWNED);
#endif
+ s = splnet();
if (sc->sc_mbuf != NULL)
pfsync_sendout(sc);
if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR,
@@ -1647,6 +1766,25 @@ pfsync_timeout(void *v)
splx(s);
}
+#ifdef PFSYNC_TDB
+void
+pfsync_tdb_timeout(void *v)
+{
+ struct pfsync_softc *sc = v;
+ int s;
+
+ s = splnet();
+#ifdef __FreeBSD__
+ PF_LOCK();
+#endif
+ pfsync_tdb_sendout(sc);
+#ifdef __FreeBSD__
+ PF_UNLOCK();
+#endif
+ splx(s);
+}
+#endif
+
/* This must be called in splnet() */
void
pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status)
@@ -1678,10 +1816,10 @@ pfsync_bulk_update(void *v)
int s, i = 0;
struct pf_state *state;
+ s = splnet();
#ifdef __FreeBSD__
PF_LOCK();
#endif
- s = splnet();
if (sc->sc_mbuf != NULL)
pfsync_sendout(sc);
@@ -1689,37 +1827,44 @@ pfsync_bulk_update(void *v)
* Grab at most PFSYNC_BULKPACKETS worth of states which have not
* been sent since the latest request was made.
*/
- while ((state = TAILQ_FIRST(&state_updates)) != NULL &&
- ++i < (sc->sc_maxcount * PFSYNC_BULKPACKETS)) {
- if (state->pfsync_time > sc->sc_ureq_received) {
- /* we're done */
- pfsync_send_bus(sc, PFSYNC_BUS_END);
- sc->sc_ureq_received = 0;
-#ifdef __FreeBSD__
- callout_stop(&sc->sc_bulk_tmo);
-#else
- timeout_del(&sc->sc_bulk_tmo);
-#endif
- if (pf_status.debug >= PF_DEBUG_MISC)
- printf("pfsync: bulk update complete\n");
- break;
- } else {
- /* send an update and move to end of list */
- if (!state->sync_flags)
+ state = sc->sc_bulk_send_next;
+ if (state)
+ do {
+ /* send state update if syncable and not already sent */
+ if (!state->sync_flags
+ && state->timeout < PFTM_MAX
+ && state->pfsync_time <= sc->sc_ureq_received) {
pfsync_pack_state(PFSYNC_ACT_UPD, state, 0);
- state->pfsync_time = time_uptime;
- TAILQ_REMOVE(&state_updates, state, u.s.entry_updates);
- TAILQ_INSERT_TAIL(&state_updates, state,
- u.s.entry_updates);
+ i++;
+ }
- /* look again for more in a bit */
+ /* figure next state to send */
+ state = TAILQ_NEXT(state, u.s.entry_list);
+
+ /* wrap to start of list if we hit the end */
+ if (!state)
+ state = TAILQ_FIRST(&state_list);
+ } while (i < sc->sc_maxcount * PFSYNC_BULKPACKETS &&
+ state != sc->sc_bulk_terminator);
+
+ if (!state || state == sc->sc_bulk_terminator) {
+ /* we're done */
+ pfsync_send_bus(sc, PFSYNC_BUS_END);
+ sc->sc_ureq_received = 0;
+ sc->sc_bulk_send_next = NULL;
+ sc->sc_bulk_terminator = NULL;
+ timeout_del(&sc->sc_bulk_tmo);
+ if (pf_status.debug >= PF_DEBUG_MISC)
+ printf("pfsync: bulk update complete\n");
+ } else {
+ /* look again for more in a bit */
#ifdef __FreeBSD__
- callout_reset(&sc->sc_bulk_tmo, 1, pfsync_timeout,
- LIST_FIRST(&pfsync_list));
+ callout_reset(&sc->sc_bulk_tmo, 1, pfsync_bulk_update,
+ pfsyncif);
#else
- timeout_add(&sc->sc_bulk_tmo, 1);
+ timeout_add(&sc->sc_bulk_tmo, 1);
#endif
- }
+ sc->sc_bulk_send_next = state;
}
if (sc->sc_mbuf != NULL)
pfsync_sendout(sc);
@@ -1742,7 +1887,7 @@ pfsync_bulkfail(void *v)
/* Try again in a bit */
#ifdef __FreeBSD__
callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail,
- LIST_FIRST(&pfsync_list));
+ pfsyncif);
#else
timeout_add(&sc->sc_bulkfail_tmo, 5 * hz);
#endif
@@ -1761,17 +1906,19 @@ pfsync_bulkfail(void *v)
sc->sc_bulk_tries = 0;
#if NCARP > 0
if (!pfsync_sync_ok)
- carp_suppress_preempt--;
+#ifdef __FreeBSD__
+#ifdef CARP_ADVANCED
+ carp_group_demote_adj(sc->sc_ifp, -1);
+#endif
+#else
+ carp_group_demote_adj(&sc->sc_if, -1);
+#endif
#endif
pfsync_sync_ok = 1;
if (pf_status.debug >= PF_DEBUG_MISC)
printf("pfsync: failed to receive "
"bulk update status\n");
-#ifdef __FreeBSD__
- callout_stop(&sc->sc_bulkfail_tmo);
-#else
timeout_del(&sc->sc_bulkfail_tmo);
-#endif
}
#ifdef __FreeBSD__
PF_UNLOCK();
@@ -1780,24 +1927,21 @@ pfsync_bulkfail(void *v)
/* This must be called in splnet() */
int
-pfsync_sendout(sc)
- struct pfsync_softc *sc;
+pfsync_sendout(struct pfsync_softc *sc)
{
#if NBPFILTER > 0
-# ifdef __FreeBSD__
- struct ifnet *ifp = SCP2IFP(sc);
-# else
- struct ifnet *ifp = &sc->if_sc;
-# endif
+#ifdef __FreeBSD__
+ struct ifnet *ifp = sc->sc_ifp;
+#else
+ struct ifnet *ifp = &sc->sc_if;
+#endif
#endif
struct mbuf *m;
#ifdef __FreeBSD__
PF_ASSERT(MA_OWNED);
- callout_stop(&sc->sc_tmo);
-#else
- timeout_del(&sc->sc_tmo);
#endif
+ timeout_del(&sc->sc_tmo);
if (sc->sc_mbuf == NULL)
return (0);
@@ -1805,15 +1949,12 @@ pfsync_sendout(sc)
sc->sc_mbuf = NULL;
sc->sc_statep.s = NULL;
-#ifdef __FreeBSD__
- KASSERT(m != NULL, ("pfsync_sendout: null mbuf"));
-#endif
#if NBPFILTER > 0
+ if (ifp->if_bpf)
#ifdef __FreeBSD__
- BPF_MTAP(ifp, m);
+ BPF_MTAP(ifp, m);
#else
- if (ifp->if_bpf)
- bpf_mtap(ifp->if_bpf, m);
+ bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
#endif
#endif
@@ -1824,15 +1965,61 @@ pfsync_sendout(sc)
sc->sc_statep_net.s = NULL;
}
+ return pfsync_sendout_mbuf(sc, m);
+}
+
+#ifdef PFSYNC_TDB
+int
+pfsync_tdb_sendout(struct pfsync_softc *sc)
+{
+#if NBPFILTER > 0
+#ifdef __FreeBSD__
+ struct ifnet *ifp = sc->sc_ifp;
+#else
+ struct ifnet *ifp = &sc->sc_if;
+#endif
+#endif
+ struct mbuf *m;
+
#ifdef __FreeBSD__
+ PF_ASSERT(MA_OWNED);
+#endif
+ timeout_del(&sc->sc_tdb_tmo);
+
+ if (sc->sc_mbuf_tdb == NULL)
+ return (0);
+ m = sc->sc_mbuf_tdb;
+ sc->sc_mbuf_tdb = NULL;
+ sc->sc_statep_tdb.t = NULL;
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+#ifdef __FreeBSD__
+ BPF_MTAP(ifp, m);
+#else
+ bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+#endif
+#endif
+
+ return pfsync_sendout_mbuf(sc, m);
+}
+#endif
+
+int
+pfsync_sendout_mbuf(struct pfsync_softc *sc, struct mbuf *m)
+{
+ struct sockaddr sa;
+ struct ip *ip;
+
+#ifdef __FreeBSD__
+ PF_ASSERT(MA_OWNED);
+#endif
if (sc->sc_sync_ifp ||
+#ifdef __FreeBSD__
sc->sc_sync_peer.s_addr != htonl(INADDR_PFSYNC_GROUP)) {
#else
- if (sc->sc_sync_ifp ||sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
+ sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) {
#endif
- struct ip *ip;
- struct sockaddr sa;
-
M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
if (m == NULL) {
pfsyncstats.pfsyncs_onomem++;
@@ -1870,10 +2057,11 @@ pfsync_sendout(sc)
sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr;
pfsyncstats.pfsyncs_opackets++;
+
#ifdef __FreeBSD__
if (!IF_HANDOFF(&sc->sc_ifq, m, NULL))
pfsyncstats.pfsyncs_oerrors++;
- callout_reset(&sc->sc_send_tmo, 1, pfsync_senddef, sc);
+ taskqueue_enqueue(taskqueue_thread, &pfsyncif->sc_send_task);
#else
if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL))
pfsyncstats.pfsyncs_oerrors++;
@@ -1884,15 +2072,179 @@ pfsync_sendout(sc)
return (0);
}
+#ifdef PFSYNC_TDB
+/* Update an in-kernel tdb. Silently fail if no tdb is found. */
+void
+pfsync_update_net_tdb(struct pfsync_tdb *pt)
+{
+ struct tdb *tdb;
+ int s;
+
+ /* check for invalid values */
+ if (ntohl(pt->spi) <= SPI_RESERVED_MAX ||
+ (pt->dst.sa.sa_family != AF_INET &&
+ pt->dst.sa.sa_family != AF_INET6))
+ goto bad;
+
+ s = spltdb();
+ tdb = gettdb(pt->spi, &pt->dst, pt->sproto);
+ if (tdb) {
+ pt->rpl = ntohl(pt->rpl);
+ pt->cur_bytes = betoh64(pt->cur_bytes);
+
+ /* Neither replay nor byte counter should ever decrease. */
+ if (pt->rpl < tdb->tdb_rpl ||
+ pt->cur_bytes < tdb->tdb_cur_bytes) {
+ splx(s);
+ goto bad;
+ }
+
+ tdb->tdb_rpl = pt->rpl;
+ tdb->tdb_cur_bytes = pt->cur_bytes;
+ }
+ splx(s);
+ return;
+
+ bad:
+ if (pf_status.debug >= PF_DEBUG_MISC)
+ printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: "
+ "invalid value\n");
+ pfsyncstats.pfsyncs_badstate++;
+ return;
+}
+
+/* One of our local tdbs have been updated, need to sync rpl with others */
+int
+pfsync_update_tdb(struct tdb *tdb, int output)
+{
+ struct ifnet *ifp = NULL;
+ struct pfsync_softc *sc = pfsyncif;
+ struct pfsync_header *h;
+ struct pfsync_tdb *pt = NULL;
+ int s, i, ret;
+
+ if (sc == NULL)
+ return (0);
+
+#ifdef __FreeBSD__
+ ifp = sc->sc_ifp;
+#else
+ ifp = &sc->sc_if;
+#endif
+ if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL &&
+#ifdef __FreeBSD__
+ sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
+#else
+ sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) {
+#endif
+ /* Don't leave any stale pfsync packets hanging around. */
+ if (sc->sc_mbuf_tdb != NULL) {
+ m_freem(sc->sc_mbuf_tdb);
+ sc->sc_mbuf_tdb = NULL;
+ sc->sc_statep_tdb.t = NULL;
+ }
+ return (0);
+ }
+
+#ifdef __FreeBSD__
+ PF_ASSERT(MA_OWNED);
+#endif
+ s = splnet();
+ if (sc->sc_mbuf_tdb == NULL) {
+ if ((sc->sc_mbuf_tdb = pfsync_get_mbuf(sc, PFSYNC_ACT_TDB_UPD,
+ (void *)&sc->sc_statep_tdb.t)) == NULL) {
+ splx(s);
+ return (ENOMEM);
+ }
+ h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *);
+ } else {
+ h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *);
+ if (h->action != PFSYNC_ACT_TDB_UPD) {
+ /*
+ * XXX will never happen as long as there's
+ * only one "TDB action".
+ */
+ pfsync_tdb_sendout(sc);
+ sc->sc_mbuf_tdb = pfsync_get_mbuf(sc,
+ PFSYNC_ACT_TDB_UPD, (void *)&sc->sc_statep_tdb.t);
+ if (sc->sc_mbuf_tdb == NULL) {
+ splx(s);
+ return (ENOMEM);
+ }
+ h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *);
+ } else if (sc->sc_maxupdates) {
+ /*
+ * If it's an update, look in the packet to see if
+ * we already have an update for the state.
+ */
+ struct pfsync_tdb *u =
+ (void *)((char *)h + PFSYNC_HDRLEN);
+
+ for (i = 0; !pt && i < h->count; i++) {
+ if (tdb->tdb_spi == u->spi &&
+ tdb->tdb_sproto == u->sproto &&
+ !bcmp(&tdb->tdb_dst, &u->dst,
+ SA_LEN(&u->dst.sa))) {
+ pt = u;
+ pt->updates++;
+ }
+ u++;
+ }
+ }
+ }
+
+ if (pt == NULL) {
+ /* not a "duplicate" update */
+ pt = sc->sc_statep_tdb.t++;
+ sc->sc_mbuf_tdb->m_pkthdr.len =
+ sc->sc_mbuf_tdb->m_len += sizeof(struct pfsync_tdb);
+ h->count++;
+ bzero(pt, sizeof(*pt));
+
+ pt->spi = tdb->tdb_spi;
+ memcpy(&pt->dst, &tdb->tdb_dst, sizeof pt->dst);
+ pt->sproto = tdb->tdb_sproto;
+ }
+
+ /*
+ * When a failover happens, the master's rpl is probably above
+ * what we see here (we may be up to a second late), so
+ * increase it a bit for outbound tdbs to manage most such
+ * situations.
+ *
+ * For now, just add an offset that is likely to be larger
+ * than the number of packets we can see in one second. The RFC
+ * just says the next packet must have a higher seq value.
+ *
+ * XXX What is a good algorithm for this? We could use
+ * a rate-determined increase, but to know it, we would have
+ * to extend struct tdb.
+ * XXX pt->rpl can wrap over MAXINT, but if so the real tdb
+ * will soon be replaced anyway. For now, just don't handle
+ * this edge case.
+ */
+#define RPL_INCR 16384
+ pt->rpl = htonl(tdb->tdb_rpl + (output ? RPL_INCR : 0));
+ pt->cur_bytes = htobe64(tdb->tdb_cur_bytes);
+
+ if (h->count == sc->sc_maxcount ||
+ (sc->sc_maxupdates && (pt->updates >= sc->sc_maxupdates)))
+ ret = pfsync_tdb_sendout(sc);
+
+ splx(s);
+ return (ret);
+}
+#endif /* PFSYNC_TDB */
+
#ifdef __FreeBSD__
-static void
+void
pfsync_ifdetach(void *arg, struct ifnet *ifp)
{
struct pfsync_softc *sc = (struct pfsync_softc *)arg;
struct ip_moptions *imo;
if (sc == NULL || sc->sc_sync_ifp != ifp)
- return; /* not for us; unlocked read */
+ return; /* not for us; unlocked read */
PF_LOCK();
@@ -1906,22 +2258,24 @@ pfsync_ifdetach(void *arg, struct ifnet *ifp)
imo = &sc->sc_imo;
if (imo->imo_num_memberships > 0) {
KASSERT(imo->imo_num_memberships == 1,
- ("%s: imo_num_memberships != 1", __func__));
+ ("%s: imo_num_memberships != 1", __func__));
/*
* Our event handler is always called after protocol
* domains have been detached from the underlying ifnet.
* Do not call in_delmulti(); we held a single reference
* which the protocol domain has purged in in_purgemaddrs().
*/
+ PF_UNLOCK();
imo->imo_membership[--imo->imo_num_memberships] = NULL;
+ PF_LOCK();
imo->imo_multicast_ifp = NULL;
}
PF_UNLOCK();
}
-static void
-pfsync_senddef(void *arg)
+void
+pfsync_senddef(void *arg, __unused int pending)
{
struct pfsync_softc *sc = (struct pfsync_softc *)arg;
struct mbuf *m;
@@ -1948,14 +2302,11 @@ pfsync_modevent(module_t mod, int type, void *data)
switch (type) {
case MOD_LOAD:
- LIST_INIT(&pfsync_list);
- if_clone_attach(&pfsync_cloner);
+ pfsyncattach(0);
break;
-
case MOD_UNLOAD:
if_clone_detach(&pfsync_cloner);
break;
-
default:
error = EINVAL;
break;
@@ -1974,4 +2325,5 @@ static moduledata_t pfsync_mod = {
DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
MODULE_VERSION(pfsync, PFSYNC_MODVER);
+MODULE_DEPEND(pflog, pf, PF_MODVER, PF_MODVER, PF_MODVER);
#endif /* __FreeBSD__ */
OpenPOWER on IntegriCloud