diff mbox series

[ovs-dev,v3] controller: add ovn-set-local-ip option

Message ID 20220218183814.2976667-1-odivlad@gmail.com
State Accepted
Headers show
Series [ovs-dev,v3] controller: add ovn-set-local-ip option | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed
ovsrobot/github-robot-_ovn-kubernetes fail github build: failed

Commit Message

Vladislav Odintsov Feb. 18, 2022, 6:38 p.m. UTC
When transport node has multiple interfaces (vlans) and
ovn-encap-ip on different hosts need to be configured
from different VLANs source IP for encapsulated packet
can be not the same, which is expected by remote system.

Explicitely setting local_ip resolves such problem.

Signed-off-by: Vladislav Odintsov <odivlad@gmail.com>
---
 controller/encaps.c             | 43 +++++++++++++++++++++------------
 controller/ovn-controller.8.xml |  7 ++++++
 tests/ovn-controller.at         |  9 +++++++
 3 files changed, 44 insertions(+), 15 deletions(-)

Comments

Han Zhou Feb. 19, 2022, 6:31 a.m. UTC | #1
On Fri, Feb 18, 2022 at 10:38 AM Vladislav Odintsov <odivlad@gmail.com>
wrote:
>
> When transport node has multiple interfaces (vlans) and
> ovn-encap-ip on different hosts need to be configured
> from different VLANs source IP for encapsulated packet
> can be not the same, which is expected by remote system.
>
> Explicitely setting local_ip resolves such problem.
>
> Signed-off-by: Vladislav Odintsov <odivlad@gmail.com>
> ---
>  controller/encaps.c             | 43 +++++++++++++++++++++------------
>  controller/ovn-controller.8.xml |  7 ++++++
>  tests/ovn-controller.at         |  9 +++++++
>  3 files changed, 44 insertions(+), 15 deletions(-)
>
> diff --git a/controller/encaps.c b/controller/encaps.c
> index 66e0cd8cd..8e6d290c1 100644
> --- a/controller/encaps.c
> +++ b/controller/encaps.c
> @@ -23,6 +23,7 @@
>  #include "openvswitch/vlog.h"
>  #include "lib/ovn-sb-idl.h"
>  #include "ovn-controller.h"
> +#include "smap.h"
>
>  VLOG_DEFINE_THIS_MODULE(encaps);
>
> @@ -176,8 +177,31 @@ tunnel_add(struct tunnel_ctx *tc, const struct
sbrec_sb_global *sbg,
>          smap_add(&options, "dst_port", dst_port);
>      }
>
> +    const struct ovsrec_open_vswitch *cfg =
> +        ovsrec_open_vswitch_table_first(ovs_table);
> +
> +    bool set_local_ip = false;
> +    if (cfg) {
> +        /* If the tos option is configured, get it */
> +        const char *encap_tos = smap_get_def(&cfg->external_ids,
> +           "ovn-encap-tos", "none");
> +
> +        if (encap_tos && strcmp(encap_tos, "none")) {
> +            smap_add(&options, "tos", encap_tos);
> +        }
> +
> +        /* If ovn-set-local-ip option is configured, get it */
> +        set_local_ip = smap_get_bool(&cfg->external_ids,
"ovn-set-local-ip",
> +                                     false);
> +    }
> +
>      /* Add auth info if ipsec is enabled. */
>      if (sbg->ipsec) {
> +        set_local_ip = true;
> +        smap_add(&options, "remote_name", new_chassis_id);
> +    }
> +
> +    if (set_local_ip) {
>          const struct sbrec_chassis *this_chassis = tc->this_chassis;
>          const char *local_ip = NULL;
>
> @@ -187,8 +211,10 @@ tunnel_add(struct tunnel_ctx *tc, const struct
sbrec_sb_global *sbg,
>           */
>          for (int i = 0; i < this_chassis->n_encaps; i++) {
>              if (local_ip && strcmp(local_ip,
this_chassis->encaps[i]->ip)) {
> -                VLOG_ERR("ovn-encap-ip has been configured as a list.
This "
> -                         "is unsupported for IPsec.");
> +                static struct vlog_rate_limit rl =
VLOG_RATE_LIMIT_INIT(5, 1);
> +                VLOG_ERR_RL(&rl, "ovn-encap-ip has been configured as a
list. "
> +                            "This is unsupported for IPsec and explicit "
> +                            "local_ip configuration.");
>                  /* No need to loop further as we know this condition has
been
>                   * hit */
>                  break;
> @@ -200,19 +226,6 @@ tunnel_add(struct tunnel_ctx *tc, const struct
sbrec_sb_global *sbg,
>          if (local_ip) {
>              smap_add(&options, "local_ip", local_ip);
>          }
> -        smap_add(&options, "remote_name", new_chassis_id);
> -    }
> -
> -    const struct ovsrec_open_vswitch *cfg =
> -        ovsrec_open_vswitch_table_first(ovs_table);
> -    /* If the tos option is configured, get it */
> -    if (cfg) {
> -        const char *encap_tos = smap_get_def(&cfg->external_ids,
> -           "ovn-encap-tos", "none");
> -
> -        if (encap_tos && strcmp(encap_tos, "none")) {
> -            smap_add(&options, "tos", encap_tos);
> -        }
>      }
>
>      /* If there's an existing chassis record that does not need any
change,
> diff --git a/controller/ovn-controller.8.xml
b/controller/ovn-controller.8.xml
> index e9708fe64..cc9a7d1c2 100644
> --- a/controller/ovn-controller.8.xml
> +++ b/controller/ovn-controller.8.xml
> @@ -304,6 +304,13 @@
>          of how many entries there are in the cache.  By default this is
set to
>          30000 (30 seconds).
>        </dd>
> +      <dt><code>external_ids:ovn-set-local-ip</code></dt>
> +      <dd>
> +        The boolean flag indicates if <code>ovn-controller</code> when
create
> +        tunnel ports should set <code>local_ip</code> parameter.  Can be
> +        heplful to pin source outer IP for the tunnel when multiple
interfaces
> +        are used on the host for overlay traffic.
> +      </dd>
>      </dl>
>
>      <p>
> diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
> index e99eec1d6..89ae2c9e1 100644
> --- a/tests/ovn-controller.at
> +++ b/tests/ovn-controller.at
> @@ -298,6 +298,15 @@ OVS_WAIT_UNTIL([check_tunnel_property type geneve])
>  ovs-vsctl del-port ovn-fakech-0
>  OVS_WAIT_UNTIL([check_tunnel_property type geneve])
>
> +# set `ovn-set-local-ip` option to true and check if tunnel parameters
> +OVS_WAIT_WHILE([check_tunnel_property options:local_ip
"\"192.168.0.1\""])
> +ovs-vsctl set open . external_ids:ovn-set-local-ip=true
> +OVS_WAIT_UNTIL([check_tunnel_property options:local_ip
"\"192.168.0.1\""])
> +
> +# Change the local_ip on the OVS side and check than OVN fixes it
> +ovs-vsctl set interface ovn-fakech-0 options:local_ip="1.1.1.1"
> +OVS_WAIT_UNTIL([check_tunnel_property options:local_ip
"\"192.168.0.1\""])
> +
>  # Gracefully terminate daemons
>  OVN_CLEANUP_SBOX([hv])
>  OVN_CLEANUP_VSWITCH([main])
> --
> 2.26.3
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Thanks Vladislav.

Acked-by: Han Zhou <hzhou@ovn.org>

I will let Numan confirm again.
Numan Siddique Feb. 22, 2022, 3:41 p.m. UTC | #2
On Sat, Feb 19, 2022 at 1:38 AM Han Zhou <hzhou@ovn.org> wrote:
>
> On Fri, Feb 18, 2022 at 10:38 AM Vladislav Odintsov <odivlad@gmail.com>
> wrote:
> >
> > When transport node has multiple interfaces (vlans) and
> > ovn-encap-ip on different hosts need to be configured
> > from different VLANs source IP for encapsulated packet
> > can be not the same, which is expected by remote system.
> >
> > Explicitely setting local_ip resolves such problem.
> >
> > Signed-off-by: Vladislav Odintsov <odivlad@gmail.com>
> > ---
> >  controller/encaps.c             | 43 +++++++++++++++++++++------------
> >  controller/ovn-controller.8.xml |  7 ++++++
> >  tests/ovn-controller.at         |  9 +++++++
> >  3 files changed, 44 insertions(+), 15 deletions(-)
> >
> > diff --git a/controller/encaps.c b/controller/encaps.c
> > index 66e0cd8cd..8e6d290c1 100644
> > --- a/controller/encaps.c
> > +++ b/controller/encaps.c
> > @@ -23,6 +23,7 @@
> >  #include "openvswitch/vlog.h"
> >  #include "lib/ovn-sb-idl.h"
> >  #include "ovn-controller.h"
> > +#include "smap.h"
> >
> >  VLOG_DEFINE_THIS_MODULE(encaps);
> >
> > @@ -176,8 +177,31 @@ tunnel_add(struct tunnel_ctx *tc, const struct
> sbrec_sb_global *sbg,
> >          smap_add(&options, "dst_port", dst_port);
> >      }
> >
> > +    const struct ovsrec_open_vswitch *cfg =
> > +        ovsrec_open_vswitch_table_first(ovs_table);
> > +
> > +    bool set_local_ip = false;
> > +    if (cfg) {
> > +        /* If the tos option is configured, get it */
> > +        const char *encap_tos = smap_get_def(&cfg->external_ids,
> > +           "ovn-encap-tos", "none");
> > +
> > +        if (encap_tos && strcmp(encap_tos, "none")) {
> > +            smap_add(&options, "tos", encap_tos);
> > +        }
> > +
> > +        /* If ovn-set-local-ip option is configured, get it */
> > +        set_local_ip = smap_get_bool(&cfg->external_ids,
> "ovn-set-local-ip",
> > +                                     false);
> > +    }
> > +
> >      /* Add auth info if ipsec is enabled. */
> >      if (sbg->ipsec) {
> > +        set_local_ip = true;
> > +        smap_add(&options, "remote_name", new_chassis_id);
> > +    }
> > +
> > +    if (set_local_ip) {
> >          const struct sbrec_chassis *this_chassis = tc->this_chassis;
> >          const char *local_ip = NULL;
> >
> > @@ -187,8 +211,10 @@ tunnel_add(struct tunnel_ctx *tc, const struct
> sbrec_sb_global *sbg,
> >           */
> >          for (int i = 0; i < this_chassis->n_encaps; i++) {
> >              if (local_ip && strcmp(local_ip,
> this_chassis->encaps[i]->ip)) {
> > -                VLOG_ERR("ovn-encap-ip has been configured as a list.
> This "
> > -                         "is unsupported for IPsec.");
> > +                static struct vlog_rate_limit rl =
> VLOG_RATE_LIMIT_INIT(5, 1);
> > +                VLOG_ERR_RL(&rl, "ovn-encap-ip has been configured as a
> list. "
> > +                            "This is unsupported for IPsec and explicit "
> > +                            "local_ip configuration.");
> >                  /* No need to loop further as we know this condition has
> been
> >                   * hit */
> >                  break;
> > @@ -200,19 +226,6 @@ tunnel_add(struct tunnel_ctx *tc, const struct
> sbrec_sb_global *sbg,
> >          if (local_ip) {
> >              smap_add(&options, "local_ip", local_ip);
> >          }
> > -        smap_add(&options, "remote_name", new_chassis_id);
> > -    }
> > -
> > -    const struct ovsrec_open_vswitch *cfg =
> > -        ovsrec_open_vswitch_table_first(ovs_table);
> > -    /* If the tos option is configured, get it */
> > -    if (cfg) {
> > -        const char *encap_tos = smap_get_def(&cfg->external_ids,
> > -           "ovn-encap-tos", "none");
> > -
> > -        if (encap_tos && strcmp(encap_tos, "none")) {
> > -            smap_add(&options, "tos", encap_tos);
> > -        }
> >      }
> >
> >      /* If there's an existing chassis record that does not need any
> change,
> > diff --git a/controller/ovn-controller.8.xml
> b/controller/ovn-controller.8.xml
> > index e9708fe64..cc9a7d1c2 100644
> > --- a/controller/ovn-controller.8.xml
> > +++ b/controller/ovn-controller.8.xml
> > @@ -304,6 +304,13 @@
> >          of how many entries there are in the cache.  By default this is
> set to
> >          30000 (30 seconds).
> >        </dd>
> > +      <dt><code>external_ids:ovn-set-local-ip</code></dt>
> > +      <dd>
> > +        The boolean flag indicates if <code>ovn-controller</code> when
> create
> > +        tunnel ports should set <code>local_ip</code> parameter.  Can be
> > +        heplful to pin source outer IP for the tunnel when multiple
> interfaces
> > +        are used on the host for overlay traffic.
> > +      </dd>
> >      </dl>
> >
> >      <p>
> > diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
> > index e99eec1d6..89ae2c9e1 100644
> > --- a/tests/ovn-controller.at
> > +++ b/tests/ovn-controller.at
> > @@ -298,6 +298,15 @@ OVS_WAIT_UNTIL([check_tunnel_property type geneve])
> >  ovs-vsctl del-port ovn-fakech-0
> >  OVS_WAIT_UNTIL([check_tunnel_property type geneve])
> >
> > +# set `ovn-set-local-ip` option to true and check if tunnel parameters
> > +OVS_WAIT_WHILE([check_tunnel_property options:local_ip
> "\"192.168.0.1\""])
> > +ovs-vsctl set open . external_ids:ovn-set-local-ip=true
> > +OVS_WAIT_UNTIL([check_tunnel_property options:local_ip
> "\"192.168.0.1\""])
> > +
> > +# Change the local_ip on the OVS side and check than OVN fixes it
> > +ovs-vsctl set interface ovn-fakech-0 options:local_ip="1.1.1.1"
> > +OVS_WAIT_UNTIL([check_tunnel_property options:local_ip
> "\"192.168.0.1\""])
> > +
> >  # Gracefully terminate daemons
> >  OVN_CLEANUP_SBOX([hv])
> >  OVN_CLEANUP_VSWITCH([main])
> > --
> > 2.26.3
> >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
> Thanks Vladislav.
>
> Acked-by: Han Zhou <hzhou@ovn.org>
>
> I will let Numan confirm again.

Thanks.  I applied the patch to the main branch.

Numan

> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Vladislav Odintsov Feb. 22, 2022, 3:49 p.m. UTC | #3
Thanks Numan.

Regards,
Vladislav Odintsov

> On 22 Feb 2022, at 18:41, Numan Siddique <numans@ovn.org> wrote:
> 
> On Sat, Feb 19, 2022 at 1:38 AM Han Zhou <hzhou@ovn.org> wrote:
>> 
>> On Fri, Feb 18, 2022 at 10:38 AM Vladislav Odintsov <odivlad@gmail.com>
>> wrote:
>>> 
>>> When transport node has multiple interfaces (vlans) and
>>> ovn-encap-ip on different hosts need to be configured
>>> from different VLANs source IP for encapsulated packet
>>> can be not the same, which is expected by remote system.
>>> 
>>> Explicitely setting local_ip resolves such problem.
>>> 
>>> Signed-off-by: Vladislav Odintsov <odivlad@gmail.com>
>>> ---
>>> controller/encaps.c             | 43 +++++++++++++++++++++------------
>>> controller/ovn-controller.8.xml |  7 ++++++
>>> tests/ovn-controller.at         |  9 +++++++
>>> 3 files changed, 44 insertions(+), 15 deletions(-)
>>> 
>>> diff --git a/controller/encaps.c b/controller/encaps.c
>>> index 66e0cd8cd..8e6d290c1 100644
>>> --- a/controller/encaps.c
>>> +++ b/controller/encaps.c
>>> @@ -23,6 +23,7 @@
>>> #include "openvswitch/vlog.h"
>>> #include "lib/ovn-sb-idl.h"
>>> #include "ovn-controller.h"
>>> +#include "smap.h"
>>> 
>>> VLOG_DEFINE_THIS_MODULE(encaps);
>>> 
>>> @@ -176,8 +177,31 @@ tunnel_add(struct tunnel_ctx *tc, const struct
>> sbrec_sb_global *sbg,
>>>         smap_add(&options, "dst_port", dst_port);
>>>     }
>>> 
>>> +    const struct ovsrec_open_vswitch *cfg =
>>> +        ovsrec_open_vswitch_table_first(ovs_table);
>>> +
>>> +    bool set_local_ip = false;
>>> +    if (cfg) {
>>> +        /* If the tos option is configured, get it */
>>> +        const char *encap_tos = smap_get_def(&cfg->external_ids,
>>> +           "ovn-encap-tos", "none");
>>> +
>>> +        if (encap_tos && strcmp(encap_tos, "none")) {
>>> +            smap_add(&options, "tos", encap_tos);
>>> +        }
>>> +
>>> +        /* If ovn-set-local-ip option is configured, get it */
>>> +        set_local_ip = smap_get_bool(&cfg->external_ids,
>> "ovn-set-local-ip",
>>> +                                     false);
>>> +    }
>>> +
>>>     /* Add auth info if ipsec is enabled. */
>>>     if (sbg->ipsec) {
>>> +        set_local_ip = true;
>>> +        smap_add(&options, "remote_name", new_chassis_id);
>>> +    }
>>> +
>>> +    if (set_local_ip) {
>>>         const struct sbrec_chassis *this_chassis = tc->this_chassis;
>>>         const char *local_ip = NULL;
>>> 
>>> @@ -187,8 +211,10 @@ tunnel_add(struct tunnel_ctx *tc, const struct
>> sbrec_sb_global *sbg,
>>>          */
>>>         for (int i = 0; i < this_chassis->n_encaps; i++) {
>>>             if (local_ip && strcmp(local_ip,
>> this_chassis->encaps[i]->ip)) {
>>> -                VLOG_ERR("ovn-encap-ip has been configured as a list.
>> This "
>>> -                         "is unsupported for IPsec.");
>>> +                static struct vlog_rate_limit rl =
>> VLOG_RATE_LIMIT_INIT(5, 1);
>>> +                VLOG_ERR_RL(&rl, "ovn-encap-ip has been configured as a
>> list. "
>>> +                            "This is unsupported for IPsec and explicit "
>>> +                            "local_ip configuration.");
>>>                 /* No need to loop further as we know this condition has
>> been
>>>                  * hit */
>>>                 break;
>>> @@ -200,19 +226,6 @@ tunnel_add(struct tunnel_ctx *tc, const struct
>> sbrec_sb_global *sbg,
>>>         if (local_ip) {
>>>             smap_add(&options, "local_ip", local_ip);
>>>         }
>>> -        smap_add(&options, "remote_name", new_chassis_id);
>>> -    }
>>> -
>>> -    const struct ovsrec_open_vswitch *cfg =
>>> -        ovsrec_open_vswitch_table_first(ovs_table);
>>> -    /* If the tos option is configured, get it */
>>> -    if (cfg) {
>>> -        const char *encap_tos = smap_get_def(&cfg->external_ids,
>>> -           "ovn-encap-tos", "none");
>>> -
>>> -        if (encap_tos && strcmp(encap_tos, "none")) {
>>> -            smap_add(&options, "tos", encap_tos);
>>> -        }
>>>     }
>>> 
>>>     /* If there's an existing chassis record that does not need any
>> change,
>>> diff --git a/controller/ovn-controller.8.xml
>> b/controller/ovn-controller.8.xml
>>> index e9708fe64..cc9a7d1c2 100644
>>> --- a/controller/ovn-controller.8.xml
>>> +++ b/controller/ovn-controller.8.xml
>>> @@ -304,6 +304,13 @@
>>>         of how many entries there are in the cache.  By default this is
>> set to
>>>         30000 (30 seconds).
>>>       </dd>
>>> +      <dt><code>external_ids:ovn-set-local-ip</code></dt>
>>> +      <dd>
>>> +        The boolean flag indicates if <code>ovn-controller</code> when
>> create
>>> +        tunnel ports should set <code>local_ip</code> parameter.  Can be
>>> +        heplful to pin source outer IP for the tunnel when multiple
>> interfaces
>>> +        are used on the host for overlay traffic.
>>> +      </dd>
>>>     </dl>
>>> 
>>>     <p>
>>> diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
>>> index e99eec1d6..89ae2c9e1 100644
>>> --- a/tests/ovn-controller.at
>>> +++ b/tests/ovn-controller.at
>>> @@ -298,6 +298,15 @@ OVS_WAIT_UNTIL([check_tunnel_property type geneve])
>>> ovs-vsctl del-port ovn-fakech-0
>>> OVS_WAIT_UNTIL([check_tunnel_property type geneve])
>>> 
>>> +# set `ovn-set-local-ip` option to true and check if tunnel parameters
>>> +OVS_WAIT_WHILE([check_tunnel_property options:local_ip
>> "\"192.168.0.1\""])
>>> +ovs-vsctl set open . external_ids:ovn-set-local-ip=true
>>> +OVS_WAIT_UNTIL([check_tunnel_property options:local_ip
>> "\"192.168.0.1\""])
>>> +
>>> +# Change the local_ip on the OVS side and check than OVN fixes it
>>> +ovs-vsctl set interface ovn-fakech-0 options:local_ip="1.1.1.1"
>>> +OVS_WAIT_UNTIL([check_tunnel_property options:local_ip
>> "\"192.168.0.1\""])
>>> +
>>> # Gracefully terminate daemons
>>> OVN_CLEANUP_SBOX([hv])
>>> OVN_CLEANUP_VSWITCH([main])
>>> --
>>> 2.26.3
>>> 
>>> _______________________________________________
>>> dev mailing list
>>> dev@openvswitch.org
>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>> 
>> Thanks Vladislav.
>> 
>> Acked-by: Han Zhou <hzhou@ovn.org>
>> 
>> I will let Numan confirm again.
> 
> Thanks.  I applied the patch to the main branch.
> 
> Numan
> 
>> _______________________________________________
>> dev mailing list
>> dev@openvswitch.org
>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>> 
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
diff mbox series

Patch

diff --git a/controller/encaps.c b/controller/encaps.c
index 66e0cd8cd..8e6d290c1 100644
--- a/controller/encaps.c
+++ b/controller/encaps.c
@@ -23,6 +23,7 @@ 
 #include "openvswitch/vlog.h"
 #include "lib/ovn-sb-idl.h"
 #include "ovn-controller.h"
+#include "smap.h"
 
 VLOG_DEFINE_THIS_MODULE(encaps);
 
@@ -176,8 +177,31 @@  tunnel_add(struct tunnel_ctx *tc, const struct sbrec_sb_global *sbg,
         smap_add(&options, "dst_port", dst_port);
     }
 
+    const struct ovsrec_open_vswitch *cfg =
+        ovsrec_open_vswitch_table_first(ovs_table);
+
+    bool set_local_ip = false;
+    if (cfg) {
+        /* If the tos option is configured, get it */
+        const char *encap_tos = smap_get_def(&cfg->external_ids,
+           "ovn-encap-tos", "none");
+
+        if (encap_tos && strcmp(encap_tos, "none")) {
+            smap_add(&options, "tos", encap_tos);
+        }
+
+        /* If ovn-set-local-ip option is configured, get it */
+        set_local_ip = smap_get_bool(&cfg->external_ids, "ovn-set-local-ip",
+                                     false);
+    }
+
     /* Add auth info if ipsec is enabled. */
     if (sbg->ipsec) {
+        set_local_ip = true;
+        smap_add(&options, "remote_name", new_chassis_id);
+    }
+
+    if (set_local_ip) {
         const struct sbrec_chassis *this_chassis = tc->this_chassis;
         const char *local_ip = NULL;
 
@@ -187,8 +211,10 @@  tunnel_add(struct tunnel_ctx *tc, const struct sbrec_sb_global *sbg,
          */
         for (int i = 0; i < this_chassis->n_encaps; i++) {
             if (local_ip && strcmp(local_ip, this_chassis->encaps[i]->ip)) {
-                VLOG_ERR("ovn-encap-ip has been configured as a list. This "
-                         "is unsupported for IPsec.");
+                static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+                VLOG_ERR_RL(&rl, "ovn-encap-ip has been configured as a list. "
+                            "This is unsupported for IPsec and explicit "
+                            "local_ip configuration.");
                 /* No need to loop further as we know this condition has been
                  * hit */
                 break;
@@ -200,19 +226,6 @@  tunnel_add(struct tunnel_ctx *tc, const struct sbrec_sb_global *sbg,
         if (local_ip) {
             smap_add(&options, "local_ip", local_ip);
         }
-        smap_add(&options, "remote_name", new_chassis_id);
-    }
-
-    const struct ovsrec_open_vswitch *cfg =
-        ovsrec_open_vswitch_table_first(ovs_table);
-    /* If the tos option is configured, get it */
-    if (cfg) {
-        const char *encap_tos = smap_get_def(&cfg->external_ids,
-           "ovn-encap-tos", "none");
-
-        if (encap_tos && strcmp(encap_tos, "none")) {
-            smap_add(&options, "tos", encap_tos);
-        }
     }
 
     /* If there's an existing chassis record that does not need any change,
diff --git a/controller/ovn-controller.8.xml b/controller/ovn-controller.8.xml
index e9708fe64..cc9a7d1c2 100644
--- a/controller/ovn-controller.8.xml
+++ b/controller/ovn-controller.8.xml
@@ -304,6 +304,13 @@ 
         of how many entries there are in the cache.  By default this is set to
         30000 (30 seconds).
       </dd>
+      <dt><code>external_ids:ovn-set-local-ip</code></dt>
+      <dd>
+        The boolean flag indicates if <code>ovn-controller</code> when create
+        tunnel ports should set <code>local_ip</code> parameter.  Can be
+        heplful to pin source outer IP for the tunnel when multiple interfaces
+        are used on the host for overlay traffic.
+      </dd>
     </dl>
 
     <p>
diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at
index e99eec1d6..89ae2c9e1 100644
--- a/tests/ovn-controller.at
+++ b/tests/ovn-controller.at
@@ -298,6 +298,15 @@  OVS_WAIT_UNTIL([check_tunnel_property type geneve])
 ovs-vsctl del-port ovn-fakech-0
 OVS_WAIT_UNTIL([check_tunnel_property type geneve])
 
+# set `ovn-set-local-ip` option to true and check if tunnel parameters
+OVS_WAIT_WHILE([check_tunnel_property options:local_ip "\"192.168.0.1\""])
+ovs-vsctl set open . external_ids:ovn-set-local-ip=true
+OVS_WAIT_UNTIL([check_tunnel_property options:local_ip "\"192.168.0.1\""])
+
+# Change the local_ip on the OVS side and check than OVN fixes it
+ovs-vsctl set interface ovn-fakech-0 options:local_ip="1.1.1.1"
+OVS_WAIT_UNTIL([check_tunnel_property options:local_ip "\"192.168.0.1\""])
+
 # Gracefully terminate daemons
 OVN_CLEANUP_SBOX([hv])
 OVN_CLEANUP_VSWITCH([main])