From owner-freebsd-ipfw@FreeBSD.ORG Sun Apr 21 03:30:02 2013 Return-Path: Delivered-To: freebsd-ipfw@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 07179AA4 for ; Sun, 21 Apr 2013 03:30:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id EEB43FB for ; Sun, 21 Apr 2013 03:30:01 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3L3U1gn088730 for ; Sun, 21 Apr 2013 03:30:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3L3U1c5088729; Sun, 21 Apr 2013 03:30:01 GMT (envelope-from gnats) Date: Sun, 21 Apr 2013 03:30:01 GMT Message-Id: <201304210330.r3L3U1c5088729@freefall.freebsd.org> To: freebsd-ipfw@FreeBSD.org Cc: From: Ian Smith Subject: Re: kern/177948: [ipfw] ipfw fails to parse port ranges (p1-p2) for udp X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: Ian Smith List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 21 Apr 2013 03:30:02 -0000 The following reply was made to PR kern/177948; it has been noted by GNATS. From: Ian Smith To: bug-followup@FreeBSD.org, jau@oxit.fi Cc: Subject: Re: kern/177948: [ipfw] ipfw fails to parse port ranges (p1-p2) for udp Date: Sun, 21 Apr 2013 12:17:12 +1000 I can't reproduce this on 9.1-RELEASE, unless I put a space anywhere amongst p1, '-' and p2, in which case I see the same error you show. # ipfw add 03011 deny log udp from any to any 1024-65535 in recv fxp0 03011 deny log udp from any to any dst-port 1024-65535 in recv fxp0 # ipfw list 3011 03011 deny log udp from any to any dst-port 1024-65535 in recv fxp0 # ipfw add 03011 deny log udp from any to any 1024 -65535 in recv fxp0 ipfw: unrecognised option [-1] -65535 # ipfw add 03011 deny log udp from any to any 1024- 65535 in recv fxp0 ipfw: unrecognised option [-1] 1024- Can you verify that there is no whitespace (obvious, or perhaps some non-printing character?) on or near line 7368 of your config file? If that looks ok, can you show the byte offset of that line in your file, for example by placing that line at the bottom of the screen in less(1) then pressing '='? cheers, Ian From owner-freebsd-ipfw@FreeBSD.ORG Sun Apr 21 11:40:02 2013 Return-Path: Delivered-To: freebsd-ipfw@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 4BD02839 for ; Sun, 21 Apr 2013 11:40:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 3DA1F106A for ; Sun, 21 Apr 2013 11:40:02 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3LBe1te011589 for ; Sun, 21 Apr 2013 11:40:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3LBe1cT011588; Sun, 21 Apr 2013 11:40:01 GMT (envelope-from gnats) Date: Sun, 21 Apr 2013 11:40:01 GMT Message-Id: <201304211140.r3LBe1cT011588@freefall.freebsd.org> To: freebsd-ipfw@FreeBSD.org Cc: From: Jukka Ukkonen Subject: Re: kern/177948: [ipfw] ipfw fails to parse port ranges (p1-p2) for udp X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: Jukka Ukkonen List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 21 Apr 2013 11:40:02 -0000 The following reply was made to PR kern/177948; it has been noted by GNATS. From: Jukka Ukkonen To: Ian Smith Cc: bug-followup@FreeBSD.org Subject: Re: kern/177948: [ipfw] ipfw fails to parse port ranges (p1-p2) for udp Date: Sun, 21 Apr 2013 14:33:07 +0300 On 04/21/13 05:17, Ian Smith wrote: > I can't reproduce this on 9.1-RELEASE, unless I put a space anywhere > amongst p1, '-' and p2, in which case I see the same error you show. > > # ipfw add 03011 deny log udp from any to any 1024-65535 in recv fxp0 > 03011 deny log udp from any to any dst-port 1024-65535 in recv fxp0 > # ipfw list 3011 > 03011 deny log udp from any to any dst-port 1024-65535 in recv fxp0 > > # ipfw add 03011 deny log udp from any to any 1024 -65535 in recv fxp0 > ipfw: unrecognised option [-1] -65535 > > # ipfw add 03011 deny log udp from any to any 1024- 65535 in recv fxp0 > ipfw: unrecognised option [-1] 1024- > > Can you verify that there is no whitespace (obvious, or perhaps some > non-printing character?) on or near line 7368 of your config file? > > If that looks ok, can you show the byte offset of that line in your > file, for example by placing that line at the bottom of the screen in > less(1) then pressing '='? > > cheers, Ian Right, After some further inspection I have news... This seems to be a problem in clang-cpp which adds an extra space before the dash in a macro which should have a value of the format "number1-number2". So, e.g. "1024-65535" becomes "1024 -65535". If I use gcpp instead, everything works just fine with ipfw. The fact that I did not see this happening with TCP rules as well was just lucky coincidence. So, this is a clang problem, not an ipfw problem!!! Cheers, --jau From owner-freebsd-ipfw@FreeBSD.ORG Sun Apr 21 12:30:01 2013 Return-Path: Delivered-To: freebsd-ipfw@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 7EB6135D for ; Sun, 21 Apr 2013 12:30:01 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 7173C120E for ; Sun, 21 Apr 2013 12:30:01 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3LCU1RX021174 for ; Sun, 21 Apr 2013 12:30:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3LCU1Sq021173; Sun, 21 Apr 2013 12:30:01 GMT (envelope-from gnats) Date: Sun, 21 Apr 2013 12:30:01 GMT Message-Id: <201304211230.r3LCU1Sq021173@freefall.freebsd.org> To: freebsd-ipfw@FreeBSD.org Cc: From: Ian Smith Subject: Re: kern/177948: [ipfw] ipfw fails to parse port ranges (p1-p2) for udp X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: Ian Smith List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 21 Apr 2013 12:30:01 -0000 The following reply was made to PR kern/177948; it has been noted by GNATS. From: Ian Smith To: Jukka Ukkonen Cc: bug-followup@FreeBSD.org Subject: Re: kern/177948: [ipfw] ipfw fails to parse port ranges (p1-p2) for udp Date: Sun, 21 Apr 2013 22:21:06 +1000 (EST) On Sun, 21 Apr 2013 14:33:07 +0300, Jukka Ukkonen wrote: > On 04/21/13 05:17, Ian Smith wrote: > > I can't reproduce this on 9.1-RELEASE, unless I put a space anywhere > > amongst p1, '-' and p2, in which case I see the same error you show. [..] > Right, > > After some further inspection I have news... > > This seems to be a problem in clang-cpp which adds an extra space > before the dash in a macro which should have a value of the format > "number1-number2". So, e.g. "1024-65535" becomes "1024 -65535". Naughty clang! For one thing, that's emitting two values .. > If I use gcpp instead, everything works just fine with ipfw. > > The fact that I did not see this happening with TCP rules as well was > just lucky coincidence. > > So, this is a clang problem, not an ipfw problem!!! > > Cheers, > --jau Good news for ipfw, anyway. I don't know the correct form .. should this PR be reassigned, or closed with a reference in a fresh clang PR? cheers, Ian From owner-freebsd-ipfw@FreeBSD.ORG Sun Apr 21 12:40:01 2013 Return-Path: Delivered-To: freebsd-ipfw@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 71D6D401 for ; Sun, 21 Apr 2013 12:40:01 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 625B11242 for ; Sun, 21 Apr 2013 12:40:01 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3LCe19I022803 for ; Sun, 21 Apr 2013 12:40:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3LCe19j022802; Sun, 21 Apr 2013 12:40:01 GMT (envelope-from gnats) Date: Sun, 21 Apr 2013 12:40:01 GMT Message-Id: <201304211240.r3LCe19j022802@freefall.freebsd.org> To: freebsd-ipfw@FreeBSD.org Cc: From: Jukka Ukkonen Subject: Re: kern/177948: [ipfw] ipfw fails to parse port ranges (p1-p2) for udp X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: Jukka Ukkonen List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 21 Apr 2013 12:40:01 -0000 The following reply was made to PR kern/177948; it has been noted by GNATS. From: Jukka Ukkonen To: Ian Smith Cc: bug-followup@FreeBSD.org Subject: Re: kern/177948: [ipfw] ipfw fails to parse port ranges (p1-p2) for udp Date: Sun, 21 Apr 2013 15:33:03 +0300 On 04/21/13 15:21, Ian Smith wrote: > On Sun, 21 Apr 2013 14:33:07 +0300, Jukka Ukkonen wrote: > > On 04/21/13 05:17, Ian Smith wrote: > > > I can't reproduce this on 9.1-RELEASE, unless I put a space anywhere > > > amongst p1, '-' and p2, in which case I see the same error you show. > [..] > > > Right, > > > > After some further inspection I have news... > > > > This seems to be a problem in clang-cpp which adds an extra space > > before the dash in a macro which should have a value of the format > > "number1-number2". So, e.g. "1024-65535" becomes "1024 -65535". > > Naughty clang! For one thing, that's emitting two values .. > > > If I use gcpp instead, everything works just fine with ipfw. > > > > The fact that I did not see this happening with TCP rules as well was > > just lucky coincidence. > > > > So, this is a clang problem, not an ipfw problem!!! > > > > Cheers, > > --jau > > Good news for ipfw, anyway. I don't know the correct form .. should > this PR be reassigned, or closed with a reference in a fresh clang PR? > > cheers, Ian Please, try reassigning first. This is anyhow a pretty clear issue. If the clang experts then wish to have a separate fresh PR for clang, they can close this one and request a new PR. Cheers, --jau From owner-freebsd-ipfw@FreeBSD.ORG Mon Apr 22 11:06:46 2013 Return-Path: Delivered-To: freebsd-ipfw@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 3FFF85AE for ; Mon, 22 Apr 2013 11:06:46 +0000 (UTC) (envelope-from owner-bugmaster@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 30FF0107C for ; Mon, 22 Apr 2013 11:06:46 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3MB6kjr089135 for ; Mon, 22 Apr 2013 11:06:46 GMT (envelope-from owner-bugmaster@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3MB6jH0089133 for freebsd-ipfw@FreeBSD.org; Mon, 22 Apr 2013 11:06:45 GMT (envelope-from owner-bugmaster@FreeBSD.org) Date: Mon, 22 Apr 2013 11:06:45 GMT Message-Id: <201304221106.r3MB6jH0089133@freefall.freebsd.org> X-Authentication-Warning: freefall.freebsd.org: gnats set sender to owner-bugmaster@FreeBSD.org using -f From: FreeBSD bugmaster To: freebsd-ipfw@FreeBSD.org Subject: Current problem reports assigned to freebsd-ipfw@FreeBSD.org X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 22 Apr 2013 11:06:46 -0000 Note: to view an individual PR, use: http://www.freebsd.org/cgi/query-pr.cgi?pr=(number). The following is a listing of current problems submitted by FreeBSD users. These represent problem reports covering all versions including experimental development code and obsolete releases. S Tracker Resp. Description -------------------------------------------------------------------------------- o kern/177948 ipfw [ipfw] ipfw fails to parse port ranges (p1-p2) for udp o kern/176503 ipfw [ipfw] ipfw layer2 problem o kern/174749 ipfw Unexpected change of default route o kern/169206 ipfw [ipfw] ipfw does not flush entries in table o conf/167822 ipfw [ipfw] [patch] start script doesn't load firewall_type o kern/166406 ipfw [ipfw] ipfw does not set ALTQ identifier for ipv6 traf o kern/165939 ipfw [ipfw] bug: incomplete firewall rules loaded if tables o kern/165190 ipfw [ipfw] [lo] [patch] loopback interface is not marking o kern/158066 ipfw [ipfw] ipfw + netgraph + multicast = multicast packets o kern/157796 ipfw [ipfw] IPFW in-kernel NAT nat loopback / Default Route o kern/157689 ipfw [ipfw] ipfw nat config does not accept nonexistent int f kern/155927 ipfw [ipfw] ipfw stops to check packets for compliance with o bin/153252 ipfw [ipfw][patch] ipfw lockdown system in subsequent call o kern/153161 ipfw [ipfw] does not support specifying rules with ICMP cod o kern/152113 ipfw [ipfw] page fault on 8.1-RELEASE caused by certain amo o kern/148827 ipfw [ipfw] divert broken with in-kernel ipfw o kern/148430 ipfw [ipfw] IPFW schedule delete broken. o kern/148091 ipfw [ipfw] ipfw ipv6 handling broken. f kern/143973 ipfw [ipfw] [panic] ipfw forward option causes kernel reboo o kern/143621 ipfw [ipfw] [dummynet] [patch] dummynet and vnet use result o kern/137346 ipfw [ipfw] ipfw nat redirect_proto is broken o kern/137232 ipfw [ipfw] parser troubles o kern/135476 ipfw [ipfw] IPFW table breaks after adding a large number o o kern/129036 ipfw [ipfw] 'ipfw fwd' does not change outgoing interface n o kern/127230 ipfw [ipfw] [patch] Feature request to add UID and/or GID l f kern/122963 ipfw [ipfw] tcpdump does not show packets redirected by 'ip s kern/121807 ipfw [request] TCP and UDP port_table in ipfw o kern/116009 ipfw [ipfw] [patch] Ignore errors when loading ruleset from o bin/104921 ipfw [patch] ipfw(8) sometimes treats ipv6 input as ipv4 (a o kern/104682 ipfw [ipfw] [patch] Some minor language consistency fixes a o kern/103454 ipfw [ipfw] [patch] [request] add a facility to modify DF b o kern/103328 ipfw [ipfw] [request] sugestions about ipfw table o kern/97951 ipfw [ipfw] [patch] ipfw does not tie interface details to o kern/95084 ipfw [ipfw] [regression] [patch] IPFW2 ignores "recv/xmit/v o kern/86957 ipfw [ipfw] [patch] ipfw mac logging o bin/83046 ipfw [ipfw] ipfw2 error: "setup" is allowed for icmp, but s o kern/82724 ipfw [ipfw] [patch] [request] Add setnexthop and defaultrou o bin/78785 ipfw [patch] ipfw(8) verbosity locks machine if /etc/rc.fir o kern/60719 ipfw [ipfw] Headerless fragments generate cryptic error mes s kern/55984 ipfw [ipfw] [patch] time based firewalling support for ipfw o kern/48172 ipfw [ipfw] [patch] ipfw does not log size and flags o kern/46159 ipfw [ipfw] [patch] [request] ipfw dynamic rules lifetime f a kern/26534 ipfw [ipfw] Add an option to ipfw to log gid/uid of who cau 43 problems total. From owner-freebsd-ipfw@FreeBSD.ORG Wed Apr 24 13:11:27 2013 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id D86552AF for ; Wed, 24 Apr 2013 13:11:27 +0000 (UTC) (envelope-from prvs=1826e4a5c1=agave.spring@cadamericas.com) Received: from cadamericas.com (mail02.amotive.com [173.164.153.20]) by mx1.freebsd.org (Postfix) with ESMTP id A7B2E143F for ; Wed, 24 Apr 2013 13:11:27 +0000 (UTC) Received: from agave.cadamericas.com ([64.183.139.162]) by amotive.com (mail02.amotive.com) (MDaemon PRO v13.0.2) with ESMTP id md50001684604.msg; Wed, 24 Apr 2013 06:09:51 -0700 X-Spam-Processed: mail02.amotive.com, Wed, 24 Apr 2013 06:09:51 -0700 (not processed: message from trusted or authenticated source) X-MDRemoteIP: 64.183.139.162 X-Return-Path: prvs=1826e4a5c1=agave.spring@cadamericas.com X-Envelope-From: agave.spring@cadamericas.com X-MDaemon-Deliver-To: freebsd-ipfw@freebsd.org Date: Wed, 24 Apr 2013 06:09:04 -0700 To: freebsd-ipfw From: CAD Americas Subject: CAD Americas Training Days Sessions Announced Message-ID: <9b1b5a268e19c3ed3a34e18a0a6f2d73@agave.cadamericas.com> X-Priority: 3 X-Mailer: PHPMailer 5.2.1 (http://code.google.com/a/apache-extras.org/p/phpmailer/) X-CampTrackID: b8aa9cd4-f01c-8bac-08ea-5177d96af25a MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Content-Filtered-By: Mailman/MimeDel 2.1.14 X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: CAD Americas List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Apr 2013 13:11:27 -0000 ATTEND CAD AMERICAS TRAINING DAYS =E2=80=A6 and reach new heights! =0AMark = your calendar: A CAD Americas Training Day is coming to your area this Spri= ng! Join us for this one-day training event with an information-packed agen= da of topics important to you. Whether your focus is Mechanical Design, Con= struction, BIM, Electrical Design or Plant Design, there will be sessions t= hat will improve your productivity immediately!=0AIMPROVE YOUR PERFORMANCE = WITH NEW TOOLS AND TECHNIQUES=0A=0A=0A=0A=0ARick Ellis Civil 3D ExpertMore= =0ARobert Green CAD Mgmt ExpertMore=0ASteve Schain AutoCAD ExpertMore=0ATod= Stephens Revit ExpertMore=0ALearn from well-known industry instructors who= will share best practices and trends, product tips and tricks, new feature= s =E2=80=A6 and more.=0AImprove your productivity with new techniques that = you can put to work right away.=0AMeet your peers and exchange ideas on how= to best use the CAD tools you have to meet the demands of your job.=0ATake= a closer look at services and technologies offered by resellers in your ar= ea.=0ACHECK FOR A DATE IN YOUR LOCATION =E2=80=A6 AND REGISTER TODAY!=0A=0A= =C2=A0April 17 =E2=80=93 San Jose, CA April 18 =E2=80=93 San Bernardino, C= A =0A=0A=0A April 23 =E2=80=93 Cleveland, OH =C2=A0 April 24 =E2=80=93 Detr= oit, MI =0A=0A=0A April 25 =E2=80=93 Cincinnati, OH =C2=A0 April 30 =E2=80= =93 Atlanta, GA May 1 =E2=80=93 Dallas, TX =0A=0ACOMPLETE THIS SURVEY AND I= NFLUENCE THE SESSION CONTENT Tell us what session content you're looking fo= r. Take this survey today =E2=80=A6 and enter a drawing to win a free CAD A= mericas registration.=0AREGISTER BY MARCH 27TH AND SAVE Register for this C= AD Americas Training Day by March 27th and save.=0AEarly Bird Rate: $150 (U= ntil March 27th)=0AStandard Rate: $195 (AFTER March 27th)=0AStudent/Faculty= Rate: $95 (must present current student ID upon check-in at registration)= =0AREGISTER FOR CAD AMERICAS TRAINING TODAY! =0A=0A=0A=0A Join us at=0A=0A= =0A=0A=0A=0A=0A=0A=0A To Unsubscribe please click=C2=A0 Opt-Out=0A From owner-freebsd-ipfw@FreeBSD.ORG Wed Apr 24 16:02:25 2013 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id B3547F30; Wed, 24 Apr 2013 16:02:25 +0000 (UTC) (envelope-from melifaro@FreeBSD.org) Received: from mail.ipfw.ru (unknown [IPv6:2a01:4f8:120:6141::2]) by mx1.freebsd.org (Postfix) with ESMTP id D54081D87; Wed, 24 Apr 2013 16:02:24 +0000 (UTC) Received: from dhcp170-36-red.yandex.net ([95.108.170.36]) by mail.ipfw.ru with esmtpsa (TLSv1:CAMELLIA256-SHA:256) (Exim 4.76 (FreeBSD)) (envelope-from ) id 1UV2Cd-0008H9-1d; Wed, 24 Apr 2013 20:05:51 +0400 Message-ID: <517801D3.5040502@FreeBSD.org> Date: Wed, 24 Apr 2013 20:01:23 +0400 From: "Alexander V. Chernikov" User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:17.0) Gecko/20130418 Thunderbird/17.0.5 MIME-Version: 1.0 To: freebsd-ipfw@freebsd.org Subject: [patch] ipfw interface tracking and opcode rewriting Content-Type: multipart/mixed; boundary="------------060008050505010104000604" Cc: luigi@freebsd.org X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Apr 2013 16:02:25 -0000 This is a multi-part message in MIME format. --------------060008050505010104000604 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Hello list! Currently ipfw uses strncmp() function to do interface matching which is quite slow. Additionally, ipfw_insn_if opcode is quite big and given that struct ip_fw occupy 48 bytes (without first instruction) which gives us good chance that part of interface name will be on the second cache line on amd64. Pure synthetic testing (ipfw with 1 and 2 'ipfw count ip from any to any recv ifaceX') shows about 3.8% performance loss (190kpps out of 5.1 mpps) for each rule, while indexed version shows about 2.0% and 1.2% for first and second rule. Additionally, our production (8.3-based firewalls with old strncmp) shows about 40% kernel time spent in strncmp on 1-2mpps (each packet traverses 5-6 such rules). Here is the patch which does the following: 1) adds interface tracking for ipfw. Every interface is tracked regardless of its usage in the ruleset. This simplifies locking and makes easier to port such functionality to userland. 2) adds general opcode rewriting system permitting kernel to algorithmically (stateless) or statefully (involving extrernal data) rewrite user-supplied opcodes with possible size change. This can be used to deprecate opcodes which are now superseded by newer ones while keeping ABI (and we currently have such opcodes). 3) Store (and track) inderface index for non-wildcard interface inside opcode. If there are no objections I would like to commit (possibly updated vesrion) in the middle of the next week. --------------060008050505010104000604 Content-Type: text/plain; charset=UTF-8; name="ip_fw_rewrite3.diff" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="ip_fw_rewrite3.diff" SW5kZXg6IHN5cy9uZXRpbmV0L2lwX2Z3LmgKPT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQotLS0gc3lzL25ldGlu ZXQvaXBfZncuaAkocmV2aXNpb24gMjQ4NzA0KQorKysgc3lzL25ldGluZXQvaXBfZncuaAko d29ya2luZyBjb3B5KQpAQCAtMzQxLDYgKzM0MSw3IEBAIHR5cGVkZWYgc3RydWN0CV9pcGZ3 X2luc25faWYgewogCXVuaW9uIHsKIAkJc3RydWN0IGluX2FkZHIgaXA7CiAJCWludCBnbG9i OworCQl1bnNpZ25lZCBpbnQgaWZfaWR4OwkvKiBJbnRlcmZhY2UgaW5kZXggKGtlcm5lbCkg Ki8KIAl9IHA7CiAJY2hhciBuYW1lW0lGTkFNU0laXTsKIH0gaXBmd19pbnNuX2lmOwpAQCAt NDk1LDYgKzQ5Niw4IEBAIHR5cGVkZWYgc3RydWN0IF9pcGZ3X2luc25faWNtcDYgewogICoJ cXVldWUoMykgbWFjcm9zIGZvciBwb3J0YWJpbGl0eSBhbmQgcmVhZGFiaWxpdHkuCiAgKi8K IAorI2RlZmluZQlJUF9GV19SVUxFX1JFV1JJVFRFTgkweDAxCS8qIFJ1bGUgaXMgbW9kaWZp ZWQgYnkgcmV3cml0ZXIgKi8KKwogc3RydWN0IGlwX2Z3IHsKIAlzdHJ1Y3QgaXBfZncJKnhf bmV4dDsJLyogbGlua2VkIGxpc3Qgb2YgcnVsZXMJCSovCiAJc3RydWN0IGlwX2Z3CSpuZXh0 X3J1bGU7CS8qIHB0ciB0byBuZXh0IFtza2lwdG9dIHJ1bGUJKi8KQEAgLTUwNSw3ICs1MDgs NyBAQCBzdHJ1Y3QgaXBfZncgewogCXVpbnQxNl90CXJ1bGVudW07CS8qIHJ1bGUgbnVtYmVy CQkJKi8KIAl1aW50OF90CXNldDsJCS8qIHJ1bGUgc2V0ICgwLi4zMSkJCSovCiAjZGVmaW5l CVJFU1ZEX1NFVAkzMQkvKiBzZXQgZm9yIGRlZmF1bHQgYW5kIHBlcnNpc3RlbnQgcnVsZXMg Ki8KLQl1aW50OF90CQlfcGFkOwkJLyogcGFkZGluZwkJCSovCisJdWludDhfdAkJZmxhZ3M7 CQkvKiBwYWRkaW5nCQkJKi8KIAl1aW50MzJfdAlpZDsJCS8qIHJ1bGUgaWQgKi8KIAogCS8q IFRoZXNlIGZpZWxkcyBhcmUgcHJlc2VudCBpbiBhbGwgcnVsZXMuCQkJKi8KSW5kZXg6IHN5 cy9tb2R1bGVzL2lwZncvTWFrZWZpbGUKPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQotLS0gc3lzL21vZHVsZXMv aXBmdy9NYWtlZmlsZQkocmV2aXNpb24gMjQ4NzA0KQorKysgc3lzL21vZHVsZXMvaXBmdy9N YWtlZmlsZQkod29ya2luZyBjb3B5KQpAQCAtOCw2ICs4LDcgQEAgS01PRD0JaXBmdwogU1JD Uz0JaXBfZncyLmMgaXBfZndfcGZpbC5jCiBTUkNTKz0JaXBfZndfZHluYW1pYy5jIGlwX2Z3 X2xvZy5jCiBTUkNTKz0JaXBfZndfc29ja29wdC5jIGlwX2Z3X3RhYmxlLmMKK1NSQ1MrPQlp cF9md19pZmFjZS5jIGlwX2Z3X3Jld3JpdGUuYwogU1JDUys9CW9wdF9pbmV0Lmggb3B0X2lu ZXQ2Lmggb3B0X2lwZGl2ZXJ0Lmggb3B0X2lwZncuaCBvcHRfaXBzZWMuaAogCiBDRkxBR1Mr PSAtRElQRklSRVdBTEwKSW5kZXg6IHN5cy9uZXRwZmlsL2lwZncvaXBfZncyLmMKPT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PQotLS0gc3lzL25ldHBmaWwvaXBmdy9pcF9mdzIuYwkocmV2aXNpb24gMjQ4NzA0 KQorKysgc3lzL25ldHBmaWwvaXBmdy9pcF9mdzIuYwkod29ya2luZyBjb3B5KQpAQCAtMzUz LDE3ICszNTMsMTcgQEAgaWZhY2VfbWF0Y2goc3RydWN0IGlmbmV0ICppZnAsIGlwZndfaW5z bl9pZiAqY21kLAogCWlmIChpZnAgPT0gTlVMTCkJLyogbm8gaWZhY2Ugd2l0aCB0aGlzIHBh Y2tldCwgbWF0Y2ggZmFpbHMgKi8KIAkJcmV0dXJuIDA7CiAJLyogQ2hlY2sgYnkgbmFtZSBv ciBieSBJUCBhZGRyZXNzICovCi0JaWYgKGNtZC0+bmFtZVswXSAhPSAnXDAnKSB7IC8qIG1h dGNoIGJ5IG5hbWUgKi8KLQkJaWYgKGNtZC0+bmFtZVswXSA9PSAnXDEnKSAvKiB1c2UgdGFi bGVhcmcgdG8gbWF0Y2ggKi8KKwlpZiAoY21kLT5vLmFyZzEgIT0gMCkgeyAvKiBtYXRjaCBi eSBuYW1lICovCisJCWlmIChjbWQtPm8uYXJnMSA9PSAxKSAvKiB1c2UgdGFibGVhcmcgdG8g bWF0Y2ggKi8KIAkJCXJldHVybiBpcGZ3X2xvb2t1cF90YWJsZV9leHRlbmRlZChjaGFpbiwg Y21kLT5wLmdsb2IsCiAJCQkJaWZwLT5pZl94bmFtZSwgdGFibGVhcmcsIElQRldfVEFCTEVf SU5URVJGQUNFKTsKIAkJLyogQ2hlY2sgbmFtZSAqLwotCQlpZiAoY21kLT5wLmdsb2IpIHsK KwkJaWYgKGNtZC0+cC5pZl9pZHgpIHsKKwkJCWlmIChpZnAtPmlmX2luZGV4ID09IGNtZC0+ cC5pZl9pZHgpCisJCQkJcmV0dXJuICgxKTsKKwkJfSBlbHNlIHsKIAkJCWlmIChmbm1hdGNo KGNtZC0+bmFtZSwgaWZwLT5pZl94bmFtZSwgMCkgPT0gMCkKIAkJCQlyZXR1cm4oMSk7Ci0J CX0gZWxzZSB7Ci0JCQlpZiAoc3RybmNtcChpZnAtPmlmX3huYW1lLCBjbWQtPm5hbWUsIElG TkFNU0laKSA9PSAwKQotCQkJCXJldHVybigxKTsKIAkJfQogCX0gZWxzZSB7CiAjaWZkZWYg X19GcmVlQlNEX18JLyogYW5kIE9TWCB0b28gPyAqLwpAQCAtMjY2Nyw2ICsyNjY3LDggQEAg dm5ldF9pcGZ3X2luaXQoY29uc3Qgdm9pZCAqdW51c2VkKQogCiAJSVBGV19MT0NLX0lOSVQo Y2hhaW4pOwogCWlwZndfZHluX2luaXQoY2hhaW4pOworCWlwZndfaWZoYXNoX2luaXQoY2hh aW4pOworCWlwZndfcmV3cml0ZV9pbml0KGNoYWluKTsKIAogCS8qIEZpcnN0IHNldCB1cCBz b21lIHZhbHVlcyB0aGF0IGFyZSBjb21waWxlIHRpbWUgb3B0aW9ucyAqLwogCVZfaXBmd192 bmV0X3JlYWR5ID0gMTsJCS8qIE9wZW4gZm9yIGJ1c2luZXNzICovCkBAIC0yNzA4LDYgKzI3 MTAsNyBAQCB2bmV0X2lwZndfdW5pbml0KGNvbnN0IHZvaWQgKnVudXNlZCkKIAkodm9pZClp cGZ3X2F0dGFjaF9ob29rcygwIC8qIGRldGFjaCAqLyk7CiAJVl9pcF9md19jdGxfcHRyID0g TlVMTDsKIAlJUEZXX1VIX1dMT0NLKGNoYWluKTsKKwlpcGZ3X2lmaGFzaF9kZXRhY2goY2hh aW4pOyAvKiBkZXRhY2ggZXZlbnRoYW5kbGVycyAqLwogCUlQRldfVUhfV1VOTE9DSyhjaGFp bik7CiAJSVBGV19VSF9XTE9DSyhjaGFpbik7CiAKQEAgLTI3MjIsOSArMjcyNSwxNCBAQCB2 bmV0X2lwZndfdW5pbml0KGNvbnN0IHZvaWQgKnVudXNlZCkKIAkJcnVsZSA9IGNoYWluLT5t YXBbaV07CiAJCXJ1bGUtPnhfbmV4dCA9IHJlYXA7CiAJCXJlYXAgPSBydWxlOworCQkvKiBD bGVhciByZXdyaXRlcyBpZiBhbnkgKi8KKwkJaWYgKHJ1bGUtPmZsYWdzICYgSVBfRldfUlVM RV9SRVdSSVRURU4pCisJCQlpcGZ3X3JlbG9jYXRlX3Jld3JpdGUoY2hhaW4sIHJ1bGUtPmNt ZCwgTlVMTCk7CiAJfQogCWlmIChjaGFpbi0+bWFwKQogCQlmcmVlKGNoYWluLT5tYXAsIE1f SVBGVyk7CisJaXBmd19yZXdyaXRlX2ZyZWUoY2hhaW4pOworCWlwZndfaWZoYXNoX2ZyZWUo Y2hhaW4pOwogCUlQRldfV1VOTE9DSyhjaGFpbik7CiAJSVBGV19VSF9XVU5MT0NLKGNoYWlu KTsKIAlpZiAocmVhcCAhPSBOVUxMKQpJbmRleDogc3lzL25ldHBmaWwvaXBmdy9pcF9md19w cml2YXRlLmgKPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PQotLS0gc3lzL25ldHBmaWwvaXBmdy9pcF9md19wcml2 YXRlLmgJKHJldmlzaW9uIDI0ODcwNCkKKysrIHN5cy9uZXRwZmlsL2lwZncvaXBfZndfcHJp dmF0ZS5oCSh3b3JraW5nIGNvcHkpCkBAIC0yMTIsNiArMjEyLDEzIEBAIFZORVRfREVDTEFS RShpbnQsIGF1dG9pbmNfc3RlcCk7CiBWTkVUX0RFQ0xBUkUodW5zaWduZWQgaW50LCBmd190 YWJsZXNfbWF4KTsKICNkZWZpbmUgVl9md190YWJsZXNfbWF4CQlWTkVUKGZ3X3RhYmxlc19t YXgpCiAKKworI2RlZmluZSBDTURTSVpFKHJ1bGUpICAoKChzdHJ1Y3QgaXBfZncgKikocnVs ZSkpLT5jbWRfbGVuICogc2l6ZW9mKHVpbnQzMl90KSkKKworCitzdHJ1Y3QgaXBfZndfaWZf ZGF0YTsKK3N0cnVjdCBpcF9md19yd19kYXRhOworCiBzdHJ1Y3QgaXBfZndfY2hhaW4gewog CXN0cnVjdCBpcF9mdwkqcnVsZXM7CQkvKiBsaXN0IG9mIHJ1bGVzICovCiAJc3RydWN0IGlw X2Z3CSpyZWFwOwkJLyogbGlzdCBvZiBydWxlcyB0byByZWFwICovCkBAIC0yMzIsOCArMjM5 LDQyIEBAIHN0cnVjdCBpcF9md19jaGFpbiB7CiAjZW5kaWYKIAl1aW50MzJfdAlpZDsJCS8q IHJ1bGVzZXQgaWQgKi8KIAl1aW50MzJfdAlnZW5jbnQ7CQkvKiBnZW5lcmF0aW9uIGNvdW50 ICovCisJc3RydWN0IGlwX2Z3X2lmX2RhdGEJKmlmX2RhdGE7CS8qIEludGVyZmFjZSB0cmFj a2luZyBkYXRhICovCisJc3RydWN0IGlwX2Z3X3J3X2RhdGEJKnJld3JpdGVfZGF0YTsJLyog UnVsZSByZXdyaXRlIGRhdGEgKi8KIH07CiAKKy8qIGlwX2Z3X3Jld3JpdGUuYyAqLworc3Ry dWN0IGlwX2Z3X3J3X2luZm8geworCXZvaWQJKnNwdHI7CS8qIFN0YXRlIGNyZWF0ZWQgYnkg aXBmd19wcmVwYXJlX3Jld3JpdGUoKSAqLworCWludAljb3VudDsJLyogTnVtYmVyIG9mIG9w Y29kZXMgcmVxdWVzdGluZyByZXdyaXRlICovCisJaW50CXN0YXRlczsJLyogTnVtYmVyIG9m IG9wY29kZXMgd2l0aCBzdGF0ZWZ1bCByZXdyaXRlICovCisJaW50CWxlbmRpZmY7CS8qIERp ZmZlcmVuY2Ugd2l0aCBvcmlkaW5hbCBydWxlIGxlbiAoaW5zbnMpICovCit9OworCit2b2lk IGlwZndfcmV3cml0ZV9pbml0KHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4pOwordm9pZCBp cGZ3X3Jld3JpdGVfZnJlZShzdHJ1Y3QgaXBfZndfY2hhaW4gKmNoYWluKTsKK2ludCBpcGZ3 X3Jld3JpdGVfbGVuKHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4pOwordm9pZCAqaXBmd19w cmVwYXJlX3Jld3JpdGUoc3RydWN0IGlwX2Z3X2NoYWluICpjaGFpbiwgaXBmd19pbnNuICpj bWQsCisgICAgaW50IGNtZF9sZW4sIHN0cnVjdCBpcF9md19yd19pbmZvICpyd2kpOwordm9p ZCBpcGZ3X3BlcmZvcm1fcmV3cml0ZShzdHJ1Y3QgaXBfZndfY2hhaW4gKmNoYWluLCBpcGZ3 X2luc24gKmtjbWQsCisgICAgdm9pZCAqc3RhdGUpOwordm9pZCBpcGZ3X3JlbG9jYXRlX3Jl d3JpdGUoc3RydWN0IGlwX2Z3X2NoYWluICpjaGFpbiwgaXBmd19pbnNuICpvbGQsCisgICAg aXBmd19pbnNuICpuZXcpOworaW50IGlwZndfZXhwb3J0X3Jld3JpdGUoc3RydWN0IGlwX2Z3 X2NoYWluICpjaGFpbiwgaXBmd19pbnNuICprY21kLAorICAgIGlwZndfaW5zbiAqdGFyZ2V0 KTsKKwordm9pZCBpcGZ3X2NoZWNrX3Jld3JpdGUoc3RydWN0IGlwX2Z3X2NoYWluICpjaGFp biwgaXBmd19pbnNuICppbnNuLAorICAgIHN0cnVjdCBpcF9md19yd19pbmZvICpyd2kpOwor dm9pZCBpcGZ3X3VwZGF0ZV9yZXdyaXRlKHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4sIGlw ZndfaW5zbiAqaW5zbiwKKyAgICB2b2lkICpzdGF0ZSwgdWludHB0cl90IHZhbCk7CisKKwor LyogaXBfZndfaWZhY2UuYyAqLwordm9pZCBpcGZ3X2lmaGFzaF9pbml0KHN0cnVjdCBpcF9m d19jaGFpbiAqY2hhaW4pOwordm9pZCBpcGZ3X2lmaGFzaF9mcmVlKHN0cnVjdCBpcF9md19j aGFpbiAqY2hhaW4pOwordm9pZCBpcGZ3X2lmaGFzaF9kZXRhY2goc3RydWN0IGlwX2Z3X2No YWluICpjaGFpbik7CisKKwogc3RydWN0IHNvY2tvcHQ7CS8qIHVzZWQgYnkgdGNwX3Zhci5o ICovCiAKIC8qIE1hY3JvIGZvciB3b3JraW5nIHdpdGggdmFyaW91cyBjb3VudGVycyAqLwpA QCAtMjk1LDcgKzMzNiw4IEBAIHN0cnVjdCBzb2Nrb3B0OwkvKiB1c2VkIGJ5IHRjcF92YXIu aCAqLwogCiAvKiBJbiBpcF9md19zb2Nrb3B0LmMgKi8KIGludCBpcGZ3X2ZpbmRfcnVsZShz dHJ1Y3QgaXBfZndfY2hhaW4gKmNoYWluLCB1aW50MzJfdCBrZXksIHVpbnQzMl90IGlkKTsK LWludCBpcGZ3X2FkZF9ydWxlKHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4sIHN0cnVjdCBp cF9mdyAqaW5wdXRfcnVsZSk7CitpbnQgaXBmd19hZGRfcnVsZShzdHJ1Y3QgaXBfZndfY2hh aW4gKmNoYWluLCBzdHJ1Y3QgaXBfZncgKmlucHV0X3J1bGUsCisgICAgc3RydWN0IGlwX2Z3 X3J3X2luZm8gKnJ3aSk7CiBpbnQgaXBmd19jdGwoc3RydWN0IHNvY2tvcHQgKnNvcHQpOwog aW50IGlwZndfY2hrKHN0cnVjdCBpcF9md19hcmdzICphcmdzKTsKIHZvaWQgaXBmd19yZWFw X3J1bGVzKHN0cnVjdCBpcF9mdyAqaGVhZCk7CkluZGV4OiBzeXMvbmV0cGZpbC9pcGZ3L2lw X2Z3X3NvY2tvcHQuYwo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09Ci0tLSBzeXMvbmV0cGZpbC9pcGZ3L2lwX2Z3 X3NvY2tvcHQuYwkocmV2aXNpb24gMjQ4OTcxKQorKysgc3lzL25ldHBmaWwvaXBmdy9pcF9m d19zb2Nrb3B0LmMJKHdvcmtpbmcgY29weSkKQEAgLTczLDYgKzczLDggQEAgTUFMTE9DX0RF RklORShNX0lQRlcsICJJcEZ3L0lwQWNjdCIsICJJcEZ3L0lwQWNjdAogICogc3RhdGljIHZh cmlhYmxlcyBmb2xsb3dlZCBieSBnbG9iYWwgb25lcyAobm9uZSBpbiB0aGlzIGZpbGUpCiAg Ki8KIAorc3RhdGljIHZvaWQgaXBmd19leHBvcnRfaGVhZGVyKHN0cnVjdCBpcF9mdyAqa3J1 bGUsIHN0cnVjdCBpcF9mdyAqZHN0KTsKKwogLyoKICAqIEZpbmQgdGhlIHNtYWxsZXN0IHJ1 bGUgPj0ga2V5LCBpZC4KICAqIFdlIGNvdWxkIHVzZSBic2VhcmNoIGJ1dCBpdCBpcyBzbyBz aW1wbGUgdGhhdCB3ZSBjb2RlIGl0IGRpcmVjdGx5CkBAIC0xNTMsNyArMTU1LDggQEAgc3dh cF9tYXAoc3RydWN0IGlwX2Z3X2NoYWluICpjaGFpbiwgc3RydWN0IGlwX2Z3ICoKICAqIE11 c3QgYmUgY2FsbGVkIHdpdGhvdXQgSVBGV19VSCBoZWxkCiAgKi8KIGludAotaXBmd19hZGRf cnVsZShzdHJ1Y3QgaXBfZndfY2hhaW4gKmNoYWluLCBzdHJ1Y3QgaXBfZncgKmlucHV0X3J1 bGUpCitpcGZ3X2FkZF9ydWxlKHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4sIHN0cnVjdCBp cF9mdyAqaW5wdXRfcnVsZSwKKyAgICBzdHJ1Y3QgaXBfZndfcndfaW5mbyAqcndpKQogewog CXN0cnVjdCBpcF9mdyAqcnVsZTsKIAlpbnQgaSwgbCwgaW5zZXJ0X2JlZm9yZTsKQEAgLTE2 Myw3ICsxNjYsOCBAQCBpbnQKIAkJcmV0dXJuIChFSU5WQUwpOwogCiAJbCA9IFJVTEVTSVpF KGlucHV0X3J1bGUpOwotCXJ1bGUgPSBtYWxsb2MobCwgTV9JUEZXLCBNX1dBSVRPSyB8IE1f WkVSTyk7CisJcnVsZSA9IG1hbGxvYyhsICsgcndpLT5sZW5kaWZmICogc2l6ZW9mKHVpbnQz Ml90KSwgTV9JUEZXLAorCSAgICBNX1dBSVRPSyB8IE1fWkVSTyk7CiAJLyogZ2V0X21hcCBy ZXR1cm5zIHdpdGggSVBGV19VSF9XTE9DSyBpZiBzdWNjZXNzZnVsICovCiAJbWFwID0gZ2V0 X21hcChjaGFpbiwgMSwgMCAvKiBub3QgbG9ja2VkICovKTsKIAlpZiAobWFwID09IE5VTEwp IHsKQEAgLTE3MSw3ICsxNzUsMTUgQEAgaW50CiAJCXJldHVybiBFTk9TUEM7CiAJfQogCi0J YmNvcHkoaW5wdXRfcnVsZSwgcnVsZSwgbCk7CisJaWYgKHJ3aS0+c3B0ciA9PSBOVUxMKQor CQliY29weShpbnB1dF9ydWxlLCBydWxlLCBsKTsKKwllbHNlIHsKKwkJLyogQ29weSBoZWFk ZXIgYW5kIGZpcnN0IGluc3R1Y3Rpb24gKi8KKwkJYmNvcHkoaW5wdXRfcnVsZSwgcnVsZSwg c2l6ZW9mKHN0cnVjdCBpcF9mdykpOworCQlydWxlLT5mbGFncyB8PSBJUF9GV19SVUxFX1JF V1JJVFRFTjsKKwkJaXBmd19wZXJmb3JtX3Jld3JpdGUoY2hhaW4sIHJ1bGUtPmNtZCwgcndp LT5zcHRyKTsKKwl9CisKIAkvKiBjbGVhciBmaWVsZHMgbm90IHNldHRhYmxlIGZyb20gdXNl cmxhbmQgKi8KIAlydWxlLT54X25leHQgPSBOVUxMOwogCXJ1bGUtPm5leHRfcnVsZSA9IE5V TEw7CkBAIC0zNjYsNiArMzc4LDE0IEBAIGRlbF9lbnRyeShzdHJ1Y3QgaXBfZndfY2hhaW4g KmNoYWluLCB1aW50MzJfdCBhcmcpCiAJCQlydWxlID0gY2hhaW4tPm1hcFtpXTsKIAkJCWlm IChrZWVwX3J1bGUocnVsZSwgY21kLCBuZXdfc2V0LCBudW0pKQogCQkJCW1hcFtvZnMrK10g PSBydWxlOworCQkJZWxzZSB7CisJCQkJLyogQ2xlYXIgcmV3cml0ZXMgaWYgYW55ICovCisJ CQkJaWYgKHJ1bGUtPmZsYWdzICYgSVBfRldfUlVMRV9SRVdSSVRURU4pIHsKKwkJCQkJcHJp bnRmKCJNb3ZpbmcgcnVsZSAlcCB0byBjbGVhciBsaXN0XG4iLCBydWxlKTsKKwkJCQkJaXBm d19yZWxvY2F0ZV9yZXdyaXRlKGNoYWluLAorCQkJCQkgICAgcnVsZS0+Y21kLCBOVUxMKTsK KwkJCQl9CisJCQl9CiAJCX0KIAkJLyogMy4gY29weSB0aGUgZmluYWwgcGFydCBvZiB0aGUg bWFwICovCiAJCWJjb3B5KGNoYWluLT5tYXAgKyBlbmQsIG1hcCArIG9mcywKQEAgLTM4NCw2 ICs0MDQsNyBAQCBkZWxfZW50cnkoc3RydWN0IGlwX2Z3X2NoYWluICpjaGFpbiwgdWludDMy X3QgYXJnKQogCQkJCWlwZndfZXhwaXJlX2R5bl9ydWxlcyhjaGFpbiwgcnVsZSwgUkVTVkRf U0VUKTsKIAkJCXJ1bGUtPnhfbmV4dCA9IGNoYWluLT5yZWFwOwogCQkJY2hhaW4tPnJlYXAg PSBydWxlOworCQkJcHJpbnRmKCJBZGRpbmcgcnVsZSAlcCB0byByZWFwIGxpc3RcbiIsIHJ1 bGUpOwogCQl9CiAJCWJyZWFrOwogCkBAIC01MTcsNyArNTM4LDggQEAgemVyb19lbnRyeShz dHJ1Y3QgaXBfZndfY2hhaW4gKmNoYWluLCB1X2ludDMyX3QgYXIKICAqIFJ1bGVzIGFyZSBz aW1wbGUsIHNvIHRoaXMgbW9zdGx5IG5lZWQgdG8gY2hlY2sgcnVsZSBzaXplcy4KICAqLwog c3RhdGljIGludAotY2hlY2tfaXBmd19zdHJ1Y3Qoc3RydWN0IGlwX2Z3ICpydWxlLCBpbnQg c2l6ZSkKK2NoZWNrX2lwZndfc3RydWN0KHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4sIHN0 cnVjdCBpcF9mdyAqcnVsZSwgaW50IHNpemUsCisgICAgc3RydWN0IGlwX2Z3X3J3X2luZm8g KnJ3aSkKIHsKIAlpbnQgbCwgY21kbGVuID0gMDsKIAlpbnQgaGF2ZV9hY3Rpb249MDsKQEAg LTY5Niw2ICs3MTgsNyBAQCBzdGF0aWMgaW50CiAJCWNhc2UgT19WSUE6CiAJCQlpZiAoY21k bGVuICE9IEZfSU5TTl9TSVpFKGlwZndfaW5zbl9pZikpCiAJCQkJZ290byBiYWRfc2l6ZTsK KwkJCWlwZndfY2hlY2tfcmV3cml0ZShjaGFpbiwgY21kLCByd2kpOwogCQkJYnJlYWs7CiAK IAkJY2FzZSBPX0FMVFE6CkBAIC04NjgsNiArODkxLDEzIEBAIGludCBjb252ZXJ0X3J1bGVf dG9fOChzdHJ1Y3QgaXBfZncgKnJ1bGUpOwogI2VuZGlmCiAKIAorc3RhdGljIHZvaWQKK2lw ZndfZXhwb3J0X2hlYWRlcihzdHJ1Y3QgaXBfZncgKmtydWxlLCBzdHJ1Y3QgaXBfZncgKmRz dCkKK3sKKworCW1lbWNweShkc3QsIGtydWxlLCBzaXplb2Yoc3RydWN0IGlwX2Z3KSAtIHNp emVvZihpcGZ3X2luc24pKTsKK30KKwogLyoKICAqIENvcHkgdGhlIHN0YXRpYyBhbmQgZHlu YW1pYyBydWxlcyB0byB0aGUgc3VwcGxpZWQgYnVmZmVyCiAgKiBhbmQgcmV0dXJuIHRoZSBh bW91bnQgb2Ygc3BhY2UgYWN0dWFsbHkgdXNlZC4KQEAgLTg4NywxMSArOTE3LDI4IEBAIGlw ZndfZ2V0cnVsZXMoc3RydWN0IGlwX2Z3X2NoYWluICpjaGFpbiwgdm9pZCAqYnVmCiAJCXJ1 bGUgPSBjaGFpbi0+bWFwW2ldOwogCiAJCWlmIChpczcpIHsKLQkJICAgIC8qIENvbnZlcnQg cnVsZSB0byBGcmVlQlNkIDcuMiBmb3JtYXQgKi8KLQkJICAgIGwgPSBSVUxFU0laRTcocnVs ZSk7CisJCSAgICAvKiBDb252ZXJ0IHJ1bGUgdG8gRnJlZUJTRCA3LjIgZm9ybWF0ICovCisJ CQlpZiAocnVsZS0+ZmxhZ3MgJiBJUF9GV19SVUxFX1JFV1JJVFRFTikKKwkJCQlsID0gaXBm d19leHBvcnRfcmV3cml0ZShjaGFpbiwgcnVsZS0+Y21kLCBOVUxMKTsKKwkJCWVsc2UKKwkJ CQlsID0gQ01EU0laRShydWxlKTsKKworCQkJLyoKKwkJCSAqIEFkZCBoZWFkZXIgbGVuZ3Ro LgorCQkJICogdi44IHJ1bGUgaGVhZGVyIGlzIDQgYnl0ZXMgYmlnZ2VyLgorCQkJICovCisJ CQlsICs9IHNpemVvZihzdHJ1Y3QgaXBfZnc3KSAtIHNpemVvZihpcGZ3X2luc24pOworCiAJ CSAgICBpZiAoYnAgKyBsICsgc2l6ZW9mKHVpbnQzMl90KSA8PSBlcCkgewogCQkJaW50IGVy cm9yOwogCQkJYmNvcHkocnVsZSwgYnAsIGwgKyBzaXplb2YodWludDMyX3QpKTsKKworCQkJ aWYgKHJ1bGUtPmZsYWdzICYgSVBfRldfUlVMRV9SRVdSSVRURU4pIHsKKwkJCQlpcGZ3X2V4 cG9ydF9yZXdyaXRlKGNoYWluLCBydWxlLT5jbWQsIGRzdC0+Y21kKTsKKwkJCQlpcGZ3X2V4 cG9ydF9oZWFkZXIocnVsZSwgZHN0KTsKKwkJCX0gZWxzZQorCQkJCWJjb3B5KHJ1bGUsIGJw LCBsICsgc2l6ZW9mKHVpbnQzMl90KSk7CisKIAkJCWVycm9yID0gY29udmVydF9ydWxlX3Rv XzcoKHN0cnVjdCBpcF9mdyAqKSBicCk7CiAJCQlpZiAoZXJyb3IpCiAJCQkJcmV0dXJuIDA7 IC8qWFhYIGNvcnJlY3Q/ICovCkBAIC05MTAsMTQgKzk1NywyMyBAQCBpcGZ3X2dldHJ1bGVz KHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4sIHZvaWQgKmJ1ZgogCQkgICAgY29udGludWU7 IC8qIGdvIHRvIG5leHQgcnVsZSAqLwogCQl9CiAKLQkJLyogbm9ybWFsIG1vZGUsIGRvbid0 IHRvdWNoIHJ1bGVzICovCi0JCWwgPSBSVUxFU0laRShydWxlKTsKKwkJaWYgKHJ1bGUtPmZs YWdzICYgSVBfRldfUlVMRV9SRVdSSVRURU4pCisJCQlsID0gaXBmd19leHBvcnRfcmV3cml0 ZShjaGFpbiwgcnVsZS0+Y21kLCBOVUxMKTsKKwkJZWxzZQorCQkJbCA9IENNRFNJWkUocnVs ZSk7CisJCS8qIEFkZCBoZWFkZXIgbGVuZ3RoICovCisJCWwgKz0gc2l6ZW9mKHN0cnVjdCBp cF9mdykgLSBzaXplb2YoaXBmd19pbnNuKTsKKwogCQlpZiAoYnAgKyBsID4gZXApIHsgLyog c2hvdWxkIG5vdCBoYXBwZW4gKi8KIAkJCXByaW50Zigib3ZlcmZsb3cgZHVtcGluZyBzdGF0 aWMgcnVsZXNcbiIpOwogCQkJYnJlYWs7CiAJCX0KIAkJZHN0ID0gKHN0cnVjdCBpcF9mdyAq KWJwOwotCQliY29weShydWxlLCBkc3QsIGwpOworCQlpZiAocnVsZS0+ZmxhZ3MgJiBJUF9G V19SVUxFX1JFV1JJVFRFTikgeworCQkJaXBmd19leHBvcnRfcmV3cml0ZShjaGFpbiwgcnVs ZS0+Y21kLCBkc3QtPmNtZCk7CisJCQlpcGZ3X2V4cG9ydF9oZWFkZXIocnVsZSwgZHN0KTsK KwkJfSBlbHNlCisJCQliY29weShydWxlLCBkc3QsIGwpOwogCQkvKgogCQkgKiBYWFggSEFD Sy4gU3RvcmUgdGhlIGRpc2FibGUgbWFzayBpbiB0aGUgIm5leHQiCiAJCSAqIHBvaW50ZXIg aW4gYSB3aWxkIGF0dGVtcHQgdG8ga2VlcCB0aGUgQUJJIHRoZSBzYW1lLgpAQCAtOTQ5LDYg KzEwMDUsNyBAQCBpcGZ3X2N0bChzdHJ1Y3Qgc29ja29wdCAqc29wdCkKIAl1aW50MzJfdCBv cHQ7CiAJY2hhciB4YnVmWzEyOF07CiAJaXBfZnczX29waGVhZGVyICpvcDMgPSBOVUxMOwor CXN0cnVjdCBpcF9md19yd19pbmZvIHJ3aTsKIAogCWVycm9yID0gcHJpdl9jaGVjayhzb3B0 LT5zb3B0X3RkLCBQUklWX05FVElORVRfSVBGVyk7CiAJaWYgKGVycm9yKQpAQCAtOTk4LDcg KzEwNTUsNyBAQCBpcGZ3X2N0bChzdHJ1Y3Qgc29ja29wdCAqc29wdCkKIAkJZm9yICg7Oykg ewogCQkJaW50IGxlbiA9IDAsIHdhbnQ7CiAKLQkJCXNpemUgPSBjaGFpbi0+c3RhdGljX2xl bjsKKwkJCXNpemUgPSBjaGFpbi0+c3RhdGljX2xlbiArIGlwZndfcmV3cml0ZV9sZW4oY2hh aW4pOwogCQkJc2l6ZSArPSBpcGZ3X2R5bl9sZW4oKTsKIAkJCWlmIChzaXplID49IHNvcHQt PnNvcHRfdmFsc2l6ZSkKIAkJCQlicmVhazsKQEAgLTEwMjcsNiArMTA4NCw4IEBAIGlwZndf Y3RsKHN0cnVjdCBzb2Nrb3B0ICpzb3B0KQogCQllcnJvciA9IHNvb3B0Y29weWluKHNvcHQs IHJ1bGUsIFJVTEVfTUFYU0laRSwKIAkJCXNpemVvZihzdHJ1Y3QgaXBfZnc3KSApOwogCisJ CW1lbXNldCgmcndpLCAwLCBzaXplb2YocndpKSk7CisKIAkJLyoKIAkJICogSWYgdGhlIHNp emUgb2YgY29tbWFuZHMgZXF1YWxzIFJVTEVTSVpFNyB0aGVuIHdlIGFzc3VtZQogCQkgKiBh IEZyZWVCU0Q3LjIgYmluYXJ5IGlzIHRhbGtpbmcgdG8gdXMgKHNldCBpczc9MSkuCkBAIC0x MDQyLDE1ICsxMTAxLDIxIEBAIGlwZndfY3RsKHN0cnVjdCBzb2Nrb3B0ICpzb3B0KQogCQkg ICAgaWYgKGVycm9yKQogCQkJcmV0dXJuIGVycm9yOwogCQkgICAgaWYgKGVycm9yID09IDAp Ci0JCQllcnJvciA9IGNoZWNrX2lwZndfc3RydWN0KHJ1bGUsIFJVTEVTSVpFKHJ1bGUpKTsK KwkJCWVycm9yID0gY2hlY2tfaXBmd19zdHJ1Y3QoY2hhaW4sIHJ1bGUsIFJVTEVTSVpFKHJ1 bGUpLAorCQkJICAgICZyd2kpOwogCQl9IGVsc2UgewogCQkgICAgaXM3ID0gMDsKIAkJaWYg KGVycm9yID09IDApCi0JCQllcnJvciA9IGNoZWNrX2lwZndfc3RydWN0KHJ1bGUsIHNvcHQt PnNvcHRfdmFsc2l6ZSk7CisJCQllcnJvciA9IGNoZWNrX2lwZndfc3RydWN0KGNoYWluLCBy dWxlLAorCQkJICAgIHNvcHQtPnNvcHRfdmFsc2l6ZSwgJnJ3aSk7CiAJCX0KIAkJaWYgKGVy cm9yID09IDApIHsKKwkJCS8qIFByZXBhcmUgcmV3cml0ZSwgaWYgbmVlZGVkICovCisJCQlp ZiAocndpLmNvdW50ID4gMCkKKwkJCQlyd2kuc3B0ciA9IGlwZndfcHJlcGFyZV9yZXdyaXRl KGNoYWluLAorCQkJCSAgICBydWxlLT5jbWQsIHJ1bGUtPmNtZF9sZW4sICZyd2kpOwogCQkJ LyogbG9ja2luZyBpcyBkb25lIHdpdGhpbiBpcGZ3X2FkZF9ydWxlKCkgKi8KLQkJCWVycm9y ID0gaXBmd19hZGRfcnVsZShjaGFpbiwgcnVsZSk7CisJCQllcnJvciA9IGlwZndfYWRkX3J1 bGUoY2hhaW4sIHJ1bGUsICZyd2kpOwogCQkJc2l6ZSA9IFJVTEVTSVpFKHJ1bGUpOwogCQkJ aWYgKCFlcnJvciAmJiBzb3B0LT5zb3B0X2RpciA9PSBTT1BUX0dFVCkgewogCQkJCWlmIChp czcpIHsKQEAgLTEzNTAsNyArMTQxNSw3IEBAIGNvbnZlcnRfcnVsZV90b183KHN0cnVjdCBp cF9mdyAqcnVsZSkKIAliY29weShydWxlLCB0bXAsIFJVTEVfTUFYU0laRSk7CiAKIAkvKiBD b3B5IGZpZWxkcyAqLwotCXJ1bGU3LT5fcGFkID0gdG1wLT5fcGFkOworCXJ1bGU3LT5fcGFk ID0gMDsKIAlydWxlNy0+c2V0ID0gdG1wLT5zZXQ7CiAJcnVsZTctPnJ1bGVudW0gPSB0bXAt PnJ1bGVudW07CiAJcnVsZTctPmNtZF9sZW4gPSB0bXAtPmNtZF9sZW47CkBAIC0xNDIzLDcg KzE0ODgsNyBAQCBjb252ZXJ0X3J1bGVfdG9fOChzdHJ1Y3QgaXBfZncgKnJ1bGUpCiAJCX0K IAl9CiAKLQlydWxlLT5fcGFkID0gdG1wLT5fcGFkOworCXJ1bGUtPmZsYWdzID0gMDsKIAly dWxlLT5zZXQgPSB0bXAtPnNldDsKIAlydWxlLT5ydWxlbnVtID0gdG1wLT5ydWxlbnVtOwog CXJ1bGUtPmNtZF9sZW4gPSB0bXAtPmNtZF9sZW47Ci0tLSAvZGV2L251bGwJMjAxMy0wNC0y NCAxNzoyMDoxOS4wMDAwMDAwMDAgKzA0MDAKKysrIHN5cy9uZXRwZmlsL2lwZncvaXBfZndf cmV3cml0ZS5jCTIwMTMtMDQtMjQgMTc6MTk6MTUuMjc4MDk3MjQzICswNDAwCkBAIC0wLDAg KzEsODM1IEBACisvKi0KKyAqIENvcHlyaWdodCAoYykgMjAxMyBZYW5kZXggTExDLgorICog QXV0aG9yOiBBbGV4YW5kZXIgVi4gQ2hlcm5pa292IDxtZWxpZmFyb0B5YW5kZXgtdGVhbS5y dT4KKyAqCisgKiBSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5 IGZvcm1zLCB3aXRoIG9yIHdpdGhvdXQKKyAqIG1vZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRl ZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9ucworICogYXJlIG1ldDoK KyAqIDEuIFJlZGlzdHJpYnV0aW9ucyBvZiBzb3VyY2UgY29kZSBtdXN0IHJldGFpbiB0aGUg YWJvdmUgY29weXJpZ2h0CisgKiAgICBub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25z IGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCisgKiAyLiBSZWRpc3RyaWJ1dGlvbnMg aW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodAorICog ICAgbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBk aXNjbGFpbWVyIGluIHRoZQorICogICAgZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXIgbWF0 ZXJpYWxzIHByb3ZpZGVkIHdpdGggdGhlIGRpc3RyaWJ1dGlvbi4KKyAqCisgKiBUSElTIFNP RlRXQVJFIElTIFBST1ZJREVEIEJZIFRIRSBBVVRIT1IgQU5EIENPTlRSSUJVVE9SUyBgYEFT IElTJycgQU5ECisgKiBBTlkgRVhQUkVTUyBPUiBJTVBMSUVEIFdBUlJBTlRJRVMsIElOQ0xV RElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBUSEUKKyAqIElNUExJRUQgV0FSUkFOVElFUyBP RiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NF CisgKiBBUkUgRElTQ0xBSU1FRC4gIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1IgT1Ig Q09OVFJJQlVUT1JTIEJFIExJQUJMRQorICogRk9SIEFOWSBESVJFQ1QsIElORElSRUNULCBJ TkNJREVOVEFMLCBTUEVDSUFMLCBFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwKKyAqIERB TUFHRVMgKElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBT VUJTVElUVVRFIEdPT0RTCisgKiBPUiBTRVJWSUNFUzsgTE9TUyBPRiBVU0UsIERBVEEsIE9S IFBST0ZJVFM7IE9SIEJVU0lORVNTIElOVEVSUlVQVElPTikKKyAqIEhPV0VWRVIgQ0FVU0VE IEFORCBPTiBBTlkgVEhFT1JZIE9GIExJQUJJTElUWSwgV0hFVEhFUiBJTiBDT05UUkFDVCwg U1RSSUNUCisgKiBMSUFCSUxJVFksIE9SIFRPUlQgKElOQ0xVRElORyBORUdMSUdFTkNFIE9S IE9USEVSV0lTRSkgQVJJU0lORyBJTiBBTlkgV0FZCisgKiBPVVQgT0YgVEhFIFVTRSBPRiBU SElTIFNPRlRXQVJFLCBFVkVOIElGIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GCisg KiBTVUNIIERBTUFHRS4KKyAqLworCisjaW5jbHVkZSA8c3lzL2NkZWZzLmg+CitfX0ZCU0RJ RCgiJEZyZWVCU0QkIik7CisKKy8qCisgKiBSdWxlIG9wY29kZSByZXdyaXRpbmcgc3lzdGVt IGZvciBpcGZ3LgorICogU3lzdGVtIHBlcm1pdHMgYXV0b21hdGljIGFsZ29yaXRtaWMgKHN0 YXRlbGVzcykgb3Igc3RhdGVmdWxsICgKKyAqIHJlcXVpcmluZyBhY2Nlc3MvbW9uaWRpZmNh dGlvbiB0byBleHRlcm5hbCBkYXRhKSBvZiBvcGNvZGVzLgorICogTW9kaWZpY2F0aW9uIGlz IGRvbmUgYnkgY2FsbGluZyBzcGVjaWFsIHBlci1vcGNvZGUgZGVwZW5kZW50CisgKiBjYWxs YmFja3MuIFNhdmluZyB1bm1vZGlmaWVkIHVzZXItc3VwcGxpZWQgcnVsZXMsIHNpemUgcmVj YWxjdWxhdGlvbiwKKyAqIHJ1bGUgZXhwb3J0IGFuZCByZWxvY2F0aW9uIGlzIGhhbmRsZWQg Ynkgc3Vic3lzdGVtLgorICogV3JpdGluZyBvcGNvZGUgbW9kaWZpY2F0b3IgcmVxdWlyZXMg YWRkaW5nIGl0IHRvIHJld3JpdGVzW10gYXJyYXkKKyAqIGFuZCBmaWxsaW5nIGFwcHJvcHJp YXRlIGNhbGxiYWNrcyAoYXQgbGVhc3QgJ2NvbnZlcnQnIG9uZS4KKyAqLworCisjaW5jbHVk ZSAib3B0X2lwZncuaCIKKworI2luY2x1ZGUgPHN5cy9wYXJhbS5oPgorI2luY2x1ZGUgPHN5 cy9zeXN0bS5oPgorI2luY2x1ZGUgPHN5cy9tYWxsb2MuaD4KKyNpbmNsdWRlIDxzeXMva2Vy bmVsLmg+CisjaW5jbHVkZSA8c3lzL2xvY2suaD4KKyNpbmNsdWRlIDxzeXMvcndsb2NrLmg+ CisjaW5jbHVkZSA8c3lzL2Zudl9oYXNoLmg+CisjaW5jbHVkZSA8c3lzL3NvY2tldC5oPgor I2luY2x1ZGUgPG5ldC9pZi5oPgorCisjaW5jbHVkZSA8bmV0aW5ldC9pbi5oPgorI2luY2x1 ZGUgPG5ldGluZXQvaXBfdmFyLmg+IC8qIGhvb2tzICovCisjaW5jbHVkZSA8bmV0aW5ldC9p cF9mdy5oPgorCisjaW5jbHVkZSA8bmV0cGZpbC9pcGZ3L2lwX2Z3X3ByaXZhdGUuaD4KKyNp bmNsdWRlIDxuZXRwZmlsL2lwZncvaXBfZndfaWZhY2UuaD4KKworI2RlZmluZQlOT19SRVdS SVRFCQkwCisjZGVmaW5lCVNUQVRFTEVTU19SRVdSSVRFCTEKKyNkZWZpbmUJU1RBVEVGVUxf UkVXUklURQkyCisKK3N0cnVjdCBpcF9md19yZXdyaXRlIHsKKwl1aW50MzJfdCBvcGNvZGU7 CisKKwkvKgorCSAqIENoZWNrcyBpZiBnaXZlbiBvcGNvZGUgbmVlZHMgdG8gYmUgY2hhbmdl ZC4gQ2FsbGVkIChpbmRpcmVjdGx5KQorCSAqIGZyb20gY2hlY2tfaXBmd19zdHJ1Y3QoKSB3 aXRob3V0IGhvbGRpbmcgYW55IGxvY2tzLiBGdWN0aW9uIHNob3VsZAorCSAqIHF1aWNrbHkg Y2hlY2sgaWYgZ2l2ZW4gb3Bjb2RlIG5lZWRzIHRvIGJlIHJld3JpdHRlbiBhbmQgc2V0IEBs ZW4gdG8gCisJICogc2l6ZSBkaWZmZXJlbmNlIChpbiBieXRlcykgYmV0d2VlbiBuZXcgKGFs dGVyZWQpIG9wY29kZSBzaXplIGFuZAorCSAqIG9sZCBvbmUuIE5vdGUgdGhhdCAmbGVuIGhv dWxkIGJlIGFsaWduZWQgdG8gdTMyLgorCSAqCisJICogUGFyYW1zOgorCSAqIEBjaGFpbiAt IHBvaW50ZXIgdG8gY3VycmVudCBpZnB3IGNoYWluCisJICogQGluc24gLSBnaXZlbiBpcGZ3 X2luc3RuCisJICogQGxlbiAtIHBvaW50ZXIgdG8gbGVuZ3RoIGRpZmYgKGluIGluc25zKQor CSAqCisJICogUmV0dXJuczoKKwkgKiBOT19SRVdSSVRFIC0gbm8gbmVlZCB0byBjb252ZXJ0 CisJICogU1RBVEVMRVNTX1JFV1JJVEUgLSAoYWxnb3JpdG1pYykgY29udmVyc2lvbiByZXF1 aXJlZC4KKwkgKiBTVEFURUZVTF9SRVdSSVRFIC0gc3RhdGVmdWwgY29udmVyc2lvbiByZXF1 aXJlZC4KKwkgKgorCSAqIENhbGxiYWNrIGlzIE9QVElPTkFMLCBkZWZhdWx0cyB0byBTVEFU RUxFU1NfUkVXUklURSBpZiBub3Qgc2V0LgorCSAqLworCWludCAoKmNoZWNrKShzdHJ1Y3Qg aXBfZndfY2hhaW4gKiwgaXBmd19pbnNuICosIGludCAqKTsKKworCS8qCisJICogUHJlcGFy ZXMgc3RhdGUgZm9yIGdpdmVuIG9wY29kZSBpZiBuZWVkZWQuIENhbGxlZCB3aXRob3V0CisJ ICogaG9sZGluZyBhbnkgbG9ja3MgcGVybWl0dGluZyB0byBhbGxvY2F0ZSBhbnkgYW1vdW50 IG9mIG1lbW9yeS4KKwkgKiBOb3RlIHRoYXQgcmVzdWx0IChhbmQgYWN0dWFsIHN0YXRlIHVz YWdlKSBoYXMgdG8gYmUgY29uc2lzdGVudAorCSAqIHdpdGggKmNoZWNrIChhbmQgb3RoZXIp IGNhbGxiYWNrcy4KKwkgKgorCSAqIFBhcmFtczoKKwkgKiBAY2hhaW4gLSBwb2ludGVyIHRv IGN1cnJlbnQgaWZwdyBjaGFpbgorCSAqIEBpbnNuIC0gZ2l2ZW4gaXBmd19pbnN0bgorCSAq IEBwc3RhdGUgLSBwb2ludGVyIHRvIHBvaW50ZXIgdG8gc3RhdGUKKwkgKgorCSAqIFJldHVy bnM6CisJICogTk9fUkVXUklURSAtIG5vIG5lZWQgdG8gY29udmVydAorCSAqIFNUQVRFTEVT U19SRVdSSVRFIC0gKGFsZ29yaXRtaWMpIGNvbnZlcnNpb24gY2FuIGJlIGRvbmUuCisJICog U1RBVEVGVUxfUkVXUklURSAtIHN0YXRlZnVsIGNvbnZlcnNpb24gcmVxdWlyZWQsIHN0YXRl IGlzIHNhdmVkIHRvCisJICogZ2l2ZW4gcG9pbnRlci4KKwkgKgorCSAqIENhbGxiYWNrIGlz IE9QVElPTkFMLCBkZWZhdWx0cyB0byBTVEFURUxFU1NfUkVXUklURSBpZiBub3Qgc2V0Lgor CSAqLworCWludCAoKnByZXBhcmUpKHN0cnVjdCBpcF9md19jaGFpbiAqLCBpcGZ3X2luc24g Kmluc24sIHZvaWQgKiopOworCisJLyoKKwkgKiBQZXJmb3JtcyBvcGNvZGUgY29udmVyc2lv bi4gQ2FsbGVkIHdpdGggY2hhaW4gV0xPQ0sgaGVsZC4KKwkgKiBOb3RlIHRoYXQgb3Bjb2Rl IGNvcHkgaXMgaGFuZGxlZCBhdXRvbWF0aWNhbGx5IGlmCisJICogTk9fUkVXUklURSBpcyBy ZXR1cm5lZC4gQGxlbiBoYXMgdG8gYmUgZmlsbGVkIG90aGVyd2lzZS4KKwkgKgorCSAqIFBh cmFtczoKKwkgKiBAY2hhaW4gLSBwb2ludGVyIHRvIGN1cnJlbnQgaWZwdyBjaGFpbgorCSAq IEBfb2xkIC0gdXNlcmxhbmQgaXBmd19pbnN0bgorCSAqIEBfbmV3IC0ga2VybmVsIGlwZndf aW5zbgorCSAqIEBzdGF0ZSAtIHBvaW50ZXIgdG8gc3RhdGUgc2F2ZWQKKwkgKiBAbGVuIC0g cG9pbnRlciB0byBvcGNvZGUgbGVuZ3RoIChpbiBpbnN0cnVjdGlvbnMpCisJICoKKwkgKiBS ZXR1cm5zOgorCSAqIE5PX1JFV1JJVEUgLSBubyBuZWVkIHRvIGNvbnZlcnQKKwkgKiBTVEFU RUxFU1NfUkVXUklURSAtIChhbGdvcml0bWljKSBjb252ZXJzaW9uIGlzICBkb25lLgorCSAq IFNUQVRFRlVMX1JFV1JJVEUgLSBzdGF0ZWZ1bCBjb252ZXJzaW9uIGlzIGRvbmUsIHN0YXRl IGlzIGNvbnN1bWVkLgorCSAqCisJICogQ2FsbGJhY2sgaXMgTUFOREFUT1JZLgorIAkgKi8K KwlpbnQgKCpjb252ZXJ0KShzdHJ1Y3QgaXBfZndfY2hhaW4gKiwgaXBmd19pbnNuICosIGlw ZndfaW5zbiAqLCB2b2lkICosIGludCAqKTsKKworCS8qCisJICogUGVyZm9ybXMgc3RhdGUg Y2xlYW51cCAocnVsZSBkZWxldGlvbikuIENhbGxlZCB3aXRoIGNoYWluIFdMT0NLIGhlbGQu CisJICogU3RhdGUgaGludCBjYW4gYmUgcHJvdmlkZWQuCisJICoKKwkgKiBQYXJhbXM6CisJ ICogQGNoYWluIC0gcG9pbnRlciB0byBjdXJyZW50IGlmcHcgY2hhaW4KKwkgKiBAaW5zbiAt IGtlcm5lbCBpcGZ3X2luc24KKwkgKiBAc3RhdGUgLSBwb2ludGVyIHRvIHN0YXRlIGhpbnQK KwkgKgorCSAqIENhbGxiYWNrIGlzIE9QVElPTkFMLgorCSAqLworCXZvaWQgKCpjbGVhciko c3RydWN0IGlwX2Z3X2NoYWluICosIGlwZndfaW5zbiAqLCB2b2lkICopOworCisJLyoKKwkg KiBQZXJmb3JtcyBvcGNvZGUtZGVwZW5kZW50IHVwZGF0ZS4KKwkgKiBGbGFnL2FyZ3VtZW50 IGNhbiBiZSBwcm92aWRlZC4KKwkgKgorCSAqIFBhcmFtczoKKwkgKiBAY2hhaW4gLSBwb2lu dGVyIHRvIGN1cnJlbnQgaWZwdyBjaGFpbgorCSAqIEBpbnNuIC0ga2VybmVsIGlwZndfaW5z bgorCSAqIEBzdGF0ZSAtIHBvaW50ZXIgdG8gb3Bjb2RlLWRlcGVuZGVudCBkYXRhCisJICog QHZhbCAtIG9wY29kZS1kZXBlbmRldCB2YWx1ZSAKKwkgKgorCSAqIENhbGxiYWNrIGlzIE9Q VElPTkFMLgorCSAqLworCXZvaWQgKCp1cGRhdGUpKHN0cnVjdCBpcF9md19jaGFpbiAqLCBp cGZ3X2luc24gKiwgdm9pZCAqLCB1aW50cHRyX3QpOworCisJLyoKKwkgKiBEaXNwYXRjaGVz IG1lbW9yeSByZWxvY2F0aW9uIG9mIGdpdmVuIG9wY29kZSwgQ2FsbGVkIHdpdGggV0xPQ0sg aGVsZC4KKwkgKiBBY3R1YWwgY29weSBpcyBhbHJlYWR5IGRvbmUgYXQgdGhlIG1vbWVudCBv ZiBjYWxsLgorCSAqCisJICogUGFyYW1zOgorCSAqIEBjaGFpbiAtIHBvaW50ZXIgdG8gY3Vy cmVudCBpZnB3IGNoYWluCisJICogQF9vbGQgLSBrZXJuZWwgaXBmd19pbnNuCisJICogQF9v bGQgLSBuZXcga2VybmVsIGlwZndfaW5zbgorCSAqCisJICogQ2FsbGJhY2sgaXMgT1BUSU9O QUwuCisJICovCisJdm9pZCAoKm1vdmUpKHN0cnVjdCBpcF9md19jaGFpbiAqLCBpcGZ3X2lu c24gKiwgaXBmd19pbnNuICopOworfTsKKworLyogT3Bjb2RlIGNhbGxiYWNrcyAqLworc3Rh dGljIGludAorY29udmVydGFibGVfaW5zbl9pZihzdHJ1Y3QgaXBfZndfY2hhaW4gKmNoYWlu LCBpcGZ3X2luc24gKmluc24pOworCitzdGF0aWMgdm9pZCBtb3ZlX2luc25faWYoc3RydWN0 IGlwX2Z3X2NoYWluICpjaGFpbiwgaXBmd19pbnNuICpfb2xkLCBpcGZ3X2luc24gKl9uZXcp Oworc3RhdGljIHZvaWQgdXBkYXRlX2luc25faWYoc3RydWN0IGlwX2Z3X2NoYWluICpjaGFp biwgaXBmd19pbnNuICppbnNuLAorICAgIHZvaWQgKl9pZmFjZV9tYXNrLCB1aW50cHRyX3Qg bmV3X2lkKTsKK3N0YXRpYyB2b2lkIGNsZWFyX2luc25faWYoc3RydWN0IGlwX2Z3X2NoYWlu ICpjaGFpbiwgaXBmd19pbnNuICpfc3JjLCB2b2lkICpkYXRhKTsKK3N0YXRpYyBpbnQgY29u dmVydF9pbnNuX2lmKHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4sIGlwZndfaW5zbiAqX29s ZCwgaXBmd19pbnNuICpfbmV3LAorICAgIHZvaWQgKnN0YXRlLCBpbnQgKmxlbik7CitzdGF0 aWMgaW50IHByZXBhcmVfaW5zbl9pZihzdHJ1Y3QgaXBfZndfY2hhaW4gKmNoYWluLCBpcGZ3 X2luc24gKmluc24sIHZvaWQgKipwc3RhdGUpOworc3RhdGljIGludCBjaGVja19pbnNuX2lm KHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4sIGlwZndfaW5zbiAqaW5zbiwgaW50ICpsZW4p OworCisKKy8qIE5vdGUgb3Bjb2RlcyBNVVNUIGJlIGluIGFzY2VkaW5nIG9yZGVyICovCitz dHJ1Y3QgaXBfZndfcmV3cml0ZSByZXdyaXRlc1tdID0geworCXsKKwkJT19SRUNWLAorCQlj aGVja19pbnNuX2lmLAorCQlwcmVwYXJlX2luc25faWYsCisJCWNvbnZlcnRfaW5zbl9pZiwK KwkJY2xlYXJfaW5zbl9pZiwKKwkJdXBkYXRlX2luc25faWYsCisJCW1vdmVfaW5zbl9pZiwK Kwl9LAorCXsKKwkJT19YTUlULAorCQljaGVja19pbnNuX2lmLAorCQlwcmVwYXJlX2luc25f aWYsCisJCWNvbnZlcnRfaW5zbl9pZiwKKwkJY2xlYXJfaW5zbl9pZiwKKwkJdXBkYXRlX2lu c25faWYsCisJCW1vdmVfaW5zbl9pZiwKKwl9LAorCXsKKwkJT19WSUEsCisJCWNoZWNrX2lu c25faWYsCisJCXByZXBhcmVfaW5zbl9pZiwKKwkJY29udmVydF9pbnNuX2lmLAorCQljbGVh cl9pbnNuX2lmLAorCQl1cGRhdGVfaW5zbl9pZiwKKwkJbW92ZV9pbnNuX2lmLAorCX0sCit9 OworCitzdHJ1Y3QgcmV3cml0ZV9ydWxlX3B0ciB7CisJVEFJTFFfRU5UUlkocmV3cml0ZV9y dWxlX3B0cikJbmV4dDsKKwlpbnQJCWNtZF9rbGVuOwkvKiBLZXJuZWwgb3Bjb2RlcyBsZW4g KGluc25zKSAqLworCWludAkJY21kX2xlbjsJLyogT3JpZ2luYWwgb3Bjb2RlcyBsZW4gKGlu c25zKSAqLworCWlwZndfaW5zbgkqa2NtZDsJLyogS2VybmVsIHJ1bGUgdmVyc2lvbiAqLwor CXZvaWQJCSoqc3RhdGVzOwkvKiBvcGNvZGUgc3RhdGVzICovCisJaW50CQlzdGF0ZXNfY291 bnQ7CS8qIG51bWJlciBvZiBzdGF0ZXMgKi8KKwlpcGZ3X2luc24JY21kWzFdOwkvKiBPcmln aW5hbCBvcGNvZGVzICovCit9OworVEFJTFFfSEVBRChyZXdyaXRlX3J1bGVfaGVhZCwgcmV3 cml0ZV9ydWxlX3B0cik7CisKK3N0cnVjdCBpcF9md19yd19kYXRhIHsKKwlzdHJ1Y3QgcmV3 cml0ZV9ydWxlX2hlYWQJKmhhc2g7CisJc2l6ZV90CQloc2l6ZTsKKwlpbnQJCWxlbmRpZmY7 CS8qIHNpemVvZihrZXJuKSAtIHNpemVvZih1c2VyKSAqLworfTsKKworI2RlZmluZQlERUZB VUxUX0hBU0hfU0laRQkzMgorI2RlZmluZQlQVFJfSEFTSF9QUklNRQkJMzEKKworc3RhdGlj IHN0cnVjdCBpcF9md19yZXdyaXRlICppcGZ3X2ZpbmRfcmV3cml0ZSh1aW50MzJfdCBvcGNv ZGUpOworCit2b2lkCitpcGZ3X3Jld3JpdGVfaW5pdChzdHJ1Y3QgaXBfZndfY2hhaW4gKmNo YWluKQoreworCXN0cnVjdCBpcF9md19yd19kYXRhICpyd2Q7CisJc3RydWN0IHJld3JpdGVf cnVsZV9oZWFkICpyaDsKKwlpbnQgaTsKKworCXJ3ZCA9IG1hbGxvYyhzaXplb2Yoc3RydWN0 IGlwX2Z3X3J3X2RhdGEpLCBNX0lQRlcsIE1fV0FJVE9LIHwgTV9aRVJPKTsKKworCXJ3ZC0+ aHNpemUgPSBERUZBVUxUX0hBU0hfU0laRTsKKwlyd2QtPmhhc2ggPSBtYWxsb2Moc2l6ZW9m KHN0cnVjdCByZXdyaXRlX3J1bGVfaGVhZCkgKiByd2QtPmhzaXplLAorCSAgICBNX0lQRlcs IE1fV0FJVE9LIHwgTV9aRVJPKTsKKworCWZvciAoaSA9IDAsIHJoID0gcndkLT5oYXNoOyBp IDwgcndkLT5oc2l6ZTsgaSsrLCByaCsrKQorCQlUQUlMUV9JTklUKHJoKTsKKworCWNoYWlu LT5yZXdyaXRlX2RhdGEgPSByd2Q7Cit9CisKK3ZvaWQKK2lwZndfcmV3cml0ZV9mcmVlKHN0 cnVjdCBpcF9md19jaGFpbiAqY2hhaW4pCit7CisJc3RydWN0IGlwX2Z3X3J3X2RhdGEgKnJ3 ZDsKKworCXJ3ZCA9IGNoYWluLT5yZXdyaXRlX2RhdGE7CisJY2hhaW4tPnJld3JpdGVfZGF0 YSA9IE5VTEw7CisKKwkvKiBBc3N1bWUgZXZlcnkgcnVsZSB0byBiZSBhbHJlYWR5IHJlbW92 ZWQgKi8KKwlmcmVlKHJ3ZC0+aGFzaCwgTV9JUEZXKTsKKwlmcmVlKHJ3ZCwgTV9JUEZXKTsK K30KKworaW50CitpcGZ3X3Jld3JpdGVfbGVuKHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4p Cit7CisJc3RydWN0IGlwX2Z3X3J3X2RhdGEgKnJ3ZDsKKworCXJ3ZCA9IGNoYWluLT5yZXdy aXRlX2RhdGE7CisKKwlyZXR1cm4gKHJ3ZC0+bGVuZGlmZik7Cit9CisKKy8qCisgKiBQcmVw YXJlcyBnaXZlbiBydWxlIGZvciBtb2RpZmljYXRpb246CisgKiBhbGxvY2F0ZXMgbWVtb3J5 IGZvciBydWxlIGFuZCBudW1iZXIgb2Ygc3RhdGVzIHJlcG9ydGVkCisgKiBieSAnY2hlY2sn IGNhbGxiYWNrcy4gQ2FsbHMgJ3ByZXBhcmUnIGNhbGxiYWNrIGZvcgorICogZXZlcnkgb3Bj b2RlIGluIHJ1bGUuCisgKgorICogUmV0dXJucyBzdGF0ZSB0byBiZSBwYXNzZWQgdG8gaXBm d19zdG9yZV9ydWxlLgorICovCit2b2lkICoKK2lwZndfcHJlcGFyZV9yZXdyaXRlKHN0cnVj dCBpcF9md19jaGFpbiAqY2hhaW4sIGlwZndfaW5zbiAqdWNtZCwKKyAgICBpbnQgY21kX2xl biwgc3RydWN0IGlwX2Z3X3J3X2luZm8gKnJ3aSkKK3sKKwlpbnQgaSwgbCwgY21kbGVuLCBz aXplLCBzdGF0ZXNfY291bnQ7CisJc3RydWN0IHJld3JpdGVfcnVsZV9wdHIgKnJwdHI7CisJ aXBmd19pbnNuICpjbWQ7CisJc3RydWN0IGlwX2Z3X3Jld3JpdGUgKnJld3JpdGU7CisJdm9p ZCAqKnBzdGF0ZTsKKworCS8qCisJICogQWxsb2NhdGUgbWVtb3J5IGZvciBydWxlIGhlYWRl ciwgb3Bjb2RlcyBhbmQgc3RhdGUgYXJyYXkuCisJICovCisJc2l6ZSA9IHNpemVvZihzdHJ1 Y3QgcmV3cml0ZV9ydWxlX3B0cikgKworCSAgICAoY21kX2xlbiAtIDEpICogc2l6ZW9mKHVp bnQzMl90KTsKKworCXNpemUgPSByb3VuZHVwKHNpemUsIHNpemVvZih2b2lkICopKTsKKwor CXJwdHIgPSBtYWxsb2Moc2l6ZSArIHJ3aS0+c3RhdGVzICogc2l6ZW9mKHZvaWQgKiksIE1f SVBGVywKKwkgICAgTV9XQUlUT0sgfCBNX1pFUk8pOworCisJLyogU2F2ZSBvcmlnaW5hbCBv cGNvZGVzICovCisJbWVtY3B5KHJwdHItPmNtZCwgdWNtZCwgY21kX2xlbiAqIHNpemVvZih1 aW50MzJfdCkpOworCXJwdHItPmNtZF9sZW4gPSBjbWRfbGVuOworCXJwdHItPmNtZF9rbGVu ID0gcnB0ci0+Y21kX2xlbiArIHJ3aS0+bGVuZGlmZjsgCisKKwlycHRyLT5zdGF0ZXMgPSAo dm9pZCAqKikoKGNoYXIgKilycHRyICsgc2l6ZSk7CisJcnB0ci0+c3RhdGVzX2NvdW50ID0g cndpLT5zdGF0ZXM7CisJcHN0YXRlID0gcnB0ci0+c3RhdGVzOworCXN0YXRlc19jb3VudCA9 IHJwdHItPnN0YXRlc19jb3VudDsKKworCUNUUjQoS1RSX05FVCwgIlByZXBhcmUgcnVsZSBy ZXdyaXRlOiBjbWQgJXAgbGVuICVkIGtsZW4gJWQgcnB0ciAlcCIsCisJICAgIHVjbWQsIHJw dHItPmNtZF9sZW4sIHJwdHItPmNtZF9rbGVuLCBycHRyKTsKKworCWZvciAobCA9IGNtZF9s ZW4sIGNtZCA9IHVjbWQgOworCQkJbCA+IDAgOyBsIC09IGNtZGxlbiwgY21kICs9IGNtZGxl bikgeworCQljbWRsZW4gPSBGX0xFTihjbWQpOworCisJCWlmICgocmV3cml0ZSA9IGlwZndf ZmluZF9yZXdyaXRlKGNtZC0+b3Bjb2RlKSkgPT0gTlVMTCkKKwkJCWNvbnRpbnVlOworCisJ CWlmIChyZXdyaXRlLT5wcmVwYXJlID09IE5VTEwpCisJCQljb250aW51ZTsKKworCQlpID0g cmV3cml0ZS0+cHJlcGFyZShjaGFpbiwgY21kLCBwc3RhdGUpOworCisJCWlmIChpID09IFNU QVRFRlVMX1JFV1JJVEUpIHsKKwkJCUNUUjMoS1RSX05FVCwgIk5ldyBzdGF0ZWZ1bCByZXdy aXRlICVwIHZhbCAlcCBjb3VudCAlZCIsCisJCQkgICAgcHN0YXRlLCAqcHN0YXRlLCBzdGF0 ZXNfY291bnQpOworCQkJcHN0YXRlKys7CisJCQlzdGF0ZXNfY291bnQtLTsKKworCQkJS0FT U0VSVChzdGF0ZXNfY291bnQgPj0gMCwKKwkJCSAgICAoInByZXBhcmVfcmV3cml0ZSBzdGF0 ZSBvdmVyZmxvdyIpKTsKKwkJfQorCX0KKworCXJldHVybiAoKHZvaWQgKilycHRyKTsKK30K Kworc3RhdGljIGludAoraGFzaF9wdHIoc3RydWN0IGlwX2Z3X3J3X2RhdGEgKnJ3ZCwgaXBm d19pbnNuICpjbWQpCit7CisJcmV0dXJuICh1aW50cHRyX3QpY21kICUgUFRSX0hBU0hfUFJJ TUU7Cit9CisKKy8qCisgKiBGaWxscyBpbiBrZXJuZWwgcnVsZSB3aXRoIG1vZGlmaWVkIG9w Y29kZXMuIFVwZGF0ZXMgb2xkIHJ1bGUgc3RhdGUKKyAqIHdpdGggbmV3IGtlcm5lbCBwb2lu dGVyLiBBY3R1YWwgcmV3cml0aW5nIGFuZCBoZWFkZXIgY29weSBpcyBkb25lCisgKiBpbiBp cGZ3X3J1bl9yZXdyaXRlKCkuCisgKi8KK3ZvaWQKK2lwZndfcGVyZm9ybV9yZXdyaXRlKHN0 cnVjdCBpcF9md19jaGFpbiAqY2hhaW4sIGlwZndfaW5zbiAqa2NtZCwgdm9pZCAqc3RhdGUp Cit7CisJc3RydWN0IHJld3JpdGVfcnVsZV9wdHIgKnJwdHI7CisJc3RydWN0IHJld3JpdGVf cnVsZV9oZWFkICpyaDsKKwlzdHJ1Y3QgaXBfZndfcndfZGF0YSAqcndkOworCXN0cnVjdCBp cF9md19yZXdyaXRlICpyZXdyaXRlOworCWlwZndfaW5zbiAqdWNtZDsKKwl2b2lkICoqcHN0 YXRlOworCWludCBpLCBsLCB1Y21kbGVuLCBrY21kbGVuLCBzdGF0ZXNfY291bnQ7CisKKwly d2QgPSBjaGFpbi0+cmV3cml0ZV9kYXRhOworCisJcnB0ciA9IChzdHJ1Y3QgcmV3cml0ZV9y dWxlX3B0ciAqKXN0YXRlOworCXJwdHItPmtjbWQgPSBrY21kOworCXBzdGF0ZSA9IHJwdHIt PnN0YXRlczsKKwlzdGF0ZXNfY291bnQgPSBycHRyLT5zdGF0ZXNfY291bnQ7CisKKwlDVFIz KEtUUl9ORVQsICJMaW5raW5nIGtjbWQgJXAgdG8gb3JpZyAlcCBpZHggJWQiLAorCSAgICBr Y21kLCBycHRyLCBoYXNoX3B0cihyd2QsIGtjbWQpKTsKKworCXJoID0gJnJ3ZC0+aGFzaFto YXNoX3B0cihyd2QsIGtjbWQpXTsKKwlUQUlMUV9JTlNFUlRfVEFJTChyaCwgcnB0ciwgbmV4 dCk7CisKKwl1Y21kID0gcnB0ci0+Y21kOworCQorCWZvciAobCA9IHJwdHItPmNtZF9sZW47 IGwgPiAwIDsKKwkgICAgbCAtPSB1Y21kbGVuLCB1Y21kICs9IHVjbWRsZW4sIGtjbWQgKz0g a2NtZGxlbikgeworCQl1Y21kbGVuID0gRl9MRU4odWNtZCk7CisKKwkJaWYgKChyZXdyaXRl ID0gaXBmd19maW5kX3Jld3JpdGUodWNtZC0+b3Bjb2RlKSkgPT0gTlVMTCkgeworCQkJLyog Tm8gY29udmVyc2lvbiByZXF1aXJlZCwgY29weSBhcyBpcyAqLworCQkJa2NtZGxlbiA9IHVj bWRsZW47CisJCQltZW1jcHkoa2NtZCwgdWNtZCwgdWNtZGxlbiAqIHNpemVvZihpcGZ3X2lu c24pKTsKKwkJCWNvbnRpbnVlOworCQl9CisKKwkJaSA9IHJld3JpdGUtPmNvbnZlcnQoY2hh aW4sIHVjbWQsIGtjbWQsICpwc3RhdGUsICZrY21kbGVuKTsKKwkJQ1RSMigiUlcgZm9yICVk IHN0ICVwIHJldHVybmVkICVkIiwgdWNtZC0+Y21kLCAqcHN0YXRlLCBpKTsKKworCQlpZiAo aSA9PSBOT19SRVdSSVRFKSB7CisJCQlrY21kbGVuID0gdWNtZGxlbjsKKwkJCW1lbWNweShr Y21kLCB1Y21kLCB1Y21kbGVuICogc2l6ZW9mKGlwZndfaW5zbikpOworCQl9IGVsc2UgaWYg KGkgPT0gU1RBVEVGVUxfUkVXUklURSkgeworCQkJcHN0YXRlKys7CisJCQlzdGF0ZXNfY291 bnQtLTsKKworCQkJS0FTU0VSVChzdGF0ZXNfY291bnQgPj0gMCwgKCJyZXdyaXRlIHN0YXRl IG92ZXJmbG93IikpOworCQl9CisJfQorCisJLyogU2F2ZSBzaXplIGRpZmZlcmVuY2UgKi8K Kwlyd2QtPmxlbmRpZmYgKz0gcnB0ci0+Y21kX2tsZW4gLSBycHRyLT5jbWRfbGVuOworCUNU UjIoS1RSX05FVCwgIm9sZCBsZW46ICVkLCBuZXc6ICVkIiwgcnB0ci0+Y21kX2xlbiwgcnB0 ci0+Y21kX2tsZW4pOworfQorCisvKgorICogSGFuZGxlIHJ1bGUgbW92aW5nIHRvIG5ldyBw bGFjZSAob3IgZGVsZXRpb24pLgorICogVXBkYXRlcyBrZXJuZWwgcnVsZSBwb2ludGVyIGFu ZCBydW4gb3Bjb2RlIGNhbGxiYWNrcyB2aWEKKyAqIGlwZndfbW92ZV9yZXdyaXRlKCkgb3Ig Y2xlYXJzIHN0YXRlIHZpYSBpcGZ3X2NsZWFyX3Jld3JpdGUoKQorICogaW50IGxhdHRlciBj YXNlLgorICovCit2b2lkCitpcGZ3X3JlbG9jYXRlX3Jld3JpdGUoc3RydWN0IGlwX2Z3X2No YWluICpjaGFpbiwgaXBmd19pbnNuICpvbGQsIGlwZndfaW5zbiAqbmV3KQoreworCXN0cnVj dCByZXdyaXRlX3J1bGVfcHRyICpycHRyOworCXN0cnVjdCByZXdyaXRlX3J1bGVfaGVhZCAq cmg7CisJc3RydWN0IGlwX2Z3X3J3X2RhdGEgKnJ3ZDsKKwlzdHJ1Y3QgaXBfZndfcmV3cml0 ZSAqcmV3cml0ZTsKKwlpbnQgbCwgY21kbGVuOworCisJcndkID0gY2hhaW4tPnJld3JpdGVf ZGF0YTsKKworCXJoID0gJnJ3ZC0+aGFzaFtoYXNoX3B0cihyd2QsIG9sZCldOworCisJVEFJ TFFfRk9SRUFDSChycHRyLCByaCwgbmV4dCkgeworCQlpZiAocnB0ci0+a2NtZCA9PSBvbGQp CisJCQlicmVhazsKKwl9CisKKwlDVFIzKEtUUl9ORVQsICJNb3ZpbmcgJXAgaWR4ICVwIHRv ICVwIiwgcnB0ciwgaGFzaF9wdHIocndkLCBvbGQpLCBuZXcpOworCisJS0FTU0VSVChycHRy ICE9IE5VTEwsICgiaXBmd19yZWxvY2F0ZV9yZXdyaXRlOiBvbGQgcnVsZSBub3QgZm91bmQi KSk7CisKKwlUQUlMUV9SRU1PVkUocmgsIHJwdHIsIG5leHQpOworCisJaWYgKG5ldyA9PSBO VUxMKSB7CisJCS8qIENsZWFyIHN0YXRlcyAoaWYgYW55KSBhbmQgZGVsZXRlIG9yaWdpbmFs IHJ1bGUgKi8KKwkJZm9yIChsID0gcnB0ci0+Y21kX2tsZW47IGwgPiAwOyBsIC09IGNtZGxl biwgb2xkICs9IGNtZGxlbikgeworCQkJY21kbGVuID0gRl9MRU4ob2xkKTsKKwkKKwkJCWlm ICgocmV3cml0ZSA9IGlwZndfZmluZF9yZXdyaXRlKG9sZC0+b3Bjb2RlKSkgPT0gTlVMTCkK KwkJCQljb250aW51ZTsKKwkKKwkJCWlmIChyZXdyaXRlLT5jbGVhciA9PSBOVUxMKQorCQkJ CWNvbnRpbnVlOworCQorCQkJQ1RSMShLVFJfTkVULCAiY2xlYXItc3RhdGUgZm9yIG9wY29k ZSAldSIsIG9sZC0+b3Bjb2RlKTsKKwkJCXJld3JpdGUtPmNsZWFyKGNoYWluLCBvbGQsIE5V TEwpOworCQl9CisKKwkJLyogVXBkYXRlIHNpemUgZGlmZmVyZW5jZSAqLworCQlyd2QtPmxl bmRpZmYgLT0gcnB0ci0+Y21kX2tsZW4gLSBycHRyLT5jbWRfbGVuOworCQlmcmVlKHJwdHIs IE1fSVBGVyk7CisJfSBlbHNlIHsKKwkJLyogUHV0IHRvIG5ldyBzbG90ICovCisJCXJwdHIt PmtjbWQgPSBuZXc7CisJCXJoID0gJnJ3ZC0+aGFzaFtoYXNoX3B0cihyd2QsIG5ldyldOwor CQlUQUlMUV9JTlNFUlRfVEFJTChyaCwgcnB0ciwgbmV4dCk7CisKKwkJLyogVXBkYXRlIGlu c3RydWN0aW9ucyBwb2ludGVycyAqLworCQlmb3IgKGwgPSBycHRyLT5jbWRfa2xlbjsgbCA+ IDAgOworCQkgICAgbCAtPSBjbWRsZW4sIG9sZCArPSBjbWRsZW4sIG5ldyArPSBjbWRsZW4p IHsKKwkJCWNtZGxlbiA9IEZfTEVOKG9sZCk7CisJCisJCQlpZiAoKHJld3JpdGUgPSBpcGZ3 X2ZpbmRfcmV3cml0ZShvbGQtPm9wY29kZSkpID09IE5VTEwpCisJCQkJY29udGludWU7CisJ CisJCQlpZiAocmV3cml0ZS0+bW92ZSA9PSBOVUxMKQorCQkJCWNvbnRpbnVlOworCQorCQkJ cmV3cml0ZS0+bW92ZShjaGFpbiwgb2xkLCBuZXcpOworCQl9CisJfQorfQorCisvKgorICog RXhwb3J0cyBtb2RpZmllZCBydWxlIHRvIHVzZXJsYW5kLiBSZXR1cm5zIHVzZXJsYW5kIHJ1 bGUgbGVuZ3RoCisgKiAodXNlZCBpbiBpbml0aWFsIHNpemUtY2hlY2tpbmcgY2FsY3VsYXRp b25zKS4gQ29waWVzIHVzZXJsYW5kIHJ1bGUgdmVyc2lvbgorICogd2l0aCB1cGRhdGVkIGNv dW50ZXJzIHRvIHN1cHBsaWVkIGJ1ZmZlci4KKyAqLworaW50CitpcGZ3X2V4cG9ydF9yZXdy aXRlKHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4sIGlwZndfaW5zbiAqa2NtZCwgaXBmd19p bnNuICp0YXJnZXQpCit7CisJc3RydWN0IHJld3JpdGVfcnVsZV9wdHIgKnJwdHI7CisJc3Ry dWN0IHJld3JpdGVfcnVsZV9oZWFkICpyaDsKKwlzdHJ1Y3QgaXBfZndfcndfZGF0YSAqcndk OworCWlwZndfaW5zbiAqdWNtZDsKKworCXJ3ZCA9IGNoYWluLT5yZXdyaXRlX2RhdGE7CisK KwlLQVNTRVJUKHJ3ICE9IE5VTEwsICgiaXBmd19leHBvcnRfcmV3cml0ZTogcmV3cml0ZSBu b3QgaW5pdGlhbGl6ZWQiKSk7CisKKwlyaCA9ICZyd2QtPmhhc2hbaGFzaF9wdHIocndkLCBr Y21kKV07CisKKwlUQUlMUV9GT1JFQUNIKHJwdHIsIHJoLCBuZXh0KSB7CisJCWlmIChycHRy LT5rY21kID09IGtjbWQpCisJCQlicmVhazsKKwl9CisKKwlLQVNTRVJUKHJwdHIgIT0gTlVM TCwgKCJpcGZ3X2V4cG9ydF9yZXdyaXRlOiAga2NtZCBub3QgZm91bmQiKSk7CisJdWNtZCA9 IHJwdHItPmNtZDsKKworCWlmICh0YXJnZXQgIT0gTlVMTCkKKwkJbWVtY3B5KHRhcmdldCwg cnB0ci0+Y21kLCBycHRyLT5jbWRfbGVuICogc2l6ZW9mKHVpbnQzMl90KSk7CisKKwlyZXR1 cm4gKHJwdHItPmNtZF9sZW4gKiBzaXplb2YodWludDMyX3QpKTsKK30KKworLyoKKyAqIGJz ZWFyY2goKSBoZWxwZXIgZnVuY3Rpb24uCisgKi8KK3N0YXRpYyBpbnQKK3Jld3JpdGVfY29t cChjb25zdCB2b2lkICpfa2V5LCBjb25zdCB2b2lkICpfbWVtYmVyKQoreworCXVpbnQzMl90 IG9wY29kZTsKKwlzdHJ1Y3QgaXBfZndfcmV3cml0ZSAqcmV3cml0ZTsKKworCW9wY29kZSA9 ICooKHVpbnQzMl90ICopX2tleSk7CisJcmV3cml0ZSA9IChzdHJ1Y3QgaXBfZndfcmV3cml0 ZSAqKV9tZW1iZXI7CisKKwlpZiAob3Bjb2RlIDwgcmV3cml0ZS0+b3Bjb2RlKQorCQlyZXR1 cm4gKC0xKTsKKwllbHNlIGlmIChvcGNvZGUgPT0gcmV3cml0ZS0+b3Bjb2RlKQorCQlyZXR1 cm4gKDApOworCWVsc2UKKwkJcmV0dXJuICgxKTsKK30KKworCitzdGF0aWMgc3RydWN0IGlw X2Z3X3Jld3JpdGUgKgoraXBmd19maW5kX3Jld3JpdGUodWludDMyX3Qgb3Bjb2RlKQorewor CXNpemVfdCBjb3VudDsKKwlzdHJ1Y3QgaXBfZndfcmV3cml0ZSAqcmV3cml0ZTsKKworCWNv dW50ID0gc2l6ZW9mKHJld3JpdGVzKSAvIHNpemVvZihzdHJ1Y3QgaXBfZndfcmV3cml0ZSk7 CisKKwlyZXdyaXRlID0gKHN0cnVjdCBpcF9md19yZXdyaXRlICopYnNlYXJjaCgmb3Bjb2Rl LCByZXdyaXRlcywKKwkgICAgY291bnQsIHNpemVvZihzdHJ1Y3QgaXBfZndfcmV3cml0ZSks IHJld3JpdGVfY29tcCk7CisKKwlyZXR1cm4gKHJld3JpdGUpOworfQorCisKKy8qCisgKiBD aGVja3MgaWYgZ2l2ZW4gb3Bjb2RlIG5lZWRzIHRvIGJlIGNoYW5nZWQuCisgKiBVcGRhdGVz IEByd2kgYXBwcm9wcmlhdGUgZmllbGRzIGlmIGluc3RydWN0aW9uIG5lZWRzIHRvIGJlCisg KiBzdGF0ZWxlc3Mvc3RhZnVsbHkgcmV3cml0dGVuIHBvc3NpYmx5IHdpdGggY2hhbmdlZCBz aXplLgorICovCit2b2lkCitpcGZ3X2NoZWNrX3Jld3JpdGUoc3RydWN0IGlwX2Z3X2NoYWlu ICpjaGFpbiwgaXBmd19pbnNuICppbnNuLAorICAgIHN0cnVjdCBpcF9md19yd19pbmZvICpy d2kpCit7CisJc3RydWN0IGlwX2Z3X3Jld3JpdGUgKnJld3JpdGU7CisJaW50IGkgPSAwLCBs ZW4gPSAwOworCisJaWYgKChyZXdyaXRlID0gaXBmd19maW5kX3Jld3JpdGUoaW5zbi0+b3Bj b2RlKSkgPT0gTlVMTCkKKwkJaSA9IE5PX1JFV1JJVEU7CisJZWxzZSBpZiAocmV3cml0ZS0+ Y2hlY2sgPT0gTlVMTCkKKwkJaSA9IFNUQVRFTEVTU19SRVdSSVRFOworCWVsc2UKKwkJaSA9 IHJld3JpdGUtPmNoZWNrKGNoYWluLCBpbnNuLCAmbGVuKTsKKworCWlmIChsZW4gIT0gMCkK KwkJcndpLT5sZW5kaWZmICs9IGxlbjsKKworCWlmIChpID09IFNUQVRFTEVTU19SRVdSSVRF KQorCQlyd2ktPmNvdW50Kys7CisKKwlpZiAoaSA9PSBTVEFURUZVTF9SRVdSSVRFKSB7CisJ CXJ3aS0+Y291bnQrKzsKKwkJcndpLT5zdGF0ZXMrKzsKKwl9CisKKwlpZiAoaSAhPSBOT19S RVdSSVRFKQorCQlDVFI0KEtUUl9ORVQsICJvcGNvZGUgJWQ6IGNvdW50PSVkIHN0YXRlcz0l ZCBsZW49JWQiLCAKKwkJICAgIGluc24tPm9wY29kZSwgcndpLT5jb3VudCwgcndpLT5zdGF0 ZXMsIHJ3aS0+bGVuZGlmZik7Cit9CisKKy8qCisgKiBDYWxsIG9wY29kZS1kZXBlbmRlbnQg J3VwZGF0ZScgY2FsbGJhY2suCisgKi8KK3ZvaWQKK2lwZndfdXBkYXRlX3Jld3JpdGUoc3Ry dWN0IGlwX2Z3X2NoYWluICpjaGFpbiwgaXBmd19pbnNuICppbnNuLAorICAgIHZvaWQgKnN0 YXRlLCB1aW50cHRyX3QgdmFsKQoreworCXN0cnVjdCBpcF9md19yZXdyaXRlICpyZXdyaXRl OworCisJaWYgKChyZXdyaXRlID0gaXBmd19maW5kX3Jld3JpdGUoaW5zbi0+b3Bjb2RlKSkg PT0gTlVMTCkKKwkJcmV0dXJuOworCisJaWYgKHJld3JpdGUtPnVwZGF0ZSA9PSBOVUxMKQor CQlyZXR1cm47CisKKwlyZXdyaXRlLT51cGRhdGUoY2hhaW4sIGluc24sIHN0YXRlLCB2YWwp OworfQorCisvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq KioqKioqKioqKioqKioqKioqKioqKgorICogCQkJCQkJCQkgICAgKgorICogICAgICAgICAg T19SRUNWIHwgT19WSUEgfCBPX1hNSVQgcmV3cml0ZSBoYW5kbGluZy4gICAgICAgICAgICAg ICAqCisgKiAJCQkJCQkJCSAgICAqCisgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8KKy8qCisgKiBDb252ZXJ0 cyBpbnNuc19pZiB0byBtb3JlIGNvbXBhY3QgZm9ybS4gQ3VycmVudGx5IGluc3RydWN0aW9u CisgKiBpcyB1c2VkIHRvIHNwZWNpZnkKKyAqIDEpIGludGVyZmFjZSBuYW1lICggLT5uYW1l WzBdICE9ICgnXDAnIHwgJ1wxJykgQU5EIHAuZ2xvYiA9PSAwKQorICogMikgaW50ZXJmYWNl IHBhdHRlcm4gKCAtPm5hbWVbMF0gIT0gKCdcMCcgfCAnXDEnKSBBTkQgcC5nbG9iICE9IDAp CisgKiAzKSBlWHRlbmRlZCB0YWJsZSBudW1iZXIgKCAtPm5hbWVbMF0gPT0gJ1wxJykKKyAq IDQpIGludGVyZmFjZSBhZGRyZXNzICggLT5uYW1lWzBdID09ICdcMCcpCisgKgorICogV2Ug d2FudCB0byBzYXZlIGlmYWNlIGluZGV4IGluIGNhc2UgMSAoYW5kIHRvIGVsaW1pbmF0ZSBp bnRlcmZhY2UgbmFtZSBhdCBhbGwpLgorICogR2l2ZW4gdGhhdCwgd2UgZG8gdGhlIGZvbGxv d2luZzoKKyAqCisgKiBwLmdsb2IgaXMgbm93IHAuaWZfaWR4ICh1X2ludCkgKGdsb2IgaWYg emVybywgaWZhY2UgaW5kZXggb3RoZXJ3aXNlKQorICogby5hcmcxIHdvcmtzIGxpa2UgLT5u YW1lWzBdLCBzbzoKKyAqCisgKiAxKSBpbnRlcmZhY2UgbmFtZSAoby5hcmcxID09IDIsIHAu aWZfaWR4IGNvbnRhaW5zIGluZGV4KQorICogMikgaW50ZXJmYWNlIHBhdHRlcm4gKG8uYXJn MSA9PSAyLCBwLmlmX2lkeCA9PSAwKQorICogMykgZVh0ZW5kZWQgdGFibGUgbnVtYmVyIChv LmFyZzEgPT0gMSkKKyAqIDQpIGludGVyZmFjZSBhZGRyZXNzIChvLmFyZzEgPT0gMCkKKyAq LworCitzdGF0aWMgaW50Citjb252ZXJ0YWJsZV9pbnNuX2lmKHN0cnVjdCBpcF9md19jaGFp biAqY2hhaW4sIGlwZndfaW5zbiAqaW5zbikKK3sKKwlpcGZ3X2luc25faWYgKmNtZCA9IChp cGZ3X2luc25faWYgKilpbnNuOworCisJLyogRWl0aGVyIElQdjQgYWRkcmVzcyBvciBleHRl bmRlZCB0YWJsZSAoMykgYW5kICg0KSAqLworCWlmIChjbWQtPm5hbWVbMF0gPT0gJ1wwJyB8 fCBjbWQtPm5hbWVbMF0gPT0gJ1wxJykKKwkJcmV0dXJuICgwKTsKKworCXJldHVybiAoMSk7 Cit9CisKK3N0YXRpYyBpbnQKK2NoZWNrX2luc25faWYoc3RydWN0IGlwX2Z3X2NoYWluICpj aGFpbiwgaXBmd19pbnNuICppbnNuLCBpbnQgKmxlbl9kaWZmKQoreworCWlwZndfaW5zbl9p ZiAqY21kID0gKGlwZndfaW5zbl9pZiAqKWluc247CisKKwkqbGVuX2RpZmYgPSAwOworCisJ aWYgKGNvbnZlcnRhYmxlX2luc25faWYoY2hhaW4sIGluc24pID09IDApCisJCXJldHVybiAo U1RBVEVMRVNTX1JFV1JJVEUpOworCisJLyogRWl0aGVyIGludGVyZmFjZSBuYW1lICgxKSBv ciBnbG9iIHBhdHRlcm4gKDIpLiAqLworCisJaWYgKGNtZC0+cC5nbG9iICE9IDApCisJCXJl dHVybiAoU1RBVEVMRVNTX1JFV1JJVEUpOworCWVsc2UKKwkJcmV0dXJuIChTVEFURUZVTF9S RVdSSVRFKTsKK30KKworc3RhdGljIGludAorcHJlcGFyZV9pbnNuX2lmKHN0cnVjdCBpcF9m d19jaGFpbiAqY2hhaW4sIGlwZndfaW5zbiAqaW5zbiwgdm9pZCAqKnBzdGF0ZSkKK3sKKwlz dHJ1Y3QgaWZhY2VfbWFzayAqaWZtOworCXN0cnVjdCBpcGZ3X2luc25fcHRyICppbnNuX3B0 cjsKKwlpcGZ3X2luc25faWYgKmNtZCA9IChpcGZ3X2luc25faWYgKilpbnNuOworCisJaWYg KGNvbnZlcnRhYmxlX2luc25faWYoY2hhaW4sIGluc24pID09IDApCisJCXJldHVybiAoU1RB VEVMRVNTX1JFV1JJVEUpOworCisJaWYgKGNtZC0+cC5nbG9iICE9IDApIHsKKwkJLyogR2xv YiBwYXR0ZXJuICgyKSwgbm8gc3RhdGUgbmVlZGVkLCAqLworCQlyZXR1cm4gKFNUQVRFTEVT U19SRVdSSVRFKTsKKwl9CisKKwkvKiBBbGxvY2F0ZSBkYXRhIHVzZWQgYnkgY29udmVydCBj YWxsYmFjayAqLworCWluc25fcHRyID0gbWFsbG9jKHNpemVvZihzdHJ1Y3QgaXBmd19pbnNu X3B0ciksIE1fSVBGVywKKwkgICAgTV9XQUlUT0sgfCBNX1pFUk8pOworCWlmbSA9IG1hbGxv YyhzaXplb2Yoc3RydWN0IGlmYWNlX21hc2spLCBNX0lQRlcsIE1fV0FJVE9LIHwgTV9aRVJP KTsKKworCVRBSUxRX0lOSVQoJmlmbS0+aW5zdHJ1Y3Rpb25zKTsKKwlUQUlMUV9JTlNFUlRf VEFJTCgmaWZtLT5pbnN0cnVjdGlvbnMsIGluc25fcHRyLCBuZXh0KTsKKworCUNUUjMoS1RS X05FVCwgInBzdGF0ZSAlcCwgdmFsICVwIGluc25zICVwIiwgcHN0YXRlLCBpZm0sIGluc24p OworCisJKnBzdGF0ZSA9IGlmbTsKKwlyZXR1cm4gKFNUQVRFRlVMX1JFV1JJVEUpOworfQor CitzdGF0aWMgaW50Citjb252ZXJ0X2luc25faWYoc3RydWN0IGlwX2Z3X2NoYWluICpjaGFp biwgaXBmd19pbnNuICpfb2xkLCBpcGZ3X2luc24gKl9uZXcsCisgICAgdm9pZCAqc3RhdGUs IGludCAqbGVuKQoreworCXN0cnVjdCBpZmFjZV9tYXNrICppZm0sICppZm0yOworCXN0cnVj dCBpcGZ3X2luc25fcHRyICppbnNuX3B0cjsKKwlpcGZ3X2luc25faWYgKmNtZF9vbGQgPSAo aXBmd19pbnNuX2lmICopX29sZDsKKwlpcGZ3X2luc25faWYgKmNtZF9uZXcgPSAoaXBmd19p bnNuX2lmICopX25ldzsKKworCS8qIFNldCBsZW5ndGggYW55d2F5ICovCisJKmxlbiA9IEZf SU5TTl9TSVpFKGlwZndfaW5zbl9pZik7CisJbWVtY3B5KGNtZF9uZXcsIGNtZF9vbGQsIHNp emVvZihpcGZ3X2luc25faWYpKTsKKworCWlmIChjb252ZXJ0YWJsZV9pbnNuX2lmKGNoYWlu LCBfb2xkKSA9PSAwKSB7CisJCS8qCisJCSAqIGNhc2UgKDMsIGVYIHRhYmxlKTogby5hcmcx ID0gMQorCQkgKiBjYXNlICg0LCBpZmFkZHIpOiBvLmFyZzEgPSAwCisJCSAqLworCisJCWNt ZF9uZXctPm8uYXJnMSA9IChjbWRfb2xkLT5uYW1lWzBdID09ICdcMScpID8gMSA6IDA7CisK KwkJcmV0dXJuIChTVEFURUxFU1NfUkVXUklURSk7CisJfQorCisJLyoKKwkgKiBQcmVwYXJl IGluc3RydWN0aW9uIGZvciBhbHRlcmluZy4KKwkgKiBjYXNlICgxLCBpZm5hbWUpOiBvLmFy ZzEgPSAyOyBwX2lmX2lkeCA9PSBpbnRlcmZhY2UgaW5kZXgKKwkgKiBjYXNlICgyLCBnbG9i KTogby5hcmcxID0gMicgcC5pZl9pZHggPSAwCisJICovCisJbWVtY3B5KGNtZF9uZXcsIGNt ZF9vbGQsIHNpemVvZihpcGZ3X2luc25faWYpKTsKKwljbWRfbmV3LT5vLmFyZzEgPSAyOwor CisJaWYgKGNtZF9vbGQtPnAuZ2xvYikgeworCQkvKiBJbnRlcmZhY2UgbWFzayAoMikuIENv cHkgYXMgaXMgYW5kIHNldCBpbmRleCAqLworCQljbWRfbmV3LT5wLmlmX2lkeCA9IDA7CisJ CXJldHVybiAoU1RBVEVMRVNTX1JFV1JJVEUpOworCX0KKworCS8qIEludGVyZmFjZSBuYW1l LiAqLworCWlmbSA9IChzdHJ1Y3QgaWZhY2VfbWFzayAqKXN0YXRlOworCWluc25fcHRyID0g VEFJTFFfRklSU1QoJmlmbS0+aW5zdHJ1Y3Rpb25zKTsKKworCWluc25fcHRyLT5pbnNuID0g X25ldzsKKworCWlmICgoaWZtMiA9IGlwZndfc2VhcmNoX2lmbmFtZShjaGFpbiwgY21kX29s ZC0+bmFtZSkpICE9IE5VTEwpIHsKKwkJLyogSW50ZXJmYWNlIGZvdW5kLCBsaW5rIGVudHJ5 IGhlcmUgKi8KKwkJVEFJTFFfSU5TRVJUX1RBSUwoJmlmbTItPmluc3RydWN0aW9ucywgaW5z bl9wdHIsIG5leHQpOworCQlpZm0yLT5yZWZjb3VudCsrOworCQljbWRfbmV3LT5wLmlmX2lk eCA9IGlmbTItPmlkeDsKKwkJaWYgKGlmbTItPmZsYWdzICYgSVBGV19JRkxBR19GQUtFKQor CQkJY21kX25ldy0+cC5pZl9pZHggfD0gSVBGV19GQUtFX0lEWDsKKworCQlmcmVlKGlmbSwg TV9JUEZXKTsKKwkJcmV0dXJuIChTVEFURUZVTF9SRVdSSVRFKTsKKwl9CisKKwkvKiBJbnRl cmZhY2Ugbm90IGZvdW5kLCBhZGQgYW5kIG1hcmsgYXMgdW5leGlzdGVudCAqLworCXN0cmxj cHkoaWZtLT5uYW1lLCBjbWRfb2xkLT5uYW1lLCBJRk5BTVNJWik7CisJaWZtLT5mbGFncyB8 PSBJUEZXX0lGTEFHX0ZBS0U7CisJaWZtLT5yZWZjb3VudCsrOworCWlwZndfYWRkX2lmbmFt ZShjaGFpbiwgaWZtKTsKKwljbWRfbmV3LT5wLmlmX2lkeCA9IGlmbS0+aWR4IHwgSVBGV19G QUtFX0lEWDsKKwkvKiBBZGQgaW5zdHJ1Y3Rpb24gYmFjayAoYWRkX2lmbmFtZSByZWluaXRz IGxpc3QpICovCisJVEFJTFFfSU5TRVJUX1RBSUwoJmlmbS0+aW5zdHJ1Y3Rpb25zLCBpbnNu X3B0ciwgbmV4dCk7CisKKwlyZXR1cm4gKFNUQVRFRlVMX1JFV1JJVEUpOworfQorCitzdGF0 aWMgdm9pZAorY2xlYXJfaW5zbl9pZihzdHJ1Y3QgaXBfZndfY2hhaW4gKmNoYWluLCBpcGZ3 X2luc24gKl9zcmMsIHZvaWQgKmRhdGEpCit7CisJc3RydWN0IGlmYWNlX21hc2sgKmlmbTsK KwlpcGZ3X2luc25faWYgKmNtZDsKKwlzdHJ1Y3QgaXBmd19pbnNuX3B0ciAqaW5zbl9wdHIg PSAoc3RydWN0IGlwZndfaW5zbl9wdHIgKilkYXRhOworCisJY21kID0gKGlwZndfaW5zbl9p ZiAqKV9zcmM7CisKKwkvKiBTdGF0ZSBpcyB1c2VkIGZvciBpbnRlcmZhY2UgbmFtZXMsIHNr aXAgb3RoZXIgY2FzZXMgKi8KKwlpZiAoY21kLT5vLmFyZzEgIT0gMikKKwkJcmV0dXJuOwor CisJaWZtID0gaXBmd19zZWFyY2hfaWZpbmRleChjaGFpbiwgY21kLT5wLmlmX2lkeCk7CisJ S0FTU0VSVChpZm0gIT0gTlVMTCwgKCJubyBpZnAgZm91bmQgZm9yIGluZGV4ICV1IiwgY21k LT5wLmlmX2lkeCkpOworCisJaWYgKGluc25fcHRyID09IE5VTEwpIHsKKwkJVEFJTFFfRk9S RUFDSChpbnNuX3B0ciwgJmlmbS0+aW5zdHJ1Y3Rpb25zLCBuZXh0KSB7CisJCQlpZiAoaW5z bl9wdHItPmluc24gPT0gX3NyYykKKwkJCQlicmVhazsKKwkJfQorCisJCUtBU1NFUlQoaW5z bl9wdHIgIT0gTlVMTCwgKCJubyBpbnNucyBmb3VuZCIpKTsKKwl9CisKKwkvKiBSZW1vdmUg aW5zdHJ1Y3Rpb24gZnJvbSBpbnRlcmZhY2UgKi8KKwlUQUlMUV9SRU1PVkUoJmlmbS0+aW5z dHJ1Y3Rpb25zLCBpbnNuX3B0ciwgbmV4dCk7CisJaWZtLT5yZWZjb3VudC0tOworCisJZnJl ZShpbnNuX3B0ciwgTV9JUEZXKTsKK30KKworc3RhdGljIHZvaWQKK3VwZGF0ZV9pbnNuX2lm KHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4sIGlwZndfaW5zbiAqaW5zbiwgdm9pZCAqX2lm YWNlX21hc2ssCisgICAgdWludHB0cl90IG5ld19pZCkKK3sKKwlzdHJ1Y3QgaXBfZndfaWZf ZGF0YSAqaWZkOworCWlwZndfaW5zbl9pZiAqY21kOworCisJSVBGV19XTE9DS19BU1NFUlQo Y2hhaW4pOworCisJaWZkID0gY2hhaW4tPmlmX2RhdGE7CisJY21kID0gKGlwZndfaW5zbl9p ZiAqKWluc247CisKKwlDVFIyKEtUUl9ORVQsICJ1cGRhdGluZyBpbnNuOiBpZmkgJXUgLT4g JXUiLAorCSAgICBjbWQtPnAuaWZfaWR4LCAodWludDMyX3QpbmV3X2lkKTsKKworCWNtZC0+ cC5pZl9pZHggPSAodWludDMyX3QpbmV3X2lkOworfQorCitzdGF0aWMgdm9pZAorbW92ZV9p bnNuX2lmKHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4sIGlwZndfaW5zbiAqX29sZCwgaXBm d19pbnNuICpfbmV3KQoreworCXN0cnVjdCBpZmFjZV9tYXNrICppZm07CisJaXBmd19pbnNu X2lmICpjbWQ7CisJc3RydWN0IGlwZndfaW5zbl9wdHIgKmluc25fcHRyOworCisJY21kID0g KGlwZndfaW5zbl9pZiAqKV9vbGQ7CisKKwkvKiBTdGF0ZSBpcyB1c2VkIGZvciBpbnRlcmZh Y2UgbmFtZXMsIHNraXAgb3RoZXIgY2FzZXMgKi8KKwlpZiAoY21kLT5vLmFyZzEgIT0gMikK KwkJcmV0dXJuOworCisJaWZtID0gaXBmd19zZWFyY2hfaWZpbmRleChjaGFpbiwgY21kLT5w LmlmX2lkeCk7CisJS0FTU0VSVChpZm0gIT0gTlVMTCwgKCJubyBpZnAgZm91bmQgZm9yIGlu ZGV4ICV1IiwgY21kLT5wLmlmX2lkeCkpOworCisJVEFJTFFfRk9SRUFDSChpbnNuX3B0ciwg JmlmbS0+aW5zdHJ1Y3Rpb25zLCBuZXh0KSB7CisJCWlmIChpbnNuX3B0ci0+aW5zbiA9PSBf b2xkKQorCQkJYnJlYWs7CisJfQorCisJS0FTU0VSVChpbnNuX3B0ciAhPSBOVUxMLCAoIm5v IGluc25zIGZvdW5kIikpOworCisJaW5zbl9wdHItPmluc24gPSBfbmV3OworfQorCisKLS0t IC9kZXYvbnVsbAkyMDEzLTA0LTI0IDE3OjIwOjE5LjAwMDAwMDAwMCArMDQwMAorKysgc3lz L25ldHBmaWwvaXBmdy9pcF9md19pZmFjZS5jCTIwMTMtMDQtMjQgMTc6MTg6MzUuNTQ2MzU3 NTk0ICswNDAwCkBAIC0wLDAgKzEsNDY3IEBACisvKi0KKyAqIENvcHlyaWdodCAoYykgMjAx MyBZYW5kZXggTExDLgorICogQXV0aG9yOiBBbGV4YW5kZXIgVi4gQ2hlcm5pa292IDxtZWxp ZmFyb0B5YW5kZXgtdGVhbS5ydT4KKyAqCisgKiBSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGlu IHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdpdGhvdXQKKyAqIG1vZGlmaWNh dGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcgY29uZGl0 aW9ucworICogYXJlIG1ldDoKKyAqIDEuIFJlZGlzdHJpYnV0aW9ucyBvZiBzb3VyY2UgY29k ZSBtdXN0IHJldGFpbiB0aGUgYWJvdmUgY29weXJpZ2h0CisgKiAgICBub3RpY2UsIHRoaXMg bGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCisgKiAy LiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFi b3ZlIGNvcHlyaWdodAorICogICAgbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBh bmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyIGluIHRoZQorICogICAgZG9jdW1lbnRhdGlv biBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdpdGggdGhlIGRpc3RyaWJ1dGlv bi4KKyAqCisgKiBUSElTIFNPRlRXQVJFIElTIFBST1ZJREVEIEJZIFRIRSBBVVRIT1IgQU5E IENPTlRSSUJVVE9SUyBgYEFTIElTJycgQU5ECisgKiBBTlkgRVhQUkVTUyBPUiBJTVBMSUVE IFdBUlJBTlRJRVMsIElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBUSEUKKyAqIElN UExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEg UEFSVElDVUxBUiBQVVJQT1NFCisgKiBBUkUgRElTQ0xBSU1FRC4gIElOIE5PIEVWRU5UIFNI QUxMIFRIRSBBVVRIT1IgT1IgQ09OVFJJQlVUT1JTIEJFIExJQUJMRQorICogRk9SIEFOWSBE SVJFQ1QsIElORElSRUNULCBJTkNJREVOVEFMLCBTUEVDSUFMLCBFWEVNUExBUlksIE9SIENP TlNFUVVFTlRJQUwKKyAqIERBTUFHRVMgKElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRP LCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdPT0RTCisgKiBPUiBTRVJWSUNFUzsgTE9T UyBPRiBVU0UsIERBVEEsIE9SIFBST0ZJVFM7IE9SIEJVU0lORVNTIElOVEVSUlVQVElPTikK KyAqIEhPV0VWRVIgQ0FVU0VEIEFORCBPTiBBTlkgVEhFT1JZIE9GIExJQUJJTElUWSwgV0hF VEhFUiBJTiBDT05UUkFDVCwgU1RSSUNUCisgKiBMSUFCSUxJVFksIE9SIFRPUlQgKElOQ0xV RElORyBORUdMSUdFTkNFIE9SIE9USEVSV0lTRSkgQVJJU0lORyBJTiBBTlkgV0FZCisgKiBP VVQgT0YgVEhFIFVTRSBPRiBUSElTIFNPRlRXQVJFLCBFVkVOIElGIEFEVklTRUQgT0YgVEhF IFBPU1NJQklMSVRZIE9GCisgKiBTVUNIIERBTUFHRS4KKyAqLworCisjaW5jbHVkZSA8c3lz L2NkZWZzLmg+CitfX0ZCU0RJRCgiJEZyZWVCU0QkIik7CisKKy8qCisgKiBJbnRlcmZhY2Ug dHJhY2tpbmcgZm9yIGlwZncuCisgKi8KKworI2luY2x1ZGUgIm9wdF9pcGZ3LmgiCisKKyNp bmNsdWRlIDxzeXMvcGFyYW0uaD4KKyNpbmNsdWRlIDxzeXMvc3lzdG0uaD4KKyNpbmNsdWRl IDxzeXMvbWFsbG9jLmg+CisjaW5jbHVkZSA8c3lzL2tlcm5lbC5oPgorI2luY2x1ZGUgPHN5 cy9sb2NrLmg+CisjaW5jbHVkZSA8c3lzL3J3bG9jay5oPgorI2luY2x1ZGUgPHN5cy9mbnZf aGFzaC5oPgorI2luY2x1ZGUgPHN5cy9zb2NrZXQuaD4KKyNpbmNsdWRlIDxuZXQvaWYuaD4K KyNpbmNsdWRlIDxuZXQvdm5ldC5oPgorCisjaW5jbHVkZSA8bmV0aW5ldC9pbi5oPgorI2lu Y2x1ZGUgPG5ldGluZXQvaXBfdmFyLmg+IC8qIGhvb2tzICovCisjaW5jbHVkZSA8bmV0aW5l dC9pcF9mdy5oPgorCisjaW5jbHVkZSA8bmV0cGZpbC9pcGZ3L2lwX2Z3X3ByaXZhdGUuaD4K KyNpbmNsdWRlIDxuZXRwZmlsL2lwZncvaXBfZndfaWZhY2UuaD4KKworI2RlZmluZQlJUEZX X0lGSEFTSF9JRFgoaWR4LCBoc2l6ZSkJKChpZHgpICUgKGhzaXplKSkKKyNkZWZpbmUJSVBG V19JRkhBU0hfTkFNRShuYW1lLCBoc2l6ZSkJKGZudl8zMl9zdHIobmFtZSwgRk5WMV8zMl9J TklUKSAlIChoc2l6ZSkpCisKK1RBSUxRX0hFQUQoaWZhY2VfbWFza19oZWFkLCBpZmFjZV9t YXNrKTsKKworc3RydWN0IGlwX2Z3X2lmX2RhdGEgeworCXN0cnVjdCBpZmFjZV9tYXNrX2hl YWQgKm1hc2tzOyAvKiBJbnRlcmZhY2UgbmFtZSBoYXNoICovCisJc2l6ZV90IG1hc2tzX2Nv dW50LCBtYXNrc19oc2l6ZTsKKwlzdHJ1Y3QgaWZhY2VfbWFza19oZWFkICpyZWFsX2lmYWNl czsgLyogJ1JlYWwnIGludGVyZmFjZSBpbmRleCBoYXNoICovCisJc2l6ZV90IHJlYWxfY291 bnQsIHJlYWxfaHNpemU7CisJc3RydWN0IGlmYWNlX21hc2tfaGVhZCAqZmFrZV9pZmFjZXM7 IC8qIE5vbmV4aXN0ZW50IGludGVyZmFjZSBpbmRleCBoYXNoICovCisJc2l6ZV90IGZha2Vf Y291bnQsIGZha2VfaHNpemU7CisJZXZlbnRoYW5kbGVyX3RhZyBhcnJpdmFsLCBkZXBhcnR1 cmU7CisJdV9zaG9ydCBmYWtlX2lkeDsKK307CisKK3N0YXRpYyB2b2lkIGlwZndfaWZoYXNo X2luaXRfaW50KHN0cnVjdCBpZmFjZV9tYXNrX2hlYWQgKipwaGFzaCwgc2l6ZV90IGhzaXpl KTsKK3N0YXRpYyB2b2lkIGlwZndfaWZuZXRfaW5pdChzdHJ1Y3QgaXBfZndfY2hhaW4gKmNo YWluLCBzdHJ1Y3QgaWZhY2VfbWFzayAqaWZtKTsKKworLyoKKyAqIE1hcHBpbmdzOgorICog J2lmYWNlX21hc2snIC0+IGlkeAorICogaWZfaW5kZXggLT4gaWZhY2VfbWFzaworICogZmFr ZV9pbmRleCAtPiBpZmFjZV9tYXNrCisgKgorICogTGlzdCBvZiBtYXNrcworICoKKyAqLwor c3RhdGljIHZvaWQgaWZuZXRfYXJyaXZhbCh2b2lkICphcmcsIHN0cnVjdCBpZm5ldCAqaWZw KTsKK3N0YXRpYyB2b2lkIGlmbmV0X2RlcGFydHVyZSh2b2lkICphcmcsIHN0cnVjdCBpZm5l dCAqaWZwKTsKKworLyoKKyAqIEZpbmQgaW50ZXJmYWNlIHN0cnVjdHVyZSBieSBuYW1lLgor ICogQ2FsbGVkIHdpdGggZWl0aGVyIFVIIG9yIGNoYWluIHJlYWRsb2NrIGhlbGQuCisgKi8K K3N0cnVjdCBpZmFjZV9tYXNrICoKK2lwZndfc2VhcmNoX2lmbmFtZShzdHJ1Y3QgaXBfZndf Y2hhaW4gKmNoYWluLCBjaGFyICpuYW1lKQoreworCXN0cnVjdCBpZmFjZV9tYXNrICppZm07 CisJc3RydWN0IGlwX2Z3X2lmX2RhdGEgKmlmZDsKKwlzdHJ1Y3QgaWZhY2VfbWFza19oZWFk ICppZmg7CisJaW50IGk7CisKKwlpZmQgPSBjaGFpbi0+aWZfZGF0YTsKKworCWkgPSBJUEZX X0lGSEFTSF9OQU1FKG5hbWUsIGlmZC0+bWFza3NfaHNpemUpOworCisJaWZoID0gJmlmZC0+ bWFza3NbaV07CisJVEFJTFFfRk9SRUFDSChpZm0sIGlmaCwgbmFtZV9uZXh0KSB7CisJCWlm IChzdHJjbXAobmFtZSwgaWZtLT5uYW1lKSA9PSAwKQorCQkJcmV0dXJuIChpZm0pOworCX0K KworCXJldHVybiAoTlVMTCk7Cit9CisKKy8qCisgKiBGaW5kIGludGVyZmFjZSBzdHJ1Y3R1 cmUgYnkgcmVhbCBvciBmYWtlIGlmaW5kZXguCisgKiBDYWxsZWQgd2l0aCBlaXRoZXIgVUgg b3IgY2hhaW4gcmVhZGxvY2sgaGVsZC4KKyAqLworc3RydWN0IGlmYWNlX21hc2sgKgoraXBm d19zZWFyY2hfaWZpbmRleChzdHJ1Y3QgaXBfZndfY2hhaW4gKmNoYWluLCB1aW50MzJfdCBp ZHgpCit7CisJc3RydWN0IGlmYWNlX21hc2sgKmlmbTsKKwlzdHJ1Y3QgaXBfZndfaWZfZGF0 YSAqaWZkOworCXN0cnVjdCBpZmFjZV9tYXNrX2hlYWQgKmlmaDsKKwlpbnQgaTsKKworCWlm ZCA9IGNoYWluLT5pZl9kYXRhOworCisJaWYgKGlkeCAmIElQRldfRkFLRV9JRFgpIHsKKwkJ aWR4ICY9IH5JUEZXX0ZBS0VfSURYOworCQlpID0gSVBGV19JRkhBU0hfSURYKGlkeCwgaWZk LT5mYWtlX2hzaXplKTsKKwkJaWZoID0gJmlmZC0+ZmFrZV9pZmFjZXNbaV07CisJfSBlbHNl IHsKKwkJaSA9IElQRldfSUZIQVNIX0lEWChpZHgsIGlmZC0+cmVhbF9oc2l6ZSk7CisJCWlm aCA9ICZpZmQtPnJlYWxfaWZhY2VzW2ldOworCX0KKworCVRBSUxRX0ZPUkVBQ0goaWZtLCBp ZmgsIGlkeF9uZXh0KSB7CisJCWlmIChpZm0tPmlkeCA9PSBpZHgpCisJCQlyZXR1cm4gKGlm bSk7CisJfQorCisJcmV0dXJuIChOVUxMKTsKK30KKwordm9pZAoraXBmd19hZGRfaWZuYW1l KHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4sIHN0cnVjdCBpZmFjZV9tYXNrICppZm0pCit7 CisJc3RydWN0IGlwX2Z3X2lmX2RhdGEgKmlmZDsKKwlzdHJ1Y3QgaWZhY2VfbWFza19oZWFk ICppZmg7CisJc3RydWN0IGlmYWNlX21hc2sgKmlmdGVtcDsKKwlpbnQgaTsKKworCWlmZCA9 IGNoYWluLT5pZl9kYXRhOworCisJaXBmd19pZm5ldF9pbml0KGNoYWluLCBpZm0pOworCisJ LyogQWRkIHRvIG5hbWVkIGhhc2ggKi8KKwlpID0gSVBGV19JRkhBU0hfTkFNRShpZm0tPm5h bWUsIGlmZC0+bWFza3NfaHNpemUpOworCWlmaCA9ICZpZmQtPm1hc2tzW2ldOworCVRBSUxR X0lOU0VSVF9UQUlMKGlmaCwgaWZtLCBuYW1lX25leHQpOworCisJaWYgKGlmbS0+ZmxhZ3Mg JiBJUEZXX0lGTEFHX0ZBS0UpIHsKKwkJLyogQWRkIHRvIGZha2UgaW50ZXJmYWNlcyBoYXNo ICovCisJCWlmbS0+aWR4ID0gKytpZmQtPmZha2VfaWR4OworCQlpID0gSVBGV19JRkhBU0hf SURYKGlmbS0+aWR4LCBpZmQtPmZha2VfaHNpemUpOworCQlpZmggPSAmaWZkLT5mYWtlX2lm YWNlc1tpXTsKKwl9IGVsc2UgeworCQkvKiBBZGQgdG8gcmVhbCBpbnRlcmZhY2VzIGhhc2gg Ki8KKwkJaSA9IElQRldfSUZIQVNIX0lEWChpZm0tPmlkeCwgaWZkLT5yZWFsX2hzaXplKTsK KwkJaWZoID0gJmlmZC0+cmVhbF9pZmFjZXNbaV07CisJCisJCS8qIENoZWNrIGluZGV4IGZv ciBjb25zaXN0ZW5jeSAqLworCQlUQUlMUV9GT1JFQUNIKGlmdGVtcCwgaWZoLCBpZHhfbmV4 dCkgeworCQkJS0FTU0VSVChpZnRlbXAtPmlkeCAhPSBpZm0tPmlkeCwKKwkJCSAgICAoIk5v bi1mYWtlIGlmICVzIHcgaWR4ICVkIGZvdW5kICglcykhIiwKKwkJCSAgICAgaWZ0ZW1wLT5u YW1lLCBpZm0tPmlkeCwgaWZtLT5uYW1lKSk7CisJCX0KKwl9CisJCisJVEFJTFFfSU5TRVJU X1RBSUwoaWZoLCBpZm0sIGlkeF9uZXh0KTsKK30KKworc3RhdGljIHZvaWQKK2lmbmV0X2Fy cml2YWwodm9pZCAqYXJnLCBzdHJ1Y3QgaWZuZXQgKmlmcCkKK3sKKwlzdHJ1Y3QgaXBfZndf Y2hhaW4gKmNoYWluID0gKHN0cnVjdCBpcF9md19jaGFpbiAqKWFyZzsKKwlzdHJ1Y3QgaXBf ZndfaWZfZGF0YSAqaWZkOworCXN0cnVjdCBpZmFjZV9tYXNrICppZnRlbXAsICppZm07CisJ c3RydWN0IGlmYWNlX21hc2tfaGVhZCAqaWZoOworCXN0cnVjdCBpcGZ3X2luc25fcHRyICpp bnNuX3B0cjsKKwlpbnQgaTsKKworCWlmdGVtcCA9IG1hbGxvYyhzaXplb2Yoc3RydWN0IGlm YWNlX21hc2spLCBNX0lQRlcsIE1fV0FJVE9LIHwgTV9aRVJPKTsKKworCWlmdGVtcC0+aWZw ID0gaWZwOworCWlmdGVtcC0+aWR4ID0gaWZwLT5pZl9pbmRleDsKKwlzdHJsY3B5KGlmdGVt cC0+bmFtZSwgaWZwLT5pZl94bmFtZSwgSUZOQU1TSVopOworCisJSVBGV19VSF9XTE9DSyhj aGFpbik7CisJSVBGV19XTE9DSyhjaGFpbik7CisKKwlpZmQgPSBjaGFpbi0+aWZfZGF0YTsK KworCWlmIChpZmQgPT0gTlVMTCB8fCBpZmQtPmFycml2YWwgPT0gTlVMTCkgeworCQkvKiBX ZSdyZSBzaHV0dGluZyBkb3duICovCisJCUlQRldfV1VOTE9DSyhjaGFpbik7CisJCUlQRldf VUhfV1VOTE9DSyhjaGFpbik7CisJCWZyZWUoaWZ0ZW1wLCBNX0lQRlcpOworCQlyZXR1cm47 CisJfQorCisJaWZtID0gaXBmd19zZWFyY2hfaWZuYW1lKGNoYWluLCBpZnRlbXAtPm5hbWUp OworCisJaWYgKGlmbSAhPSBOVUxMKSB7CisJCS8qIEZvdW5kLiBMZXQncyB1cGRhdGUgaW5k ZXggKi8KKwkJS0FTU0VSVChpZm0tPmZsYWdzICYgSVBGV19JRkxBR19GQUtFLAorCQkgICAg KCJOb24tZmFrZSBpbnRlcmZhY2UgZm91bmQgZm9yICVzIiwgaWZtLT5uYW1lKSk7CisKKwkJ aWZtLT5mbGFncyAmPSB+SVBGV19JRkxBR19GQUtFOworCQkvKiBSZWxpbmsgdG8gcmVhbCBp bmRleCAqLworCQlpID0gSVBGV19JRkhBU0hfSURYKGlmbS0+aWR4LCBpZmQtPmZha2VfaHNp emUpOworCQlpZmggPSAmaWZkLT5mYWtlX2lmYWNlc1tpXTsKKwkJVEFJTFFfUkVNT1ZFKGlm aCwgaWZtLCBpZHhfbmV4dCk7CisKKwkJaSA9IElQRldfSUZIQVNIX0lEWChpZnRlbXAtPmlk eCwgaWZkLT5yZWFsX2hzaXplKTsKKwkJaWZoID0gJmlmZC0+cmVhbF9pZmFjZXNbaV07CisJ CVRBSUxRX0lOU0VSVF9UQUlMKGlmaCwgaWZtLCBpZHhfbmV4dCk7CisKKwkJQ1RSMihLVFJf TkVULCAiaWZuZXQgdXBncmFkZTogZmFrZSAldSAtPiAldSIsIGlmbS0+aWR4LAorCQkgICAg aWZ0ZW1wLT5pZHgpOworCQkvKiBOb3RpZnkgY29uc3VtZXJzICovCisJCVRBSUxRX0ZPUkVB Q0goaW5zbl9wdHIsICZpZm0tPmluc3RydWN0aW9ucywgbmV4dCkKKwkJCWlwZndfdXBkYXRl X3Jld3JpdGUoY2hhaW4sIGluc25fcHRyLT5pbnNuLCBpZm0sCisJCQkgICAgKHVpbnRwdHJf dClpZnRlbXAtPmlkeCk7CisKKwkJaWZtLT5pZHggPSBpZnRlbXAtPmlkeDsKKwl9IGVsc2Ug eworCQkvKiBOb3QgZm91bmQuIEFkZCB0byBsaXN0ICovCisJCWlmbSA9IGlmdGVtcDsKKwkJ aWZ0ZW1wID0gTlVMTDsKKworCQlpcGZ3X2lmbmV0X2luaXQoY2hhaW4sIGlmbSk7CisKKwkJ Q1RSMihLVFJfTkVULCAiaWZtcD0lcCB1Yz0ldSIsIGlmbSwgaWZtLT5yZWZjb3VudCk7CisK KwkJLyogQWRkIHRvIG5hbWVkIGhhc2ggKi8KKwkJaSA9IElQRldfSUZIQVNIX05BTUUoaWZt LT5uYW1lLCBpZmQtPm1hc2tzX2hzaXplKTsKKwkJaWZoID0gJmlmZC0+bWFza3NbaV07CisJ CVRBSUxRX0lOU0VSVF9UQUlMKGlmaCwgaWZtLCBuYW1lX25leHQpOworCisJCS8qIEFkZCB0 byByZWFsIGludGVyZmFjZXMgaGFzaCAqLworCQlpID0gSVBGV19JRkhBU0hfSURYKGlmbS0+ aWR4LCBpZmQtPnJlYWxfaHNpemUpOworCQlpZmggPSAmaWZkLT5yZWFsX2lmYWNlc1tpXTsK KworCQkvKiBDaGVjayBpbmRleCBmb3IgY29uc2lzdGVuY3kgKi8KKwkJVEFJTFFfRk9SRUFD SChpZnRlbXAsIGlmaCwgaWR4X25leHQpIHsKKwkJCUtBU1NFUlQoaWZ0ZW1wLT5pZHggIT0g aWZtLT5pZHgsCisJCQkgICAgKCJOb24tZmFrZSBpZiAlcyB3IGlkeCAlZCBmb3VuZCAoJXMp ISIsCisJCQkgICAgIGlmdGVtcC0+bmFtZSwgaWZtLT5pZHgsIGlmbS0+bmFtZSkpOworCQl9 CisKKwkJVEFJTFFfSU5TRVJUX1RBSUwoaWZoLCBpZm0sIGlkeF9uZXh0KTsKKworCQlDVFIz KEtUUl9ORVQsICJuZXcgaWZhY2UgJXAsIGlkeCAldSB1Yz0ldSIsIGlmbS0+bmFtZSwKKwkJ ICAgIGlmbS0+aWR4LCBpZm0tPnJlZmNvdW50KTsKKwl9CisJSVBGV19XVU5MT0NLKGNoYWlu KTsKKwlJUEZXX1VIX1dVTkxPQ0soY2hhaW4pOworCisJaWYgKGlmdGVtcCAhPSBOVUxMKQor CQlmcmVlKGlmdGVtcCwgTV9JUEZXKTsKK30KKworc3RhdGljIHZvaWQKK2lmbmV0X2RlcGFy dHVyZSh2b2lkICphcmcsIHN0cnVjdCBpZm5ldCAqaWZwKQoreworCXN0cnVjdCBpcF9md19j aGFpbiAqY2hhaW4gPSAoc3RydWN0IGlwX2Z3X2NoYWluICopYXJnOworCXN0cnVjdCBpcF9m d19pZl9kYXRhICppZmQ7CisJc3RydWN0IGlmYWNlX21hc2sgKmlmbTsKKwlzdHJ1Y3QgaWZh Y2VfbWFza19oZWFkICppZmg7CisJc3RydWN0IGlwZndfaW5zbl9wdHIgKmluc25fcHRyOwor CWludCBpOworCisJSVBGV19VSF9XTE9DSyhjaGFpbik7CisJSVBGV19XTE9DSyhjaGFpbik7 CisKKwlpZiAoKGlmZCA9IGNoYWluLT5pZl9kYXRhKSA9PSBOVUxMKSB7CisJCS8qIFdlJ3Jl IHNodXR0aW5nIGRvd24gKi8KKwkJSVBGV19XVU5MT0NLKGNoYWluKTsKKwkJSVBGV19VSF9X VU5MT0NLKGNoYWluKTsKKwkJcmV0dXJuOworCX0KKworCWlmbSA9IGlwZndfc2VhcmNoX2lm bmFtZShjaGFpbiwgaWZwLT5pZl94bmFtZSk7CisKKwlpZiAoaWZtID09IE5VTEwpIHsKKwkJ SVBGV19XVU5MT0NLKGNoYWluKTsKKwkJSVBGV19VSF9XVU5MT0NLKGNoYWluKTsKKwkJcHJp bnRmKCJpcGZ3OiB1bmtub3duIGlmYWNlICVzIGRlcGFydHVyZVxuIiwgaWZwLT5pZl94bmFt ZSk7CisJCXJldHVybjsKKwl9CisKKwlLQVNTRVJUKChpZm0tPmZsYWdzICYgSVBGV19JRkxB R19GQUtFKSA9PSAwLAorCSAgICAoIkZha2UgaW50ZXJmYWNlIGZvdW5kIGZvciAlcyIsIGlm bS0+bmFtZSkpOworCisJLyogQ2hlY2sgaWYgd2UgbmVlZCB0byBzYXZlIGdpdmVuIGludGVy ZmFjZS4gKi8KKwlpZiAoaWZtLT5yZWZjb3VudCA9PSAwKSB7CisJCUNUUjEoS1RSX05FVCwg IkRlbGV0aW5nIGludGVyZmFjZSAlcCIsIGlmbSk7CisJCS8qIERlbGV0ZSBmcm9tIG5hbWUg aGFzaCAqLworCQlpID0gSVBGV19JRkhBU0hfTkFNRShpZm0tPm5hbWUsIGlmZC0+bWFza3Nf aHNpemUpOworCQlpZmggPSAmaWZkLT5tYXNrc1tpXTsKKwkJVEFJTFFfUkVNT1ZFKGlmaCwg aWZtLCBuYW1lX25leHQpOworCisJCS8qIERlbGV0ZSBmcm9tIHJlYWwgaWZhY2UgaGFzaCAq LworCQlpID0gSVBGV19JRkhBU0hfSURYKGlmbS0+aWR4LCBpZmQtPnJlYWxfaHNpemUpOwor CQlpZmggPSAmaWZkLT5yZWFsX2lmYWNlc1tpXTsKKwkJVEFJTFFfUkVNT1ZFKGlmaCwgaWZt LCBpZHhfbmV4dCk7CisKKwkJSVBGV19XVU5MT0NLKGNoYWluKTsKKwkJSVBGV19VSF9XVU5M T0NLKGNoYWluKTsKKworCQlmcmVlKGlmbSwgTV9JUEZXKTsKKwkJcmV0dXJuOworCX0KKwor CUNUUjEoS1RSX05FVCwgIkludGVyZmFjZSB1Yz0ldSIsIGlmbS0+cmVmY291bnQpOworCisJ LyogSW50ZXJmYWNlIGlzIHVzZWQuIE1vdmUgdG8gZmFrZSBoYXNoICovCisJaWZtLT5mbGFn cyB8PSBJUEZXX0lGTEFHX0ZBS0U7CisJLyogUmVsaW5rIHRvIGZha2UgaW5kZXggKi8KKwlp ID0gSVBGV19JRkhBU0hfSURYKGlmbS0+aWR4LCBpZmQtPnJlYWxfaHNpemUpOworCWlmaCA9 ICZpZmQtPnJlYWxfaWZhY2VzW2ldOworCVRBSUxRX1JFTU9WRShpZmgsIGlmbSwgaWR4X25l eHQpOworCisJLyogQWxsb2MgZmFrZSBpbmRleCAqLworCWlmZC0+ZmFrZV9pZHgrKzsKKwlp ID0gSVBGV19JRkhBU0hfSURYKGlmZC0+ZmFrZV9pZHgsIGlmZC0+ZmFrZV9oc2l6ZSk7CisJ aWZoID0gJmlmZC0+ZmFrZV9pZmFjZXNbaV07CisJVEFJTFFfSU5TRVJUX1RBSUwoaWZoLCBp Zm0sIGlkeF9uZXh0KTsKKworCUNUUjIoS1RSX05FVCwgIkludGVyZmFjZSAlcCBkZXBhcnR1 cmUsIGZha2UgaW5kZXggJXUiLAorCSAgICBpZm0sIGlmZC0+ZmFrZV9pZHgpOworCisJLyog Tm90aWZ5IGNvbnN1bWVycyAqLworCVRBSUxRX0ZPUkVBQ0goaW5zbl9wdHIsICZpZm0tPmlu c3RydWN0aW9ucywgbmV4dCkKKwkJaXBmd191cGRhdGVfcmV3cml0ZShjaGFpbiwgaW5zbl9w dHItPmluc24sIGlmbSwKKwkJICAgICh1aW50cHRyX3QpKGlmZC0+ZmFrZV9pZHggfCBJUEZX X0ZBS0VfSURYKSk7CisKKwlpZm0tPmlkeCA9IGlmZC0+ZmFrZV9pZHg7CisKKwlJUEZXX1dV TkxPQ0soY2hhaW4pOworCUlQRldfVUhfV1VOTE9DSyhjaGFpbik7Cit9CisKK3N0YXRpYyB2 b2lkCitpcGZ3X2lmbmV0X2luaXQoc3RydWN0IGlwX2Z3X2NoYWluICpjaGFpbiwgc3RydWN0 IGlmYWNlX21hc2sgKmlmbSkKK3sKKworCVRBSUxRX0lOSVQoJmlmbS0+aW5zdHJ1Y3Rpb25z KTsKK30KKworCitzdGF0aWMgdm9pZAoraXBmd19pZmhhc2hfaW5pdF9pbnQoc3RydWN0IGlm YWNlX21hc2tfaGVhZCAqKnBoYXNoLCBzaXplX3QgaHNpemUpCit7CisJc3RydWN0IGlmYWNl X21hc2tfaGVhZCAqaWZoOworCWludCBpOworCisJaWZoID0gbWFsbG9jKHNpemVvZihzdHJ1 Y3QgaWZhY2VfbWFza19oZWFkKSAqIGhzaXplLCBNX0lQRlcsCisJICAgIE1fV0FJVE9LIHwg TV9aRVJPKTsKKworCSpwaGFzaCA9IGlmaDsKKworCWZvciAoaSA9IDA7IGkgPCBoc2l6ZTsg aSsrLCBpZmgrKykKKwkJVEFJTFFfSU5JVChpZmgpOworfQorCit2b2lkCitpcGZ3X2lmaGFz aF9pbml0KHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4pCit7CisJc3RydWN0IGlwX2Z3X2lm X2RhdGEgKmlmZDsKKwlzdHJ1Y3QgaWZhY2VfbWFza19oZWFkICppZmg7CisJc3RydWN0IGlm YWNlX21hc2sgKmlmbTsKKwlzdHJ1Y3QgaWZuZXQgKmlmcDsKKwlpbnQgaTsKKworCWlmZCA9 IG1hbGxvYyhzaXplb2Yoc3RydWN0IGlwX2Z3X2lmX2RhdGEpLCBNX0lQRlcsIE1fV0FJVE9L IHwgTV9aRVJPKTsKKwljaGFpbi0+aWZfZGF0YSA9IGlmZDsKKworCWlmZC0+bWFza3NfaHNp emUgPSBpZmQtPnJlYWxfaHNpemUgPSBpZmQtPmZha2VfaHNpemUgPSAzMjsKKworCWlwZndf aWZoYXNoX2luaXRfaW50KCZpZmQtPm1hc2tzLCBpZmQtPm1hc2tzX2hzaXplKTsKKwlpcGZ3 X2lmaGFzaF9pbml0X2ludCgmaWZkLT5yZWFsX2lmYWNlcywgaWZkLT5mYWtlX2hzaXplKTsK KwlpcGZ3X2lmaGFzaF9pbml0X2ludCgmaWZkLT5mYWtlX2lmYWNlcywgaWZkLT5yZWFsX2hz aXplKTsKKworCUlGTkVUX1JMT0NLKCk7CisJVEFJTFFfRk9SRUFDSChpZnAsICZWX2lmbmV0 LCBpZl9saW5rKSB7CisJCWlmbSA9IG1hbGxvYyhzaXplb2Yoc3RydWN0IGlmYWNlX21hc2sp LCBNX0lQRlcsIE1fV0FJVE9LIHwgTV9aRVJPKTsKKwkJc3RybGNweShpZm0tPm5hbWUsIGlm cC0+aWZfeG5hbWUsIElGTkFNU0laKTsKKwkJaWZtLT5pZnAgPSBpZnA7CisJCWlmbS0+aWR4 ID0gaWZwLT5pZl9pbmRleDsKKworCQlpcGZ3X2lmbmV0X2luaXQoY2hhaW4sIGlmbSk7CisK KwkJaSA9IElQRldfSUZIQVNIX0lEWChpZm0tPmlkeCwgaWZkLT5yZWFsX2hzaXplKTsKKwkJ aWZoID0gJmlmZC0+cmVhbF9pZmFjZXNbaV07CisJCVRBSUxRX0lOU0VSVF9UQUlMKGlmaCwg aWZtLCBpZHhfbmV4dCk7CisKKwkJaSA9IElQRldfSUZIQVNIX05BTUUoaWZtLT5uYW1lLCBp ZmQtPm1hc2tzX2hzaXplKTsKKwkJaWZoID0gJmlmZC0+bWFza3NbaV07CisJCVRBSUxRX0lO U0VSVF9UQUlMKGlmaCwgaWZtLCBuYW1lX25leHQpOworCisJCUNUUjIoS1RSX05FVCwgImlu aXQgaWZhY2UgJXAgaWR4ICV1IiwgaWZtLCBpZm0tPmlkeCk7CisKKwl9CisJSUZORVRfUlVO TE9DSygpOworCisJLyogWFhYOiB0aGVyZSBpcyBhIGdhcCBiZXR3ZWVuIFJVTkxPQ0sgYW5k IGludGVyZmFjZSByZWdpc3RyYXRpb24gKi8KKworCWlmZC0+YXJyaXZhbCA9IEVWRU5USEFO RExFUl9SRUdJU1RFUihpZm5ldF9hcnJpdmFsX2V2ZW50LAorCSAgICBpZm5ldF9hcnJpdmFs LCBjaGFpbiwgRVZFTlRIQU5ETEVSX1BSSV9BTlkpOworCisJaWZkLT5kZXBhcnR1cmUgPSBF VkVOVEhBTkRMRVJfUkVHSVNURVIoaWZuZXRfZGVwYXJ0dXJlX2V2ZW50LAorCSAgICBpZm5l dF9kZXBhcnR1cmUsIGNoYWluLCBFVkVOVEhBTkRMRVJfUFJJX0FOWSk7Cit9CisKK3ZvaWQK K2lwZndfaWZoYXNoX2RldGFjaChzdHJ1Y3QgaXBfZndfY2hhaW4gKmNoYWluKQoreworCXN0 cnVjdCBpcF9md19pZl9kYXRhICppZmQ7CisJCisJaWZkID0gY2hhaW4tPmlmX2RhdGE7CisK KwlFVkVOVEhBTkRMRVJfREVSRUdJU1RFUihpZm5ldF9hcnJpdmFsX2V2ZW50LCBpZmQtPmFy cml2YWwpOworCUVWRU5USEFORExFUl9ERVJFR0lTVEVSKGlmbmV0X2RlcGFydHVyZV9ldmVu dCwgaWZkLT5kZXBhcnR1cmUpOworCisJaWZkLT5hcnJpdmFsID0gTlVMTDsKKwlpZmQtPmRl cGFydHVyZSA9IE5VTEw7Cit9CisKKwordm9pZAoraXBmd19pZmhhc2hfZnJlZShzdHJ1Y3Qg aXBfZndfY2hhaW4gKmNoYWluKQoreworCXN0cnVjdCBpcF9md19pZl9kYXRhICppZmQ7CisJ c3RydWN0IGlmYWNlX21hc2tfaGVhZCAqaWZoOworCXN0cnVjdCBpZmFjZV9tYXNrICppZm0s ICppZm1fbmV4dDsKKwlpbnQgaTsKKwkKKwlpZmQgPSBjaGFpbi0+aWZfZGF0YTsKKwljaGFp bi0+aWZfZGF0YSA9IE5VTEw7CisKKwlpZmggPSBpZmQtPm1hc2tzOworCisJZm9yIChpID0g MDsgaSA8IGlmZC0+bWFza3NfaHNpemU7IGkrKywgaWZoKyspIHsKKwkJVEFJTFFfRk9SRUFD SF9TQUZFKGlmbSwgaWZoLCBuYW1lX25leHQsIGlmbV9uZXh0KSB7CisJCQkvKgorCQkJICog QXNzdW1lIGV2ZXJ5IGNvbnN1bWVyIHRvIGZyZWUgaXRzCisJCQkgKiBpZmFjZS1zcGVjaWZp YyBkYXRhIGJlZm9yZWhhbmQuCisJCQkgKi8KKwkJCWZyZWUoaWZtLCBNX0lQRlcpOworCQl9 CisJfQorCisJZnJlZShpZmQtPm1hc2tzLCBNX0lQRlcpOworCWZyZWUoaWZkLT5yZWFsX2lm YWNlcywgTV9JUEZXKTsKKwlmcmVlKGlmZC0+ZmFrZV9pZmFjZXMsIE1fSVBGVyk7CisKKwlm cmVlKGlmZCwgTV9JUEZXKTsKK30KKwotLS0gL2Rldi9udWxsCTIwMTMtMDQtMjQgMTc6MjI6 MDAuMDAwMDAwMDAwICswNDAwCisrKyBzeXMvbmV0cGZpbC9pcGZ3L2lwX2Z3X2lmYWNlLmgJ MjAxMy0wNC0yMiAxOTowOTo1Ni42MjQ5OTY0OTEgKzA0MDAKQEAgLTAsMCArMSw1NSBAQAor LyotCisgKiBDb3B5cmlnaHQgKGMpIDIwMTMgWWFuZGV4IExMQy4KKyAqCisgKiBSZWRpc3Ry aWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdp dGhvdXQKKyAqIG1vZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRo ZSBmb2xsb3dpbmcgY29uZGl0aW9ucworICogYXJlIG1ldDoKKyAqIDEuIFJlZGlzdHJpYnV0 aW9ucyBvZiBzb3VyY2UgY29kZSBtdXN0IHJldGFpbiB0aGUgYWJvdmUgY29weXJpZ2h0Cisg KiAgICBub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5n IGRpc2NsYWltZXIuCisgKiAyLiBSZWRpc3RyaWJ1dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVz dCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodAorICogICAgbm90aWNlLCB0aGlzIGxp c3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyIGluIHRoZQor ICogICAgZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdp dGggdGhlIGRpc3RyaWJ1dGlvbi4KKyAqCisgKiBUSElTIFNPRlRXQVJFIElTIFBST1ZJREVE IEJZIFRIRSBBVVRIT1IgQU5EIENPTlRSSUJVVE9SUyBgYEFTIElTJycgQU5ECisgKiBBTlkg RVhQUkVTUyBPUiBJTVBMSUVEIFdBUlJBTlRJRVMsIElOQ0xVRElORywgQlVUIE5PVCBMSU1J VEVEIFRPLCBUSEUKKyAqIElNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkg QU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFCisgKiBBUkUgRElTQ0xBSU1F RC4gIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1IgT1IgQ09OVFJJQlVUT1JTIEJFIExJ QUJMRQorICogRk9SIEFOWSBESVJFQ1QsIElORElSRUNULCBJTkNJREVOVEFMLCBTUEVDSUFM LCBFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwKKyAqIERBTUFHRVMgKElOQ0xVRElORywg QlVUIE5PVCBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdPT0RTCisg KiBPUiBTRVJWSUNFUzsgTE9TUyBPRiBVU0UsIERBVEEsIE9SIFBST0ZJVFM7IE9SIEJVU0lO RVNTIElOVEVSUlVQVElPTikKKyAqIEhPV0VWRVIgQ0FVU0VEIEFORCBPTiBBTlkgVEhFT1JZ IE9GIExJQUJJTElUWSwgV0hFVEhFUiBJTiBDT05UUkFDVCwgU1RSSUNUCisgKiBMSUFCSUxJ VFksIE9SIFRPUlQgKElOQ0xVRElORyBORUdMSUdFTkNFIE9SIE9USEVSV0lTRSkgQVJJU0lO RyBJTiBBTlkgV0FZCisgKiBPVVQgT0YgVEhFIFVTRSBPRiBUSElTIFNPRlRXQVJFLCBFVkVO IElGIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GCisgKiBTVUNIIERBTUFHRS4KKyAq CisgKiAkRnJlZUJTRCQKKyAqLworCisjaWZuZGVmIF9JUF9GV19JRkFDRV9IXworI2RlZmlu ZSBfSVBfRldfSUZBQ0VfSF8KKworc3RydWN0IGlwZndfaW5zbl9wdHIgeworCVRBSUxRX0VO VFJZKGlwZndfaW5zbl9wdHIpCW5leHQ7CisJaXBmd19pbnNuCSppbnNuOworfTsgCisKK3N0 cnVjdCBpZmFjZV9tYXNrIHsKKwlzdHJ1Y3QgaWZuZXQJKmlmcDsKKwl1aW50MzJfdAlpZHg7 CS8qIFNhdmVkIGludGVyZmFjZSBpbmRleCAqLworCXVpbnQzMl90CWZsYWdzOwkvKiBQYWQg Ki8KKwl1aW50MzJfdAlyZWZjb3VudDsJLyogVXNhZ2UgY291bnQgKi8KKwljaGFyCQluYW1l W0lGTkFNU0laXTsJLyogSW50ZXJmYWNlL21hc2sgKi8KKwlUQUlMUV9FTlRSWShpZmFjZV9t YXNrKQlpZHhfbmV4dDsKKwlUQUlMUV9FTlRSWShpZmFjZV9tYXNrKQluYW1lX25leHQ7CisJ VEFJTFFfSEVBRChydWxlX2xpc3QsIGlwZndfaW5zbl9wdHIpCWluc3RydWN0aW9uczsJLyog aW5zdHJ1Y3Rpb25zIHVzaW5nIGdpdmVuIG1hc2sgKi8KK307CisjZGVmaW5lCUlQRldfSUZM QUdfRkFLRQkweDAxCisKKyNkZWZpbmUJSVBGV19GQUtFX0lEWAkoMSA8PCAzMSkKKworc3Ry dWN0IGlmYWNlX21hc2sgKmlwZndfc2VhcmNoX2lmbmFtZShzdHJ1Y3QgaXBfZndfY2hhaW4g KmNoYWluLCBjaGFyICpuYW1lKTsKK3N0cnVjdCBpZmFjZV9tYXNrICppcGZ3X3NlYXJjaF9p ZmluZGV4KHN0cnVjdCBpcF9md19jaGFpbiAqY2hhaW4sIHVpbnQzMl90IGlkeCk7Cit2b2lk IGlwZndfYWRkX2lmbmFtZShzdHJ1Y3QgaXBfZndfY2hhaW4gKmNoYWluLCBzdHJ1Y3QgaWZh Y2VfbWFzayAqaWZtKTsKKworI2VuZGlmCisKCg== --------------060008050505010104000604-- From owner-freebsd-ipfw@FreeBSD.ORG Wed Apr 24 16:22:05 2013 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 61135B4B; Wed, 24 Apr 2013 16:22:05 +0000 (UTC) (envelope-from luigi@onelab2.iet.unipi.it) Received: from onelab2.iet.unipi.it (onelab2.iet.unipi.it [131.114.59.238]) by mx1.freebsd.org (Postfix) with ESMTP id 0AB1E1E93; Wed, 24 Apr 2013 16:22:02 +0000 (UTC) Received: by onelab2.iet.unipi.it (Postfix, from userid 275) id D6C0B7300A; Wed, 24 Apr 2013 18:23:49 +0200 (CEST) Date: Wed, 24 Apr 2013 18:23:49 +0200 From: Luigi Rizzo To: "Alexander V. Chernikov" Subject: Re: [patch] ipfw interface tracking and opcode rewriting Message-ID: <20130424162349.GA8439@onelab2.iet.unipi.it> References: <517801D3.5040502@FreeBSD.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <517801D3.5040502@FreeBSD.org> User-Agent: Mutt/1.5.20 (2009-06-14) Cc: freebsd-ipfw@freebsd.org, luigi@freebsd.org X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Apr 2013 16:22:05 -0000 On Wed, Apr 24, 2013 at 08:01:23PM +0400, Alexander V. Chernikov wrote: > Hello list! > > Currently ipfw uses strncmp() function to do interface matching which is > quite slow. > Additionally, ipfw_insn_if opcode is quite big and given that struct > ip_fw occupy 48 bytes > (without first instruction) which gives us good chance that part of > interface name will be on the second cache line on amd64. > > Pure synthetic testing (ipfw with 1 and 2 'ipfw count ip from any to any > recv ifaceX') shows about 3.8% performance loss (190kpps out of 5.1 > mpps) for each rule, > while indexed version shows about 2.0% and 1.2% for first and second rule. > > Additionally, our production (8.3-based firewalls with old strncmp) > shows about 40% kernel time spent in strncmp on 1-2mpps (each packet > traverses 5-6 such rules). > > Here is the patch which does the following: > 1) adds interface tracking for ipfw. Every interface is tracked > regardless of its usage in the ruleset. This simplifies locking and > makes easier to port such functionality to userland. > 2) adds general opcode rewriting system permitting kernel to > algorithmically (stateless) or statefully (involving extrernal data) > rewrite user-supplied opcodes with possible size change. > This can be used to deprecate opcodes which are now superseded by newer > ones while keeping ABI (and we currently have such opcodes). > 3) Store (and track) inderface index for non-wildcard interface inside > opcode. > > If there are no objections I would like to commit (possibly updated > vesrion) in the middle of the next week. hmmm.... this is quite a large change, and from the description it is a bit unclear to me how the "opcode rewriting" thing relates to the use of strings vs index for name matching. Additionally, i wonder if there isn't a better way to replace strncmp with some two 64-bit comparisons (the name is 16 bytes) by making sure that the fields are zero-padded and suitably aligned. At this point, on the machines you care about (able to sustain 1+ Mpps) the two comparison should have the same cost as the index comparison, without the need to track update in the names. note, my comment is only about the strncmp() part, i guess the opcode rewriting is orthogonal and may have other applications, but i am not completely sure about it. cheers luigi understand if While in principle i do not think the strncmp is a major performance killer. even if it is, i believe it > > Index: sys/netinet/ip_fw.h > =================================================================== > --- sys/netinet/ip_fw.h (revision 248704) > +++ sys/netinet/ip_fw.h (working copy) > @@ -341,6 +341,7 @@ typedef struct _ipfw_insn_if { > union { > struct in_addr ip; > int glob; > + unsigned int if_idx; /* Interface index (kernel) */ > } p; > char name[IFNAMSIZ]; > } ipfw_insn_if; > @@ -495,6 +496,8 @@ typedef struct _ipfw_insn_icmp6 { > * queue(3) macros for portability and readability. > */ > > +#define IP_FW_RULE_REWRITTEN 0x01 /* Rule is modified by rewriter */ > + > struct ip_fw { > struct ip_fw *x_next; /* linked list of rules */ > struct ip_fw *next_rule; /* ptr to next [skipto] rule */ > @@ -505,7 +508,7 @@ struct ip_fw { > uint16_t rulenum; /* rule number */ > uint8_t set; /* rule set (0..31) */ > #define RESVD_SET 31 /* set for default and persistent rules */ > - uint8_t _pad; /* padding */ > + uint8_t flags; /* padding */ > uint32_t id; /* rule id */ > > /* These fields are present in all rules. */ > Index: sys/modules/ipfw/Makefile > =================================================================== > --- sys/modules/ipfw/Makefile (revision 248704) > +++ sys/modules/ipfw/Makefile (working copy) > @@ -8,6 +8,7 @@ KMOD= ipfw > SRCS= ip_fw2.c ip_fw_pfil.c > SRCS+= ip_fw_dynamic.c ip_fw_log.c > SRCS+= ip_fw_sockopt.c ip_fw_table.c > +SRCS+= ip_fw_iface.c ip_fw_rewrite.c > SRCS+= opt_inet.h opt_inet6.h opt_ipdivert.h opt_ipfw.h opt_ipsec.h > > CFLAGS+= -DIPFIREWALL > Index: sys/netpfil/ipfw/ip_fw2.c > =================================================================== > --- sys/netpfil/ipfw/ip_fw2.c (revision 248704) > +++ sys/netpfil/ipfw/ip_fw2.c (working copy) > @@ -353,17 +353,17 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd, > if (ifp == NULL) /* no iface with this packet, match fails */ > return 0; > /* Check by name or by IP address */ > - if (cmd->name[0] != '\0') { /* match by name */ > - if (cmd->name[0] == '\1') /* use tablearg to match */ > + if (cmd->o.arg1 != 0) { /* match by name */ > + if (cmd->o.arg1 == 1) /* use tablearg to match */ > return ipfw_lookup_table_extended(chain, cmd->p.glob, > ifp->if_xname, tablearg, IPFW_TABLE_INTERFACE); > /* Check name */ > - if (cmd->p.glob) { > + if (cmd->p.if_idx) { > + if (ifp->if_index == cmd->p.if_idx) > + return (1); > + } else { > if (fnmatch(cmd->name, ifp->if_xname, 0) == 0) > return(1); > - } else { > - if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0) > - return(1); > } > } else { > #ifdef __FreeBSD__ /* and OSX too ? */ > @@ -2667,6 +2667,8 @@ vnet_ipfw_init(const void *unused) > > IPFW_LOCK_INIT(chain); > ipfw_dyn_init(chain); > + ipfw_ifhash_init(chain); > + ipfw_rewrite_init(chain); > > /* First set up some values that are compile time options */ > V_ipfw_vnet_ready = 1; /* Open for business */ > @@ -2708,6 +2710,7 @@ vnet_ipfw_uninit(const void *unused) > (void)ipfw_attach_hooks(0 /* detach */); > V_ip_fw_ctl_ptr = NULL; > IPFW_UH_WLOCK(chain); > + ipfw_ifhash_detach(chain); /* detach eventhandlers */ > IPFW_UH_WUNLOCK(chain); > IPFW_UH_WLOCK(chain); > > @@ -2722,9 +2725,14 @@ vnet_ipfw_uninit(const void *unused) > rule = chain->map[i]; > rule->x_next = reap; > reap = rule; > + /* Clear rewrites if any */ > + if (rule->flags & IP_FW_RULE_REWRITTEN) > + ipfw_relocate_rewrite(chain, rule->cmd, NULL); > } > if (chain->map) > free(chain->map, M_IPFW); > + ipfw_rewrite_free(chain); > + ipfw_ifhash_free(chain); > IPFW_WUNLOCK(chain); > IPFW_UH_WUNLOCK(chain); > if (reap != NULL) > Index: sys/netpfil/ipfw/ip_fw_private.h > =================================================================== > --- sys/netpfil/ipfw/ip_fw_private.h (revision 248704) > +++ sys/netpfil/ipfw/ip_fw_private.h (working copy) > @@ -212,6 +212,13 @@ VNET_DECLARE(int, autoinc_step); > VNET_DECLARE(unsigned int, fw_tables_max); > #define V_fw_tables_max VNET(fw_tables_max) > > + > +#define CMDSIZE(rule) (((struct ip_fw *)(rule))->cmd_len * sizeof(uint32_t)) > + > + > +struct ip_fw_if_data; > +struct ip_fw_rw_data; > + > struct ip_fw_chain { > struct ip_fw *rules; /* list of rules */ > struct ip_fw *reap; /* list of rules to reap */ > @@ -232,8 +239,42 @@ struct ip_fw_chain { > #endif > uint32_t id; /* ruleset id */ > uint32_t gencnt; /* generation count */ > + struct ip_fw_if_data *if_data; /* Interface tracking data */ > + struct ip_fw_rw_data *rewrite_data; /* Rule rewrite data */ > }; > > +/* ip_fw_rewrite.c */ > +struct ip_fw_rw_info { > + void *sptr; /* State created by ipfw_prepare_rewrite() */ > + int count; /* Number of opcodes requesting rewrite */ > + int states; /* Number of opcodes with stateful rewrite */ > + int lendiff; /* Difference with oridinal rule len (insns) */ > +}; > + > +void ipfw_rewrite_init(struct ip_fw_chain *chain); > +void ipfw_rewrite_free(struct ip_fw_chain *chain); > +int ipfw_rewrite_len(struct ip_fw_chain *chain); > +void *ipfw_prepare_rewrite(struct ip_fw_chain *chain, ipfw_insn *cmd, > + int cmd_len, struct ip_fw_rw_info *rwi); > +void ipfw_perform_rewrite(struct ip_fw_chain *chain, ipfw_insn *kcmd, > + void *state); > +void ipfw_relocate_rewrite(struct ip_fw_chain *chain, ipfw_insn *old, > + ipfw_insn *new); > +int ipfw_export_rewrite(struct ip_fw_chain *chain, ipfw_insn *kcmd, > + ipfw_insn *target); > + > +void ipfw_check_rewrite(struct ip_fw_chain *chain, ipfw_insn *insn, > + struct ip_fw_rw_info *rwi); > +void ipfw_update_rewrite(struct ip_fw_chain *chain, ipfw_insn *insn, > + void *state, uintptr_t val); > + > + > +/* ip_fw_iface.c */ > +void ipfw_ifhash_init(struct ip_fw_chain *chain); > +void ipfw_ifhash_free(struct ip_fw_chain *chain); > +void ipfw_ifhash_detach(struct ip_fw_chain *chain); > + > + > struct sockopt; /* used by tcp_var.h */ > > /* Macro for working with various counters */ > @@ -295,7 +336,8 @@ struct sockopt; /* used by tcp_var.h */ > > /* In ip_fw_sockopt.c */ > int ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id); > -int ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule); > +int ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule, > + struct ip_fw_rw_info *rwi); > int ipfw_ctl(struct sockopt *sopt); > int ipfw_chk(struct ip_fw_args *args); > void ipfw_reap_rules(struct ip_fw *head); > Index: sys/netpfil/ipfw/ip_fw_sockopt.c > =================================================================== > --- sys/netpfil/ipfw/ip_fw_sockopt.c (revision 248971) > +++ sys/netpfil/ipfw/ip_fw_sockopt.c (working copy) > @@ -73,6 +73,8 @@ MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct > * static variables followed by global ones (none in this file) > */ > > +static void ipfw_export_header(struct ip_fw *krule, struct ip_fw *dst); > + > /* > * Find the smallest rule >= key, id. > * We could use bsearch but it is so simple that we code it directly > @@ -153,7 +155,8 @@ swap_map(struct ip_fw_chain *chain, struct ip_fw * > * Must be called without IPFW_UH held > */ > int > -ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule) > +ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule, > + struct ip_fw_rw_info *rwi) > { > struct ip_fw *rule; > int i, l, insert_before; > @@ -163,7 +166,8 @@ int > return (EINVAL); > > l = RULESIZE(input_rule); > - rule = malloc(l, M_IPFW, M_WAITOK | M_ZERO); > + rule = malloc(l + rwi->lendiff * sizeof(uint32_t), M_IPFW, > + M_WAITOK | M_ZERO); > /* get_map returns with IPFW_UH_WLOCK if successful */ > map = get_map(chain, 1, 0 /* not locked */); > if (map == NULL) { > @@ -171,7 +175,15 @@ int > return ENOSPC; > } > > - bcopy(input_rule, rule, l); > + if (rwi->sptr == NULL) > + bcopy(input_rule, rule, l); > + else { > + /* Copy header and first instuction */ > + bcopy(input_rule, rule, sizeof(struct ip_fw)); > + rule->flags |= IP_FW_RULE_REWRITTEN; > + ipfw_perform_rewrite(chain, rule->cmd, rwi->sptr); > + } > + > /* clear fields not settable from userland */ > rule->x_next = NULL; > rule->next_rule = NULL; > @@ -366,6 +378,14 @@ del_entry(struct ip_fw_chain *chain, uint32_t arg) > rule = chain->map[i]; > if (keep_rule(rule, cmd, new_set, num)) > map[ofs++] = rule; > + else { > + /* Clear rewrites if any */ > + if (rule->flags & IP_FW_RULE_REWRITTEN) { > + printf("Moving rule %p to clear list\n", rule); > + ipfw_relocate_rewrite(chain, > + rule->cmd, NULL); > + } > + } > } > /* 3. copy the final part of the map */ > bcopy(chain->map + end, map + ofs, > @@ -384,6 +404,7 @@ del_entry(struct ip_fw_chain *chain, uint32_t arg) > ipfw_expire_dyn_rules(chain, rule, RESVD_SET); > rule->x_next = chain->reap; > chain->reap = rule; > + printf("Adding rule %p to reap list\n", rule); > } > break; > > @@ -517,7 +538,8 @@ zero_entry(struct ip_fw_chain *chain, u_int32_t ar > * Rules are simple, so this mostly need to check rule sizes. > */ > static int > -check_ipfw_struct(struct ip_fw *rule, int size) > +check_ipfw_struct(struct ip_fw_chain *chain, struct ip_fw *rule, int size, > + struct ip_fw_rw_info *rwi) > { > int l, cmdlen = 0; > int have_action=0; > @@ -696,6 +718,7 @@ static int > case O_VIA: > if (cmdlen != F_INSN_SIZE(ipfw_insn_if)) > goto bad_size; > + ipfw_check_rewrite(chain, cmd, rwi); > break; > > case O_ALTQ: > @@ -868,6 +891,13 @@ int convert_rule_to_8(struct ip_fw *rule); > #endif > > > +static void > +ipfw_export_header(struct ip_fw *krule, struct ip_fw *dst) > +{ > + > + memcpy(dst, krule, sizeof(struct ip_fw) - sizeof(ipfw_insn)); > +} > + > /* > * Copy the static and dynamic rules to the supplied buffer > * and return the amount of space actually used. > @@ -887,11 +917,28 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf > rule = chain->map[i]; > > if (is7) { > - /* Convert rule to FreeBSd 7.2 format */ > - l = RULESIZE7(rule); > + /* Convert rule to FreeBSD 7.2 format */ > + if (rule->flags & IP_FW_RULE_REWRITTEN) > + l = ipfw_export_rewrite(chain, rule->cmd, NULL); > + else > + l = CMDSIZE(rule); > + > + /* > + * Add header length. > + * v.8 rule header is 4 bytes bigger. > + */ > + l += sizeof(struct ip_fw7) - sizeof(ipfw_insn); > + > if (bp + l + sizeof(uint32_t) <= ep) { > int error; > bcopy(rule, bp, l + sizeof(uint32_t)); > + > + if (rule->flags & IP_FW_RULE_REWRITTEN) { > + ipfw_export_rewrite(chain, rule->cmd, dst->cmd); > + ipfw_export_header(rule, dst); > + } else > + bcopy(rule, bp, l + sizeof(uint32_t)); > + > error = convert_rule_to_7((struct ip_fw *) bp); > if (error) > return 0; /*XXX correct? */ > @@ -910,14 +957,23 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf > continue; /* go to next rule */ > } > > - /* normal mode, don't touch rules */ > - l = RULESIZE(rule); > + if (rule->flags & IP_FW_RULE_REWRITTEN) > + l = ipfw_export_rewrite(chain, rule->cmd, NULL); > + else > + l = CMDSIZE(rule); > + /* Add header length */ > + l += sizeof(struct ip_fw) - sizeof(ipfw_insn); > + > if (bp + l > ep) { /* should not happen */ > printf("overflow dumping static rules\n"); > break; > } > dst = (struct ip_fw *)bp; > - bcopy(rule, dst, l); > + if (rule->flags & IP_FW_RULE_REWRITTEN) { > + ipfw_export_rewrite(chain, rule->cmd, dst->cmd); > + ipfw_export_header(rule, dst); > + } else > + bcopy(rule, dst, l); > /* > * XXX HACK. Store the disable mask in the "next" > * pointer in a wild attempt to keep the ABI the same. > @@ -949,6 +1005,7 @@ ipfw_ctl(struct sockopt *sopt) > uint32_t opt; > char xbuf[128]; > ip_fw3_opheader *op3 = NULL; > + struct ip_fw_rw_info rwi; > > error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW); > if (error) > @@ -998,7 +1055,7 @@ ipfw_ctl(struct sockopt *sopt) > for (;;) { > int len = 0, want; > > - size = chain->static_len; > + size = chain->static_len + ipfw_rewrite_len(chain); > size += ipfw_dyn_len(); > if (size >= sopt->sopt_valsize) > break; > @@ -1027,6 +1084,8 @@ ipfw_ctl(struct sockopt *sopt) > error = sooptcopyin(sopt, rule, RULE_MAXSIZE, > sizeof(struct ip_fw7) ); > > + memset(&rwi, 0, sizeof(rwi)); > + > /* > * If the size of commands equals RULESIZE7 then we assume > * a FreeBSD7.2 binary is talking to us (set is7=1). > @@ -1042,15 +1101,21 @@ ipfw_ctl(struct sockopt *sopt) > if (error) > return error; > if (error == 0) > - error = check_ipfw_struct(rule, RULESIZE(rule)); > + error = check_ipfw_struct(chain, rule, RULESIZE(rule), > + &rwi); > } else { > is7 = 0; > if (error == 0) > - error = check_ipfw_struct(rule, sopt->sopt_valsize); > + error = check_ipfw_struct(chain, rule, > + sopt->sopt_valsize, &rwi); > } > if (error == 0) { > + /* Prepare rewrite, if needed */ > + if (rwi.count > 0) > + rwi.sptr = ipfw_prepare_rewrite(chain, > + rule->cmd, rule->cmd_len, &rwi); > /* locking is done within ipfw_add_rule() */ > - error = ipfw_add_rule(chain, rule); > + error = ipfw_add_rule(chain, rule, &rwi); > size = RULESIZE(rule); > if (!error && sopt->sopt_dir == SOPT_GET) { > if (is7) { > @@ -1350,7 +1415,7 @@ convert_rule_to_7(struct ip_fw *rule) > bcopy(rule, tmp, RULE_MAXSIZE); > > /* Copy fields */ > - rule7->_pad = tmp->_pad; > + rule7->_pad = 0; > rule7->set = tmp->set; > rule7->rulenum = tmp->rulenum; > rule7->cmd_len = tmp->cmd_len; > @@ -1423,7 +1488,7 @@ convert_rule_to_8(struct ip_fw *rule) > } > } > > - rule->_pad = tmp->_pad; > + rule->flags = 0; > rule->set = tmp->set; > rule->rulenum = tmp->rulenum; > rule->cmd_len = tmp->cmd_len; > --- /dev/null 2013-04-24 17:20:19.000000000 +0400 > +++ sys/netpfil/ipfw/ip_fw_rewrite.c 2013-04-24 17:19:15.278097243 +0400 > @@ -0,0 +1,835 @@ > +/*- > + * Copyright (c) 2013 Yandex LLC. > + * Author: Alexander V. Chernikov > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#include > +__FBSDID("$FreeBSD$"); > + > +/* > + * Rule opcode rewriting system for ipfw. > + * System permits automatic algoritmic (stateless) or statefull ( > + * requiring access/monidifcation to external data) of opcodes. > + * Modification is done by calling special per-opcode dependent > + * callbacks. Saving unmodified user-supplied rules, size recalculation, > + * rule export and relocation is handled by subsystem. > + * Writing opcode modificator requires adding it to rewrites[] array > + * and filling appropriate callbacks (at least 'convert' one. > + */ > + > +#include "opt_ipfw.h" > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include /* hooks */ > +#include > + > +#include > +#include > + > +#define NO_REWRITE 0 > +#define STATELESS_REWRITE 1 > +#define STATEFUL_REWRITE 2 > + > +struct ip_fw_rewrite { > + uint32_t opcode; > + > + /* > + * Checks if given opcode needs to be changed. Called (indirectly) > + * from check_ipfw_struct() without holding any locks. Fuction should > + * quickly check if given opcode needs to be rewritten and set @len to > + * size difference (in bytes) between new (altered) opcode size and > + * old one. Note that &len hould be aligned to u32. > + * > + * Params: > + * @chain - pointer to current ifpw chain > + * @insn - given ipfw_instn > + * @len - pointer to length diff (in insns) > + * > + * Returns: > + * NO_REWRITE - no need to convert > + * STATELESS_REWRITE - (algoritmic) conversion required. > + * STATEFUL_REWRITE - stateful conversion required. > + * > + * Callback is OPTIONAL, defaults to STATELESS_REWRITE if not set. > + */ > + int (*check)(struct ip_fw_chain *, ipfw_insn *, int *); > + > + /* > + * Prepares state for given opcode if needed. Called without > + * holding any locks permitting to allocate any amount of memory. > + * Note that result (and actual state usage) has to be consistent > + * with *check (and other) callbacks. > + * > + * Params: > + * @chain - pointer to current ifpw chain > + * @insn - given ipfw_instn > + * @pstate - pointer to pointer to state > + * > + * Returns: > + * NO_REWRITE - no need to convert > + * STATELESS_REWRITE - (algoritmic) conversion can be done. > + * STATEFUL_REWRITE - stateful conversion required, state is saved to > + * given pointer. > + * > + * Callback is OPTIONAL, defaults to STATELESS_REWRITE if not set. > + */ > + int (*prepare)(struct ip_fw_chain *, ipfw_insn *insn, void **); > + > + /* > + * Performs opcode conversion. Called with chain WLOCK held. > + * Note that opcode copy is handled automatically if > + * NO_REWRITE is returned. @len has to be filled otherwise. > + * > + * Params: > + * @chain - pointer to current ifpw chain > + * @_old - userland ipfw_instn > + * @_new - kernel ipfw_insn > + * @state - pointer to state saved > + * @len - pointer to opcode length (in instructions) > + * > + * Returns: > + * NO_REWRITE - no need to convert > + * STATELESS_REWRITE - (algoritmic) conversion is done. > + * STATEFUL_REWRITE - stateful conversion is done, state is consumed. > + * > + * Callback is MANDATORY. > + */ > + int (*convert)(struct ip_fw_chain *, ipfw_insn *, ipfw_insn *, void *, int *); > + > + /* > + * Performs state cleanup (rule deletion). Called with chain WLOCK held. > + * State hint can be provided. > + * > + * Params: > + * @chain - pointer to current ifpw chain > + * @insn - kernel ipfw_insn > + * @state - pointer to state hint > + * > + * Callback is OPTIONAL. > + */ > + void (*clear)(struct ip_fw_chain *, ipfw_insn *, void *); > + > + /* > + * Performs opcode-dependent update. > + * Flag/argument can be provided. > + * > + * Params: > + * @chain - pointer to current ifpw chain > + * @insn - kernel ipfw_insn > + * @state - pointer to opcode-dependent data > + * @val - opcode-dependet value > + * > + * Callback is OPTIONAL. > + */ > + void (*update)(struct ip_fw_chain *, ipfw_insn *, void *, uintptr_t); > + > + /* > + * Dispatches memory relocation of given opcode, Called with WLOCK held. > + * Actual copy is already done at the moment of call. > + * > + * Params: > + * @chain - pointer to current ifpw chain > + * @_old - kernel ipfw_insn > + * @_old - new kernel ipfw_insn > + * > + * Callback is OPTIONAL. > + */ > + void (*move)(struct ip_fw_chain *, ipfw_insn *, ipfw_insn *); > +}; > + > +/* Opcode callbacks */ > +static int > +convertable_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn); > + > +static void move_insn_if(struct ip_fw_chain *chain, ipfw_insn *_old, ipfw_insn *_new); > +static void update_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn, > + void *_iface_mask, uintptr_t new_id); > +static void clear_insn_if(struct ip_fw_chain *chain, ipfw_insn *_src, void *data); > +static int convert_insn_if(struct ip_fw_chain *chain, ipfw_insn *_old, ipfw_insn *_new, > + void *state, int *len); > +static int prepare_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn, void **pstate); > +static int check_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn, int *len); > + > + > +/* Note opcodes MUST be in asceding order */ > +struct ip_fw_rewrite rewrites[] = { > + { > + O_RECV, > + check_insn_if, > + prepare_insn_if, > + convert_insn_if, > + clear_insn_if, > + update_insn_if, > + move_insn_if, > + }, > + { > + O_XMIT, > + check_insn_if, > + prepare_insn_if, > + convert_insn_if, > + clear_insn_if, > + update_insn_if, > + move_insn_if, > + }, > + { > + O_VIA, > + check_insn_if, > + prepare_insn_if, > + convert_insn_if, > + clear_insn_if, > + update_insn_if, > + move_insn_if, > + }, > +}; > + > +struct rewrite_rule_ptr { > + TAILQ_ENTRY(rewrite_rule_ptr) next; > + int cmd_klen; /* Kernel opcodes len (insns) */ > + int cmd_len; /* Original opcodes len (insns) */ > + ipfw_insn *kcmd; /* Kernel rule version */ > + void **states; /* opcode states */ > + int states_count; /* number of states */ > + ipfw_insn cmd[1]; /* Original opcodes */ > +}; > +TAILQ_HEAD(rewrite_rule_head, rewrite_rule_ptr); > + > +struct ip_fw_rw_data { > + struct rewrite_rule_head *hash; > + size_t hsize; > + int lendiff; /* sizeof(kern) - sizeof(user) */ > +}; > + > +#define DEFAULT_HASH_SIZE 32 > +#define PTR_HASH_PRIME 31 > + > +static struct ip_fw_rewrite *ipfw_find_rewrite(uint32_t opcode); > + > +void > +ipfw_rewrite_init(struct ip_fw_chain *chain) > +{ > + struct ip_fw_rw_data *rwd; > + struct rewrite_rule_head *rh; > + int i; > + > + rwd = malloc(sizeof(struct ip_fw_rw_data), M_IPFW, M_WAITOK | M_ZERO); > + > + rwd->hsize = DEFAULT_HASH_SIZE; > + rwd->hash = malloc(sizeof(struct rewrite_rule_head) * rwd->hsize, > + M_IPFW, M_WAITOK | M_ZERO); > + > + for (i = 0, rh = rwd->hash; i < rwd->hsize; i++, rh++) > + TAILQ_INIT(rh); > + > + chain->rewrite_data = rwd; > +} > + > +void > +ipfw_rewrite_free(struct ip_fw_chain *chain) > +{ > + struct ip_fw_rw_data *rwd; > + > + rwd = chain->rewrite_data; > + chain->rewrite_data = NULL; > + > + /* Assume every rule to be already removed */ > + free(rwd->hash, M_IPFW); > + free(rwd, M_IPFW); > +} > + > +int > +ipfw_rewrite_len(struct ip_fw_chain *chain) > +{ > + struct ip_fw_rw_data *rwd; > + > + rwd = chain->rewrite_data; > + > + return (rwd->lendiff); > +} > + > +/* > + * Prepares given rule for modification: > + * allocates memory for rule and number of states reported > + * by 'check' callbacks. Calls 'prepare' callback for > + * every opcode in rule. > + * > + * Returns state to be passed to ipfw_store_rule. > + */ > +void * > +ipfw_prepare_rewrite(struct ip_fw_chain *chain, ipfw_insn *ucmd, > + int cmd_len, struct ip_fw_rw_info *rwi) > +{ > + int i, l, cmdlen, size, states_count; > + struct rewrite_rule_ptr *rptr; > + ipfw_insn *cmd; > + struct ip_fw_rewrite *rewrite; > + void **pstate; > + > + /* > + * Allocate memory for rule header, opcodes and state array. > + */ > + size = sizeof(struct rewrite_rule_ptr) + > + (cmd_len - 1) * sizeof(uint32_t); > + > + size = roundup(size, sizeof(void *)); > + > + rptr = malloc(size + rwi->states * sizeof(void *), M_IPFW, > + M_WAITOK | M_ZERO); > + > + /* Save original opcodes */ > + memcpy(rptr->cmd, ucmd, cmd_len * sizeof(uint32_t)); > + rptr->cmd_len = cmd_len; > + rptr->cmd_klen = rptr->cmd_len + rwi->lendiff; > + > + rptr->states = (void **)((char *)rptr + size); > + rptr->states_count = rwi->states; > + pstate = rptr->states; > + states_count = rptr->states_count; > + > + CTR4(KTR_NET, "Prepare rule rewrite: cmd %p len %d klen %d rptr %p", > + ucmd, rptr->cmd_len, rptr->cmd_klen, rptr); > + > + for (l = cmd_len, cmd = ucmd ; > + l > 0 ; l -= cmdlen, cmd += cmdlen) { > + cmdlen = F_LEN(cmd); > + > + if ((rewrite = ipfw_find_rewrite(cmd->opcode)) == NULL) > + continue; > + > + if (rewrite->prepare == NULL) > + continue; > + > + i = rewrite->prepare(chain, cmd, pstate); > + > + if (i == STATEFUL_REWRITE) { > + CTR3(KTR_NET, "New stateful rewrite %p val %p count %d", > + pstate, *pstate, states_count); > + pstate++; > + states_count--; > + > + KASSERT(states_count >= 0, > + ("prepare_rewrite state overflow")); > + } > + } > + > + return ((void *)rptr); > +} > + > +static int > +hash_ptr(struct ip_fw_rw_data *rwd, ipfw_insn *cmd) > +{ > + return (uintptr_t)cmd % PTR_HASH_PRIME; > +} > + > +/* > + * Fills in kernel rule with modified opcodes. Updates old rule state > + * with new kernel pointer. Actual rewriting and header copy is done > + * in ipfw_run_rewrite(). > + */ > +void > +ipfw_perform_rewrite(struct ip_fw_chain *chain, ipfw_insn *kcmd, void *state) > +{ > + struct rewrite_rule_ptr *rptr; > + struct rewrite_rule_head *rh; > + struct ip_fw_rw_data *rwd; > + struct ip_fw_rewrite *rewrite; > + ipfw_insn *ucmd; > + void **pstate; > + int i, l, ucmdlen, kcmdlen, states_count; > + > + rwd = chain->rewrite_data; > + > + rptr = (struct rewrite_rule_ptr *)state; > + rptr->kcmd = kcmd; > + pstate = rptr->states; > + states_count = rptr->states_count; > + > + CTR3(KTR_NET, "Linking kcmd %p to orig %p idx %d", > + kcmd, rptr, hash_ptr(rwd, kcmd)); > + > + rh = &rwd->hash[hash_ptr(rwd, kcmd)]; > + TAILQ_INSERT_TAIL(rh, rptr, next); > + > + ucmd = rptr->cmd; > + > + for (l = rptr->cmd_len; l > 0 ; > + l -= ucmdlen, ucmd += ucmdlen, kcmd += kcmdlen) { > + ucmdlen = F_LEN(ucmd); > + > + if ((rewrite = ipfw_find_rewrite(ucmd->opcode)) == NULL) { > + /* No conversion required, copy as is */ > + kcmdlen = ucmdlen; > + memcpy(kcmd, ucmd, ucmdlen * sizeof(ipfw_insn)); > + continue; > + } > + > + i = rewrite->convert(chain, ucmd, kcmd, *pstate, &kcmdlen); > + CTR2("RW for %d st %p returned %d", ucmd->cmd, *pstate, i); > + > + if (i == NO_REWRITE) { > + kcmdlen = ucmdlen; > + memcpy(kcmd, ucmd, ucmdlen * sizeof(ipfw_insn)); > + } else if (i == STATEFUL_REWRITE) { > + pstate++; > + states_count--; > + > + KASSERT(states_count >= 0, ("rewrite state overflow")); > + } > + } > + > + /* Save size difference */ > + rwd->lendiff += rptr->cmd_klen - rptr->cmd_len; > + CTR2(KTR_NET, "old len: %d, new: %d", rptr->cmd_len, rptr->cmd_klen); > +} > + > +/* > + * Handle rule moving to new place (or deletion). > + * Updates kernel rule pointer and run opcode callbacks via > + * ipfw_move_rewrite() or clears state via ipfw_clear_rewrite() > + * int latter case. > + */ > +void > +ipfw_relocate_rewrite(struct ip_fw_chain *chain, ipfw_insn *old, ipfw_insn *new) > +{ > + struct rewrite_rule_ptr *rptr; > + struct rewrite_rule_head *rh; > + struct ip_fw_rw_data *rwd; > + struct ip_fw_rewrite *rewrite; > + int l, cmdlen; > + > + rwd = chain->rewrite_data; > + > + rh = &rwd->hash[hash_ptr(rwd, old)]; > + > + TAILQ_FOREACH(rptr, rh, next) { > + if (rptr->kcmd == old) > + break; > + } > + > + CTR3(KTR_NET, "Moving %p idx %p to %p", rptr, hash_ptr(rwd, old), new); > + > + KASSERT(rptr != NULL, ("ipfw_relocate_rewrite: old rule not found")); > + > + TAILQ_REMOVE(rh, rptr, next); > + > + if (new == NULL) { > + /* Clear states (if any) and delete original rule */ > + for (l = rptr->cmd_klen; l > 0; l -= cmdlen, old += cmdlen) { > + cmdlen = F_LEN(old); > + > + if ((rewrite = ipfw_find_rewrite(old->opcode)) == NULL) > + continue; > + > + if (rewrite->clear == NULL) > + continue; > + > + CTR1(KTR_NET, "clear-state for opcode %u", old->opcode); > + rewrite->clear(chain, old, NULL); > + } > + > + /* Update size difference */ > + rwd->lendiff -= rptr->cmd_klen - rptr->cmd_len; > + free(rptr, M_IPFW); > + } else { > + /* Put to new slot */ > + rptr->kcmd = new; > + rh = &rwd->hash[hash_ptr(rwd, new)]; > + TAILQ_INSERT_TAIL(rh, rptr, next); > + > + /* Update instructions pointers */ > + for (l = rptr->cmd_klen; l > 0 ; > + l -= cmdlen, old += cmdlen, new += cmdlen) { > + cmdlen = F_LEN(old); > + > + if ((rewrite = ipfw_find_rewrite(old->opcode)) == NULL) > + continue; > + > + if (rewrite->move == NULL) > + continue; > + > + rewrite->move(chain, old, new); > + } > + } > +} > + > +/* > + * Exports modified rule to userland. Returns userland rule length > + * (used in initial size-checking calculations). Copies userland rule version > + * with updated counters to supplied buffer. > + */ > +int > +ipfw_export_rewrite(struct ip_fw_chain *chain, ipfw_insn *kcmd, ipfw_insn *target) > +{ > + struct rewrite_rule_ptr *rptr; > + struct rewrite_rule_head *rh; > + struct ip_fw_rw_data *rwd; > + ipfw_insn *ucmd; > + > + rwd = chain->rewrite_data; > + > + KASSERT(rw != NULL, ("ipfw_export_rewrite: rewrite not initialized")); > + > + rh = &rwd->hash[hash_ptr(rwd, kcmd)]; > + > + TAILQ_FOREACH(rptr, rh, next) { > + if (rptr->kcmd == kcmd) > + break; > + } > + > + KASSERT(rptr != NULL, ("ipfw_export_rewrite: kcmd not found")); > + ucmd = rptr->cmd; > + > + if (target != NULL) > + memcpy(target, rptr->cmd, rptr->cmd_len * sizeof(uint32_t)); > + > + return (rptr->cmd_len * sizeof(uint32_t)); > +} > + > +/* > + * bsearch() helper function. > + */ > +static int > +rewrite_comp(const void *_key, const void *_member) > +{ > + uint32_t opcode; > + struct ip_fw_rewrite *rewrite; > + > + opcode = *((uint32_t *)_key); > + rewrite = (struct ip_fw_rewrite *)_member; > + > + if (opcode < rewrite->opcode) > + return (-1); > + else if (opcode == rewrite->opcode) > + return (0); > + else > + return (1); > +} > + > + > +static struct ip_fw_rewrite * > +ipfw_find_rewrite(uint32_t opcode) > +{ > + size_t count; > + struct ip_fw_rewrite *rewrite; > + > + count = sizeof(rewrites) / sizeof(struct ip_fw_rewrite); > + > + rewrite = (struct ip_fw_rewrite *)bsearch(&opcode, rewrites, > + count, sizeof(struct ip_fw_rewrite), rewrite_comp); > + > + return (rewrite); > +} > + > + > +/* > + * Checks if given opcode needs to be changed. > + * Updates @rwi appropriate fields if instruction needs to be > + * stateless/stafully rewritten possibly with changed size. > + */ > +void > +ipfw_check_rewrite(struct ip_fw_chain *chain, ipfw_insn *insn, > + struct ip_fw_rw_info *rwi) > +{ > + struct ip_fw_rewrite *rewrite; > + int i = 0, len = 0; > + > + if ((rewrite = ipfw_find_rewrite(insn->opcode)) == NULL) > + i = NO_REWRITE; > + else if (rewrite->check == NULL) > + i = STATELESS_REWRITE; > + else > + i = rewrite->check(chain, insn, &len); > + > + if (len != 0) > + rwi->lendiff += len; > + > + if (i == STATELESS_REWRITE) > + rwi->count++; > + > + if (i == STATEFUL_REWRITE) { > + rwi->count++; > + rwi->states++; > + } > + > + if (i != NO_REWRITE) > + CTR4(KTR_NET, "opcode %d: count=%d states=%d len=%d", > + insn->opcode, rwi->count, rwi->states, rwi->lendiff); > +} > + > +/* > + * Call opcode-dependent 'update' callback. > + */ > +void > +ipfw_update_rewrite(struct ip_fw_chain *chain, ipfw_insn *insn, > + void *state, uintptr_t val) > +{ > + struct ip_fw_rewrite *rewrite; > + > + if ((rewrite = ipfw_find_rewrite(insn->opcode)) == NULL) > + return; > + > + if (rewrite->update == NULL) > + return; > + > + rewrite->update(chain, insn, state, val); > +} > + > +/******************************************************************* > + * * > + * O_RECV | O_VIA | O_XMIT rewrite handling. * > + * * > + *******************************************************************/ > +/* > + * Converts insns_if to more compact form. Currently instruction > + * is used to specify > + * 1) interface name ( ->name[0] != ('\0' | '\1') AND p.glob == 0) > + * 2) interface pattern ( ->name[0] != ('\0' | '\1') AND p.glob != 0) > + * 3) eXtended table number ( ->name[0] == '\1') > + * 4) interface address ( ->name[0] == '\0') > + * > + * We want to save iface index in case 1 (and to eliminate interface name at all). > + * Given that, we do the following: > + * > + * p.glob is now p.if_idx (u_int) (glob if zero, iface index otherwise) > + * o.arg1 works like ->name[0], so: > + * > + * 1) interface name (o.arg1 == 2, p.if_idx contains index) > + * 2) interface pattern (o.arg1 == 2, p.if_idx == 0) > + * 3) eXtended table number (o.arg1 == 1) > + * 4) interface address (o.arg1 == 0) > + */ > + > +static int > +convertable_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn) > +{ > + ipfw_insn_if *cmd = (ipfw_insn_if *)insn; > + > + /* Either IPv4 address or extended table (3) and (4) */ > + if (cmd->name[0] == '\0' || cmd->name[0] == '\1') > + return (0); > + > + return (1); > +} > + > +static int > +check_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn, int *len_diff) > +{ > + ipfw_insn_if *cmd = (ipfw_insn_if *)insn; > + > + *len_diff = 0; > + > + if (convertable_insn_if(chain, insn) == 0) > + return (STATELESS_REWRITE); > + > + /* Either interface name (1) or glob pattern (2). */ > + > + if (cmd->p.glob != 0) > + return (STATELESS_REWRITE); > + else > + return (STATEFUL_REWRITE); > +} > + > +static int > +prepare_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn, void **pstate) > +{ > + struct iface_mask *ifm; > + struct ipfw_insn_ptr *insn_ptr; > + ipfw_insn_if *cmd = (ipfw_insn_if *)insn; > + > + if (convertable_insn_if(chain, insn) == 0) > + return (STATELESS_REWRITE); > + > + if (cmd->p.glob != 0) { > + /* Glob pattern (2), no state needed, */ > + return (STATELESS_REWRITE); > + } > + > + /* Allocate data used by convert callback */ > + insn_ptr = malloc(sizeof(struct ipfw_insn_ptr), M_IPFW, > + M_WAITOK | M_ZERO); > + ifm = malloc(sizeof(struct iface_mask), M_IPFW, M_WAITOK | M_ZERO); > + > + TAILQ_INIT(&ifm->instructions); > + TAILQ_INSERT_TAIL(&ifm->instructions, insn_ptr, next); > + > + CTR3(KTR_NET, "pstate %p, val %p insns %p", pstate, ifm, insn); > + > + *pstate = ifm; > + return (STATEFUL_REWRITE); > +} > + > +static int > +convert_insn_if(struct ip_fw_chain *chain, ipfw_insn *_old, ipfw_insn *_new, > + void *state, int *len) > +{ > + struct iface_mask *ifm, *ifm2; > + struct ipfw_insn_ptr *insn_ptr; > + ipfw_insn_if *cmd_old = (ipfw_insn_if *)_old; > + ipfw_insn_if *cmd_new = (ipfw_insn_if *)_new; > + > + /* Set length anyway */ > + *len = F_INSN_SIZE(ipfw_insn_if); > + memcpy(cmd_new, cmd_old, sizeof(ipfw_insn_if)); > + > + if (convertable_insn_if(chain, _old) == 0) { > + /* > + * case (3, eX table): o.arg1 = 1 > + * case (4, ifaddr): o.arg1 = 0 > + */ > + > + cmd_new->o.arg1 = (cmd_old->name[0] == '\1') ? 1 : 0; > + > + return (STATELESS_REWRITE); > + } > + > + /* > + * Prepare instruction for altering. > + * case (1, ifname): o.arg1 = 2; p_if_idx == interface index > + * case (2, glob): o.arg1 = 2' p.if_idx = 0 > + */ > + memcpy(cmd_new, cmd_old, sizeof(ipfw_insn_if)); > + cmd_new->o.arg1 = 2; > + > + if (cmd_old->p.glob) { > + /* Interface mask (2). Copy as is and set index */ > + cmd_new->p.if_idx = 0; > + return (STATELESS_REWRITE); > + } > + > + /* Interface name. */ > + ifm = (struct iface_mask *)state; > + insn_ptr = TAILQ_FIRST(&ifm->instructions); > + > + insn_ptr->insn = _new; > + > + if ((ifm2 = ipfw_search_ifname(chain, cmd_old->name)) != NULL) { > + /* Interface found, link entry here */ > + TAILQ_INSERT_TAIL(&ifm2->instructions, insn_ptr, next); > + ifm2->refcount++; > + cmd_new->p.if_idx = ifm2->idx; > + if (ifm2->flags & IPFW_IFLAG_FAKE) > + cmd_new->p.if_idx |= IPFW_FAKE_IDX; > + > + free(ifm, M_IPFW); > + return (STATEFUL_REWRITE); > + } > + > + /* Interface not found, add and mark as unexistent */ > + strlcpy(ifm->name, cmd_old->name, IFNAMSIZ); > + ifm->flags |= IPFW_IFLAG_FAKE; > + ifm->refcount++; > + ipfw_add_ifname(chain, ifm); > + cmd_new->p.if_idx = ifm->idx | IPFW_FAKE_IDX; > + /* Add instruction back (add_ifname reinits list) */ > + TAILQ_INSERT_TAIL(&ifm->instructions, insn_ptr, next); > + > + return (STATEFUL_REWRITE); > +} > + > +static void > +clear_insn_if(struct ip_fw_chain *chain, ipfw_insn *_src, void *data) > +{ > + struct iface_mask *ifm; > + ipfw_insn_if *cmd; > + struct ipfw_insn_ptr *insn_ptr = (struct ipfw_insn_ptr *)data; > + > + cmd = (ipfw_insn_if *)_src; > + > + /* State is used for interface names, skip other cases */ > + if (cmd->o.arg1 != 2) > + return; > + > + ifm = ipfw_search_ifindex(chain, cmd->p.if_idx); > + KASSERT(ifm != NULL, ("no ifp found for index %u", cmd->p.if_idx)); > + > + if (insn_ptr == NULL) { > + TAILQ_FOREACH(insn_ptr, &ifm->instructions, next) { > + if (insn_ptr->insn == _src) > + break; > + } > + > + KASSERT(insn_ptr != NULL, ("no insns found")); > + } > + > + /* Remove instruction from interface */ > + TAILQ_REMOVE(&ifm->instructions, insn_ptr, next); > + ifm->refcount--; > + > + free(insn_ptr, M_IPFW); > +} > + > +static void > +update_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn, void *_iface_mask, > + uintptr_t new_id) > +{ > + struct ip_fw_if_data *ifd; > + ipfw_insn_if *cmd; > + > + IPFW_WLOCK_ASSERT(chain); > + > + ifd = chain->if_data; > + cmd = (ipfw_insn_if *)insn; > + > + CTR2(KTR_NET, "updating insn: ifi %u -> %u", > + cmd->p.if_idx, (uint32_t)new_id); > + > + cmd->p.if_idx = (uint32_t)new_id; > +} > + > +static void > +move_insn_if(struct ip_fw_chain *chain, ipfw_insn *_old, ipfw_insn *_new) > +{ > + struct iface_mask *ifm; > + ipfw_insn_if *cmd; > + struct ipfw_insn_ptr *insn_ptr; > + > + cmd = (ipfw_insn_if *)_old; > + > + /* State is used for interface names, skip other cases */ > + if (cmd->o.arg1 != 2) > + return; > + > + ifm = ipfw_search_ifindex(chain, cmd->p.if_idx); > + KASSERT(ifm != NULL, ("no ifp found for index %u", cmd->p.if_idx)); > + > + TAILQ_FOREACH(insn_ptr, &ifm->instructions, next) { > + if (insn_ptr->insn == _old) > + break; > + } > + > + KASSERT(insn_ptr != NULL, ("no insns found")); > + > + insn_ptr->insn = _new; > +} > + > + > --- /dev/null 2013-04-24 17:20:19.000000000 +0400 > +++ sys/netpfil/ipfw/ip_fw_iface.c 2013-04-24 17:18:35.546357594 +0400 > @@ -0,0 +1,467 @@ > +/*- > + * Copyright (c) 2013 Yandex LLC. > + * Author: Alexander V. Chernikov > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#include > +__FBSDID("$FreeBSD$"); > + > +/* > + * Interface tracking for ipfw. > + */ > + > +#include "opt_ipfw.h" > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include /* hooks */ > +#include > + > +#include > +#include > + > +#define IPFW_IFHASH_IDX(idx, hsize) ((idx) % (hsize)) > +#define IPFW_IFHASH_NAME(name, hsize) (fnv_32_str(name, FNV1_32_INIT) % (hsize)) > + > +TAILQ_HEAD(iface_mask_head, iface_mask); > + > +struct ip_fw_if_data { > + struct iface_mask_head *masks; /* Interface name hash */ > + size_t masks_count, masks_hsize; > + struct iface_mask_head *real_ifaces; /* 'Real' interface index hash */ > + size_t real_count, real_hsize; > + struct iface_mask_head *fake_ifaces; /* Nonexistent interface index hash */ > + size_t fake_count, fake_hsize; > + eventhandler_tag arrival, departure; > + u_short fake_idx; > +}; > + > +static void ipfw_ifhash_init_int(struct iface_mask_head **phash, size_t hsize); > +static void ipfw_ifnet_init(struct ip_fw_chain *chain, struct iface_mask *ifm); > + > +/* > + * Mappings: > + * 'iface_mask' -> idx > + * if_index -> iface_mask > + * fake_index -> iface_mask > + * > + * List of masks > + * > + */ > +static void ifnet_arrival(void *arg, struct ifnet *ifp); > +static void ifnet_departure(void *arg, struct ifnet *ifp); > + > +/* > + * Find interface structure by name. > + * Called with either UH or chain readlock held. > + */ > +struct iface_mask * > +ipfw_search_ifname(struct ip_fw_chain *chain, char *name) > +{ > + struct iface_mask *ifm; > + struct ip_fw_if_data *ifd; > + struct iface_mask_head *ifh; > + int i; > + > + ifd = chain->if_data; > + > + i = IPFW_IFHASH_NAME(name, ifd->masks_hsize); > + > + ifh = &ifd->masks[i]; > + TAILQ_FOREACH(ifm, ifh, name_next) { > + if (strcmp(name, ifm->name) == 0) > + return (ifm); > + } > + > + return (NULL); > +} > + > +/* > + * Find interface structure by real or fake ifindex. > + * Called with either UH or chain readlock held. > + */ > +struct iface_mask * > +ipfw_search_ifindex(struct ip_fw_chain *chain, uint32_t idx) > +{ > + struct iface_mask *ifm; > + struct ip_fw_if_data *ifd; > + struct iface_mask_head *ifh; > + int i; > + > + ifd = chain->if_data; > + > + if (idx & IPFW_FAKE_IDX) { > + idx &= ~IPFW_FAKE_IDX; > + i = IPFW_IFHASH_IDX(idx, ifd->fake_hsize); > + ifh = &ifd->fake_ifaces[i]; > + } else { > + i = IPFW_IFHASH_IDX(idx, ifd->real_hsize); > + ifh = &ifd->real_ifaces[i]; > + } > + > + TAILQ_FOREACH(ifm, ifh, idx_next) { > + if (ifm->idx == idx) > + return (ifm); > + } > + > + return (NULL); > +} > + > +void > +ipfw_add_ifname(struct ip_fw_chain *chain, struct iface_mask *ifm) > +{ > + struct ip_fw_if_data *ifd; > + struct iface_mask_head *ifh; > + struct iface_mask *iftemp; > + int i; > + > + ifd = chain->if_data; > + > + ipfw_ifnet_init(chain, ifm); > + > + /* Add to named hash */ > + i = IPFW_IFHASH_NAME(ifm->name, ifd->masks_hsize); > + ifh = &ifd->masks[i]; > + TAILQ_INSERT_TAIL(ifh, ifm, name_next); > + > + if (ifm->flags & IPFW_IFLAG_FAKE) { > + /* Add to fake interfaces hash */ > + ifm->idx = ++ifd->fake_idx; > + i = IPFW_IFHASH_IDX(ifm->idx, ifd->fake_hsize); > + ifh = &ifd->fake_ifaces[i]; > + } else { > + /* Add to real interfaces hash */ > + i = IPFW_IFHASH_IDX(ifm->idx, ifd->real_hsize); > + ifh = &ifd->real_ifaces[i]; > + > + /* Check index for consistency */ > + TAILQ_FOREACH(iftemp, ifh, idx_next) { > + KASSERT(iftemp->idx != ifm->idx, > + ("Non-fake if %s w idx %d found (%s)!", > + iftemp->name, ifm->idx, ifm->name)); > + } > + } > + > + TAILQ_INSERT_TAIL(ifh, ifm, idx_next); > +} > + > +static void > +ifnet_arrival(void *arg, struct ifnet *ifp) > +{ > + struct ip_fw_chain *chain = (struct ip_fw_chain *)arg; > + struct ip_fw_if_data *ifd; > + struct iface_mask *iftemp, *ifm; > + struct iface_mask_head *ifh; > + struct ipfw_insn_ptr *insn_ptr; > + int i; > + > + iftemp = malloc(sizeof(struct iface_mask), M_IPFW, M_WAITOK | M_ZERO); > + > + iftemp->ifp = ifp; > + iftemp->idx = ifp->if_index; > + strlcpy(iftemp->name, ifp->if_xname, IFNAMSIZ); > + > + IPFW_UH_WLOCK(chain); > + IPFW_WLOCK(chain); > + > + ifd = chain->if_data; > + > + if (ifd == NULL || ifd->arrival == NULL) { > + /* We're shutting down */ > + IPFW_WUNLOCK(chain); > + IPFW_UH_WUNLOCK(chain); > + free(iftemp, M_IPFW); > + return; > + } > + > + ifm = ipfw_search_ifname(chain, iftemp->name); > + > + if (ifm != NULL) { > + /* Found. Let's update index */ > + KASSERT(ifm->flags & IPFW_IFLAG_FAKE, > + ("Non-fake interface found for %s", ifm->name)); > + > + ifm->flags &= ~IPFW_IFLAG_FAKE; > + /* Relink to real index */ > + i = IPFW_IFHASH_IDX(ifm->idx, ifd->fake_hsize); > + ifh = &ifd->fake_ifaces[i]; > + TAILQ_REMOVE(ifh, ifm, idx_next); > + > + i = IPFW_IFHASH_IDX(iftemp->idx, ifd->real_hsize); > + ifh = &ifd->real_ifaces[i]; > + TAILQ_INSERT_TAIL(ifh, ifm, idx_next); > + > + CTR2(KTR_NET, "ifnet upgrade: fake %u -> %u", ifm->idx, > + iftemp->idx); > + /* Notify consumers */ > + TAILQ_FOREACH(insn_ptr, &ifm->instructions, next) > + ipfw_update_rewrite(chain, insn_ptr->insn, ifm, > + (uintptr_t)iftemp->idx); > + > + ifm->idx = iftemp->idx; > + } else { > + /* Not found. Add to list */ > + ifm = iftemp; > + iftemp = NULL; > + > + ipfw_ifnet_init(chain, ifm); > + > + CTR2(KTR_NET, "ifmp=%p uc=%u", ifm, ifm->refcount); > + > + /* Add to named hash */ > + i = IPFW_IFHASH_NAME(ifm->name, ifd->masks_hsize); > + ifh = &ifd->masks[i]; > + TAILQ_INSERT_TAIL(ifh, ifm, name_next); > + > + /* Add to real interfaces hash */ > + i = IPFW_IFHASH_IDX(ifm->idx, ifd->real_hsize); > + ifh = &ifd->real_ifaces[i]; > + > + /* Check index for consistency */ > + TAILQ_FOREACH(iftemp, ifh, idx_next) { > + KASSERT(iftemp->idx != ifm->idx, > + ("Non-fake if %s w idx %d found (%s)!", > + iftemp->name, ifm->idx, ifm->name)); > + } > + > + TAILQ_INSERT_TAIL(ifh, ifm, idx_next); > + > + CTR3(KTR_NET, "new iface %p, idx %u uc=%u", ifm->name, > + ifm->idx, ifm->refcount); > + } > + IPFW_WUNLOCK(chain); > + IPFW_UH_WUNLOCK(chain); > + > + if (iftemp != NULL) > + free(iftemp, M_IPFW); > +} > + > +static void > +ifnet_departure(void *arg, struct ifnet *ifp) > +{ > + struct ip_fw_chain *chain = (struct ip_fw_chain *)arg; > + struct ip_fw_if_data *ifd; > + struct iface_mask *ifm; > + struct iface_mask_head *ifh; > + struct ipfw_insn_ptr *insn_ptr; > + int i; > + > + IPFW_UH_WLOCK(chain); > + IPFW_WLOCK(chain); > + > + if ((ifd = chain->if_data) == NULL) { > + /* We're shutting down */ > + IPFW_WUNLOCK(chain); > + IPFW_UH_WUNLOCK(chain); > + return; > + } > + > + ifm = ipfw_search_ifname(chain, ifp->if_xname); > + > + if (ifm == NULL) { > + IPFW_WUNLOCK(chain); > + IPFW_UH_WUNLOCK(chain); > + printf("ipfw: unknown iface %s departure\n", ifp->if_xname); > + return; > + } > + > + KASSERT((ifm->flags & IPFW_IFLAG_FAKE) == 0, > + ("Fake interface found for %s", ifm->name)); > + > + /* Check if we need to save given interface. */ > + if (ifm->refcount == 0) { > + CTR1(KTR_NET, "Deleting interface %p", ifm); > + /* Delete from name hash */ > + i = IPFW_IFHASH_NAME(ifm->name, ifd->masks_hsize); > + ifh = &ifd->masks[i]; > + TAILQ_REMOVE(ifh, ifm, name_next); > + > + /* Delete from real iface hash */ > + i = IPFW_IFHASH_IDX(ifm->idx, ifd->real_hsize); > + ifh = &ifd->real_ifaces[i]; > + TAILQ_REMOVE(ifh, ifm, idx_next); > + > + IPFW_WUNLOCK(chain); > + IPFW_UH_WUNLOCK(chain); > + > + free(ifm, M_IPFW); > + return; > + } > + > + CTR1(KTR_NET, "Interface uc=%u", ifm->refcount); > + > + /* Interface is used. Move to fake hash */ > + ifm->flags |= IPFW_IFLAG_FAKE; > + /* Relink to fake index */ > + i = IPFW_IFHASH_IDX(ifm->idx, ifd->real_hsize); > + ifh = &ifd->real_ifaces[i]; > + TAILQ_REMOVE(ifh, ifm, idx_next); > + > + /* Alloc fake index */ > + ifd->fake_idx++; > + i = IPFW_IFHASH_IDX(ifd->fake_idx, ifd->fake_hsize); > + ifh = &ifd->fake_ifaces[i]; > + TAILQ_INSERT_TAIL(ifh, ifm, idx_next); > + > + CTR2(KTR_NET, "Interface %p departure, fake index %u", > + ifm, ifd->fake_idx); > + > + /* Notify consumers */ > + TAILQ_FOREACH(insn_ptr, &ifm->instructions, next) > + ipfw_update_rewrite(chain, insn_ptr->insn, ifm, > + (uintptr_t)(ifd->fake_idx | IPFW_FAKE_IDX)); > + > + ifm->idx = ifd->fake_idx; > + > + IPFW_WUNLOCK(chain); > + IPFW_UH_WUNLOCK(chain); > +} > + > +static void > +ipfw_ifnet_init(struct ip_fw_chain *chain, struct iface_mask *ifm) > +{ > + > + TAILQ_INIT(&ifm->instructions); > +} > + > + > +static void > +ipfw_ifhash_init_int(struct iface_mask_head **phash, size_t hsize) > +{ > + struct iface_mask_head *ifh; > + int i; > + > + ifh = malloc(sizeof(struct iface_mask_head) * hsize, M_IPFW, > + M_WAITOK | M_ZERO); > + > + *phash = ifh; > + > + for (i = 0; i < hsize; i++, ifh++) > + TAILQ_INIT(ifh); > +} > + > +void > +ipfw_ifhash_init(struct ip_fw_chain *chain) > +{ > + struct ip_fw_if_data *ifd; > + struct iface_mask_head *ifh; > + struct iface_mask *ifm; > + struct ifnet *ifp; > + int i; > + > + ifd = malloc(sizeof(struct ip_fw_if_data), M_IPFW, M_WAITOK | M_ZERO); > + chain->if_data = ifd; > + > + ifd->masks_hsize = ifd->real_hsize = ifd->fake_hsize = 32; > + > + ipfw_ifhash_init_int(&ifd->masks, ifd->masks_hsize); > + ipfw_ifhash_init_int(&ifd->real_ifaces, ifd->fake_hsize); > + ipfw_ifhash_init_int(&ifd->fake_ifaces, ifd->real_hsize); > + > + IFNET_RLOCK(); > + TAILQ_FOREACH(ifp, &V_ifnet, if_link) { > + ifm = malloc(sizeof(struct iface_mask), M_IPFW, M_WAITOK | M_ZERO); > + strlcpy(ifm->name, ifp->if_xname, IFNAMSIZ); > + ifm->ifp = ifp; > + ifm->idx = ifp->if_index; > + > + ipfw_ifnet_init(chain, ifm); > + > + i = IPFW_IFHASH_IDX(ifm->idx, ifd->real_hsize); > + ifh = &ifd->real_ifaces[i]; > + TAILQ_INSERT_TAIL(ifh, ifm, idx_next); > + > + i = IPFW_IFHASH_NAME(ifm->name, ifd->masks_hsize); > + ifh = &ifd->masks[i]; > + TAILQ_INSERT_TAIL(ifh, ifm, name_next); > + > + CTR2(KTR_NET, "init iface %p idx %u", ifm, ifm->idx); > + > + } > + IFNET_RUNLOCK(); > + > + /* XXX: there is a gap between RUNLOCK and interface registration */ > + > + ifd->arrival = EVENTHANDLER_REGISTER(ifnet_arrival_event, > + ifnet_arrival, chain, EVENTHANDLER_PRI_ANY); > + > + ifd->departure = EVENTHANDLER_REGISTER(ifnet_departure_event, > + ifnet_departure, chain, EVENTHANDLER_PRI_ANY); > +} > + > +void > +ipfw_ifhash_detach(struct ip_fw_chain *chain) > +{ > + struct ip_fw_if_data *ifd; > + > + ifd = chain->if_data; > + > + EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ifd->arrival); > + EVENTHANDLER_DEREGISTER(ifnet_departure_event, ifd->departure); > + > + ifd->arrival = NULL; > + ifd->departure = NULL; > +} > + > + > +void > +ipfw_ifhash_free(struct ip_fw_chain *chain) > +{ > + struct ip_fw_if_data *ifd; > + struct iface_mask_head *ifh; > + struct iface_mask *ifm, *ifm_next; > + int i; > + > + ifd = chain->if_data; > + chain->if_data = NULL; > + > + ifh = ifd->masks; > + > + for (i = 0; i < ifd->masks_hsize; i++, ifh++) { > + TAILQ_FOREACH_SAFE(ifm, ifh, name_next, ifm_next) { > + /* > + * Assume every consumer to free its > + * iface-specific data beforehand. > + */ > + free(ifm, M_IPFW); > + } > + } > + > + free(ifd->masks, M_IPFW); > + free(ifd->real_ifaces, M_IPFW); > + free(ifd->fake_ifaces, M_IPFW); > + > + free(ifd, M_IPFW); > +} > + > --- /dev/null 2013-04-24 17:22:00.000000000 +0400 > +++ sys/netpfil/ipfw/ip_fw_iface.h 2013-04-22 19:09:56.624996491 +0400 > @@ -0,0 +1,55 @@ > +/*- > + * Copyright (c) 2013 Yandex LLC. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + * > + * $FreeBSD$ > + */ > + > +#ifndef _IP_FW_IFACE_H_ > +#define _IP_FW_IFACE_H_ > + > +struct ipfw_insn_ptr { > + TAILQ_ENTRY(ipfw_insn_ptr) next; > + ipfw_insn *insn; > +}; > + > +struct iface_mask { > + struct ifnet *ifp; > + uint32_t idx; /* Saved interface index */ > + uint32_t flags; /* Pad */ > + uint32_t refcount; /* Usage count */ > + char name[IFNAMSIZ]; /* Interface/mask */ > + TAILQ_ENTRY(iface_mask) idx_next; > + TAILQ_ENTRY(iface_mask) name_next; > + TAILQ_HEAD(rule_list, ipfw_insn_ptr) instructions; /* instructions using given mask */ > +}; > +#define IPFW_IFLAG_FAKE 0x01 > + > +#define IPFW_FAKE_IDX (1 << 31) > + > +struct iface_mask *ipfw_search_ifname(struct ip_fw_chain *chain, char *name); > +struct iface_mask *ipfw_search_ifindex(struct ip_fw_chain *chain, uint32_t idx); > +void ipfw_add_ifname(struct ip_fw_chain *chain, struct iface_mask *ifm); > + > +#endif > + > From owner-freebsd-ipfw@FreeBSD.ORG Wed Apr 24 16:47:03 2013 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 1CEE24AE; Wed, 24 Apr 2013 16:47:03 +0000 (UTC) (envelope-from melifaro@FreeBSD.org) Received: from mail.ipfw.ru (unknown [IPv6:2a01:4f8:120:6141::2]) by mx1.freebsd.org (Postfix) with ESMTP id 496E31FEF; Wed, 24 Apr 2013 16:47:02 +0000 (UTC) Received: from dhcp170-36-red.yandex.net ([95.108.170.36]) by mail.ipfw.ru with esmtpsa (TLSv1:CAMELLIA256-SHA:256) (Exim 4.76 (FreeBSD)) (envelope-from ) id 1UV2tp-0008bW-0d; Wed, 24 Apr 2013 20:50:29 +0400 Message-ID: <51780C49.7000204@FreeBSD.org> Date: Wed, 24 Apr 2013 20:46:01 +0400 From: "Alexander V. Chernikov" User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:17.0) Gecko/20130418 Thunderbird/17.0.5 MIME-Version: 1.0 To: Luigi Rizzo Subject: Re: [patch] ipfw interface tracking and opcode rewriting References: <517801D3.5040502@FreeBSD.org> <20130424162349.GA8439@onelab2.iet.unipi.it> In-Reply-To: <20130424162349.GA8439@onelab2.iet.unipi.it> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: freebsd-ipfw@freebsd.org, luigi@freebsd.org X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Apr 2013 16:47:03 -0000 On 24.04.2013 20:23, Luigi Rizzo wrote: > On Wed, Apr 24, 2013 at 08:01:23PM +0400, Alexander V. Chernikov wrote: >> Hello list! >> >> Currently ipfw uses strncmp() function to do interface matching which is >> quite slow. >> Additionally, ipfw_insn_if opcode is quite big and given that struct >> ip_fw occupy 48 bytes >> (without first instruction) which gives us good chance that part of >> interface name will be on the second cache line on amd64. >> >> Pure synthetic testing (ipfw with 1 and 2 'ipfw count ip from any to any >> recv ifaceX') shows about 3.8% performance loss (190kpps out of 5.1 >> mpps) for each rule, >> while indexed version shows about 2.0% and 1.2% for first and second rule. >> >> Additionally, our production (8.3-based firewalls with old strncmp) >> shows about 40% kernel time spent in strncmp on 1-2mpps (each packet >> traverses 5-6 such rules). >> >> Here is the patch which does the following: >> 1) adds interface tracking for ipfw. Every interface is tracked >> regardless of its usage in the ruleset. This simplifies locking and >> makes easier to port such functionality to userland. >> 2) adds general opcode rewriting system permitting kernel to >> algorithmically (stateless) or statefully (involving extrernal data) >> rewrite user-supplied opcodes with possible size change. >> This can be used to deprecate opcodes which are now superseded by newer >> ones while keeping ABI (and we currently have such opcodes). >> 3) Store (and track) inderface index for non-wildcard interface inside >> opcode. >> >> If there are no objections I would like to commit (possibly updated >> vesrion) in the middle of the next week. > hmmm.... this is quite a large change, and from the description it > is a bit unclear to me how the "opcode rewriting" thing relates to > the use of strings vs index for name matching. sorry, I havent't describe this explicitly. Index matching is done via storing interface index in in p.glob field of ipfw_insn_if instruction. > > Additionally, i wonder if there isn't a better way to replace strncmp > with some two 64-bit comparisons (the name is 16 bytes) by making > sure that the fields are zero-padded and suitably aligned. > At this point, on the machines you care about (able to sustain > 1+ Mpps) the two comparison should have the same cost as > the index comparison, without the need to track update in the names. Well, actually I'm thinking of the next 2 steps: 1) making kernel rule header more compact (20 bytes instead of 48) and making it invisible for userland. This involves rule counters to be stored separately (and possibly as pcpu-based ones). 2) since ruleset is now nearly readonly and more or less compact we can try to store it in contiguous address space to optimize cache line usage. > > note, my comment is only about the strncmp() part, i guess the > opcode rewriting is orthogonal and may have other applications, > but i am not completely sure about it. > > cheers > luigi > > understand if > While in principle > i do not think the strncmp is a major performance killer. even if it is, > i believe it > >> Index: sys/netinet/ip_fw.h >> =================================================================== >> --- sys/netinet/ip_fw.h (revision 248704) >> +++ sys/netinet/ip_fw.h (working copy) >> @@ -341,6 +341,7 @@ typedef struct _ipfw_insn_if { >> union { >> struct in_addr ip; >> int glob; >> + unsigned int if_idx; /* Interface index (kernel) */ >> } p; >> char name[IFNAMSIZ]; >> } ipfw_insn_if; >> @@ -495,6 +496,8 @@ typedef struct _ipfw_insn_icmp6 { >> * queue(3) macros for portability and readability. >> */ >> >> +#define IP_FW_RULE_REWRITTEN 0x01 /* Rule is modified by rewriter */ >> + >> struct ip_fw { >> struct ip_fw *x_next; /* linked list of rules */ >> struct ip_fw *next_rule; /* ptr to next [skipto] rule */ >> @@ -505,7 +508,7 @@ struct ip_fw { >> uint16_t rulenum; /* rule number */ >> uint8_t set; /* rule set (0..31) */ >> #define RESVD_SET 31 /* set for default and persistent rules */ >> - uint8_t _pad; /* padding */ >> + uint8_t flags; /* padding */ >> uint32_t id; /* rule id */ >> >> /* These fields are present in all rules. */ >> Index: sys/modules/ipfw/Makefile >> =================================================================== >> --- sys/modules/ipfw/Makefile (revision 248704) >> +++ sys/modules/ipfw/Makefile (working copy) >> @@ -8,6 +8,7 @@ KMOD= ipfw >> SRCS= ip_fw2.c ip_fw_pfil.c >> SRCS+= ip_fw_dynamic.c ip_fw_log.c >> SRCS+= ip_fw_sockopt.c ip_fw_table.c >> +SRCS+= ip_fw_iface.c ip_fw_rewrite.c >> SRCS+= opt_inet.h opt_inet6.h opt_ipdivert.h opt_ipfw.h opt_ipsec.h >> >> CFLAGS+= -DIPFIREWALL >> Index: sys/netpfil/ipfw/ip_fw2.c >> =================================================================== >> --- sys/netpfil/ipfw/ip_fw2.c (revision 248704) >> +++ sys/netpfil/ipfw/ip_fw2.c (working copy) >> @@ -353,17 +353,17 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd, >> if (ifp == NULL) /* no iface with this packet, match fails */ >> return 0; >> /* Check by name or by IP address */ >> - if (cmd->name[0] != '\0') { /* match by name */ >> - if (cmd->name[0] == '\1') /* use tablearg to match */ >> + if (cmd->o.arg1 != 0) { /* match by name */ >> + if (cmd->o.arg1 == 1) /* use tablearg to match */ >> return ipfw_lookup_table_extended(chain, cmd->p.glob, >> ifp->if_xname, tablearg, IPFW_TABLE_INTERFACE); >> /* Check name */ >> - if (cmd->p.glob) { >> + if (cmd->p.if_idx) { >> + if (ifp->if_index == cmd->p.if_idx) >> + return (1); >> + } else { >> if (fnmatch(cmd->name, ifp->if_xname, 0) == 0) >> return(1); >> - } else { >> - if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0) >> - return(1); >> } >> } else { >> #ifdef __FreeBSD__ /* and OSX too ? */ >> @@ -2667,6 +2667,8 @@ vnet_ipfw_init(const void *unused) >> >> IPFW_LOCK_INIT(chain); >> ipfw_dyn_init(chain); >> + ipfw_ifhash_init(chain); >> + ipfw_rewrite_init(chain); >> >> /* First set up some values that are compile time options */ >> V_ipfw_vnet_ready = 1; /* Open for business */ >> @@ -2708,6 +2710,7 @@ vnet_ipfw_uninit(const void *unused) >> (void)ipfw_attach_hooks(0 /* detach */); >> V_ip_fw_ctl_ptr = NULL; >> IPFW_UH_WLOCK(chain); >> + ipfw_ifhash_detach(chain); /* detach eventhandlers */ >> IPFW_UH_WUNLOCK(chain); >> IPFW_UH_WLOCK(chain); >> >> @@ -2722,9 +2725,14 @@ vnet_ipfw_uninit(const void *unused) >> rule = chain->map[i]; >> rule->x_next = reap; >> reap = rule; >> + /* Clear rewrites if any */ >> + if (rule->flags & IP_FW_RULE_REWRITTEN) >> + ipfw_relocate_rewrite(chain, rule->cmd, NULL); >> } >> if (chain->map) >> free(chain->map, M_IPFW); >> + ipfw_rewrite_free(chain); >> + ipfw_ifhash_free(chain); >> IPFW_WUNLOCK(chain); >> IPFW_UH_WUNLOCK(chain); >> if (reap != NULL) >> Index: sys/netpfil/ipfw/ip_fw_private.h >> =================================================================== >> --- sys/netpfil/ipfw/ip_fw_private.h (revision 248704) >> +++ sys/netpfil/ipfw/ip_fw_private.h (working copy) >> @@ -212,6 +212,13 @@ VNET_DECLARE(int, autoinc_step); >> VNET_DECLARE(unsigned int, fw_tables_max); >> #define V_fw_tables_max VNET(fw_tables_max) >> >> + >> +#define CMDSIZE(rule) (((struct ip_fw *)(rule))->cmd_len * sizeof(uint32_t)) >> + >> + >> +struct ip_fw_if_data; >> +struct ip_fw_rw_data; >> + >> struct ip_fw_chain { >> struct ip_fw *rules; /* list of rules */ >> struct ip_fw *reap; /* list of rules to reap */ >> @@ -232,8 +239,42 @@ struct ip_fw_chain { >> #endif >> uint32_t id; /* ruleset id */ >> uint32_t gencnt; /* generation count */ >> + struct ip_fw_if_data *if_data; /* Interface tracking data */ >> + struct ip_fw_rw_data *rewrite_data; /* Rule rewrite data */ >> }; >> >> +/* ip_fw_rewrite.c */ >> +struct ip_fw_rw_info { >> + void *sptr; /* State created by ipfw_prepare_rewrite() */ >> + int count; /* Number of opcodes requesting rewrite */ >> + int states; /* Number of opcodes with stateful rewrite */ >> + int lendiff; /* Difference with oridinal rule len (insns) */ >> +}; >> + >> +void ipfw_rewrite_init(struct ip_fw_chain *chain); >> +void ipfw_rewrite_free(struct ip_fw_chain *chain); >> +int ipfw_rewrite_len(struct ip_fw_chain *chain); >> +void *ipfw_prepare_rewrite(struct ip_fw_chain *chain, ipfw_insn *cmd, >> + int cmd_len, struct ip_fw_rw_info *rwi); >> +void ipfw_perform_rewrite(struct ip_fw_chain *chain, ipfw_insn *kcmd, >> + void *state); >> +void ipfw_relocate_rewrite(struct ip_fw_chain *chain, ipfw_insn *old, >> + ipfw_insn *new); >> +int ipfw_export_rewrite(struct ip_fw_chain *chain, ipfw_insn *kcmd, >> + ipfw_insn *target); >> + >> +void ipfw_check_rewrite(struct ip_fw_chain *chain, ipfw_insn *insn, >> + struct ip_fw_rw_info *rwi); >> +void ipfw_update_rewrite(struct ip_fw_chain *chain, ipfw_insn *insn, >> + void *state, uintptr_t val); >> + >> + >> +/* ip_fw_iface.c */ >> +void ipfw_ifhash_init(struct ip_fw_chain *chain); >> +void ipfw_ifhash_free(struct ip_fw_chain *chain); >> +void ipfw_ifhash_detach(struct ip_fw_chain *chain); >> + >> + >> struct sockopt; /* used by tcp_var.h */ >> >> /* Macro for working with various counters */ >> @@ -295,7 +336,8 @@ struct sockopt; /* used by tcp_var.h */ >> >> /* In ip_fw_sockopt.c */ >> int ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id); >> -int ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule); >> +int ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule, >> + struct ip_fw_rw_info *rwi); >> int ipfw_ctl(struct sockopt *sopt); >> int ipfw_chk(struct ip_fw_args *args); >> void ipfw_reap_rules(struct ip_fw *head); >> Index: sys/netpfil/ipfw/ip_fw_sockopt.c >> =================================================================== >> --- sys/netpfil/ipfw/ip_fw_sockopt.c (revision 248971) >> +++ sys/netpfil/ipfw/ip_fw_sockopt.c (working copy) >> @@ -73,6 +73,8 @@ MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct >> * static variables followed by global ones (none in this file) >> */ >> >> +static void ipfw_export_header(struct ip_fw *krule, struct ip_fw *dst); >> + >> /* >> * Find the smallest rule >= key, id. >> * We could use bsearch but it is so simple that we code it directly >> @@ -153,7 +155,8 @@ swap_map(struct ip_fw_chain *chain, struct ip_fw * >> * Must be called without IPFW_UH held >> */ >> int >> -ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule) >> +ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule, >> + struct ip_fw_rw_info *rwi) >> { >> struct ip_fw *rule; >> int i, l, insert_before; >> @@ -163,7 +166,8 @@ int >> return (EINVAL); >> >> l = RULESIZE(input_rule); >> - rule = malloc(l, M_IPFW, M_WAITOK | M_ZERO); >> + rule = malloc(l + rwi->lendiff * sizeof(uint32_t), M_IPFW, >> + M_WAITOK | M_ZERO); >> /* get_map returns with IPFW_UH_WLOCK if successful */ >> map = get_map(chain, 1, 0 /* not locked */); >> if (map == NULL) { >> @@ -171,7 +175,15 @@ int >> return ENOSPC; >> } >> >> - bcopy(input_rule, rule, l); >> + if (rwi->sptr == NULL) >> + bcopy(input_rule, rule, l); >> + else { >> + /* Copy header and first instuction */ >> + bcopy(input_rule, rule, sizeof(struct ip_fw)); >> + rule->flags |= IP_FW_RULE_REWRITTEN; >> + ipfw_perform_rewrite(chain, rule->cmd, rwi->sptr); >> + } >> + >> /* clear fields not settable from userland */ >> rule->x_next = NULL; >> rule->next_rule = NULL; >> @@ -366,6 +378,14 @@ del_entry(struct ip_fw_chain *chain, uint32_t arg) >> rule = chain->map[i]; >> if (keep_rule(rule, cmd, new_set, num)) >> map[ofs++] = rule; >> + else { >> + /* Clear rewrites if any */ >> + if (rule->flags & IP_FW_RULE_REWRITTEN) { >> + printf("Moving rule %p to clear list\n", rule); >> + ipfw_relocate_rewrite(chain, >> + rule->cmd, NULL); >> + } >> + } >> } >> /* 3. copy the final part of the map */ >> bcopy(chain->map + end, map + ofs, >> @@ -384,6 +404,7 @@ del_entry(struct ip_fw_chain *chain, uint32_t arg) >> ipfw_expire_dyn_rules(chain, rule, RESVD_SET); >> rule->x_next = chain->reap; >> chain->reap = rule; >> + printf("Adding rule %p to reap list\n", rule); >> } >> break; >> >> @@ -517,7 +538,8 @@ zero_entry(struct ip_fw_chain *chain, u_int32_t ar >> * Rules are simple, so this mostly need to check rule sizes. >> */ >> static int >> -check_ipfw_struct(struct ip_fw *rule, int size) >> +check_ipfw_struct(struct ip_fw_chain *chain, struct ip_fw *rule, int size, >> + struct ip_fw_rw_info *rwi) >> { >> int l, cmdlen = 0; >> int have_action=0; >> @@ -696,6 +718,7 @@ static int >> case O_VIA: >> if (cmdlen != F_INSN_SIZE(ipfw_insn_if)) >> goto bad_size; >> + ipfw_check_rewrite(chain, cmd, rwi); >> break; >> >> case O_ALTQ: >> @@ -868,6 +891,13 @@ int convert_rule_to_8(struct ip_fw *rule); >> #endif >> >> >> +static void >> +ipfw_export_header(struct ip_fw *krule, struct ip_fw *dst) >> +{ >> + >> + memcpy(dst, krule, sizeof(struct ip_fw) - sizeof(ipfw_insn)); >> +} >> + >> /* >> * Copy the static and dynamic rules to the supplied buffer >> * and return the amount of space actually used. >> @@ -887,11 +917,28 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf >> rule = chain->map[i]; >> >> if (is7) { >> - /* Convert rule to FreeBSd 7.2 format */ >> - l = RULESIZE7(rule); >> + /* Convert rule to FreeBSD 7.2 format */ >> + if (rule->flags & IP_FW_RULE_REWRITTEN) >> + l = ipfw_export_rewrite(chain, rule->cmd, NULL); >> + else >> + l = CMDSIZE(rule); >> + >> + /* >> + * Add header length. >> + * v.8 rule header is 4 bytes bigger. >> + */ >> + l += sizeof(struct ip_fw7) - sizeof(ipfw_insn); >> + >> if (bp + l + sizeof(uint32_t) <= ep) { >> int error; >> bcopy(rule, bp, l + sizeof(uint32_t)); >> + >> + if (rule->flags & IP_FW_RULE_REWRITTEN) { >> + ipfw_export_rewrite(chain, rule->cmd, dst->cmd); >> + ipfw_export_header(rule, dst); >> + } else >> + bcopy(rule, bp, l + sizeof(uint32_t)); >> + >> error = convert_rule_to_7((struct ip_fw *) bp); >> if (error) >> return 0; /*XXX correct? */ >> @@ -910,14 +957,23 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf >> continue; /* go to next rule */ >> } >> >> - /* normal mode, don't touch rules */ >> - l = RULESIZE(rule); >> + if (rule->flags & IP_FW_RULE_REWRITTEN) >> + l = ipfw_export_rewrite(chain, rule->cmd, NULL); >> + else >> + l = CMDSIZE(rule); >> + /* Add header length */ >> + l += sizeof(struct ip_fw) - sizeof(ipfw_insn); >> + >> if (bp + l > ep) { /* should not happen */ >> printf("overflow dumping static rules\n"); >> break; >> } >> dst = (struct ip_fw *)bp; >> - bcopy(rule, dst, l); >> + if (rule->flags & IP_FW_RULE_REWRITTEN) { >> + ipfw_export_rewrite(chain, rule->cmd, dst->cmd); >> + ipfw_export_header(rule, dst); >> + } else >> + bcopy(rule, dst, l); >> /* >> * XXX HACK. Store the disable mask in the "next" >> * pointer in a wild attempt to keep the ABI the same. >> @@ -949,6 +1005,7 @@ ipfw_ctl(struct sockopt *sopt) >> uint32_t opt; >> char xbuf[128]; >> ip_fw3_opheader *op3 = NULL; >> + struct ip_fw_rw_info rwi; >> >> error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW); >> if (error) >> @@ -998,7 +1055,7 @@ ipfw_ctl(struct sockopt *sopt) >> for (;;) { >> int len = 0, want; >> >> - size = chain->static_len; >> + size = chain->static_len + ipfw_rewrite_len(chain); >> size += ipfw_dyn_len(); >> if (size >= sopt->sopt_valsize) >> break; >> @@ -1027,6 +1084,8 @@ ipfw_ctl(struct sockopt *sopt) >> error = sooptcopyin(sopt, rule, RULE_MAXSIZE, >> sizeof(struct ip_fw7) ); >> >> + memset(&rwi, 0, sizeof(rwi)); >> + >> /* >> * If the size of commands equals RULESIZE7 then we assume >> * a FreeBSD7.2 binary is talking to us (set is7=1). >> @@ -1042,15 +1101,21 @@ ipfw_ctl(struct sockopt *sopt) >> if (error) >> return error; >> if (error == 0) >> - error = check_ipfw_struct(rule, RULESIZE(rule)); >> + error = check_ipfw_struct(chain, rule, RULESIZE(rule), >> + &rwi); >> } else { >> is7 = 0; >> if (error == 0) >> - error = check_ipfw_struct(rule, sopt->sopt_valsize); >> + error = check_ipfw_struct(chain, rule, >> + sopt->sopt_valsize, &rwi); >> } >> if (error == 0) { >> + /* Prepare rewrite, if needed */ >> + if (rwi.count > 0) >> + rwi.sptr = ipfw_prepare_rewrite(chain, >> + rule->cmd, rule->cmd_len, &rwi); >> /* locking is done within ipfw_add_rule() */ >> - error = ipfw_add_rule(chain, rule); >> + error = ipfw_add_rule(chain, rule, &rwi); >> size = RULESIZE(rule); >> if (!error && sopt->sopt_dir == SOPT_GET) { >> if (is7) { >> @@ -1350,7 +1415,7 @@ convert_rule_to_7(struct ip_fw *rule) >> bcopy(rule, tmp, RULE_MAXSIZE); >> >> /* Copy fields */ >> - rule7->_pad = tmp->_pad; >> + rule7->_pad = 0; >> rule7->set = tmp->set; >> rule7->rulenum = tmp->rulenum; >> rule7->cmd_len = tmp->cmd_len; >> @@ -1423,7 +1488,7 @@ convert_rule_to_8(struct ip_fw *rule) >> } >> } >> >> - rule->_pad = tmp->_pad; >> + rule->flags = 0; >> rule->set = tmp->set; >> rule->rulenum = tmp->rulenum; >> rule->cmd_len = tmp->cmd_len; >> --- /dev/null 2013-04-24 17:20:19.000000000 +0400 >> +++ sys/netpfil/ipfw/ip_fw_rewrite.c 2013-04-24 17:19:15.278097243 +0400 >> @@ -0,0 +1,835 @@ >> +/*- >> + * Copyright (c) 2013 Yandex LLC. >> + * Author: Alexander V. Chernikov >> + * >> + * Redistribution and use in source and binary forms, with or without >> + * modification, are permitted provided that the following conditions >> + * are met: >> + * 1. Redistributions of source code must retain the above copyright >> + * notice, this list of conditions and the following disclaimer. >> + * 2. Redistributions in binary form must reproduce the above copyright >> + * notice, this list of conditions and the following disclaimer in the >> + * documentation and/or other materials provided with the distribution. >> + * >> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND >> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >> + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE >> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS >> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT >> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY >> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF >> + * SUCH DAMAGE. >> + */ >> + >> +#include >> +__FBSDID("$FreeBSD$"); >> + >> +/* >> + * Rule opcode rewriting system for ipfw. >> + * System permits automatic algoritmic (stateless) or statefull ( >> + * requiring access/monidifcation to external data) of opcodes. >> + * Modification is done by calling special per-opcode dependent >> + * callbacks. Saving unmodified user-supplied rules, size recalculation, >> + * rule export and relocation is handled by subsystem. >> + * Writing opcode modificator requires adding it to rewrites[] array >> + * and filling appropriate callbacks (at least 'convert' one. >> + */ >> + >> +#include "opt_ipfw.h" >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include >> +#include /* hooks */ >> +#include >> + >> +#include >> +#include >> + >> +#define NO_REWRITE 0 >> +#define STATELESS_REWRITE 1 >> +#define STATEFUL_REWRITE 2 >> + >> +struct ip_fw_rewrite { >> + uint32_t opcode; >> + >> + /* >> + * Checks if given opcode needs to be changed. Called (indirectly) >> + * from check_ipfw_struct() without holding any locks. Fuction should >> + * quickly check if given opcode needs to be rewritten and set @len to >> + * size difference (in bytes) between new (altered) opcode size and >> + * old one. Note that &len hould be aligned to u32. >> + * >> + * Params: >> + * @chain - pointer to current ifpw chain >> + * @insn - given ipfw_instn >> + * @len - pointer to length diff (in insns) >> + * >> + * Returns: >> + * NO_REWRITE - no need to convert >> + * STATELESS_REWRITE - (algoritmic) conversion required. >> + * STATEFUL_REWRITE - stateful conversion required. >> + * >> + * Callback is OPTIONAL, defaults to STATELESS_REWRITE if not set. >> + */ >> + int (*check)(struct ip_fw_chain *, ipfw_insn *, int *); >> + >> + /* >> + * Prepares state for given opcode if needed. Called without >> + * holding any locks permitting to allocate any amount of memory. >> + * Note that result (and actual state usage) has to be consistent >> + * with *check (and other) callbacks. >> + * >> + * Params: >> + * @chain - pointer to current ifpw chain >> + * @insn - given ipfw_instn >> + * @pstate - pointer to pointer to state >> + * >> + * Returns: >> + * NO_REWRITE - no need to convert >> + * STATELESS_REWRITE - (algoritmic) conversion can be done. >> + * STATEFUL_REWRITE - stateful conversion required, state is saved to >> + * given pointer. >> + * >> + * Callback is OPTIONAL, defaults to STATELESS_REWRITE if not set. >> + */ >> + int (*prepare)(struct ip_fw_chain *, ipfw_insn *insn, void **); >> + >> + /* >> + * Performs opcode conversion. Called with chain WLOCK held. >> + * Note that opcode copy is handled automatically if >> + * NO_REWRITE is returned. @len has to be filled otherwise. >> + * >> + * Params: >> + * @chain - pointer to current ifpw chain >> + * @_old - userland ipfw_instn >> + * @_new - kernel ipfw_insn >> + * @state - pointer to state saved >> + * @len - pointer to opcode length (in instructions) >> + * >> + * Returns: >> + * NO_REWRITE - no need to convert >> + * STATELESS_REWRITE - (algoritmic) conversion is done. >> + * STATEFUL_REWRITE - stateful conversion is done, state is consumed. >> + * >> + * Callback is MANDATORY. >> + */ >> + int (*convert)(struct ip_fw_chain *, ipfw_insn *, ipfw_insn *, void *, int *); >> + >> + /* >> + * Performs state cleanup (rule deletion). Called with chain WLOCK held. >> + * State hint can be provided. >> + * >> + * Params: >> + * @chain - pointer to current ifpw chain >> + * @insn - kernel ipfw_insn >> + * @state - pointer to state hint >> + * >> + * Callback is OPTIONAL. >> + */ >> + void (*clear)(struct ip_fw_chain *, ipfw_insn *, void *); >> + >> + /* >> + * Performs opcode-dependent update. >> + * Flag/argument can be provided. >> + * >> + * Params: >> + * @chain - pointer to current ifpw chain >> + * @insn - kernel ipfw_insn >> + * @state - pointer to opcode-dependent data >> + * @val - opcode-dependet value >> + * >> + * Callback is OPTIONAL. >> + */ >> + void (*update)(struct ip_fw_chain *, ipfw_insn *, void *, uintptr_t); >> + >> + /* >> + * Dispatches memory relocation of given opcode, Called with WLOCK held. >> + * Actual copy is already done at the moment of call. >> + * >> + * Params: >> + * @chain - pointer to current ifpw chain >> + * @_old - kernel ipfw_insn >> + * @_old - new kernel ipfw_insn >> + * >> + * Callback is OPTIONAL. >> + */ >> + void (*move)(struct ip_fw_chain *, ipfw_insn *, ipfw_insn *); >> +}; >> + >> +/* Opcode callbacks */ >> +static int >> +convertable_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn); >> + >> +static void move_insn_if(struct ip_fw_chain *chain, ipfw_insn *_old, ipfw_insn *_new); >> +static void update_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn, >> + void *_iface_mask, uintptr_t new_id); >> +static void clear_insn_if(struct ip_fw_chain *chain, ipfw_insn *_src, void *data); >> +static int convert_insn_if(struct ip_fw_chain *chain, ipfw_insn *_old, ipfw_insn *_new, >> + void *state, int *len); >> +static int prepare_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn, void **pstate); >> +static int check_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn, int *len); >> + >> + >> +/* Note opcodes MUST be in asceding order */ >> +struct ip_fw_rewrite rewrites[] = { >> + { >> + O_RECV, >> + check_insn_if, >> + prepare_insn_if, >> + convert_insn_if, >> + clear_insn_if, >> + update_insn_if, >> + move_insn_if, >> + }, >> + { >> + O_XMIT, >> + check_insn_if, >> + prepare_insn_if, >> + convert_insn_if, >> + clear_insn_if, >> + update_insn_if, >> + move_insn_if, >> + }, >> + { >> + O_VIA, >> + check_insn_if, >> + prepare_insn_if, >> + convert_insn_if, >> + clear_insn_if, >> + update_insn_if, >> + move_insn_if, >> + }, >> +}; >> + >> +struct rewrite_rule_ptr { >> + TAILQ_ENTRY(rewrite_rule_ptr) next; >> + int cmd_klen; /* Kernel opcodes len (insns) */ >> + int cmd_len; /* Original opcodes len (insns) */ >> + ipfw_insn *kcmd; /* Kernel rule version */ >> + void **states; /* opcode states */ >> + int states_count; /* number of states */ >> + ipfw_insn cmd[1]; /* Original opcodes */ >> +}; >> +TAILQ_HEAD(rewrite_rule_head, rewrite_rule_ptr); >> + >> +struct ip_fw_rw_data { >> + struct rewrite_rule_head *hash; >> + size_t hsize; >> + int lendiff; /* sizeof(kern) - sizeof(user) */ >> +}; >> + >> +#define DEFAULT_HASH_SIZE 32 >> +#define PTR_HASH_PRIME 31 >> + >> +static struct ip_fw_rewrite *ipfw_find_rewrite(uint32_t opcode); >> + >> +void >> +ipfw_rewrite_init(struct ip_fw_chain *chain) >> +{ >> + struct ip_fw_rw_data *rwd; >> + struct rewrite_rule_head *rh; >> + int i; >> + >> + rwd = malloc(sizeof(struct ip_fw_rw_data), M_IPFW, M_WAITOK | M_ZERO); >> + >> + rwd->hsize = DEFAULT_HASH_SIZE; >> + rwd->hash = malloc(sizeof(struct rewrite_rule_head) * rwd->hsize, >> + M_IPFW, M_WAITOK | M_ZERO); >> + >> + for (i = 0, rh = rwd->hash; i < rwd->hsize; i++, rh++) >> + TAILQ_INIT(rh); >> + >> + chain->rewrite_data = rwd; >> +} >> + >> +void >> +ipfw_rewrite_free(struct ip_fw_chain *chain) >> +{ >> + struct ip_fw_rw_data *rwd; >> + >> + rwd = chain->rewrite_data; >> + chain->rewrite_data = NULL; >> + >> + /* Assume every rule to be already removed */ >> + free(rwd->hash, M_IPFW); >> + free(rwd, M_IPFW); >> +} >> + >> +int >> +ipfw_rewrite_len(struct ip_fw_chain *chain) >> +{ >> + struct ip_fw_rw_data *rwd; >> + >> + rwd = chain->rewrite_data; >> + >> + return (rwd->lendiff); >> +} >> + >> +/* >> + * Prepares given rule for modification: >> + * allocates memory for rule and number of states reported >> + * by 'check' callbacks. Calls 'prepare' callback for >> + * every opcode in rule. >> + * >> + * Returns state to be passed to ipfw_store_rule. >> + */ >> +void * >> +ipfw_prepare_rewrite(struct ip_fw_chain *chain, ipfw_insn *ucmd, >> + int cmd_len, struct ip_fw_rw_info *rwi) >> +{ >> + int i, l, cmdlen, size, states_count; >> + struct rewrite_rule_ptr *rptr; >> + ipfw_insn *cmd; >> + struct ip_fw_rewrite *rewrite; >> + void **pstate; >> + >> + /* >> + * Allocate memory for rule header, opcodes and state array. >> + */ >> + size = sizeof(struct rewrite_rule_ptr) + >> + (cmd_len - 1) * sizeof(uint32_t); >> + >> + size = roundup(size, sizeof(void *)); >> + >> + rptr = malloc(size + rwi->states * sizeof(void *), M_IPFW, >> + M_WAITOK | M_ZERO); >> + >> + /* Save original opcodes */ >> + memcpy(rptr->cmd, ucmd, cmd_len * sizeof(uint32_t)); >> + rptr->cmd_len = cmd_len; >> + rptr->cmd_klen = rptr->cmd_len + rwi->lendiff; >> + >> + rptr->states = (void **)((char *)rptr + size); >> + rptr->states_count = rwi->states; >> + pstate = rptr->states; >> + states_count = rptr->states_count; >> + >> + CTR4(KTR_NET, "Prepare rule rewrite: cmd %p len %d klen %d rptr %p", >> + ucmd, rptr->cmd_len, rptr->cmd_klen, rptr); >> + >> + for (l = cmd_len, cmd = ucmd ; >> + l > 0 ; l -= cmdlen, cmd += cmdlen) { >> + cmdlen = F_LEN(cmd); >> + >> + if ((rewrite = ipfw_find_rewrite(cmd->opcode)) == NULL) >> + continue; >> + >> + if (rewrite->prepare == NULL) >> + continue; >> + >> + i = rewrite->prepare(chain, cmd, pstate); >> + >> + if (i == STATEFUL_REWRITE) { >> + CTR3(KTR_NET, "New stateful rewrite %p val %p count %d", >> + pstate, *pstate, states_count); >> + pstate++; >> + states_count--; >> + >> + KASSERT(states_count >= 0, >> + ("prepare_rewrite state overflow")); >> + } >> + } >> + >> + return ((void *)rptr); >> +} >> + >> +static int >> +hash_ptr(struct ip_fw_rw_data *rwd, ipfw_insn *cmd) >> +{ >> + return (uintptr_t)cmd % PTR_HASH_PRIME; >> +} >> + >> +/* >> + * Fills in kernel rule with modified opcodes. Updates old rule state >> + * with new kernel pointer. Actual rewriting and header copy is done >> + * in ipfw_run_rewrite(). >> + */ >> +void >> +ipfw_perform_rewrite(struct ip_fw_chain *chain, ipfw_insn *kcmd, void *state) >> +{ >> + struct rewrite_rule_ptr *rptr; >> + struct rewrite_rule_head *rh; >> + struct ip_fw_rw_data *rwd; >> + struct ip_fw_rewrite *rewrite; >> + ipfw_insn *ucmd; >> + void **pstate; >> + int i, l, ucmdlen, kcmdlen, states_count; >> + >> + rwd = chain->rewrite_data; >> + >> + rptr = (struct rewrite_rule_ptr *)state; >> + rptr->kcmd = kcmd; >> + pstate = rptr->states; >> + states_count = rptr->states_count; >> + >> + CTR3(KTR_NET, "Linking kcmd %p to orig %p idx %d", >> + kcmd, rptr, hash_ptr(rwd, kcmd)); >> + >> + rh = &rwd->hash[hash_ptr(rwd, kcmd)]; >> + TAILQ_INSERT_TAIL(rh, rptr, next); >> + >> + ucmd = rptr->cmd; >> + >> + for (l = rptr->cmd_len; l > 0 ; >> + l -= ucmdlen, ucmd += ucmdlen, kcmd += kcmdlen) { >> + ucmdlen = F_LEN(ucmd); >> + >> + if ((rewrite = ipfw_find_rewrite(ucmd->opcode)) == NULL) { >> + /* No conversion required, copy as is */ >> + kcmdlen = ucmdlen; >> + memcpy(kcmd, ucmd, ucmdlen * sizeof(ipfw_insn)); >> + continue; >> + } >> + >> + i = rewrite->convert(chain, ucmd, kcmd, *pstate, &kcmdlen); >> + CTR2("RW for %d st %p returned %d", ucmd->cmd, *pstate, i); >> + >> + if (i == NO_REWRITE) { >> + kcmdlen = ucmdlen; >> + memcpy(kcmd, ucmd, ucmdlen * sizeof(ipfw_insn)); >> + } else if (i == STATEFUL_REWRITE) { >> + pstate++; >> + states_count--; >> + >> + KASSERT(states_count >= 0, ("rewrite state overflow")); >> + } >> + } >> + >> + /* Save size difference */ >> + rwd->lendiff += rptr->cmd_klen - rptr->cmd_len; >> + CTR2(KTR_NET, "old len: %d, new: %d", rptr->cmd_len, rptr->cmd_klen); >> +} >> + >> +/* >> + * Handle rule moving to new place (or deletion). >> + * Updates kernel rule pointer and run opcode callbacks via >> + * ipfw_move_rewrite() or clears state via ipfw_clear_rewrite() >> + * int latter case. >> + */ >> +void >> +ipfw_relocate_rewrite(struct ip_fw_chain *chain, ipfw_insn *old, ipfw_insn *new) >> +{ >> + struct rewrite_rule_ptr *rptr; >> + struct rewrite_rule_head *rh; >> + struct ip_fw_rw_data *rwd; >> + struct ip_fw_rewrite *rewrite; >> + int l, cmdlen; >> + >> + rwd = chain->rewrite_data; >> + >> + rh = &rwd->hash[hash_ptr(rwd, old)]; >> + >> + TAILQ_FOREACH(rptr, rh, next) { >> + if (rptr->kcmd == old) >> + break; >> + } >> + >> + CTR3(KTR_NET, "Moving %p idx %p to %p", rptr, hash_ptr(rwd, old), new); >> + >> + KASSERT(rptr != NULL, ("ipfw_relocate_rewrite: old rule not found")); >> + >> + TAILQ_REMOVE(rh, rptr, next); >> + >> + if (new == NULL) { >> + /* Clear states (if any) and delete original rule */ >> + for (l = rptr->cmd_klen; l > 0; l -= cmdlen, old += cmdlen) { >> + cmdlen = F_LEN(old); >> + >> + if ((rewrite = ipfw_find_rewrite(old->opcode)) == NULL) >> + continue; >> + >> + if (rewrite->clear == NULL) >> + continue; >> + >> + CTR1(KTR_NET, "clear-state for opcode %u", old->opcode); >> + rewrite->clear(chain, old, NULL); >> + } >> + >> + /* Update size difference */ >> + rwd->lendiff -= rptr->cmd_klen - rptr->cmd_len; >> + free(rptr, M_IPFW); >> + } else { >> + /* Put to new slot */ >> + rptr->kcmd = new; >> + rh = &rwd->hash[hash_ptr(rwd, new)]; >> + TAILQ_INSERT_TAIL(rh, rptr, next); >> + >> + /* Update instructions pointers */ >> + for (l = rptr->cmd_klen; l > 0 ; >> + l -= cmdlen, old += cmdlen, new += cmdlen) { >> + cmdlen = F_LEN(old); >> + >> + if ((rewrite = ipfw_find_rewrite(old->opcode)) == NULL) >> + continue; >> + >> + if (rewrite->move == NULL) >> + continue; >> + >> + rewrite->move(chain, old, new); >> + } >> + } >> +} >> + >> +/* >> + * Exports modified rule to userland. Returns userland rule length >> + * (used in initial size-checking calculations). Copies userland rule version >> + * with updated counters to supplied buffer. >> + */ >> +int >> +ipfw_export_rewrite(struct ip_fw_chain *chain, ipfw_insn *kcmd, ipfw_insn *target) >> +{ >> + struct rewrite_rule_ptr *rptr; >> + struct rewrite_rule_head *rh; >> + struct ip_fw_rw_data *rwd; >> + ipfw_insn *ucmd; >> + >> + rwd = chain->rewrite_data; >> + >> + KASSERT(rw != NULL, ("ipfw_export_rewrite: rewrite not initialized")); >> + >> + rh = &rwd->hash[hash_ptr(rwd, kcmd)]; >> + >> + TAILQ_FOREACH(rptr, rh, next) { >> + if (rptr->kcmd == kcmd) >> + break; >> + } >> + >> + KASSERT(rptr != NULL, ("ipfw_export_rewrite: kcmd not found")); >> + ucmd = rptr->cmd; >> + >> + if (target != NULL) >> + memcpy(target, rptr->cmd, rptr->cmd_len * sizeof(uint32_t)); >> + >> + return (rptr->cmd_len * sizeof(uint32_t)); >> +} >> + >> +/* >> + * bsearch() helper function. >> + */ >> +static int >> +rewrite_comp(const void *_key, const void *_member) >> +{ >> + uint32_t opcode; >> + struct ip_fw_rewrite *rewrite; >> + >> + opcode = *((uint32_t *)_key); >> + rewrite = (struct ip_fw_rewrite *)_member; >> + >> + if (opcode < rewrite->opcode) >> + return (-1); >> + else if (opcode == rewrite->opcode) >> + return (0); >> + else >> + return (1); >> +} >> + >> + >> +static struct ip_fw_rewrite * >> +ipfw_find_rewrite(uint32_t opcode) >> +{ >> + size_t count; >> + struct ip_fw_rewrite *rewrite; >> + >> + count = sizeof(rewrites) / sizeof(struct ip_fw_rewrite); >> + >> + rewrite = (struct ip_fw_rewrite *)bsearch(&opcode, rewrites, >> + count, sizeof(struct ip_fw_rewrite), rewrite_comp); >> + >> + return (rewrite); >> +} >> + >> + >> +/* >> + * Checks if given opcode needs to be changed. >> + * Updates @rwi appropriate fields if instruction needs to be >> + * stateless/stafully rewritten possibly with changed size. >> + */ >> +void >> +ipfw_check_rewrite(struct ip_fw_chain *chain, ipfw_insn *insn, >> + struct ip_fw_rw_info *rwi) >> +{ >> + struct ip_fw_rewrite *rewrite; >> + int i = 0, len = 0; >> + >> + if ((rewrite = ipfw_find_rewrite(insn->opcode)) == NULL) >> + i = NO_REWRITE; >> + else if (rewrite->check == NULL) >> + i = STATELESS_REWRITE; >> + else >> + i = rewrite->check(chain, insn, &len); >> + >> + if (len != 0) >> + rwi->lendiff += len; >> + >> + if (i == STATELESS_REWRITE) >> + rwi->count++; >> + >> + if (i == STATEFUL_REWRITE) { >> + rwi->count++; >> + rwi->states++; >> + } >> + >> + if (i != NO_REWRITE) >> + CTR4(KTR_NET, "opcode %d: count=%d states=%d len=%d", >> + insn->opcode, rwi->count, rwi->states, rwi->lendiff); >> +} >> + >> +/* >> + * Call opcode-dependent 'update' callback. >> + */ >> +void >> +ipfw_update_rewrite(struct ip_fw_chain *chain, ipfw_insn *insn, >> + void *state, uintptr_t val) >> +{ >> + struct ip_fw_rewrite *rewrite; >> + >> + if ((rewrite = ipfw_find_rewrite(insn->opcode)) == NULL) >> + return; >> + >> + if (rewrite->update == NULL) >> + return; >> + >> + rewrite->update(chain, insn, state, val); >> +} >> + >> +/******************************************************************* >> + * * >> + * O_RECV | O_VIA | O_XMIT rewrite handling. * >> + * * >> + *******************************************************************/ >> +/* >> + * Converts insns_if to more compact form. Currently instruction >> + * is used to specify >> + * 1) interface name ( ->name[0] != ('\0' | '\1') AND p.glob == 0) >> + * 2) interface pattern ( ->name[0] != ('\0' | '\1') AND p.glob != 0) >> + * 3) eXtended table number ( ->name[0] == '\1') >> + * 4) interface address ( ->name[0] == '\0') >> + * >> + * We want to save iface index in case 1 (and to eliminate interface name at all). >> + * Given that, we do the following: >> + * >> + * p.glob is now p.if_idx (u_int) (glob if zero, iface index otherwise) >> + * o.arg1 works like ->name[0], so: >> + * >> + * 1) interface name (o.arg1 == 2, p.if_idx contains index) >> + * 2) interface pattern (o.arg1 == 2, p.if_idx == 0) >> + * 3) eXtended table number (o.arg1 == 1) >> + * 4) interface address (o.arg1 == 0) >> + */ >> + >> +static int >> +convertable_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn) >> +{ >> + ipfw_insn_if *cmd = (ipfw_insn_if *)insn; >> + >> + /* Either IPv4 address or extended table (3) and (4) */ >> + if (cmd->name[0] == '\0' || cmd->name[0] == '\1') >> + return (0); >> + >> + return (1); >> +} >> + >> +static int >> +check_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn, int *len_diff) >> +{ >> + ipfw_insn_if *cmd = (ipfw_insn_if *)insn; >> + >> + *len_diff = 0; >> + >> + if (convertable_insn_if(chain, insn) == 0) >> + return (STATELESS_REWRITE); >> + >> + /* Either interface name (1) or glob pattern (2). */ >> + >> + if (cmd->p.glob != 0) >> + return (STATELESS_REWRITE); >> + else >> + return (STATEFUL_REWRITE); >> +} >> + >> +static int >> +prepare_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn, void **pstate) >> +{ >> + struct iface_mask *ifm; >> + struct ipfw_insn_ptr *insn_ptr; >> + ipfw_insn_if *cmd = (ipfw_insn_if *)insn; >> + >> + if (convertable_insn_if(chain, insn) == 0) >> + return (STATELESS_REWRITE); >> + >> + if (cmd->p.glob != 0) { >> + /* Glob pattern (2), no state needed, */ >> + return (STATELESS_REWRITE); >> + } >> + >> + /* Allocate data used by convert callback */ >> + insn_ptr = malloc(sizeof(struct ipfw_insn_ptr), M_IPFW, >> + M_WAITOK | M_ZERO); >> + ifm = malloc(sizeof(struct iface_mask), M_IPFW, M_WAITOK | M_ZERO); >> + >> + TAILQ_INIT(&ifm->instructions); >> + TAILQ_INSERT_TAIL(&ifm->instructions, insn_ptr, next); >> + >> + CTR3(KTR_NET, "pstate %p, val %p insns %p", pstate, ifm, insn); >> + >> + *pstate = ifm; >> + return (STATEFUL_REWRITE); >> +} >> + >> +static int >> +convert_insn_if(struct ip_fw_chain *chain, ipfw_insn *_old, ipfw_insn *_new, >> + void *state, int *len) >> +{ >> + struct iface_mask *ifm, *ifm2; >> + struct ipfw_insn_ptr *insn_ptr; >> + ipfw_insn_if *cmd_old = (ipfw_insn_if *)_old; >> + ipfw_insn_if *cmd_new = (ipfw_insn_if *)_new; >> + >> + /* Set length anyway */ >> + *len = F_INSN_SIZE(ipfw_insn_if); >> + memcpy(cmd_new, cmd_old, sizeof(ipfw_insn_if)); >> + >> + if (convertable_insn_if(chain, _old) == 0) { >> + /* >> + * case (3, eX table): o.arg1 = 1 >> + * case (4, ifaddr): o.arg1 = 0 >> + */ >> + >> + cmd_new->o.arg1 = (cmd_old->name[0] == '\1') ? 1 : 0; >> + >> + return (STATELESS_REWRITE); >> + } >> + >> + /* >> + * Prepare instruction for altering. >> + * case (1, ifname): o.arg1 = 2; p_if_idx == interface index >> + * case (2, glob): o.arg1 = 2' p.if_idx = 0 >> + */ >> + memcpy(cmd_new, cmd_old, sizeof(ipfw_insn_if)); >> + cmd_new->o.arg1 = 2; >> + >> + if (cmd_old->p.glob) { >> + /* Interface mask (2). Copy as is and set index */ >> + cmd_new->p.if_idx = 0; >> + return (STATELESS_REWRITE); >> + } >> + >> + /* Interface name. */ >> + ifm = (struct iface_mask *)state; >> + insn_ptr = TAILQ_FIRST(&ifm->instructions); >> + >> + insn_ptr->insn = _new; >> + >> + if ((ifm2 = ipfw_search_ifname(chain, cmd_old->name)) != NULL) { >> + /* Interface found, link entry here */ >> + TAILQ_INSERT_TAIL(&ifm2->instructions, insn_ptr, next); >> + ifm2->refcount++; >> + cmd_new->p.if_idx = ifm2->idx; >> + if (ifm2->flags & IPFW_IFLAG_FAKE) >> + cmd_new->p.if_idx |= IPFW_FAKE_IDX; >> + >> + free(ifm, M_IPFW); >> + return (STATEFUL_REWRITE); >> + } >> + >> + /* Interface not found, add and mark as unexistent */ >> + strlcpy(ifm->name, cmd_old->name, IFNAMSIZ); >> + ifm->flags |= IPFW_IFLAG_FAKE; >> + ifm->refcount++; >> + ipfw_add_ifname(chain, ifm); >> + cmd_new->p.if_idx = ifm->idx | IPFW_FAKE_IDX; >> + /* Add instruction back (add_ifname reinits list) */ >> + TAILQ_INSERT_TAIL(&ifm->instructions, insn_ptr, next); >> + >> + return (STATEFUL_REWRITE); >> +} >> + >> +static void >> +clear_insn_if(struct ip_fw_chain *chain, ipfw_insn *_src, void *data) >> +{ >> + struct iface_mask *ifm; >> + ipfw_insn_if *cmd; >> + struct ipfw_insn_ptr *insn_ptr = (struct ipfw_insn_ptr *)data; >> + >> + cmd = (ipfw_insn_if *)_src; >> + >> + /* State is used for interface names, skip other cases */ >> + if (cmd->o.arg1 != 2) >> + return; >> + >> + ifm = ipfw_search_ifindex(chain, cmd->p.if_idx); >> + KASSERT(ifm != NULL, ("no ifp found for index %u", cmd->p.if_idx)); >> + >> + if (insn_ptr == NULL) { >> + TAILQ_FOREACH(insn_ptr, &ifm->instructions, next) { >> + if (insn_ptr->insn == _src) >> + break; >> + } >> + >> + KASSERT(insn_ptr != NULL, ("no insns found")); >> + } >> + >> + /* Remove instruction from interface */ >> + TAILQ_REMOVE(&ifm->instructions, insn_ptr, next); >> + ifm->refcount--; >> + >> + free(insn_ptr, M_IPFW); >> +} >> + >> +static void >> +update_insn_if(struct ip_fw_chain *chain, ipfw_insn *insn, void *_iface_mask, >> + uintptr_t new_id) >> +{ >> + struct ip_fw_if_data *ifd; >> + ipfw_insn_if *cmd; >> + >> + IPFW_WLOCK_ASSERT(chain); >> + >> + ifd = chain->if_data; >> + cmd = (ipfw_insn_if *)insn; >> + >> + CTR2(KTR_NET, "updating insn: ifi %u -> %u", >> + cmd->p.if_idx, (uint32_t)new_id); >> + >> + cmd->p.if_idx = (uint32_t)new_id; >> +} >> + >> +static void >> +move_insn_if(struct ip_fw_chain *chain, ipfw_insn *_old, ipfw_insn *_new) >> +{ >> + struct iface_mask *ifm; >> + ipfw_insn_if *cmd; >> + struct ipfw_insn_ptr *insn_ptr; >> + >> + cmd = (ipfw_insn_if *)_old; >> + >> + /* State is used for interface names, skip other cases */ >> + if (cmd->o.arg1 != 2) >> + return; >> + >> + ifm = ipfw_search_ifindex(chain, cmd->p.if_idx); >> + KASSERT(ifm != NULL, ("no ifp found for index %u", cmd->p.if_idx)); >> + >> + TAILQ_FOREACH(insn_ptr, &ifm->instructions, next) { >> + if (insn_ptr->insn == _old) >> + break; >> + } >> + >> + KASSERT(insn_ptr != NULL, ("no insns found")); >> + >> + insn_ptr->insn = _new; >> +} >> + >> + >> --- /dev/null 2013-04-24 17:20:19.000000000 +0400 >> +++ sys/netpfil/ipfw/ip_fw_iface.c 2013-04-24 17:18:35.546357594 +0400 >> @@ -0,0 +1,467 @@ >> +/*- >> + * Copyright (c) 2013 Yandex LLC. >> + * Author: Alexander V. Chernikov >> + * >> + * Redistribution and use in source and binary forms, with or without >> + * modification, are permitted provided that the following conditions >> + * are met: >> + * 1. Redistributions of source code must retain the above copyright >> + * notice, this list of conditions and the following disclaimer. >> + * 2. Redistributions in binary form must reproduce the above copyright >> + * notice, this list of conditions and the following disclaimer in the >> + * documentation and/or other materials provided with the distribution. >> + * >> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND >> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >> + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE >> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS >> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT >> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY >> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF >> + * SUCH DAMAGE. >> + */ >> + >> +#include >> +__FBSDID("$FreeBSD$"); >> + >> +/* >> + * Interface tracking for ipfw. >> + */ >> + >> +#include "opt_ipfw.h" >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +#include >> +#include /* hooks */ >> +#include >> + >> +#include >> +#include >> + >> +#define IPFW_IFHASH_IDX(idx, hsize) ((idx) % (hsize)) >> +#define IPFW_IFHASH_NAME(name, hsize) (fnv_32_str(name, FNV1_32_INIT) % (hsize)) >> + >> +TAILQ_HEAD(iface_mask_head, iface_mask); >> + >> +struct ip_fw_if_data { >> + struct iface_mask_head *masks; /* Interface name hash */ >> + size_t masks_count, masks_hsize; >> + struct iface_mask_head *real_ifaces; /* 'Real' interface index hash */ >> + size_t real_count, real_hsize; >> + struct iface_mask_head *fake_ifaces; /* Nonexistent interface index hash */ >> + size_t fake_count, fake_hsize; >> + eventhandler_tag arrival, departure; >> + u_short fake_idx; >> +}; >> + >> +static void ipfw_ifhash_init_int(struct iface_mask_head **phash, size_t hsize); >> +static void ipfw_ifnet_init(struct ip_fw_chain *chain, struct iface_mask *ifm); >> + >> +/* >> + * Mappings: >> + * 'iface_mask' -> idx >> + * if_index -> iface_mask >> + * fake_index -> iface_mask >> + * >> + * List of masks >> + * >> + */ >> +static void ifnet_arrival(void *arg, struct ifnet *ifp); >> +static void ifnet_departure(void *arg, struct ifnet *ifp); >> + >> +/* >> + * Find interface structure by name. >> + * Called with either UH or chain readlock held. >> + */ >> +struct iface_mask * >> +ipfw_search_ifname(struct ip_fw_chain *chain, char *name) >> +{ >> + struct iface_mask *ifm; >> + struct ip_fw_if_data *ifd; >> + struct iface_mask_head *ifh; >> + int i; >> + >> + ifd = chain->if_data; >> + >> + i = IPFW_IFHASH_NAME(name, ifd->masks_hsize); >> + >> + ifh = &ifd->masks[i]; >> + TAILQ_FOREACH(ifm, ifh, name_next) { >> + if (strcmp(name, ifm->name) == 0) >> + return (ifm); >> + } >> + >> + return (NULL); >> +} >> + >> +/* >> + * Find interface structure by real or fake ifindex. >> + * Called with either UH or chain readlock held. >> + */ >> +struct iface_mask * >> +ipfw_search_ifindex(struct ip_fw_chain *chain, uint32_t idx) >> +{ >> + struct iface_mask *ifm; >> + struct ip_fw_if_data *ifd; >> + struct iface_mask_head *ifh; >> + int i; >> + >> + ifd = chain->if_data; >> + >> + if (idx & IPFW_FAKE_IDX) { >> + idx &= ~IPFW_FAKE_IDX; >> + i = IPFW_IFHASH_IDX(idx, ifd->fake_hsize); >> + ifh = &ifd->fake_ifaces[i]; >> + } else { >> + i = IPFW_IFHASH_IDX(idx, ifd->real_hsize); >> + ifh = &ifd->real_ifaces[i]; >> + } >> + >> + TAILQ_FOREACH(ifm, ifh, idx_next) { >> + if (ifm->idx == idx) >> + return (ifm); >> + } >> + >> + return (NULL); >> +} >> + >> +void >> +ipfw_add_ifname(struct ip_fw_chain *chain, struct iface_mask *ifm) >> +{ >> + struct ip_fw_if_data *ifd; >> + struct iface_mask_head *ifh; >> + struct iface_mask *iftemp; >> + int i; >> + >> + ifd = chain->if_data; >> + >> + ipfw_ifnet_init(chain, ifm); >> + >> + /* Add to named hash */ >> + i = IPFW_IFHASH_NAME(ifm->name, ifd->masks_hsize); >> + ifh = &ifd->masks[i]; >> + TAILQ_INSERT_TAIL(ifh, ifm, name_next); >> + >> + if (ifm->flags & IPFW_IFLAG_FAKE) { >> + /* Add to fake interfaces hash */ >> + ifm->idx = ++ifd->fake_idx; >> + i = IPFW_IFHASH_IDX(ifm->idx, ifd->fake_hsize); >> + ifh = &ifd->fake_ifaces[i]; >> + } else { >> + /* Add to real interfaces hash */ >> + i = IPFW_IFHASH_IDX(ifm->idx, ifd->real_hsize); >> + ifh = &ifd->real_ifaces[i]; >> + >> + /* Check index for consistency */ >> + TAILQ_FOREACH(iftemp, ifh, idx_next) { >> + KASSERT(iftemp->idx != ifm->idx, >> + ("Non-fake if %s w idx %d found (%s)!", >> + iftemp->name, ifm->idx, ifm->name)); >> + } >> + } >> + >> + TAILQ_INSERT_TAIL(ifh, ifm, idx_next); >> +} >> + >> +static void >> +ifnet_arrival(void *arg, struct ifnet *ifp) >> +{ >> + struct ip_fw_chain *chain = (struct ip_fw_chain *)arg; >> + struct ip_fw_if_data *ifd; >> + struct iface_mask *iftemp, *ifm; >> + struct iface_mask_head *ifh; >> + struct ipfw_insn_ptr *insn_ptr; >> + int i; >> + >> + iftemp = malloc(sizeof(struct iface_mask), M_IPFW, M_WAITOK | M_ZERO); >> + >> + iftemp->ifp = ifp; >> + iftemp->idx = ifp->if_index; >> + strlcpy(iftemp->name, ifp->if_xname, IFNAMSIZ); >> + >> + IPFW_UH_WLOCK(chain); >> + IPFW_WLOCK(chain); >> + >> + ifd = chain->if_data; >> + >> + if (ifd == NULL || ifd->arrival == NULL) { >> + /* We're shutting down */ >> + IPFW_WUNLOCK(chain); >> + IPFW_UH_WUNLOCK(chain); >> + free(iftemp, M_IPFW); >> + return; >> + } >> + >> + ifm = ipfw_search_ifname(chain, iftemp->name); >> + >> + if (ifm != NULL) { >> + /* Found. Let's update index */ >> + KASSERT(ifm->flags & IPFW_IFLAG_FAKE, >> + ("Non-fake interface found for %s", ifm->name)); >> + >> + ifm->flags &= ~IPFW_IFLAG_FAKE; >> + /* Relink to real index */ >> + i = IPFW_IFHASH_IDX(ifm->idx, ifd->fake_hsize); >> + ifh = &ifd->fake_ifaces[i]; >> + TAILQ_REMOVE(ifh, ifm, idx_next); >> + >> + i = IPFW_IFHASH_IDX(iftemp->idx, ifd->real_hsize); >> + ifh = &ifd->real_ifaces[i]; >> + TAILQ_INSERT_TAIL(ifh, ifm, idx_next); >> + >> + CTR2(KTR_NET, "ifnet upgrade: fake %u -> %u", ifm->idx, >> + iftemp->idx); >> + /* Notify consumers */ >> + TAILQ_FOREACH(insn_ptr, &ifm->instructions, next) >> + ipfw_update_rewrite(chain, insn_ptr->insn, ifm, >> + (uintptr_t)iftemp->idx); >> + >> + ifm->idx = iftemp->idx; >> + } else { >> + /* Not found. Add to list */ >> + ifm = iftemp; >> + iftemp = NULL; >> + >> + ipfw_ifnet_init(chain, ifm); >> + >> + CTR2(KTR_NET, "ifmp=%p uc=%u", ifm, ifm->refcount); >> + >> + /* Add to named hash */ >> + i = IPFW_IFHASH_NAME(ifm->name, ifd->masks_hsize); >> + ifh = &ifd->masks[i]; >> + TAILQ_INSERT_TAIL(ifh, ifm, name_next); >> + >> + /* Add to real interfaces hash */ >> + i = IPFW_IFHASH_IDX(ifm->idx, ifd->real_hsize); >> + ifh = &ifd->real_ifaces[i]; >> + >> + /* Check index for consistency */ >> + TAILQ_FOREACH(iftemp, ifh, idx_next) { >> + KASSERT(iftemp->idx != ifm->idx, >> + ("Non-fake if %s w idx %d found (%s)!", >> + iftemp->name, ifm->idx, ifm->name)); >> + } >> + >> + TAILQ_INSERT_TAIL(ifh, ifm, idx_next); >> + >> + CTR3(KTR_NET, "new iface %p, idx %u uc=%u", ifm->name, >> + ifm->idx, ifm->refcount); >> + } >> + IPFW_WUNLOCK(chain); >> + IPFW_UH_WUNLOCK(chain); >> + >> + if (iftemp != NULL) >> + free(iftemp, M_IPFW); >> +} >> + >> +static void >> +ifnet_departure(void *arg, struct ifnet *ifp) >> +{ >> + struct ip_fw_chain *chain = (struct ip_fw_chain *)arg; >> + struct ip_fw_if_data *ifd; >> + struct iface_mask *ifm; >> + struct iface_mask_head *ifh; >> + struct ipfw_insn_ptr *insn_ptr; >> + int i; >> + >> + IPFW_UH_WLOCK(chain); >> + IPFW_WLOCK(chain); >> + >> + if ((ifd = chain->if_data) == NULL) { >> + /* We're shutting down */ >> + IPFW_WUNLOCK(chain); >> + IPFW_UH_WUNLOCK(chain); >> + return; >> + } >> + >> + ifm = ipfw_search_ifname(chain, ifp->if_xname); >> + >> + if (ifm == NULL) { >> + IPFW_WUNLOCK(chain); >> + IPFW_UH_WUNLOCK(chain); >> + printf("ipfw: unknown iface %s departure\n", ifp->if_xname); >> + return; >> + } >> + >> + KASSERT((ifm->flags & IPFW_IFLAG_FAKE) == 0, >> + ("Fake interface found for %s", ifm->name)); >> + >> + /* Check if we need to save given interface. */ >> + if (ifm->refcount == 0) { >> + CTR1(KTR_NET, "Deleting interface %p", ifm); >> + /* Delete from name hash */ >> + i = IPFW_IFHASH_NAME(ifm->name, ifd->masks_hsize); >> + ifh = &ifd->masks[i]; >> + TAILQ_REMOVE(ifh, ifm, name_next); >> + >> + /* Delete from real iface hash */ >> + i = IPFW_IFHASH_IDX(ifm->idx, ifd->real_hsize); >> + ifh = &ifd->real_ifaces[i]; >> + TAILQ_REMOVE(ifh, ifm, idx_next); >> + >> + IPFW_WUNLOCK(chain); >> + IPFW_UH_WUNLOCK(chain); >> + >> + free(ifm, M_IPFW); >> + return; >> + } >> + >> + CTR1(KTR_NET, "Interface uc=%u", ifm->refcount); >> + >> + /* Interface is used. Move to fake hash */ >> + ifm->flags |= IPFW_IFLAG_FAKE; >> + /* Relink to fake index */ >> + i = IPFW_IFHASH_IDX(ifm->idx, ifd->real_hsize); >> + ifh = &ifd->real_ifaces[i]; >> + TAILQ_REMOVE(ifh, ifm, idx_next); >> + >> + /* Alloc fake index */ >> + ifd->fake_idx++; >> + i = IPFW_IFHASH_IDX(ifd->fake_idx, ifd->fake_hsize); >> + ifh = &ifd->fake_ifaces[i]; >> + TAILQ_INSERT_TAIL(ifh, ifm, idx_next); >> + >> + CTR2(KTR_NET, "Interface %p departure, fake index %u", >> + ifm, ifd->fake_idx); >> + >> + /* Notify consumers */ >> + TAILQ_FOREACH(insn_ptr, &ifm->instructions, next) >> + ipfw_update_rewrite(chain, insn_ptr->insn, ifm, >> + (uintptr_t)(ifd->fake_idx | IPFW_FAKE_IDX)); >> + >> + ifm->idx = ifd->fake_idx; >> + >> + IPFW_WUNLOCK(chain); >> + IPFW_UH_WUNLOCK(chain); >> +} >> + >> +static void >> +ipfw_ifnet_init(struct ip_fw_chain *chain, struct iface_mask *ifm) >> +{ >> + >> + TAILQ_INIT(&ifm->instructions); >> +} >> + >> + >> +static void >> +ipfw_ifhash_init_int(struct iface_mask_head **phash, size_t hsize) >> +{ >> + struct iface_mask_head *ifh; >> + int i; >> + >> + ifh = malloc(sizeof(struct iface_mask_head) * hsize, M_IPFW, >> + M_WAITOK | M_ZERO); >> + >> + *phash = ifh; >> + >> + for (i = 0; i < hsize; i++, ifh++) >> + TAILQ_INIT(ifh); >> +} >> + >> +void >> +ipfw_ifhash_init(struct ip_fw_chain *chain) >> +{ >> + struct ip_fw_if_data *ifd; >> + struct iface_mask_head *ifh; >> + struct iface_mask *ifm; >> + struct ifnet *ifp; >> + int i; >> + >> + ifd = malloc(sizeof(struct ip_fw_if_data), M_IPFW, M_WAITOK | M_ZERO); >> + chain->if_data = ifd; >> + >> + ifd->masks_hsize = ifd->real_hsize = ifd->fake_hsize = 32; >> + >> + ipfw_ifhash_init_int(&ifd->masks, ifd->masks_hsize); >> + ipfw_ifhash_init_int(&ifd->real_ifaces, ifd->fake_hsize); >> + ipfw_ifhash_init_int(&ifd->fake_ifaces, ifd->real_hsize); >> + >> + IFNET_RLOCK(); >> + TAILQ_FOREACH(ifp, &V_ifnet, if_link) { >> + ifm = malloc(sizeof(struct iface_mask), M_IPFW, M_WAITOK | M_ZERO); >> + strlcpy(ifm->name, ifp->if_xname, IFNAMSIZ); >> + ifm->ifp = ifp; >> + ifm->idx = ifp->if_index; >> + >> + ipfw_ifnet_init(chain, ifm); >> + >> + i = IPFW_IFHASH_IDX(ifm->idx, ifd->real_hsize); >> + ifh = &ifd->real_ifaces[i]; >> + TAILQ_INSERT_TAIL(ifh, ifm, idx_next); >> + >> + i = IPFW_IFHASH_NAME(ifm->name, ifd->masks_hsize); >> + ifh = &ifd->masks[i]; >> + TAILQ_INSERT_TAIL(ifh, ifm, name_next); >> + >> + CTR2(KTR_NET, "init iface %p idx %u", ifm, ifm->idx); >> + >> + } >> + IFNET_RUNLOCK(); >> + >> + /* XXX: there is a gap between RUNLOCK and interface registration */ >> + >> + ifd->arrival = EVENTHANDLER_REGISTER(ifnet_arrival_event, >> + ifnet_arrival, chain, EVENTHANDLER_PRI_ANY); >> + >> + ifd->departure = EVENTHANDLER_REGISTER(ifnet_departure_event, >> + ifnet_departure, chain, EVENTHANDLER_PRI_ANY); >> +} >> + >> +void >> +ipfw_ifhash_detach(struct ip_fw_chain *chain) >> +{ >> + struct ip_fw_if_data *ifd; >> + >> + ifd = chain->if_data; >> + >> + EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ifd->arrival); >> + EVENTHANDLER_DEREGISTER(ifnet_departure_event, ifd->departure); >> + >> + ifd->arrival = NULL; >> + ifd->departure = NULL; >> +} >> + >> + >> +void >> +ipfw_ifhash_free(struct ip_fw_chain *chain) >> +{ >> + struct ip_fw_if_data *ifd; >> + struct iface_mask_head *ifh; >> + struct iface_mask *ifm, *ifm_next; >> + int i; >> + >> + ifd = chain->if_data; >> + chain->if_data = NULL; >> + >> + ifh = ifd->masks; >> + >> + for (i = 0; i < ifd->masks_hsize; i++, ifh++) { >> + TAILQ_FOREACH_SAFE(ifm, ifh, name_next, ifm_next) { >> + /* >> + * Assume every consumer to free its >> + * iface-specific data beforehand. >> + */ >> + free(ifm, M_IPFW); >> + } >> + } >> + >> + free(ifd->masks, M_IPFW); >> + free(ifd->real_ifaces, M_IPFW); >> + free(ifd->fake_ifaces, M_IPFW); >> + >> + free(ifd, M_IPFW); >> +} >> + >> --- /dev/null 2013-04-24 17:22:00.000000000 +0400 >> +++ sys/netpfil/ipfw/ip_fw_iface.h 2013-04-22 19:09:56.624996491 +0400 >> @@ -0,0 +1,55 @@ >> +/*- >> + * Copyright (c) 2013 Yandex LLC. >> + * >> + * Redistribution and use in source and binary forms, with or without >> + * modification, are permitted provided that the following conditions >> + * are met: >> + * 1. Redistributions of source code must retain the above copyright >> + * notice, this list of conditions and the following disclaimer. >> + * 2. Redistributions in binary form must reproduce the above copyright >> + * notice, this list of conditions and the following disclaimer in the >> + * documentation and/or other materials provided with the distribution. >> + * >> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND >> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >> + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE >> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL >> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS >> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT >> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY >> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF >> + * SUCH DAMAGE. >> + * >> + * $FreeBSD$ >> + */ >> + >> +#ifndef _IP_FW_IFACE_H_ >> +#define _IP_FW_IFACE_H_ >> + >> +struct ipfw_insn_ptr { >> + TAILQ_ENTRY(ipfw_insn_ptr) next; >> + ipfw_insn *insn; >> +}; >> + >> +struct iface_mask { >> + struct ifnet *ifp; >> + uint32_t idx; /* Saved interface index */ >> + uint32_t flags; /* Pad */ >> + uint32_t refcount; /* Usage count */ >> + char name[IFNAMSIZ]; /* Interface/mask */ >> + TAILQ_ENTRY(iface_mask) idx_next; >> + TAILQ_ENTRY(iface_mask) name_next; >> + TAILQ_HEAD(rule_list, ipfw_insn_ptr) instructions; /* instructions using given mask */ >> +}; >> +#define IPFW_IFLAG_FAKE 0x01 >> + >> +#define IPFW_FAKE_IDX (1 << 31) >> + >> +struct iface_mask *ipfw_search_ifname(struct ip_fw_chain *chain, char *name); >> +struct iface_mask *ipfw_search_ifindex(struct ip_fw_chain *chain, uint32_t idx); >> +void ipfw_add_ifname(struct ip_fw_chain *chain, struct iface_mask *ifm); >> + >> +#endif >> + >> > _______________________________________________ > freebsd-ipfw@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-ipfw > To unsubscribe, send any mail to "freebsd-ipfw-unsubscribe@freebsd.org" > From owner-freebsd-ipfw@FreeBSD.ORG Wed Apr 24 18:40:01 2013 Return-Path: Delivered-To: freebsd-ipfw@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 3FFC7DAB for ; Wed, 24 Apr 2013 18:40:01 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 329B115E2 for ; Wed, 24 Apr 2013 18:40:01 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3OIe19p069711 for ; Wed, 24 Apr 2013 18:40:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3OIe1AR069710; Wed, 24 Apr 2013 18:40:01 GMT (envelope-from gnats) Date: Wed, 24 Apr 2013 18:40:01 GMT Message-Id: <201304241840.r3OIe1AR069710@freefall.freebsd.org> To: freebsd-ipfw@FreeBSD.org Cc: From: dfilter@FreeBSD.ORG (dfilter service) Subject: Re: kern/157796: commit references a PR X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: dfilter service List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Apr 2013 18:40:01 -0000 The following reply was made to PR kern/157796; it has been noted by GNATS. From: dfilter@FreeBSD.ORG (dfilter service) To: bug-followup@FreeBSD.org Cc: Subject: Re: kern/157796: commit references a PR Date: Wed, 24 Apr 2013 18:30:40 +0000 (UTC) Author: rrs Date: Wed Apr 24 18:30:32 2013 New Revision: 249848 URL: http://svnweb.freebsd.org/changeset/base/249848 Log: This fixes the issue with the "randomly changing" default route. What it was is there are two places in ip_output.c where we do a goto again. One place was fine, it copies out the new address and then resets dst = ro->rt_dst; But the other place does *not* do that, which means earlier when we found the gateway, we have dst pointing there aka dst = ro->rt_gateway is done.. then we do a goto again.. bam now we clobber the default route. The fix is just to move the again so we are always doing dst = &ro->rt_dst; in the again loop. PR: 174749,157796 MFC after: 1 week Modified: head/sys/netinet/ip_output.c Modified: head/sys/netinet/ip_output.c ============================================================================== --- head/sys/netinet/ip_output.c Wed Apr 24 18:00:28 2013 (r249847) +++ head/sys/netinet/ip_output.c Wed Apr 24 18:30:32 2013 (r249848) @@ -196,8 +196,8 @@ ip_output(struct mbuf *m, struct mbuf *o hlen = ip->ip_hl << 2; } - dst = (struct sockaddr_in *)&ro->ro_dst; again: + dst = (struct sockaddr_in *)&ro->ro_dst; ia = NULL; /* * If there is a cached route, _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" From owner-freebsd-ipfw@FreeBSD.ORG Wed Apr 24 18:40:02 2013 Return-Path: Delivered-To: freebsd-ipfw@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 456FFDAC for ; Wed, 24 Apr 2013 18:40:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 38B7515E3 for ; Wed, 24 Apr 2013 18:40:02 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3OIe2rk069717 for ; Wed, 24 Apr 2013 18:40:02 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3OIe2bT069716; Wed, 24 Apr 2013 18:40:02 GMT (envelope-from gnats) Date: Wed, 24 Apr 2013 18:40:02 GMT Message-Id: <201304241840.r3OIe2bT069716@freefall.freebsd.org> To: freebsd-ipfw@FreeBSD.org Cc: From: dfilter@FreeBSD.ORG (dfilter service) Subject: Re: kern/174749: commit references a PR X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: dfilter service List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Apr 2013 18:40:02 -0000 The following reply was made to PR kern/174749; it has been noted by GNATS. From: dfilter@FreeBSD.ORG (dfilter service) To: bug-followup@FreeBSD.org Cc: Subject: Re: kern/174749: commit references a PR Date: Wed, 24 Apr 2013 18:30:39 +0000 (UTC) Author: rrs Date: Wed Apr 24 18:30:32 2013 New Revision: 249848 URL: http://svnweb.freebsd.org/changeset/base/249848 Log: This fixes the issue with the "randomly changing" default route. What it was is there are two places in ip_output.c where we do a goto again. One place was fine, it copies out the new address and then resets dst = ro->rt_dst; But the other place does *not* do that, which means earlier when we found the gateway, we have dst pointing there aka dst = ro->rt_gateway is done.. then we do a goto again.. bam now we clobber the default route. The fix is just to move the again so we are always doing dst = &ro->rt_dst; in the again loop. PR: 174749,157796 MFC after: 1 week Modified: head/sys/netinet/ip_output.c Modified: head/sys/netinet/ip_output.c ============================================================================== --- head/sys/netinet/ip_output.c Wed Apr 24 18:00:28 2013 (r249847) +++ head/sys/netinet/ip_output.c Wed Apr 24 18:30:32 2013 (r249848) @@ -196,8 +196,8 @@ ip_output(struct mbuf *m, struct mbuf *o hlen = ip->ip_hl << 2; } - dst = (struct sockaddr_in *)&ro->ro_dst; again: + dst = (struct sockaddr_in *)&ro->ro_dst; ia = NULL; /* * If there is a cached route, _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" From owner-freebsd-ipfw@FreeBSD.ORG Wed Apr 24 19:07:38 2013 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 15011BBC; Wed, 24 Apr 2013 19:07:38 +0000 (UTC) (envelope-from luigi@onelab2.iet.unipi.it) Received: from onelab2.iet.unipi.it (onelab2.iet.unipi.it [131.114.59.238]) by mx1.freebsd.org (Postfix) with ESMTP id CD97E1787; Wed, 24 Apr 2013 19:07:37 +0000 (UTC) Received: by onelab2.iet.unipi.it (Postfix, from userid 275) id 523CF7300A; Wed, 24 Apr 2013 21:09:30 +0200 (CEST) Date: Wed, 24 Apr 2013 21:09:30 +0200 From: Luigi Rizzo To: "Alexander V. Chernikov" Subject: Re: [patch] ipfw interface tracking and opcode rewriting Message-ID: <20130424190930.GA10395@onelab2.iet.unipi.it> References: <517801D3.5040502@FreeBSD.org> <20130424162349.GA8439@onelab2.iet.unipi.it> <51780C49.7000204@FreeBSD.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <51780C49.7000204@FreeBSD.org> User-Agent: Mutt/1.5.20 (2009-06-14) Cc: freebsd-ipfw@freebsd.org, luigi@freebsd.org X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Apr 2013 19:07:38 -0000 On Wed, Apr 24, 2013 at 08:46:01PM +0400, Alexander V. Chernikov wrote: > On 24.04.2013 20:23, Luigi Rizzo wrote: ... > >> vesrion) in the middle of the next week. > > hmmm.... this is quite a large change, and from the description it > > is a bit unclear to me how the "opcode rewriting" thing relates to > > the use of strings vs index for name matching. > sorry, I havent't describe this explicitly. > Index matching is done via storing interface index in in p.glob field of > ipfw_insn_if instruction. understood. the reasons why i did not use the index is that one could specify a non-existing interface name, and also interfaces can be renamed. If you want to use indexses, you should add (perhaps you do, i haven't checked) hooks to the interface add/rename/delete code in order to update the ruleset upon changes on the if list, and it seemed to me a bad idea to add this dependency (lockingwise, too). Really, with 16-byte fixed size interface names, the match is as simple as this: #if CAN_DO_FAST_MATCH && IFNAMSIZ == 16 /* archs with no align requirements */ { uint64_t *a = (uint64_t *)ifp->if_xname; uint64_t *b = (uint64_t *)cmd->name; if (a[0] == b[0] && a[1] == b[1]) return 1; } #else if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0) return 1 #endif (assuming the names are zero-padded, which should be the case already). Since you have the measurement infrastructure in place, perhaps you have an easy way to try this patch and see how effective it is in terms of performance. > > Additionally, i wonder if there isn't a better way to replace strncmp > > with some two 64-bit comparisons (the name is 16 bytes) by making > > sure that the fields are zero-padded and suitably aligned. > > At this point, on the machines you care about (able to sustain > > 1+ Mpps) the two comparison should have the same cost as > > the index comparison, without the need to track update in the names. > Well, actually I'm thinking of the next 2 steps: > 1) making kernel rule header more compact (20 bytes instead of 48) and > making it invisible for userland. > This involves rule counters to be stored separately (and possibly as > pcpu-based ones). > 2) since ruleset is now nearly readonly and more or less compact we can > try to store it in > contiguous address space to optimize cache line usage. certainly a worthwhile goal (also using gleb's new counters) but i suspect that compacting rules are a second order effect. I a bit skeptical they make a big difference on the in-kernel version of ipfw. You might see some difference in the userspace version, which runs on top of netmap. cheers luigi From owner-freebsd-ipfw@FreeBSD.ORG Wed Apr 24 19:51:38 2013 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id DD38A8FA; Wed, 24 Apr 2013 19:51:38 +0000 (UTC) (envelope-from melifaro@FreeBSD.org) Received: from mail.ipfw.ru (unknown [IPv6:2a01:4f8:120:6141::2]) by mx1.freebsd.org (Postfix) with ESMTP id A317D1AF6; Wed, 24 Apr 2013 19:51:38 +0000 (UTC) Received: from dhcp170-36-red.yandex.net ([95.108.170.36]) by mail.ipfw.ru with esmtpsa (TLSv1:CAMELLIA256-SHA:256) (Exim 4.76 (FreeBSD)) (envelope-from ) id 1UV5mT-000A67-I5; Wed, 24 Apr 2013 23:55:05 +0400 Message-ID: <51783798.4020004@FreeBSD.org> Date: Wed, 24 Apr 2013 23:50:48 +0400 From: "Alexander V. Chernikov" User-Agent: Mozilla/5.0 (X11; FreeBSD amd64; rv:17.0) Gecko/20130418 Thunderbird/17.0.5 MIME-Version: 1.0 To: Luigi Rizzo Subject: Re: [patch] ipfw interface tracking and opcode rewriting References: <517801D3.5040502@FreeBSD.org> <20130424162349.GA8439@onelab2.iet.unipi.it> <51780C49.7000204@FreeBSD.org> <20130424190930.GA10395@onelab2.iet.unipi.it> In-Reply-To: <20130424190930.GA10395@onelab2.iet.unipi.it> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: freebsd-ipfw@freebsd.org, luigi@freebsd.org X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Apr 2013 19:51:38 -0000 On 24.04.2013 23:09, Luigi Rizzo wrote: > On Wed, Apr 24, 2013 at 08:46:01PM +0400, Alexander V. Chernikov wrote: >> On 24.04.2013 20:23, Luigi Rizzo wrote: > ... >>>> vesrion) in the middle of the next week. >>> hmmm.... this is quite a large change, and from the description it >>> is a bit unclear to me how the "opcode rewriting" thing relates to >>> the use of strings vs index for name matching. >> sorry, I havent't describe this explicitly. >> Index matching is done via storing interface index in in p.glob field of >> ipfw_insn_if instruction. > understood. the reasons why i did not use the index is that > one could specify a non-existing interface name, and also interfaces > can be renamed. If you want to use indexses, you should add > (perhaps you do, i haven't checked) Yes, this is done (without 'good' renaming handling), but still. > hooks to the interface add/rename/delete code in order to > update the ruleset upon changes on the if list, and it > seemed to me a bad idea to add this dependency > (lockingwise, too). > > Really, with 16-byte fixed size interface names, the match > is as simple as this: > > #if CAN_DO_FAST_MATCH && IFNAMSIZ == 16 /* archs with no align requirements */ > { > uint64_t *a = (uint64_t *)ifp->if_xname; > uint64_t *b = (uint64_t *)cmd->name; > if (a[0] == b[0] && a[1] == b[1]) > return 1; > } > #else > if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0) > return 1 > #endif > > (assuming the names are zero-padded, which should be the case already). > Since you have the measurement infrastructure in place, perhaps > you have an easy way to try this patch and see how effective > it is in terms of performance. I'll try this tomorrow, thanks. > >>> Additionally, i wonder if there isn't a better way to replace strncmp >>> with some two 64-bit comparisons (the name is 16 bytes) by making >>> sure that the fields are zero-padded and suitably aligned. >>> At this point, on the machines you care about (able to sustain >>> 1+ Mpps) the two comparison should have the same cost as >>> the index comparison, without the need to track update in the names. >> Well, actually I'm thinking of the next 2 steps: >> 1) making kernel rule header more compact (20 bytes instead of 48) and >> making it invisible for userland. >> This involves rule counters to be stored separately (and possibly as >> pcpu-based ones). >> 2) since ruleset is now nearly readonly and more or less compact we can >> try to store it in >> contiguous address space to optimize cache line usage. > certainly a worthwhile goal (also using gleb's new counters) > but i suspect that compacting rules are a second order effect. > I a bit skeptical they make a big difference on the in-kernel > version of ipfw. You might see some difference in the My current numbers are ~5mpps of IPv4 forwarding with ipfw turned on (1 rule) for vlans over ixgbe, with 60% cpu usage (2xE5646). For lagg with 2x ixgbe it is ~7mpps with the same 60% usage. (And, say, 70% of CPU usage on our production is ipfw, despite low number of rules). > userspace version, which runs on top of netmap. We are preparing to move forward in this direction (and thinking of 20-30mpps as our goal). (And I hope some changes of kernel-based version can migrate to userland one :)) > > cheers > luigi > From owner-freebsd-ipfw@FreeBSD.ORG Wed Apr 24 20:21:16 2013 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 00110490; Wed, 24 Apr 2013 20:21:15 +0000 (UTC) (envelope-from luigi@onelab2.iet.unipi.it) Received: from onelab2.iet.unipi.it (onelab2.iet.unipi.it [131.114.59.238]) by mx1.freebsd.org (Postfix) with ESMTP id B7B781CD9; Wed, 24 Apr 2013 20:21:15 +0000 (UTC) Received: by onelab2.iet.unipi.it (Postfix, from userid 275) id 5CA8B7300A; Wed, 24 Apr 2013 22:23:08 +0200 (CEST) Date: Wed, 24 Apr 2013 22:23:08 +0200 From: Luigi Rizzo To: "Alexander V. Chernikov" Subject: Re: [patch] ipfw interface tracking and opcode rewriting Message-ID: <20130424202308.GA11146@onelab2.iet.unipi.it> References: <517801D3.5040502@FreeBSD.org> <20130424162349.GA8439@onelab2.iet.unipi.it> <51780C49.7000204@FreeBSD.org> <20130424190930.GA10395@onelab2.iet.unipi.it> <51783798.4020004@FreeBSD.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <51783798.4020004@FreeBSD.org> User-Agent: Mutt/1.5.20 (2009-06-14) Cc: freebsd-ipfw@freebsd.org, luigi@freebsd.org X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 24 Apr 2013 20:21:16 -0000 On Wed, Apr 24, 2013 at 11:50:48PM +0400, Alexander V. Chernikov wrote: > On 24.04.2013 23:09, Luigi Rizzo wrote: > > On Wed, Apr 24, 2013 at 08:46:01PM +0400, Alexander V. Chernikov wrote: > >> On 24.04.2013 20:23, Luigi Rizzo wrote: ... > >> Well, actually I'm thinking of the next 2 steps: > >> 1) making kernel rule header more compact (20 bytes instead of 48) and > >> making it invisible for userland. > >> This involves rule counters to be stored separately (and possibly as > >> pcpu-based ones). > >> 2) since ruleset is now nearly readonly and more or less compact we can > >> try to store it in > >> contiguous address space to optimize cache line usage. > > certainly a worthwhile goal (also using gleb's new counters) > > but i suspect that compacting rules are a second order effect. > > I a bit skeptical they make a big difference on the in-kernel > > version of ipfw. You might see some difference in the > My current numbers are ~5mpps of IPv4 forwarding with ipfw turned on (1 > rule) for vlans over ixgbe, with 60% cpu usage (2xE5646). yes, but that means about 1mpps per core. the userspace version, i have been told, reached 14.2mpps with one core when running on netmap interfaces (single rule). So the impact of 20-30ns per rule is much higher in the second case. Speaking of which -- it would be better to report performance in terms of ns per packet (or per rule), rather than Mpps, because it is much easier to compare results. Saying "20% better" or "300Kpps more" requires a lot more context to understand how much things improved. > For lagg with 2x ixgbe it is ~7mpps with the same 60% usage. > (And, say, 70% of CPU usage on our production is ipfw, despite low > number of rules). > > userspace version, which runs on top of netmap. > We are preparing to move forward in this direction (and thinking of > 20-30mpps as our goal). > (And I hope some changes of kernel-based version can migrate to userland > one :)) yes, my goal is to have a single source tree that builds both in kernel and userspace. The diffs are very small, I just have a little bit of glue code to hook the packet path and the control socket. cheers luigi From owner-freebsd-ipfw@FreeBSD.ORG Thu Apr 25 11:30:01 2013 Return-Path: Delivered-To: freebsd-ipfw@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 36675B6B for ; Thu, 25 Apr 2013 11:30:01 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 296BD1EB0 for ; Thu, 25 Apr 2013 11:30:01 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3PBU193078276 for ; Thu, 25 Apr 2013 11:30:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3PBU06e078275; Thu, 25 Apr 2013 11:30:00 GMT (envelope-from gnats) Date: Thu, 25 Apr 2013 11:30:00 GMT Message-Id: <201304251130.r3PBU06e078275@freefall.freebsd.org> To: freebsd-ipfw@FreeBSD.org Cc: From: dfilter@FreeBSD.ORG (dfilter service) Subject: Re: kern/157796: commit references a PR X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: dfilter service List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 25 Apr 2013 11:30:01 -0000 The following reply was made to PR kern/157796; it has been noted by GNATS. From: dfilter@FreeBSD.ORG (dfilter service) To: bug-followup@FreeBSD.org Cc: Subject: Re: kern/157796: commit references a PR Date: Thu, 25 Apr 2013 11:24:53 +0000 (UTC) Author: rrs Date: Thu Apr 25 11:24:40 2013 New Revision: 249891 URL: http://svnweb.freebsd.org/changeset/base/249891 Log: MFC of PR r249848. PR: 174749, 157796 Modified: stable/8/sys/netinet/ip_output.c Directory Properties: stable/8/sys/ (props changed) stable/8/sys/netinet/ (props changed) Modified: stable/8/sys/netinet/ip_output.c ============================================================================== --- stable/8/sys/netinet/ip_output.c Thu Apr 25 08:57:15 2013 (r249890) +++ stable/8/sys/netinet/ip_output.c Thu Apr 25 11:24:40 2013 (r249891) @@ -197,8 +197,8 @@ ip_output(struct mbuf *m, struct mbuf *o hlen = ip->ip_hl << 2; } - dst = (struct sockaddr_in *)&ro->ro_dst; again: + dst = (struct sockaddr_in *)&ro->ro_dst; /* * If there is a cached route, * check that it is to the same destination _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" From owner-freebsd-ipfw@FreeBSD.ORG Thu Apr 25 11:30:02 2013 Return-Path: Delivered-To: freebsd-ipfw@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 2E888B6C for ; Thu, 25 Apr 2013 11:30:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 216AB1EB1 for ; Thu, 25 Apr 2013 11:30:02 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3PBU27L078282 for ; Thu, 25 Apr 2013 11:30:02 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3PBU1jd078281; Thu, 25 Apr 2013 11:30:01 GMT (envelope-from gnats) Date: Thu, 25 Apr 2013 11:30:01 GMT Message-Id: <201304251130.r3PBU1jd078281@freefall.freebsd.org> To: freebsd-ipfw@FreeBSD.org Cc: From: dfilter@FreeBSD.ORG (dfilter service) Subject: Re: kern/174749: commit references a PR X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: dfilter service List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 25 Apr 2013 11:30:02 -0000 The following reply was made to PR kern/174749; it has been noted by GNATS. From: dfilter@FreeBSD.ORG (dfilter service) To: bug-followup@FreeBSD.org Cc: Subject: Re: kern/174749: commit references a PR Date: Thu, 25 Apr 2013 11:24:53 +0000 (UTC) Author: rrs Date: Thu Apr 25 11:24:40 2013 New Revision: 249891 URL: http://svnweb.freebsd.org/changeset/base/249891 Log: MFC of PR r249848. PR: 174749, 157796 Modified: stable/8/sys/netinet/ip_output.c Directory Properties: stable/8/sys/ (props changed) stable/8/sys/netinet/ (props changed) Modified: stable/8/sys/netinet/ip_output.c ============================================================================== --- stable/8/sys/netinet/ip_output.c Thu Apr 25 08:57:15 2013 (r249890) +++ stable/8/sys/netinet/ip_output.c Thu Apr 25 11:24:40 2013 (r249891) @@ -197,8 +197,8 @@ ip_output(struct mbuf *m, struct mbuf *o hlen = ip->ip_hl << 2; } - dst = (struct sockaddr_in *)&ro->ro_dst; again: + dst = (struct sockaddr_in *)&ro->ro_dst; /* * If there is a cached route, * check that it is to the same destination _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" From owner-freebsd-ipfw@FreeBSD.ORG Thu Apr 25 11:30:03 2013 Return-Path: Delivered-To: freebsd-ipfw@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 1F4E6B6D for ; Thu, 25 Apr 2013 11:30:03 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 125A61EB2 for ; Thu, 25 Apr 2013 11:30:03 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3PBU2C8078288 for ; Thu, 25 Apr 2013 11:30:02 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3PBU2JM078287; Thu, 25 Apr 2013 11:30:02 GMT (envelope-from gnats) Date: Thu, 25 Apr 2013 11:30:02 GMT Message-Id: <201304251130.r3PBU2JM078287@freefall.freebsd.org> To: freebsd-ipfw@FreeBSD.org Cc: From: dfilter@FreeBSD.ORG (dfilter service) Subject: Re: kern/174749: commit references a PR X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: dfilter service List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 25 Apr 2013 11:30:03 -0000 The following reply was made to PR kern/174749; it has been noted by GNATS. From: dfilter@FreeBSD.ORG (dfilter service) To: bug-followup@FreeBSD.org Cc: Subject: Re: kern/174749: commit references a PR Date: Thu, 25 Apr 2013 11:25:42 +0000 (UTC) Author: rrs Date: Thu Apr 25 11:25:24 2013 New Revision: 249892 URL: http://svnweb.freebsd.org/changeset/base/249892 Log: MFC of r249848 PR: 174749, 157796 Modified: stable/9/sys/netinet/ip_output.c Directory Properties: stable/9/sys/ (props changed) Modified: stable/9/sys/netinet/ip_output.c ============================================================================== --- stable/9/sys/netinet/ip_output.c Thu Apr 25 11:24:40 2013 (r249891) +++ stable/9/sys/netinet/ip_output.c Thu Apr 25 11:25:24 2013 (r249892) @@ -194,8 +194,8 @@ ip_output(struct mbuf *m, struct mbuf *o hlen = ip->ip_hl << 2; } - dst = (struct sockaddr_in *)&ro->ro_dst; again: + dst = (struct sockaddr_in *)&ro->ro_dst; ia = NULL; /* * If there is a cached route, _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" From owner-freebsd-ipfw@FreeBSD.ORG Thu Apr 25 11:30:04 2013 Return-Path: Delivered-To: freebsd-ipfw@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 15F58B6E for ; Thu, 25 Apr 2013 11:30:04 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 08D6B1EB3 for ; Thu, 25 Apr 2013 11:30:04 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3PBU3aY078295 for ; Thu, 25 Apr 2013 11:30:03 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3PBU3C2078294; Thu, 25 Apr 2013 11:30:03 GMT (envelope-from gnats) Date: Thu, 25 Apr 2013 11:30:03 GMT Message-Id: <201304251130.r3PBU3C2078294@freefall.freebsd.org> To: freebsd-ipfw@FreeBSD.org Cc: From: dfilter@FreeBSD.ORG (dfilter service) Subject: Re: kern/157796: commit references a PR X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: dfilter service List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 25 Apr 2013 11:30:04 -0000 The following reply was made to PR kern/157796; it has been noted by GNATS. From: dfilter@FreeBSD.ORG (dfilter service) To: bug-followup@FreeBSD.org Cc: Subject: Re: kern/157796: commit references a PR Date: Thu, 25 Apr 2013 11:25:42 +0000 (UTC) Author: rrs Date: Thu Apr 25 11:25:24 2013 New Revision: 249892 URL: http://svnweb.freebsd.org/changeset/base/249892 Log: MFC of r249848 PR: 174749, 157796 Modified: stable/9/sys/netinet/ip_output.c Directory Properties: stable/9/sys/ (props changed) Modified: stable/9/sys/netinet/ip_output.c ============================================================================== --- stable/9/sys/netinet/ip_output.c Thu Apr 25 11:24:40 2013 (r249891) +++ stable/9/sys/netinet/ip_output.c Thu Apr 25 11:25:24 2013 (r249892) @@ -194,8 +194,8 @@ ip_output(struct mbuf *m, struct mbuf *o hlen = ip->ip_hl << 2; } - dst = (struct sockaddr_in *)&ro->ro_dst; again: + dst = (struct sockaddr_in *)&ro->ro_dst; ia = NULL; /* * If there is a cached route, _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org" From owner-freebsd-ipfw@FreeBSD.ORG Thu Apr 25 18:40:01 2013 Return-Path: Delivered-To: freebsd-ipfw@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id E126C8C4 for ; Thu, 25 Apr 2013 18:40:01 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id B8B1B135B for ; Thu, 25 Apr 2013 18:40:01 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3PIe1V5064488 for ; Thu, 25 Apr 2013 18:40:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3PIe1pg064487; Thu, 25 Apr 2013 18:40:01 GMT (envelope-from gnats) Date: Thu, 25 Apr 2013 18:40:01 GMT Message-Id: <201304251840.r3PIe1pg064487@freefall.freebsd.org> To: freebsd-ipfw@FreeBSD.org Cc: From: =?iso-8859-2?Q?Radek_Krej=E8a?= Subject: Re: kern/174749: Unexpected change of default route X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: =?iso-8859-2?Q?Radek_Krej=E8a?= List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 25 Apr 2013 18:40:01 -0000 The following reply was made to PR kern/174749; it has been noted by GNATS. From: =?iso-8859-2?Q?Radek_Krej=E8a?= To: "'bug-followup@FreeBSD.org'" Cc: Subject: Re: kern/174749: Unexpected change of default route Date: Thu, 25 Apr 2013 20:32:08 +0200 Hello, thank you very much, I will try it. The same problem I noticed also in 9.1. Radek From owner-freebsd-ipfw@FreeBSD.ORG Fri Apr 26 08:58:37 2013 Return-Path: Delivered-To: freebsd-ipfw@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 94393FDC; Fri, 26 Apr 2013 08:58:37 +0000 (UTC) (envelope-from glebius@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 6D7401A79; Fri, 26 Apr 2013 08:58:37 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3Q8wbSw040974; Fri, 26 Apr 2013 08:58:37 GMT (envelope-from glebius@freefall.freebsd.org) Received: (from glebius@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3Q8wbae040973; Fri, 26 Apr 2013 08:58:37 GMT (envelope-from glebius) Date: Fri, 26 Apr 2013 08:58:37 GMT Message-Id: <201304260858.r3Q8wbae040973@freefall.freebsd.org> To: glebius@FreeBSD.org, freebsd-ipfw@FreeBSD.org, rrs@FreeBSD.org From: glebius@FreeBSD.org Subject: Re: kern/174749: Unexpected change of default route X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 26 Apr 2013 08:58:37 -0000 Synopsis: Unexpected change of default route Responsible-Changed-From-To: freebsd-ipfw->rrs Responsible-Changed-By: glebius Responsible-Changed-When: Fri Apr 26 08:58:18 UTC 2013 Responsible-Changed-Why: Randall fixed this recently. http://www.freebsd.org/cgi/query-pr.cgi?pr=174749 From owner-freebsd-ipfw@FreeBSD.ORG Fri Apr 26 08:59:10 2013 Return-Path: Delivered-To: freebsd-ipfw@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id BBFAAB2; Fri, 26 Apr 2013 08:59:10 +0000 (UTC) (envelope-from glebius@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 95EB31A9F; Fri, 26 Apr 2013 08:59:10 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r3Q8xAfc041023; Fri, 26 Apr 2013 08:59:10 GMT (envelope-from glebius@freefall.freebsd.org) Received: (from glebius@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r3Q8xAeN041022; Fri, 26 Apr 2013 08:59:10 GMT (envelope-from glebius) Date: Fri, 26 Apr 2013 08:59:10 GMT Message-Id: <201304260859.r3Q8xAeN041022@freefall.freebsd.org> To: glebius@FreeBSD.org, freebsd-ipfw@FreeBSD.org, rrs@FreeBSD.org From: glebius@FreeBSD.org Subject: Re: kern/157796: [ipfw] IPFW in-kernel NAT nat loopback / Default Router Changes Unexpectedly X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 26 Apr 2013 08:59:10 -0000 Synopsis: [ipfw] IPFW in-kernel NAT nat loopback / Default Router Changes Unexpectedly Responsible-Changed-From-To: freebsd-ipfw->rrs Responsible-Changed-By: glebius Responsible-Changed-When: Fri Apr 26 08:58:57 UTC 2013 Responsible-Changed-Why: Randall fixed this recently. http://www.freebsd.org/cgi/query-pr.cgi?pr=157796