Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 25 Jan 2019 13:31:46 +1300
From:      "Kristof Provost" <kristof@sigsegv.be>
To:        byrnejb@harte-lyne.ca
Cc:        freebsd-pf@freebsd.org
Subject:   Re: routing LAN traffic through/around a pf gateway
Message-ID:  <77538042-3448-4C7F-8499-F492A06E52E9@sigsegv.be>
In-Reply-To: <c3e5a147fa9548de5dea67be5e05f8bc.squirrel@webmail.harte-lyne.ca>
References:  <c3e5a147fa9548de5dea67be5e05f8bc.squirrel@webmail.harte-lyne.ca>

next in thread | previous in thread | raw e-mail | index | archive | help


On 25 Jan 2019, at 9:37, James B. Byrne via freebsd-pf wrote:

> I have limited knowledge of PF being in the process of transitioning
> from 20+ years of RHEL/CentOS to FreeBSD.  Neither do I possess a
> great fund of knowledge respecting IP routing.  That said this is my
> problem:
>
> On a small test LAN I have three hosts, W44, W4 and G5:
>
> network layout, gateway address 216.185.71.5
>
>      W44                 G5                  w4
> 216.185.71.44 ----> 216.185.71.5        216.185.71.4   int_if IP
> 192.168.150.44      192.168.150.5 ----> 192.168.150.4  int_if IP alias
>
> Using ssh and with PF running on the gateway, when I connect from
> 216.185.71.44 to 216.185.71.4 then the ssh session operates normally.
> However, if instead I connect from 216.185.71.44 to 192.168.150.4 then
> the initial connection is made but the ssh session remains responsive
> for a brief time before it becomes non-responsive.  If I terminate the
> PF running on the gateway the ssh session again becomes responsive.
> If I do not terminate PF then eventually the ssh session client
> disconnects with a timeout error.
>
> Besides macros the entire active contents of pf.conf on G5 are:
>
> scrub         in        all no-df max-mss 1440 fragment reassemble
>
> block return  out log   all
>
> block drop    in  log   all
>
> pass              log   on $int_if
>
> pass                    inet proto icmp all \
>                         icmp-type $icmp_types keep state
>
> pass          out       quick on $ext_if inet proto udp \
>                   from  any \
>                   to    any         port  33433 >< 33626 keep state
>
> Which results in these rules when PF is running:
>
> @0 scrub in all no-df max-mss 1440 fragment reassemble
> @1 block return out log all
> @2 block drop in log all
> @3 pass log on em0 all flags S/SA keep state
> @4 pass inet proto icmp all icmp-type echoreq keep state
> @5 pass inet proto icmp all icmp-type unreach keep state
> @6 pass out quick on em1 inet proto udp from any to any port 33433 ><
> 33626 keep state
>
You don’t appear to have a rule permitting the SSH traffic to pass 
through your router.
I’m a more than little surprised you manage to establish a connection 
in the first place.
Unless the connection existed before you started pf, of course.

Try adding something like:
pass inet porto tcp port 22

Regards,
Kristof
From owner-freebsd-pf@freebsd.org  Fri Jan 25 13:14:18 2019
Return-Path: <owner-freebsd-pf@freebsd.org>
Delivered-To: freebsd-pf@mailman.ysv.freebsd.org
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1])
 by mailman.ysv.freebsd.org (Postfix) with ESMTP id 2D6F114B561D
 for <freebsd-pf@mailman.ysv.freebsd.org>; Fri, 25 Jan 2019 13:14:18 +0000 (UTC)
 (envelope-from kib@freebsd.org)
Received: from kib.kiev.ua (kib.kiev.ua [IPv6:2001:470:d5e7:1::1])
 (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
 (Client did not present a certificate)
 by mx1.freebsd.org (Postfix) with ESMTPS id A9D9282F04;
 Fri, 25 Jan 2019 13:14:17 +0000 (UTC) (envelope-from kib@freebsd.org)
Received: from tom.home (kib@localhost [127.0.0.1])
 by kib.kiev.ua (8.15.2/8.15.2) with ESMTPS id x0PDEApu032336
 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO);
 Fri, 25 Jan 2019 15:14:13 +0200 (EET) (envelope-from kib@freebsd.org)
DKIM-Filter: OpenDKIM Filter v2.10.3 kib.kiev.ua x0PDEApu032336
Received: (from kostik@localhost)
 by tom.home (8.15.2/8.15.2/Submit) id x0PDE9Z2032335;
 Fri, 25 Jan 2019 15:14:09 +0200 (EET) (envelope-from kib@freebsd.org)
X-Authentication-Warning: tom.home: kostik set sender to kib@freebsd.org using
 -f
Date: Fri, 25 Jan 2019 15:14:09 +0200
From: Konstantin Belousov <kib@freebsd.org>
To: Andreas Longwitz <longwitz@incore.de>
Cc: freebsd-pf@freebsd.org, Gleb Smirnoff <glebius@freebsd.org>,
 Kristof Provost <kristof@sigsegv.be>
Subject: Re: rdr pass for proto tcp sometimes creates states with expire time
 zero and so breaking connections
Message-ID: <20190125131409.GZ24863@kib.kiev.ua>
References: <5BC51424.5000309@incore.de>
 <C4D1F141-2979-4103-957F-F0314637D978@sigsegv.be>
 <5BD45882.1000207@incore.de>
 <D5EEA773-1F0F-4FA0-A39A-486EE323907D@sigsegv.be>
 <5BEB3B9A.9080402@incore.de> <20181113222533.GJ9744@FreeBSD.org>
 <5C49ECAA.7060505@incore.de> <20190124203802.GU24863@kib.kiev.ua>
 <5C4A37A1.80206@incore.de>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <5C4A37A1.80206@incore.de>
User-Agent: Mutt/1.11.2 (2019-01-07)
X-Spam-Status: No, score=-2.9 required=5.0 tests=ALL_TRUSTED,BAYES_00
 autolearn=ham autolearn_force=no version=3.4.2
X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on tom.home
X-BeenThere: freebsd-pf@freebsd.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: "Technical discussion and general questions about packet filter
 \(pf\)" <freebsd-pf.freebsd.org>
List-Unsubscribe: <https://lists.freebsd.org/mailman/options/freebsd-pf>,
 <mailto:freebsd-pf-request@freebsd.org?subject=unsubscribe>
List-Archive: <http://lists.freebsd.org/pipermail/freebsd-pf/>;
List-Post: <mailto:freebsd-pf@freebsd.org>
List-Help: <mailto:freebsd-pf-request@freebsd.org?subject=help>
List-Subscribe: <https://lists.freebsd.org/mailman/listinfo/freebsd-pf>,
 <mailto:freebsd-pf-request@freebsd.org?subject=subscribe>
X-List-Received-Date: Fri, 25 Jan 2019 13:14:18 -0000

On Thu, Jan 24, 2019 at 11:09:37PM +0100, Andreas Longwitz wrote:
> >> I think the problem is the cmpxchg8b instruction used in
> >> counter_u64_fetch(), because this machine instruction always writes to
> >> memory, also when we only want to read and have (EDX:EAX) = (ECX:EBX):
> >>
> >>     TEMP64 <- DEST
> >>     IF (EDX:EAX = TEMP64)
> >>        THEN
> >>           ZF <- 1
> >>           DEST <- ECX:EBX
> >>        ELSE
> >>           ZF <- 0
> >>           EDX:EAX <- TEMP64
> >>           DEST <- TEMP64
> >>     FI
> >>
> >> If one CPU increments the counter in pf_create_state() and another does
> >> the fetch, then both CPU's may run the xmpxschg8b at once with the
> >> chance that both read the same memory value in TEMP64 and the fetching
> >> CPU is the second CPU that writes and so the increment is lossed. Thats
> >> what I see without the above patch two or three times a week.
> > 
> > Please try the following patch.  The idea is to make the value to compare
> > with unlikely to be equal to the memory content, for fetch_one().
> 
> During my research I first had the same idea, but it did not work. In
> the actual coding eax/edx is not well defined before cmpxchg8b is
> executed, but it does not help for the problem to do so.
> 
> > Also it fixes a silly bug in zero_one().
> > 
> > diff --git a/sys/i386/include/counter.h b/sys/i386/include/counter.h
> > index 7fd26d2a960..aa20831ba18 100644
> > --- a/sys/i386/include/counter.h
> > +++ b/sys/i386/include/counter.h
> > @@ -78,6 +78,9 @@ counter_u64_read_one_8b(uint64_t *p)
> >  	uint32_t res_lo, res_high;
> >  
> >  	__asm __volatile(
> > +	"movl	(%0),%%eax\n\t"
> > +	"movl	4(%0),%%edx\n\t"
> > +	"addl	$0x10000000,%%edx\n\t"	/* avoid write */
> >  	"movl	%%eax,%%ebx\n\t"
> >  	"movl	%%edx,%%ecx\n\t"
> >  	"cmpxchg8b	(%2)"
> 
> We can not avoid the write done by cmpxchg8b as can be seen from the
> microcode given above, we always end up with "DEST <- TEMP". From the
> Intel instruction reference manual:
> 
> The destination operand is written back if the comparision fails. (The
> processor never produces a locked read without also producing a locked
> write).
I see, AMD APM is more clear there, stating that the instruction always
do rmw regardless of lock prefix.

> 
> Maybe it is enough to prefix the cmpxchg8b with LOCK only in function
> counter_u64_read_one_8b().
I am not sure.  Lets switch to IPI method for fetch, similar to clear.
I do not think that the cost of fetch is too important comparing with
the race.

> 
> 
> > @@ -120,11 +123,11 @@ counter_u64_zero_one_8b(uint64_t *p)
> >  {
> >  	__asm __volatile(
> > +"\n1:\n\t"
> >  	"movl	(%0),%%eax\n\t"
> > -	"movl	4(%0),%%edx\n"
> > +	"movl	4(%0),%%edx\n\t"
> >  	"xorl	%%ebx,%%ebx\n\t"
> >  	"xorl	%%ecx,%%ecx\n\t"
> > -"1:\n\t"
> >  	"cmpxchg8b	(%0)\n\t"
> >  	"jnz	1b"
> >  	:
> 
> If jnz jumps back the instruction cmpxchg8b has load registers eax/edx
> with (%0), therefor I do not understand the silly bug.
Ignore me.


diff --git a/sys/i386/include/counter.h b/sys/i386/include/counter.h
index 7fd26d2a960..278f89123a4 100644
--- a/sys/i386/include/counter.h
+++ b/sys/i386/include/counter.h
@@ -72,7 +72,12 @@ counter_64_inc_8b(uint64_t *p, int64_t inc)
 }
 
 #ifdef IN_SUBR_COUNTER_C
-static inline uint64_t
+struct counter_u64_fetch_cx8_arg {
+	uint64_t res;
+	uint64_t *p;
+};
+
+static uint64_t
 counter_u64_read_one_8b(uint64_t *p)
 {
 	uint32_t res_lo, res_high;
@@ -87,9 +92,22 @@ counter_u64_read_one_8b(uint64_t *p)
 	return (res_lo + ((uint64_t)res_high << 32));
 }
 
+static void
+counter_u64_fetch_cx8_one(void *arg1)
+{
+	struct counter_u64_fetch_cx8_arg *arg;
+	uint64_t val;
+
+	arg = arg1;
+	val = counter_u64_read_one_8b((uint64_t *)((char *)arg->p +
+	    UMA_PCPU_ALLOC_SIZE * PCPU_GET(cpuid)));
+	atomic_add_64(&arg->res, val);
+}
+
 static inline uint64_t
 counter_u64_fetch_inline(uint64_t *p)
 {
+	struct counter_u64_fetch_cx8_arg arg;
 	uint64_t res;
 	int i;
 
@@ -108,9 +126,10 @@ counter_u64_fetch_inline(uint64_t *p)
 		}
 		critical_exit();
 	} else {
-		CPU_FOREACH(i)
-			res += counter_u64_read_one_8b((uint64_t *)((char *)p +
-			    UMA_PCPU_ALLOC_SIZE * i));
+		arg.p = p;
+		arg.res = 0;
+		smp_rendezvous(NULL, counter_u64_fetch_cx8_one, NULL, &arg);
+		res = arg.res;
 	}
 	return (res);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?77538042-3448-4C7F-8499-F492A06E52E9>