get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 810804,
    "url": "http://patchwork.ozlabs.org/api/patches/810804/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/openvswitch/patch/20170906210839.26091-4-mmichels@redhat.com/",
    "project": {
        "id": 47,
        "url": "http://patchwork.ozlabs.org/api/projects/47/?format=api",
        "name": "Open vSwitch",
        "link_name": "openvswitch",
        "list_id": "ovs-dev.openvswitch.org",
        "list_email": "ovs-dev@openvswitch.org",
        "web_url": "http://openvswitch.org/",
        "scm_url": "git@github.com:openvswitch/ovs.git",
        "webscm_url": "https://github.com/openvswitch/ovs",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20170906210839.26091-4-mmichels@redhat.com>",
    "list_archive_url": null,
    "date": "2017-09-06T21:08:38",
    "name": "[ovs-dev,3/4] ovn: Allow northd to install IPv6 ct_lb logical flows.",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "eb8835b6eb42996feb163248ab19fd2cea50db40",
    "submitter": {
        "id": 71978,
        "url": "http://patchwork.ozlabs.org/api/people/71978/?format=api",
        "name": "Mark Michelson",
        "email": "mmichels@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/openvswitch/patch/20170906210839.26091-4-mmichels@redhat.com/mbox/",
    "series": [
        {
            "id": 1883,
            "url": "http://patchwork.ozlabs.org/api/series/1883/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/openvswitch/list/?series=1883",
            "date": "2017-09-06T21:08:35",
            "name": "ovn: Add support for IPv6 load balancers",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/1883/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/810804/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/810804/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@mail.linuxfoundation.org"
        ],
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)",
            "ext-mx02.extmail.prod.ext.phx2.redhat.com;\n\tdmarc=none (p=none dis=none) header.from=redhat.com",
            "ext-mx02.extmail.prod.ext.phx2.redhat.com;\n\tspf=fail smtp.mailfrom=mmichels@redhat.com"
        ],
        "Received": [
            "from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xnbpL5gzlz9t3F\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu,  7 Sep 2017 07:10:34 +1000 (AEST)",
            "from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id 2E05BB9B;\n\tWed,  6 Sep 2017 21:08:47 +0000 (UTC)",
            "from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id 1A878B4C\n\tfor <dev@openvswitch.org>; Wed,  6 Sep 2017 21:08:45 +0000 (UTC)",
            "from mx1.redhat.com (mx1.redhat.com [209.132.183.28])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 672A9488\n\tfor <dev@openvswitch.org>; Wed,  6 Sep 2017 21:08:44 +0000 (UTC)",
            "from smtp.corp.redhat.com\n\t(int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby mx1.redhat.com (Postfix) with ESMTPS id D1F72859F7\n\tfor <dev@openvswitch.org>; Wed,  6 Sep 2017 21:08:43 +0000 (UTC)",
            "from monae.redhat.com (ovpn-121-224.rdu2.redhat.com\n\t[10.10.121.224])\n\tby smtp.corp.redhat.com (Postfix) with ESMTP id 4D913179D3\n\tfor <dev@openvswitch.org>; Wed,  6 Sep 2017 21:08:43 +0000 (UTC)"
        ],
        "X-Greylist": [
            "domain auto-whitelisted by SQLgrey-1.7.6",
            "Sender IP whitelisted, not delayed by milter-greylist-4.5.16\n\t(mx1.redhat.com [10.5.110.26]);\n\tWed, 06 Sep 2017 21:08:43 +0000 (UTC)"
        ],
        "DMARC-Filter": "OpenDMARC Filter v1.3.2 mx1.redhat.com D1F72859F7",
        "From": "Mark Michelson <mmichels@redhat.com>",
        "To": "dev@openvswitch.org",
        "Date": "Wed,  6 Sep 2017 16:08:38 -0500",
        "Message-Id": "<20170906210839.26091-4-mmichels@redhat.com>",
        "In-Reply-To": "<20170906210839.26091-1-mmichels@redhat.com>",
        "References": "<20170906210839.26091-1-mmichels@redhat.com>",
        "X-Scanned-By": "MIMEDefang 2.79 on 10.5.11.14",
        "X-Spam-Status": "No, score=-5.0 required=5.0 tests=RCVD_IN_DNSWL_HI,\n\tRP_MATCHES_RCVD autolearn=disabled version=3.3.1",
        "X-Spam-Checker-Version": "SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org",
        "Subject": "[ovs-dev] [PATCH 3/4] ovn: Allow northd to install IPv6 ct_lb\n\tlogical flows.",
        "X-BeenThere": "ovs-dev@openvswitch.org",
        "X-Mailman-Version": "2.1.12",
        "Precedence": "list",
        "List-Id": "<ovs-dev.openvswitch.org>",
        "List-Unsubscribe": "<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<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\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Sender": "ovs-dev-bounces@openvswitch.org",
        "Errors-To": "ovs-dev-bounces@openvswitch.org"
    },
    "content": "For this commit, ovn-northd will now accept both IPv4 and IPv6 addresses\nin the northbound database for a load balancer VIP or destination\naddresses. For IPv4, the behavior remains the same. For IPv6, the\nfollowing logical flows will be added to the southbound database:\n\n* An ND_NA response for incoming ND_NS requests for the load balancer\n  VIP.\n* A ct_lb flow with the configured IPv6 addresses.\n\nSigned-off-by: Mark Michelson <mmichels@redhat.com>\n---\n ovn/northd/ovn-northd.c | 170 ++++++++++++++++++++++++++++--------------------\n 1 file changed, 101 insertions(+), 69 deletions(-)",
    "diff": "diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c\nindex 49e4ac338..c8b4e4d4f 100644\n--- a/ovn/northd/ovn-northd.c\n+++ b/ovn/northd/ovn-northd.c\n@@ -1562,11 +1562,11 @@ join_logical_ports(struct northd_context *ctx,\n \n static void\n ip_address_and_port_from_lb_key(const char *key, char **ip_address,\n-                                uint16_t *port);\n+                                uint16_t *port, int *addr_family);\n \n static void\n get_router_load_balancer_ips(const struct ovn_datapath *od,\n-                             struct sset *all_ips)\n+                             struct sset *all_ips, int *addr_family)\n {\n     if (!od->nbr) {\n         return;\n@@ -1582,7 +1582,8 @@ get_router_load_balancer_ips(const struct ovn_datapath *od,\n             char *ip_address = NULL;\n             uint16_t port;\n \n-            ip_address_and_port_from_lb_key(node->key, &ip_address, &port);\n+            ip_address_and_port_from_lb_key(node->key, &ip_address, &port,\n+                                            addr_family);\n             if (!ip_address) {\n                 continue;\n             }\n@@ -1659,7 +1660,8 @@ get_nat_addresses(const struct ovn_port *op, size_t *n)\n \n     /* A set to hold all load-balancer vips. */\n     struct sset all_ips = SSET_INITIALIZER(&all_ips);\n-    get_router_load_balancer_ips(op->od, &all_ips);\n+    int addr_family;\n+    get_router_load_balancer_ips(op->od, &all_ips, &addr_family);\n \n     const char *ip_address;\n     SSET_FOR_EACH (ip_address, &all_ips) {\n@@ -2889,44 +2891,33 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows)\n  * 'ip_address'. */\n static void\n ip_address_and_port_from_lb_key(const char *key, char **ip_address,\n-                                uint16_t *port)\n+                                uint16_t *port, int *addr_family)\n {\n-    char *ip_str, *start, *next;\n-    *ip_address = NULL;\n-    *port = 0;\n+    struct sockaddr_storage ss;\n+    char ip_addr_buf[INET6_ADDRSTRLEN];\n+    char *error;\n \n-    next = start = xstrdup(key);\n-    ip_str = strsep(&next, \":\");\n-    if (!ip_str || !ip_str[0]) {\n-        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);\n-        VLOG_WARN_RL(&rl, \"bad ip address for load balancer key %s\", key);\n-        free(start);\n-        return;\n-    }\n-\n-    ovs_be32 ip, mask;\n-    char *error = ip_parse_masked(ip_str, &ip, &mask);\n-    if (error || mask != OVS_BE32_MAX) {\n+    error = ipv46_parse(key, PORT_OPTIONAL, &ss);\n+    if (error) {\n         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);\n-        VLOG_WARN_RL(&rl, \"bad ip address for load balancer key %s\", key);\n-        free(start);\n+        VLOG_WARN_RL(&rl, \"bad ip address or port for load balancer key %s\",\n+                     key);\n         free(error);\n         return;\n     }\n \n-    int l4_port = 0;\n-    if (next && next[0]) {\n-        if (!str_to_int(next, 0, &l4_port) || l4_port < 0 || l4_port > 65535) {\n-            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);\n-            VLOG_WARN_RL(&rl, \"bad ip port for load balancer key %s\", key);\n-            free(start);\n-            return;\n-        }\n+    if (ss.ss_family == AF_INET) {\n+        struct sockaddr_in *sin = ALIGNED_CAST(struct sockaddr_in *, &ss);\n+        *port = sin->sin_port == 0 ? 0 : ntohs(sin->sin_port);\n+        inet_ntop(AF_INET, &sin->sin_addr, ip_addr_buf, sizeof ip_addr_buf);\n+    } else {\n+        struct sockaddr_in6 *sin6 = ALIGNED_CAST(struct sockaddr_in6 *, &ss);\n+        *port = sin6->sin6_port == 0 ? 0 : ntohs(sin6->sin6_port);\n+        inet_ntop(AF_INET6, &sin6->sin6_addr, ip_addr_buf, sizeof ip_addr_buf);\n     }\n \n-    *port = l4_port;\n-    *ip_address = strdup(ip_str);\n-    free(start);\n+    *ip_address = xstrdup(ip_addr_buf);\n+    *addr_family = ss.ss_family;\n }\n \n /*\n@@ -2954,6 +2945,7 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows)\n \n     struct sset all_ips = SSET_INITIALIZER(&all_ips);\n     bool vip_configured = false;\n+    int addr_family = AF_INET;\n     for (int i = 0; i < od->nbs->n_load_balancer; i++) {\n         struct nbrec_load_balancer *lb = od->nbs->load_balancer[i];\n         struct smap *vips = &lb->vips;\n@@ -2965,7 +2957,8 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows)\n             /* node->key contains IP:port or just IP. */\n             char *ip_address = NULL;\n             uint16_t port;\n-            ip_address_and_port_from_lb_key(node->key, &ip_address, &port);\n+            ip_address_and_port_from_lb_key(node->key, &ip_address, &port,\n+                                            &addr_family);\n             if (!ip_address) {\n                 continue;\n             }\n@@ -2987,7 +2980,13 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows)\n      * packet to conntrack for defragmentation. */\n     const char *ip_address;\n     SSET_FOR_EACH(ip_address, &all_ips) {\n-        char *match = xasprintf(\"ip && ip4.dst == %s\", ip_address);\n+        char *match;\n+\n+        if (addr_family == AF_INET) {\n+            match = xasprintf(\"ip && ip4.dst == %s\", ip_address);\n+        } else {\n+            match = xasprintf(\"ip && ip6.dst == %s\", ip_address);\n+        }\n         ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB,\n                       100, match, REGBIT_CONNTRACK_DEFRAG\" = 1; next;\");\n         free(match);\n@@ -3445,10 +3444,12 @@ build_stateful(struct ovn_datapath *od, struct hmap *lflows)\n \n         SMAP_FOR_EACH (node, vips) {\n             uint16_t port = 0;\n+            int addr_family;\n \n             /* node->key contains IP:port or just IP. */\n             char *ip_address = NULL;\n-            ip_address_and_port_from_lb_key(node->key, &ip_address, &port);\n+            ip_address_and_port_from_lb_key(node->key, &ip_address, &port,\n+                                            &addr_family);\n             if (!ip_address) {\n                 continue;\n             }\n@@ -3456,7 +3457,11 @@ build_stateful(struct ovn_datapath *od, struct hmap *lflows)\n             /* New connections in Ingress table. */\n             char *action = xasprintf(\"ct_lb(%s);\", node->value);\n             struct ds match = DS_EMPTY_INITIALIZER;\n-            ds_put_format(&match, \"ct.new && ip4.dst == %s\", ip_address);\n+            if (addr_family == AF_INET) {\n+                ds_put_format(&match, \"ct.new && ip4.dst == %s\", ip_address);\n+            } else {\n+                ds_put_format(&match, \"ct.new && ip6.dst == %s\", ip_address);\n+            }\n             if (port) {\n                 if (lb->protocol && !strcmp(lb->protocol, \"udp\")) {\n                     ds_put_format(&match, \" && udp.dst == %d\", port);\n@@ -4564,36 +4569,55 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,\n \n         /* A set to hold all load-balancer vips that need ARP responses. */\n         struct sset all_ips = SSET_INITIALIZER(&all_ips);\n-        get_router_load_balancer_ips(op->od, &all_ips);\n+        int addr_family;\n+        get_router_load_balancer_ips(op->od, &all_ips, &addr_family);\n \n         const char *ip_address;\n         SSET_FOR_EACH(ip_address, &all_ips) {\n-            ovs_be32 ip;\n-            if (!ip_parse(ip_address, &ip) || !ip) {\n-                continue;\n-            }\n-\n             ds_clear(&match);\n-            ds_put_format(&match,\n-                          \"inport == %s && arp.tpa == \"IP_FMT\" && arp.op == 1\",\n-                          op->json_key, IP_ARGS(ip));\n+            if (addr_family == AF_INET) {\n+                ds_put_format(&match,\n+                              \"inport == %s && arp.tpa == %s && arp.op == 1\",\n+                              op->json_key, ip_address);\n+            } else {\n+                ds_put_format(&match,\n+                              \"inport == %s && nd_ns && nd.target == %s\",\n+                              op->json_key, ip_address);\n+            }\n \n             ds_clear(&actions);\n-            ds_put_format(&actions,\n+            if (addr_family == AF_INET) {\n+                ds_put_format(&actions,\n                 \"eth.dst = eth.src; \"\n                 \"eth.src = %s; \"\n                 \"arp.op = 2; /* ARP reply */ \"\n                 \"arp.tha = arp.sha; \"\n                 \"arp.sha = %s; \"\n                 \"arp.tpa = arp.spa; \"\n-                \"arp.spa = \"IP_FMT\"; \"\n+                \"arp.spa = %s; \"\n                 \"outport = %s; \"\n                 \"flags.loopback = 1; \"\n                 \"output;\",\n                 op->lrp_networks.ea_s,\n                 op->lrp_networks.ea_s,\n-                IP_ARGS(ip),\n+                ip_address,\n                 op->json_key);\n+            } else {\n+                ds_put_format(&actions,\n+                \"nd_na { \"\n+                \"eth.src = %s; \"\n+                \"ip6.src = %s; \"\n+                \"nd.target = %s; \"\n+                \"nd.tll = %s; \"\n+                \"outport = inport; \"\n+                \"flags.loopback = 1; \"\n+                \"output; \"\n+                \"};\",\n+                op->lrp_networks.ea_s,\n+                ip_address,\n+                ip_address,\n+                op->lrp_networks.ea_s);\n+            }\n             ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,\n                           ds_cstr(&match), ds_cstr(&actions));\n         }\n@@ -5257,16 +5281,36 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,\n \n             SMAP_FOR_EACH (node, vips) {\n                 uint16_t port = 0;\n+                int addr_family;\n \n                 /* node->key contains IP:port or just IP. */\n                 char *ip_address = NULL;\n-                ip_address_and_port_from_lb_key(node->key, &ip_address, &port);\n+                ip_address_and_port_from_lb_key(node->key, &ip_address, &port,\n+                        &addr_family);\n                 if (!ip_address) {\n                     continue;\n                 }\n \n                 if (!sset_contains(&all_ips, ip_address)) {\n                     sset_add(&all_ips, ip_address);\n+                    /* If there are any load balancing rules, we should send\n+                     * the packet to conntrack for defragmentation and\n+                     * tracking.  This helps with two things.\n+                     *\n+                     * 1. With tracking, we can send only new connections to\n+                     *    pick a DNAT ip address from a group.\n+                     * 2. If there are L4 ports in load balancing rules, we\n+                     *    need the defragmentation to match on L4 ports. */\n+                    ds_clear(&match);\n+                    if (addr_family == AF_INET) {\n+                        ds_put_format(&match, \"ip && ip4.dst == %s\",\n+                                      ip_address);\n+                    } else {\n+                        ds_put_format(&match, \"ip && ip6.dst == %s\",\n+                                      ip_address);\n+                    }\n+                    ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG,\n+                                  100, ds_cstr(&match), \"ct_next;\");\n                 }\n \n                 /* Higher priority rules are added for load-balancing in DNAT\n@@ -5278,8 +5322,13 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,\n                 ds_put_format(&actions, \"ct_lb(%s);\", node->value);\n \n                 ds_clear(&match);\n-                ds_put_format(&match, \"ip && ip4.dst == %s\",\n-                              ip_address);\n+                if (addr_family == AF_INET) {\n+                    ds_put_format(&match, \"ip && ip4.dst == %s\",\n+                                ip_address);\n+                } else {\n+                    ds_put_format(&match, \"ip && ip6.dst == %s\",\n+                                ip_address);\n+                }\n                 free(ip_address);\n \n                 if (port) {\n@@ -5298,23 +5347,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,\n                 }\n             }\n         }\n-\n-        /* If there are any load balancing rules, we should send the\n-         * packet to conntrack for defragmentation and tracking.  This helps\n-         * with two things.\n-         *\n-         * 1. With tracking, we can send only new connections to pick a\n-         *    DNAT ip address from a group.\n-         * 2. If there are L4 ports in load balancing rules, we need the\n-         *    defragmentation to match on L4 ports. */\n-        const char *ip_address;\n-        SSET_FOR_EACH(ip_address, &all_ips) {\n-            ds_clear(&match);\n-            ds_put_format(&match, \"ip && ip4.dst == %s\", ip_address);\n-            ovn_lflow_add(lflows, od, S_ROUTER_IN_DEFRAG,\n-                          100, ds_cstr(&match), \"ct_next;\");\n-        }\n-\n         sset_destroy(&all_ips);\n     }\n \n",
    "prefixes": [
        "ovs-dev",
        "3/4"
    ]
}