From patchwork Wed Aug 5 07:05:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Han Zhou X-Patchwork-Id: 1341110 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ovn.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BM2hL5bTtz9sPB for ; Wed, 5 Aug 2020 17:05:37 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 7A9D286444; Wed, 5 Aug 2020 07:05:35 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id uWS5ZF1-ZcJi; Wed, 5 Aug 2020 07:05:34 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 9512285E6D; Wed, 5 Aug 2020 07:05:34 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 68A5CC0050; Wed, 5 Aug 2020 07:05:34 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id C8EC7C004C for ; Wed, 5 Aug 2020 07:05:32 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id B19B186119 for ; Wed, 5 Aug 2020 07:05:32 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 3E3K8BHjC1zM for ; Wed, 5 Aug 2020 07:05:31 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by fraxinus.osuosl.org (Postfix) with ESMTPS id 1C89385E6D for ; Wed, 5 Aug 2020 07:05:30 +0000 (UTC) X-Originating-IP: 216.113.160.71 Received: from localhost.localdomain.localdomain (unknown [216.113.160.71]) (Authenticated sender: hzhou@ovn.org) by relay1-d.mail.gandi.net (Postfix) with ESMTPSA id 70BFD24000C; Wed, 5 Aug 2020 07:05:28 +0000 (UTC) From: Han Zhou To: dev@openvswitch.org Date: Wed, 5 Aug 2020 00:05:12 -0700 Message-Id: <1596611114-118204-2-git-send-email-hzhou@ovn.org> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1596611114-118204-1-git-send-email-hzhou@ovn.org> References: <1596611114-118204-1-git-send-email-hzhou@ovn.org> Cc: Han Zhou Subject: [ovs-dev] [PATCH ovn v2 1/3] ovn-northd: Support optionally avoid static neighbor flows in routers. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Support option:dynamic_neigh_routers for logical routers, so that in particular use cases static neighbor flows are not prepopulated IP addresses belonging to neighbor router ports, to avoid flow exploding problem reported for ovn-kubernetes large scale setup. Reported-by: Girish Moodalbail Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2020-May/049995.html Signed-off-by: Han Zhou --- northd/ovn-northd.8.xml | 5 ++- northd/ovn-northd.c | 6 +++ ovn-nb.xml | 13 ++++++ tests/ovn.at | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 1 deletion(-) diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml index ed1cd58..508123e 100644 --- a/northd/ovn-northd.8.xml +++ b/northd/ovn-northd.8.xml @@ -2727,7 +2727,10 @@ outport = P; Logical_Switch_Port table. For router ports connected to other logical routers, MAC bindings can be known statically from the mac and networks - column in the Logical_Router_Port table. + column in the Logical_Router_Port table. (Note: the + flow is NOT installed for the IP addresses that belong to a neighbor + logical router port if the current router has the + options:dynamic_neigh_routers set to true)

diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 03c62ba..5dd49f9 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -10401,6 +10401,12 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, continue; } + if (peer->od->nbr && + smap_get_bool(&peer->od->nbr->options, + "dynamic_neigh_routers", false)) { + continue; + } + for (size_t i = 0; i < op->od->n_router_ports; i++) { const char *router_port_name = smap_get( &op->od->router_ports[i]->nbsp->options, diff --git a/ovn-nb.xml b/ovn-nb.xml index 5e434d2..4c59338 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -1846,6 +1846,19 @@ connected to the logical router. Default: False.

+ +

+ If set to true, the router will resolve neighbor + routers' MAC addresses only by dynamic ARP/ND, instead of + prepopulating static mappings for all neighbor routers in the ARP/ND + Resolution stage. This reduces number of flows, but requires ARP/ND + messages to resolve the IP-MAC bindings when needed. It is + false by default. It is recommended to set to + true when a large number of logical routers are + connected to the same logical switch but most of them never need to + send traffic between each other. +

+
diff --git a/tests/ovn.at b/tests/ovn.at index b0179a8..654c343 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -21122,3 +21122,115 @@ AT_CHECK([ OVN_CLEANUP([hv1], [hv2]) AT_CLEANUP + +# Test option:dynamic_neigh_routers. No static neighbor flows when enabled, and +# traffic should still work, with the help of dynamic mac_bindings. +AT_SETUP([ovn -- Dynamic neighbor between LRs]) +ovn_start + +# Logical network: +# 2 LRs - R1 and R2 that are connected to each other via LS "join" +# in 10.0.0.0/24 network. +# R1 is connected to S1 (10.0.1.0/24), R2 is connected to S2 (10.0.2.0/24) + +ovn-nbctl lr-add r1 -- set logical_router r1 option:dynamic_neigh_routers=true +ovn-nbctl lr-add r2 -- set logical_router r2 option:dynamic_neigh_routers=true + +ovn-nbctl ls-add s1 +ovn-nbctl ls-add s2 +ovn-nbctl ls-add join + +# Connnect r1 to s1. +ovn-nbctl lrp-add r1 lrp-r1-s1 00:00:00:00:01:01 10.0.1.1/24 +ovn-nbctl lsp-add s1 lsp-s1-r1 -- set Logical_Switch_Port lsp-s1-r1 type=router \ + options:router-port=lrp-r1-s1 addresses=router + +# Connnect r2 to s2. +ovn-nbctl lrp-add r2 lrp-r2-s2 00:00:00:00:02:01 10.0.2.1/24 +ovn-nbctl lsp-add s2 lsp-s2-r2 -- set Logical_Switch_Port lsp-s2-r2 type=router \ + options:router-port=lrp-r2-s2 addresses=router + +# Connect r1 to join +ovn-nbctl lrp-add r1 lrp-r1-join 00:00:00:00:03:01 10.0.0.1/24 +ovn-nbctl lsp-add join lsp-join-r1 -- set Logical_Switch_Port lsp-join-r1 \ + type=router options:router-port=lrp-r1-join addresses=router + +# Connect r2 to join +ovn-nbctl lrp-add r2 lrp-r2-join 00:00:00:00:03:02 10.0.0.2/24 +ovn-nbctl lsp-add join lsp-join-r2 -- set Logical_Switch_Port lsp-join-r2 \ + type=router options:router-port=lrp-r2-join addresses=router + +#install static routes +ovn-nbctl lr-route-add r1 10.0.2.0/24 10.0.0.2 +ovn-nbctl lr-route-add r2 10.0.1.0/24 10.0.0.1 + +# Create logical port p1 in s1 +ovn-nbctl lsp-add s1 p1 \ +-- lsp-set-addresses p1 "f0:00:00:00:01:02 10.0.1.2" + +# Create logical port p2 in s2 +ovn-nbctl lsp-add s2 p2 \ +-- lsp-set-addresses p2 "f0:00:00:00:02:02 10.0.2.2" + +# Create two hypervisor and create OVS ports corresponding to logical ports. +net_add n1 + +sim_add hv1 +as hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +ovs-vsctl -- add-port br-int hv1-vif1 -- \ + set interface hv1-vif1 external-ids:iface-id=p1 \ + options:tx_pcap=hv1/vif1-tx.pcap \ + options:rxq_pcap=hv1/vif1-rx.pcap \ + ofport-request=1 + +sim_add hv2 +as hv2 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 +ovs-vsctl -- add-port br-int hv2-vif1 -- \ + set interface hv2-vif1 external-ids:iface-id=p2 \ + options:tx_pcap=hv2/vif1-tx.pcap \ + options:rxq_pcap=hv2/vif1-rx.pcap \ + ofport-request=1 + + +# Pre-populate the hypervisors' ARP tables so that we don't lose any +# packets for ARP resolution (native tunneling doesn't queue packets +# for ARP resolution). +OVN_POPULATE_ARP + +ovn-nbctl --wait=hv sync + +AT_CHECK([ovn-sbctl lflow-list | grep lr_in_arp_resolve | grep 10.0.0.1], [1], []) +AT_CHECK([ovn-sbctl lflow-list | grep lr_in_arp_resolve | grep 10.0.0.2], [1], []) + +ip_to_hex() { + printf "%02x%02x%02x%02x" "$@" +} + +# Send ip packets from p1 to p2 +src_mac="f00000000102" +dst_mac="000000000101" +src_ip=`ip_to_hex 10 0 1 2` +dst_ip=`ip_to_hex 10 0 2 2` +packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000 +as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet +as hv1 ovs-appctl ofproto/trace br-int in_port=1 $packet + +# Packet to Expect at p2 +src_mac="000000000201" +dst_mac="f00000000202" +src_ip=`ip_to_hex 10 0 1 2` +dst_ip=`ip_to_hex 10 0 2 2` +echo "${dst_mac}${src_mac}08004500001c000000003e110200${src_ip}${dst_ip}0035111100080000" > expected + +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +# MAC binding entry should have generated +AT_CHECK([ovn-sbctl find mac ip=10.0.0.2 mac='"00:00:00:00:03:02"' logical_port=lrp-r1-join | grep 10\.0\.0\.2], [0], [ignore], []) + +OVN_CLEANUP([hv1],[hv2]) + +AT_CLEANUP From patchwork Wed Aug 5 07:05:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Han Zhou X-Patchwork-Id: 1341112 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ovn.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BM2hV4GbXz9sR4 for ; Wed, 5 Aug 2020 17:05:46 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id E4C35867BD; Wed, 5 Aug 2020 07:05:44 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id D6y4T1xmNePA; Wed, 5 Aug 2020 07:05:42 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 0944F86599; Wed, 5 Aug 2020 07:05:42 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id DC105C0889; Wed, 5 Aug 2020 07:05:41 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 13818C004C for ; Wed, 5 Aug 2020 07:05:40 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id EF4DA20656 for ; Wed, 5 Aug 2020 07:05:39 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id z0iLxiG3ZcbR for ; Wed, 5 Aug 2020 07:05:33 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by silver.osuosl.org (Postfix) with ESMTPS id 7C2E520366 for ; Wed, 5 Aug 2020 07:05:32 +0000 (UTC) X-Originating-IP: 216.113.160.71 Received: from localhost.localdomain.localdomain (unknown [216.113.160.71]) (Authenticated sender: hzhou@ovn.org) by relay1-d.mail.gandi.net (Postfix) with ESMTPSA id C5E7C240005; Wed, 5 Aug 2020 07:05:29 +0000 (UTC) From: Han Zhou To: dev@openvswitch.org Date: Wed, 5 Aug 2020 00:05:13 -0700 Message-Id: <1596611114-118204-3-git-send-email-hzhou@ovn.org> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1596611114-118204-1-git-send-email-hzhou@ovn.org> References: <1596611114-118204-1-git-send-email-hzhou@ovn.org> Cc: Han Zhou Subject: [ovs-dev] [PATCH ovn v2 2/3] actions: Implement new actions lookup_arp_ip and lookup_nd_ip. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" lookup_arp_ip and lookup_nd_ip are added to lookup if an entry exists in MAC bindings for a given IP address, for IPv4 and IPv6 respectively. Signed-off-by: Han Zhou --- controller/lflow.c | 4 +- include/ovn/actions.h | 10 +++++ lib/actions.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++ ovn-sb.xml | 55 +++++++++++++++++++++++++ tests/ovn.at | 50 ++++++++++++++++++++++ utilities/ovn-trace.c | 54 ++++++++++++++++++++++-- 6 files changed, 281 insertions(+), 4 deletions(-) diff --git a/controller/lflow.c b/controller/lflow.c index b2f5857..1515612 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -782,13 +782,15 @@ consider_neighbor_flow(struct ovsdb_idl_index *sbrec_port_binding_by_name, uint64_t stub[1024 / 8]; struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(stub); + uint8_t value = 1; put_load(mac.ea, sizeof mac.ea, MFF_ETH_DST, 0, 48, &ofpacts); + put_load(&value, sizeof value, MFF_LOG_FLAGS, MLF_LOOKUP_MAC_BIT, 1, + &ofpacts); ofctrl_add_flow(flow_table, OFTABLE_MAC_BINDING, 100, b->header_.uuid.parts[0], &get_arp_match, &ofpacts, &b->header_.uuid); ofpbuf_clear(&ofpacts); - uint8_t value = 1; put_load(&value, sizeof value, MFF_LOG_FLAGS, MLF_LOOKUP_MAC_BIT, 1, &ofpacts); match_set_dl_src(&lookup_arp_match, mac); diff --git a/include/ovn/actions.h b/include/ovn/actions.h index 12b7ab0..636cb4b 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -75,9 +75,11 @@ struct ovn_extend_table; OVNACT(GET_ARP, ovnact_get_mac_bind) \ OVNACT(PUT_ARP, ovnact_put_mac_bind) \ OVNACT(LOOKUP_ARP, ovnact_lookup_mac_bind) \ + OVNACT(LOOKUP_ARP_IP, ovnact_lookup_mac_bind_ip) \ OVNACT(GET_ND, ovnact_get_mac_bind) \ OVNACT(PUT_ND, ovnact_put_mac_bind) \ OVNACT(LOOKUP_ND, ovnact_lookup_mac_bind) \ + OVNACT(LOOKUP_ND_IP, ovnact_lookup_mac_bind_ip) \ OVNACT(PUT_DHCPV4_OPTS, ovnact_put_opts) \ OVNACT(PUT_DHCPV6_OPTS, ovnact_put_opts) \ OVNACT(SET_QUEUE, ovnact_set_queue) \ @@ -301,6 +303,14 @@ struct ovnact_lookup_mac_bind { struct expr_field mac; /* 48-bit Ethernet address. */ }; +/* OVNACT_LOOKUP_ARP_IP, OVNACT_LOOKUP_ND_IP. */ +struct ovnact_lookup_mac_bind_ip { + struct ovnact ovnact; + struct expr_field dst; /* 1-bit destination field. */ + struct expr_field port; /* Logical port name. */ + struct expr_field ip; /* 32-bit or 128-bit IP address. */ +}; + struct ovnact_gen_option { const struct gen_opts_map *option; struct expr_constant_set value; diff --git a/lib/actions.c b/lib/actions.c index 05fa44b..d7ed7a1 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -1902,6 +1902,110 @@ ovnact_lookup_mac_bind_free( } + +static void format_lookup_mac_bind_ip( + const struct ovnact_lookup_mac_bind_ip *lookup_mac, + struct ds *s, const char *name) +{ + expr_field_format(&lookup_mac->dst, s); + ds_put_format(s, " = %s(", name); + expr_field_format(&lookup_mac->port, s); + ds_put_cstr(s, ", "); + expr_field_format(&lookup_mac->ip, s); + ds_put_cstr(s, ");"); +} + +static void +format_LOOKUP_ARP_IP(const struct ovnact_lookup_mac_bind_ip *lookup_mac, + struct ds *s) +{ + format_lookup_mac_bind_ip(lookup_mac, s, "lookup_arp_ip"); +} + +static void +format_LOOKUP_ND_IP(const struct ovnact_lookup_mac_bind_ip *lookup_mac, + struct ds *s) +{ + format_lookup_mac_bind_ip(lookup_mac, s, "lookup_nd_ip"); +} + +static void +encode_lookup_mac_bind_ip(const struct ovnact_lookup_mac_bind_ip *lookup_mac, + enum mf_field_id ip_field, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) +{ + const struct arg args[] = { + { expr_resolve_field(&lookup_mac->port), MFF_LOG_OUTPORT }, + { expr_resolve_field(&lookup_mac->ip), ip_field }, + }; + + encode_setup_args(args, ARRAY_SIZE(args), ofpacts); + init_stack(ofpact_put_STACK_PUSH(ofpacts), MFF_ETH_DST); + + struct mf_subfield dst = expr_resolve_field(&lookup_mac->dst); + ovs_assert(dst.field); + + put_load(0, MFF_LOG_FLAGS, MLF_LOOKUP_MAC_BIT, 1, ofpacts); + emit_resubmit(ofpacts, ep->mac_bind_ptable); + + struct ofpact_reg_move *orm = ofpact_put_REG_MOVE(ofpacts); + orm->dst = dst; + orm->src.field = mf_from_id(MFF_LOG_FLAGS); + orm->src.ofs = MLF_LOOKUP_MAC_BIT; + orm->src.n_bits = 1; + + init_stack(ofpact_put_STACK_POP(ofpacts), MFF_ETH_DST); + encode_restore_args(args, ARRAY_SIZE(args), ofpacts); +} + +static void +encode_LOOKUP_ARP_IP(const struct ovnact_lookup_mac_bind_ip *lookup_mac, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) +{ + encode_lookup_mac_bind_ip(lookup_mac, MFF_REG0, ep, ofpacts); +} + +static void +encode_LOOKUP_ND_IP(const struct ovnact_lookup_mac_bind_ip *lookup_mac, + const struct ovnact_encode_params *ep, + struct ofpbuf *ofpacts) +{ + encode_lookup_mac_bind_ip(lookup_mac, MFF_XXREG0, ep, ofpacts); +} + +static void +parse_lookup_mac_bind_ip(struct action_context *ctx, + const struct expr_field *dst, + int width, + struct ovnact_lookup_mac_bind_ip *lookup_mac) +{ + /* Validate that the destination is a 1-bit, modifiable field. */ + char *error = expr_type_check(dst, 1, true, ctx->scope); + if (error) { + lexer_error(ctx->lexer, "%s", error); + free(error); + return; + } + + lexer_get(ctx->lexer); /* Skip lookup_arp/lookup_nd. */ + lexer_get(ctx->lexer); /* Skip '('. * */ + + action_parse_field(ctx, 0, false, &lookup_mac->port); + lexer_force_match(ctx->lexer, LEX_T_COMMA); + action_parse_field(ctx, width, false, &lookup_mac->ip); + lexer_force_match(ctx->lexer, LEX_T_RPAREN); + lookup_mac->dst = *dst; +} + +static void +ovnact_lookup_mac_bind_ip_free( + struct ovnact_lookup_mac_bind_ip *lookup_mac OVS_UNUSED) +{ + +} + static void parse_gen_opt(struct action_context *ctx, struct ovnact_gen_option *o, @@ -3358,6 +3462,14 @@ parse_set_action(struct action_context *ctx) && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) { parse_lookup_mac_bind(ctx, &lhs, 128, ovnact_put_LOOKUP_ND(ctx->ovnacts)); + } else if (!strcmp(ctx->lexer->token.s, "lookup_arp_ip") + && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) { + parse_lookup_mac_bind_ip(ctx, &lhs, 32, + ovnact_put_LOOKUP_ARP_IP(ctx->ovnacts)); + } else if (!strcmp(ctx->lexer->token.s, "lookup_nd_ip") + && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) { + parse_lookup_mac_bind_ip(ctx, &lhs, 128, + ovnact_put_LOOKUP_ND_IP(ctx->ovnacts)); } else { parse_assignment_action(ctx, false, &lhs); } diff --git a/ovn-sb.xml b/ovn-sb.xml index 32281eb..a74d9c3 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -1448,6 +1448,34 @@

+
+ R = lookup_arp_ip(P, A); +
+ +
+

+ Parameters: logical port string field P, 32-bit + IP address field A. +

+ +

+ Result: stored to a 1-bit subfield R. +

+ +

+ Looks up A in P's mac binding table. If an + entry is found, stores 1 in the 1-bit subfield + R, else 0. +

+ +

+ Example: + + reg0[0] = lookup_arp_ip(inport, arp.spa); + +

+
+
nd_ns { action; ... };

@@ -1632,6 +1660,33 @@

+
R = lookup_nd_ip(P, A); +
+ +
+

+ Parameters: logical port string field P, 128-bit + IP address field A. +

+ +

+ Result: stored to a 1-bit subfield R. +

+ +

+ Looks up A in P's mac binding table. If an + entry is found, stores 1 in the 1-bit subfield + R, else 0. +

+ +

+ Example: + + reg0[0] = lookup_nd_ip(inport, ip6.src); + +

+
+
R = put_dhcp_opts(D1 = V1, D2 = V2, ..., Dn = Vn);
diff --git a/tests/ovn.at b/tests/ovn.at index 654c343..33fa6f2 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -1246,6 +1246,31 @@ reg0[0] = lookup_arp(inport, eth.dst); reg0[0] = lookup_arp(inport, ip4.src, ip4.dst); Cannot use 32-bit field ip4.dst[0..31] where 48-bit field is required. +# lookup_arp_ip +reg0[0] = lookup_arp_ip(inport, ip4.dst); + encodes as push:NXM_NX_REG15[],push:NXM_NX_REG0[],push:NXM_OF_IP_DST[],push:NXM_NX_REG14[],pop:NXM_NX_REG15[],pop:NXM_NX_REG0[],push:NXM_OF_ETH_DST[],set_field:0/0x40->reg10,resubmit(,66),move:NXM_NX_REG10[6]->NXM_NX_XXREG0[96],pop:NXM_OF_ETH_DST[],pop:NXM_NX_REG0[],pop:NXM_NX_REG15[] + has prereqs eth.type == 0x800 +reg1[1] = lookup_arp_ip(inport, arp.spa); + encodes as push:NXM_NX_REG15[],push:NXM_NX_REG0[],push:NXM_OF_ARP_SPA[],push:NXM_NX_REG14[],pop:NXM_NX_REG15[],pop:NXM_NX_REG0[],push:NXM_OF_ETH_DST[],set_field:0/0x40->reg10,resubmit(,66),move:NXM_NX_REG10[6]->NXM_NX_XXREG0[65],pop:NXM_OF_ETH_DST[],pop:NXM_NX_REG0[],pop:NXM_NX_REG15[] + has prereqs eth.type == 0x806 + +lookup_arp_ip; + Syntax error at `lookup_arp_ip' expecting action. +reg0[0] = lookup_arp_ip; + Syntax error at `lookup_arp_ip' expecting field name. +reg0[0] = lookup_arp_ip(); + Syntax error at `)' expecting field name. +reg0[0] = lookup_arp_ip(inport); + Syntax error at `)' expecting `,'. +reg0[0] = lookup_arp_ip(inport ip4.dst); + Syntax error at `ip4.dst' expecting `,'. +reg0[0] = lookup_arp_ip(inport, ip4.dst; + Syntax error at `;' expecting `)'. +reg0[0] = lookup_arp_ip(inport, ip4.dst, eth.src; + Syntax error at `,' expecting `)'. +reg0[0] = lookup_arp_ip(inport, eth.dst); + Cannot use 48-bit field eth.dst[0..47] where 32-bit field is required. + # put_dhcp_opts reg1[0] = put_dhcp_opts(offerip = 1.2.3.4, router = 10.0.0.1); encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.40.01.02.03.04.03.04.0a.00.00.01,pause) @@ -1389,6 +1414,31 @@ reg0[0] = lookup_nd(inport, ip4.src, ip4.dst); reg0[0] = lookup_nd(inport, ip6.src, ip6.dst); Cannot use 128-bit field ip6.dst[0..127] where 48-bit field is required. +# lookup_nd_ip +reg2[0] = lookup_nd_ip(inport, ip6.dst); + encodes as push:NXM_NX_REG15[],push:NXM_NX_XXREG0[],push:NXM_NX_IPV6_DST[],push:NXM_NX_REG14[],pop:NXM_NX_REG15[],pop:NXM_NX_XXREG0[],push:NXM_OF_ETH_DST[],set_field:0/0x40->reg10,resubmit(,66),move:NXM_NX_REG10[6]->NXM_NX_XXREG0[32],pop:NXM_OF_ETH_DST[],pop:NXM_NX_XXREG0[],pop:NXM_NX_REG15[] + has prereqs eth.type == 0x86dd +reg3[0] = lookup_nd_ip(inport, nd.target); + encodes as push:NXM_NX_REG15[],push:NXM_NX_XXREG0[],push:NXM_NX_ND_TARGET[],push:NXM_NX_REG14[],pop:NXM_NX_REG15[],pop:NXM_NX_XXREG0[],push:NXM_OF_ETH_DST[],set_field:0/0x40->reg10,resubmit(,66),move:NXM_NX_REG10[6]->NXM_NX_XXREG0[0],pop:NXM_OF_ETH_DST[],pop:NXM_NX_XXREG0[],pop:NXM_NX_REG15[] + has prereqs (icmp6.type == 0x87 || icmp6.type == 0x88) && eth.type == 0x86dd && ip.proto == 0x3a && (eth.type == 0x800 || eth.type == 0x86dd) && icmp6.code == 0 && eth.type == 0x86dd && ip.proto == 0x3a && (eth.type == 0x800 || eth.type == 0x86dd) && ip.ttl == 0xff && (eth.type == 0x800 || eth.type == 0x86dd) + +lookup_nd_ip; + Syntax error at `lookup_nd_ip' expecting action. +reg0[0] = lookup_nd_ip; + Syntax error at `lookup_nd_ip' expecting field name. +reg0[0] = lookup_nd_ip(); + Syntax error at `)' expecting field name. +reg0[0] = lookup_nd_ip(inport); + Syntax error at `)' expecting `,'. +reg0[0] = lookup_nd_ip(inport ip6.dst); + Syntax error at `ip6.dst' expecting `,'. +reg0[0] = lookup_nd_ip(inport, ip6.dst; + Syntax error at `;' expecting `)'. +reg0[0] = lookup_nd_ip(inport, eth.dst); + Cannot use 48-bit field eth.dst[0..47] where 128-bit field is required. +reg0[0] = lookup_nd_ip(inport, ip4.src); + Cannot use 32-bit field ip4.src[0..31] where 128-bit field is required. + # set_queue set_queue(0); encodes as set_queue:0 diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c index 2c432ac..50a32b7 100644 --- a/utilities/ovn-trace.c +++ b/utilities/ovn-trace.c @@ -582,13 +582,13 @@ ovntrace_mac_binding_find(const struct ovntrace_datapath *dp, static const struct ovntrace_mac_binding * ovntrace_mac_binding_find_mac_ip(const struct ovntrace_datapath *dp, uint16_t port_key, const struct in6_addr *ip, - struct eth_addr mac) + struct eth_addr *mac) { const struct ovntrace_mac_binding *bind; HMAP_FOR_EACH_WITH_HASH (bind, node, hash_mac_binding(port_key, ip), &dp->mac_bindings) { if (bind->port_key == port_key && ipv6_addr_equals(ip, &bind->ip) - && eth_addr_equals(bind->mac, mac)) { + && (!mac || eth_addr_equals(bind->mac, *mac))) { return bind; } } @@ -1772,7 +1772,7 @@ execute_lookup_mac_bind(const struct ovnact_lookup_mac_bind *bind, mf_read_subfield(&mac_sf, uflow, &mac_sv); const struct ovntrace_mac_binding *binding - = ovntrace_mac_binding_find_mac_ip(dp, port_key, &ip, mac_sv.mac); + = ovntrace_mac_binding_find_mac_ip(dp, port_key, &ip, &mac_sv.mac); struct mf_subfield dst = expr_resolve_field(&bind->dst); uint8_t val = 0; @@ -1791,6 +1791,44 @@ execute_lookup_mac_bind(const struct ovnact_lookup_mac_bind *bind, } static void +execute_lookup_mac_bind_ip(const struct ovnact_lookup_mac_bind_ip *bind, + const struct ovntrace_datapath *dp, + struct flow *uflow, + struct ovs_list *super) +{ + /* Get logical port number.*/ + struct mf_subfield port_sf = expr_resolve_field(&bind->port); + ovs_assert(port_sf.n_bits == 32); + uint32_t port_key = mf_get_subfield(&port_sf, uflow); + + /* Get IP address. */ + struct mf_subfield ip_sf = expr_resolve_field(&bind->ip); + ovs_assert(ip_sf.n_bits == 32 || ip_sf.n_bits == 128); + union mf_subvalue ip_sv; + mf_read_subfield(&ip_sf, uflow, &ip_sv); + struct in6_addr ip = (ip_sf.n_bits == 32 + ? in6_addr_mapped_ipv4(ip_sv.ipv4) + : ip_sv.ipv6); + + const struct ovntrace_mac_binding *binding + = ovntrace_mac_binding_find_mac_ip(dp, port_key, &ip, NULL); + + struct mf_subfield dst = expr_resolve_field(&bind->dst); + uint8_t val = 0; + + if (binding) { + val = 1; + ovntrace_node_append(super, OVNTRACE_NODE_ACTION, + "/* MAC binding found. */"); + } else { + ovntrace_node_append(super, OVNTRACE_NODE_ACTION, + "/* lookup failed - No MAC binding. */"); + } + union mf_subvalue sv = { .u8_val = val }; + mf_write_subfield_flow(&dst, &sv, uflow); +} + +static void execute_put_opts(const struct ovnact_put_opts *po, const char *name, struct flow *uflow, struct ovs_list *super) @@ -2222,6 +2260,16 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, execute_lookup_mac_bind(ovnact_get_LOOKUP_ND(a), dp, uflow, super); break; + case OVNACT_LOOKUP_ARP_IP: + execute_lookup_mac_bind_ip(ovnact_get_LOOKUP_ARP_IP(a), dp, uflow, + super); + break; + + case OVNACT_LOOKUP_ND_IP: + execute_lookup_mac_bind_ip(ovnact_get_LOOKUP_ND_IP(a), dp, uflow, + super); + break; + case OVNACT_PUT_DHCPV4_OPTS: execute_put_dhcp_opts(ovnact_get_PUT_DHCPV4_OPTS(a), "put_dhcp_opts", uflow, super); From patchwork Wed Aug 5 07:05:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Han Zhou X-Patchwork-Id: 1341113 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ovn.org Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BM2hc68BSz9sR4 for ; Wed, 5 Aug 2020 17:05:52 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 643C986879; Wed, 5 Aug 2020 07:05:51 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id lp22_X8VOj2E; Wed, 5 Aug 2020 07:05:47 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 0D8C6866C8; Wed, 5 Aug 2020 07:05:43 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id EA40FC0889; Wed, 5 Aug 2020 07:05:42 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 8AEF0C004C for ; Wed, 5 Aug 2020 07:05:41 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 7ED2120448 for ; Wed, 5 Aug 2020 07:05:41 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id oq+Kud5Yc3Ec for ; Wed, 5 Aug 2020 07:05:34 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from relay1-d.mail.gandi.net (relay1-d.mail.gandi.net [217.70.183.193]) by silver.osuosl.org (Postfix) with ESMTPS id 98C9120402 for ; Wed, 5 Aug 2020 07:05:33 +0000 (UTC) X-Originating-IP: 216.113.160.71 Received: from localhost.localdomain.localdomain (unknown [216.113.160.71]) (Authenticated sender: hzhou@ovn.org) by relay1-d.mail.gandi.net (Postfix) with ESMTPSA id 27EFF240004; Wed, 5 Aug 2020 07:05:30 +0000 (UTC) From: Han Zhou To: dev@openvswitch.org Date: Wed, 5 Aug 2020 00:05:14 -0700 Message-Id: <1596611114-118204-4-git-send-email-hzhou@ovn.org> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1596611114-118204-1-git-send-email-hzhou@ovn.org> References: <1596611114-118204-1-git-send-email-hzhou@ovn.org> Cc: Han Zhou Subject: [ovs-dev] [PATCH ovn v2 3/3] ovn-northd.c: Support optionally disabling neighbor learning from ARP request/NS. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Support a new logical router option "always_learn_from_arp_request" that controls behavior when handling ARP requests or IPv4 ND-NS packets. "true" - Always learn the MAC/IP binding and add a new MAC_Binding entry (default behavior) "false" - If there is a MAC_binding for that IP and the MAC is different, or, if TPA of ARP request belongs to any router port on this router, then update/add that MAC/IP binding. Otherwise, don't update/add entries. Reported-by: Girish Moodalbail Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2020-May/049995.html Signed-off-by: Han Zhou Acked-by: Numan Siddique for all the 3 patches in the series. --- northd/ovn-northd.8.xml | 109 ++++++++++++++++++++++++++++++++++++++++-------- northd/ovn-northd.c | 96 +++++++++++++++++++++++++++++++++++------- ovn-nb.xml | 27 ++++++++++++ tests/ovn.at | 18 ++++++++ 4 files changed, 217 insertions(+), 33 deletions(-) diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml index 508123e..b08293f 100644 --- a/northd/ovn-northd.8.xml +++ b/northd/ovn-northd.8.xml @@ -1537,58 +1537,126 @@ output;

For each router port P that owns IP address A, which belongs to subnet S with prefix length L, - a priority-100 flow is added which matches - inport == P && - arp.spa == S/L && arp.op == 1 - (ARP request) with the - following actions: + if the option always_learn_from_arp_request is + true for this router, a priority-100 flow is added which + matches inport == P && arp.spa == + S/L && arp.op == 1 (ARP request) + with the following actions: +

+ +
+reg9[2] = lookup_arp(inport, arp.spa, arp.sha);
+next;
+        
+ +

+ If the option always_learn_from_arp_request is + false, the following two flows are added. +

+ +

+ A priority-110 flow is added which matches inport == + P && arp.spa == S/L + && arp.tpa == A && arp.op == 1 + (ARP request) with the following actions:

 reg9[2] = lookup_arp(inport, arp.spa, arp.sha);
+reg9[3] = 1;
+next;
+        
+ +

+ A priority-100 flow is added which matches inport == + P && arp.spa == S/L + && arp.op == 1 (ARP request) with the following + actions: +

+ +
+reg9[2] = lookup_arp(inport, arp.spa, arp.sha);
+reg9[3] = lookup_arp_ip(inport, arp.spa);
 next;
         

If the logical router port P is a distributed gateway router port, additional match - is_chassis_resident(cr-P) is added so that - the resident gateway chassis handles the neighbor lookup. + is_chassis_resident(cr-P) is added for all + these flows.

  • A priority-100 flow which matches on ARP reply packets and applies - the actions: + the actions if the option always_learn_from_arp_request + is true:

     reg9[2] = lookup_arp(inport, arp.spa, arp.sha);
     next;
             
    + +

    + If the option always_learn_from_arp_request + is false, the above actions will be: +

    + +
    +reg9[2] = lookup_arp(inport, arp.spa, arp.sha);
    +reg9[3] = 1;
    +next;
    +        
    +
  • A priority-100 flow which matches on IPv6 Neighbor Discovery - advertisement packet and applies the actions: + advertisement packet and applies the actions if the option + always_learn_from_arp_request is true:

     reg9[2] = lookup_nd(inport, nd.target, nd.tll);
     next;
             
    + +

    + If the option always_learn_from_arp_request + is false, the above actions will be: +

    + +
    +reg9[2] = lookup_nd(inport, nd.target, nd.tll);
    +reg9[3] = 1;
    +next;
    +        
  • A priority-100 flow which matches on IPv6 Neighbor Discovery - solicitation packet and applies the actions: + solicitation packet and applies the actions if the option + always_learn_from_arp_request is true: +

    + +
    +reg9[2] = lookup_nd(inport, ip6.src, nd.sll);
    +next;
    +        
    + +

    + If the option always_learn_from_arp_request + is false, the above actions will be:

     reg9[2] = lookup_nd(inport, ip6.src, nd.sll);
    +reg9[3] = lookup_nd_ip(inport, ip6.src);
     next;
             
  • @@ -1604,21 +1672,28 @@ next;

    This table adds flows to learn the mac bindings from the ARP and - IPv6 Neighbor Solicitation/Advertisement packets if ARP/ND lookup - failed in the previous table. + IPv6 Neighbor Solicitation/Advertisement packets if it is needed + according to the lookup results from the previous stage.

    reg9[2] will be 1 if the lookup_arp/lookup_nd - in the previous table was successful, or if there was no need to do the - lookup. + in the previous table was successful or skipped, meaning no need + to learn mac binding from the packet. +

    + +

    + reg9[3] will be 1 if the + lookup_arp_ip/lookup_nd_ip in the previous table was + successful or skipped, meaning it is ok to learn mac binding from + the packet (if reg9[2] is 0).

    • - A priority-100 flow with the match - reg9[2] == 1 and advances the packet - to the next table as there is no need to learn the neighbor. + A priority-100 flow with the match reg9[2] == 1 || reg9[3] == + 0 and advances the packet to the next table as there is no need + to learn the neighbor.
    • diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 5dd49f9..b7102b2 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -222,6 +222,7 @@ enum ovn_stage { /* Register to store the result of check_pkt_larger action. */ #define REGBIT_PKT_LARGER "reg9[1]" #define REGBIT_LOOKUP_NEIGHBOR_RESULT "reg9[2]" +#define REGBIT_LOOKUP_NEIGHBOR_IP_RESULT "reg9[3]" /* Register to store the eth address associated to a router port for packets * received in S_ROUTER_IN_ADMISSION. @@ -8442,36 +8443,62 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * For ARP packets, table LOOKUP_NEIGHBOR does a lookup for the * (arp.spa, arp.sha) in the mac binding table using the 'lookup_arp' * action and stores the result in REGBIT_LOOKUP_NEIGHBOR_RESULT bit. + * If "always_learn_from_arp_request" is set to false, it will also + * lookup for the (arp.spa) in the mac binding table using the + * "lookup_arp_ip" action for ARP request packets, and stores the + * result in REGBIT_LOOKUP_NEIGHBOR_IP_RESULT bit; or set that bit + * to "1" directly for ARP response packets. * * For IPv6 ND NA packets, table LOOKUP_NEIGHBOR does a lookup * for the (nd.target, nd.tll) in the mac binding table using the * 'lookup_nd' action and stores the result in - * REGBIT_LOOKUP_NEIGHBOR_RESULT bit. + * REGBIT_LOOKUP_NEIGHBOR_RESULT bit. If + * "always_learn_from_arp_request" is set to false, + * REGBIT_LOOKUP_NEIGHBOR_IP_RESULT bit is set. * * For IPv6 ND NS packets, table LOOKUP_NEIGHBOR does a lookup * for the (ip6.src, nd.sll) in the mac binding table using the * 'lookup_nd' action and stores the result in - * REGBIT_LOOKUP_NEIGHBOR_RESULT bit. + * REGBIT_LOOKUP_NEIGHBOR_RESULT bit. If + * "always_learn_from_arp_request" is set to false, it will also lookup + * for the (ip6.src) in the mac binding table using the "lookup_nd_ip" + * action and stores the result in REGBIT_LOOKUP_NEIGHBOR_IP_RESULT + * bit. * * Table LEARN_NEIGHBOR learns the mac-binding using the action - * - 'put_arp/put_nd' only if REGBIT_LOOKUP_NEIGHBOR_RESULT bit - * is not set. + * - 'put_arp/put_nd'. Learning mac-binding is skipped if + * REGBIT_LOOKUP_NEIGHBOR_RESULT bit is set or + * REGBIT_LOOKUP_NEIGHBOR_IP_RESULT is not set. * * */ /* Flows for LOOKUP_NEIGHBOR. */ + bool learn_from_arp_request = smap_get_bool(&od->nbr->options, + "always_learn_from_arp_request", true); + ds_clear(&actions); + ds_put_format(&actions, REGBIT_LOOKUP_NEIGHBOR_RESULT + " = lookup_arp(inport, arp.spa, arp.sha); %snext;", + learn_from_arp_request ? "" : + REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1; "); ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, - "arp.op == 2", - REGBIT_LOOKUP_NEIGHBOR_RESULT" = " - "lookup_arp(inport, arp.spa, arp.sha); next;"); + "arp.op == 2", ds_cstr(&actions)); + ds_clear(&actions); + ds_put_format(&actions, REGBIT_LOOKUP_NEIGHBOR_RESULT + " = lookup_nd(inport, nd.target, nd.tll); %snext;", + learn_from_arp_request ? "" : + REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1; "); ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, "nd_na", - REGBIT_LOOKUP_NEIGHBOR_RESULT" = " - "lookup_nd(inport, nd.target, nd.tll); next;"); + ds_cstr(&actions)); + ds_clear(&actions); + ds_put_format(&actions, REGBIT_LOOKUP_NEIGHBOR_RESULT + " = lookup_nd(inport, ip6.src, nd.sll); %snext;", + learn_from_arp_request ? "" : + REGBIT_LOOKUP_NEIGHBOR_IP_RESULT + " = lookup_nd_ip(inport, ip6.src); "); ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, "nd_ns", - REGBIT_LOOKUP_NEIGHBOR_RESULT" = " - "lookup_nd(inport, ip6.src, nd.sll); next;"); + ds_cstr(&actions)); /* For other packet types, we can skip neighbor learning. * So set REGBIT_LOOKUP_NEIGHBOR_RESULT to 1. */ @@ -8480,8 +8507,12 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, /* Flows for LEARN_NEIGHBOR. */ /* Skip Neighbor learning if not required. */ + ds_clear(&match); + ds_put_format(&match, REGBIT_LOOKUP_NEIGHBOR_RESULT" == 1%s", + learn_from_arp_request ? "" : + " || "REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" == 0"); ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 100, - REGBIT_LOOKUP_NEIGHBOR_RESULT" == 1", "next;"); + ds_cstr(&match), "next;"); ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, "arp", "put_arp(inport, arp.spa, arp.sha); next;"); @@ -8498,8 +8529,37 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, continue; } + bool learn_from_arp_request = smap_get_bool(&op->od->nbr->options, + "always_learn_from_arp_request", true); + /* Check if we need to learn mac-binding from ARP requests. */ for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { + if (!learn_from_arp_request) { + /* ARP request to this address should always get learned, + * so add a priority-110 flow to set + * REGBIT_LOOKUP_NEIGHBOR_IP_RESULT to 1. */ + ds_clear(&match); + ds_put_format(&match, + "inport == %s && arp.spa == %s/%u && " + "arp.tpa == %s && arp.op == 1", + op->json_key, + op->lrp_networks.ipv4_addrs[i].network_s, + op->lrp_networks.ipv4_addrs[i].plen, + op->lrp_networks.ipv4_addrs[i].addr_s); + if (op->od->l3dgw_port && op == op->od->l3dgw_port + && op->od->l3redirect_port) { + ds_put_format(&match, " && is_chassis_resident(%s)", + op->od->l3redirect_port->json_key); + } + const char *actions_s = REGBIT_LOOKUP_NEIGHBOR_RESULT + " = lookup_arp(inport, arp.spa, arp.sha); " + REGBIT_LOOKUP_NEIGHBOR_IP_RESULT" = 1;" + " next;"; + ovn_lflow_add_with_hint(lflows, op->od, + S_ROUTER_IN_LOOKUP_NEIGHBOR, 110, + ds_cstr(&match), actions_s, + &op->nbrp->header_); + } ds_clear(&match); ds_put_format(&match, "inport == %s && arp.spa == %s/%u && arp.op == 1", @@ -8511,12 +8571,16 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_put_format(&match, " && is_chassis_resident(%s)", op->od->l3redirect_port->json_key); } + ds_clear(&actions); + ds_put_format(&actions, REGBIT_LOOKUP_NEIGHBOR_RESULT + " = lookup_arp(inport, arp.spa, arp.sha); %snext;", + learn_from_arp_request ? "" : + REGBIT_LOOKUP_NEIGHBOR_IP_RESULT + " = lookup_arp_ip(inport, arp.spa); "); ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 100, - ds_cstr(&match), - REGBIT_LOOKUP_NEIGHBOR_RESULT" = " - "lookup_arp(inport, arp.spa, arp.sha); " - "next;", &op->nbrp->header_); + ds_cstr(&match), ds_cstr(&actions), + &op->nbrp->header_); } } diff --git a/ovn-nb.xml b/ovn-nb.xml index 4c59338..d0317db 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -1859,6 +1859,33 @@ send traffic between each other.

      + +

      + This option controls the behavior when handling IPv4 ARP requests or + IPv6 ND-NS packets - whether a dynamic neighbor (MAC binding) entry + is added/updated. +

      + +

      + true - Always learn the MAC-IP binding, and add/update + the MAC binding entry. +

      + +

      + false - If there is a MAC binding for that IP and the + MAC is different, or, if TPA of ARP request belongs to any router + port on this router, then update/add that MAC-IP binding. Otherwise, + don't update/add entries. +

      + +

      + It is true by default. It is recommended to set to + false when a large number of logical routers are + connected to the same logical switch but most of them never need to + send traffic between each other, to reduce the size of the MAC + binding table. +

      +
      diff --git a/tests/ovn.at b/tests/ovn.at index 33fa6f2..ef5ef12 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -4042,6 +4042,18 @@ ip_to_hex() { sha=f00000000011 spa=`ip_to_hex 192 168 1 100` tpa=$spa + +# When always_learn_from_arp_request=false, the new mac-binding will not be learned +# through GARP request. +ovn-nbctl --wait=hv set logical_router lr0 options:always_learn_from_arp_request=false + +test_arp 11 $sha $spa $tpa +sleep 1 +AT_CHECK([ovn-sbctl find mac_binding ip="192.168.1.100"], [0], []) + +# When always_learn_from_arp_request=true, the new mac-binding will be learned. +ovn-nbctl --wait=hv set logical_router lr0 options:always_learn_from_arp_request=true + test_arp 11 $sha $spa $tpa OVS_WAIT_UNTIL([test `ovn-sbctl find mac_binding ip="192.168.1.100" | wc -l` -gt 0]) ovn-nbctl --wait=hv sync @@ -4056,6 +4068,12 @@ test_ip 21 $smac $dmac $sip $dip 11 # lp12 send GARP request to announce ownership of 192.168.1.100. +# Even when always_learn_from_arp_request=false, the existing mac-binding should be +# updated through GARP request. +ovn-nbctl --wait=hv set logical_router lr0 options:always_learn_from_arp_request=false +ovn-sbctl lflow-list +as hv2 ovs-ofctl dump-flows br-int + sha=f00000000012 test_arp 12 $sha $spa $tpa OVS_WAIT_UNTIL([ovn-sbctl find mac_binding ip="192.168.1.100" | grep f0:00:00:00:00:12])