[ovs-dev,ovn,1/2] Add support to Default Router Preference (PRF) - RFC 4191
diff mbox series

Message ID 7f49dc40eaf25dcc35de5ee6208789eefb7f378a.1573731441.git.lorenzo.bianconi@redhat.com
State New
Headers show
Series
  • Add support for PRF and Route Info Option in RA (RFC 4191)
Related show

Commit Message

Lorenzo Bianconi Nov. 14, 2019, 11:38 a.m. UTC
Introduce support for Default Router Preference (PRF) in IPv6 Router
Advertisement according to RFC 4191

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
---
 controller/pinctrl.c | 20 +++++++++++++++++---
 lib/ovn-l7.h         |  4 ++++
 northd/ovn-northd.c  |  7 +++++++
 ovn-nb.xml           | 12 ++++++++++++
 tests/ovn.at         | 13 +++++++++----
 5 files changed, 49 insertions(+), 7 deletions(-)

Comments

Numan Siddique Nov. 28, 2019, 10:26 a.m. UTC | #1
On Thu, Nov 14, 2019 at 5:10 PM Lorenzo Bianconi
<lorenzo.bianconi@redhat.com> wrote:
>
> Introduce support for Default Router Preference (PRF) in IPv6 Router
> Advertisement according to RFC 4191
>
> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>

Thanks Lorenzo for the patches.

The patch LGTM.  Just one comment

 1. Can you please change the option name in the OVN NB DB from "prf"
to "router_preference"
     Using "ipv6_ra_prf" in south db is fine with me.


Thanks
Numan
> ---
>  controller/pinctrl.c | 20 +++++++++++++++++---
>  lib/ovn-l7.h         |  4 ++++
>  northd/ovn-northd.c  |  7 +++++++
>  ovn-nb.xml           | 12 ++++++++++++
>  tests/ovn.at         | 13 +++++++++----
>  5 files changed, 49 insertions(+), 7 deletions(-)
>
> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> index a90ee73d6..b736b60ad 100644
> --- a/controller/pinctrl.c
> +++ b/controller/pinctrl.c
> @@ -2263,10 +2263,10 @@ ipv6_ra_update_config(const struct sbrec_port_binding *pb)
>          goto fail;
>      }
>      if (!strcmp(address_mode, "dhcpv6_stateless")) {
> -        config->mo_flags = IPV6_ND_RA_FLAG_OTHER_ADDR_CONFIG;
> +        config->mo_flags |= IPV6_ND_RA_FLAG_OTHER_ADDR_CONFIG;
>          config->la_flags |= IPV6_ND_RA_OPT_PREFIX_AUTONOMOUS;
>      } else if (!strcmp(address_mode, "dhcpv6_stateful")) {
> -        config->mo_flags = IPV6_ND_RA_FLAG_MANAGED_ADDR_CONFIG;
> +        config->mo_flags |= IPV6_ND_RA_FLAG_MANAGED_ADDR_CONFIG;
>      } else if (!strcmp(address_mode, "slaac")) {
>          config->la_flags |= IPV6_ND_RA_OPT_PREFIX_AUTONOMOUS;
>      } else {
> @@ -2274,6 +2274,13 @@ ipv6_ra_update_config(const struct sbrec_port_binding *pb)
>          goto fail;
>      }
>
> +    const char *prf = smap_get(&pb->options, "ipv6_ra_prf");
> +    if (!strcmp(prf, "HIGH")) {
> +        config->mo_flags |= IPV6_ND_RA_OPT_PRF_HIGH;
> +    } else if (!strcmp(prf, "LOW")) {
> +        config->mo_flags |= IPV6_ND_RA_OPT_PRF_LOW;
> +    }
> +
>      const char *prefixes = smap_get(&pb->options, "ipv6_ra_prefixes");
>      if (prefixes && !extract_ip_addresses(prefixes, &config->prefixes)) {
>          VLOG_WARN("Invalid IPv6 prefixes: %s", prefixes);
> @@ -2423,10 +2430,17 @@ ipv6_ra_send(struct rconn *swconn, struct ipv6_ra_state *ra)
>
>      uint64_t packet_stub[128 / 8];
>      struct dp_packet packet;
> +    uint16_t router_lt = IPV6_ND_RA_LIFETIME;
> +
> +    if (!router_lt) {
> +        /* Reset PRF to MEDIUM if router lifetime is not set */
> +        ra->config->mo_flags &= ~IPV6_ND_RA_OPT_PRF_LOW;
> +    }
> +
>      dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
>      compose_nd_ra(&packet, ra->config->eth_src, ra->config->eth_dst,
>              &ra->config->ipv6_src, &ra->config->ipv6_dst,
> -            255, ra->config->mo_flags, htons(IPV6_ND_RA_LIFETIME), 0, 0,
> +            255, ra->config->mo_flags, htons(router_lt), 0, 0,
>              ra->config->mtu);
>
>      for (int i = 0; i < ra->config->prefixes.n_ipv6_addrs; i++) {
> diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h
> index 5fc370bf5..fd898b0dc 100644
> --- a/lib/ovn-l7.h
> +++ b/lib/ovn-l7.h
> @@ -287,6 +287,10 @@ nd_ra_opts_destroy(struct hmap *nd_ra_opts)
>  #define IPV6_ND_RA_OPT_PREFIX_VALID_LIFETIME        0xffffffff
>  #define IPV6_ND_RA_OPT_PREFIX_PREFERRED_LIFETIME    0xffffffff
>
> +#define IPV6_ND_RA_OPT_PRF_NORMAL                   0x00
> +#define IPV6_ND_RA_OPT_PRF_HIGH                     0x08
> +#define IPV6_ND_RA_OPT_PRF_LOW                      0x18
> +
>  static inline void
>  nd_ra_opts_init(struct hmap *nd_ra_opts)
>  {
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index d6beb9768..a1eaa9071 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -6757,6 +6757,13 @@ copy_ra_to_sb(struct ovn_port *op, const char *address_mode)
>
>      smap_add(&options, "ipv6_ra_src_eth", op->lrp_networks.ea_s);
>
> +    const char *prf = smap_get(&op->nbrp->ipv6_ra_configs, "prf");
> +    if (!prf || (strcmp(prf, "HIGH") && strcmp(prf, "LOW"))) {
> +        smap_add(&options, "ipv6_ra_prf", "MEDIUM");
> +    } else {
> +        smap_add(&options, "ipv6_ra_prf", prf);
> +    }
> +
>      sbrec_port_binding_set_options(op->sb, &options);
>      smap_destroy(&options);
>  }
> diff --git a/ovn-nb.xml b/ovn-nb.xml
> index d8f3237fc..89d23ad7b 100644
> --- a/ovn-nb.xml
> +++ b/ovn-nb.xml
> @@ -1859,6 +1859,18 @@
>          </ul>
>        </column>
>
> +      <column name="ipv6_ra_configs" key="prf">
> +        Default Router Preference (PRF) indicates whether to prefer this
> +        router over other default routers (RFC 4191).
> +        Possible values are:
> +
> +        <ul>
> +          <li>HIGH: mapped to 0x01 in RA PRF field</li>
> +          <li>MEDIUM: mapped to 0x00 in RA PRF field</li>
> +          <li>LOW: mapped to 0x11 in RA PRF field</li>
> +        </ul>
> +      </column>
> +
>        <column name="ipv6_ra_configs" key="mtu">
>          The recommended MTU for the link. Default is 0, which means no MTU
>          Option will be included in RA packet replied by ovn-controller.
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 4a10a11e9..85d539c78 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -11504,23 +11504,28 @@ ra_test 000005dc 00 0 0 c0 40 aef00000000000000000000000000000
>  ovn-nbctl --wait=hv set Logical_Router_port ro-sw networks='aef0\:\:1/64 fd0f\:\:1/48'
>  ra_test 000005dc 00 0 0 c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
>
> +# Test PRF for default gw
> +ovn-nbctl --wait=hv set Logical_Router_port ro-sw ipv6_ra_configs:prf="LOW"
> +ra_test 000005dc 18 0 0 c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> +
>  # Now test for RDNSS
>  ovn-nbctl --wait=hv set Logical_Router_port ro-sw ipv6_ra_configs:rdnss='aef0::11'
>  dns_addr=aef00000000000000000000000000011
> -ra_test 000005dc 00 $dns_addr 0 c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> +ra_test 000005dc 18 $dns_addr 0 c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
>
>  # Now test for DNSSL
>  ovn-nbctl --wait=hv set Logical_Router_port ro-sw ipv6_ra_configs:dnssl="aa.bb.cc"
> +ovn-nbctl --wait=hv set Logical_Router_port ro-sw ipv6_ra_configs:prf="HIGH"
>  dnssl=02616102626202636300000000000000
> -ra_test 000005dc 00 $dns_addr $dnssl c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> +ra_test 000005dc 08 $dns_addr $dnssl c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
>
>  ## Test a different address mode now
>  ovn-nbctl --wait=hv set Logical_Router_Port ro-sw ipv6_ra_configs:address_mode=dhcpv6_stateful
> -ra_test 000005dc 80 $dns_addr $dnssl 80 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> +ra_test 000005dc 88 $dns_addr $dnssl 80 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
>
>  # And the other address mode
>  ovn-nbctl --wait=hv set Logical_Router_Port ro-sw ipv6_ra_configs:address_mode=dhcpv6_stateless
> -ra_test 000005dc 40 $dns_addr $dnssl c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> +ra_test 000005dc 48 $dns_addr $dnssl c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
>
>  OVN_CLEANUP([hv1],[hv2])
>  AT_CLEANUP
> --
> 2.21.0
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Lorenzo Bianconi Nov. 28, 2019, 1:19 p.m. UTC | #2
> On Thu, Nov 14, 2019 at 5:10 PM Lorenzo Bianconi
> <lorenzo.bianconi@redhat.com> wrote:
> >
> > Introduce support for Default Router Preference (PRF) in IPv6 Router
> > Advertisement according to RFC 4191
> >
> > Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
> 
> Thanks Lorenzo for the patches.
> 
> The patch LGTM.  Just one comment
> 
>  1. Can you please change the option name in the OVN NB DB from "prf"
> to "router_preference"
>      Using "ipv6_ra_prf" in south db is fine with me.

Hi Numan,

Thx for the review. Fixed in v2.

Regards,
Lorenzo

> 
> 
> Thanks
> Numan
> > ---
> >  controller/pinctrl.c | 20 +++++++++++++++++---
> >  lib/ovn-l7.h         |  4 ++++
> >  northd/ovn-northd.c  |  7 +++++++
> >  ovn-nb.xml           | 12 ++++++++++++
> >  tests/ovn.at         | 13 +++++++++----
> >  5 files changed, 49 insertions(+), 7 deletions(-)
> >
> > diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> > index a90ee73d6..b736b60ad 100644
> > --- a/controller/pinctrl.c
> > +++ b/controller/pinctrl.c
> > @@ -2263,10 +2263,10 @@ ipv6_ra_update_config(const struct sbrec_port_binding *pb)
> >          goto fail;
> >      }
> >      if (!strcmp(address_mode, "dhcpv6_stateless")) {
> > -        config->mo_flags = IPV6_ND_RA_FLAG_OTHER_ADDR_CONFIG;
> > +        config->mo_flags |= IPV6_ND_RA_FLAG_OTHER_ADDR_CONFIG;
> >          config->la_flags |= IPV6_ND_RA_OPT_PREFIX_AUTONOMOUS;
> >      } else if (!strcmp(address_mode, "dhcpv6_stateful")) {
> > -        config->mo_flags = IPV6_ND_RA_FLAG_MANAGED_ADDR_CONFIG;
> > +        config->mo_flags |= IPV6_ND_RA_FLAG_MANAGED_ADDR_CONFIG;
> >      } else if (!strcmp(address_mode, "slaac")) {
> >          config->la_flags |= IPV6_ND_RA_OPT_PREFIX_AUTONOMOUS;
> >      } else {
> > @@ -2274,6 +2274,13 @@ ipv6_ra_update_config(const struct sbrec_port_binding *pb)
> >          goto fail;
> >      }
> >
> > +    const char *prf = smap_get(&pb->options, "ipv6_ra_prf");
> > +    if (!strcmp(prf, "HIGH")) {
> > +        config->mo_flags |= IPV6_ND_RA_OPT_PRF_HIGH;
> > +    } else if (!strcmp(prf, "LOW")) {
> > +        config->mo_flags |= IPV6_ND_RA_OPT_PRF_LOW;
> > +    }
> > +
> >      const char *prefixes = smap_get(&pb->options, "ipv6_ra_prefixes");
> >      if (prefixes && !extract_ip_addresses(prefixes, &config->prefixes)) {
> >          VLOG_WARN("Invalid IPv6 prefixes: %s", prefixes);
> > @@ -2423,10 +2430,17 @@ ipv6_ra_send(struct rconn *swconn, struct ipv6_ra_state *ra)
> >
> >      uint64_t packet_stub[128 / 8];
> >      struct dp_packet packet;
> > +    uint16_t router_lt = IPV6_ND_RA_LIFETIME;
> > +
> > +    if (!router_lt) {
> > +        /* Reset PRF to MEDIUM if router lifetime is not set */
> > +        ra->config->mo_flags &= ~IPV6_ND_RA_OPT_PRF_LOW;
> > +    }
> > +
> >      dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
> >      compose_nd_ra(&packet, ra->config->eth_src, ra->config->eth_dst,
> >              &ra->config->ipv6_src, &ra->config->ipv6_dst,
> > -            255, ra->config->mo_flags, htons(IPV6_ND_RA_LIFETIME), 0, 0,
> > +            255, ra->config->mo_flags, htons(router_lt), 0, 0,
> >              ra->config->mtu);
> >
> >      for (int i = 0; i < ra->config->prefixes.n_ipv6_addrs; i++) {
> > diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h
> > index 5fc370bf5..fd898b0dc 100644
> > --- a/lib/ovn-l7.h
> > +++ b/lib/ovn-l7.h
> > @@ -287,6 +287,10 @@ nd_ra_opts_destroy(struct hmap *nd_ra_opts)
> >  #define IPV6_ND_RA_OPT_PREFIX_VALID_LIFETIME        0xffffffff
> >  #define IPV6_ND_RA_OPT_PREFIX_PREFERRED_LIFETIME    0xffffffff
> >
> > +#define IPV6_ND_RA_OPT_PRF_NORMAL                   0x00
> > +#define IPV6_ND_RA_OPT_PRF_HIGH                     0x08
> > +#define IPV6_ND_RA_OPT_PRF_LOW                      0x18
> > +
> >  static inline void
> >  nd_ra_opts_init(struct hmap *nd_ra_opts)
> >  {
> > diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> > index d6beb9768..a1eaa9071 100644
> > --- a/northd/ovn-northd.c
> > +++ b/northd/ovn-northd.c
> > @@ -6757,6 +6757,13 @@ copy_ra_to_sb(struct ovn_port *op, const char *address_mode)
> >
> >      smap_add(&options, "ipv6_ra_src_eth", op->lrp_networks.ea_s);
> >
> > +    const char *prf = smap_get(&op->nbrp->ipv6_ra_configs, "prf");
> > +    if (!prf || (strcmp(prf, "HIGH") && strcmp(prf, "LOW"))) {
> > +        smap_add(&options, "ipv6_ra_prf", "MEDIUM");
> > +    } else {
> > +        smap_add(&options, "ipv6_ra_prf", prf);
> > +    }
> > +
> >      sbrec_port_binding_set_options(op->sb, &options);
> >      smap_destroy(&options);
> >  }
> > diff --git a/ovn-nb.xml b/ovn-nb.xml
> > index d8f3237fc..89d23ad7b 100644
> > --- a/ovn-nb.xml
> > +++ b/ovn-nb.xml
> > @@ -1859,6 +1859,18 @@
> >          </ul>
> >        </column>
> >
> > +      <column name="ipv6_ra_configs" key="prf">
> > +        Default Router Preference (PRF) indicates whether to prefer this
> > +        router over other default routers (RFC 4191).
> > +        Possible values are:
> > +
> > +        <ul>
> > +          <li>HIGH: mapped to 0x01 in RA PRF field</li>
> > +          <li>MEDIUM: mapped to 0x00 in RA PRF field</li>
> > +          <li>LOW: mapped to 0x11 in RA PRF field</li>
> > +        </ul>
> > +      </column>
> > +
> >        <column name="ipv6_ra_configs" key="mtu">
> >          The recommended MTU for the link. Default is 0, which means no MTU
> >          Option will be included in RA packet replied by ovn-controller.
> > diff --git a/tests/ovn.at b/tests/ovn.at
> > index 4a10a11e9..85d539c78 100644
> > --- a/tests/ovn.at
> > +++ b/tests/ovn.at
> > @@ -11504,23 +11504,28 @@ ra_test 000005dc 00 0 0 c0 40 aef00000000000000000000000000000
> >  ovn-nbctl --wait=hv set Logical_Router_port ro-sw networks='aef0\:\:1/64 fd0f\:\:1/48'
> >  ra_test 000005dc 00 0 0 c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> >
> > +# Test PRF for default gw
> > +ovn-nbctl --wait=hv set Logical_Router_port ro-sw ipv6_ra_configs:prf="LOW"
> > +ra_test 000005dc 18 0 0 c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> > +
> >  # Now test for RDNSS
> >  ovn-nbctl --wait=hv set Logical_Router_port ro-sw ipv6_ra_configs:rdnss='aef0::11'
> >  dns_addr=aef00000000000000000000000000011
> > -ra_test 000005dc 00 $dns_addr 0 c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> > +ra_test 000005dc 18 $dns_addr 0 c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> >
> >  # Now test for DNSSL
> >  ovn-nbctl --wait=hv set Logical_Router_port ro-sw ipv6_ra_configs:dnssl="aa.bb.cc"
> > +ovn-nbctl --wait=hv set Logical_Router_port ro-sw ipv6_ra_configs:prf="HIGH"
> >  dnssl=02616102626202636300000000000000
> > -ra_test 000005dc 00 $dns_addr $dnssl c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> > +ra_test 000005dc 08 $dns_addr $dnssl c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> >
> >  ## Test a different address mode now
> >  ovn-nbctl --wait=hv set Logical_Router_Port ro-sw ipv6_ra_configs:address_mode=dhcpv6_stateful
> > -ra_test 000005dc 80 $dns_addr $dnssl 80 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> > +ra_test 000005dc 88 $dns_addr $dnssl 80 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> >
> >  # And the other address mode
> >  ovn-nbctl --wait=hv set Logical_Router_Port ro-sw ipv6_ra_configs:address_mode=dhcpv6_stateless
> > -ra_test 000005dc 40 $dns_addr $dnssl c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> > +ra_test 000005dc 48 $dns_addr $dnssl c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
> >
> >  OVN_CLEANUP([hv1],[hv2])
> >  AT_CLEANUP
> > --
> > 2.21.0
> >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
>

Patch
diff mbox series

diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index a90ee73d6..b736b60ad 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -2263,10 +2263,10 @@  ipv6_ra_update_config(const struct sbrec_port_binding *pb)
         goto fail;
     }
     if (!strcmp(address_mode, "dhcpv6_stateless")) {
-        config->mo_flags = IPV6_ND_RA_FLAG_OTHER_ADDR_CONFIG;
+        config->mo_flags |= IPV6_ND_RA_FLAG_OTHER_ADDR_CONFIG;
         config->la_flags |= IPV6_ND_RA_OPT_PREFIX_AUTONOMOUS;
     } else if (!strcmp(address_mode, "dhcpv6_stateful")) {
-        config->mo_flags = IPV6_ND_RA_FLAG_MANAGED_ADDR_CONFIG;
+        config->mo_flags |= IPV6_ND_RA_FLAG_MANAGED_ADDR_CONFIG;
     } else if (!strcmp(address_mode, "slaac")) {
         config->la_flags |= IPV6_ND_RA_OPT_PREFIX_AUTONOMOUS;
     } else {
@@ -2274,6 +2274,13 @@  ipv6_ra_update_config(const struct sbrec_port_binding *pb)
         goto fail;
     }
 
+    const char *prf = smap_get(&pb->options, "ipv6_ra_prf");
+    if (!strcmp(prf, "HIGH")) {
+        config->mo_flags |= IPV6_ND_RA_OPT_PRF_HIGH;
+    } else if (!strcmp(prf, "LOW")) {
+        config->mo_flags |= IPV6_ND_RA_OPT_PRF_LOW;
+    }
+
     const char *prefixes = smap_get(&pb->options, "ipv6_ra_prefixes");
     if (prefixes && !extract_ip_addresses(prefixes, &config->prefixes)) {
         VLOG_WARN("Invalid IPv6 prefixes: %s", prefixes);
@@ -2423,10 +2430,17 @@  ipv6_ra_send(struct rconn *swconn, struct ipv6_ra_state *ra)
 
     uint64_t packet_stub[128 / 8];
     struct dp_packet packet;
+    uint16_t router_lt = IPV6_ND_RA_LIFETIME;
+
+    if (!router_lt) {
+        /* Reset PRF to MEDIUM if router lifetime is not set */
+        ra->config->mo_flags &= ~IPV6_ND_RA_OPT_PRF_LOW;
+    }
+
     dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
     compose_nd_ra(&packet, ra->config->eth_src, ra->config->eth_dst,
             &ra->config->ipv6_src, &ra->config->ipv6_dst,
-            255, ra->config->mo_flags, htons(IPV6_ND_RA_LIFETIME), 0, 0,
+            255, ra->config->mo_flags, htons(router_lt), 0, 0,
             ra->config->mtu);
 
     for (int i = 0; i < ra->config->prefixes.n_ipv6_addrs; i++) {
diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h
index 5fc370bf5..fd898b0dc 100644
--- a/lib/ovn-l7.h
+++ b/lib/ovn-l7.h
@@ -287,6 +287,10 @@  nd_ra_opts_destroy(struct hmap *nd_ra_opts)
 #define IPV6_ND_RA_OPT_PREFIX_VALID_LIFETIME        0xffffffff
 #define IPV6_ND_RA_OPT_PREFIX_PREFERRED_LIFETIME    0xffffffff
 
+#define IPV6_ND_RA_OPT_PRF_NORMAL                   0x00
+#define IPV6_ND_RA_OPT_PRF_HIGH                     0x08
+#define IPV6_ND_RA_OPT_PRF_LOW                      0x18
+
 static inline void
 nd_ra_opts_init(struct hmap *nd_ra_opts)
 {
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index d6beb9768..a1eaa9071 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -6757,6 +6757,13 @@  copy_ra_to_sb(struct ovn_port *op, const char *address_mode)
 
     smap_add(&options, "ipv6_ra_src_eth", op->lrp_networks.ea_s);
 
+    const char *prf = smap_get(&op->nbrp->ipv6_ra_configs, "prf");
+    if (!prf || (strcmp(prf, "HIGH") && strcmp(prf, "LOW"))) {
+        smap_add(&options, "ipv6_ra_prf", "MEDIUM");
+    } else {
+        smap_add(&options, "ipv6_ra_prf", prf);
+    }
+
     sbrec_port_binding_set_options(op->sb, &options);
     smap_destroy(&options);
 }
diff --git a/ovn-nb.xml b/ovn-nb.xml
index d8f3237fc..89d23ad7b 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -1859,6 +1859,18 @@ 
         </ul>
       </column>
 
+      <column name="ipv6_ra_configs" key="prf">
+        Default Router Preference (PRF) indicates whether to prefer this
+        router over other default routers (RFC 4191).
+        Possible values are:
+
+        <ul>
+          <li>HIGH: mapped to 0x01 in RA PRF field</li>
+          <li>MEDIUM: mapped to 0x00 in RA PRF field</li>
+          <li>LOW: mapped to 0x11 in RA PRF field</li>
+        </ul>
+      </column>
+
       <column name="ipv6_ra_configs" key="mtu">
         The recommended MTU for the link. Default is 0, which means no MTU
         Option will be included in RA packet replied by ovn-controller.
diff --git a/tests/ovn.at b/tests/ovn.at
index 4a10a11e9..85d539c78 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -11504,23 +11504,28 @@  ra_test 000005dc 00 0 0 c0 40 aef00000000000000000000000000000
 ovn-nbctl --wait=hv set Logical_Router_port ro-sw networks='aef0\:\:1/64 fd0f\:\:1/48'
 ra_test 000005dc 00 0 0 c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
 
+# Test PRF for default gw
+ovn-nbctl --wait=hv set Logical_Router_port ro-sw ipv6_ra_configs:prf="LOW"
+ra_test 000005dc 18 0 0 c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
+
 # Now test for RDNSS
 ovn-nbctl --wait=hv set Logical_Router_port ro-sw ipv6_ra_configs:rdnss='aef0::11'
 dns_addr=aef00000000000000000000000000011
-ra_test 000005dc 00 $dns_addr 0 c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
+ra_test 000005dc 18 $dns_addr 0 c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
 
 # Now test for DNSSL
 ovn-nbctl --wait=hv set Logical_Router_port ro-sw ipv6_ra_configs:dnssl="aa.bb.cc"
+ovn-nbctl --wait=hv set Logical_Router_port ro-sw ipv6_ra_configs:prf="HIGH"
 dnssl=02616102626202636300000000000000
-ra_test 000005dc 00 $dns_addr $dnssl c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
+ra_test 000005dc 08 $dns_addr $dnssl c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
 
 ## Test a different address mode now
 ovn-nbctl --wait=hv set Logical_Router_Port ro-sw ipv6_ra_configs:address_mode=dhcpv6_stateful
-ra_test 000005dc 80 $dns_addr $dnssl 80 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
+ra_test 000005dc 88 $dns_addr $dnssl 80 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
 
 # And the other address mode
 ovn-nbctl --wait=hv set Logical_Router_Port ro-sw ipv6_ra_configs:address_mode=dhcpv6_stateless
-ra_test 000005dc 40 $dns_addr $dnssl c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
+ra_test 000005dc 48 $dns_addr $dnssl c0 40 aef00000000000000000000000000000 30 fd0f0000000000000000000000000000
 
 OVN_CLEANUP([hv1],[hv2])
 AT_CLEANUP