Re: [ovs-dev] [PATCH v4] ovn: Support a new Logical_Switch_Port.type - 'external'

2019-01-17 Thread Numan Siddique
On Thu, Jan 17, 2019 at 10:57 PM Han Zhou  wrote:

> On Tue, Jan 15, 2019 at 10:24 AM Numan Siddique 
> wrote:
> >
> >
> >
> > On Tue, Jan 15, 2019 at 5:42 AM Han Zhou  wrote:
> >>
> >> Hi Numan,
> >>
> >> The feature looks very good overall. I have some more comments inlined.
> >
> >
> > Thank Han for the review and the comments.
> >
> > You are right. The logical port's mac flaps too. I had to read the
> commit message again to
> > recall :)
> >
> >
> >>
> >> On Thu, Jan 10, 2019 at 12:37 PM  wrote:
> >> >
> >> > From: Numan Siddique 
> >> >
> >> > In the case of OpenStack + OVN, when the VMs are booted on
> >> > hypervisors supporting SR-IOV nics, there are no OVS ports
> >> > for these VMs. When these VMs sends DHCPv4, DHPCv6 or IPv6
> >> > Router Solicitation requests, the local ovn-controller
> >> > cannot reply to these packets. OpenStack Neutron dhcp agent
> >> > service needs to be run to serve these requests.
> >> >
> >> > With the new logical port type - 'external', OVN itself can
> >> > handle these requests avoiding the need to deploy any
> >> > external services like neutron dhcp agent.
> >> >
> >> > To make use of this feature, CMS has to
> >> >  - create a logical port for such VMs
> >> >  - set the type to 'external'
> >> >  - set requested-chassis="" in the options
> >> >column.
> >> >  - create a localnet port for the logical switch
> >> >  - configure the ovn-bridge-mappings option in the OVS db.
> >> >
> >> > When the ovn-controller running in that 'chassis', detects
> >> > the Port_Binding row, it adds the necessary DHCPv4/v6 OF
> >> > flows. Since the packet enters the logical switch pipeline
> >> > via the localnet port, the inport register (reg14) is set
> >> > to the tunnel key of localnet port in the match conditions.
> >> >
> >> > In case the chassis goes down for some reason, it is the
> >> > responsibility of CMS to change the 'requested-chassis'
> >> > option to some other active chassis, so that it can serve
> >> > these requests.
> >> >
> >> > When the VM with the external port, sends an ARP request for
> >> > the router ips, only the chassis which has claimed the port,
> >> > will reply to the ARP requests. Rest of the chassis on
> >> > receiving these packets drop them in the ingress switch
> >> > datapath stage - S_SWITCH_IN_EXTERNAL_PORT which is just
> >> > before S_SWITCH_IN_L2_LKUP.
> >> >
> >> > This would guarantee that only the chassis which has claimed
> >> > the external ports will run the router datapath pipeline.
> >> >
> >> > Signed-off-by: Numan Siddique 
> >> > ---
> >> >
> >> > v3 -> v4
> >> > --
> >> >   * Updated the documention as per Han Zhou's suggestion.
> >> >
> >> > v2 -> v3
> >> > ---
> >> >   * Rebased
> >> >
> >> >  ovn/controller/binding.c|  15 +-
> >> >  ovn/controller/lflow.c  |  41 ++-
> >> >  ovn/controller/lflow.h  |   2 +
> >> >  ovn/controller/lport.c  |  26 ++
> >> >  ovn/controller/lport.h  |   5 +
> >> >  ovn/controller/ovn-controller.c |   6 +
> >> >  ovn/lib/ovn-util.c  |   1 +
> >> >  ovn/northd/ovn-northd.8.xml |  52 +++-
> >> >  ovn/northd/ovn-northd.c | 123 ++--
> >> >  ovn/ovn-architecture.7.xml  |  76 +
> >> >  ovn/ovn-nb.xml  |  44 +++
> >> >  tests/ovn.at| 530
> +++-
> >> >  12 files changed, 889 insertions(+), 32 deletions(-)
> >> >
> >> > diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
> >> > index 021ecddcf..ee396c93d 100644
> >> > --- a/ovn/controller/binding.c
> >> > +++ b/ovn/controller/binding.c
> >> > @@ -471,13 +471,26 @@ consider_local_datapath(struct ovsdb_idl_txn
> *ovnsb_idl_txn,
> >> >   * for them. */
> >> >  sset_add(local_lports, binding_rec->logical_port);
> >> >  our_chassis = false;
> >> > +} else if (!strcmp(binding_rec->type, "external")) {
> >> > +const char *chassis_id = smap_get(_rec->options,
> >> > +  "requested-chassis");
> >> > +our_chassis = chassis_id && (
> >> > +!strcmp(chassis_id, chassis_rec->name) ||
> >> > +!strcmp(chassis_id, chassis_rec->hostname));
> >> > +if (our_chassis) {
> >> > +add_local_datapath(sbrec_datapath_binding_by_key,
> >> > +   sbrec_port_binding_by_datapath,
> >> > +   sbrec_port_binding_by_name,
> >> > +   binding_rec->datapath, true,
> local_datapaths);
> >> > +}
> >> >  }
> >> >
> >> >  if (our_chassis
> >> >  || !strcmp(binding_rec->type, "patch")
> >> >  || !strcmp(binding_rec->type, "localport")
> >> >  || !strcmp(binding_rec->type, "vtep")
> >> > -|| !strcmp(binding_rec->type, "localnet")) {
> >> > +|| !strcmp(binding_rec->type, "localnet")
> >> > +|| !strcmp(binding_rec->type, "external")) {
> >>
> >> Why calling 

Re: [ovs-dev] [PATCH v4] ovn: Support a new Logical_Switch_Port.type - 'external'

2019-01-17 Thread Han Zhou
On Tue, Jan 15, 2019 at 10:24 AM Numan Siddique  wrote:
>
>
>
> On Tue, Jan 15, 2019 at 5:42 AM Han Zhou  wrote:
>>
>> Hi Numan,
>>
>> The feature looks very good overall. I have some more comments inlined.
>
>
> Thank Han for the review and the comments.
>
> You are right. The logical port's mac flaps too. I had to read the commit 
> message again to
> recall :)
>
>
>>
>> On Thu, Jan 10, 2019 at 12:37 PM  wrote:
>> >
>> > From: Numan Siddique 
>> >
>> > In the case of OpenStack + OVN, when the VMs are booted on
>> > hypervisors supporting SR-IOV nics, there are no OVS ports
>> > for these VMs. When these VMs sends DHCPv4, DHPCv6 or IPv6
>> > Router Solicitation requests, the local ovn-controller
>> > cannot reply to these packets. OpenStack Neutron dhcp agent
>> > service needs to be run to serve these requests.
>> >
>> > With the new logical port type - 'external', OVN itself can
>> > handle these requests avoiding the need to deploy any
>> > external services like neutron dhcp agent.
>> >
>> > To make use of this feature, CMS has to
>> >  - create a logical port for such VMs
>> >  - set the type to 'external'
>> >  - set requested-chassis="" in the options
>> >column.
>> >  - create a localnet port for the logical switch
>> >  - configure the ovn-bridge-mappings option in the OVS db.
>> >
>> > When the ovn-controller running in that 'chassis', detects
>> > the Port_Binding row, it adds the necessary DHCPv4/v6 OF
>> > flows. Since the packet enters the logical switch pipeline
>> > via the localnet port, the inport register (reg14) is set
>> > to the tunnel key of localnet port in the match conditions.
>> >
>> > In case the chassis goes down for some reason, it is the
>> > responsibility of CMS to change the 'requested-chassis'
>> > option to some other active chassis, so that it can serve
>> > these requests.
>> >
>> > When the VM with the external port, sends an ARP request for
>> > the router ips, only the chassis which has claimed the port,
>> > will reply to the ARP requests. Rest of the chassis on
>> > receiving these packets drop them in the ingress switch
>> > datapath stage - S_SWITCH_IN_EXTERNAL_PORT which is just
>> > before S_SWITCH_IN_L2_LKUP.
>> >
>> > This would guarantee that only the chassis which has claimed
>> > the external ports will run the router datapath pipeline.
>> >
>> > Signed-off-by: Numan Siddique 
>> > ---
>> >
>> > v3 -> v4
>> > --
>> >   * Updated the documention as per Han Zhou's suggestion.
>> >
>> > v2 -> v3
>> > ---
>> >   * Rebased
>> >
>> >  ovn/controller/binding.c|  15 +-
>> >  ovn/controller/lflow.c  |  41 ++-
>> >  ovn/controller/lflow.h  |   2 +
>> >  ovn/controller/lport.c  |  26 ++
>> >  ovn/controller/lport.h  |   5 +
>> >  ovn/controller/ovn-controller.c |   6 +
>> >  ovn/lib/ovn-util.c  |   1 +
>> >  ovn/northd/ovn-northd.8.xml |  52 +++-
>> >  ovn/northd/ovn-northd.c | 123 ++--
>> >  ovn/ovn-architecture.7.xml  |  76 +
>> >  ovn/ovn-nb.xml  |  44 +++
>> >  tests/ovn.at| 530 +++-
>> >  12 files changed, 889 insertions(+), 32 deletions(-)
>> >
>> > diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
>> > index 021ecddcf..ee396c93d 100644
>> > --- a/ovn/controller/binding.c
>> > +++ b/ovn/controller/binding.c
>> > @@ -471,13 +471,26 @@ consider_local_datapath(struct ovsdb_idl_txn 
>> > *ovnsb_idl_txn,
>> >   * for them. */
>> >  sset_add(local_lports, binding_rec->logical_port);
>> >  our_chassis = false;
>> > +} else if (!strcmp(binding_rec->type, "external")) {
>> > +const char *chassis_id = smap_get(_rec->options,
>> > +  "requested-chassis");
>> > +our_chassis = chassis_id && (
>> > +!strcmp(chassis_id, chassis_rec->name) ||
>> > +!strcmp(chassis_id, chassis_rec->hostname));
>> > +if (our_chassis) {
>> > +add_local_datapath(sbrec_datapath_binding_by_key,
>> > +   sbrec_port_binding_by_datapath,
>> > +   sbrec_port_binding_by_name,
>> > +   binding_rec->datapath, true, 
>> > local_datapaths);
>> > +}
>> >  }
>> >
>> >  if (our_chassis
>> >  || !strcmp(binding_rec->type, "patch")
>> >  || !strcmp(binding_rec->type, "localport")
>> >  || !strcmp(binding_rec->type, "vtep")
>> > -|| !strcmp(binding_rec->type, "localnet")) {
>> > +|| !strcmp(binding_rec->type, "localnet")
>> > +|| !strcmp(binding_rec->type, "external")) {
>>
>> Why calling update_local_lport_ids() when the type is external? I
>> think "our_chassis" is enough as the condition for "external" port to
>> be considered.
>
>
> Agree. I will address in v5.
>
>
>>
>>
>> >  update_local_lport_ids(local_lport_ids, binding_rec);
>> >  }
>> >
>> > diff --git 

Re: [ovs-dev] [PATCH v4] ovn: Support a new Logical_Switch_Port.type - 'external'

2019-01-15 Thread Numan Siddique
On Tue, Jan 15, 2019 at 5:42 AM Han Zhou  wrote:

> Hi Numan,
>
> The feature looks very good overall. I have some more comments inlined.
>

Thank Han for the review and the comments.

You are right. The logical port's mac flaps too. I had to read the commit
message again to
recall :)



> On Thu, Jan 10, 2019 at 12:37 PM  wrote:
> >
> > From: Numan Siddique 
> >
> > In the case of OpenStack + OVN, when the VMs are booted on
> > hypervisors supporting SR-IOV nics, there are no OVS ports
> > for these VMs. When these VMs sends DHCPv4, DHPCv6 or IPv6
> > Router Solicitation requests, the local ovn-controller
> > cannot reply to these packets. OpenStack Neutron dhcp agent
> > service needs to be run to serve these requests.
> >
> > With the new logical port type - 'external', OVN itself can
> > handle these requests avoiding the need to deploy any
> > external services like neutron dhcp agent.
> >
> > To make use of this feature, CMS has to
> >  - create a logical port for such VMs
> >  - set the type to 'external'
> >  - set requested-chassis="" in the options
> >column.
> >  - create a localnet port for the logical switch
> >  - configure the ovn-bridge-mappings option in the OVS db.
> >
> > When the ovn-controller running in that 'chassis', detects
> > the Port_Binding row, it adds the necessary DHCPv4/v6 OF
> > flows. Since the packet enters the logical switch pipeline
> > via the localnet port, the inport register (reg14) is set
> > to the tunnel key of localnet port in the match conditions.
> >
> > In case the chassis goes down for some reason, it is the
> > responsibility of CMS to change the 'requested-chassis'
> > option to some other active chassis, so that it can serve
> > these requests.
> >
> > When the VM with the external port, sends an ARP request for
> > the router ips, only the chassis which has claimed the port,
> > will reply to the ARP requests. Rest of the chassis on
> > receiving these packets drop them in the ingress switch
> > datapath stage - S_SWITCH_IN_EXTERNAL_PORT which is just
> > before S_SWITCH_IN_L2_LKUP.
> >
> > This would guarantee that only the chassis which has claimed
> > the external ports will run the router datapath pipeline.
> >
> > Signed-off-by: Numan Siddique 
> > ---
> >
> > v3 -> v4
> > --
> >   * Updated the documention as per Han Zhou's suggestion.
> >
> > v2 -> v3
> > ---
> >   * Rebased
> >
> >  ovn/controller/binding.c|  15 +-
> >  ovn/controller/lflow.c  |  41 ++-
> >  ovn/controller/lflow.h  |   2 +
> >  ovn/controller/lport.c  |  26 ++
> >  ovn/controller/lport.h  |   5 +
> >  ovn/controller/ovn-controller.c |   6 +
> >  ovn/lib/ovn-util.c  |   1 +
> >  ovn/northd/ovn-northd.8.xml |  52 +++-
> >  ovn/northd/ovn-northd.c | 123 ++--
> >  ovn/ovn-architecture.7.xml  |  76 +
> >  ovn/ovn-nb.xml  |  44 +++
> >  tests/ovn.at| 530 +++-
> >  12 files changed, 889 insertions(+), 32 deletions(-)
> >
> > diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
> > index 021ecddcf..ee396c93d 100644
> > --- a/ovn/controller/binding.c
> > +++ b/ovn/controller/binding.c
> > @@ -471,13 +471,26 @@ consider_local_datapath(struct ovsdb_idl_txn
> *ovnsb_idl_txn,
> >   * for them. */
> >  sset_add(local_lports, binding_rec->logical_port);
> >  our_chassis = false;
> > +} else if (!strcmp(binding_rec->type, "external")) {
> > +const char *chassis_id = smap_get(_rec->options,
> > +  "requested-chassis");
> > +our_chassis = chassis_id && (
> > +!strcmp(chassis_id, chassis_rec->name) ||
> > +!strcmp(chassis_id, chassis_rec->hostname));
> > +if (our_chassis) {
> > +add_local_datapath(sbrec_datapath_binding_by_key,
> > +   sbrec_port_binding_by_datapath,
> > +   sbrec_port_binding_by_name,
> > +   binding_rec->datapath, true,
> local_datapaths);
> > +}
> >  }
> >
> >  if (our_chassis
> >  || !strcmp(binding_rec->type, "patch")
> >  || !strcmp(binding_rec->type, "localport")
> >  || !strcmp(binding_rec->type, "vtep")
> > -|| !strcmp(binding_rec->type, "localnet")) {
> > +|| !strcmp(binding_rec->type, "localnet")
> > +|| !strcmp(binding_rec->type, "external")) {
>
> Why calling update_local_lport_ids() when the type is external? I
> think "our_chassis" is enough as the condition for "external" port to
> be considered.
>

Agree. I will address in v5.



>
> >  update_local_lport_ids(local_lport_ids, binding_rec);
> >  }
> >
> > diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c
> > index 8db81927e..98e8ed3b9 100644
> > --- a/ovn/controller/lflow.c
> > +++ b/ovn/controller/lflow.c
> > @@ -52,7 +52,10 @@ lflow_init(void)
> >  struct 

Re: [ovs-dev] [PATCH v4] ovn: Support a new Logical_Switch_Port.type - 'external'

2019-01-14 Thread Han Zhou
Hi Numan,

The feature looks very good overall. I have some more comments inlined.

On Thu, Jan 10, 2019 at 12:37 PM  wrote:
>
> From: Numan Siddique 
>
> In the case of OpenStack + OVN, when the VMs are booted on
> hypervisors supporting SR-IOV nics, there are no OVS ports
> for these VMs. When these VMs sends DHCPv4, DHPCv6 or IPv6
> Router Solicitation requests, the local ovn-controller
> cannot reply to these packets. OpenStack Neutron dhcp agent
> service needs to be run to serve these requests.
>
> With the new logical port type - 'external', OVN itself can
> handle these requests avoiding the need to deploy any
> external services like neutron dhcp agent.
>
> To make use of this feature, CMS has to
>  - create a logical port for such VMs
>  - set the type to 'external'
>  - set requested-chassis="" in the options
>column.
>  - create a localnet port for the logical switch
>  - configure the ovn-bridge-mappings option in the OVS db.
>
> When the ovn-controller running in that 'chassis', detects
> the Port_Binding row, it adds the necessary DHCPv4/v6 OF
> flows. Since the packet enters the logical switch pipeline
> via the localnet port, the inport register (reg14) is set
> to the tunnel key of localnet port in the match conditions.
>
> In case the chassis goes down for some reason, it is the
> responsibility of CMS to change the 'requested-chassis'
> option to some other active chassis, so that it can serve
> these requests.
>
> When the VM with the external port, sends an ARP request for
> the router ips, only the chassis which has claimed the port,
> will reply to the ARP requests. Rest of the chassis on
> receiving these packets drop them in the ingress switch
> datapath stage - S_SWITCH_IN_EXTERNAL_PORT which is just
> before S_SWITCH_IN_L2_LKUP.
>
> This would guarantee that only the chassis which has claimed
> the external ports will run the router datapath pipeline.
>
> Signed-off-by: Numan Siddique 
> ---
>
> v3 -> v4
> --
>   * Updated the documention as per Han Zhou's suggestion.
>
> v2 -> v3
> ---
>   * Rebased
>
>  ovn/controller/binding.c|  15 +-
>  ovn/controller/lflow.c  |  41 ++-
>  ovn/controller/lflow.h  |   2 +
>  ovn/controller/lport.c  |  26 ++
>  ovn/controller/lport.h  |   5 +
>  ovn/controller/ovn-controller.c |   6 +
>  ovn/lib/ovn-util.c  |   1 +
>  ovn/northd/ovn-northd.8.xml |  52 +++-
>  ovn/northd/ovn-northd.c | 123 ++--
>  ovn/ovn-architecture.7.xml  |  76 +
>  ovn/ovn-nb.xml  |  44 +++
>  tests/ovn.at| 530 +++-
>  12 files changed, 889 insertions(+), 32 deletions(-)
>
> diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
> index 021ecddcf..ee396c93d 100644
> --- a/ovn/controller/binding.c
> +++ b/ovn/controller/binding.c
> @@ -471,13 +471,26 @@ consider_local_datapath(struct ovsdb_idl_txn 
> *ovnsb_idl_txn,
>   * for them. */
>  sset_add(local_lports, binding_rec->logical_port);
>  our_chassis = false;
> +} else if (!strcmp(binding_rec->type, "external")) {
> +const char *chassis_id = smap_get(_rec->options,
> +  "requested-chassis");
> +our_chassis = chassis_id && (
> +!strcmp(chassis_id, chassis_rec->name) ||
> +!strcmp(chassis_id, chassis_rec->hostname));
> +if (our_chassis) {
> +add_local_datapath(sbrec_datapath_binding_by_key,
> +   sbrec_port_binding_by_datapath,
> +   sbrec_port_binding_by_name,
> +   binding_rec->datapath, true, local_datapaths);
> +}
>  }
>
>  if (our_chassis
>  || !strcmp(binding_rec->type, "patch")
>  || !strcmp(binding_rec->type, "localport")
>  || !strcmp(binding_rec->type, "vtep")
> -|| !strcmp(binding_rec->type, "localnet")) {
> +|| !strcmp(binding_rec->type, "localnet")
> +|| !strcmp(binding_rec->type, "external")) {

Why calling update_local_lport_ids() when the type is external? I
think "our_chassis" is enough as the condition for "external" port to
be considered.

>  update_local_lport_ids(local_lport_ids, binding_rec);
>  }
>
> diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c
> index 8db81927e..98e8ed3b9 100644
> --- a/ovn/controller/lflow.c
> +++ b/ovn/controller/lflow.c
> @@ -52,7 +52,10 @@ lflow_init(void)
>  struct lookup_port_aux {
>  struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath;
>  struct ovsdb_idl_index *sbrec_port_binding_by_name;
> +struct ovsdb_idl_index *sbrec_port_binding_by_type;
> +struct ovsdb_idl_index *sbrec_datapath_binding_by_key;
>  const struct sbrec_datapath_binding *dp;
> +const struct sbrec_chassis *chassis;
>  };
>
>  struct condition_aux {
> @@ -66,6 +69,8 @@ static void consider_logical_flow(
>  struct 

[ovs-dev] [PATCH v4] ovn: Support a new Logical_Switch_Port.type - 'external'

2019-01-10 Thread nusiddiq
From: Numan Siddique 

In the case of OpenStack + OVN, when the VMs are booted on
hypervisors supporting SR-IOV nics, there are no OVS ports
for these VMs. When these VMs sends DHCPv4, DHPCv6 or IPv6
Router Solicitation requests, the local ovn-controller
cannot reply to these packets. OpenStack Neutron dhcp agent
service needs to be run to serve these requests.

With the new logical port type - 'external', OVN itself can
handle these requests avoiding the need to deploy any
external services like neutron dhcp agent.

To make use of this feature, CMS has to
 - create a logical port for such VMs
 - set the type to 'external'
 - set requested-chassis="" in the options
   column.
 - create a localnet port for the logical switch
 - configure the ovn-bridge-mappings option in the OVS db.

When the ovn-controller running in that 'chassis', detects
the Port_Binding row, it adds the necessary DHCPv4/v6 OF
flows. Since the packet enters the logical switch pipeline
via the localnet port, the inport register (reg14) is set
to the tunnel key of localnet port in the match conditions.

In case the chassis goes down for some reason, it is the
responsibility of CMS to change the 'requested-chassis'
option to some other active chassis, so that it can serve
these requests.

When the VM with the external port, sends an ARP request for
the router ips, only the chassis which has claimed the port,
will reply to the ARP requests. Rest of the chassis on
receiving these packets drop them in the ingress switch
datapath stage - S_SWITCH_IN_EXTERNAL_PORT which is just
before S_SWITCH_IN_L2_LKUP.

This would guarantee that only the chassis which has claimed
the external ports will run the router datapath pipeline.

Signed-off-by: Numan Siddique 
---

v3 -> v4
--
  * Updated the documention as per Han Zhou's suggestion.

v2 -> v3
---
  * Rebased 

 ovn/controller/binding.c|  15 +-
 ovn/controller/lflow.c  |  41 ++-
 ovn/controller/lflow.h  |   2 +
 ovn/controller/lport.c  |  26 ++
 ovn/controller/lport.h  |   5 +
 ovn/controller/ovn-controller.c |   6 +
 ovn/lib/ovn-util.c  |   1 +
 ovn/northd/ovn-northd.8.xml |  52 +++-
 ovn/northd/ovn-northd.c | 123 ++--
 ovn/ovn-architecture.7.xml  |  76 +
 ovn/ovn-nb.xml  |  44 +++
 tests/ovn.at| 530 +++-
 12 files changed, 889 insertions(+), 32 deletions(-)

diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
index 021ecddcf..ee396c93d 100644
--- a/ovn/controller/binding.c
+++ b/ovn/controller/binding.c
@@ -471,13 +471,26 @@ consider_local_datapath(struct ovsdb_idl_txn 
*ovnsb_idl_txn,
  * for them. */
 sset_add(local_lports, binding_rec->logical_port);
 our_chassis = false;
+} else if (!strcmp(binding_rec->type, "external")) {
+const char *chassis_id = smap_get(_rec->options,
+  "requested-chassis");
+our_chassis = chassis_id && (
+!strcmp(chassis_id, chassis_rec->name) ||
+!strcmp(chassis_id, chassis_rec->hostname));
+if (our_chassis) {
+add_local_datapath(sbrec_datapath_binding_by_key,
+   sbrec_port_binding_by_datapath,
+   sbrec_port_binding_by_name,
+   binding_rec->datapath, true, local_datapaths);
+}
 }
 
 if (our_chassis
 || !strcmp(binding_rec->type, "patch")
 || !strcmp(binding_rec->type, "localport")
 || !strcmp(binding_rec->type, "vtep")
-|| !strcmp(binding_rec->type, "localnet")) {
+|| !strcmp(binding_rec->type, "localnet")
+|| !strcmp(binding_rec->type, "external")) {
 update_local_lport_ids(local_lport_ids, binding_rec);
 }
 
diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c
index 8db81927e..98e8ed3b9 100644
--- a/ovn/controller/lflow.c
+++ b/ovn/controller/lflow.c
@@ -52,7 +52,10 @@ lflow_init(void)
 struct lookup_port_aux {
 struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath;
 struct ovsdb_idl_index *sbrec_port_binding_by_name;
+struct ovsdb_idl_index *sbrec_port_binding_by_type;
+struct ovsdb_idl_index *sbrec_datapath_binding_by_key;
 const struct sbrec_datapath_binding *dp;
+const struct sbrec_chassis *chassis;
 };
 
 struct condition_aux {
@@ -66,6 +69,8 @@ static void consider_logical_flow(
 struct ovsdb_idl_index *sbrec_chassis_by_name,
 struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath,
 struct ovsdb_idl_index *sbrec_port_binding_by_name,
+struct ovsdb_idl_index *sbrec_port_binding_by_type,
+struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
 const struct sbrec_logical_flow *,
 const struct hmap *local_datapaths,
 const struct sbrec_chassis *,
@@ -89,8 +94,24 @@ lookup_port_cb(const void *aux_, const char *port_name, 
unsigned int *portp)