<br><tt><font size=2>"Daniel P. Berrange" <berrange@redhat.com>
wrote on 03/25/2010 07:37:14 AM:<br>
<br>
</font></tt>
<br><tt><font size=2>> <br>
> Please respond to "Daniel P. Berrange"</font></tt>
<br><tt><font size=2>> <br>
> On Tue, Mar 23, 2010 at 10:54:06AM -0400, stefanb@us.ibm.com wrote:<br>
> > One comment about the instantiation of the rules: Since the XML
allows<br>
> > to create nearly any possible combination of parameters to ebtables
or<br>
> > iptables commands, I haven't used the ebtables or iptables wrappers.<br>
> > Instead, I am writing ebtables/iptables command into a buffer,
add<br>
> > command line options to each one of them as described in the
rule's XML,<br>
> > write the buffer into a file and run it as a script. For those
commands<br>
> > that are not allowed to fail I am using the following format
to run<br>
> > them:<br>
> > <br>
> > cmd="ebtables <some options>"<br>
> > r=`${cmd}`<br>
> > if [ $? -ne 0 ]; then<br>
> > echo "Failure in command ${cmd}."<br>
> > exit 1<br>
> > fi<br>
> > <br>
> > cmd="..."<br>
> > [...]<br>
> > <br>
> > If one of the command fails in such a batch, the libvirt code
is going<br>
> > pick up the error code '1', tear down anything previously established<br>
> > and report an error back. The actual error message shown above
is<br>
> > currently not reported back, but can be later on with some changes
to<br>
> > the commands running external programs that need to read the
script's<br>
> > stdout.<br>
> <br>
> I've tried out this patch series, but not entirely sure whether it
is<br>
> working correctly, since there are lots of errors in the libvirt debug<br>
> logs.<br>
> </font></tt>
<br>
<br><tt><font size=2>The errors in the debugging log are due to attempts
to cleanup user-defined tables</font></tt>
<br><tt><font size=2>that do not exist. Though attempting to clean them
up gets the system into a well</font></tt>
<br><tt><font size=2>known start state. The errors could be avoided with
a sequence of checking for</font></tt>
<br><tt><font size=2>existence of the user-defined chain first and then
try to flush and delete them,</font></tt>
<br><tt><font size=2>but it's faster not to do so.</font></tt>
<br><tt><font size=2><br>
> I have a guest<br>
> <br>
>     <interface type='network'><br>
>       <mac address='52:54:00:4d:c8:5f'/><br>
>       <source network='default'/><br>
>       <filterref filter='demofilter4'><br>
>         <parameter name='IP' value='9.59.241.151'/><br>
>       </filterref><br>
>       <address type='pci' domain='0x0000' bus='0x00'
slot='0x04' <br>
> function='0x0'/><br>
>     </interface><br>
> <br>
> And demofilter4 is setup as:<br>
> <br>
> <filter name='demofilter4' chain='root'><br>
>   <uuid>d33d17bf-0198-6b89-0b03-55abba1eae7f</uuid><br>
>   <filterref filter='no-mac-spoofing'/><br>
>   <filterref filter='no-mac-broadcast'/><br>
>   <filterref filter='no-arp-spoofing'/><br>
>   <filterref filter='allow-dhcp'><br>
>     <parameter name='DHCPSERVER' value='10.0.0.1'/><br>
>   </filterref><br>
> </filter><br>
> <br>
> The filter it references here are the XML examples you sent out previously<br>
> <br>
> The guest starts without error, and I get a lot of things in the ebtables<br>
> 'nat' table, but nothing in the 'filter' table - is that expected
?</font></tt>
<br>
<br><tt><font size=2>Yes, this is correct. The nat table handles the filtering
correctly and with the</font></tt>
<br><tt><font size=2>PREROUTING chain we can filter for traffic coming
from the VM (that becomes</font></tt>
<br><tt><font size=2>incoming to the host - prefix letter 'I') and in the
POSTROUTING chain</font></tt>
<br><tt><font size=2>traffic going to the VM (outgoing from the host -
prefix letter 'O').</font></tt>
<br><tt><font size=2><br>
> <br>
> # ebtables -t nat -L<br>
> Bridge table: nat<br>
> <br>
> Bridge chain: PREROUTING, entries: 1, policy: ACCEPT<br>
> -i vnet0 -j I-vnet0<br>
> <br>
> Bridge chain: OUTPUT, entries: 0, policy: ACCEPT<br>
> <br>
> Bridge chain: POSTROUTING, entries: 1, policy: ACCEPT<br>
> -o vnet0 -j O-vnet0<br>
> <br>
> Bridge chain: I-vnet0, entries: 2, policy: ACCEPT<br>
> -p IPv4 -j I-vnet0-ipv4<br>
> -p ARP -j I-vnet0-arp<br>
> <br>
> Bridge chain: O-vnet0, entries: 2, policy: ACCEPT<br>
> -p IPv4 -j O-vnet0-ipv4<br>
> -p ARP -j O-vnet0-arp<br>
> <br>
> Bridge chain: I-vnet0-ipv4, entries: 3, policy: ACCEPT<br>
> -s ! 52:54:0:4d:c8:5f -j DROP <br>
> -p IPv4 --ip-src 0.0.0.0 --ip-dst 255.255.255.255 --ip-proto udp --<br>
> ip-sport 68 --ip-dport 67 -j ACCEPT <br>
> -d Broadcast -j DROP <br>
> <br>
> Bridge chain: O-vnet0-ipv4, entries: 1, policy: ACCEPT<br>
> -p IPv4 --ip-src 10.0.0.1 --ip-proto udp --ip-sport 67 --ip-dport
68-j ACCEPT <br>
> <br>
> Bridge chain: I-vnet0-arp, entries: 5, policy: ACCEPT<br>
> -p ARP --arp-mac-src ! 52:54:0:4d:c8:5f -j DROP <br>
> -p ARP --arp-ip-src ! 9.59.241.151 -j DROP <br>
> -p ARP --arp-op Request -j ACCEPT <br>
> -p ARP --arp-op Reply -j ACCEPT <br>
> -j DROP <br>
> <br>
> Bridge chain: O-vnet0-arp, entries: 5, policy: ACCEPT<br>
> -p ARP --arp-op Reply --arp-mac-dst ! 52:54:0:4d:c8:5f -j DROP <br>
> -p ARP --arp-ip-dst ! 9.59.241.151 -j DROP <br>
> -p ARP --arp-op Request -j ACCEPT <br>
> -p ARP --arp-op Reply -j ACCEPT <br>
> -j DROP <br>
> <br>
> <br>
> <br>
> The libvirt logs show a bunch of shell erorrs - see the attachment
to this<br>
> mail. Are these errors to be expected, or are they actual errors ?</font></tt>
<br>
<br><tt><font size=2>They are due to attempted cleanups that try to cleanup
user-defined tables that did not exist on your system, </font></tt>
<br><tt><font size=2>however. As said, this gets the system into a well
known start-out state so that those user-defined ebtables</font></tt>
<br><tt><font size=2>tables can be established with rules. As seen above,
every interface gets a 'tree' of user-defined tables.</font></tt>
<br><tt><font size=2>Following the chain identifier in the above XML</font></tt>
<br>
<br><tt><font size=2> <filter name='demofilter4' chain='root'><br>
   <uuid>d33d17bf-0198-6b89-0b03-55abba1eae7f</uuid><br>
[...]</font></tt>
<br>
<br><tt><font size=2>which can be either left out entirely for meaning
of 'root', or be 'root' explicitly or have the values 'arp' or 'ipv4'.</font></tt>
<br>
<br><tt><font size=2>The patterns of the user-defined ebtables tables is
due to 32 byte size restrictions (including trailing 0) as follows:</font></tt>
<br>
<br><tt><font size=2><one letter prefix>-<name of the interface>-<filter
chain identifier>:</font></tt>
<br>
<br><tt><font size=2>This then leads to</font></tt>
<br>
<br><tt><font size=2>I-vnet0    and</font></tt>
<br><tt><font size=2>I-vnet0-ipv4  etc.</font></tt>
<br>
<br><tt><font size=2>as shown above.</font></tt>
<br>
<br><tt><font size=2>However, the tricky part are updates of filters. You
can, using virsh-define, update any filter while it is being used by running</font></tt>
<br><tt><font size=2>VMs. For updates I decided not to compare the current
filter tree against the new one, calculating 'diffs' </font></tt>
<br><tt><font size=2>for the rules and remove rules that don't exist in
the new one along with user defined tables that may not exist anymore</font></tt>
<br><tt><font size=2>etc., which would be much more complicated. Instead,
I am completely rebuilding the filter tree. So, a temporary filter</font></tt>
<br><tt><font size=2>tree is established with user-defined names following
the above pattern while the current filter tree is still active.</font></tt>
<br><tt><font size=2>However, the prefixes are different. So the temporary
 filter tree would have user-defined tables named</font></tt>
<br>
<br><tt><font size=2>J-vnet0    and </font></tt>
<br><tt><font size=2>J-vnet0-ipv4  etc.</font></tt>
<br>
<br><tt><font size=2>where all the rules are established. Then, while the
'old' filter tree is active, the new one is anchored, leading to</font></tt>
<br><tt><font size=2>entries like this one:</font></tt>
<br>
<br><tt><font size=2>Bridge chain: PREROUTING, entries: 1, policy: ACCEPT<br>
-i vnet0 -j I-vnet0</font></tt>
<br><tt><font size=2>-i vnet0 -j J-vnet0</font></tt>
<br>
<br>
<br><tt><font size=2>Yes, temporarily you would have two parallel filter
trees for an interface, but the old one is still active. Then</font></tt>
<br><tt><font size=2>comes the switch-over to the new tree where the old
filter tree is un-anchored, leading to this situation:</font></tt>
<br>
<br><tt><font size=2>Bridge chain: PREROUTING, entries: 1, policy: ACCEPT<br>
-i vnet0 -j J-vnet0</font></tt>
<br><tt><font size=2><br>
Now all possible chains starting with prefix I-vnet0-<XYZ> are flushed
and deleted.</font></tt>
<br><tt><font size=2>In the subsequent step I rename the filter tree starting
with J-<vnet0>-<XYZ> to I-<vnet0>-<XYZ> leading
to</font></tt>
<br>
<br><tt><font size=2>Bridge chain: PREROUTING, entries: 1, policy: ACCEPT<br>
-i vnet0 -j I-vnet0</font></tt>
<br>
<br><tt><font size=2>which is where we want to be so that the next update
can do the same procedure again.</font></tt>
<br>
<br><tt><font size=2>I have made some changes to the core patch (part 11)
that split up the application of new filter rules into</font></tt>
<br><tt><font size=2>3 different (interface) functions, for application
of new rules, switch over + tear down of old, or </font></tt>
<br><tt><font size=2>tear down of new in case an error happened. </font></tt>
<br><tt><font size=2><br>
> <br>
> <br>
> Also, I'm wondering if it is possible to include 'libvirt-' in the
custom<br>
> ebtables/iptables chains that we create ?  I think that would
be useful<br>
> for sysadmins who might be surprised at where all these rules are
coming<br>
> from. From the code it looks like we have a fairly low size limit
on the<br>
> possible chain names, but I think at least for the first two chains
we<br>
> ought to be able to get 'libvirt-' prefix in there. Or perhaps instead<br>
> of adding the per-VIF chains straight to PREROUTING/POSTROUTING, have<br>
> an unconditional jump to a libvirt specific chain.<br>
> <br>
> So either have<br>
> <br>
> <br>
>   Bridge chain: PREROUTING, entries: 1, policy: ACCEPT<br>
>   -i vnet0 -j libvirt-I-vnet0<br>
> <br>
>   Bridge chain: OUTPUT, entries: 0, policy: ACCEPT<br>
> <br>
>   Bridge chain: POSTROUTING, entries: 1, policy: ACCEPT<br>
>   -o vnet0 -j libvirt-O-vnet0<br>
> <br>
> <br>
> <br>
> Or the slightly more complex<br>
> <br>
>   Bridge chain: PREROUTING, entries: 1, policy: ACCEPT<br>
>   -j libvirt-I<br>
> <br>
>   Bridge chain: OUTPUT, entries: 0, policy: ACCEPT<br>
> <br>
>   Bridge chain: POSTROUTING, entries: 1, policy: ACCEPT<br>
>   -j libvirt-O<br>
> <br>
>   Bridge chain: libvirt-I, entries: 1, policy: ACCEPT<br>
>   -i vnet0 -j I-vnet0<br>
> <br>
>   Bridge chain: OUTPUT, entries: 0, policy: ACCEPT<br>
> <br>
>   Bridge chain: libvirt-O, entries: 1, policy: ACCEPT<br>
>   -o vnet0 -j O-vnet0</font></tt>
<br>
<br><tt><font size=2>Both is possible with the first one resulting in being
more efficient.</font></tt>
<br>
<br><tt><font size=2>I'll try to make that change.</font></tt>
<br>
<br><tt><font size=2>  Regards,</font></tt>
<br><tt><font size=2>     Stefan</font></tt>
<br>
<br>
<br><tt><font size=2><br>
> <br>
> <br>
> Regards,<br>
> Daniel<br>
> -- <br>
> |: Red Hat, Engineering, London    -o-   </font></tt><a href=http://people.redhat.com/berrange/:|><tt><font size=2>http://people.redhat.com/berrange/:|</font></tt></a><tt><font size=2><br>
> |: </font></tt><a href=http://libvirt.org/><tt><font size=2>http://libvirt.org</font></tt></a><tt><font size=2>
-o- </font></tt><a href="http://virt-manager.org/"><tt><font size=2>http://virt-manager.org</font></tt></a><tt><font size=2>
-o- </font></tt><a href=http://deltacloud.org:|/><tt><font size=2>http://deltacloud.org:|</font></tt></a><tt><font size=2><br>
> |: </font></tt><a href=http://autobuild.org/><tt><font size=2>http://autobuild.org</font></tt></a><tt><font size=2>
       -o-         </font></tt><a href=http://search.cpan.org/~danberr/:|><tt><font size=2>http://search.cpan.org/~danberr/:|</font></tt></a><tt><font size=2><br>
> |: GnuPG: 7D3B9505  -o-   F3C9 553F A1DA 4AC2 5648 23C1
B3DF F742 7D3B 9505 :|<br>
> [attachment "filter.log" deleted by Stefan Berger/Watson/IBM]
</font></tt>