> Hi Lorenzo,
> 
> I have a few comments below.
> 
> On 1/17/24 06:11, Lorenzo Bianconi wrote:
> > Similar to OVN static routes, introduce the capability to link a BFD
> > session for OVN reroute policies.
> > 
> > Reported-at: https://issues.redhat.com/browse/FDP-234
> > Signed-off-by: Lorenzo Bianconi <lorenzo.bianc...@redhat.com>
> > ---
> >   NEWS                      |  1 +
> >   northd/northd.c           | 71 +++++++++++++++++++++++++++++----
> >   ovn-nb.ovsschema          |  9 ++++-
> >   ovn-nb.xml                |  7 ++++
> >   tests/ovn-nbctl.at        |  6 +++
> >   tests/ovn-northd.at       | 20 +++++++++-
> >   tests/system-ovn.at       | 51 +++++++++++++++++++++---
> >   utilities/ovn-nbctl.8.xml |  8 ++++
> >   utilities/ovn-nbctl.c     | 84 ++++++++++++++++++++++++++++++++++++++-
> >   9 files changed, 239 insertions(+), 18 deletions(-)
> > 
> > diff --git a/NEWS b/NEWS
> > index 5f267b4c6..5c0ea7e80 100644
> > --- a/NEWS
> > +++ b/NEWS
> > @@ -14,6 +14,7 @@ Post v23.09.0
> >     - ovn-northd-ddlog has been removed.
> >     - A new LSP option "enable_router_port_acl" has been added to enable
> >       conntrack for the router port whose peer is l3dgw_port if set it true.
> > +  - Introduce next-hop BFD availability check for OVN reroute policies.
> >   OVN v23.09.0 - 15 Sep 2023
> >   --------------------------
> > diff --git a/northd/northd.c b/northd/northd.c
> > index 952f8200d..b517e5a7b 100644
> > --- a/northd/northd.c
> > +++ b/northd/northd.c
> > @@ -10887,10 +10887,48 @@ get_outport_for_routing_policy_nexthop(struct 
> > ovn_datapath *od,
> >       return NULL;
> >   }
> > +static struct ovs_mutex bfd_lock = OVS_MUTEX_INITIALIZER;
> > +
> > +static bool check_bfd_state(
> > +        const struct nbrec_logical_router_policy *rule,
> > +        const struct hmap *bfd_connections,
> > +        struct ovn_port *out_port,
> > +        const char *nexthop)
> > +{
> > +    for (size_t i = 0; i < rule->n_bfd_sessions; i++) {
> > +        /* Check if there is a BFD session associated to the reroute
> > +         * policy. */
> > +        const struct nbrec_bfd *nb_bt = rule->bfd_sessions[i];
> > +        if (!strcmp(nb_bt->dst_ip, nexthop) &&
> 
> If nb_bt->dst_ip and nexthop are IPv6 addresses, then strcmp is a not a good
> way to compare addresses, since there are many ways to represent the same
> IPv6 address as a string.

ack, I will fix it.

> 
> > +            !strcmp(nb_bt->logical_port, out_port->key)) {
> > +            struct bfd_entry *bfd_e = bfd_port_lookup(
> > +                    bfd_connections, nb_bt->logical_port,
> > +                    nb_bt->dst_ip);
> > +
> > +            ovs_mutex_lock(&bfd_lock);
> 
> Correct me if I'm wrong, but I think that there is a 1-to-1 relationship
> between northbound BFD rows and internal northd bfd_entry structs. If that's
> correct, then could we add a mutex to struct bfd_entry and lock that here
> instead of using a global bfd_lock? That way, contention is limited to
> reroute policies that reroute to the same destination IP address.

yep, I agree but I do not this is strictly related to this series since we
already have bfd_lock for static route as well. What about address your
comments in a subsequent patch?

> 
> > +            if (bfd_e) {
> > +                bfd_e->ref = true;
> > +            }
> > +
> > +            if (!strcmp(nb_bt->status, "admin_down")) {
> > +                nbrec_bfd_set_status(nb_bt, "down");
> 
> You could unlock and return false here.

we will need to duplicate the code with the one below in this way, don't we?

> 
> > +            }
> > +
> > +            if (!strcmp(nb_bt->status, "down")) {
> > +                ovs_mutex_unlock(&bfd_lock);
> > +                return false;
> > +            }
> > +            ovs_mutex_unlock(&bfd_lock);
> 
> Would it be possible to return true here? Or can there be multiple BFD
> sessions associated with the nexthop IP address that we need to check the
> state of? And must all of them be "up" for us to return true?

ack, we can just return here, I will fix it.

> 
> > +        }
> > +    }
> > +    return true;
> > +}
> > +
> >   static void
> >   build_routing_policy_flow(struct hmap *lflows, struct ovn_datapath *od,
> >                             const struct hmap *lr_ports,
> >                             const struct nbrec_logical_router_policy *rule,
> > +                          const struct hmap *bfd_connections,
> >                             const struct ovsdb_idl_row *stage_hint)
> >   {
> >       struct ds match = DS_EMPTY_INITIALIZER;
> > @@ -10915,6 +10953,11 @@ build_routing_policy_flow(struct hmap *lflows, 
> > struct ovn_datapath *od,
> >                            rule->priority, nexthop);
> >               return;
> >           }
> > +
> > +        if (!check_bfd_state(rule, bfd_connections, out_port, nexthop)) {
> > +            return;
> > +        }
> > +
> >           uint32_t pkt_mark = ovn_smap_get_uint(&rule->options, "pkt_mark", 
> > 0);
> >           if (pkt_mark) {
> >               ds_put_format(&actions, "pkt.mark = %u; ", pkt_mark);
> > @@ -10956,6 +10999,7 @@ static void
> >   build_ecmp_routing_policy_flows(struct hmap *lflows, struct ovn_datapath 
> > *od,
> >                                   const struct hmap *lr_ports,
> >                                   const struct nbrec_logical_router_policy 
> > *rule,
> > +                                const struct hmap *bfd_connections,
> >                                   uint16_t ecmp_group_id)
> >   {
> >       ovs_assert(rule->n_nexthops > 1);
> > @@ -10984,6 +11028,9 @@ build_ecmp_routing_policy_flows(struct hmap 
> > *lflows, struct ovn_datapath *od,
> >       struct ds match = DS_EMPTY_INITIALIZER;
> >       struct ds actions = DS_EMPTY_INITIALIZER;
> > +    size_t *valid_nexthops = xcalloc(rule->n_nexthops, sizeof 
> > *valid_nexthops);
> > +    size_t n_valid_nexthops = 0;
> > +
> >       for (size_t i = 0; i < rule->n_nexthops; i++) {
> >           struct ovn_port *out_port = 
> > get_outport_for_routing_policy_nexthop(
> >                od, lr_ports, rule->priority, rule->nexthops[i]);
> > @@ -11001,6 +11048,13 @@ build_ecmp_routing_policy_flows(struct hmap 
> > *lflows, struct ovn_datapath *od,
> >               goto cleanup;
> >           }
> > +        if (!check_bfd_state(rule, bfd_connections, out_port,
> > +                             rule->nexthops[i])) {
> > +            continue;
> > +        }
> > +
> > +        valid_nexthops[n_valid_nexthops++] = i + 1;
> > +
> >           ds_clear(&actions);
> >           uint32_t pkt_mark = ovn_smap_get_uint(&rule->options, "pkt_mark", 
> > 0);
> >           if (pkt_mark) {
> > @@ -11036,12 +11090,12 @@ build_ecmp_routing_policy_flows(struct hmap 
> > *lflows, struct ovn_datapath *od,
> >                     "; %s = select(", REG_ECMP_GROUP_ID, ecmp_group_id,
> >                     REG_ECMP_MEMBER_ID);
> > -    for (size_t i = 0; i < rule->n_nexthops; i++) {
> > +    for (size_t i = 0; i < n_valid_nexthops; i++) {
> >           if (i > 0) {
> >               ds_put_cstr(&actions, ", ");
> >           }
> > -        ds_put_format(&actions, "%"PRIuSIZE, i + 1);
> > +        ds_put_format(&actions, "%"PRIuSIZE, valid_nexthops[i]);
> >       }
> >       ds_put_cstr(&actions, ");");
> >       ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY,
> > @@ -11049,6 +11103,7 @@ build_ecmp_routing_policy_flows(struct hmap 
> > *lflows, struct ovn_datapath *od,
> >                               ds_cstr(&actions), &rule->header_);
> >   cleanup:
> > +    free(valid_nexthops);
> >       ds_destroy(&match);
> >       ds_destroy(&actions);
> >   }
> > @@ -11132,8 +11187,6 @@ route_hash(struct parsed_route *route)
> >                         (uint32_t)route->plen);
> >   }
> > -static struct ovs_mutex bfd_lock = OVS_MUTEX_INITIALIZER;
> > -
> >   static bool
> >   find_static_route_outport(struct ovn_datapath *od, const struct hmap 
> > *lr_ports,
> >       const struct nbrec_logical_router_static_route *route, bool is_ipv4,
> > @@ -13679,7 +13732,8 @@ build_mcast_lookup_flows_for_lrouter(
> >   static void
> >   build_ingress_policy_flows_for_lrouter(
> >           struct ovn_datapath *od, struct hmap *lflows,
> > -        const struct hmap *lr_ports)
> > +        const struct hmap *lr_ports,
> > +        const struct hmap *bfd_connections)
> >   {
> >       ovs_assert(od->nbr);
> >       /* This is a catch-all rule. It has the lowest priority (0)
> > @@ -13700,11 +13754,11 @@ build_ingress_policy_flows_for_lrouter(
> >           if (is_ecmp_reroute) {
> >               build_ecmp_routing_policy_flows(lflows, od, lr_ports, rule,
> > -                                            ecmp_group_id);
> > +                                            bfd_connections, 
> > ecmp_group_id);
> >               ecmp_group_id++;
> >           } else {
> >               build_routing_policy_flow(lflows, od, lr_ports, rule,
> > -                                      &rule->header_);
> > +                                      bfd_connections, &rule->header_);
> >           }
> >       }
> >   }
> > @@ -16139,7 +16193,8 @@ build_lswitch_and_lrouter_iterate_by_lr(struct 
> > ovn_datapath *od,
> >                                            lsi->bfd_connections);
> >       build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match,
> >                                            &lsi->actions);
> > -    build_ingress_policy_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports);
> > +    build_ingress_policy_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports,
> > +                                           lsi->bfd_connections);
> >       build_arp_resolve_flows_for_lrouter(od, lsi->lflows);
> >       build_check_pkt_len_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports,
> >                                             &lsi->match, &lsi->actions,
> > diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema
> > index b2e0993e0..cec02a172 100644
> > --- a/ovn-nb.ovsschema
> > +++ b/ovn-nb.ovsschema
> > @@ -1,7 +1,7 @@
> >   {
> >       "name": "OVN_Northbound",
> > -    "version": "7.2.0",
> > -    "cksum": "1069338687 34162",
> > +    "version": "7.2.1",
> > +    "cksum": "4156161406 34467",
> >       "tables": {
> >           "NB_Global": {
> >               "columns": {
> > @@ -477,6 +477,11 @@
> >                   "nexthop": {"type": {"key": "string", "min": 0, "max": 
> > 1}},
> >                   "nexthops": {"type": {
> >                       "key": "string", "min": 0, "max": "unlimited"}},
> > +                "bfd_sessions": {"type": {"key": {"type": "uuid",
> > +                                                  "refTable": "BFD",
> > +                                                  "refType": "weak"},
> > +                                  "min": 0,
> > +                                  "max": "unlimited"}},
> >                   "options": {
> >                       "type": {"key": "string", "value": "string",
> >                                "min": 0, "max": "unlimited"}},
> > diff --git a/ovn-nb.xml b/ovn-nb.xml
> > index 765ffcf2e..d35c34517 100644
> > --- a/ovn-nb.xml
> > +++ b/ovn-nb.xml
> > @@ -3682,6 +3682,13 @@ or
> >         </p>
> >       </column>
> > +    <column name="bfd_sessions">
> > +      <p>
> > +        Reference to <ref table="BFD"/> row if the route policy has 
> > associated
> > +        some BFD sessions.
> > +      </p>
> > +    </column>
> > +
> >       <column name="options" key="pkt_mark">
> >         <p>
> >           Marks the packet with the value specified when the router policy
> > diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at
> > index 2d74e9cc6..fcaee1342 100644
> > --- a/tests/ovn-nbctl.at
> > +++ b/tests/ovn-nbctl.at
> > @@ -2189,6 +2189,12 @@ AT_CHECK([ovn-nbctl lr-policy-add lr0 100 "ip4.src 
> > == 1.1.2.0/24" allow pkt_mark
> >   AT_CHECK([ovn-nbctl lr-policy-add lr0 101 "ip4.src == 2.1.1.0/24" allow])
> >   AT_CHECK([ovn-nbctl lr-policy-add lr0 101 "ip4.src == 2.1.2.0/24" drop])
> >   AT_CHECK([ovn-nbctl lr-policy-add lr0 101 "ip6.src == 2002::/64" drop])
> > +AT_CHECK([ovn-nbctl --bfd lr-policy-add lr0 103 "ip4.src == 1.2.3.0/24" 
> > reroute 192.168.1.1], [1], [],
> > +  [ovn-nbctl: out lrp not found for 192.168.1.1 nexthop
> > +])
> > +AT_CHECK([ovn-nbctl --bfd lr-policy-add lr0 103 "ip4.src == 1.2.3.0/24" 
> > drop], [1], [],
> > +  [ovn-nbctl: BFD is valid only with reroute action.
> > +])
> >   dnl Incomplete option set.
> >   AT_CHECK([ovn-nbctl lr-policy-add lr0 200 "ip4.src == 1.1.4.0/24" reroute 
> > 192.168.0.10 foo], [1], [],
> > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> > index 9a0d418e4..d9806d5d0 100644
> > --- a/tests/ovn-northd.at
> > +++ b/tests/ovn-northd.at
> > @@ -3580,7 +3580,7 @@ AT_KEYWORDS([northd-bfd])
> >   ovn_start
> >   check ovn-nbctl --wait=sb lr-add r0
> > -for i in $(seq 1 7); do
> > +for i in $(seq 1 9); do
> >       check ovn-nbctl --wait=sb lrp-add r0 r0-sw$i 00:00:00:00:00:0$i 
> > 192.168.$i.1/24
> >       check ovn-nbctl --wait=sb ls-add sw$i
> >       check ovn-nbctl --wait=sb lsp-add sw$i sw$i-r0
> > @@ -3644,6 +3644,24 @@ bfd2_uuid=$(fetch_column bfd _uuid 
> > logical_port=r0-sw2)
> >   check ovn-sbctl set bfd $bfd2_uuid status=up
> >   wait_column up nb:bfd status logical_port=r0-sw2
> > +# Create reroute policies associated with BFD sessions
> > +check ovn-nbctl lr-route-del r0
> > +check ovn-nbctl --bfd lr-policy-add r0 100 "ip4.src == 1.2.3.0/24" reroute 
> > 192.168.8.2
> > +wait_column down bfd status logical_port=r0-sw8
> > +
> > +bfd_route_policy_uuid=$(fetch_column nb:bfd _uuid logical_port=r0-sw8)
> > +AT_CHECK([ovn-nbctl list logical_router_policy | grep -q 
> > $bfd_route_policy_uuid])
> > +
> > +check ovn-nbctl lr-policy-del r0
> > +check ovn-nbctl --bfd lr-policy-add r0 100 "ip4.src == 2.3.4.0/24" reroute 
> > 192.168.9.2,192.168.9.3,192.168.9.4
> > +
> > +wait_column down bfd status dst_ip=192.168.9.2
> > +wait_column down bfd status dst_ip=192.168.9.3
> > +wait_column down bfd status dst_ip=192.168.9.4
> > +
> > +bfd_route_policy_uuid=$(fetch_column nb:bfd _uuid logical_port=r0-sw9)
> > +AT_CHECK([ovn-nbctl list logical_router_policy | sed s/,//g | grep -q 
> > "$bfd_route_policy_uuid"])
> > +
> >   AT_CLEANUP
> >   ])
> > diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> > index 91fe7cac1..62455d696 100644
> > --- a/tests/system-ovn.at
> > +++ b/tests/system-ovn.at
> > @@ -6837,6 +6837,15 @@ OVS_WAIT_UNTIL([ovn-sbctl dump-flows R1 |grep 
> > lr_in_ip_routing |grep 'ip4.dst ==
> >   check ovn-nbctl clear logical_router_static_route $route_uuid bfd
> >   wait_column "admin_down" nb:bfd status logical_port=rp-public
> >   OVS_WAIT_UNTIL([ip netns exec server bfdd-control status | grep -qi 
> > state=Down])
> > +
> > +check ovn-nbctl --bfd lr-policy-add R1 100 "ip4.src == 200.0.0.0/8" 
> > reroute 172.16.1.50
> > +wait_column "up" nb:bfd status logical_port=rp-public
> > +OVS_WAIT_UNTIL([ovn-sbctl dump-flows R1 |grep lr_in_policy |grep 'ip4.src 
> > == 200.0.0.0/8' |grep -q 172.16.1.50])
> > +
> > +check ovn-nbctl lr-policy-del R1
> > +wait_column "admin_down" nb:bfd status logical_port=rp-public
> > +OVS_WAIT_UNTIL([ip netns exec server bfdd-control status | grep -qi 
> > state=Down])
> > +
> >   NS_CHECK_EXEC([server], [tcpdump -nni s1 udp port 3784 -Q in > bfd.pcap 
> > &])
> >   sleep 5
> >   kill $(pidof tcpdump)
> > @@ -6844,25 +6853,57 @@ AT_CHECK([grep -qi bfd bfd.pcap],[1])
> >   # restart the connection
> >   check ovn-nbctl set logical_router_static_route $route_uuid bfd=$uuid
> > +check ovn-nbctl --bfd lr-policy-add R1 100 "ip4.src == 200.0.0.0/8" 
> > reroute 172.16.1.50
> >   wait_column "up" nb:bfd status logical_port=rp-public
> > +OVS_WAIT_UNTIL([ovn-sbctl dump-flows R1 |grep lr_in_ip_routing |grep 
> > 'ip4.dst == 100.0.0.0/8' |grep -q 172.16.1.50])
> > +OVS_WAIT_UNTIL([ovn-sbctl dump-flows R1 |grep lr_in_policy |grep 'ip4.src 
> > == 200.0.0.0/8' |grep -q 172.16.1.50])
> > +
> > +# stop bfd endpoint
> > +NS_CHECK_EXEC([server], [bfdd-control stop], [0], [dnl
> > +stopping
> > +])
> > +wait_column "down" nb:bfd status logical_port=rp-public
> > +OVS_WAIT_UNTIL([test "$(ovn-sbctl dump-flows R1 |grep lr_in_ip_routing 
> > |grep 'ip4.dst == 100.0.0.0/8' |grep 172.16.1.50)" = ""])
> > +OVS_WAIT_UNTIL([test "$(ovn-sbctl dump-flows R1 |grep lr_in_policy |grep 
> > 'ip4.src == 200.0.0.0/8' |grep 172.16.1.50)" = ""])
> > +
> >   # switch to gw router configuration
> >   check ovn-nbctl clear logical_router_static_route $route_uuid bfd
> > -wait_column "admin_down" nb:bfd status logical_port=rp-public
> > -OVS_WAIT_UNTIL([ip netns exec server bfdd-control status | grep -qi 
> > state=Down])
> > +check ovn-nbctl lr-policy-del R1
> >   check ovn-nbctl clear logical_router_port rp-public gateway_chassis
> >   check ovn-nbctl set logical_router R1 options:chassis=hv1
> >   check ovn-nbctl set logical_router_static_route $route_uuid bfd=$uuid
> > +
> > +# restart bfdd
> > +NS_CHECK_EXEC([server], [bfdd-beacon --listen=172.16.1.50], [0])
> > +NS_CHECK_EXEC([server], [bfdd-control allow 172.16.1.1], [0], [dnl
> > +Allowing connections from 172.16.1.1
> > +])
> > +
> >   wait_column "up" nb:bfd status logical_port=rp-public
> > +OVS_WAIT_UNTIL([ovn-sbctl dump-flows R1 |grep lr_in_ip_routing |grep 
> > 'ip4.dst == 100.0.0.0/8' |grep -q 172.16.1.50])
> > +
> > +check ovn-nbctl clear logical_router_static_route $route_uuid bfd
> > +wait_column "admin_down" nb:bfd status logical_port=rp-public
> > +OVS_WAIT_UNTIL([ip netns exec server bfdd-control status | grep -qi 
> > state=Down])
> > +ovn-nbctl destroy bfd $uuid
> > +check_row_count bfd 0
> > +
> > +# create reroute route policy
> > +check ovn-nbctl --bfd lr-policy-add R1 100 "ip4.src == 210.0.0.0/8" 
> > reroute 172.16.1.50
> > +wait_column "up" nb:bfd status logical_port=rp-public
> > +OVS_WAIT_UNTIL([ovn-sbctl dump-flows R1 |grep lr_in_policy |grep 'ip4.src 
> > == 210.0.0.0/8' |grep -q 172.16.1.50])
> > +
> > +check ovn-nbctl lr-policy-del R1
> > +wait_column "admin_down" nb:bfd status logical_port=rp-public
> > +OVS_WAIT_UNTIL([ip netns exec server bfdd-control status | grep -qi 
> > state=Down])
> > +uuid=$(fetch_column nb:bfd _uuid logical_port="rp-public")
> >   # stop bfd endpoint
> >   NS_CHECK_EXEC([server], [bfdd-control stop], [0], [dnl
> >   stopping
> >   ])
> > -wait_column "down" nb:bfd status logical_port=rp-public
> > -OVS_WAIT_UNTIL([test "$(ovn-sbctl dump-flows R1 |grep lr_in_ip_routing 
> > |grep 'ip4.dst == 100.0.0.0/8' |grep 172.16.1.50)" = ""])
> > -
> >   # remove bfd entry
> >   ovn-nbctl destroy bfd $uuid
> >   check_row_count bfd 0
> > diff --git a/utilities/ovn-nbctl.8.xml b/utilities/ovn-nbctl.8.xml
> > index 6f74bd557..5aa01f2f8 100644
> > --- a/utilities/ovn-nbctl.8.xml
> > +++ b/utilities/ovn-nbctl.8.xml
> > @@ -1119,6 +1119,14 @@
> >             duplicated routing policy results in error.
> >           </p>
> > +        <p>
> > +          <code>--bfd</code> option is used to link a BFD session to the
> > +          OVN reroute policy. OVN will look for an already running BFD
> > +          session using next-hop as lookup key in the BFD table.
> > +          If the lookup fails, a new entry in the BFD table will be created
> > +          using the <var>nexthop</var> as <var>dst_ip</var>.
> > +        </p>
> > +
> >             <p>
> >             The following example shows a policy to lr1, which will drop 
> > packets
> >             from<code>192.168.100.0/24</code>.
> > diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c
> > index 0586eccdb..3d16555a5 100644
> > --- a/utilities/ovn-nbctl.c
> > +++ b/utilities/ovn-nbctl.c
> > @@ -4014,14 +4014,26 @@ normalize_addr_str(const char *orig_addr)
> >       return ret;
> >   }
> > +static bool
> > +ip_in_lrp_networks(const struct nbrec_logical_router_port *lrp,
> > +                   const char *ip_s);
> > +
> >   static void
> >   nbctl_pre_lr_policy_add(struct ctl_context *ctx)
> >   {
> >       ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_col_name);
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_col_ports);
> >       ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_col_policies);
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_name);
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_mac);
> > +    ovsdb_idl_add_column(ctx->idl, 
> > &nbrec_logical_router_port_col_networks);
> > +
> >       ovsdb_idl_add_column(ctx->idl, 
> > &nbrec_logical_router_policy_col_priority);
> >       ovsdb_idl_add_column(ctx->idl, 
> > &nbrec_logical_router_policy_col_match);
> > +
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_bfd_col_dst_ip);
> > +    ovsdb_idl_add_column(ctx->idl, &nbrec_bfd_col_logical_port);
> >   }
> >   static void
> > @@ -4158,6 +4170,68 @@ nbctl_lr_policy_add(struct ctl_context *ctx)
> >       nbrec_logical_router_update_policies_addvalue(lr, policy);
> > +    struct shash_node *bfd = shash_find(&ctx->options, "--bfd");
> > +    const struct nbrec_bfd **bfd_sessions = NULL;
> > +
> > +    if (bfd) {
> > +        if (!reroute) {
> > +            ctl_error(ctx, "BFD is valid only with reroute action.");
> > +            goto free_nexthops;
> > +        }
> > +
> > +        bfd_sessions = xcalloc(n_nexthops, sizeof *bfd_sessions);
> > +        size_t j, n_bfd_sessions = 0;
> > +
> > +        for (i = 0; i < n_nexthops; i++) {
> > +            for (j = 0; j < lr->n_ports; j++) {
> > +                if (ip_in_lrp_networks(lr->ports[j], nexthops[i])) {
> > +                    break;
> > +                }
> > +            }
> > +
> > +            if (j == lr->n_ports) {
> > +                ctl_error(ctx, "out lrp not found for %s nexthop",
> > +                          nexthops[i]);
> > +                goto free_nexthops;
> > +            }
> > +
> > +            const struct nbrec_bfd *iter, *nb_bt = NULL;
> > +            NBREC_BFD_FOR_EACH (iter, ctx->idl) {
> > +                /* match endpoint ip. */
> > +                if (strcmp(iter->dst_ip, nexthops[i])) {
> 
> Like my other comment, string comparison of IPv6 addresses may yield
> incorrect results.

ack, I will fix it.

Regards,
Lorenzo

> 
> > +                    continue;
> > +                }
> > +                /* match outport. */
> > +                if (strcmp(iter->logical_port, lr->ports[j]->name)) {
> > +                    continue;
> > +                }
> > +
> > +                nb_bt = iter;
> > +                break;
> > +            }
> > +
> > +            /* Create the BFD session if it does not already exist. */
> > +            if (!nb_bt) {
> > +                nb_bt = nbrec_bfd_insert(ctx->txn);
> > +                nbrec_bfd_set_dst_ip(nb_bt, nexthops[i]);
> > +                nbrec_bfd_set_logical_port(nb_bt, lr->ports[j]->name);
> > +            }
> > +
> > +            for (j = 0; j < n_bfd_sessions; j++) {
> > +                if (bfd_sessions[j] == nb_bt) {
> > +                    break;
> > +                }
> > +            }
> > +            if (j == n_bfd_sessions) {
> > +                bfd_sessions[n_bfd_sessions++] = nb_bt;
> > +            }
> > +        }
> > +        nbrec_logical_router_policy_set_bfd_sessions(
> > +                policy, (struct nbrec_bfd **) bfd_sessions, 
> > n_bfd_sessions);
> > +    }
> > +
> > +free_nexthops:
> > +    free(bfd_sessions);
> >       for (i = 0; i < n_nexthops; i++) {
> >           free(nexthops[i]);
> >       }
> > @@ -4282,8 +4356,11 @@ print_routing_policy(const struct 
> > nbrec_logical_router_policy *policy,
> >                         policy->match, policy->action);
> >       }
> > -    if (!smap_is_empty(&policy->options)) {
> > +    if (!smap_is_empty(&policy->options) || policy->n_bfd_sessions) {
> >           ds_put_format(s, "%15s", "");
> > +        if (policy->n_bfd_sessions) {
> > +            ds_put_cstr(s, "bfd,");
> > +        }
> >           struct smap_node *node;
> >           SMAP_FOR_EACH (node, &policy->options) {
> >               ds_put_format(s, "%s=%s,", node->key, node->value);
> > @@ -4305,6 +4382,8 @@ nbctl_pre_lr_policy_list(struct ctl_context *ctx)
> >       ovsdb_idl_add_column(ctx->idl, 
> > &nbrec_logical_router_policy_col_nexthops);
> >       ovsdb_idl_add_column(ctx->idl, 
> > &nbrec_logical_router_policy_col_action);
> >       ovsdb_idl_add_column(ctx->idl, 
> > &nbrec_logical_router_policy_col_options);
> > +    ovsdb_idl_add_column(ctx->idl,
> > +                         &nbrec_logical_router_policy_col_bfd_sessions);
> >   }
> >   static void
> > @@ -7900,7 +7979,8 @@ static const struct ctl_command_syntax 
> > nbctl_commands[] = {
> >       /* Policy commands */
> >       { "lr-policy-add", 4, INT_MAX,
> >        "ROUTER PRIORITY MATCH ACTION [NEXTHOP] [OPTIONS - KEY=VALUE ...]",
> > -     nbctl_pre_lr_policy_add, nbctl_lr_policy_add, NULL, "--may-exist", RW 
> > },
> > +     nbctl_pre_lr_policy_add, nbctl_lr_policy_add, NULL, 
> > "--may-exist,--bfd?",
> > +     RW },
> >       { "lr-policy-del", 1, 3, "ROUTER [{PRIORITY | UUID} [MATCH]]",
> >         nbctl_pre_lr_policy_del, nbctl_lr_policy_del, NULL, "--if-exists", 
> > RW },
> >       { "lr-policy-list", 1, 1, "ROUTER", nbctl_pre_lr_policy_list,
> 
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to