[ovs-dev] [PATCH ovn v2 03/10] ovn-northd-ddlog: Derive load balancer IP addresses in new LoadBalancer.

Ben Pfaff blp at ovn.org
Tue Sep 7 22:45:09 UTC 2021


This makes the get_router_load_balancer_ips() function much faster.
This function is a hot path for the use of load balancers, so it
improves performance overall when they are in use.

Signed-off-by: Ben Pfaff <blp at ovn.org>
---
 northd/lrouter.dl    | 68 +++++++++++++++++++++++++++++++++------
 northd/ovn_northd.dl | 76 +++++++++++++++++++-------------------------
 2 files changed, 91 insertions(+), 53 deletions(-)

diff --git a/northd/lrouter.dl b/northd/lrouter.dl
index b6e752f7c..17d803292 100644
--- a/northd/lrouter.dl
+++ b/northd/lrouter.dl
@@ -402,14 +402,13 @@ LogicalRouterSnatIPs(lr._uuid, map_empty()) :-
     lr in nb::Logical_Router(),
     not LogicalRouterSnatIP(.lr = lr._uuid).
 
-relation LogicalRouterLB(lr: uuid, nat: Intern<nb::Load_Balancer>)
-
+relation LogicalRouterLB(lr: uuid, nat: Intern<LoadBalancer>)
 LogicalRouterLB(lr, lb) :-
     nb::Logical_Router(._uuid = lr, .load_balancer = lbs),
     var lb_uuid = FlatMap(lbs),
-    lb in &nb::Load_Balancer(._uuid = lb_uuid).
+    lb in &LoadBalancer(.lb = &nb::Load_Balancer{._uuid = lb_uuid}).
 
-relation LogicalRouterLBs(lr: uuid, nat: Vec<Intern<nb::Load_Balancer>>)
+relation LogicalRouterLBs(lr: uuid, nat: Vec<Intern<LoadBalancer>>)
 
 LogicalRouterLBs(lr, lbs) :-
      LogicalRouterLB(lr, lb),
@@ -448,6 +447,31 @@ LogicalRouterCopp0(lr, meters) :-
 
 function chassis_redirect_name(port_name: istring): string = "cr-${port_name}"
 
+typedef LoadBalancer = LoadBalancer {
+    lb: Intern<nb::Load_Balancer>,
+    ipv4s: Set<istring>,
+    ipv6s: Set<istring>,
+    routable: bool
+}
+
+relation LoadBalancer[Intern<LoadBalancer>]
+LoadBalancer[LoadBalancer{lb, ipv4s, ipv6s, routable}.intern()] :-
+    nb::Load_Balancer[lb],
+    var routable = lb.options.get_bool_def(i"add_route", false),
+    (var ipv4s, var ipv6s) = {
+        var ipv4s = set_empty();
+        var ipv6s = set_empty();
+        for ((vip, _) in lb.vips) {
+            /* node->key contains IP:port or just IP. */
+            match (ip_address_and_port_from_lb_key(vip.ival())) {
+                None -> (),
+                Some{(IPv4{ipv4}, _)} -> ipv4s.insert(i"${ipv4}"),
+                Some{(IPv6{ipv6}, _)} -> ipv6s.insert(i"${ipv6}"),
+            }
+        };
+        (ipv4s, ipv6s)
+    }.
+
 typedef Router = Router {
     /* Fields copied from nb::Logical_Router. */
     _uuid:              uuid,
@@ -464,7 +488,11 @@ typedef Router = Router {
     is_gateway:         bool,
     nats:               Vec<NAT>,
     snat_ips:           Map<v46_ip, Set<NAT>>,
-    lbs:                Vec<Intern<nb::Load_Balancer>>,
+    lbs:                Vec<Intern<LoadBalancer>>,
+    lb_ipv4s_routable:  Set<istring>,
+    lb_ipv4s_unroutable: Set<istring>,
+    lb_ipv6s_routable:  Set<istring>,
+    lb_ipv6s_unroutable: Set<istring>,
     mcast_cfg:          Intern<McastRouterCfg>,
     learn_from_arp_request: bool,
     force_lb_snat: bool,
@@ -488,6 +516,10 @@ Router[Router{
         .nats        = nats,
         .snat_ips    = snat_ips,
         .lbs         = lbs,
+        .lb_ipv4s_routable = lb_ipv4s_routable,
+        .lb_ipv4s_unroutable = lb_ipv4s_unroutable,
+        .lb_ipv6s_routable = lb_ipv6s_routable,
+        .lb_ipv6s_unroutable = lb_ipv6s_unroutable,
         .mcast_cfg   = mcast_cfg,
         .learn_from_arp_request = learn_from_arp_request,
         .force_lb_snat = force_lb_snat,
@@ -501,10 +533,28 @@ Router[Router{
     LogicalRouterCopp(lr._uuid, copp),
     mcast_cfg in &McastRouterCfg(.datapath = lr._uuid),
     var learn_from_arp_request = lr.options.get_bool_def(i"always_learn_from_arp_request", true),
-    var force_lb_snat = lb_force_snat_router_ip(lr.options).
+    var force_lb_snat = lb_force_snat_router_ip(lr.options),
+    (var lb_ipv4s_routable, var lb_ipv4s_unroutable,
+     var lb_ipv6s_routable, var lb_ipv6s_unroutable) = {
+        var lb_ipv4s_routable = set_empty();
+        var lb_ipv4s_unroutable = set_empty();
+        var lb_ipv6s_routable = set_empty();
+        var lb_ipv6s_unroutable = set_empty();
+        for (lb in lbs) {
+            if (lb.routable) {
+                lb_ipv4s_routable = lb_ipv4s_routable.union(lb.ipv4s);
+                lb_ipv6s_routable = lb_ipv6s_routable.union(lb.ipv6s);
+            } else {
+                lb_ipv4s_unroutable = lb_ipv4s_unroutable.union(lb.ipv4s);
+                lb_ipv6s_unroutable = lb_ipv6s_unroutable.union(lb.ipv6s);
+            }
+        };
+        (lb_ipv4s_routable, lb_ipv4s_unroutable,
+         lb_ipv6s_routable, lb_ipv6s_unroutable)
+    }.
 
 /* RouterLB: many-to-many relation between logical routers and nb::LB */
-relation RouterLB(router: Intern<Router>, lb: Intern<nb::Load_Balancer>)
+relation RouterLB(router: Intern<Router>, lb: Intern<LoadBalancer>)
 
 RouterLB(router, lb) :-
     router in &Router(.lbs = lbs),
@@ -513,12 +563,12 @@ RouterLB(router, lb) :-
 /* Load balancer VIPs associated with routers */
 relation RouterLBVIP(
     router: Intern<Router>,
-    lb: Intern<nb::Load_Balancer>,
+    lb: Intern<LoadBalancer>,
     vip: istring,
     backends: istring)
 
 RouterLBVIP(router, lb, vip, backends) :-
-    RouterLB(router, lb@(&nb::Load_Balancer{.vips = vips})),
+    RouterLB(router, lb@(&LoadBalancer{.lb = &nb::Load_Balancer{.vips = vips}})),
     (var vip, var backends) = FlatMap(vips).
 
 /* Router-to-router logical port connections */
diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl
index c41a79b84..4348171ba 100644
--- a/northd/ovn_northd.dl
+++ b/northd/ovn_northd.dl
@@ -312,22 +312,12 @@ function get_router_load_balancer_ips(router: Intern<Router>,
                                       routable_only: bool) :
     (Set<istring>, Set<istring>) =
 {
-    var all_ips_v4 = set_empty();
-    var all_ips_v6 = set_empty();
-    for (lb in router.lbs) {
-        if (routable_only and not lb.options.get_bool_def(i"add_route", false)) {
-            continue;
-        };
-        for ((vip, _) in lb.vips) {
-            /* node->key contains IP:port or just IP. */
-            match (ip_address_and_port_from_lb_key(vip.ival())) {
-                None -> (),
-                Some{(IPv4{ipv4}, _)} -> all_ips_v4.insert(i"${ipv4}"),
-                Some{(IPv6{ipv6}, _)} -> all_ips_v6.insert(i"${ipv6}")
-            }
-        }
-    };
-    (all_ips_v4, all_ips_v6)
+    if (routable_only) {
+        (router.lb_ipv4s_routable, router.lb_ipv6s_routable)
+    } else {
+        (union(router.lb_ipv4s_routable, router.lb_ipv4s_unroutable),
+         union(router.lb_ipv6s_routable, router.lb_ipv6s_unroutable))
+    }
 }
 
 /* Returns an array of strings, each consisting of a MAC address followed
@@ -2204,11 +2194,11 @@ function build_empty_lb_event_flow(key: istring, lb: Intern<nb::Load_Balancer>):
  * The deprecated way is to set nb::NB_Global options:controller_event=true,
  * which enables events for every load balancer.
  */
-relation LoadBalancerEmptyEvents(lb: Intern<nb::Load_Balancer>)
-LoadBalancerEmptyEvents(lb) :-
+relation LoadBalancerEmptyEvents(lb_uuid: uuid)
+LoadBalancerEmptyEvents(lb_uuid) :-
     nb::NB_Global(.options = global_options),
     var global_events = global_options.get_bool_def(i"controller_event", false),
-    lb in &nb::Load_Balancer(.options = local_options),
+    &nb::Load_Balancer(._uuid = lb_uuid, .options = local_options),
     var local_events = local_options.get_bool_def(i"event", false),
     global_events or local_events.
 
@@ -2221,7 +2211,7 @@ Flow(.logical_datapath = sw._uuid,
      .controller_meter = sw.copp.get(cOPP_EVENT_ELB()),
      .stage_hint       = stage_hint(lb._uuid)) :-
     SwitchLBVIP(.sw_uuid = sw_uuid, .lb = lb, .vip = vip, .backends = backends),
-    LoadBalancerEmptyEvents(lb),
+    LoadBalancerEmptyEvents(lb._uuid),
     not lb.options.get_bool_def(i"reject", false),
     sw in &Switch(._uuid = sw_uuid),
     backends == i"",
@@ -5676,18 +5666,16 @@ var residence_check = match (is_redirect) {
     true -> Some{i"is_chassis_resident(${json_escape(chassis_redirect_name(lrp.name))})"},
     false -> None
 } in {
-    (var all_ips_v4, _) = get_router_load_balancer_ips(router, false) in {
-        if (not all_ips_v4.is_empty()) {
-            LogicalRouterArpFlow(.lr = router,
-                                 .lrp = Some{lrp},
-                                 .ip = i"{ ${all_ips_v4.map(ival).to_vec().join(\", \")} }",
-                                 .mac = rEG_INPORT_ETH_ADDR(),
-                                 .extra_match = residence_check,
-                                 .drop = false,
-                                 .priority = 90,
-                                 .stage_hint = 0)
-        }
-    };
+    var all_ipv4s = union(router.lb_ipv4s_routable, router.lb_ipv4s_unroutable) in
+    not all_ipv4s.is_empty() in
+    LogicalRouterArpFlow(.lr = router,
+                         .lrp = Some{lrp},
+                         .ip = i"{ ${all_ipv4s.map(ival).to_vec().join(\", \")} }",
+                         .mac = rEG_INPORT_ETH_ADDR(),
+                         .extra_match = residence_check,
+                         .drop = false,
+                         .priority = 90,
+                         .stage_hint = 0);
     for (RouterLBVIP(.router = &Router{._uuid= lr_uuid}, .vip = vip)) {
         Some{(var ip_address, _)} = ip_address_and_port_from_lb_key(vip.ival()) in {
             IPv6{var ipv6} = ip_address in
@@ -6057,11 +6045,11 @@ Flow(.logical_datapath = lr,
      .priority         = 120,
      .__match          = i"flags.skip_snat_for_lb == 1 && ip",
      .actions          = i"next;",
-     .stage_hint       = stage_hint(lb._uuid),
+     .stage_hint       = stage_hint(lb.lb._uuid),
      .io_port          = None,
      .controller_meter = None) :-
     LogicalRouterLB(lr, lb),
-    lb.options.get_bool_def(i"skip_snat", false)
+    lb.lb.options.get_bool_def(i"skip_snat", false)
     .
 
 function lrouter_nat_is_stateless(nat: NAT): bool = {
@@ -6683,10 +6671,10 @@ for (RouterLBVIP(
         .backends = backends)
      if not l3dgw_ports.is_empty() or is_gateway)
 {
-    if (backends == i"" and not lb.options.get_bool_def(i"reject", false)) {
-        for (LoadBalancerEmptyEvents(lb)) {
+    if (backends == i"" and not lb.lb.options.get_bool_def(i"reject", false)) {
+        for (LoadBalancerEmptyEvents(lb.lb._uuid)) {
             Some {(var __match, var __action)} =
-                build_empty_lb_event_flow(vip, lb) in
+                build_empty_lb_event_flow(vip, lb.lb) in
             Flow(.logical_datapath = lr_uuid,
                  .stage            = s_ROUTER_IN_DNAT(),
                  .priority         = 130,
@@ -6694,7 +6682,7 @@ for (RouterLBVIP(
                  .actions          = __action,
                  .io_port          = None,
                  .controller_meter = r.copp.get(cOPP_EVENT_ELB()),
-                 .stage_hint       = stage_hint(lb._uuid))
+                 .stage_hint       = stage_hint(lb.lb._uuid))
         }
     };
 
@@ -6703,7 +6691,7 @@ for (RouterLBVIP(
     /* vip contains IP:port or just IP. */
     Some{(var ip_address, var port)} = ip_address_and_port_from_lb_key(vip.ival()) in
     var ipX = ip_address.ipX() in
-    var proto = match (lb.protocol) {
+    var proto = match (lb.lb.protocol) {
         Some{proto} -> proto,
         _ -> i"tcp"
     } in {
@@ -6759,15 +6747,15 @@ for (RouterLBVIP(
                 (110, "")
             } in
         var __match = match1 ++ match2 ++
-            match ((l3dgw_ports.nth(0), backends != i"" or lb.options.get_bool_def(i"reject", false))) {
+            match ((l3dgw_ports.nth(0), backends != i"" or lb.lb.options.get_bool_def(i"reject", false))) {
                 (Some{gw_port}, true) -> " && is_chassis_resident(${json_escape(chassis_redirect_name(gw_port.name))})",
                 _ -> ""
             } in
-        var snat_for_lb = snat_for_lb(r.options, lb) in
+        var snat_for_lb = snat_for_lb(r.options, lb.lb) in
         {
             /* A match and actions for established connections. */
             var est_match = "ct.est && " ++ match1 ++ match2 ++ " && ct_label.natted == 1" ++
-                match ((l3dgw_ports.nth(0), backends != i"" or lb.options.get_bool_def(i"reject", false))) {
+                match ((l3dgw_ports.nth(0), backends != i"" or lb.lb.options.get_bool_def(i"reject", false))) {
                     (Some {var gw_port}, true) -> " && is_chassis_resident(${json_string_escape(chassis_redirect_name(gw_port.name))})",
                     _ -> ""
                 } in
@@ -6806,7 +6794,7 @@ for (RouterLBVIP(
                      .priority         = 120,
                      .__match          = match3.intern(),
                      .actions          = i"next;",
-                     .stage_hint       = stage_hint(lb._uuid),
+                     .stage_hint       = stage_hint(lb.lb._uuid),
                      .io_port          = None,
                      .controller_meter = None)
             };
@@ -6848,7 +6836,7 @@ for (RouterLBVIP(
                  .priority         = 120,
                  .__match          = undnat_match.intern(),
                  .actions          = action,
-                 .stage_hint       = stage_hint(lb._uuid),
+                 .stage_hint       = stage_hint(lb.lb._uuid),
                  .io_port          = None,
                  .controller_meter = None)
         }
-- 
2.31.1



More information about the dev mailing list