get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/1525567/
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1525567,
    "url": "http://patchwork.ozlabs.org/api/patches/1525567/",
    "web_url": "http://patchwork.ozlabs.org/project/ovn/patch/20210907224516.489604-4-blp@ovn.org/",
    "project": {
        "id": 68,
        "url": "http://patchwork.ozlabs.org/api/projects/68/",
        "name": "Open Virtual Network development",
        "link_name": "ovn",
        "list_id": "ovs-dev.openvswitch.org",
        "list_email": "ovs-dev@openvswitch.org",
        "web_url": "http://openvswitch.org/",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20210907224516.489604-4-blp@ovn.org>",
    "list_archive_url": null,
    "date": "2021-09-07T22:45:09",
    "name": "[ovs-dev,v2,03/10] ovn-northd-ddlog: Derive load balancer IP addresses in new LoadBalancer.",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "ca653d6f1050e3d9102887df33b40bfe4d459016",
    "submitter": {
        "id": 67603,
        "url": "http://patchwork.ozlabs.org/api/people/67603/",
        "name": "Ben Pfaff",
        "email": "blp@ovn.org"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/ovn/patch/20210907224516.489604-4-blp@ovn.org/mbox/",
    "series": [
        {
            "id": 261352,
            "url": "http://patchwork.ozlabs.org/api/series/261352/",
            "web_url": "http://patchwork.ozlabs.org/project/ovn/list/?series=261352",
            "date": "2021-09-07T22:45:06",
            "name": "3x performance improvement for ddlog with load balancer benchmark",
            "version": 2,
            "mbox": "http://patchwork.ozlabs.org/series/261352/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/1525567/comments/",
    "check": "fail",
    "checks": "http://patchwork.ozlabs.org/api/patches/1525567/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<ovs-dev-bounces@openvswitch.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "dev@openvswitch.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@bilbo.ozlabs.org",
            "ovs-dev@lists.linuxfoundation.org"
        ],
        "Authentication-Results": "ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN>)",
        "Received": [
            "from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest\n SHA256)\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 4H40jQ1NdKz9t10\n\tfor <incoming@patchwork.ozlabs.org>; Wed,  8 Sep 2021 08:45:46 +1000 (AEST)",
            "from localhost (localhost [127.0.0.1])\n\tby smtp4.osuosl.org (Postfix) with ESMTP id 11074404D0;\n\tTue,  7 Sep 2021 22:45:41 +0000 (UTC)",
            "from smtp4.osuosl.org ([127.0.0.1])\n\tby localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id KrLwSbw8bSp0; Tue,  7 Sep 2021 22:45:38 +0000 (UTC)",
            "from lists.linuxfoundation.org (lf-lists.osuosl.org\n [IPv6:2605:bc80:3010:104::8cd3:938])\n\tby smtp4.osuosl.org (Postfix) with ESMTPS id BFA984045D;\n\tTue,  7 Sep 2021 22:45:37 +0000 (UTC)",
            "from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id B499EC0028;\n\tTue,  7 Sep 2021 22:45:35 +0000 (UTC)",
            "from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 37F5EC001D\n for <dev@openvswitch.org>; Tue,  7 Sep 2021 22:45:34 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n by smtp4.osuosl.org (Postfix) with ESMTP id 2B9B140393\n for <dev@openvswitch.org>; Tue,  7 Sep 2021 22:45:34 +0000 (UTC)",
            "from smtp4.osuosl.org ([127.0.0.1])\n by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n with ESMTP id RUgLhx6pvAlZ for <dev@openvswitch.org>;\n Tue,  7 Sep 2021 22:45:33 +0000 (UTC)",
            "from relay8-d.mail.gandi.net (relay8-d.mail.gandi.net\n [217.70.183.201])\n by smtp4.osuosl.org (Postfix) with ESMTPS id E35D740332\n for <dev@openvswitch.org>; Tue,  7 Sep 2021 22:45:32 +0000 (UTC)",
            "(Authenticated sender: blp@ovn.org)\n by relay8-d.mail.gandi.net (Postfix) with ESMTPSA id C7B1D1BF203;\n Tue,  7 Sep 2021 22:45:29 +0000 (UTC)"
        ],
        "X-Virus-Scanned": [
            "amavisd-new at osuosl.org",
            "amavisd-new at osuosl.org"
        ],
        "X-Greylist": "domain auto-whitelisted by SQLgrey-1.8.0",
        "From": "Ben Pfaff <blp@ovn.org>",
        "To": "dev@openvswitch.org",
        "Date": "Tue,  7 Sep 2021 15:45:09 -0700",
        "Message-Id": "<20210907224516.489604-4-blp@ovn.org>",
        "X-Mailer": "git-send-email 2.31.1",
        "In-Reply-To": "<20210907224516.489604-1-blp@ovn.org>",
        "References": "<20210907224516.489604-1-blp@ovn.org>",
        "MIME-Version": "1.0",
        "Cc": "Ben Pfaff <blp@ovn.org>",
        "Subject": "[ovs-dev] [PATCH ovn v2 03/10] ovn-northd-ddlog: Derive load\n\tbalancer IP addresses in new LoadBalancer.",
        "X-BeenThere": "ovs-dev@openvswitch.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "<ovs-dev.openvswitch.org>",
        "List-Unsubscribe": "<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>",
        "List-Archive": "<http://mail.openvswitch.org/pipermail/ovs-dev/>",
        "List-Post": "<mailto:ovs-dev@openvswitch.org>",
        "List-Help": "<mailto:ovs-dev-request@openvswitch.org?subject=help>",
        "List-Subscribe": "<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=subscribe>",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "ovs-dev-bounces@openvswitch.org",
        "Sender": "\"dev\" <ovs-dev-bounces@openvswitch.org>"
    },
    "content": "This makes the get_router_load_balancer_ips() function much faster.\nThis function is a hot path for the use of load balancers, so it\nimproves performance overall when they are in use.\n\nSigned-off-by: Ben Pfaff <blp@ovn.org>\n---\n northd/lrouter.dl    | 68 +++++++++++++++++++++++++++++++++------\n northd/ovn_northd.dl | 76 +++++++++++++++++++-------------------------\n 2 files changed, 91 insertions(+), 53 deletions(-)",
    "diff": "diff --git a/northd/lrouter.dl b/northd/lrouter.dl\nindex b6e752f7c..17d803292 100644\n--- a/northd/lrouter.dl\n+++ b/northd/lrouter.dl\n@@ -402,14 +402,13 @@ LogicalRouterSnatIPs(lr._uuid, map_empty()) :-\n     lr in nb::Logical_Router(),\n     not LogicalRouterSnatIP(.lr = lr._uuid).\n \n-relation LogicalRouterLB(lr: uuid, nat: Intern<nb::Load_Balancer>)\n-\n+relation LogicalRouterLB(lr: uuid, nat: Intern<LoadBalancer>)\n LogicalRouterLB(lr, lb) :-\n     nb::Logical_Router(._uuid = lr, .load_balancer = lbs),\n     var lb_uuid = FlatMap(lbs),\n-    lb in &nb::Load_Balancer(._uuid = lb_uuid).\n+    lb in &LoadBalancer(.lb = &nb::Load_Balancer{._uuid = lb_uuid}).\n \n-relation LogicalRouterLBs(lr: uuid, nat: Vec<Intern<nb::Load_Balancer>>)\n+relation LogicalRouterLBs(lr: uuid, nat: Vec<Intern<LoadBalancer>>)\n \n LogicalRouterLBs(lr, lbs) :-\n      LogicalRouterLB(lr, lb),\n@@ -448,6 +447,31 @@ LogicalRouterCopp0(lr, meters) :-\n \n function chassis_redirect_name(port_name: istring): string = \"cr-${port_name}\"\n \n+typedef LoadBalancer = LoadBalancer {\n+    lb: Intern<nb::Load_Balancer>,\n+    ipv4s: Set<istring>,\n+    ipv6s: Set<istring>,\n+    routable: bool\n+}\n+\n+relation LoadBalancer[Intern<LoadBalancer>]\n+LoadBalancer[LoadBalancer{lb, ipv4s, ipv6s, routable}.intern()] :-\n+    nb::Load_Balancer[lb],\n+    var routable = lb.options.get_bool_def(i\"add_route\", false),\n+    (var ipv4s, var ipv6s) = {\n+        var ipv4s = set_empty();\n+        var ipv6s = set_empty();\n+        for ((vip, _) in lb.vips) {\n+            /* node->key contains IP:port or just IP. */\n+            match (ip_address_and_port_from_lb_key(vip.ival())) {\n+                None -> (),\n+                Some{(IPv4{ipv4}, _)} -> ipv4s.insert(i\"${ipv4}\"),\n+                Some{(IPv6{ipv6}, _)} -> ipv6s.insert(i\"${ipv6}\"),\n+            }\n+        };\n+        (ipv4s, ipv6s)\n+    }.\n+\n typedef Router = Router {\n     /* Fields copied from nb::Logical_Router. */\n     _uuid:              uuid,\n@@ -464,7 +488,11 @@ typedef Router = Router {\n     is_gateway:         bool,\n     nats:               Vec<NAT>,\n     snat_ips:           Map<v46_ip, Set<NAT>>,\n-    lbs:                Vec<Intern<nb::Load_Balancer>>,\n+    lbs:                Vec<Intern<LoadBalancer>>,\n+    lb_ipv4s_routable:  Set<istring>,\n+    lb_ipv4s_unroutable: Set<istring>,\n+    lb_ipv6s_routable:  Set<istring>,\n+    lb_ipv6s_unroutable: Set<istring>,\n     mcast_cfg:          Intern<McastRouterCfg>,\n     learn_from_arp_request: bool,\n     force_lb_snat: bool,\n@@ -488,6 +516,10 @@ Router[Router{\n         .nats        = nats,\n         .snat_ips    = snat_ips,\n         .lbs         = lbs,\n+        .lb_ipv4s_routable = lb_ipv4s_routable,\n+        .lb_ipv4s_unroutable = lb_ipv4s_unroutable,\n+        .lb_ipv6s_routable = lb_ipv6s_routable,\n+        .lb_ipv6s_unroutable = lb_ipv6s_unroutable,\n         .mcast_cfg   = mcast_cfg,\n         .learn_from_arp_request = learn_from_arp_request,\n         .force_lb_snat = force_lb_snat,\n@@ -501,10 +533,28 @@ Router[Router{\n     LogicalRouterCopp(lr._uuid, copp),\n     mcast_cfg in &McastRouterCfg(.datapath = lr._uuid),\n     var learn_from_arp_request = lr.options.get_bool_def(i\"always_learn_from_arp_request\", true),\n-    var force_lb_snat = lb_force_snat_router_ip(lr.options).\n+    var force_lb_snat = lb_force_snat_router_ip(lr.options),\n+    (var lb_ipv4s_routable, var lb_ipv4s_unroutable,\n+     var lb_ipv6s_routable, var lb_ipv6s_unroutable) = {\n+        var lb_ipv4s_routable = set_empty();\n+        var lb_ipv4s_unroutable = set_empty();\n+        var lb_ipv6s_routable = set_empty();\n+        var lb_ipv6s_unroutable = set_empty();\n+        for (lb in lbs) {\n+            if (lb.routable) {\n+                lb_ipv4s_routable = lb_ipv4s_routable.union(lb.ipv4s);\n+                lb_ipv6s_routable = lb_ipv6s_routable.union(lb.ipv6s);\n+            } else {\n+                lb_ipv4s_unroutable = lb_ipv4s_unroutable.union(lb.ipv4s);\n+                lb_ipv6s_unroutable = lb_ipv6s_unroutable.union(lb.ipv6s);\n+            }\n+        };\n+        (lb_ipv4s_routable, lb_ipv4s_unroutable,\n+         lb_ipv6s_routable, lb_ipv6s_unroutable)\n+    }.\n \n /* RouterLB: many-to-many relation between logical routers and nb::LB */\n-relation RouterLB(router: Intern<Router>, lb: Intern<nb::Load_Balancer>)\n+relation RouterLB(router: Intern<Router>, lb: Intern<LoadBalancer>)\n \n RouterLB(router, lb) :-\n     router in &Router(.lbs = lbs),\n@@ -513,12 +563,12 @@ RouterLB(router, lb) :-\n /* Load balancer VIPs associated with routers */\n relation RouterLBVIP(\n     router: Intern<Router>,\n-    lb: Intern<nb::Load_Balancer>,\n+    lb: Intern<LoadBalancer>,\n     vip: istring,\n     backends: istring)\n \n RouterLBVIP(router, lb, vip, backends) :-\n-    RouterLB(router, lb@(&nb::Load_Balancer{.vips = vips})),\n+    RouterLB(router, lb@(&LoadBalancer{.lb = &nb::Load_Balancer{.vips = vips}})),\n     (var vip, var backends) = FlatMap(vips).\n \n /* Router-to-router logical port connections */\ndiff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl\nindex c41a79b84..4348171ba 100644\n--- a/northd/ovn_northd.dl\n+++ b/northd/ovn_northd.dl\n@@ -312,22 +312,12 @@ function get_router_load_balancer_ips(router: Intern<Router>,\n                                       routable_only: bool) :\n     (Set<istring>, Set<istring>) =\n {\n-    var all_ips_v4 = set_empty();\n-    var all_ips_v6 = set_empty();\n-    for (lb in router.lbs) {\n-        if (routable_only and not lb.options.get_bool_def(i\"add_route\", false)) {\n-            continue;\n-        };\n-        for ((vip, _) in lb.vips) {\n-            /* node->key contains IP:port or just IP. */\n-            match (ip_address_and_port_from_lb_key(vip.ival())) {\n-                None -> (),\n-                Some{(IPv4{ipv4}, _)} -> all_ips_v4.insert(i\"${ipv4}\"),\n-                Some{(IPv6{ipv6}, _)} -> all_ips_v6.insert(i\"${ipv6}\")\n-            }\n-        }\n-    };\n-    (all_ips_v4, all_ips_v6)\n+    if (routable_only) {\n+        (router.lb_ipv4s_routable, router.lb_ipv6s_routable)\n+    } else {\n+        (union(router.lb_ipv4s_routable, router.lb_ipv4s_unroutable),\n+         union(router.lb_ipv6s_routable, router.lb_ipv6s_unroutable))\n+    }\n }\n \n /* Returns an array of strings, each consisting of a MAC address followed\n@@ -2204,11 +2194,11 @@ function build_empty_lb_event_flow(key: istring, lb: Intern<nb::Load_Balancer>):\n  * The deprecated way is to set nb::NB_Global options:controller_event=true,\n  * which enables events for every load balancer.\n  */\n-relation LoadBalancerEmptyEvents(lb: Intern<nb::Load_Balancer>)\n-LoadBalancerEmptyEvents(lb) :-\n+relation LoadBalancerEmptyEvents(lb_uuid: uuid)\n+LoadBalancerEmptyEvents(lb_uuid) :-\n     nb::NB_Global(.options = global_options),\n     var global_events = global_options.get_bool_def(i\"controller_event\", false),\n-    lb in &nb::Load_Balancer(.options = local_options),\n+    &nb::Load_Balancer(._uuid = lb_uuid, .options = local_options),\n     var local_events = local_options.get_bool_def(i\"event\", false),\n     global_events or local_events.\n \n@@ -2221,7 +2211,7 @@ Flow(.logical_datapath = sw._uuid,\n      .controller_meter = sw.copp.get(cOPP_EVENT_ELB()),\n      .stage_hint       = stage_hint(lb._uuid)) :-\n     SwitchLBVIP(.sw_uuid = sw_uuid, .lb = lb, .vip = vip, .backends = backends),\n-    LoadBalancerEmptyEvents(lb),\n+    LoadBalancerEmptyEvents(lb._uuid),\n     not lb.options.get_bool_def(i\"reject\", false),\n     sw in &Switch(._uuid = sw_uuid),\n     backends == i\"\",\n@@ -5676,18 +5666,16 @@ var residence_check = match (is_redirect) {\n     true -> Some{i\"is_chassis_resident(${json_escape(chassis_redirect_name(lrp.name))})\"},\n     false -> None\n } in {\n-    (var all_ips_v4, _) = get_router_load_balancer_ips(router, false) in {\n-        if (not all_ips_v4.is_empty()) {\n-            LogicalRouterArpFlow(.lr = router,\n-                                 .lrp = Some{lrp},\n-                                 .ip = i\"{ ${all_ips_v4.map(ival).to_vec().join(\\\", \\\")} }\",\n-                                 .mac = rEG_INPORT_ETH_ADDR(),\n-                                 .extra_match = residence_check,\n-                                 .drop = false,\n-                                 .priority = 90,\n-                                 .stage_hint = 0)\n-        }\n-    };\n+    var all_ipv4s = union(router.lb_ipv4s_routable, router.lb_ipv4s_unroutable) in\n+    not all_ipv4s.is_empty() in\n+    LogicalRouterArpFlow(.lr = router,\n+                         .lrp = Some{lrp},\n+                         .ip = i\"{ ${all_ipv4s.map(ival).to_vec().join(\\\", \\\")} }\",\n+                         .mac = rEG_INPORT_ETH_ADDR(),\n+                         .extra_match = residence_check,\n+                         .drop = false,\n+                         .priority = 90,\n+                         .stage_hint = 0);\n     for (RouterLBVIP(.router = &Router{._uuid= lr_uuid}, .vip = vip)) {\n         Some{(var ip_address, _)} = ip_address_and_port_from_lb_key(vip.ival()) in {\n             IPv6{var ipv6} = ip_address in\n@@ -6057,11 +6045,11 @@ Flow(.logical_datapath = lr,\n      .priority         = 120,\n      .__match          = i\"flags.skip_snat_for_lb == 1 && ip\",\n      .actions          = i\"next;\",\n-     .stage_hint       = stage_hint(lb._uuid),\n+     .stage_hint       = stage_hint(lb.lb._uuid),\n      .io_port          = None,\n      .controller_meter = None) :-\n     LogicalRouterLB(lr, lb),\n-    lb.options.get_bool_def(i\"skip_snat\", false)\n+    lb.lb.options.get_bool_def(i\"skip_snat\", false)\n     .\n \n function lrouter_nat_is_stateless(nat: NAT): bool = {\n@@ -6683,10 +6671,10 @@ for (RouterLBVIP(\n         .backends = backends)\n      if not l3dgw_ports.is_empty() or is_gateway)\n {\n-    if (backends == i\"\" and not lb.options.get_bool_def(i\"reject\", false)) {\n-        for (LoadBalancerEmptyEvents(lb)) {\n+    if (backends == i\"\" and not lb.lb.options.get_bool_def(i\"reject\", false)) {\n+        for (LoadBalancerEmptyEvents(lb.lb._uuid)) {\n             Some {(var __match, var __action)} =\n-                build_empty_lb_event_flow(vip, lb) in\n+                build_empty_lb_event_flow(vip, lb.lb) in\n             Flow(.logical_datapath = lr_uuid,\n                  .stage            = s_ROUTER_IN_DNAT(),\n                  .priority         = 130,\n@@ -6694,7 +6682,7 @@ for (RouterLBVIP(\n                  .actions          = __action,\n                  .io_port          = None,\n                  .controller_meter = r.copp.get(cOPP_EVENT_ELB()),\n-                 .stage_hint       = stage_hint(lb._uuid))\n+                 .stage_hint       = stage_hint(lb.lb._uuid))\n         }\n     };\n \n@@ -6703,7 +6691,7 @@ for (RouterLBVIP(\n     /* vip contains IP:port or just IP. */\n     Some{(var ip_address, var port)} = ip_address_and_port_from_lb_key(vip.ival()) in\n     var ipX = ip_address.ipX() in\n-    var proto = match (lb.protocol) {\n+    var proto = match (lb.lb.protocol) {\n         Some{proto} -> proto,\n         _ -> i\"tcp\"\n     } in {\n@@ -6759,15 +6747,15 @@ for (RouterLBVIP(\n                 (110, \"\")\n             } in\n         var __match = match1 ++ match2 ++\n-            match ((l3dgw_ports.nth(0), backends != i\"\" or lb.options.get_bool_def(i\"reject\", false))) {\n+            match ((l3dgw_ports.nth(0), backends != i\"\" or lb.lb.options.get_bool_def(i\"reject\", false))) {\n                 (Some{gw_port}, true) -> \" && is_chassis_resident(${json_escape(chassis_redirect_name(gw_port.name))})\",\n                 _ -> \"\"\n             } in\n-        var snat_for_lb = snat_for_lb(r.options, lb) in\n+        var snat_for_lb = snat_for_lb(r.options, lb.lb) in\n         {\n             /* A match and actions for established connections. */\n             var est_match = \"ct.est && \" ++ match1 ++ match2 ++ \" && ct_label.natted == 1\" ++\n-                match ((l3dgw_ports.nth(0), backends != i\"\" or lb.options.get_bool_def(i\"reject\", false))) {\n+                match ((l3dgw_ports.nth(0), backends != i\"\" or lb.lb.options.get_bool_def(i\"reject\", false))) {\n                     (Some {var gw_port}, true) -> \" && is_chassis_resident(${json_string_escape(chassis_redirect_name(gw_port.name))})\",\n                     _ -> \"\"\n                 } in\n@@ -6806,7 +6794,7 @@ for (RouterLBVIP(\n                      .priority         = 120,\n                      .__match          = match3.intern(),\n                      .actions          = i\"next;\",\n-                     .stage_hint       = stage_hint(lb._uuid),\n+                     .stage_hint       = stage_hint(lb.lb._uuid),\n                      .io_port          = None,\n                      .controller_meter = None)\n             };\n@@ -6848,7 +6836,7 @@ for (RouterLBVIP(\n                  .priority         = 120,\n                  .__match          = undnat_match.intern(),\n                  .actions          = action,\n-                 .stage_hint       = stage_hint(lb._uuid),\n+                 .stage_hint       = stage_hint(lb.lb._uuid),\n                  .io_port          = None,\n                  .controller_meter = None)\n         }\n",
    "prefixes": [
        "ovs-dev",
        "v2",
        "03/10"
    ]
}