{"id":817002,"url":"http://patchwork.ozlabs.org/api/patches/817002/?format=json","web_url":"http://patchwork.ozlabs.org/project/openvswitch/patch/20170921160949.24901-1-nusiddiq@redhat.com/","project":{"id":47,"url":"http://patchwork.ozlabs.org/api/projects/47/?format=json","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":"<20170921160949.24901-1-nusiddiq@redhat.com>","list_archive_url":null,"date":"2017-09-21T16:09:49","name":"[ovs-dev,v8,3/4] ovn-northd: Add logical flows to support native IPv6 RA","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"04182983eaead65a630451ceb32dc2ff2540a56d","submitter":{"id":67480,"url":"http://patchwork.ozlabs.org/api/people/67480/?format=json","name":"Numan Siddique","email":"nusiddiq@redhat.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/openvswitch/patch/20170921160949.24901-1-nusiddiq@redhat.com/mbox/","series":[{"id":4431,"url":"http://patchwork.ozlabs.org/api/series/4431/?format=json","web_url":"http://patchwork.ozlabs.org/project/openvswitch/list/?series=4431","date":"2017-09-21T16:07:47","name":"ovn IPv6: Add Router Solicitation responder support and generate Neighbor Solicitation request for unknown MACs","version":8,"mbox":"http://patchwork.ozlabs.org/series/4431/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/817002/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/817002/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=nusiddiq@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 3xyhRd75K9z9t42\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 22 Sep 2017 02:10:53 +1000 (AEST)","from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id B130BB7F;\n\tThu, 21 Sep 2017 16:10:10 +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 B8162B4B\n\tfor <dev@openvswitch.org>; Thu, 21 Sep 2017 16:10:09 +0000 (UTC)","from mx1.redhat.com (mx1.redhat.com [209.132.183.28])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 4565941D\n\tfor <dev@openvswitch.org>; Thu, 21 Sep 2017 16:10:08 +0000 (UTC)","from smtp.corp.redhat.com\n\t(int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15])\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 840308765C;\n\tThu, 21 Sep 2017 16:10:07 +0000 (UTC)","from numans.blr.redhat.com (ovpn-116-55.sin2.redhat.com\n\t[10.67.116.55])\n\tby smtp.corp.redhat.com (Postfix) with ESMTP id BF83D61F21;\n\tThu, 21 Sep 2017 16:10:03 +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\tThu, 21 Sep 2017 16:10:07 +0000 (UTC)"],"DMARC-Filter":"OpenDMARC Filter v1.3.2 mx1.redhat.com 840308765C","From":"nusiddiq@redhat.com","To":"dev@openvswitch.org","Date":"Thu, 21 Sep 2017 21:39:49 +0530","Message-Id":"<20170921160949.24901-1-nusiddiq@redhat.com>","In-Reply-To":"<20170921160747.24602-1-nusiddiq@redhat.com>","References":"<20170921160747.24602-1-nusiddiq@redhat.com>","X-Scanned-By":"MIMEDefang 2.79 on 10.5.11.15","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 v8 3/4] ovn-northd: Add logical flows to support\n\tnative IPv6 RA","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":"From: Zongkai LI <zealokii@gmail.com>\n\nThis patch adds logical flows which sends IPv6 Router Advertisement\npacket in response to the IPv6 Router Solicitation request. It uses\nthe actions \"put_nd_ra_opts\" to transform the RS packet to RA packet\nin the newly added ingress stage \"lr_in_nd_ra_options\" in router\npipeline. If the action \"put_nd_ra_opts\" is successful, it sends the\nRA packet back to the originating port in the next ingress stage\n\"lr_in_nd_ra_response\".\n\nA new column \"ipv6_ra_configs\" is added in the Logical_Router_Port\ntable, which the CMS is expected to configure IPv6 RA\nconfigurations - \"address_mode\" and \"mtu\" for adding these flows.\n\nCo-authored-by: Numan Siddique <nusiddiq@redhat.com>\nSigned-off-by: Zongkai LI <zealokii@gmail.com>\nSigned-off-by: Numan Siddique <nusiddiq@redhat.com>\nAcked-by: Miguel Angel Ajo <majopela@redhat.com>\n---\n ovn/lib/logical-fields.c    |   4 +\n ovn/northd/ovn-northd.8.xml |  83 ++++++++++++++-\n ovn/northd/ovn-northd.c     | 137 +++++++++++++++++++++---\n ovn/ovn-nb.ovsschema        |   7 +-\n ovn/ovn-nb.xml              |  39 +++++++\n ovn/ovn-sb.xml              |   4 +\n tests/ovn.at                | 249 ++++++++++++++++++++++++++++++++++++++++++++\n 7 files changed, 500 insertions(+), 23 deletions(-)","diff":"diff --git a/ovn/lib/logical-fields.c b/ovn/lib/logical-fields.c\nindex 26e336f5a..a8b5e3c51 100644\n--- a/ovn/lib/logical-fields.c\n+++ b/ovn/lib/logical-fields.c\n@@ -183,6 +183,10 @@ ovn_init_symtab(struct shash *symtab)\n               \"icmp6.type == 135 && icmp6.code == 0 && ip.ttl == 255\");\n     expr_symtab_add_predicate(symtab, \"nd_na\",\n               \"icmp6.type == 136 && icmp6.code == 0 && ip.ttl == 255\");\n+    expr_symtab_add_predicate(symtab, \"nd_rs\",\n+              \"icmp6.type == 133 && icmp6.code == 0 && ip.ttl == 255\");\n+    expr_symtab_add_predicate(symtab, \"nd_ra\",\n+              \"icmp6.type == 134 && icmp6.code == 0 && ip.ttl == 255\");\n     expr_symtab_add_field(symtab, \"nd.target\", MFF_ND_TARGET, \"nd\", false);\n     expr_symtab_add_field(symtab, \"nd.sll\", MFF_ND_SLL, \"nd_ns\", false);\n     expr_symtab_add_field(symtab, \"nd.tll\", MFF_ND_TLL, \"nd_na\", false);\ndiff --git a/ovn/northd/ovn-northd.8.xml b/ovn/northd/ovn-northd.8.xml\nindex 0d85ec0d2..a994abf78 100644\n--- a/ovn/northd/ovn-northd.8.xml\n+++ b/ovn/northd/ovn-northd.8.xml\n@@ -1584,7 +1584,82 @@ icmp4 {\n       </li>\n     </ul>\n \n-    <h3>Ingress Table 5: IP Routing</h3>\n+    <h3>Ingress Table 5: IPv6 ND RA option processing</h3>\n+\n+    <ul>\n+      <li>\n+        <p>\n+          A priority-50 logical flow is added for each logical router port\n+          configured with IPv6 ND RA options which matches IPv6 ND Router\n+          Solicitation packet and applies the action\n+          <code>put_nd_ra_opts</code> and advances the packet to the next\n+          table.\n+        </p>\n+\n+        <pre>\n+reg0[5] = put_nd_ra_opts(<var>options</var>);next;\n+        </pre>\n+\n+        <p>\n+          For a valid IPv6 ND RS packet, this transforms the packet into an\n+          IPv6 ND RA reply and sets the RA options to the packet and stores 1\n+          into reg0[5]. For other kinds of packets, it just stores 0 into\n+          reg0[5]. Either way, it continues to the next table.\n+        </p>\n+      </li>\n+\n+      <li>\n+        A priority-0 logical flow with match <code>1</code> has actions\n+        <code>next;</code>.\n+      </li>\n+    </ul>\n+\n+    <h3>Ingress Table 6: IPv6 ND RA responder</h3>\n+\n+    <p>\n+      This table implements IPv6 ND RA responder for the IPv6 ND RA replies\n+      generated by the previous table.\n+    </p>\n+\n+    <ul>\n+      <li>\n+        <p>\n+          A priority-50 logical flow is added for each logical router port\n+          configured with IPv6 ND RA options which matches IPv6 ND RA\n+          packets and <code>reg0[5] == 1</code> and responds back to the\n+          <code>inport</code> after applying these actions.\n+          If <code>reg0[5]</code> is set to 1, it means that the action\n+          <code>put_nd_ra_opts</code> was successful.\n+        </p>\n+\n+        <pre>\n+eth.dst = eth.src;\n+eth.src = <var>E</var>;\n+ip6.dst = ip6.src;\n+ip6.src = <var>I</var>;\n+outport = <var>P</var>;\n+flags.loopback = 1;\n+output;\n+        </pre>\n+\n+        <p>\n+          where <var>E</var> is the MAC address and <var>I</var> is the IPv6\n+          link local address of the logical router port.\n+        </p>\n+\n+        <p>\n+          (This terminates packet processing in ingress pipeline; the packet\n+          does not go to the next ingress table.)\n+        </p>\n+      </li>\n+\n+      <li>\n+        A priority-0 logical flow with match <code>1</code> has actions\n+        <code>next;</code>.\n+      </li>\n+    </ul>\n+\n+    <h3>Ingress Table 7: IP Routing</h3>\n \n     <p>\n       A packet that arrives at this table is an IP packet that should be\n@@ -1686,7 +1761,7 @@ next;\n       </li>\n     </ul>\n \n-    <h3>Ingress Table 6: ARP/ND Resolution</h3>\n+    <h3>Ingress Table 8: ARP/ND Resolution</h3>\n \n     <p>\n       Any packet that reaches this table is an IP packet whose next-hop\n@@ -1779,7 +1854,7 @@ next;\n       </li>\n     </ul>\n \n-    <h3>Ingress Table 7: Gateway Redirect</h3>\n+    <h3>Ingress Table 9: Gateway Redirect</h3>\n \n     <p>\n       For distributed logical routers where one of the logical router\n@@ -1836,7 +1911,7 @@ next;\n       </li>\n     </ul>\n \n-    <h3>Ingress Table 8: ARP Request</h3>\n+    <h3>Ingress Table 10: ARP Request</h3>\n \n     <p>\n       In the common case where the Ethernet destination has been resolved, this\ndiff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c\nindex 75f2c6607..3da20d25b 100644\n--- a/ovn/northd/ovn-northd.c\n+++ b/ovn/northd/ovn-northd.c\n@@ -129,15 +129,17 @@ enum ovn_stage {\n     PIPELINE_STAGE(SWITCH, OUT, PORT_SEC_L2,  8, \"ls_out_port_sec_l2\")    \\\n                                                                       \\\n     /* Logical router ingress stages. */                              \\\n-    PIPELINE_STAGE(ROUTER, IN,  ADMISSION,   0, \"lr_in_admission\")    \\\n-    PIPELINE_STAGE(ROUTER, IN,  IP_INPUT,    1, \"lr_in_ip_input\")     \\\n-    PIPELINE_STAGE(ROUTER, IN,  DEFRAG,      2, \"lr_in_defrag\")       \\\n-    PIPELINE_STAGE(ROUTER, IN,  UNSNAT,      3, \"lr_in_unsnat\")       \\\n-    PIPELINE_STAGE(ROUTER, IN,  DNAT,        4, \"lr_in_dnat\")         \\\n-    PIPELINE_STAGE(ROUTER, IN,  IP_ROUTING,  5, \"lr_in_ip_routing\")   \\\n-    PIPELINE_STAGE(ROUTER, IN,  ARP_RESOLVE, 6, \"lr_in_arp_resolve\")  \\\n-    PIPELINE_STAGE(ROUTER, IN,  GW_REDIRECT, 7, \"lr_in_gw_redirect\")  \\\n-    PIPELINE_STAGE(ROUTER, IN,  ARP_REQUEST, 8, \"lr_in_arp_request\")  \\\n+    PIPELINE_STAGE(ROUTER, IN,  ADMISSION,      0, \"lr_in_admission\")    \\\n+    PIPELINE_STAGE(ROUTER, IN,  IP_INPUT,       1, \"lr_in_ip_input\")     \\\n+    PIPELINE_STAGE(ROUTER, IN,  DEFRAG,         2, \"lr_in_defrag\")       \\\n+    PIPELINE_STAGE(ROUTER, IN,  UNSNAT,         3, \"lr_in_unsnat\")       \\\n+    PIPELINE_STAGE(ROUTER, IN,  DNAT,           4, \"lr_in_dnat\")         \\\n+    PIPELINE_STAGE(ROUTER, IN,  ND_RA_OPTIONS,  5, \"lr_in_nd_ra_options\") \\\n+    PIPELINE_STAGE(ROUTER, IN,  ND_RA_RESPONSE, 6, \"lr_in_nd_ra_response\") \\\n+    PIPELINE_STAGE(ROUTER, IN,  IP_ROUTING,     7, \"lr_in_ip_routing\")   \\\n+    PIPELINE_STAGE(ROUTER, IN,  ARP_RESOLVE,    8, \"lr_in_arp_resolve\")  \\\n+    PIPELINE_STAGE(ROUTER, IN,  GW_REDIRECT,    9, \"lr_in_gw_redirect\")  \\\n+    PIPELINE_STAGE(ROUTER, IN,  ARP_REQUEST,    10, \"lr_in_arp_request\")  \\\n                                                                       \\\n     /* Logical router egress stages. */                               \\\n     PIPELINE_STAGE(ROUTER, OUT, UNDNAT,    0, \"lr_out_undnat\")        \\\n@@ -159,11 +161,12 @@ enum ovn_stage {\n #define OVN_ACL_PRI_OFFSET 1000\n \n /* Register definitions specific to switches. */\n-#define REGBIT_CONNTRACK_DEFRAG \"reg0[0]\"\n-#define REGBIT_CONNTRACK_COMMIT \"reg0[1]\"\n-#define REGBIT_CONNTRACK_NAT    \"reg0[2]\"\n-#define REGBIT_DHCP_OPTS_RESULT \"reg0[3]\"\n+#define REGBIT_CONNTRACK_DEFRAG  \"reg0[0]\"\n+#define REGBIT_CONNTRACK_COMMIT  \"reg0[1]\"\n+#define REGBIT_CONNTRACK_NAT     \"reg0[2]\"\n+#define REGBIT_DHCP_OPTS_RESULT  \"reg0[3]\"\n #define REGBIT_DNS_LOOKUP_RESULT \"reg0[4]\"\n+#define REGBIT_ND_RA_OPTS_RESULT \"reg0[5]\"\n \n /* Register definitions for switches and routers. */\n #define REGBIT_NAT_REDIRECT     \"reg9[0]\"\n@@ -2868,7 +2871,11 @@ build_pre_acls(struct ovn_datapath *od, struct hmap *lflows)\n          *\n          * Not to do conntrack on ND packets. */\n         ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, \"nd\", \"next;\");\n+        ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110, \"(nd_rs || nd_ra)\",\n+                      \"next;\");\n         ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110, \"nd\", \"next;\");\n+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,\n+                      \"(nd_rs || nd_ra)\", \"next;\");\n \n         /* Ingress and Egress Pre-ACL Table (Priority 100).\n          *\n@@ -5319,7 +5326,103 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,\n         sset_destroy(&all_ips);\n     }\n \n-    /* Logical router ingress table 5: IP Routing.\n+    /* Logical router ingress table 5 and 6: IPv6 Router Adv (RA) options and\n+     * response. */\n+    HMAP_FOR_EACH (op, key_node, ports) {\n+        if (!op->nbrp || op->nbrp->peer || !op->peer) {\n+            continue;\n+        }\n+\n+        if (!op->lrp_networks.n_ipv6_addrs) {\n+            continue;\n+        }\n+\n+        const char *address_mode = smap_get(\n+            &op->nbrp->ipv6_ra_configs, \"address_mode\");\n+\n+        if (!address_mode) {\n+            continue;\n+        }\n+        if (strcmp(address_mode, \"slaac\") &&\n+            strcmp(address_mode, \"dhcpv6_stateful\") &&\n+            strcmp(address_mode, \"dhcpv6_stateless\")) {\n+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);\n+            VLOG_WARN_RL(&rl, \"Invalid address mode [%s] defined\",\n+                         address_mode);\n+            continue;\n+        }\n+\n+        ds_clear(&match);\n+        ds_put_format(&match, \"inport == %s && ip6.dst == ff02::2 && nd_rs\",\n+                              op->json_key);\n+        ds_clear(&actions);\n+\n+        const char *mtu_s = smap_get(\n+            &op->nbrp->ipv6_ra_configs, \"mtu\");\n+\n+        /* As per RFC 2460, 1280 is minimum IPv6 MTU. */\n+        uint32_t mtu = (mtu_s && atoi(mtu_s) >= 1280) ? atoi(mtu_s) : 0;\n+\n+        ds_put_format(&actions, REGBIT_ND_RA_OPTS_RESULT\" = put_nd_ra_opts(\"\n+                      \"addr_mode = \\\"%s\\\", slla = %s\",\n+                      address_mode, op->lrp_networks.ea_s);\n+        if (mtu > 0) {\n+            ds_put_format(&actions, \", mtu = %u\", mtu);\n+        }\n+\n+        bool add_rs_response_flow = false;\n+\n+        for (size_t i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {\n+            if (in6_is_lla(&op->lrp_networks.ipv6_addrs[i].network)) {\n+                continue;\n+            }\n+\n+            /* Add the prefix option if the address mode is slaac or\n+             * dhcpv6_stateless. */\n+            if (strcmp(address_mode, \"dhcpv6_stateful\")) {\n+                ds_put_format(&actions, \", prefix = %s/%u\",\n+                              op->lrp_networks.ipv6_addrs[i].network_s,\n+                              op->lrp_networks.ipv6_addrs[i].plen);\n+            }\n+            add_rs_response_flow = true;\n+        }\n+\n+        if (add_rs_response_flow) {\n+            ds_put_cstr(&actions, \"); next;\");\n+            ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ND_RA_OPTIONS, 50,\n+                          ds_cstr(&match), ds_cstr(&actions));\n+            ds_clear(&actions);\n+            ds_clear(&match);\n+            ds_put_format(&match, \"inport == %s && ip6.dst == ff02::2 && \"\n+                          \"nd_ra && \"REGBIT_ND_RA_OPTS_RESULT, op->json_key);\n+\n+            char ip6_str[INET6_ADDRSTRLEN + 1];\n+            struct in6_addr lla;\n+            in6_generate_lla(op->lrp_networks.ea, &lla);\n+            memset(ip6_str, 0, sizeof(ip6_str));\n+            ipv6_string_mapped(ip6_str, &lla);\n+            ds_put_format(&actions, \"eth.dst = eth.src; eth.src = %s; \"\n+                          \"ip6.dst = ip6.src; ip6.src = %s; \"\n+                          \"outport = inport; flags.loopback = 1; \"\n+                          \"output;\",\n+                          op->lrp_networks.ea_s, ip6_str);\n+            ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ND_RA_RESPONSE, 50,\n+                          ds_cstr(&match), ds_cstr(&actions));\n+        }\n+    }\n+\n+    /* Logical router ingress table 5, 6: RS responder, by default goto next.\n+     * (priority 0)*/\n+    HMAP_FOR_EACH (od, key_node, datapaths) {\n+        if (!od->nbr) {\n+            continue;\n+        }\n+\n+        ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_OPTIONS, 0, \"1\", \"next;\");\n+        ovn_lflow_add(lflows, od, S_ROUTER_IN_ND_RA_RESPONSE, 0, \"1\", \"next;\");\n+    }\n+\n+    /* Logical router ingress table 7: IP Routing.\n      *\n      * A packet that arrives at this table is an IP packet that should be\n      * routed to the address in 'ip[46].dst'. This table sets outport to\n@@ -5361,7 +5464,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,\n \n     /* XXX destination unreachable */\n \n-    /* Local router ingress table 6: ARP Resolution.\n+    /* Local router ingress table 8: ARP Resolution.\n      *\n      * Any packet that reaches this table is an IP packet whose next-hop IP\n      * address is in reg0. (ip4.dst is the final destination.) This table\n@@ -5556,7 +5659,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,\n                       \"get_nd(outport, xxreg0); next;\");\n     }\n \n-    /* Logical router ingress table 7: Gateway redirect.\n+    /* Logical router ingress table 9: Gateway redirect.\n      *\n      * For traffic with outport equal to the l3dgw_port\n      * on a distributed router, this table redirects a subset\n@@ -5596,7 +5699,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,\n         ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 0, \"1\", \"next;\");\n     }\n \n-    /* Local router ingress table 8: ARP request.\n+    /* Local router ingress table 10: ARP request.\n      *\n      * In the common case where the Ethernet destination has been resolved,\n      * this table outputs the packet (priority 0).  Otherwise, it composes\ndiff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema\nindex a077bfb81..fcd878cf2 100644\n--- a/ovn/ovn-nb.ovsschema\n+++ b/ovn/ovn-nb.ovsschema\n@@ -1,7 +1,7 @@\n {\n     \"name\": \"OVN_Northbound\",\n-    \"version\": \"5.8.0\",\n-    \"cksum\": \"2812300190 16766\",\n+    \"version\": \"5.8.1\",\n+    \"cksum\": \"607160660 16929\",\n     \"tables\": {\n         \"NB_Global\": {\n             \"columns\": {\n@@ -222,6 +222,9 @@\n                 \"mac\": {\"type\": \"string\"},\n                 \"peer\": {\"type\": {\"key\": \"string\", \"min\": 0, \"max\": 1}},\n                 \"enabled\": {\"type\": {\"key\": \"boolean\", \"min\": 0, \"max\": 1}},\n+                \"ipv6_ra_configs\": {\n+                    \"type\": {\"key\": \"string\", \"value\": \"string\",\n+                             \"min\": 0, \"max\": \"unlimited\"}},\n                 \"external_ids\": {\n                     \"type\": {\"key\": \"string\", \"value\": \"string\",\n                              \"min\": 0, \"max\": \"unlimited\"}}},\ndiff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml\nindex 9869d7ed7..8ad53cd7d 100644\n--- a/ovn/ovn-nb.xml\n+++ b/ovn/ovn-nb.xml\n@@ -1332,6 +1332,45 @@\n       port has all ingress and egress traffic dropped.\n     </column>\n \n+    <group title=\"ipv6_ra_configs\">\n+      <p>\n+        This column defines the IPv6 ND RA address mode and ND MTU Option to be\n+        included by <code>ovn-controller</code> when it replies to the IPv6\n+        Router solicitation requests.\n+      </p>\n+\n+      <column name=\"ipv6_ra_configs\" key=\"address_mode\">\n+        The address mode to be used for IPv6 address configuration.\n+        The supported values are:\n+        <ul>\n+          <li>\n+            <code>slaac</code>: Address configuration using Router\n+            Advertisement (RA) packet. The IPv6 prefixes defined in the\n+            <ref table=\"Logical_Router_Port\"/> table's\n+            <ref table=\"Logical_Router_Port\" column=\"networks\"/> column will\n+            be included in the RA's ICMPv6 option - Prefix information.\n+          </li>\n+\n+          <li>\n+            <code>dhcpv6_stateful</code>: Address configuration using DHCPv6.\n+          </li>\n+\n+          <li>\n+            <code>dhcpv6_stateless</code>: Address configuration using Router\n+            Advertisement (RA) packet. Other IPv6 options are provided by\n+            DHCPv6.\n+          </li>\n+        </ul>\n+      </column>\n+\n+      <column name=\"ipv6_ra_configs\" key=\"mtu\">\n+        The recommended MTU for the link. Default is 0, which means no MTU\n+        Option will be included in RA packet replied by ovn-controller.\n+        Per RFC 2460, the mtu value is recommended no less than 1280, so\n+        any mtu value less than 1280 will be considered as no MTU Option.\n+      </column>\n+    </group>\n+\n     <group title=\"Options\">\n       <p>\n         Additional options for the logical router port.\ndiff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml\nindex fab3f9de6..2e4f28b96 100644\n--- a/ovn/ovn-sb.xml\n+++ b/ovn/ovn-sb.xml\n@@ -911,6 +911,10 @@\n         <li><code>nd</code> expands to <code>icmp6.type == {135, 136} &amp;&amp; icmp6.code == 0 &amp;&amp; ip.ttl == 255</code></li>\n         <li><code>nd_ns</code> expands to <code>icmp6.type == 135 &amp;&amp; icmp6.code == 0 &amp;&amp; ip.ttl == 255</code></li>\n         <li><code>nd_na</code> expands to <code>icmp6.type == 136 &amp;&amp; icmp6.code == 0 &amp;&amp; ip.ttl == 255</code></li>\n+        <li><code>nd_rs</code> expands to <code>icmp6.type == 133 &amp;&amp;\n+        icmp6.code == 0 &amp;&amp; ip.ttl == 255</code></li>\n+        <li><code>nd_ra</code> expands to <code>icmp6.type == 134 &amp;&amp;\n+        icmp6.code == 0 &amp;&amp; ip.ttl == 255</code></li>\n         <li><code>tcp</code> expands to <code>ip.proto == 6</code></li>\n         <li><code>udp</code> expands to <code>ip.proto == 17</code></li>\n         <li><code>sctp</code> expands to <code>ip.proto == 132</code></li>\ndiff --git a/tests/ovn.at b/tests/ovn.at\nindex e56dc6232..3aa4e5e22 100644\n--- a/tests/ovn.at\n+++ b/tests/ovn.at\n@@ -7847,6 +7847,255 @@ OVN_CLEANUP([hv1],[hv2],[hv3])\n \n AT_CLEANUP\n \n+AT_SETUP([ovn -- IPv6 ND Router Solicitation responder])\n+AT_KEYWORDS([ovn-nd_ra])\n+AT_SKIP_IF([test $HAVE_PYTHON = no])\n+ovn_start\n+\n+# In this test case we create 1 lswitch with 3 VIF ports attached,\n+# and a lrouter connected to the lswitch.\n+# We generate the Router solicitation packet and verify the Router Advertisement\n+# reply packet from the ovn-controller.\n+\n+# Create hypervisor and logical switch lsw0, logical router lr0, attach lsw0\n+# onto lr0, set Logical_Router_Port.ipv6_ra_configs:address_mode column to\n+# 'slaac' to allow lrp0 send RA for SLAAC mode.\n+ovn-nbctl ls-add lsw0\n+ovn-nbctl lr-add lr0\n+ovn-nbctl lrp-add lr0 lrp0 fa:16:3e:00:00:01 fdad:1234:5678::1/64\n+ovn-nbctl set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode=\"slaac\"\n+ovn-nbctl \\\n+    -- lsp-add lsw0 lsp0 \\\n+    -- set Logical_Switch_Port lsp0 type=router \\\n+                     options:router-port=lrp0 \\\n+                     addresses='\"fa:16:3e:00:00:01 fdad:1234:5678::1\"'\n+net_add n1\n+sim_add hv1\n+as hv1\n+ovs-vsctl add-br br-phys\n+ovn_attach n1 br-phys 192.168.0.2\n+\n+ovn-nbctl lsp-add lsw0 lp1\n+ovn-nbctl lsp-set-addresses lp1 \"fa:16:3e:00:00:02 10.0.0.12 fdad:1234:5678:0:f816:3eff:fe:2\"\n+ovn-nbctl lsp-set-port-security lp1 \"fa:16:3e:00:00:02 10.0.0.12 fdad:1234:5678:0:f816:3eff:fe:2\"\n+\n+ovn-nbctl lsp-add lsw0 lp2\n+ovn-nbctl lsp-set-addresses lp2 \"fa:16:3e:00:00:03 10.0.0.13 fdad:1234:5678:0:f816:3eff:fe:3\"\n+ovn-nbctl lsp-set-port-security lp2 \"fa:16:3e:00:00:03 10.0.0.13 fdad:1234:5678:0:f816:3eff:fe:3\"\n+\n+ovn-nbctl lsp-add lsw0 lp3\n+ovn-nbctl lsp-set-addresses lp3 \"fa:16:3e:00:00:04 10.0.0.14 fdad:1234:5678:0:f816:3eff:fe:4\"\n+ovn-nbctl lsp-set-port-security lp3 \"fa:16:3e:00:00:04 10.0.0.14 fdad:1234:5678:0:f816:3eff:fe:4\"\n+\n+# Add ACL rule for ICMPv6 on lsw0\n+ovn-nbctl acl-add lsw0 from-lport 1002 'ip6 && icmp6'  allow-related\n+ovn-nbctl acl-add lsw0 to-lport 1002 'outport == \"lp1\" && ip6 && icmp6'  allow-related\n+ovn-nbctl acl-add lsw0 to-lport 1002 'outport == \"lp2\" && ip6 && icmp6'  allow-related\n+ovn-nbctl acl-add lsw0 to-lport 1002 'outport == \"lp3\" && ip6 && icmp6'  allow-related\n+\n+ovs-vsctl -- add-port br-int hv1-vif1 -- \\\n+    set interface hv1-vif1 external-ids:iface-id=lp1 \\\n+    options:tx_pcap=hv1/vif1-tx.pcap \\\n+    options:rxq_pcap=hv1/vif1-rx.pcap \\\n+    ofport-request=1\n+\n+ovs-vsctl -- add-port br-int hv1-vif2 -- \\\n+    set interface hv1-vif2 external-ids:iface-id=lp2 \\\n+    options:tx_pcap=hv1/vif2-tx.pcap \\\n+    options:rxq_pcap=hv1/vif2-rx.pcap \\\n+    ofport-request=2\n+\n+ovs-vsctl -- add-port br-int hv1-vif3 -- \\\n+    set interface hv1-vif3 external-ids:iface-id=lp3 \\\n+    options:tx_pcap=hv1/vif3-tx.pcap \\\n+    options:rxq_pcap=hv1/vif3-rx.pcap \\\n+    ofport-request=3\n+\n+# Allow some time for ovn-northd and ovn-controller to catch up.\n+# XXX This should be more systematic.\n+sleep 1\n+\n+reset_pcap_file() {\n+    local iface=$1\n+    local pcap_file=$2\n+    ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \\\n+options:rxq_pcap=dummy-rx.pcap\n+    rm -f ${pcap_file}*.pcap\n+    ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \\\n+options:rxq_pcap=${pcap_file}-rx.pcap\n+}\n+\n+# Make sure that ovn-controller has installed the corresponding OF Flow.\n+OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c \"ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0\"`])\n+\n+# This shell function sends a Router Solicitation packet.\n+# test_ipv6_ra INPORT SRC_MAC SRC_LLA ADDR_MODE MTU RA_PREFIX_OPT\n+test_ipv6_ra() {\n+    local inport=$1 src_mac=$2 src_lla=$3 addr_mode=$4 mtu=$5 prefix_opt=$6\n+    local request=333300000002${src_mac}86dd6000000000103aff${src_lla}ff02000000000000000000000000000285000efc000000000101${src_mac}\n+\n+    local len=24\n+    local mtu_opt=\"\"\n+    if test $mtu != 0; then\n+        len=`expr $len + 8`\n+        mtu_opt=05010000${mtu}\n+    fi\n+\n+    if test ${#prefix_opt} != 0; then\n+        prefix_opt=${prefix_opt}fdad1234567800000000000000000000\n+        len=`expr $len + ${#prefix_opt} / 2`\n+    fi\n+\n+    len=$(printf \"%x\" $len)\n+    local lrp_mac=fa163e000001\n+    local lrp_lla=fe80000000000000f8163efffe000001\n+    local reply=${src_mac}${lrp_mac}86dd6000000000${len}3aff${lrp_lla}${src_lla}8600XXXXff${addr_mode}ffff00000000000000000101${lrp_mac}${mtu_opt}${prefix_opt}\n+    echo $reply >> $inport.expected\n+\n+    as hv1 ovs-appctl netdev-dummy/receive hv1-vif${inport} $request\n+}\n+\n+AT_CAPTURE_FILE([ofctl_monitor0.log])\n+as hv1 ovs-ofctl monitor br-int resume --detach --no-chdir \\\n+--pidfile=ovs-ofctl0.pid 2> ofctl_monitor0.log\n+\n+# MTU is not set and the address mode is set to slaac\n+addr_mode=00\n+default_prefix_option_config=030440c0ffffffffffffffff00000000\n+src_mac=fa163e000002\n+src_lla=fe80000000000000f8163efffe000002\n+test_ipv6_ra 1 $src_mac $src_lla $addr_mode 0 $default_prefix_option_config\n+\n+# NXT_RESUME should be 1.\n+OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])\n+\n+$PYTHON \"$top_srcdir/utilities/ovs-pcap.in\" hv1/vif1-tx.pcap  > 1.packets\n+\n+cat 1.expected | cut -c -112 > expout\n+AT_CHECK([cat 1.packets | cut -c -112], [0], [expout])\n+\n+# Skipping the ICMPv6 checksum.\n+cat 1.expected | cut -c 117- > expout\n+AT_CHECK([cat 1.packets | cut -c 117-], [0], [expout])\n+\n+rm -f *.expected\n+reset_pcap_file hv1-vif1 hv1/vif1\n+reset_pcap_file hv1-vif2 hv1/vif2\n+reset_pcap_file hv1-vif3 hv1/vif3\n+\n+# Set the MTU to 1500\n+ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:mtu=1500\n+\n+# Make sure that ovn-controller has installed the corresponding OF Flow.\n+OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c \"ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0\"`])\n+\n+addr_mode=00\n+default_prefix_option_config=030440c0ffffffffffffffff00000000\n+src_mac=fa163e000003\n+src_lla=fe80000000000000f8163efffe000003\n+mtu=000005dc\n+\n+test_ipv6_ra 2 $src_mac $src_lla $addr_mode $mtu $default_prefix_option_config\n+\n+# NXT_RESUME should be 2.\n+OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])\n+\n+$PYTHON \"$top_srcdir/utilities/ovs-pcap.in\" hv1/vif2-tx.pcap  > 2.packets\n+\n+cat 2.expected | cut -c -112 > expout\n+AT_CHECK([cat 2.packets | cut -c -112], [0], [expout])\n+\n+# Skipping the ICMPv6 checksum.\n+cat 2.expected | cut -c 117- > expout\n+AT_CHECK([cat 2.packets | cut -c 117-], [0], [expout])\n+\n+rm -f *.expected\n+reset_pcap_file hv1-vif1 hv1/vif1\n+reset_pcap_file hv1-vif2 hv1/vif2\n+reset_pcap_file hv1-vif3 hv1/vif3\n+\n+# Set the address mode to dhcpv6_stateful\n+ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode=dhcpv6_stateful\n+# Make sure that ovn-controller has installed the corresponding OF Flow.\n+OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c \"ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0\"`])\n+\n+addr_mode=80\n+default_prefix_option_config=\"\"\n+src_mac=fa163e000004\n+src_lla=fe80000000000000f8163efffe000004\n+mtu=000005dc\n+\n+test_ipv6_ra 3 $src_mac $src_lla $addr_mode $mtu $default_prefix_option_config\n+\n+# NXT_RESUME should be 3.\n+OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])\n+\n+$PYTHON \"$top_srcdir/utilities/ovs-pcap.in\" hv1/vif3-tx.pcap  > 3.packets\n+\n+cat 3.expected | cut -c -112 > expout\n+AT_CHECK([cat 3.packets | cut -c -112], [0], [expout])\n+\n+# Skipping the ICMPv6 checksum.\n+cat 3.expected | cut -c 117- > expout\n+AT_CHECK([cat 3.packets | cut -c 117-], [0], [expout])\n+\n+rm -f *.expected\n+reset_pcap_file hv1-vif1 hv1/vif1\n+reset_pcap_file hv1-vif2 hv1/vif2\n+reset_pcap_file hv1-vif3 hv1/vif3\n+\n+# Set the address mode to dhcpv6_stateless\n+ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode=dhcpv6_stateless\n+# Make sure that ovn-controller has installed the corresponding OF Flow.\n+OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c \"ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0\"`])\n+\n+addr_mode=40\n+default_prefix_option_config=030440c0ffffffffffffffff00000000\n+src_mac=fa163e000002\n+src_lla=fe80000000000000f8163efffe000002\n+mtu=000005dc\n+\n+test_ipv6_ra 1 $src_mac $src_lla $addr_mode $mtu $default_prefix_option_config\n+\n+# NXT_RESUME should be 4.\n+OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])\n+\n+$PYTHON \"$top_srcdir/utilities/ovs-pcap.in\" hv1/vif1-tx.pcap  > 1.packets\n+\n+cat 1.expected | cut -c -112 > expout\n+AT_CHECK([cat 1.packets | cut -c -112], [0], [expout])\n+\n+# Skipping the ICMPv6 checksum.\n+cat 1.expected | cut -c 117- > expout\n+AT_CHECK([cat 1.packets | cut -c 117-], [0], [expout])\n+\n+rm -f *.expected\n+reset_pcap_file hv1-vif1 hv1/vif1\n+reset_pcap_file hv1-vif2 hv1/vif2\n+reset_pcap_file hv1-vif3 hv1/vif3\n+\n+# Set the address mode to invalid.\n+ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode=invalid\n+# Make sure that ovn-controller has not installed any OF Flow for IPv6 ND RA.\n+OVS_WAIT_UNTIL([test 0 = `as hv1 ovs-ofctl dump-flows br-int | grep -c \"ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0\"`])\n+\n+addr_mode=40\n+default_prefix_option_config=\"\"\n+src_mac=fa163e000002\n+src_lla=fe80000000000000f8163efffe000002\n+mtu=000005dc\n+\n+test_ipv6_ra 1 $src_mac $src_lla $addr_mode $mtu $default_prefix_option_config\n+\n+# NXT_RESUME should be 4 only.\n+OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])\n+\n+$PYTHON \"$top_srcdir/utilities/ovs-pcap.in\" hv1/vif1-tx.pcap  > 1.packets\n+AT_CHECK([cat 1.packets], [0], [])\n+\n+OVN_CLEANUP([hv1])\n+AT_CLEANUP\n+\n AT_SETUP([ovn -- /32 router IP address])\n AT_SKIP_IF([test $HAVE_PYTHON = no])\n ovn_start\n","prefixes":["ovs-dev","v8","3/4"]}