On 09/21/2015 08:26 PM, Joe Stringer wrote:
> 
> On 21 Sep 2015 2:36 pm, "Russell Bryant" <rbry...@redhat.com
> <mailto:rbry...@redhat.com>> wrote:
>>
>> On 09/21/2015 02:50 PM, Joe Stringer wrote:
>> > On 18 September 2015 at 08:27, Russell Bryant <rbry...@redhat.com
> <mailto:rbry...@redhat.com>> wrote:
>> >> I mentioned in yesterday's OVN meeting that I was finally to the point
>> >> where I could start testing Neutron security groups with OVN ACLs but
>> >> hadn't done so before the meeting.  I worked on it yesterday afternoon
>> >> and here's what happened.
>> >>
>> >> I'm using OVN from Justin's ovn-acl branch.  I'm using my
>> >> security-groups branch for the Neutron plugin (networking-ovn).
>> >>
>> >> This test is on Ubuntu 14.04.  I do most dev on Fedora 22, but the
>> >> kernel modules didn't build there (kernel too new).  I used Ubuntu
> 14.04
>> >> because I thought I remembered that being something Justin had tested
>> >> with.  I'd actually like to clarify that point so let me know what you
>> >> all are using successfully.  I was going to switch to CentOS 7 next.
>> >
>> > Yes, I most commonly test with Ubuntu14.04. YMMV, when the userspace
>> > is reviewed I plan to work on the kernel backport and get it to work
>> > on a variety of kernel versions.
>> >
>> >> The test environment is a simple single hypervisor environment.  I
>> >> created a Neutron port and booted a VM using this port.  From there I
>> >> can add/remove/update security groups on this port and see what happens
>> >> to the traffic.
>> >>
>> >> With no security group, things work as usual.  I can ping and ssh
> to the VM.
>> >>
>> >> I have a security group named "default", which has the default rules
>> >> plus two other rules that are supposed to allow me to ping and ssh to
>> >> the VM.
>> >>
>> >>> $ neutron security-group-list
>> >>>
> +--------------------------------------+---------+----------------------------------------------------------------------+
>> >>> | id                                   | name    |
> security_group_rules                                                 |
>> >>>
> +--------------------------------------+---------+----------------------------------------------------------------------+
>> >>> | 2bdabbcf-cde5-47fb-8a16-f5772545accc | default | egress, IPv4   
>                                                      |
>> >>> |                                      |         | egress, IPv6   
>                                                      |
>> >>
>> >> Allow all outbound traffic from the VM.
>> >>
>> >>> |                                      |         | ingress, IPv4,
> 22/tcp, remote_ip_prefix: 0.0.0.0/0 <http://0.0.0.0/0>                   |
>> >>> |                                      |         | ingress, IPv4,
> icmp, remote_ip_prefix: 0.0.0.0/0 <http://0.0.0.0/0>                     |
>> >>
>> >> Allow icmp and ssh from any source.
>> >>
>> >>> |                                      |         | ingress, IPv4,
> remote_group_id: 2bdabbcf-cde5-47fb-8a16-f5772545accc |
>> >>> |                                      |         | ingress, IPv6,
> remote_group_id: 2bdabbcf-cde5-47fb-8a16-f5772545accc |
>> >>>
> +--------------------------------------+---------+----------------------------------------------------------------------+
>> >>
>> >> Allow all traffic from other ports on the same security group.
>> >>
>> >>
>> >> With that configuration, here are the OVN ACLs, the logical flow table
>> >> row for ACLs, and the OpenFlow flows for the egress pipeline ACLs:
>> >>
>> >>> $ ovn-nbctl acl-list e7936efd-1cf3-4198-bff5-cd0abf1164c8
>> >>>
>> >>> from-lport  1002 (inport == "fbda6395-71fe-4eb5-abda-531bddf479ba"
> && ip4) allow-related
>> >>> from-lport  1002 (inport == "fbda6395-71fe-4eb5-abda-531bddf479ba"
> && ip6) allow-related
>> >>> from-lport  1001 (inport == "fbda6395-71fe-4eb5-abda-531bddf479ba"
> && ip) drop
>> >>>   to-lport  1002 (outport ==
> "fbda6395-71fe-4eb5-abda-531bddf479ba" && ip4 && ip4.dst == 0.0.0.0/0
> <http://0.0.0.0/0> && icmp4) allow-related
>> >>>   to-lport  1002 (outport ==
> "fbda6395-71fe-4eb5-abda-531bddf479ba" && ip4 && ip4.dst == 0.0.0.0/0
> <http://0.0.0.0/0> && tcp && tcp.dst >= 22 && tcp.dst <= 22) allow-related
>> >>>   to-lport  1001 (outport ==
> "fbda6395-71fe-4eb5-abda-531bddf479ba" && ip) drop
>> >>
>> >>
>> >>> $ ovn-sbctl lflow-list
>> >>>
>> >>> Datapath: adec5d12-20a8-4a33-9de9-0fed21109118  Pipeline: ingress
>> >>>   table=1( pre_acl), priority=100, match=(ip), action=(ct_next;)
>> >>>   table=1( pre_acl), priority=  0, match=(1), action=(next;)
>> >>>   table=2(     acl), priority=65535, match=(!ct.est && ct.rel &&
> !ct.new && !ct.inv), action=(next;)
>> >>>   table=2(     acl), priority=65535, match=(ct.est && !ct.rel &&
> !ct.new && !ct.inv), action=(next;)
>> >>>   table=2(     acl), priority=65535, match=(ct.inv), action=(drop;)
>> >>>   table=2(     acl), priority=1002, match=(ct.new && inport ==
> "fbda6395-71fe-4eb5-abda-531bddf479ba" && ip4), action=(ct_commit; next;)
>> >>>   table=2(     acl), priority=1002, match=(ct.new && inport ==
> "fbda6395-71fe-4eb5-abda-531bddf479ba" && ip6), action=(ct_commit; next;)
>> >>>   table=2(     acl), priority=1001, match=(inport ==
> "fbda6395-71fe-4eb5-abda-531bddf479ba" && ip), action=(drop;)
>> >>>   table=2(     acl), priority=  0, match=(1), action=(next;)
>> >>>
>> >>> Datapath: adec5d12-20a8-4a33-9de9-0fed21109118  Pipeline: egress
>> >>>   table=0( pre_acl), priority=100, match=(ip), action=(ct_next;)
>> >>>   table=0( pre_acl), priority=  0, match=(1), action=(next;)
>> >>>   table=1(     acl), priority=65535, match=(!ct.est && ct.rel &&
> !ct.new && !ct.inv), action=(next;)
>> >>>   table=1(     acl), priority=65535, match=(ct.est && !ct.rel &&
> !ct.new && !ct.inv), action=(next;)
>> >>>   table=1(     acl), priority=65535, match=(ct.inv), action=(drop;)
>> >>>   table=1(     acl), priority=1002, match=(ct.new && outport ==
> "fbda6395-71fe-4eb5-abda-531bddf479ba" && ip4 && ip4.dst == 0.0.0.0/0
> <http://0.0.0.0/0> && icmp4), action=(ct_commit; next;)
>> >>>   table=1(     acl), priority=1002, match=(ct.new && outport ==
> "fbda6395-71fe-4eb5-abda-531bddf479ba" && ip4 && ip4.dst == 0.0.0.0/0
> <http://0.0.0.0/0> && tcp && tcp.dst >= 22 && tcp.dst <= 22),
> action=(ct_commit; next;)
>> >>>   table=1(     acl), priority=1001, match=(outport ==
> "fbda6395-71fe-4eb5-abda-531bddf479ba" && ip), action=(drop;)
>> >>>   table=1(     acl), priority=  0, match=(1), action=(next;)
>> >>
>> >>
>> >>> flows for egress pipeline ACLs
>> >>>
>> >>>  cookie=0x0, duration=31.955s, table=48, n_packets=15,
> n_bytes=1650, priority=100,ipv6,metadata=0x1
> actions=ct(recirc,next_table=49,zone_reg=NXM_NX_REG5[])
>> >>>  cookie=0x0, duration=31.952s, table=48, n_packets=2, n_bytes=196,
> priority=100,ip,metadata=0x1
> actions=ct(recirc,next_table=49,zone_reg=NXM_NX_REG5[])
>> >>>  cookie=0x0, duration=31.955s, table=48, n_packets=2, n_bytes=84,
> priority=0,metadata=0x1 actions=resubmit(,49)
>> >>>  cookie=0x0, duration=31.955s, table=49, n_packets=0, n_bytes=0,
> priority=65535,ct_state=-new+est-rel-inv+trk,metadata=0x1
> actions=resubmit(,50)
>> >>>  cookie=0x0, duration=31.952s, table=49, n_packets=0, n_bytes=0,
> priority=65535,ct_state=-new-est+rel-inv+trk,metadata=0x1
> actions=resubmit(,50)
>> >>>  cookie=0x0, duration=31.952s, table=49, n_packets=1, n_bytes=98,
> priority=65535,ct_state=+inv+trk,metadata=0x1 actions=drop
>> >>>  cookie=0x0, duration=31.955s, table=49, n_packets=0, n_bytes=0,
> priority=1002,ct_state=+new+trk,tcp,reg7=0x4,metadata=0x1,tp_dst=22
> actions=ct(commit,zone_reg=NXM_NX_REG5[]),resubmit(,50)
>> >>>  cookie=0x0, duration=31.952s, table=49, n_packets=1, n_bytes=98,
> priority=1002,ct_state=+new+trk,icmp,reg7=0x4,metadata=0x1
> actions=ct(commit,zone_reg=NXM_NX_REG5[]),resubmit(,50)
>> >>>  cookie=0x0, duration=31.955s, table=49, n_packets=5, n_bytes=550,
> priority=1001,ipv6,reg7=0x4,metadata=0x1 actions=drop
>> >>>  cookie=0x0, duration=31.952s, table=49, n_packets=0, n_bytes=0,
> priority=1001,ip,reg7=0x4,metadata=0x1 actions=drop
>> >>>  cookie=0x0, duration=31.955s, table=49, n_packets=12,
> n_bytes=1184, priority=0,metadata=0x1 actions=resubmit(,50)
>> >>
>> >>
>> >> When I send a single ping from the hypervisor to the VM, I get no
>> >> response.  Looking at the flows, it seems the ping makes it to the VM,
>> >> but the response is dropped by an ACL flow as invalid.
>> >>
>> >> After the ping, it shows up in conntrack like so:
>> >>
>> >>> $ sudo conntrack -L
>> >>> ...
>> >>> icmp     1 21 src=172.24.4.1 dst=10.0.0.4 type=8 code=0 id=9730
> src=10.0.0.4 dst=172.24.4.1 type=0 code=0 id=9730 mark=0 zone=3 use=1
>> >>> icmp     1 21 src=172.24.4.1 dst=10.0.0.4 type=8 code=0 id=9730
> [UNREPLIED] src=10.0.0.4 dst=172.24.4.1 type=0 code=0 id=9730 mark=0 use=1
>> >>
>> >> The flows that I believe shows what happens are:
>> >>
>> >>>  cookie=0x0, duration=31.952s, table=48, n_packets=2, n_bytes=196,
> priority=100,ip,metadata=0x1
> actions=ct(recirc,next_table=49,zone_reg=NXM_NX_REG5[])
>> >>>
>> >>>  cookie=0x0, duration=31.952s, table=49, n_packets=1, n_bytes=98,
> priority=65535,ct_state=+inv+trk,metadata=0x1 actions=drop
>> >>>
>> >>>  cookie=0x0, duration=31.952s, table=49, n_packets=1, n_bytes=98,
> priority=1002,ct_state=+new+trk,icmp,reg7=0x4,metadata=0x1
> actions=ct(commit,zone_reg=NXM_NX_REG5[]),resubmit(,50)
>> >>
>> >>
>> >> I did a similar test using ssh.  After the ssh attempt, conntrack
> shows:
>> >>
>> >>> sudo conntracl -L
>> >>> tcp      6 27 SYN_RECV src=172.24.4.1 dst=10.0.0.4 sport=47784
> dport=22 src=10.0.0.4 dst=172.24.4.1 sport=22 dport=47784 mark=0 zone=3
> use=1
>> >>> tcp      6 87 SYN_SENT src=172.24.4.1 dst=10.0.0.4 sport=47784
> dport=22 [UNREPLIED] src=10.0.0.4 dst=172.24.4.1 sport=22 dport=47784
> mark=0 use=1
>> >>
>> >> It looks like the SYN makes it to the VM, but the return traffic is
>> >> dropped as invalid.
>> >>
>> >>
>> >> Any thoughts on this?  Is there anything obviously wrong with what I've
>> >> done?  Are there more details I should gather?
>> >
>> > It's a little hard to verify your analysis with only the the egress
>> > pipeline flows, but looking at the conntrack output it seems about
>> > right.
>>
>> Sorry for stripping it.  I'll include the full flow table at the end of
>> this message.
>>
>> > There's a bit of a trick here, and I'm guessing that the OVN flows as
>> > generated today aren't quite handling this right. When the conntrack
>> > module is loaded, and you send packets from the local stack (eg ping
>> > from hypervisor -> VM), linux will piggyback conntrack information
>> > onto the packet. This is attached during linux stack processing
>> > between the application sending the packet and the packet arriving at
>> > OVS. The packet's associated conntrack state is in zone=0 if you
>> > haven't otherwise configured the local IPtables rules.
>> >
>> > For the below explanation, I'm going to assume that the zone
>> > associated with your hypervisor VIF is zone=2, and the zone associated
>> > with your VM is zone=3.
>> >
>> > It looks like OVN trusts that this conntrack information is correct
>> > when the packet arrives (zone=0), and rather than going through the
>> > from-lport conntrack processing (which should commit to zone=2), it
>> > skips this step and goes straight through to the to-lport processing.
>> > In to-lport, it goes through conntrack for zone=3 and commits the
>> > connection there. So we have two connections: One in zone=0 and one in
>> > zone=3.
>> >
>> > When the reply comes in the reverse direction, coming from the VM
>> > there is no conntrack information associated. OVN correctly passes
>> > this to conntrack for zone=3, which says "yep, this is the reply for
>> > that connection we saw before". The rules continue processing to go to
>> > the to-lport for the original VIF. This time, it submits to zone=2.
>> > However, we never committed the connection to zone=2 so conntrack
>> > marks it as invalid.
>> >
>> > Looking at the OVN rules, I think that this should be logically
>> > handled correctly so probably it just needs some adjustments on the
>> > translation to OpenFlow.
>> >
>>
>> Thanks for the explanation!  I'll dig into the CT support to see if I
>> can figure out what might need to change.  I'm guessing it's something
>> like clearing existing CT state, or ignoring state from a different zone?
> 
> Roughly, yeah. The translation should be similar for conntrack matching
> when transitioning from the from-lport to to-lport pipeline stages; at
> this point, conntrack fields are present from the from-lport pipeline
> but we wish to ignore it. Similarly, I'd expect us to ignore conntrack
> fields for packets coming immediately from a port(from-lport pipeline).
> Hope that makes some sense.
> 

It does make sense, though I'm having trouble finding anything in the
current flows that does that in between the from-lport and to-lport
stages in the flows for a packet that stays on the same host.

-- 
Russell Bryant
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to