Author: glebius
Date: Fri Dec  9 17:59:15 2016
New Revision: 309746
URL: https://svnweb.freebsd.org/changeset/base/309746
Log:
  Use counter_ratecheck() in the ICMP rate limiting.
  
  Together with:        rrs, jtl

Modified:
  head/sys/netinet/icmp_var.h
  head/sys/netinet/ip_icmp.c
  head/sys/netpfil/pf/if_pfsync.c

Modified: head/sys/netinet/icmp_var.h
==============================================================================
--- head/sys/netinet/icmp_var.h Fri Dec  9 17:58:34 2016        (r309745)
+++ head/sys/netinet/icmp_var.h Fri Dec  9 17:59:15 2016        (r309746)
@@ -96,7 +96,7 @@ extern int badport_bandlim(int);
 #define BANDLIM_RST_OPENPORT 4   /* No connection, listener */
 #define BANDLIM_ICMP6_UNREACH 5
 #define BANDLIM_SCTP_OOTB 6
-#define BANDLIM_MAX 6
+#define BANDLIM_MAX 7
 #endif
 
 #endif

Modified: head/sys/netinet/ip_icmp.c
==============================================================================
--- head/sys/netinet/ip_icmp.c  Fri Dec  9 17:58:34 2016        (r309745)
+++ head/sys/netinet/ip_icmp.c  Fri Dec  9 17:59:15 2016        (r309746)
@@ -973,44 +973,59 @@ ip_next_mtu(int mtu, int dir)
  *     the 'final' error, but it doesn't make sense to solve the printing
  *     delay with more complex code.
  */
+struct icmp_rate {
+       const char *descr;
+       struct counter_rate cr;
+};
+static VNET_DEFINE(struct icmp_rate, icmp_rates[BANDLIM_MAX]) = {
+       { "icmp unreach response" },
+       { "icmp ping response" },
+       { "icmp tstamp response" },
+       { "closed port RST response" },
+       { "open port RST response" },
+       { "icmp6 unreach response" },
+       { "sctp ootb response" }
+};
+#define        V_icmp_rates    VNET(icmp_rates)
+
+static void
+icmp_bandlimit_init(void)
+{
+
+       for (int i = 0; i < BANDLIM_MAX; i++) {
+               V_icmp_rates[i].cr.cr_rate = counter_u64_alloc(M_WAITOK);
+               V_icmp_rates[i].cr.cr_ticks = ticks;
+       }
+}
+VNET_SYSINIT(icmp_bandlimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY,
+    icmp_bandlimit_init, NULL);
+
+static void
+icmp_bandlimit_uninit(void)
+{
+
+       for (int i = 0; i < BANDLIM_MAX; i++)
+               counter_u64_free(V_icmp_rates[i].cr.cr_rate);
+}
+VNET_SYSUNINIT(icmp_bandlimit, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,
+    icmp_bandlimit_uninit, NULL);
 
 int
 badport_bandlim(int which)
 {
+       int64_t pps;
 
-#define        N(a)    (sizeof (a) / sizeof (a[0]))
-       static struct rate {
-               const char      *type;
-               struct timeval  lasttime;
-               int             curpps;
-       } rates[BANDLIM_MAX+1] = {
-               { "icmp unreach response" },
-               { "icmp ping response" },
-               { "icmp tstamp response" },
-               { "closed port RST response" },
-               { "open port RST response" },
-               { "icmp6 unreach response" },
-               { "sctp ootb response" }
-       };
-
-       /*
-        * Return ok status if feature disabled or argument out of range.
-        */
-       if (V_icmplim > 0 && (u_int) which < N(rates)) {
-               struct rate *r = &rates[which];
-               int opps = r->curpps;
-
-               if (!ppsratecheck(&r->lasttime, &r->curpps, V_icmplim))
-                       return -1;      /* discard packet */
-               /*
-                * If we've dropped below the threshold after having
-                * rate-limited traffic print the message.  This preserves
-                * the previous behaviour at the expense of added complexity.
-                */
-               if (V_icmplim_output && opps > V_icmplim)
-                       log(LOG_NOTICE, "Limiting %s from %d to %d 
packets/sec\n",
-                               r->type, opps, V_icmplim);
-       }
-       return 0;                       /* okay to send packet */
-#undef N
+       if (V_icmplim == 0 || which == BANDLIM_UNLIMITED)
+               return (0);
+
+       KASSERT(which >= 0 && which < BANDLIM_MAX,
+           ("%s: which %d", __func__, which));
+
+       pps = counter_ratecheck(&V_icmp_rates[which].cr, V_icmplim);
+       if (pps == -1)
+               return (-1);
+       if (pps > 0 && V_icmplim_output)
+               log(LOG_NOTICE, "Limiting %s from %ld to %d packets/sec\n",
+                       V_icmp_rates[which].descr, pps, V_icmplim);
+       return (0);
 }

Modified: head/sys/netpfil/pf/if_pfsync.c
==============================================================================
--- head/sys/netpfil/pf/if_pfsync.c     Fri Dec  9 17:58:34 2016        
(r309745)
+++ head/sys/netpfil/pf/if_pfsync.c     Fri Dec  9 17:59:15 2016        
(r309746)
@@ -161,8 +161,8 @@ static struct pfsync_q pfsync_qs[] = {
        { pfsync_out_del,   sizeof(struct pfsync_del_c),   PFSYNC_ACT_DEL_C }
 };
 
-static void    pfsync_q_ins(struct pf_state *, int);
-static void    pfsync_q_del(struct pf_state *);
+static void    pfsync_q_ins(struct pf_state *, int, bool);
+static void    pfsync_q_del(struct pf_state *, bool);
 
 static void    pfsync_update_state(struct pf_state *);
 
@@ -542,7 +542,7 @@ pfsync_state_import(struct pfsync_state 
        if (!(flags & PFSYNC_SI_IOCTL)) {
                st->state_flags &= ~PFSTATE_NOSYNC;
                if (st->state_flags & PFSTATE_ACK) {
-                       pfsync_q_ins(st, PFSYNC_S_IACK);
+                       pfsync_q_ins(st, PFSYNC_S_IACK, true);
                        pfsync_push(sc);
                }
        }
@@ -1668,7 +1668,7 @@ pfsync_insert_state(struct pf_state *st)
        if (sc->sc_len == PFSYNC_MINPKT)
                callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, V_pfsyncif);
 
-       pfsync_q_ins(st, PFSYNC_S_INS);
+       pfsync_q_ins(st, PFSYNC_S_INS, true);
        PFSYNC_UNLOCK(sc);
 
        st->sync_updates = 0;
@@ -1789,7 +1789,7 @@ static void
 pfsync_update_state(struct pf_state *st)
 {
        struct pfsync_softc *sc = V_pfsyncif;
-       int sync = 0;
+       bool sync = false, ref = true;
 
        PF_STATE_LOCK_ASSERT(st);
        PFSYNC_LOCK(sc);
@@ -1798,7 +1798,7 @@ pfsync_update_state(struct pf_state *st)
                pfsync_undefer_state(st, 0);
        if (st->state_flags & PFSTATE_NOSYNC) {
                if (st->sync_state != PFSYNC_S_NONE)
-                       pfsync_q_del(st);
+                       pfsync_q_del(st, true);
                PFSYNC_UNLOCK(sc);
                return;
        }
@@ -1815,14 +1815,17 @@ pfsync_update_state(struct pf_state *st)
                if (st->key[PF_SK_WIRE]->proto == IPPROTO_TCP) {
                        st->sync_updates++;
                        if (st->sync_updates >= sc->sc_maxupdates)
-                               sync = 1;
+                               sync = true;
                }
                break;
 
        case PFSYNC_S_IACK:
-               pfsync_q_del(st);
+               pfsync_q_del(st, false);
+               ref = false;
+               /* FALLTHROUGH */
+
        case PFSYNC_S_NONE:
-               pfsync_q_ins(st, PFSYNC_S_UPD_C);
+               pfsync_q_ins(st, PFSYNC_S_UPD_C, ref);
                st->sync_updates = 0;
                break;
 
@@ -1880,13 +1883,14 @@ static void
 pfsync_update_state_req(struct pf_state *st)
 {
        struct pfsync_softc *sc = V_pfsyncif;
+       bool ref = true;
 
        PF_STATE_LOCK_ASSERT(st);
        PFSYNC_LOCK(sc);
 
        if (st->state_flags & PFSTATE_NOSYNC) {
                if (st->sync_state != PFSYNC_S_NONE)
-                       pfsync_q_del(st);
+                       pfsync_q_del(st, true);
                PFSYNC_UNLOCK(sc);
                return;
        }
@@ -1894,9 +1898,12 @@ pfsync_update_state_req(struct pf_state 
        switch (st->sync_state) {
        case PFSYNC_S_UPD_C:
        case PFSYNC_S_IACK:
-               pfsync_q_del(st);
+               pfsync_q_del(st, false);
+               ref = false;
+               /* FALLTHROUGH */
+
        case PFSYNC_S_NONE:
-               pfsync_q_ins(st, PFSYNC_S_UPD);
+               pfsync_q_ins(st, PFSYNC_S_UPD, true);
                pfsync_push(sc);
                break;
 
@@ -1917,13 +1924,14 @@ static void
 pfsync_delete_state(struct pf_state *st)
 {
        struct pfsync_softc *sc = V_pfsyncif;
+       bool ref = true;
 
        PFSYNC_LOCK(sc);
        if (st->state_flags & PFSTATE_ACK)
                pfsync_undefer_state(st, 1);
        if (st->state_flags & PFSTATE_NOSYNC) {
                if (st->sync_state != PFSYNC_S_NONE)
-                       pfsync_q_del(st);
+                       pfsync_q_del(st, true);
                PFSYNC_UNLOCK(sc);
                return;
        }
@@ -1931,30 +1939,27 @@ pfsync_delete_state(struct pf_state *st)
        if (sc->sc_len == PFSYNC_MINPKT)
                callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, V_pfsyncif);
 
-       pf_ref_state(st);
-
        switch (st->sync_state) {
        case PFSYNC_S_INS:
                /* We never got to tell the world so just forget about it. */
-               pfsync_q_del(st);
+               pfsync_q_del(st, true);
                break;
 
        case PFSYNC_S_UPD_C:
        case PFSYNC_S_UPD:
        case PFSYNC_S_IACK:
-               pfsync_q_del(st);
-               /* FALLTHROUGH to putting it on the del list */
+               pfsync_q_del(st, false);
+               ref = false;
+               /* FALLTHROUGH */
 
        case PFSYNC_S_NONE:
-               pfsync_q_ins(st, PFSYNC_S_DEL);
+               pfsync_q_ins(st, PFSYNC_S_DEL, ref);
                break;
 
        default:
                panic("%s: unexpected sync state %d", __func__, st->sync_state);
        }
 
-       pf_release_state(st);
-
        PFSYNC_UNLOCK(sc);
 }
 
@@ -1982,7 +1987,7 @@ pfsync_clear_states(u_int32_t creatorid,
 }
 
 static void
-pfsync_q_ins(struct pf_state *st, int q)
+pfsync_q_ins(struct pf_state *st, int q, bool ref)
 {
        struct pfsync_softc *sc = V_pfsyncif;
        size_t nlen = pfsync_qs[q].len;
@@ -2006,11 +2011,12 @@ pfsync_q_ins(struct pf_state *st, int q)
        sc->sc_len += nlen;
        TAILQ_INSERT_TAIL(&sc->sc_qs[q], st, sync_list);
        st->sync_state = q;
-       pf_ref_state(st);
+       if (ref)
+               pf_ref_state(st);
 }
 
 static void
-pfsync_q_del(struct pf_state *st)
+pfsync_q_del(struct pf_state *st, bool unref)
 {
        struct pfsync_softc *sc = V_pfsyncif;
        int q = st->sync_state;
@@ -2022,7 +2028,8 @@ pfsync_q_del(struct pf_state *st)
        sc->sc_len -= pfsync_qs[q].len;
        TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list);
        st->sync_state = PFSYNC_S_NONE;
-       pf_release_state(st);
+       if (unref)
+               pf_release_state(st);
 
        if (TAILQ_EMPTY(&sc->sc_qs[q]))
                sc->sc_len -= sizeof(struct pfsync_subheader);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to