9219d1
From a1a0c7061850d78edb74a7977d0241121575be0e Mon Sep 17 00:00:00 2001
9219d1
From: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
9219d1
Date: Tue, 7 Jul 2020 17:18:28 +0200
9219d1
Subject: [PATCH 08/22] northd: introduce icmp6_error logical flows in router
9219d1
 pipeline
9219d1
9219d1
Introduce icmp6_error logical flows in router pipeline if gateway_mtu
9219d1
has been added to logical router port option column in order to perform
9219d1
IPv6 PMTU discovery
9219d1
9219d1
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
9219d1
Signed-off-by: Numan Siddique <numans@ovn.org>
9219d1
---
9219d1
 northd/ovn-northd.8.xml | 24 +++++++++---
9219d1
 northd/ovn-northd.c     | 84 ++++++++++++++++++++++++++++-------------
9219d1
 tests/ovn.at            | 48 +++++++++++++++++++++--
9219d1
 3 files changed, 120 insertions(+), 36 deletions(-)
9219d1
9219d1
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
9219d1
index 67481f458..623768988 100644
9219d1
--- a/northd/ovn-northd.8.xml
9219d1
+++ b/northd/ovn-northd.8.xml
9219d1
@@ -2922,11 +2922,11 @@ REGBIT_PKT_LARGER = check_pkt_larger(L); next;
9219d1
       For distributed logical routers with distributed gateway port configured
9219d1
       with options:gateway_mtu to a valid integer value, this
9219d1
       table adds the following priority-50 logical flow for each
9219d1
-      logical router port with the match ip4 &&
9219d1
-      inport == LRP && outport == GW_PORT
9219d1
-      && REGBIT_PKT_LARGER, where LRP is the logical
9219d1
-      router port and GW_PORT is the distributed gateway router port
9219d1
-      and applies the following action
9219d1
+      logical router port with the match inport == LRP
9219d1
+      && outport == GW_PORT &&
9219d1
+      REGBIT_PKT_LARGER, where LRP is the logical
9219d1
+      router port and GW_PORT is the distributed gateway router
9219d1
+      port and applies the following action for ipv4 and ipv6 respectively:
9219d1
     

9219d1
 
9219d1
     
9219d1
@@ -2941,6 +2941,18 @@ icmp4 {
9219d1
     REGBIT_EGRESS_LOOPBACK = 1;
9219d1
     next(pipeline=ingress, table=0);
9219d1
 };
9219d1
+
9219d1
+icmp6 {
9219d1
+    icmp6.type = 2;
9219d1
+    icmp6.code = 0;
9219d1
+    icmp6.frag_mtu = M;
9219d1
+    eth.dst = E;
9219d1
+    ip6.dst = ip6.src;
9219d1
+    ip6.src = I;
9219d1
+    ip.ttl = 255;
9219d1
+    REGBIT_EGRESS_LOOPBACK = 1;
9219d1
+    next(pipeline=ingress, table=0);
9219d1
+};
9219d1
     
9219d1
 
9219d1
     
    9219d1
    @@ -2956,7 +2968,7 @@ icmp4 {
    9219d1
           
    9219d1
     
    9219d1
           
  • 9219d1
    -        I is the IPv4 address of the logical router port.
    9219d1
    +        I is the IPv4/IPv6 address of the logical router port.
    9219d1
           
    9219d1
         
    9219d1
     
    9219d1
    diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
    9219d1
    index 2b1257114..6375aee8d 100644
    9219d1
    --- a/northd/ovn-northd.c
    9219d1
    +++ b/northd/ovn-northd.c
    9219d1
    @@ -10495,8 +10495,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
    9219d1
                 }
    9219d1
     
    9219d1
                 ds_clear(&match);
    9219d1
    -            ds_put_format(&match, "outport == %s && ip4",
    9219d1
    -                          od->l3dgw_port->json_key);
    9219d1
    +            ds_put_format(&match, "outport == %s", od->l3dgw_port->json_key);
    9219d1
     
    9219d1
                 ds_clear(&actions);
    9219d1
                 ds_put_format(&actions,
    9219d1
    @@ -10509,34 +10508,65 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
    9219d1
                 for (size_t i = 0; i < od->nbr->n_ports; i++) {
    9219d1
                     struct ovn_port *rp = ovn_port_find(ports,
    9219d1
                                                         od->nbr->ports[i]->name);
    9219d1
    -                if (!rp || rp == od->l3dgw_port ||
    9219d1
    -                    !rp->lrp_networks.ipv4_addrs) {
    9219d1
    +                if (!rp || rp == od->l3dgw_port) {
    9219d1
                         continue;
    9219d1
                     }
    9219d1
    -                ds_clear(&match);
    9219d1
    -                ds_put_format(&match, "inport == %s && outport == %s && ip4 "
    9219d1
    -                              "&& "REGBIT_PKT_LARGER,
    9219d1
    -                              rp->json_key, od->l3dgw_port->json_key);
    9219d1
     
    9219d1
    -                ds_clear(&actions);
    9219d1
    -                /* Set icmp4.frag_mtu to gw_mtu */
    9219d1
    -                ds_put_format(&actions,
    9219d1
    -                    "icmp4_error {"
    9219d1
    -                    REGBIT_EGRESS_LOOPBACK" = 1; "
    9219d1
    -                    "eth.dst = %s; "
    9219d1
    -                    "ip4.dst = ip4.src; "
    9219d1
    -                    "ip4.src = %s; "
    9219d1
    -                    "ip.ttl = 255; "
    9219d1
    -                    "icmp4.type = 3; /* Destination Unreachable. */ "
    9219d1
    -                    "icmp4.code = 4; /* Frag Needed and DF was Set. */ "
    9219d1
    -                    "icmp4.frag_mtu = %d; "
    9219d1
    -                    "next(pipeline=ingress, table=0); };",
    9219d1
    -                    rp->lrp_networks.ea_s,
    9219d1
    -                    rp->lrp_networks.ipv4_addrs[0].addr_s,
    9219d1
    -                    gw_mtu);
    9219d1
    -                ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_LARGER_PKTS,
    9219d1
    -                                        50, ds_cstr(&match), ds_cstr(&actions),
    9219d1
    -                                        &rp->nbrp->header_);
    9219d1
    +                if (rp->lrp_networks.ipv4_addrs) {
    9219d1
    +                    ds_clear(&match);
    9219d1
    +                    ds_put_format(&match, "inport == %s && outport == %s"
    9219d1
    +                                  " && ip4 && "REGBIT_PKT_LARGER,
    9219d1
    +                                  rp->json_key, od->l3dgw_port->json_key);
    9219d1
    +
    9219d1
    +                    ds_clear(&actions);
    9219d1
    +                    /* Set icmp4.frag_mtu to gw_mtu */
    9219d1
    +                    ds_put_format(&actions,
    9219d1
    +                        "icmp4_error {"
    9219d1
    +                        REGBIT_EGRESS_LOOPBACK" = 1; "
    9219d1
    +                        "eth.dst = %s; "
    9219d1
    +                        "ip4.dst = ip4.src; "
    9219d1
    +                        "ip4.src = %s; "
    9219d1
    +                        "ip.ttl = 255; "
    9219d1
    +                        "icmp4.type = 3; /* Destination Unreachable. */ "
    9219d1
    +                        "icmp4.code = 4; /* Frag Needed and DF was Set. */ "
    9219d1
    +                        "icmp4.frag_mtu = %d; "
    9219d1
    +                        "next(pipeline=ingress, table=0); };",
    9219d1
    +                        rp->lrp_networks.ea_s,
    9219d1
    +                        rp->lrp_networks.ipv4_addrs[0].addr_s,
    9219d1
    +                        gw_mtu);
    9219d1
    +                    ovn_lflow_add_with_hint(lflows, od,
    9219d1
    +                                            S_ROUTER_IN_LARGER_PKTS, 50,
    9219d1
    +                                            ds_cstr(&match), ds_cstr(&actions),
    9219d1
    +                                            &rp->nbrp->header_);
    9219d1
    +                }
    9219d1
    +
    9219d1
    +                if (rp->lrp_networks.ipv6_addrs) {
    9219d1
    +                    ds_clear(&match);
    9219d1
    +                    ds_put_format(&match, "inport == %s && outport == %s"
    9219d1
    +                                  " && ip6 && "REGBIT_PKT_LARGER,
    9219d1
    +                                  rp->json_key, od->l3dgw_port->json_key);
    9219d1
    +
    9219d1
    +                    ds_clear(&actions);
    9219d1
    +                    /* Set icmp6.frag_mtu to gw_mtu */
    9219d1
    +                    ds_put_format(&actions,
    9219d1
    +                        "icmp6_error {"
    9219d1
    +                        REGBIT_EGRESS_LOOPBACK" = 1; "
    9219d1
    +                        "eth.dst = %s; "
    9219d1
    +                        "ip6.dst = ip6.src; "
    9219d1
    +                        "ip6.src = %s; "
    9219d1
    +                        "ip.ttl = 255; "
    9219d1
    +                        "icmp6.type = 2; /* Packet Too Big. */ "
    9219d1
    +                        "icmp6.code = 0; "
    9219d1
    +                        "icmp6.frag_mtu = %d; "
    9219d1
    +                        "next(pipeline=ingress, table=0); };",
    9219d1
    +                        rp->lrp_networks.ea_s,
    9219d1
    +                        rp->lrp_networks.ipv6_addrs[0].addr_s,
    9219d1
    +                        gw_mtu);
    9219d1
    +                    ovn_lflow_add_with_hint(lflows, od,
    9219d1
    +                                            S_ROUTER_IN_LARGER_PKTS, 50,
    9219d1
    +                                            ds_cstr(&match), ds_cstr(&actions),
    9219d1
    +                                            &rp->nbrp->header_);
    9219d1
    +                }
    9219d1
                 }
    9219d1
             }
    9219d1
         }
    9219d1
    diff --git a/tests/ovn.at b/tests/ovn.at
    9219d1
    index 80cd62c49..905112a8d 100644
    9219d1
    --- a/tests/ovn.at
    9219d1
    +++ b/tests/ovn.at
    9219d1
    @@ -15115,17 +15115,17 @@ ovn_start
    9219d1
     
    9219d1
     ovn-nbctl ls-add sw0
    9219d1
     ovn-nbctl lsp-add sw0 sw0-port1
    9219d1
    -ovn-nbctl lsp-set-addresses sw0-port1 "50:54:00:00:00:01 10.0.0.3"
    9219d1
    +ovn-nbctl lsp-set-addresses sw0-port1 "50:54:00:00:00:01 10.0.0.3 1000::3"
    9219d1
     
    9219d1
     ovn-nbctl lr-add lr0
    9219d1
    -ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24
    9219d1
    +ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 1000::1/64
    9219d1
     ovn-nbctl lsp-add sw0 sw0-lr0
    9219d1
     ovn-nbctl lsp-set-type sw0-lr0 router
    9219d1
     ovn-nbctl lsp-set-addresses sw0-lr0 router
    9219d1
     ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0
    9219d1
     
    9219d1
     ovn-nbctl ls-add public
    9219d1
    -ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 172.168.0.100/24
    9219d1
    +ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 172.168.0.100/24 2000::1/64
    9219d1
     ovn-nbctl lsp-add public public-lr0
    9219d1
     ovn-nbctl lsp-set-type public-lr0 router
    9219d1
     ovn-nbctl lsp-set-addresses public-lr0 router
    9219d1
    @@ -15139,6 +15139,7 @@ ovn-nbctl lsp-set-options ln-public network_name=phys
    9219d1
     
    9219d1
     ovn-nbctl lrp-set-gateway-chassis lr0-public hv1 20
    9219d1
     ovn-nbctl lr-nat-add lr0 snat 172.168.0.100 10.0.0.0/24
    9219d1
    +ovn-nbctl lr-nat-add lr0 snat 2000::1 1000::/64
    9219d1
     
    9219d1
     net_add n1
    9219d1
     
    9219d1
    @@ -15249,6 +15250,41 @@ test_ip_packet_larger() {
    9219d1
         fi
    9219d1
     }
    9219d1
     
    9219d1
    +test_ip6_packet_larger() {
    9219d1
    +    local icmp_pmtu_reply_expected=$1
    9219d1
    +
    9219d1
    +    local eth_src=505400000001
    9219d1
    +    local eth_dst=00000000ff01
    9219d1
    +
    9219d1
    +    local ipv6_src=10000000000000000000000000000003
    9219d1
    +    local ipv6_dst=20000000000000000000000000000002
    9219d1
    +    local ipv6_rt=10000000000000000000000000000001
    9219d1
    +
    9219d1
    +    local payload=0000000000000000000000000000000000000000
    9219d1
    +    local payload=${payload}0000000000000000000000000000000000000000
    9219d1
    +    local payload=${payload}0000000000000000000000000000000000000000
    9219d1
    +    local payload=${payload}0000000000000000000000000000000000000000
    9219d1
    +
    9219d1
    +    local ip6_hdr=6000000000583aff${ipv6_src}${ipv6_dst}
    9219d1
    +    local packet=${eth_dst}${eth_src}86dd${ip6_hdr}8000ec7662f00001${payload}
    9219d1
    +
    9219d1
    +    as hv1 reset_pcap_file br-phys_n1 hv1/br-phys_n1
    9219d1
    +    as hv1 reset_pcap_file hv1-vif1 hv1/vif1
    9219d1
    +
    9219d1
    +    # Send packet from sw0-port1 to outside
    9219d1
    +    as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet
    9219d1
    +
    9219d1
    +    if test $icmp_pmtu_reply_expected = 1; then
    9219d1
    +        icmp6_reply=${eth_src}${eth_dst}86dd6000000000883afe
    9219d1
    +        icmp6_reply=${icmp6_reply}${ipv6_rt}${ipv6_src}020041ff00000076
    9219d1
    +        icmp6_reply=${icmp6_reply}6000000000583afe${ipv6_src}${ipv6_dst}
    9219d1
    +        icmp6_reply=${icmp6_reply}8000ec7662f00001${payload}
    9219d1
    +        echo $icmp6_reply > hv1-vif1.expected
    9219d1
    +
    9219d1
    +        OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [hv1-vif1.expected])
    9219d1
    +    fi
    9219d1
    +}
    9219d1
    +
    9219d1
     ovn-nbctl show
    9219d1
     ovn-sbctl show
    9219d1
     
    9219d1
    @@ -15283,6 +15319,12 @@ OVS_WAIT_UNTIL([
    9219d1
     # Now the packet should be sent via the localnet port to br-phys.
    9219d1
     icmp_reply_expected=0
    9219d1
     test_ip_packet_larger $icmp_reply_expected
    9219d1
    +
    9219d1
    +# Set the gateway mtu to 118
    9219d1
    +ovn-nbctl --wait=hv set logical_router_port lr0-public options:gateway_mtu=118
    9219d1
    +icmp_reply_expected=1
    9219d1
    +test_ip6_packet_larger $icmp_reply_expected
    9219d1
    +
    9219d1
     OVN_CLEANUP([hv1])
    9219d1
     AT_CLEANUP
    9219d1
     
    9219d1
    -- 
    9219d1
    2.26.2
    9219d1