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 <b...@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 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev