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

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