From patchwork Thu Apr 29 17:04:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1471793 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=2605:bc80:3010::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=DjugoNkp; dkim-atps=neutral Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FWMLb0XGFz9t0G for ; Fri, 30 Apr 2021 03:04:55 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id D9A2941A71; Thu, 29 Apr 2021 17:04:52 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id VG62KEca_TMb; Thu, 29 Apr 2021 17:04:50 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTP id DE0EC41A2B; Thu, 29 Apr 2021 17:04:44 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0387AC002C; Thu, 29 Apr 2021 17:04:43 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1CA33C0011 for ; Thu, 29 Apr 2021 17:04:39 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 694764199B for ; Thu, 29 Apr 2021 17:04:38 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp2.osuosl.org (amavisd-new); dkim=pass (1024-bit key) header.d=redhat.com Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id SazDOMp5EtJi for ; Thu, 29 Apr 2021 17:04:37 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by smtp2.osuosl.org (Postfix) with ESMTPS id D2DEB41987 for ; Thu, 29 Apr 2021 17:04:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1619715875; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=eAnCgiyNw8oaHI5uL5nTMAxk+yqcBNNqMnVCCzyjvXY=; b=DjugoNkpNBJ+2EuTLTMvsNLdHYaw+fum4D4il1B2fs9oW2TR/zqSk1mx2wRW7YwQiIpezh iqzEDov/xFSsWhuXmV6Jtnf9UtszTUWlPZzhrNKcYd+rhnfcW9O3VeU2TPRqcbLIADGa4t o3H31hXlcr2UgKvrSW3w0gbJtRhqb7k= Received: from mail-ed1-f72.google.com (mail-ed1-f72.google.com [209.85.208.72]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-15-NxdwwoCvNeiNnUIoaPUP1A-1; Thu, 29 Apr 2021 13:04:27 -0400 X-MC-Unique: NxdwwoCvNeiNnUIoaPUP1A-1 Received: by mail-ed1-f72.google.com with SMTP id i17-20020a50fc110000b0290387c230e257so6915670edr.0 for ; Thu, 29 Apr 2021 10:04:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=eAnCgiyNw8oaHI5uL5nTMAxk+yqcBNNqMnVCCzyjvXY=; b=iKRxA5kdVTgP1yY7TqzSu4nIkROeAz0EdUf/dLdxYWSx/Pga0ZXXDqRQNvvlqDi3+R J3Va6jbftF/kJPq3fZ8fyvpBKsA24LElEOachFTsFvXWQ2mTxljjcj0BxspklxyYtLkL QxCO8wD16a+3/6eDwBkKL+qFsEKOHqfBQrBPjAHCnxMiVj/kHTDNNIm6jaRh0EMLE5bi PeVTfTlu+zagU5wkVlNcjrn3IC5L3YfhLuuoxON8aLe0p5gzEjj6n5oZHn03Wv4LBdNT F5QazwjtSw3evIhlApQo0SJxErnwO/TdSkxHMZhUHv+ofq7af6oxt5FGkn8FV0YBBCy4 fLfg== X-Gm-Message-State: AOAM533FViwXLApRz6uHz0v1jxS2lss7yKHyeS+bxUCcfZg/9qgbV2SI b1vDINQlnB5DYpYGQ8x+AQHIy448t82ULXtmQ1dacOMBt8AE2tMXUc7904ZF3ZOWdK3MrTFRK+a QKkxsM5Y7bOA5ky66oIyhgO7V4Iy8pxFvhdRASbUW3U61p4uIzZ9Rhr9cW4u/RlZ8JIQRuxwqX0 A= X-Received: by 2002:a17:906:dc90:: with SMTP id cs16mr891440ejc.210.1619715865308; Thu, 29 Apr 2021 10:04:25 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxBMuFlRc9tiIu/BeifIEidktYnW0a4cEywsg+CswpQ586bsIHl6jdDdy+GxSkiy18UGNtjRg== X-Received: by 2002:a17:906:dc90:: with SMTP id cs16mr891408ejc.210.1619715864924; Thu, 29 Apr 2021 10:04:24 -0700 (PDT) Received: from lore-desk.redhat.com ([151.66.28.185]) by smtp.gmail.com with ESMTPSA id re26sm299250ejb.3.2021.04.29.10.04.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Apr 2021 10:04:24 -0700 (PDT) From: Lorenzo Bianconi To: dev@openvswitch.org Date: Thu, 29 Apr 2021 19:04:14 +0200 Message-Id: X-Mailer: git-send-email 2.30.2 In-Reply-To: References: MIME-Version: 1.0 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=lorenzo.bianconi@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Cc: dceara@redhat.com Subject: [ovs-dev] [PATCH ovn 1/5] ovn-controller: Add support for Logical_Flow control meters 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: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Dumitru Ceara Add a new 'controller_meter' column to OVN Southbound Logical_Flow table. This stores an optional string which should correspond to the Meter that must be used for rate limiting controller actions generated by packets hitting the flow. Add a new 'ofctrl_add_flow_metred' function to create a new 'ovn_flow' with an attached controller meter. Change ofctrl_check_and_add_flow to allow specifying a meter ID for packets that are punted to controller. Change consider_logical_flow to parse controller_meter from the logical flow and use it when building openflow entries. Add a new 'ctrl_meter_id' field to 'struct ovnact_encode_params' to be used when encoding controller actions from logical flow actions. Co-authored-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Dumitru Ceara --- controller/lflow.c | 40 +++++++++++++++++++++++--- controller/ofctrl.c | 54 ++++++++++++++++++++++++----------- controller/ofctrl.h | 21 ++++++++++---- controller/physical.c | 7 +++-- include/ovn/actions.h | 2 ++ lib/actions.c | 66 +++++++++++++++++++++++-------------------- ovn-sb.ovsschema | 6 ++-- ovn-sb.xml | 6 ++++ 8 files changed, 139 insertions(+), 63 deletions(-) diff --git a/controller/lflow.c b/controller/lflow.c index b8424e1fb..f3f901c32 100644 --- a/controller/lflow.c +++ b/controller/lflow.c @@ -557,6 +557,27 @@ update_conj_id_ofs(uint32_t *conj_id_ofs, uint32_t n_conjs) return false; } +static void +lflow_parse_ctrl_meter(const struct sbrec_logical_flow *lflow, + struct ovn_extend_table *meter_table, + uint32_t *meter_id) +{ + ovs_assert(meter_id); + *meter_id = NX_CTLR_NO_METER; + + if (lflow->controller_meter) { + *meter_id = ovn_extend_table_assign_id(meter_table, + lflow->controller_meter, + lflow->header_.uuid); + if (*meter_id == EXT_TABLE_ID_INVALID) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "Unable to assign id for meter: %s", + lflow->controller_meter); + return; + } + } +} + static void add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, const struct sbrec_datapath_binding *dp, @@ -572,6 +593,13 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, .dp = dp, }; + /* Parse any meter to be used if this flow should punt packets to + * controller. + */ + uint32_t ctrl_meter_id = NX_CTLR_NO_METER; + lflow_parse_ctrl_meter(lflow, l_ctx_out->meter_table, + &ctrl_meter_id); + /* Encode OVN logical actions into OpenFlow. */ uint64_t ofpacts_stub[1024 / 8]; struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); @@ -595,6 +623,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, .ct_snat_vip_ptable = OFTABLE_CT_SNAT_FOR_VIP, .fdb_ptable = OFTABLE_GET_FDB, .fdb_lookup_ptable = OFTABLE_LOOKUP_FDB, + .ctrl_meter_id = ctrl_meter_id, }; ovnacts_encode(ovnacts->data, ovnacts->size, &ep, &ofpacts); @@ -621,9 +650,11 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, } } if (!m->n) { - ofctrl_add_flow(l_ctx_out->flow_table, ptable, lflow->priority, - lflow->header_.uuid.parts[0], &m->match, &ofpacts, - &lflow->header_.uuid); + ofctrl_add_flow_metred(l_ctx_out->flow_table, ptable, + lflow->priority, + lflow->header_.uuid.parts[0], &m->match, + &ofpacts, &lflow->header_.uuid, + ctrl_meter_id); } else { uint64_t conj_stubs[64 / 8]; struct ofpbuf conj; @@ -641,7 +672,8 @@ add_matches_to_flow_table(const struct sbrec_logical_flow *lflow, ofctrl_add_or_append_flow(l_ctx_out->flow_table, ptable, lflow->priority, 0, - &m->match, &conj, &lflow->header_.uuid); + &m->match, &conj, &lflow->header_.uuid, + ctrl_meter_id); ofpbuf_uninit(&conj); } } diff --git a/controller/ofctrl.c b/controller/ofctrl.c index c29c3d180..575dcd625 100644 --- a/controller/ofctrl.c +++ b/controller/ofctrl.c @@ -66,6 +66,7 @@ struct ovn_flow { struct ofpact *ofpacts; size_t ofpacts_len; uint64_t cookie; + uint32_t ctrl_meter_id; /* Meter to be used for controller actions. */ }; /* A desired flow, in struct ovn_desired_flow_table, calculated by the @@ -220,7 +221,8 @@ static struct desired_flow *desired_flow_alloc( uint16_t priority, uint64_t cookie, const struct match *match, - const struct ofpbuf *actions); + const struct ofpbuf *actions, + uint32_t meter_id); static struct desired_flow *desired_flow_lookup( struct ovn_desired_flow_table *, const struct ovn_flow *target); @@ -1010,8 +1012,9 @@ link_flow_to_sb(struct ovn_desired_flow_table *flow_table, /* Flow table interfaces to the rest of ovn-controller. */ /* Adds a flow to 'desired_flows' with the specified 'match' and 'actions' to - * the OpenFlow table numbered 'table_id' with the given 'priority' and - * OpenFlow 'cookie'. The caller retains ownership of 'match' and 'actions'. + * the OpenFlow table numbered 'table_id' with the given 'priority', OpenFlow + * 'cookie' and 'meter_id'. The caller retains ownership of 'match' and + * 'actions'. * * The flow is also linked to the sb_uuid that generates it. * @@ -1020,15 +1023,15 @@ link_flow_to_sb(struct ovn_desired_flow_table *flow_table, * * The caller should initialize its own hmap to hold the flows. */ void -ofctrl_check_and_add_flow(struct ovn_desired_flow_table *flow_table, - uint8_t table_id, uint16_t priority, - uint64_t cookie, const struct match *match, - const struct ofpbuf *actions, - const struct uuid *sb_uuid, - bool log_duplicate_flow) +ofctrl_check_and_add_flow_metred(struct ovn_desired_flow_table *flow_table, + uint8_t table_id, uint16_t priority, + uint64_t cookie, const struct match *match, + const struct ofpbuf *actions, + const struct uuid *sb_uuid, + uint32_t meter_id, bool log_duplicate_flow) { struct desired_flow *f = desired_flow_alloc(table_id, priority, cookie, - match, actions); + match, actions, meter_id); if (desired_flow_lookup_check_uuid(flow_table, &f->flow, sb_uuid)) { if (log_duplicate_flow) { @@ -1056,8 +1059,18 @@ ofctrl_add_flow(struct ovn_desired_flow_table *desired_flows, const struct match *match, const struct ofpbuf *actions, const struct uuid *sb_uuid) { - ofctrl_check_and_add_flow(desired_flows, table_id, priority, cookie, - match, actions, sb_uuid, true); + ofctrl_add_flow_metred(desired_flows, table_id, priority, cookie, + match, actions, sb_uuid, NX_CTLR_NO_METER); +} + +void +ofctrl_add_flow_metred(struct ovn_desired_flow_table *desired_flows, + uint8_t table_id, uint16_t priority, uint64_t cookie, + const struct match *match, const struct ofpbuf *actions, + const struct uuid *sb_uuid, uint32_t meter_id) +{ + ofctrl_check_and_add_flow_metred(desired_flows, table_id, priority, cookie, + match, actions, sb_uuid, meter_id, true); } /* Either add a new flow, or append actions on an existing flow. If the @@ -1068,12 +1081,14 @@ ofctrl_add_or_append_flow(struct ovn_desired_flow_table *desired_flows, uint8_t table_id, uint16_t priority, uint64_t cookie, const struct match *match, const struct ofpbuf *actions, - const struct uuid *sb_uuid) + const struct uuid *sb_uuid, + uint32_t meter_id) { struct desired_flow *existing; struct desired_flow *f; - f = desired_flow_alloc(table_id, priority, cookie, match, actions); + f = desired_flow_alloc(table_id, priority, cookie, match, actions, + meter_id); existing = desired_flow_lookup_conjunctive(desired_flows, &f->flow); if (existing) { /* There's already a flow with this particular match and action @@ -1278,7 +1293,7 @@ ofctrl_flood_remove_flows(struct ovn_desired_flow_table *flow_table, static void ovn_flow_init(struct ovn_flow *f, uint8_t table_id, uint16_t priority, uint64_t cookie, const struct match *match, - const struct ofpbuf *actions) + const struct ofpbuf *actions, uint32_t meter_id) { f->table_id = table_id; f->priority = priority; @@ -1287,11 +1302,13 @@ ovn_flow_init(struct ovn_flow *f, uint8_t table_id, uint16_t priority, f->ofpacts_len = actions->size; f->hash = ovn_flow_match_hash(f); f->cookie = cookie; + f->ctrl_meter_id = meter_id; } static struct desired_flow * desired_flow_alloc(uint8_t table_id, uint16_t priority, uint64_t cookie, - const struct match *match, const struct ofpbuf *actions) + const struct match *match, const struct ofpbuf *actions, + uint32_t meter_id) { struct desired_flow *f = xmalloc(sizeof *f); ovs_list_init(&f->references); @@ -1300,7 +1317,8 @@ desired_flow_alloc(uint8_t table_id, uint16_t priority, uint64_t cookie, ovs_list_init(&f->track_list_node); f->installed_flow = NULL; f->is_deleted = false; - ovn_flow_init(&f->flow, table_id, priority, cookie, match, actions); + ovn_flow_init(&f->flow, table_id, priority, cookie, match, actions, + meter_id); return f; } @@ -1326,6 +1344,7 @@ installed_flow_dup(struct desired_flow *src) dst->flow.ofpacts_len = src->flow.ofpacts_len; dst->flow.hash = src->flow.hash; dst->flow.cookie = src->flow.cookie; + dst->flow.ctrl_meter_id = src->flow.ctrl_meter_id; return dst; } @@ -1352,6 +1371,7 @@ desired_flow_lookup__(struct ovn_desired_flow_table *flow_table, struct ovn_flow *f = &d->flow; if (f->table_id == target->table_id && f->priority == target->priority + && f->ctrl_meter_id == target->ctrl_meter_id && minimatch_equal(&f->match, &target->match)) { if (!match_cb || match_cb(d, arg)) { diff --git a/controller/ofctrl.h b/controller/ofctrl.h index 88769566a..018d781a2 100644 --- a/controller/ofctrl.h +++ b/controller/ofctrl.h @@ -78,7 +78,15 @@ void ofctrl_add_or_append_flow(struct ovn_desired_flow_table *desired_flows, uint8_t table_id, uint16_t priority, uint64_t cookie, const struct match *match, const struct ofpbuf *actions, - const struct uuid *sb_uuid); + const struct uuid *sb_uuid, + uint32_t meter_id); + +void ofctrl_add_flow_metred(struct ovn_desired_flow_table *desired_flows, + uint8_t table_id, uint16_t priority, + uint64_t cookie, const struct match *match, + const struct ofpbuf *actions, + const struct uuid *sb_uuid, + uint32_t meter_id); /* Removes a bundles of flows from the flow table for a specific sb_uuid. The * flows are removed only if they are not referenced by any other sb_uuid(s). @@ -108,11 +116,12 @@ void ovn_desired_flow_table_init(struct ovn_desired_flow_table *); void ovn_desired_flow_table_clear(struct ovn_desired_flow_table *); void ovn_desired_flow_table_destroy(struct ovn_desired_flow_table *); -void ofctrl_check_and_add_flow(struct ovn_desired_flow_table *, - uint8_t table_id, uint16_t priority, - uint64_t cookie, const struct match *, - const struct ofpbuf *ofpacts, - const struct uuid *, bool log_duplicate_flow); +void ofctrl_check_and_add_flow_metred(struct ovn_desired_flow_table *, + uint8_t table_id, uint16_t priority, + uint64_t cookie, const struct match *, + const struct ofpbuf *ofpacts, + const struct uuid *, uint32_t meter_id, + bool log_duplicate_flow); bool ofctrl_is_connected(void); diff --git a/controller/physical.c b/controller/physical.c index 96c959d18..82bf9358a 100644 --- a/controller/physical.c +++ b/controller/physical.c @@ -838,7 +838,7 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key, * If a parent port has multiple child ports, then this if condition * will be hit multiple times, but we want to add only one flow. * ofctrl_add_flow() logs a warning message for duplicate flows. - * So use the function 'ofctrl_check_and_add_flow' which doesn't + * So use the function 'ofctrl_check_and_add_flow_metred' which doesn't * log a warning. * * Other option is to add this flow for all the ports which are not @@ -857,8 +857,9 @@ put_local_common_flows(uint32_t dp_key, uint32_t port_key, put_load(ofp_to_u16(OFPP_NONE), MFF_IN_PORT, 0, 16, ofpacts_p); put_resubmit(OFTABLE_LOG_TO_PHY, ofpacts_p); put_stack(MFF_IN_PORT, ofpact_put_STACK_POP(ofpacts_p)); - ofctrl_check_and_add_flow(flow_table, OFTABLE_SAVE_INPORT, 100, 0, - &match, ofpacts_p, hc_uuid, false); + ofctrl_check_and_add_flow_metred(flow_table, OFTABLE_SAVE_INPORT, 100, + 0, &match, ofpacts_p, hc_uuid, + NX_CTLR_NO_METER, false); } } diff --git a/include/ovn/actions.h b/include/ovn/actions.h index 040213177..ab03df12c 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -795,6 +795,8 @@ struct ovnact_encode_params { * 'get_fdb' to resubmit. */ uint8_t fdb_lookup_ptable; /* OpenFlow table for * 'lookup_fdb' to resubmit. */ + uint32_t ctrl_meter_id; /* Meter to be used if the resulting flow + sends packets to controller. */ }; void ovnacts_encode(const struct ovnact[], size_t ovnacts_len, diff --git a/lib/actions.c b/lib/actions.c index b3433f49e..155b4a45a 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -105,10 +105,10 @@ encode_finish_controller_op(size_t ofs, struct ofpbuf *ofpacts) } static void -encode_controller_op(enum action_opcode opcode, struct ofpbuf *ofpacts) +encode_controller_op(enum action_opcode opcode, uint32_t meter_id, + struct ofpbuf *ofpacts) { - size_t ofs = encode_start_controller_op(opcode, false, NX_CTLR_NO_METER, - ofpacts); + size_t ofs = encode_start_controller_op(opcode, false, meter_id, ofpacts); encode_finish_controller_op(ofs, ofpacts); } @@ -1647,7 +1647,7 @@ encode_nested_actions(const struct ovnact_nest *on, * packet to ARP or NA and then send the packet and actions back to the * switch inside an OFPT_PACKET_OUT message. */ size_t oc_offset = encode_start_controller_op(opcode, false, - NX_CTLR_NO_METER, ofpacts); + ep->ctrl_meter_id, ofpacts); ofpacts_put_openflow_actions(inner_ofpacts.data, inner_ofpacts.size, ofpacts, OFP15_VERSION); encode_finish_controller_op(oc_offset, ofpacts); @@ -1698,10 +1698,10 @@ encode_ICMP6_ERROR(const struct ovnact_nest *on, static void encode_IGMP(const struct ovnact_null *a OVS_UNUSED, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { - encode_controller_op(ACTION_OPCODE_IGMP, ofpacts); + encode_controller_op(ACTION_OPCODE_IGMP, ep->ctrl_meter_id, ofpacts); } static void @@ -1943,6 +1943,7 @@ format_PUT_ND(const struct ovnact_put_mac_bind *put_mac, struct ds *s) static void encode_put_mac(const struct ovnact_put_mac_bind *put_mac, + const struct ovnact_encode_params *ep, enum mf_field_id ip_field, enum action_opcode opcode, struct ofpbuf *ofpacts) { @@ -1952,24 +1953,24 @@ encode_put_mac(const struct ovnact_put_mac_bind *put_mac, { expr_resolve_field(&put_mac->mac), MFF_ETH_SRC } }; encode_setup_args(args, ARRAY_SIZE(args), ofpacts); - encode_controller_op(opcode, ofpacts); + encode_controller_op(opcode, ep->ctrl_meter_id, ofpacts); encode_restore_args(args, ARRAY_SIZE(args), ofpacts); } static void encode_PUT_ARP(const struct ovnact_put_mac_bind *put_mac, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { - encode_put_mac(put_mac, MFF_REG0, ACTION_OPCODE_PUT_ARP, ofpacts); + encode_put_mac(put_mac, ep, MFF_REG0, ACTION_OPCODE_PUT_ARP, ofpacts); } static void encode_PUT_ND(const struct ovnact_put_mac_bind *put_mac, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { - encode_put_mac(put_mac, MFF_XXREG0, ACTION_OPCODE_PUT_ND, ofpacts); + encode_put_mac(put_mac, ep, MFF_XXREG0, ACTION_OPCODE_PUT_ND, ofpacts); } static void @@ -2670,13 +2671,13 @@ encode_put_dhcpv6_option(const struct ovnact_gen_option *o, static void encode_PUT_DHCPV4_OPTS(const struct ovnact_put_opts *pdo, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { struct mf_subfield dst = expr_resolve_field(&pdo->dst); size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_PUT_DHCP_OPTS, - true, NX_CTLR_NO_METER, + true, ep->ctrl_meter_id, ofpacts); nx_put_header(ofpacts, dst.field->id, OFP15_VERSION, false); ovs_be32 ofs = htonl(dst.ofs); @@ -2723,13 +2724,13 @@ encode_PUT_DHCPV4_OPTS(const struct ovnact_put_opts *pdo, static void encode_PUT_DHCPV6_OPTS(const struct ovnact_put_opts *pdo, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { struct mf_subfield dst = expr_resolve_field(&pdo->dst); size_t oc_offset = encode_start_controller_op( - ACTION_OPCODE_PUT_DHCPV6_OPTS, true, NX_CTLR_NO_METER, ofpacts); + ACTION_OPCODE_PUT_DHCPV6_OPTS, true, ep->ctrl_meter_id, ofpacts); nx_put_header(ofpacts, dst.field->id, OFP15_VERSION, false); ovs_be32 ofs = htonl(dst.ofs); ofpbuf_put(ofpacts, &ofs, sizeof ofs); @@ -2756,10 +2757,11 @@ format_DHCP6_REPLY(const struct ovnact_null *a OVS_UNUSED, struct ds *s) static void encode_DHCP6_REPLY(const struct ovnact_null *a OVS_UNUSED, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { - encode_controller_op(ACTION_OPCODE_DHCP6_SERVER, ofpacts); + encode_controller_op(ACTION_OPCODE_DHCP6_SERVER, ep->ctrl_meter_id, + ofpacts); } static void @@ -2770,10 +2772,11 @@ format_BFD_MSG(const struct ovnact_null *a OVS_UNUSED, struct ds *s) static void encode_BFD_MSG(const struct ovnact_null *a OVS_UNUSED, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { - encode_controller_op(ACTION_OPCODE_BFD_MSG, ofpacts); + encode_controller_op(ACTION_OPCODE_BFD_MSG, ep->ctrl_meter_id, + ofpacts); } static void @@ -2868,13 +2871,13 @@ format_DNS_LOOKUP(const struct ovnact_result *dl, struct ds *s) static void encode_DNS_LOOKUP(const struct ovnact_result *dl, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { struct mf_subfield dst = expr_resolve_field(&dl->dst); size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_DNS_LOOKUP, - true, NX_CTLR_NO_METER, + true, ep->ctrl_meter_id, ofpacts); nx_put_header(ofpacts, dst.field->id, OFP15_VERSION, false); ovs_be32 ofs = htonl(dst.ofs); @@ -3052,13 +3055,13 @@ encode_put_nd_ra_option(const struct ovnact_gen_option *o, static void encode_PUT_ND_RA_OPTS(const struct ovnact_put_opts *po, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { struct mf_subfield dst = expr_resolve_field(&po->dst); size_t oc_offset = encode_start_controller_op( - ACTION_OPCODE_PUT_ND_RA_OPTS, true, NX_CTLR_NO_METER, ofpacts); + ACTION_OPCODE_PUT_ND_RA_OPTS, true, ep->ctrl_meter_id, ofpacts); nx_put_header(ofpacts, dst.field->id, OFP15_VERSION, false); ovs_be32 ofs = htonl(dst.ofs); ofpbuf_put(ofpacts, &ofs, sizeof ofs); @@ -3341,7 +3344,7 @@ format_OVNFIELD_LOAD(const struct ovnact_load *load , struct ds *s) static void encode_OVNFIELD_LOAD(const struct ovnact_load *load, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { const struct ovn_field *f = ovn_field_from_name(load->dst.symbol->name); @@ -3349,7 +3352,7 @@ encode_OVNFIELD_LOAD(const struct ovnact_load *load, case OVN_ICMP4_FRAG_MTU: { size_t oc_offset = encode_start_controller_op( ACTION_OPCODE_PUT_ICMP4_FRAG_MTU, true, - NX_CTLR_NO_METER, ofpacts); + ep->ctrl_meter_id, ofpacts); ofpbuf_put(ofpacts, &load->imm.value.be16_int, sizeof(ovs_be16)); encode_finish_controller_op(oc_offset, ofpacts); break; @@ -3357,7 +3360,7 @@ encode_OVNFIELD_LOAD(const struct ovnact_load *load, case OVN_ICMP6_FRAG_MTU: { size_t oc_offset = encode_start_controller_op( ACTION_OPCODE_PUT_ICMP6_FRAG_MTU, true, - NX_CTLR_NO_METER, ofpacts); + ep->ctrl_meter_id, ofpacts); ofpbuf_put(ofpacts, &load->imm.value.be32_int, sizeof(ovs_be32)); encode_finish_controller_op(oc_offset, ofpacts); break; @@ -3461,7 +3464,7 @@ encode_BIND_VPORT(const struct ovnact_bind_vport *vp, }; encode_setup_args(args, ARRAY_SIZE(args), ofpacts); size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_BIND_VPORT, - false, NX_CTLR_NO_METER, + false, ep->ctrl_meter_id, ofpacts); ovs_be32 vp_key = htonl(vport_key); ofpbuf_put(ofpacts, &vp_key, sizeof(ovs_be32)); @@ -3499,14 +3502,15 @@ format_HANDLE_SVC_CHECK(const struct ovnact_handle_svc_check *svc_chk, static void encode_HANDLE_SVC_CHECK(const struct ovnact_handle_svc_check *svc_chk, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { const struct arg args[] = { { expr_resolve_field(&svc_chk->port), MFF_LOG_INPORT }, }; encode_setup_args(args, ARRAY_SIZE(args), ofpacts); - encode_controller_op(ACTION_OPCODE_HANDLE_SVC_CHECK, ofpacts); + encode_controller_op(ACTION_OPCODE_HANDLE_SVC_CHECK, ep->ctrl_meter_id, + ofpacts); encode_restore_args(args, ARRAY_SIZE(args), ofpacts); } @@ -3755,7 +3759,7 @@ format_PUT_FDB(const struct ovnact_put_fdb *put_fdb, struct ds *s) static void encode_PUT_FDB(const struct ovnact_put_fdb *put_fdb, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { const struct arg args[] = { @@ -3763,7 +3767,7 @@ encode_PUT_FDB(const struct ovnact_put_fdb *put_fdb, { expr_resolve_field(&put_fdb->mac), MFF_ETH_SRC } }; encode_setup_args(args, ARRAY_SIZE(args), ofpacts); - encode_controller_op(ACTION_OPCODE_PUT_FDB, ofpacts); + encode_controller_op(ACTION_OPCODE_PUT_FDB, ep->ctrl_meter_id, ofpacts); encode_restore_args(args, ARRAY_SIZE(args), ofpacts); } diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema index 205a30a37..609699475 100644 --- a/ovn-sb.ovsschema +++ b/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "20.17.0", - "cksum": "669123379 26536", + "version": "20.18.0", + "cksum": "3870294693 26668", "tables": { "SB_Global": { "columns": { @@ -109,6 +109,8 @@ "maxInteger": 65535}}}, "match": {"type": "string"}, "actions": {"type": "string"}, + "controller_meter": {"type": {"key": {"type": "string"}, + "min": 0, "max": 1}}, "external_ids": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, diff --git a/ovn-sb.xml b/ovn-sb.xml index 258a12b4e..57c522db3 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -2441,6 +2441,12 @@ tcp.flags = RST; + + The name of the meter in table to be used for + all packets that the logical flow might send to + ovn-controller. + + Human-readable name for this flow's stage in the pipeline. From patchwork Thu Apr 29 17:04:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1471792 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=2605:bc80:3010::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=afpKZ0as; dkim-atps=neutral Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FWMLX0PtBz9t0G for ; Fri, 30 Apr 2021 03:04:52 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 44D1A41A53; Thu, 29 Apr 2021 17:04:49 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id qMYUMTJLFupw; Thu, 29 Apr 2021 17:04:43 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTP id 1F79C41A0D; Thu, 29 Apr 2021 17:04:42 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 56594C0019; Thu, 29 Apr 2021 17:04:41 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 10F0DC0001 for ; Thu, 29 Apr 2021 17:04:39 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 161FC843A9 for ; Thu, 29 Apr 2021 17:04:38 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp1.osuosl.org (amavisd-new); dkim=pass (1024-bit key) header.d=redhat.com Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ty0Bg48OA167 for ; Thu, 29 Apr 2021 17:04:34 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp1.osuosl.org (Postfix) with ESMTPS id 89DD5842DD for ; Thu, 29 Apr 2021 17:04:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1619715873; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NLJnlxtINX+zgKZR5D9po7Hc1zXfJjtgEwv+GcnkO5E=; b=afpKZ0asn9GXz/MVNcf0Qy9+0NDo9gsDUruOS7FyljctYBVgbnfN1bX3e4NAs3IXmS6Xoa fEvn5gyo3/4f3ymqyIo02749wkfFbLaySRrovWkh6TN6Gmop8jIBuGIF04S+y3YgUHdF7z ZcUk3ZJ+wK0mAXlhsf9E3GnNtFFSMRA= Received: from mail-ej1-f71.google.com (mail-ej1-f71.google.com [209.85.218.71]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-38-1p5beBBIMJeOZY7c5eT1dg-1; Thu, 29 Apr 2021 13:04:30 -0400 X-MC-Unique: 1p5beBBIMJeOZY7c5eT1dg-1 Received: by mail-ej1-f71.google.com with SMTP id h9-20020a1709063c09b0290393e97fec0fso2003286ejg.13 for ; Thu, 29 Apr 2021 10:04:29 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=NLJnlxtINX+zgKZR5D9po7Hc1zXfJjtgEwv+GcnkO5E=; b=fakORbKFIUbhM0Wos0O6qwmYN87QE4KlRUS+jw7dfI33sq9tkb4Rsgf1LsrKYaA9Gs CqdqFflPwrYKba9jvFauvQcPjRpnL2b/REtUX6qE5ZTpkNNnvOxJ/5fvJrBs6Ls40yCn daEF6S/9NIYRdN/ikZdTd7XgGW+515pQhwjyeSbO0aupiSkyJk8ymnE3CTyqGwprE9dj tfm+HNGAiT79fgKGxyPtI7W20j2bsF6j7Qir3m9voiqEBm35CpBB1zdjXRRN7TeaSBOj nnDBkKcp2cKqie2Ce0GKR6Qv7vYNpwlRS9AuMz+JFVlqSxEYKWTaAaV52A/B/UuMiaCf MeEQ== X-Gm-Message-State: AOAM532mMuElfHQ6uo22tKj0L75PRpxKdc+eG2ykk0O8XpeDu6Cj87+S R6Xr/EdAFJdh08Oe41XdbbaCjIJ4iuU+no4K7kB67dKotZsmHWP4JdWs2d+nFT2U88GRRjLNzDP OBNSrYhDKlX0hsW8zlKKEWdMcY6EnciG+y+YU3GP3gv2+2yKqe4PeyYgUR2ehJ+oAuiE0zMHg/v Q= X-Received: by 2002:a17:906:b0cb:: with SMTP id bk11mr923576ejb.310.1619715868107; Thu, 29 Apr 2021 10:04:28 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxs5zsVk0gyGeqSCfOtmiekNbGOCpdXo5PbcVkJi3DmJMUKG7GyypXD1aqfhUgWTWRRvc2eKg== X-Received: by 2002:a17:906:b0cb:: with SMTP id bk11mr923528ejb.310.1619715867611; Thu, 29 Apr 2021 10:04:27 -0700 (PDT) Received: from lore-desk.redhat.com ([151.66.28.185]) by smtp.gmail.com with ESMTPSA id re26sm299250ejb.3.2021.04.29.10.04.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Apr 2021 10:04:27 -0700 (PDT) From: Lorenzo Bianconi To: dev@openvswitch.org Date: Thu, 29 Apr 2021 19:04:15 +0200 Message-Id: X-Mailer: git-send-email 2.30.2 In-Reply-To: References: MIME-Version: 1.0 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=lorenzo.bianconi@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Cc: dceara@redhat.com Subject: [ovs-dev] [PATCH ovn 2/5] ovn-northd: Add support for CoPP. 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: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Dumitru Ceara Add new 'Copp' (Control plane protection) table to OVN Northbound DB: - this stores mappings between control plane protocol names and meters that should be used to rate limit controller-destined traffic for those protocols. Add new 'copp' columns to the following OVN Northbound DB tables: - Logical_Switch - Logical_Router For now, no control plane protection policy is installed for any of the existing flows that punt packets to ovn-controller. This will be added in follow-up patches. Add CLI commands in 'ovn-nbctl' to allow the user to manage Control Plane Protection Policies at different levels (logical switch, logical router). Co-authored-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Dumitru Ceara --- lib/automake.mk | 2 + lib/copp.c | 144 ++++++++++++++++++++++++++++++++ lib/copp.h | 60 ++++++++++++++ northd/ovn-northd.c | 44 +++++++--- ovn-nb.ovsschema | 18 +++- ovn-nb.xml | 78 ++++++++++++++++++ tests/ovn-northd.at | 49 +++++++++++ utilities/ovn-nbctl.8.xml | 116 ++++++++++++++++++++++++++ utilities/ovn-nbctl.c | 167 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 665 insertions(+), 13 deletions(-) create mode 100644 lib/copp.c create mode 100644 lib/copp.h diff --git a/lib/automake.mk b/lib/automake.mk index 781be2109..20e296fff 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -9,6 +9,8 @@ lib_libovn_la_SOURCES = \ lib/actions.c \ lib/chassis-index.c \ lib/chassis-index.h \ + lib/copp.c \ + lib/copp.h \ lib/ovn-dirs.h \ lib/expr.c \ lib/extend-table.h \ diff --git a/lib/copp.c b/lib/copp.c new file mode 100644 index 000000000..ac53a1094 --- /dev/null +++ b/lib/copp.c @@ -0,0 +1,144 @@ +/* Copyright (c) 2021, Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "openvswitch/shash.h" +#include "db-ctl-base.h" +#include "smap.h" +#include "lib/ovn-nb-idl.h" +#include "lib/copp.h" + +static char *copp_proto_names[COPP_PROTO_MAX] = { + [COPP_ARP] = "arp", + [COPP_ARP_RESOLVE] = "arp-resolve", + [COPP_DHCPV4_OPTS] = "dhcpv4-opts", + [COPP_DHCPV6_OPTS] = "dhcpv6-opts", + [COPP_DNS] = "dns", + [COPP_EVENT_ELB] = "event-elb", + [COPP_ICMP4_ERR] = "icmp4-error", + [COPP_ICMP6_ERR] = "icmp6-error", + [COPP_IGMP] = "igmp", + [COPP_ND_NA] = "nd-na", + [COPP_ND_NS] = "nd-ns", + [COPP_ND_NS_RESOLVE] = "nd-ns-resolve", + [COPP_ND_RA_OPTS] = "nd-ra-opts", + [COPP_TCP_RESET] = "tcp-reset", + [COPP_BFD] = "bfd", +}; + +const char * +copp_proto_get(enum copp_proto proto) +{ + if (proto >= COPP_PROTO_MAX) { + return ""; + } + return copp_proto_names[proto]; +} + +const char * +copp_meter_get(enum copp_proto proto, const struct nbrec_copp *copp, + const struct shash *meter_groups) +{ + if (!copp || proto >= COPP_PROTO_MAX) { + return NULL; + } + + const char *meter = smap_get(&copp->meters, copp_proto_names[proto]); + + if (meter && shash_find(meter_groups, meter)) { + return meter; + } + + return NULL; +} + +void +copp_list(struct ctl_context *ctx, const struct nbrec_copp *copp) +{ + if (!copp) { + return; + } + + struct smap_node *node; + + SMAP_FOR_EACH (node, &copp->meters) { + ds_put_format(&ctx->output, "%s: %s\n", node->key, node->value); + } +} + +const struct nbrec_copp * +copp_add_meter(struct ctl_context *ctx, const struct nbrec_copp *copp, + const char *proto_name, const char *meter) +{ + if (!copp) { + copp = nbrec_copp_insert(ctx->txn); + } + + struct smap meters; + smap_init(&meters); + smap_clone(&meters, &copp->meters); + smap_replace(&meters, proto_name, meter); + nbrec_copp_set_meters(copp, &meters); + smap_destroy(&meters); + + return copp; +} + +void +copp_del_meter(const struct nbrec_copp *copp, const char *proto_name) +{ + if (!copp) { + return; + } + + if (proto_name) { + if (smap_get(&copp->meters, proto_name)) { + struct smap meters; + smap_init(&meters); + smap_clone(&meters, &copp->meters); + smap_remove(&meters, proto_name); + nbrec_copp_set_meters(copp, &meters); + smap_destroy(&meters); + } + } else { + nbrec_copp_delete(copp); + } +} + +char * +copp_proto_validate(const char *proto_name) +{ + for (size_t i = COPP_PROTO_FIRST; i < COPP_PROTO_MAX; i++) { + if (!strcmp(proto_name, copp_proto_get(i))) { + return NULL; + } + } + + struct ds usage = DS_EMPTY_INITIALIZER; + + ds_put_cstr(&usage, "Invalid control protocol. Allowed values: "); + for (size_t i = COPP_PROTO_FIRST; i < COPP_PROTO_MAX; i++) { + ds_put_format(&usage, "%s, ", copp_proto_get(i)); + } + ds_chomp(&usage, ' '); + ds_chomp(&usage, ','); + ds_put_cstr(&usage, "."); + + char *usage_str = xstrdup(ds_cstr(&usage)); + ds_destroy(&usage); + return usage_str; +} diff --git a/lib/copp.h b/lib/copp.h new file mode 100644 index 000000000..82581e7e4 --- /dev/null +++ b/lib/copp.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2021, Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OVN_COPP_H +#define OVN_COPP_H 1 + +/* + * Control plane protection - metered actions. + */ +enum copp_proto { + COPP_PROTO_FIRST, + COPP_ARP = COPP_PROTO_FIRST, + COPP_ARP_RESOLVE, + COPP_DHCPV4_OPTS, + COPP_DHCPV6_OPTS, + COPP_DNS, + COPP_EVENT_ELB, + COPP_ICMP4_ERR, + COPP_ICMP6_ERR, + COPP_IGMP, + COPP_ND_NA, + COPP_ND_NS, + COPP_ND_NS_RESOLVE, + COPP_ND_RA_OPTS, + COPP_TCP_RESET, + COPP_BFD, + COPP_PROTO_MAX, + COPP_PROTO_INVALID = COPP_PROTO_MAX, +}; + +struct nbrec_copp; +struct ctl_context; + +const char *copp_proto_get(enum copp_proto); + +const char *copp_meter_get(enum copp_proto proto, + const struct nbrec_copp *copp, + const struct shash *meter_groups); + +void copp_list(struct ctl_context *ctx, const struct nbrec_copp *copp); +const struct nbrec_copp * +copp_add_meter(struct ctl_context *ctx, const struct nbrec_copp *copp, + const char *proto_name, const char *meter); +void +copp_del_meter(const struct nbrec_copp *copp, const char *proto_name); +char * copp_proto_validate(const char *proto_name); + +#endif /* lib/copp.h */ diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 94fae5648..2e9c7de22 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -32,6 +32,7 @@ #include "ovn/lex.h" #include "lib/chassis-index.h" #include "lib/ip-mcast-index.h" +#include "lib/copp.h" #include "lib/mcast-group-index.h" #include "lib/ovn-l7.h" #include "lib/ovn-nb-idl.h" @@ -4018,6 +4019,7 @@ struct ovn_lflow { char *match; char *actions; char *stage_hint; + char *ctrl_meter; const char *where; }; @@ -4051,14 +4053,15 @@ ovn_lflow_equal(const struct ovn_lflow *a, const struct ovn_lflow *b) && a->stage == b->stage && a->priority == b->priority && !strcmp(a->match, b->match) - && !strcmp(a->actions, b->actions)); + && !strcmp(a->actions, b->actions) + && nullable_string_is_equal(a->ctrl_meter, b->ctrl_meter)); } static void ovn_lflow_init(struct ovn_lflow *lflow, struct ovn_datapath *od, enum ovn_stage stage, uint16_t priority, - char *match, char *actions, char *stage_hint, - const char *where) + char *match, char *actions, char *ctrl_meter, + char *stage_hint, const char *where) { hmapx_init(&lflow->od_group); lflow->od = od; @@ -4067,6 +4070,7 @@ ovn_lflow_init(struct ovn_lflow *lflow, struct ovn_datapath *od, lflow->match = match; lflow->actions = actions; lflow->stage_hint = stage_hint; + lflow->ctrl_meter = ctrl_meter; lflow->where = where; } @@ -4107,6 +4111,7 @@ static void ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od, enum ovn_stage stage, uint16_t priority, const char *match, const char *actions, bool shared, + const char *ctrl_meter, const struct ovsdb_idl_row *stage_hint, const char *where) { ovs_assert(ovn_stage_to_datapath_type(stage) == ovn_datapath_get_type(od)); @@ -4120,6 +4125,7 @@ ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od, * one datapath in a group, so it could be hashed correctly. */ ovn_lflow_init(lflow, NULL, stage, priority, xstrdup(match), xstrdup(actions), + nullable_xstrdup(ctrl_meter), ovn_lflow_hint(stage_hint), where); hash = ovn_lflow_hash(lflow); @@ -4134,14 +4140,24 @@ ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od, } /* Adds a row with the specified contents to the Logical_Flow table. */ +#define ovn_lflow_add_with_hint__(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \ + ACTIONS, CTRL_METER, STAGE_HINT) \ + ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, true, \ + CTRL_METER, STAGE_HINT, OVS_SOURCE_LOCATOR) + #define ovn_lflow_add_with_hint(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \ ACTIONS, STAGE_HINT) \ - ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, true, \ - STAGE_HINT, OVS_SOURCE_LOCATOR) + ovn_lflow_add_with_hint__(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \ + ACTIONS, NULL, STAGE_HINT) #define ovn_lflow_add(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS) \ ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, true, \ - NULL, OVS_SOURCE_LOCATOR) + NULL, NULL, OVS_SOURCE_LOCATOR) + +#define ovn_lflow_add_ctrl(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, \ + CTRL_METER) \ + ovn_lflow_add_with_hint__(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \ + ACTIONS, CTRL_METER, NULL) /* Adds a row with the specified contents to the Logical_Flow table. * Combining of this logical flow with already existing ones, e.g., by using @@ -4156,21 +4172,22 @@ ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od, #define ovn_lflow_add_unique_with_hint(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \ ACTIONS, STAGE_HINT) \ ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, false, \ - STAGE_HINT, OVS_SOURCE_LOCATOR) + NULL, STAGE_HINT, OVS_SOURCE_LOCATOR) #define ovn_lflow_add_unique(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS) \ ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, false, \ - NULL, OVS_SOURCE_LOCATOR) + NULL, NULL, OVS_SOURCE_LOCATOR) static struct ovn_lflow * ovn_lflow_find(struct hmap *lflows, struct ovn_datapath *od, enum ovn_stage stage, uint16_t priority, - const char *match, const char *actions, uint32_t hash) + const char *match, const char *actions, const char *ctrl_meter, + uint32_t hash) { struct ovn_lflow target; ovn_lflow_init(&target, od, stage, priority, CONST_CAST(char *, match), CONST_CAST(char *, actions), - NULL, NULL); + CONST_CAST(char *, ctrl_meter), NULL, NULL); return ovn_lflow_find_by_lflow(lflows, &target, hash); } @@ -4186,6 +4203,7 @@ ovn_lflow_destroy(struct hmap *lflows, struct ovn_lflow *lflow) free(lflow->match); free(lflow->actions); free(lflow->stage_hint); + free(lflow->ctrl_meter); free(lflow); } } @@ -12333,7 +12351,8 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths, lflow = ovn_lflow_find( &lflows, logical_datapath_od, ovn_stage_build(dp_type, pipeline, sbflow->table_id), - sbflow->priority, sbflow->match, sbflow->actions, sbflow->hash); + sbflow->priority, sbflow->match, sbflow->actions, + sbflow->controller_meter, sbflow->hash); if (lflow) { /* This is a valid lflow. Checking if the datapath group needs * updates. */ @@ -12378,6 +12397,7 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths, sbrec_logical_flow_set_priority(sbflow, lflow->priority); sbrec_logical_flow_set_match(sbflow, lflow->match); sbrec_logical_flow_set_actions(sbflow, lflow->actions); + sbrec_logical_flow_set_controller_meter(sbflow, lflow->ctrl_meter); /* Trim the source locator lflow->where, which looks something like * "ovn/northd/ovn-northd.c:1234", down to just the part following the @@ -14082,6 +14102,8 @@ main(int argc, char *argv[]) add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_priority); add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_match); add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_actions); + add_column_noalert(ovnsb_idl_loop.idl, + &sbrec_logical_flow_col_controller_meter); ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_logical_dp_group); diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema index 29019809c..fb0f3a7c0 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "5.31.0", - "cksum": "2352750632 28701", + "version": "5.32.0", + "cksum": "2317195278 29378", "tables": { "NB_Global": { "columns": { @@ -30,6 +30,14 @@ "ipsec": {"type": "boolean"}}, "maxRows": 1, "isRoot": true}, + "Copp": { + "columns": { + "meters": { + "type": {"key": "string", + "value": "string", + "min": 0, + "max": "unlimited"}}}, + "isRoot": true}, "Logical_Switch": { "columns": { "name": {"type": "string"}, @@ -58,6 +66,9 @@ "refType": "weak"}, "min": 0, "max": "unlimited"}}, + "copp": {"type": {"key": {"type": "uuid", "refTable": "Copp", + "refType": "weak"}, + "min": 0, "max": 1}}, "other_config": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}, @@ -319,6 +330,9 @@ "refType": "weak"}, "min": 0, "max": "unlimited"}}, + "copp": {"type": {"key": {"type": "uuid", "refTable": "Copp", + "refType": "weak"}, + "min": 0, "max": 1}}, "options": { "type": {"key": "string", "value": "string", diff --git a/ovn-nb.xml b/ovn-nb.xml index feb38b5d3..0f03a12f2 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -339,6 +339,68 @@ + +

+ This table is used to define control plane protection policies, i.e., + associate entries from table to control protocol + names. +

+ + Rate limiting meter for ARP packets (request/reply) used for learning + neighbors. + + + Rate limiting meter for packets that require resolving the next-hop + (through ARP). + + + Rate limiting meter for packets that require adding DHCPv4 options. + + + Rate limiting meter for packets that require adding DHCPv6 options. + + + Rate limiting meter for DNS query packets that need to be replied to. + + + Rate limiting meter for empty load balancer events. + + + Rate limiting meter for packets that require replying with an ICMP + error. + + + Rate limiting meter for packets that require replying with an ICMPv6 + error. + + + Rate limiting meter for IGMP packets. + + + Rate limiting meter for ND neighbor advertisement packets used for + learning neighbors. + + + Rate limiting meter for ND neighbor solicitation packets used for + learning neighbors. + + + Rate limiting meter for packets that require resolving the next-hop + (through ND). + + + Rate limiting meter for packets that require adding ND router + advertisement options. + + + Rate limiting meter for packets that require replying with TCP RST + packet. + + + Rate limiting meter for BFD packets. + +
+

Each row represents one L2 logical switch. @@ -572,6 +634,14 @@ + +

+ The control plane protection policy from table + used for metering packets sent to ovn-controller from + ports of this logical switch. +

+ + @@ -1929,6 +1999,14 @@ + +

+ The control plane protection policy from table + used for metering packets sent to ovn-controller from + logical ports of this router. +

+
+

Additional options for the logical router. diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 32afb4fa8..7c18e6302 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -2649,6 +2649,55 @@ wait_row_count bfd 3 AT_CLEANUP ]) +OVN_FOR_EACH_NORTHD([ +AT_SETUP([ovn -- check CoPP config]) +AT_KEYWORDS([northd-CoPP]) +ovn_start + +check ovn-nbctl --wait=sb lr-add r0 +check ovn-nbctl --wait=sb lrp-add r0 r0-sw1 00:00:00:00:00:01 192.168.1.1/24 +check ovn-nbctl --wait=sb ls-add sw1 +check ovn-nbctl --wait=sb lsp-add sw1 sw1-r0 +check ovn-nbctl --wait=sb lsp-set-type sw1-r0 router +check ovn-nbctl --wait=sb lsp-set-options sw1-r0 router-port=r0-sw1 +check ovn-nbctl --wait=sb lsp-set-addresses sw1-r0 00:00:00:00:00:01 + +ovn-nbctl --wait=hv meter-add meter0 drop 100 pktps 10 +ovn-nbctl --wait=hv ls-copp-add sw1 event-elb meter0 +AT_CHECK([ovn-nbctl ls-copp-list sw1], [0], [dnl +event-elb: meter0 +]) + +ovn-nbctl --wait=hv meter-add meter1 drop 200 pktps 10 +ovn-nbctl --wait=hv ls-copp-add sw1 arp meter1 +AT_CHECK([ovn-nbctl ls-copp-list sw1], [0], [dnl +arp: meter1 +event-elb: meter0 +]) + +ovn-nbctl --wait=hv ls-copp-del sw1 arp +AT_CHECK([ovn-nbctl ls-copp-list sw1], [0], [dnl +event-elb: meter0 +]) + +ovn-nbctl --wait=hv ls-copp-del sw1 event-elb +AT_CHECK([ovn-nbctl ls-copp-list sw1], [0], [dnl +]) + +ovn-nbctl --wait=hv lr-copp-add r0 bfd meter0 +AT_CHECK([ovn-nbctl lr-copp-list r0], [0], [dnl +bfd: meter0 +]) + +ovn-nbctl --wait=hv lr-copp-add r0 igmp meter1 +AT_CHECK([ovn-nbctl lr-copp-list r0], [0], [dnl +bfd: meter0 +igmp: meter1 +]) + +AT_CLEANUP +]) + AT_SETUP([ovn -- check LSP attached to multiple LS]) ovn_start diff --git a/utilities/ovn-nbctl.8.xml b/utilities/ovn-nbctl.8.xml index 03d47dba5..6c95e8104 100644 --- a/utilities/ovn-nbctl.8.xml +++ b/utilities/ovn-nbctl.8.xml @@ -1131,6 +1131,122 @@ +

Control Plane Protection Policy commands

+

+ These commands manages meters contained in table + linking them to logical datapaths through copp column in + or tables. + Protocol packets for which CoPP is enforced when sending packets to + ovn-controller (if configured): +

    +
  • ARP
  • +
  • ND_NS
  • +
  • ND_NA
  • +
  • ND_RA
  • +
  • ND
  • +
  • DNS
  • +
  • IGMP
  • +
  • packets that require ARP resolution before forwarding
  • +
  • packets that require ND_NS before forwarding
  • +
  • packets that need to be replied to with ICMP Errors
  • +
  • packets that need to be replied to with TCP RST
  • +
  • packets that need to be replied to with DHCP_OPTS
  • +
  • BFD
  • +
+

+ +
+
ls-copp-add switch proto + meter
+
+ Adds the control proto to meter mapping + to the switch control plane protection policy. If no + policy exists yet, it creates one. If a mapping already existed for + proto, this will overwrite it. +
+ +
ls-copp-del switch [proto]
+
+ Removes the control proto mapping from the + switch control plane protection policy. If + proto is not specified, the whole control plane + protection policy is destroyed. +
+ +
ls-copp-list switch
+
+ Display the current control plane protection policy for + switch. +
+ +
lsp-copp-add proto proto + meter
+
+ Adds the control proto to meter mapping + to the port control plane protection policy. If no + policy exists yet, it creates one. If a mapping already existed for + proto, this will overwrite it. +
+ +
lsp-copp-del port [proto]
+
+ Removes the control proto mapping from the + port control plane protection policy. If + proto is not specified, the whole control plane + protection policy is destroyed. +
+
lsp-copp-list port
+
+ Display the current control plane protection policy for + port. +
+ +
lr-copp-add router proto + meter
+
+ Adds the control proto to meter mapping + to the router control plane protection policy. If no + policy exists yet, it creates one. If a mapping already existed for + proto, this will overwrite it. +
+ +
lr-copp-del router [proto]
+
+ Removes the control proto mapping from the + router control plane protection policy. If + proto is not specified, the whole control plane + protection policy is destroyed. +
+ +
lr-copp-list router
+
+ Display the current control plane protection policy for + router. +
+ +
lrp-copp-add proto proto + meter
+
+ Adds the control proto to meter mapping + to the port control plane protection policy. If no + policy exists yet, it creates one. If a mapping already existed for + proto, this will overwrite it. +
+ +
lrp-copp-del port [proto]
+
+ Removes the control proto mapping from the + port control plane protection policy. If + proto is not specified, the whole control plane + protection policy is destroyed. +
+
lrp-copp-list port
+
+ Display the current control plane protection policy for + port. +
+
+

Database Commands

These commands query and modify the contents of ovsdb tables. They are a slight abstraction of the ovsdb interface and diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c index 042c21002..2299bc6ce 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -27,6 +27,7 @@ #include "jsonrpc.h" #include "openvswitch/json.h" #include "lib/acl-log.h" +#include "lib/copp.h" #include "lib/ovn-nb-idl.h" #include "lib/ovn-util.h" #include "memory.h" @@ -835,6 +836,28 @@ chassis with optional PRIORITY to the HA chassis group GRP\n\ ha-chassis-group-remove-chassis GRP CHASSIS Removes the HA chassis\ CHASSIS from the HA chassis group GRP\n\ \n\ +Control Plane Protection Policy commands:\n\ + ls-copp-add SWITCH PROTO METER\n\ + Add a copp policy for PROTO packets on SWITCH\n\ + based on an existing METER.\n\ + ls-copp-del SWITCH [PROTO]\n\ + Delete the copp policy for PROTO packets on\n\ + SWITCH. If PROTO is not specified, delete all\n\ + copp policies on SWITCH.\n\ + ls-copp-list SWITCH\n\ + List all copp policies defined for control\n\ + protocols on SWITCH.\n\ + lr-copp-add ROUTER PROTO METER\n\ + Add a copp policy for PROTO packets on ROUTER\n\ + based on an existing METER.\n\ + lr-copp-del ROUTER [PROTO]\n\ + Delete the copp policy for PROTO packets on\n\ + ROUTER. If PROTO is not specified, delete all\n\ + copp policies on ROUTER.\n\ + lr-copp-list ROUTER\n\ + List all copp policies defined for control\n\ + protocols on ROUTER.\n\ +\n\ %s\ %s\ \n\ @@ -5711,6 +5734,138 @@ nbctl_lr_route_list(struct ctl_context *ctx) free(ipv6_routes); } +static void +nbctl_ls_copp_add(struct ctl_context *ctx) +{ + const char *ls_name = ctx->argv[1]; + const char *proto_name = ctx->argv[2]; + const char *meter = ctx->argv[3]; + + char *error = copp_proto_validate(proto_name); + if (error) { + ctx->error = error; + return; + } + + const struct nbrec_logical_switch *ls = NULL; + error = ls_by_name_or_uuid(ctx, ls_name, true, &ls); + if (error) { + ctx->error = error; + return; + } + + const struct nbrec_copp *copp = + copp_add_meter(ctx, ls->copp, proto_name, meter); + nbrec_logical_switch_set_copp(ls, copp); +} + +static void +nbctl_ls_copp_del(struct ctl_context *ctx) +{ + const char *ls_name = ctx->argv[1]; + const char *proto_name = NULL; + char *error; + + if (ctx->argc == 3) { + proto_name = ctx->argv[2]; + error = copp_proto_validate(proto_name); + if (error) { + ctx->error = error; + return; + } + } + + const struct nbrec_logical_switch *ls = NULL; + error = ls_by_name_or_uuid(ctx, ls_name, true, &ls); + if (error) { + ctx->error = error; + return; + } + + copp_del_meter(ls->copp, proto_name); +} + +static void +nbctl_ls_copp_list(struct ctl_context *ctx) +{ + const char *ls_name = ctx->argv[1]; + + const struct nbrec_logical_switch *ls = NULL; + char *error = ls_by_name_or_uuid(ctx, ls_name, true, &ls); + if (error) { + ctx->error = error; + return; + } + + copp_list(ctx, ls->copp); +} + +static void +nbctl_lr_copp_add(struct ctl_context *ctx) +{ + const char *lr_name = ctx->argv[1]; + const char *proto_name = ctx->argv[2]; + const char *meter = ctx->argv[3]; + + char *error = copp_proto_validate(proto_name); + if (error) { + ctx->error = error; + return; + } + + const struct nbrec_logical_router *lr = NULL; + error = lr_by_name_or_uuid(ctx, lr_name, true, &lr); + if (error) { + ctx->error = error; + return; + } + + const struct nbrec_copp *copp = + copp_add_meter(ctx, lr->copp, proto_name, meter); + nbrec_logical_router_set_copp(lr, copp); +} + +static void +nbctl_lr_copp_del(struct ctl_context *ctx) +{ + const char *lr_name = ctx->argv[1]; + const char *proto_name = NULL; + char *error; + + if (ctx->argc == 3) { + proto_name = ctx->argv[2]; + error = copp_proto_validate(proto_name); + if (error) { + ctx->error = error; + return; + } + } + + const struct nbrec_logical_router *lr = NULL; + error = lr_by_name_or_uuid(ctx, lr_name, true, &lr); + if (error) { + ctx->error = error; + return; + } + + copp_del_meter(lr->copp, proto_name); +} + +static void +nbctl_lr_copp_list(struct ctl_context *ctx) +{ + const char *lr_name = ctx->argv[1]; + + const struct nbrec_logical_router *lr = NULL; + char *error = lr_by_name_or_uuid(ctx, lr_name, true, &lr); + if (error) { + ctx->error = error; + return; + } + + copp_list(ctx, lr->copp); +} + static void verify_connections(struct ctl_context *ctx) { @@ -6673,6 +6828,18 @@ static const struct ctl_command_syntax nbctl_commands[] = { {"dhcp-options-get-options", 1, 1, "DHCP_OPT_UUID", NULL, nbctl_dhcp_options_get_options, NULL, "", RO }, + /* Control plane protection commands */ + {"ls-copp-add", 3, 3, "SWITCH PROTO METER", NULL, nbctl_ls_copp_add, NULL, + "", RW}, + {"ls-copp-del", 1, 2, "SWITCH [PROTO]", NULL, nbctl_ls_copp_del, NULL, + "", RW}, + {"ls-copp-list", 1, 1, "SWITCH", NULL, nbctl_ls_copp_list, NULL, "", RO}, + {"lr-copp-add", 3, 3, "ROUTER PROTO METER", NULL, nbctl_lr_copp_add, NULL, + "", RW}, + {"lr-copp-del", 1, 2, "ROUTER [PROTO]", NULL, nbctl_lr_copp_del, NULL, + "", RW}, + {"lr-copp-list", 1, 1, "ROUTER", NULL, nbctl_lr_copp_list, NULL, "", RO}, + /* Connection commands. */ {"get-connection", 0, 0, "", pre_connection, cmd_get_connection, NULL, "", RO}, {"del-connection", 0, 0, "", pre_connection, cmd_del_connection, NULL, "", RW}, From patchwork Thu Apr 29 17:04:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1471794 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=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=MqkFEnTR; dkim-atps=neutral Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FWMLd4hjrz9t0G for ; Fri, 30 Apr 2021 03:04:57 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 50C636F74E; Thu, 29 Apr 2021 17:04:55 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id kwu_TI1lVjjN; Thu, 29 Apr 2021 17:04:49 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTP id 925A86F73D; Thu, 29 Apr 2021 17:04:47 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id DD15BC0034; Thu, 29 Apr 2021 17:04:44 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1126EC0019 for ; Thu, 29 Apr 2021 17:04:41 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id A83EF6F721 for ; Thu, 29 Apr 2021 17:04:38 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id gJU6X362r5ZJ for ; Thu, 29 Apr 2021 17:04:36 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp3.osuosl.org (Postfix) with ESMTPS id 14C446F718 for ; Thu, 29 Apr 2021 17:04:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1619715875; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=1xJ1HpTHue7MtGdGH3vX0PX9fQKC06SvzLmI1yRvZAY=; b=MqkFEnTR3LL/Ys95SK6Y0JNaDB2FTf1rS/XPjpBF2vm4Efncnw6p3D05m2BOeVBSCcogb0 3f6f4bQravB+cwHh2/WxVwM0jQJXQTs+6xp+0BBkzjeftZ7vSfYeSyi+ryZCApiWM0i8R5 ugeDlu6zDb2QRxuFbupqdkzPUjAN1s4= Received: from mail-ej1-f72.google.com (mail-ej1-f72.google.com [209.85.218.72]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-448-mHJsx7j3Moe-5H04vbVNfg-1; Thu, 29 Apr 2021 13:04:32 -0400 X-MC-Unique: mHJsx7j3Moe-5H04vbVNfg-1 Received: by mail-ej1-f72.google.com with SMTP id ne22-20020a1709077b96b02903803a047edeso12416412ejc.3 for ; Thu, 29 Apr 2021 10:04:32 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=1xJ1HpTHue7MtGdGH3vX0PX9fQKC06SvzLmI1yRvZAY=; b=BsCN2nVk20cuvGKg43LezBcRvanhdVfgZVdwf5Nc8WY07sL/eiYfAsnGESWueDBDLH qmtKweUNovDD6iIYYvnL3Hq+4pgeDXy0LbLcqQIKxkj0kiWz42Y5WX8TCrnajEpgRMSB Z9yB0aVOAsDBRJLChg67aXCoWDbbbhYS2mOp+Op4sS2pcNWF6JCsoch6XP8dEmnOpIcd Z4X9qpfHLkehYObJyKEMqQoLu0aPQn6SMu1Yy9f439M6hqZoWDqYq7Z/rem6SO3rR4ql o27Y+ZJj3so4O1OZBcuINhgIHHwwmHzo0h7deGRuOUF7HfHNr7zmmuY4fsvUGR4eOmFr kwtQ== X-Gm-Message-State: AOAM531bbtqsYmPU5YGh60LHg4Y2AMa76gLT+Jw9SMwx/GyB6BesnKdW BjHdpNOwcW+85jkfKaFXOr88ryB8qGAx9/tYf8sYAFHGOyLUWoVDYqRLmV9o7NJo9UgLEF7glCz 4JyA8qZNbVT+VlE28wFlz27OkZwzfe0m8/+qGiSh1dt7xWb0hRP3NjSyA7QSaS0Wr4Nl7Wja1b7 E= X-Received: by 2002:a05:6402:3090:: with SMTP id de16mr663322edb.177.1619715870135; Thu, 29 Apr 2021 10:04:30 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwLBNPntLJoLg8N06s8qb7wluBNbQUrH37uZYRcCpdbK8lVNukwQF8HQ/tKqTQAEs1Yx/6+Jg== X-Received: by 2002:a05:6402:3090:: with SMTP id de16mr663268edb.177.1619715869621; Thu, 29 Apr 2021 10:04:29 -0700 (PDT) Received: from lore-desk.redhat.com ([151.66.28.185]) by smtp.gmail.com with ESMTPSA id re26sm299250ejb.3.2021.04.29.10.04.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Apr 2021 10:04:29 -0700 (PDT) From: Lorenzo Bianconi To: dev@openvswitch.org Date: Thu, 29 Apr 2021 19:04:16 +0200 Message-Id: X-Mailer: git-send-email 2.30.2 In-Reply-To: References: MIME-Version: 1.0 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=lorenzo.bianconi@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Cc: dceara@redhat.com Subject: [ovs-dev] [PATCH ovn 3/5] ovn-northd: Add CoPP policies for flows that punt packets to ovn-controller. 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: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Dumitru Ceara Change the ovn-northd implementation to set the new 'controller_meter' field for flows that need to punt packets to ovn-controller. Protocol packets for which CoPP is enforced when sending packets to ovn-controller (if configured): - ARP - ND_NS - ND_NA - ND_RA - DNS - IGMP - packets that require ARP resolution before forwarding - packets that require ND_NS before forwarding - packets that need to be replied to with ICMP Errors - packets that need to be replied to with TCP RST - packets that need to be replied to with DHCP_OPTS - BFD Co-authored-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Dumitru Ceara --- lib/copp.c | 1 + lib/copp.h | 1 + northd/ovn-northd.c | 451 ++++++++++++++++++++++++-------------- ovn-nb.xml | 3 + tests/atlocal.in | 3 + tests/system-ovn.at | 119 ++++++++++ utilities/ovn-nbctl.8.xml | 1 + 7 files changed, 417 insertions(+), 162 deletions(-) diff --git a/lib/copp.c b/lib/copp.c index ac53a1094..7713046e5 100644 --- a/lib/copp.c +++ b/lib/copp.c @@ -37,6 +37,7 @@ static char *copp_proto_names[COPP_PROTO_MAX] = { [COPP_ND_NS_RESOLVE] = "nd-ns-resolve", [COPP_ND_RA_OPTS] = "nd-ra-opts", [COPP_TCP_RESET] = "tcp-reset", + [COPP_REJECT] = "reject", [COPP_BFD] = "bfd", }; diff --git a/lib/copp.h b/lib/copp.h index 82581e7e4..826fe987e 100644 --- a/lib/copp.h +++ b/lib/copp.h @@ -36,6 +36,7 @@ enum copp_proto { COPP_ND_RA_OPTS, COPP_TCP_RESET, COPP_BFD, + COPP_REJECT, COPP_PROTO_MAX, COPP_PROTO_INVALID = COPP_PROTO_MAX, }; diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 2e9c7de22..93b431f4c 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -3328,11 +3328,11 @@ ovn_lb_svc_create(struct northd_context *ctx, struct ovn_northd_lb *lb, } } -static -void build_lb_vip_actions(struct ovn_lb_vip *lb_vip, - struct ovn_northd_lb_vip *lb_vip_nb, - struct ds *action, char *selection_fields, - bool ls_dp) +static bool +build_lb_vip_actions(struct ovn_lb_vip *lb_vip, + struct ovn_northd_lb_vip *lb_vip_nb, + struct ds *action, char *selection_fields, + bool ls_dp) { bool skip_hash_fields = false, reject = false; @@ -3384,6 +3384,7 @@ void build_lb_vip_actions(struct ovn_lb_vip *lb_vip, ds_chomp(action, ')'); ds_put_format(action, "; hash_fields=\"%s\");", selection_fields); } + return reject; } static void @@ -4174,9 +4175,14 @@ ovn_lflow_add_at(struct hmap *lflow_map, struct ovn_datapath *od, ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, false, \ NULL, STAGE_HINT, OVS_SOURCE_LOCATOR) -#define ovn_lflow_add_unique(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS) \ +#define ovn_lflow_add_unique__(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, \ + ACTIONS, CTRL_METER) \ ovn_lflow_add_at(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, false, \ - NULL, NULL, OVS_SOURCE_LOCATOR) + CTRL_METER, NULL, OVS_SOURCE_LOCATOR) + +#define ovn_lflow_add_unique(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS) \ + ovn_lflow_add_unique__(LFLOW_MAP, OD, STAGE, PRIORITY, MATCH, ACTIONS, \ + NULL) static struct ovn_lflow * ovn_lflow_find(struct hmap *lflows, struct ovn_datapath *od, @@ -5429,9 +5435,12 @@ build_reject_acl_rules(struct ovn_datapath *od, struct hmap *lflows, "reject { " "/* eth.dst <-> eth.src; ip.dst <-> ip.src; is implicit. */ " "outport <-> inport; %s };", next_action); - ovn_lflow_add_with_hint(lflows, od, stage, - acl->priority + OVN_ACL_PRI_OFFSET, - ds_cstr(&match), ds_cstr(&actions), stage_hint); + ovn_lflow_add_with_hint__(lflows, od, stage, + acl->priority + OVN_ACL_PRI_OFFSET, + ds_cstr(&match), ds_cstr(&actions), + copp_meter_get(COPP_REJECT, od->nbs->copp, + meter_groups), + stage_hint); free(next_action); ds_destroy(&match); @@ -5938,7 +5947,7 @@ build_lb(struct ovn_datapath *od, struct hmap *lflows) static void build_lb_rules(struct ovn_datapath *od, struct hmap *lflows, - struct ovn_northd_lb *lb) + struct ovn_northd_lb *lb, struct shash *meter_groups) { for (size_t i = 0; i < lb->n_vips; i++) { struct ovn_lb_vip *lb_vip = &lb->vips[i]; @@ -5979,21 +5988,25 @@ build_lb_rules(struct ovn_datapath *od, struct hmap *lflows, } /* New connections in Ingress table. */ - build_lb_vip_actions(lb_vip, lb_vip_nb, &action, - lb->selection_fields, true); + const char *meter = NULL; + bool reject = build_lb_vip_actions(lb_vip, lb_vip_nb, &action, + lb->selection_fields, true); + if (reject) { + meter = copp_meter_get(COPP_REJECT, od->nbs->copp, meter_groups); + } struct ds match = DS_EMPTY_INITIALIZER; ds_put_format(&match, "ct.new && %s.dst == %s", ip_match, lb_vip->vip_str); if (lb_vip->vip_port) { ds_put_format(&match, " && %s.dst == %d", proto, lb_vip->vip_port); - ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_STATEFUL, 120, - ds_cstr(&match), ds_cstr(&action), - &lb->nlb->header_); + ovn_lflow_add_with_hint__(lflows, od, S_SWITCH_IN_STATEFUL, 120, + ds_cstr(&match), ds_cstr(&action), + meter, &lb->nlb->header_); } else { - ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_STATEFUL, 110, - ds_cstr(&match), ds_cstr(&action), - &lb->nlb->header_); + ovn_lflow_add_with_hint__(lflows, od, S_SWITCH_IN_STATEFUL, 110, + ds_cstr(&match), ds_cstr(&action), + meter, &lb->nlb->header_); } ds_destroy(&match); @@ -6002,7 +6015,8 @@ build_lb_rules(struct ovn_datapath *od, struct hmap *lflows, } static void -build_stateful(struct ovn_datapath *od, struct hmap *lflows, struct hmap *lbs) +build_stateful(struct ovn_datapath *od, struct hmap *lflows, + struct hmap *lbs, struct shash *meter_groups) { /* Ingress and Egress stateful Table (Priority 0): Packets are * allowed by default. */ @@ -6072,7 +6086,7 @@ build_stateful(struct ovn_datapath *od, struct hmap *lflows, struct hmap *lbs) ovn_northd_lb_find(lbs, &od->nbs->load_balancer[i]->header_.uuid); ovs_assert(lb); - build_lb_rules(od, lflows, lb); + build_lb_rules(od, lflows, lb, meter_groups); } } @@ -6603,6 +6617,7 @@ static void build_dhcpv4_options_flows(struct ovn_port *op, struct lport_addresses *lsp_addrs, const char *json_key, bool is_external, + struct shash *meter_groups, struct hmap *lflows) { struct ds match = DS_EMPTY_INITIALIZER; @@ -6626,11 +6641,14 @@ build_dhcpv4_options_flows(struct ovn_port *op, op->json_key); } - ovn_lflow_add_with_hint(lflows, op->od, - S_SWITCH_IN_DHCP_OPTIONS, 100, - ds_cstr(&match), - ds_cstr(&options_action), - &op->nbsp->dhcpv4_options->header_); + ovn_lflow_add_with_hint__(lflows, op->od, + S_SWITCH_IN_DHCP_OPTIONS, 100, + ds_cstr(&match), + ds_cstr(&options_action), + copp_meter_get(COPP_DHCPV4_OPTS, + op->od->nbs->copp, + meter_groups), + &op->nbsp->dhcpv4_options->header_); ds_clear(&match); /* Allow ip4.src = OFFER_IP and * ip4.dst = {SERVER_IP, 255.255.255.255} for the below @@ -6650,11 +6668,14 @@ build_dhcpv4_options_flows(struct ovn_port *op, op->json_key); } - ovn_lflow_add_with_hint(lflows, op->od, - S_SWITCH_IN_DHCP_OPTIONS, 100, - ds_cstr(&match), - ds_cstr(&options_action), - &op->nbsp->dhcpv4_options->header_); + ovn_lflow_add_with_hint__(lflows, op->od, + S_SWITCH_IN_DHCP_OPTIONS, 100, + ds_cstr(&match), + ds_cstr(&options_action), + copp_meter_get(COPP_DHCPV4_OPTS, + op->od->nbs->copp, + meter_groups), + &op->nbsp->dhcpv4_options->header_); ds_clear(&match); /* If REGBIT_DHCP_OPTS_RESULT is set, it means the @@ -6688,6 +6709,7 @@ static void build_dhcpv6_options_flows(struct ovn_port *op, struct lport_addresses *lsp_addrs, const char *json_key, bool is_external, + struct shash *meter_groups, struct hmap *lflows) { struct ds match = DS_EMPTY_INITIALIZER; @@ -6710,11 +6732,14 @@ build_dhcpv6_options_flows(struct ovn_port *op, op->json_key); } - ovn_lflow_add_with_hint(lflows, op->od, - S_SWITCH_IN_DHCP_OPTIONS, 100, - ds_cstr(&match), - ds_cstr(&options_action), - &op->nbsp->dhcpv6_options->header_); + ovn_lflow_add_with_hint__(lflows, op->od, + S_SWITCH_IN_DHCP_OPTIONS, 100, + ds_cstr(&match), + ds_cstr(&options_action), + copp_meter_get(COPP_DHCPV6_OPTS, + op->od->nbs->copp, + meter_groups), + &op->nbsp->dhcpv6_options->header_); /* If REGBIT_DHCP_OPTS_RESULT is set to 1, it means the * put_dhcpv6_opts action is successful */ @@ -6853,7 +6878,7 @@ build_lswitch_lflows_pre_acl_and_acl(struct ovn_datapath *od, build_acls(od, lflows, port_groups, meter_groups); build_qos(od, lflows); build_lb(od, lflows); - build_stateful(od, lflows, lbs); + build_stateful(od, lflows, lbs, meter_groups); build_lb_hairpin(od, lflows); } } @@ -6909,6 +6934,7 @@ static void build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op, struct hmap *lflows, struct hmap *ports, + struct shash *meter_groups, struct ds *actions, struct ds *match) { @@ -7050,11 +7076,14 @@ build_lswitch_arp_nd_responder_known_ips(struct ovn_port *op, op->lsp_addrs[i].ipv6_addrs[j].addr_s, op->lsp_addrs[i].ipv6_addrs[j].addr_s, op->lsp_addrs[i].ea_s); - ovn_lflow_add_with_hint(lflows, op->od, - S_SWITCH_IN_ARP_ND_RSP, 50, - ds_cstr(match), - ds_cstr(actions), - &op->nbsp->header_); + ovn_lflow_add_with_hint__(lflows, op->od, + S_SWITCH_IN_ARP_ND_RSP, 50, + ds_cstr(match), + ds_cstr(actions), + copp_meter_get(COPP_ND_NA, + op->od->nbs->copp, + meter_groups), + &op->nbsp->header_); /* Do not reply to a solicitation from the port that owns * the address (otherwise DAD detection will fail). */ @@ -7132,7 +7161,8 @@ build_lswitch_arp_nd_service_monitor(struct ovn_northd_lb *lb, * priority 100 flows. */ static void build_lswitch_dhcp_options_and_response(struct ovn_port *op, - struct hmap *lflows) + struct hmap *lflows, + struct shash *meter_groups) { if (op->nbsp) { if (!lsp_is_enabled(op->nbsp) || lsp_is_router(op->nbsp)) { @@ -7161,17 +7191,17 @@ build_lswitch_dhcp_options_and_response(struct ovn_port *op, build_dhcpv4_options_flows( op, &op->lsp_addrs[i], op->od->localnet_ports[j]->json_key, is_external, - lflows); + meter_groups, lflows); build_dhcpv6_options_flows( op, &op->lsp_addrs[i], op->od->localnet_ports[j]->json_key, is_external, - lflows); + meter_groups, lflows); } } else { build_dhcpv4_options_flows(op, &op->lsp_addrs[i], op->json_key, - is_external, lflows); + is_external, meter_groups, lflows); build_dhcpv6_options_flows(op, &op->lsp_addrs[i], op->json_key, - is_external, lflows); + is_external, meter_groups, lflows); } } } @@ -7201,13 +7231,19 @@ build_lswitch_dhcp_and_dns_defaults(struct ovn_datapath *od, */ static void build_lswitch_dns_lookup_and_response(struct ovn_datapath *od, - struct hmap *lflows) + struct hmap *lflows, + struct shash *meter_groups) { if (od->nbs && ls_has_dns_records(od->nbs)) { ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 100, "udp.dst == 53", REGBIT_DNS_LOOKUP_RESULT" = dns_lookup(); next;"); + ovn_lflow_add_ctrl(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 100, + "udp.dst == 53", + REGBIT_DNS_LOOKUP_RESULT" = dns_lookup(); next;", + copp_meter_get(COPP_DNS, od->nbs->copp, + meter_groups)); const char *dns_action = "eth.dst <-> eth.src; ip4.src <-> ip4.dst; " "udp.dst = udp.src; udp.src = 53; outport = inport; " "flags.loopback = 1; output;"; @@ -7244,7 +7280,8 @@ build_lswitch_external_port(struct ovn_port *op, static void build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od, struct hmap *lflows, - struct ds *actions) + struct ds *actions, + struct shash *meter_groups) { if (od->nbs) { @@ -7265,12 +7302,16 @@ build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od, } ds_put_cstr(actions, "igmp;"); /* Punt IGMP traffic to controller. */ - ovn_lflow_add_unique(lflows, od, S_SWITCH_IN_L2_LKUP, 100, - "ip4 && ip.proto == 2", ds_cstr(actions)); + ovn_lflow_add_unique__(lflows, od, S_SWITCH_IN_L2_LKUP, 100, + "ip4 && ip.proto == 2", ds_cstr(actions), + copp_meter_get(COPP_IGMP, od->nbs->copp, + meter_groups)); /* Punt MLD traffic to controller. */ - ovn_lflow_add_unique(lflows, od, S_SWITCH_IN_L2_LKUP, 100, - "mldv1 || mldv2", ds_cstr(actions)); + ovn_lflow_add_unique__(lflows, od, S_SWITCH_IN_L2_LKUP, 100, + "mldv1 || mldv2", ds_cstr(actions), + copp_meter_get(COPP_IGMP, od->nbs->copp, + meter_groups)); /* Flood all IP multicast traffic destined to 224.0.0.X to all * ports - RFC 4541, section 2.1.2, item 2. @@ -8650,23 +8691,29 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od, struct ds *match, struct ds *actions, int priority, enum lb_snat_type snat_type, struct ovn_lb_vip *lb_vip, const char *proto, struct nbrec_load_balancer *lb, - struct shash *meter_groups, struct sset *nat_entries) + struct shash *meter_groups, struct sset *nat_entries, + bool reject) { build_empty_lb_event_flow(od, lflows, lb_vip, lb, S_ROUTER_IN_DNAT, meter_groups); + const char *meter = NULL; + if (reject) { + meter = copp_meter_get(COPP_REJECT, od->nbr->copp, meter_groups); + } /* A match and actions for new connections. */ char *new_match = xasprintf("ct.new && %s", ds_cstr(match)); if (snat_type == FORCE_SNAT || snat_type == SKIP_SNAT) { char *new_actions = xasprintf("flags.%s_snat_for_lb = 1; %s", snat_type == SKIP_SNAT ? "skip" : "force", ds_cstr(actions)); - ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, - new_match, new_actions, &lb->header_); + ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT, priority, + new_match, new_actions, meter, &lb->header_); free(new_actions); } else { - ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, - new_match, ds_cstr(actions), &lb->header_); + ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_DNAT, priority, + new_match, ds_cstr(actions), meter, + &lb->header_); } /* A match and actions for established connections. */ @@ -8792,8 +8839,8 @@ build_lrouter_lb_flows(struct hmap *lflows, struct ovn_datapath *od, struct ovn_lb_vip *lb_vip = &lb->vips[j]; struct ovn_northd_lb_vip *lb_vip_nb = &lb->vips_nb[j]; ds_clear(actions); - build_lb_vip_actions(lb_vip, lb_vip_nb, actions, - lb->selection_fields, false); + bool reject = build_lb_vip_actions(lb_vip, lb_vip_nb, actions, + lb->selection_fields, false); if (!sset_contains(&all_ips, lb_vip->vip_str)) { sset_add(&all_ips, lb_vip->vip_str); @@ -8858,7 +8905,7 @@ build_lrouter_lb_flows(struct hmap *lflows, struct ovn_datapath *od, } add_router_lb_flow(lflows, od, match, actions, prio, snat_type, lb_vip, proto, nb_lb, - meter_groups, nat_entries); + meter_groups, nat_entries, reject); } } sset_destroy(&all_ips); @@ -9097,7 +9144,7 @@ build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op, const char *sn_ip_address, const char *eth_addr, struct ds *extra_match, bool drop, uint16_t priority, const struct ovsdb_idl_row *hint, - struct hmap *lflows) + struct hmap *lflows, struct shash *meter_groups) { struct ds match = DS_EMPTY_INITIALIZER; struct ds actions = DS_EMPTY_INITIALIZER; @@ -9119,6 +9166,8 @@ build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op, if (drop) { ds_put_format(&actions, "drop;"); + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority, + ds_cstr(&match), ds_cstr(&actions), hint); } else { ds_put_format(&actions, "%s { " @@ -9135,11 +9184,13 @@ build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op, ip_address, ip_address, eth_addr); + ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_IP_INPUT, priority, + ds_cstr(&match), ds_cstr(&actions), + copp_meter_get(COPP_ND_NA, od->nbr->copp, + meter_groups), + hint); } - ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_INPUT, priority, - ds_cstr(&match), ds_cstr(&actions), hint); - ds_destroy(&match); ds_destroy(&actions); } @@ -9147,7 +9198,8 @@ build_lrouter_nd_flow(struct ovn_datapath *od, struct ovn_port *op, static void build_lrouter_nat_arp_nd_flow(struct ovn_datapath *od, struct ovn_nat *nat_entry, - struct hmap *lflows) + struct hmap *lflows, + struct shash *meter_groups) { struct lport_addresses *ext_addrs = &nat_entry->ext_addrs; const struct nbrec_nat *nat = nat_entry->nb; @@ -9157,7 +9209,7 @@ build_lrouter_nat_arp_nd_flow(struct ovn_datapath *od, ext_addrs->ipv6_addrs[0].addr_s, ext_addrs->ipv6_addrs[0].sn_addr_s, REG_INPORT_ETH_ADDR, NULL, false, 90, - &nat->header_, lflows); + &nat->header_, lflows, meter_groups); } else { build_lrouter_arp_flow(od, NULL, ext_addrs->ipv4_addrs[0].addr_s, @@ -9169,7 +9221,8 @@ build_lrouter_nat_arp_nd_flow(struct ovn_datapath *od, static void build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op, struct ovn_nat *nat_entry, - struct hmap *lflows) + struct hmap *lflows, + struct shash *meter_groups) { struct lport_addresses *ext_addrs = &nat_entry->ext_addrs; const struct nbrec_nat *nat = nat_entry->nb; @@ -9212,12 +9265,12 @@ build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op, ext_addrs->ipv6_addrs[0].addr_s, ext_addrs->ipv6_addrs[0].sn_addr_s, mac_s, &match, false, 92, - &nat->header_, lflows); + &nat->header_, lflows, meter_groups); build_lrouter_nd_flow(op->od, op, "nd_na", ext_addrs->ipv6_addrs[0].addr_s, ext_addrs->ipv6_addrs[0].sn_addr_s, mac_s, NULL, true, 91, - &nat->header_, lflows); + &nat->header_, lflows, meter_groups); } else { build_lrouter_arp_flow(op->od, op, ext_addrs->ipv4_addrs[0].addr_s, @@ -9390,7 +9443,8 @@ build_lrouter_force_snat_flows_op(struct ovn_port *op, } static void -build_lrouter_bfd_flows(struct hmap *lflows, struct ovn_port *op) +build_lrouter_bfd_flows(struct hmap *lflows, struct ovn_port *op, + struct shash *meter_groups) { if (!op->has_bfd) { return; @@ -9409,9 +9463,11 @@ build_lrouter_bfd_flows(struct hmap *lflows, struct ovn_port *op) ds_clear(&match); ds_put_format(&match, "ip4.dst == %s && udp.dst == 3784", ds_cstr(&ip_list)); - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 110, - ds_cstr(&match), "handle_bfd_msg(); ", - &op->nbrp->header_); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, 110, + ds_cstr(&match), "handle_bfd_msg(); ", + copp_meter_get(COPP_BFD, op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); } if (op->lrp_networks.n_ipv6_addrs) { ds_clear(&ip_list); @@ -9426,9 +9482,11 @@ build_lrouter_bfd_flows(struct hmap *lflows, struct ovn_port *op) ds_clear(&match); ds_put_format(&match, "ip6.dst == %s && udp.dst == 3784", ds_cstr(&ip_list)); - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 110, - ds_cstr(&match), "handle_bfd_msg(); ", - &op->nbrp->header_); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, 110, + ds_cstr(&match), "handle_bfd_msg(); ", + copp_meter_get(COPP_BFD, op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); } ds_destroy(&ip_list); @@ -9508,7 +9566,8 @@ build_adm_ctrl_flows_for_lrouter_port( static void build_neigh_learning_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows, - struct ds *match, struct ds *actions) + struct ds *match, struct ds *actions, + struct shash *meter_groups) { if (od->nbr) { @@ -9588,14 +9647,20 @@ build_neigh_learning_flows_for_lrouter( ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 100, ds_cstr(match), "next;"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, - "arp", "put_arp(inport, arp.spa, arp.sha); next;"); + ovn_lflow_add_ctrl(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, + "arp", "put_arp(inport, arp.spa, arp.sha); next;", + copp_meter_get(COPP_ARP, od->nbr->copp, + meter_groups)); - ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, - "nd_na", "put_nd(inport, nd.target, nd.tll); next;"); + ovn_lflow_add_ctrl(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, + "nd_na", "put_nd(inport, nd.target, nd.tll); next;", + copp_meter_get(COPP_ND_NA, od->nbr->copp, + meter_groups)); - ovn_lflow_add(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, - "nd_ns", "put_nd(inport, ip6.src, nd.sll); next;"); + ovn_lflow_add_ctrl(lflows, od, S_ROUTER_IN_LEARN_NEIGHBOR, 90, + "nd_ns", "put_nd(inport, ip6.src, nd.sll); next;", + copp_meter_get(COPP_ND_NS, od->nbr->copp, + meter_groups)); } } @@ -9670,7 +9735,8 @@ build_neigh_learning_flows_for_lrouter_port( static void build_ND_RA_flows_for_lrouter_port( struct ovn_port *op, struct hmap *lflows, - struct ds *match, struct ds *actions) + struct ds *match, struct ds *actions, + struct shash *meter_groups) { if (!op->nbrp || op->nbrp->peer || !op->peer) { return; @@ -9763,9 +9829,12 @@ build_ND_RA_flows_for_lrouter_port( if (add_rs_response_flow) { ds_put_cstr(actions, "); next;"); - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_ND_RA_OPTIONS, - 50, ds_cstr(match), ds_cstr(actions), - &op->nbrp->header_); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_ND_RA_OPTIONS, + 50, ds_cstr(match), ds_cstr(actions), + copp_meter_get(COPP_ND_RA_OPTS, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); ds_clear(actions); ds_clear(match); ds_put_format(match, "inport == %s && ip6.dst == ff02::2 && " @@ -10388,7 +10457,8 @@ static void build_check_pkt_len_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows, struct hmap *ports, - struct ds *match, struct ds *actions) + struct ds *match, struct ds *actions, + struct shash *meter_groups) { if (od->nbr) { @@ -10450,10 +10520,14 @@ build_check_pkt_len_flows_for_lrouter( rp->lrp_networks.ipv4_addrs[0].addr_s, gw_mtu, ovn_stage_get_table(S_ROUTER_IN_ADMISSION)); - ovn_lflow_add_with_hint(lflows, od, - S_ROUTER_IN_LARGER_PKTS, 50, - ds_cstr(match), ds_cstr(actions), - &rp->nbrp->header_); + ovn_lflow_add_with_hint__(lflows, od, + S_ROUTER_IN_LARGER_PKTS, 50, + ds_cstr(match), ds_cstr(actions), + copp_meter_get( + COPP_ICMP4_ERR, + rp->od->nbr->copp, + meter_groups), + &rp->nbrp->header_); } if (rp->lrp_networks.ipv6_addrs) { @@ -10479,10 +10553,14 @@ build_check_pkt_len_flows_for_lrouter( rp->lrp_networks.ipv6_addrs[0].addr_s, gw_mtu, ovn_stage_get_table(S_ROUTER_IN_ADMISSION)); - ovn_lflow_add_with_hint(lflows, od, - S_ROUTER_IN_LARGER_PKTS, 50, - ds_cstr(match), ds_cstr(actions), - &rp->nbrp->header_); + ovn_lflow_add_with_hint__(lflows, od, + S_ROUTER_IN_LARGER_PKTS, 50, + ds_cstr(match), ds_cstr(actions), + copp_meter_get( + COPP_ICMP6_ERR, + rp->od->nbr->copp, + meter_groups), + &rp->nbrp->header_); } } } @@ -10537,7 +10615,8 @@ build_gateway_redirect_flows_for_lrouter( static void build_arp_request_flows_for_lrouter( struct ovn_datapath *od, struct hmap *lflows, - struct ds *match, struct ds *actions) + struct ds *match, struct ds *actions, + struct shash *meter_groups) { if (od->nbr) { for (int i = 0; i < od->nbr->n_static_routes; i++) { @@ -10574,26 +10653,33 @@ build_arp_request_flows_for_lrouter( "};", ETH_ADDR_ARGS(eth_dst), sn_addr_s, route->nexthop); - ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ARP_REQUEST, 200, - ds_cstr(match), ds_cstr(actions), - &route->header_); - } - - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100, - "eth.dst == 00:00:00:00:00:00 && ip4", - "arp { " - "eth.dst = ff:ff:ff:ff:ff:ff; " - "arp.spa = " REG_SRC_IPV4 "; " - "arp.tpa = " REG_NEXT_HOP_IPV4 "; " - "arp.op = 1; " /* ARP request */ - "output; " - "};"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100, - "eth.dst == 00:00:00:00:00:00 && ip6", - "nd_ns { " - "nd.target = " REG_NEXT_HOP_IPV6 "; " - "output; " - "};"); + ovn_lflow_add_with_hint__(lflows, od, S_ROUTER_IN_ARP_REQUEST, 200, + ds_cstr(match), ds_cstr(actions), + copp_meter_get(COPP_ND_NS_RESOLVE, + od->nbr->copp, + meter_groups), + &route->header_); + } + + ovn_lflow_add_ctrl(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100, + "eth.dst == 00:00:00:00:00:00 && ip4", + "arp { " + "eth.dst = ff:ff:ff:ff:ff:ff; " + "arp.spa = " REG_SRC_IPV4 "; " + "arp.tpa = " REG_NEXT_HOP_IPV4 "; " + "arp.op = 1; " /* ARP request */ + "output; " + "};", + copp_meter_get(COPP_ARP_RESOLVE, od->nbr->copp, + meter_groups)); + ovn_lflow_add_ctrl(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100, + "eth.dst == 00:00:00:00:00:00 && ip6", + "nd_ns { " + "nd.target = " REG_NEXT_HOP_IPV6 "; " + "output; " + "};", + copp_meter_get(COPP_ND_NS_RESOLVE, od->nbr->copp, + meter_groups)); ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 0, "1", "output;"); } } @@ -10724,7 +10810,8 @@ build_dhcpv6_reply_flows_for_lrouter_port( static void build_ipv6_input_flows_for_lrouter_port( struct ovn_port *op, struct hmap *lflows, - struct ds *match, struct ds *actions) + struct ds *match, struct ds *actions, + struct shash *meter_groups) { if (op->nbrp && (!op->derived)) { /* No ingress packets are accepted on a chassisredirect @@ -10767,7 +10854,7 @@ build_ipv6_input_flows_for_lrouter_port( op->lrp_networks.ipv6_addrs[i].addr_s, op->lrp_networks.ipv6_addrs[i].sn_addr_s, REG_INPORT_ETH_ADDR, match, false, 90, - &op->nbrp->header_, lflows); + &op->nbrp->header_, lflows, meter_groups); } /* UDP/TCP/SCTP port unreachable */ @@ -10782,9 +10869,13 @@ build_ipv6_input_flows_for_lrouter_port( "eth.dst <-> eth.src; " "ip6.dst <-> ip6.src; " "next; };"; - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 80, ds_cstr(match), action, - &op->nbrp->header_); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 80, ds_cstr(match), action, + copp_meter_get( + COPP_TCP_RESET, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); ds_clear(match); ds_put_format(match, @@ -10809,9 +10900,13 @@ build_ipv6_input_flows_for_lrouter_port( "icmp6.type = 1; " "icmp6.code = 4; " "next; };"; - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 80, ds_cstr(match), action, - &op->nbrp->header_); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 80, ds_cstr(match), action, + copp_meter_get( + COPP_ICMP6_ERR, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); ds_clear(match); ds_put_format(match, @@ -10824,9 +10919,13 @@ build_ipv6_input_flows_for_lrouter_port( "icmp6.type = 1; " "icmp6.code = 3; " "next; };"; - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 70, ds_cstr(match), action, - &op->nbrp->header_); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 70, ds_cstr(match), action, + copp_meter_get( + COPP_ICMP6_ERR, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); } } @@ -10857,9 +10956,12 @@ build_ipv6_input_flows_for_lrouter_port( "icmp6.code = 0; /* TTL exceeded in transit */ " "next; };", op->lrp_networks.ipv6_addrs[i].addr_s); - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40, - ds_cstr(match), ds_cstr(actions), - &op->nbrp->header_); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40, + ds_cstr(match), ds_cstr(actions), + copp_meter_get(COPP_ICMP6_ERR, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); } } @@ -10867,7 +10969,8 @@ build_ipv6_input_flows_for_lrouter_port( static void build_lrouter_arp_nd_for_datapath(struct ovn_datapath *od, - struct hmap *lflows) + struct hmap *lflows, + struct shash *meter_groups) { if (od->nbr) { @@ -10893,7 +10996,7 @@ build_lrouter_arp_nd_for_datapath(struct ovn_datapath *od, if (!strcmp(nat_entry->nb->type, "snat")) { continue; } - build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows); + build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows, meter_groups); } /* Now handle SNAT entries too, one per unique SNAT IP. */ @@ -10908,7 +11011,7 @@ build_lrouter_arp_nd_for_datapath(struct ovn_datapath *od, struct ovn_nat *nat_entry = CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries), struct ovn_nat, ext_addr_list_node); - build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows); + build_lrouter_nat_arp_nd_flow(od, nat_entry, lflows, meter_groups); } } } @@ -10917,7 +11020,8 @@ build_lrouter_arp_nd_for_datapath(struct ovn_datapath *od, static void build_lrouter_ipv4_ip_input(struct ovn_port *op, struct hmap *lflows, - struct ds *match, struct ds *actions) + struct ds *match, struct ds *actions, + struct shash *meter_groups) { /* No ingress packets are accepted on a chassisredirect * port, so no need to program flows for that port. */ @@ -10955,7 +11059,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, } /* BFD msg handling */ - build_lrouter_bfd_flows(lflows, op); + build_lrouter_bfd_flows(lflows, op, meter_groups); /* ICMP time exceeded */ for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { @@ -10975,9 +11079,12 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, "ip.ttl = 255; " "next; };", op->lrp_networks.ipv4_addrs[i].addr_s); - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40, - ds_cstr(match), ds_cstr(actions), - &op->nbrp->header_); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, 40, + ds_cstr(match), ds_cstr(actions), + copp_meter_get(COPP_ICMP4_ERR, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); } /* ARP reply. These flows reply to ARP requests for the router's own @@ -11051,7 +11158,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, build_lrouter_nd_flow(op->od, op, "nd_na", ip_address, NULL, REG_INPORT_ETH_ADDR, - match, false, 90, NULL, lflows); + match, false, 90, NULL, + lflows, meter_groups); } sset_destroy(&all_ips_v4); @@ -11072,9 +11180,13 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, "icmp4.type = 3; " "icmp4.code = 3; " "next; };"; - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 80, ds_cstr(match), action, - &op->nbrp->header_); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 80, ds_cstr(match), action, + copp_meter_get( + COPP_ICMP4_ERR, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); ds_clear(match); ds_put_format(match, @@ -11084,9 +11196,13 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, "eth.dst <-> eth.src; " "ip4.dst <-> ip4.src; " "next; };"; - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 80, ds_cstr(match), action, - &op->nbrp->header_); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 80, ds_cstr(match), action, + copp_meter_get( + COPP_TCP_RESET, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); ds_clear(match); ds_put_format(match, @@ -11111,9 +11227,13 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, "icmp4.type = 3; " "icmp4.code = 2; " "next; };"; - ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_IN_IP_INPUT, - 70, ds_cstr(match), action, - &op->nbrp->header_); + ovn_lflow_add_with_hint__(lflows, op->od, S_ROUTER_IN_IP_INPUT, + 70, ds_cstr(match), action, + copp_meter_get( + COPP_ICMP4_ERR, + op->od->nbr->copp, + meter_groups), + &op->nbrp->header_); } } @@ -11157,7 +11277,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, if (!strcmp(nat_entry->nb->type, "snat")) { continue; } - build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows); + build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows, + meter_groups); } /* Now handle SNAT entries too, one per unique SNAT IP. */ @@ -11172,7 +11293,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, struct ovn_nat *nat_entry = CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries), struct ovn_nat, ext_addr_list_node); - build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows); + build_lrouter_port_nat_arp_nd_flow(op, nat_entry, lflows, + meter_groups); } } } @@ -11853,15 +11975,16 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od, build_lswitch_input_port_sec_od(od, lsi->lflows); build_lswitch_learn_fdb_od(od, lsi->lflows); build_lswitch_arp_nd_responder_default(od, lsi->lflows); - build_lswitch_dns_lookup_and_response(od, lsi->lflows); + build_lswitch_dns_lookup_and_response(od, lsi->lflows, lsi->meter_groups); build_lswitch_dhcp_and_dns_defaults(od, lsi->lflows); - build_lswitch_destination_lookup_bmcast(od, lsi->lflows, &lsi->actions); + build_lswitch_destination_lookup_bmcast(od, lsi->lflows, &lsi->actions, + lsi->meter_groups); build_lswitch_output_port_sec_od(od, lsi->lflows); /* Build Logical Router Flows. */ build_adm_ctrl_flows_for_lrouter(od, lsi->lflows); build_neigh_learning_flows_for_lrouter(od, lsi->lflows, &lsi->match, - &lsi->actions); + &lsi->actions, lsi->meter_groups); build_ND_RA_flows_for_lrouter(od, lsi->lflows); build_static_route_flows_for_lrouter(od, lsi->lflows, lsi->ports, lsi->bfd_connections); @@ -11870,13 +11993,14 @@ build_lswitch_and_lrouter_iterate_by_od(struct ovn_datapath *od, build_ingress_policy_flows_for_lrouter(od, lsi->lflows, lsi->ports); build_arp_resolve_flows_for_lrouter(od, lsi->lflows); build_check_pkt_len_flows_for_lrouter(od, lsi->lflows, lsi->ports, - &lsi->match, &lsi->actions); + &lsi->match, &lsi->actions, + lsi->meter_groups); build_gateway_redirect_flows_for_lrouter(od, lsi->lflows, &lsi->match, &lsi->actions); build_arp_request_flows_for_lrouter(od, lsi->lflows, &lsi->match, - &lsi->actions); + &lsi->actions, lsi->meter_groups); build_misc_local_traffic_drop_flows_for_lrouter(od, lsi->lflows); - build_lrouter_arp_nd_for_datapath(od, lsi->lflows); + build_lrouter_arp_nd_for_datapath(od, lsi->lflows, lsi->meter_groups); build_lrouter_nat_defrag_and_lb(od, lsi->lflows, lsi->meter_groups, lsi->lbs, &lsi->match, &lsi->actions); } @@ -11896,9 +12020,11 @@ build_lswitch_and_lrouter_iterate_by_op(struct ovn_port *op, &lsi->match); build_lswitch_arp_nd_responder_known_ips(op, lsi->lflows, lsi->ports, + lsi->meter_groups, &lsi->actions, &lsi->match); - build_lswitch_dhcp_options_and_response(op, lsi->lflows); + build_lswitch_dhcp_options_and_response(op, lsi->lflows, + lsi->meter_groups); build_lswitch_external_port(op, lsi->lflows); build_lswitch_ip_unicast_lookup(op, lsi->lflows, lsi->mcgroups, &lsi->actions, &lsi->match); @@ -11912,16 +12038,17 @@ build_lswitch_and_lrouter_iterate_by_op(struct ovn_port *op, &lsi->actions); build_ip_routing_flows_for_lrouter_port(op, lsi->lflows); build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, - &lsi->actions); + &lsi->actions, lsi->meter_groups); build_arp_resolve_flows_for_lrouter_port(op, lsi->lflows, lsi->ports, &lsi->match, &lsi->actions); build_egress_delivery_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, &lsi->actions); build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, &lsi->match); build_ipv6_input_flows_for_lrouter_port(op, lsi->lflows, - &lsi->match, &lsi->actions); + &lsi->match, &lsi->actions, + lsi->meter_groups); build_lrouter_ipv4_ip_input(op, lsi->lflows, - &lsi->match, &lsi->actions); + &lsi->match, &lsi->actions, lsi->meter_groups); build_lrouter_force_snat_flows_op(op, lsi->lflows, &lsi->match, &lsi->actions); } diff --git a/ovn-nb.xml b/ovn-nb.xml index 0f03a12f2..7695514a5 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -399,6 +399,9 @@ Rate limiting meter for BFD packets. + + Rate limiting meter for packets that trigger a reject action +

diff --git a/tests/atlocal.in b/tests/atlocal.in index b5bc0818b..310fd46a5 100644 --- a/tests/atlocal.in +++ b/tests/atlocal.in @@ -169,6 +169,9 @@ find_command tcpdump # Set HAVE_LFTP find_command lftp +# Set HAVE_SCAPY +find_command scapy + CURL_OPT="-g -v --max-time 1 --retry 2 --retry-delay 1 --connect-timeout 1" # Determine whether "diff" supports "normal" diffs. (busybox diff does not.) diff --git a/tests/system-ovn.at b/tests/system-ovn.at index b6c679907..8a9cbde98 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -5890,3 +5890,122 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d /.*terminating with signal 15.*/d"]) AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([ovn -- CoPP]) +AT_SKIP_IF([test $HAVE_TCPDUMP = no]) +AT_SKIP_IF([test $HAVE_SCAPY = no]) +AT_KEYWORDS([ovn-copp]) + +ovn_start +OVS_TRAFFIC_VSWITCHD_START() + +ADD_BR([br-int]) +ADD_BR([br-ext]) + +check ovs-ofctl add-flow br-ext action=normal +# Set external-ids in br-int needed for ovn-controller +check ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller + +check ovn-nbctl lr-add R1 +check ovn-nbctl ls-add sw0 +check ovn-nbctl ls-add public + +check ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24 +check ovn-nbctl lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24 1000::a/64 \ + -- lrp-set-gateway-chassis rp-public hv1 + +check ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \ + type=router options:router-port=rp-sw0 \ + -- lsp-set-addresses sw0-rp router + +check ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \ + type=router options:router-port=rp-public \ + -- lsp-set-addresses public-rp router + +ADD_NAMESPACES(sw01) +ADD_VETH(sw01, sw01, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \ + "192.168.1.1") +check ovn-nbctl lsp-add sw0 sw01 \ + -- lsp-set-addresses sw01 "f0:00:00:01:02:03 192.168.1.2" + +ADD_NAMESPACES(server) +NS_CHECK_EXEC([server], [ip link set dev lo up]) +ADD_VETH(s1, server, br-ext, "172.16.1.50/24", "f0:00:00:01:02:05", \ + "172.16.1.1") +NS_CHECK_EXEC([server], [ip addr add 1000::b/64 dev s1]) + +AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext]) +check ovn-nbctl lsp-add public public1 \ + -- lsp-set-addresses public1 unknown \ + -- lsp-set-type public1 localnet \ + -- lsp-set-options public1 network_name=phynet + +NS_CHECK_EXEC([sw01], [tcpdump -nni sw01 icmp -Q in > reject.pcap &]) +check ovn-nbctl meter-add acl-meter drop 1 pktps 0 +check ovn-nbctl --wait=hv ls-copp-add sw0 reject acl-meter +check ovn-nbctl acl-add sw0 from-lport 1002 'inport == "sw01" && ip && udp' reject + +AT_CHECK([ovn-nbctl ls-copp-list sw0], [0], [dnl +reject: acl-meter +]) + +ip netns exec sw01 scapy -H <<-EOF +p = IP(src="192.168.1.2", dst="192.168.1.1")/ UDP(dport = 12345) / Raw(b"X"*64) +send (p, iface='sw01', loop = 0, verbose = 0, count = 20) +EOF + +sleep 2 +kill $(pidof tcpdump) + +# 1pps + 1 burst size +OVS_WAIT_UNTIL([ + n_reject=$(grep unreachable reject.pcap | wc -l) + test "${n_reject}" = "2" +]) + +NS_CHECK_EXEC([server], [tcpdump -nni s1 arp[[24:4]]=0xac100164 > arp.pcap &]) +check ovn-nbctl meter-add arp-meter drop 1 pktps 0 +check ovn-nbctl --wait=hv lr-copp-add R1 arp-resolve arp-meter +AT_CHECK([ovn-nbctl lr-copp-list R1], [0], [dnl +arp-resolve: arp-meter +]) + +ip netns exec sw01 scapy -H <<-EOF +p = IP(src="192.168.1.2", dst="172.16.1.100")/ TCP(dport = 80, flags="S") / Raw(b"X"*64) +send (p, iface='sw01', loop = 0, verbose = 0, count = 100) +EOF + +sleep 2 +kill $(pidof tcpdump) + +# 1pps + 1 burst size +OVS_WAIT_UNTIL([ + n_arp=$(grep ARP arp.pcap | wc -l) + test "${n_arp}" = "2" +]) + +kill $(pidof ovn-controller) + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d +/.*terminating with signal 15.*/d"]) +AT_CLEANUP +]) diff --git a/utilities/ovn-nbctl.8.xml b/utilities/ovn-nbctl.8.xml index 6c95e8104..5f5f71015 100644 --- a/utilities/ovn-nbctl.8.xml +++ b/utilities/ovn-nbctl.8.xml @@ -1151,6 +1151,7 @@
  • packets that need to be replied to with ICMP Errors
  • packets that need to be replied to with TCP RST
  • packets that need to be replied to with DHCP_OPTS
  • +
  • packets that trigger a reject action
  • BFD
  • From patchwork Thu Apr 29 17:04:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1471790 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.133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=GlCafHHK; dkim-atps=neutral Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FWMLM4Zytz9t0G for ; Fri, 30 Apr 2021 03:04:43 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 7AE0A4199B; Thu, 29 Apr 2021 17:04:41 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id iWDsF7vQ3uQW; Thu, 29 Apr 2021 17:04:40 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTP id 972844199D; Thu, 29 Apr 2021 17:04:39 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 6880EC000E; Thu, 29 Apr 2021 17:04:39 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4A992C0001 for ; Thu, 29 Apr 2021 17:04:38 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id EE06B4199B for ; Thu, 29 Apr 2021 17:04:37 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 9CSoy-qIpAzB for ; Thu, 29 Apr 2021 17:04:35 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by smtp2.osuosl.org (Postfix) with ESMTPS id B9B1841994 for ; Thu, 29 Apr 2021 17:04:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1619715874; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Ln8nJITa0zj+ZxwRc9Gih5W10I7CwnfOl4cKgOM8Jak=; b=GlCafHHKsIlNhJNgjiGjBuX3vglI+L40Hj6TW7Wlq+scRSUVJfkCvWe5PjC1lIUGTzJsRG PQu/+ZAvmWa72S4botJR6uun/xSR1WmNZUNIcbfpXiF91YJtTP4D0i+aV3k8rzv2ZO/K6b vRFb59QOmgmDtGNRWM25fcmwek2s5w4= Received: from mail-ed1-f72.google.com (mail-ed1-f72.google.com [209.85.208.72]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-453-E3gfK3kmP62CGvCRo-O8HA-1; Thu, 29 Apr 2021 13:04:32 -0400 X-MC-Unique: E3gfK3kmP62CGvCRo-O8HA-1 Received: by mail-ed1-f72.google.com with SMTP id w14-20020aa7da4e0000b02903834aeed684so27314608eds.13 for ; Thu, 29 Apr 2021 10:04:32 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Ln8nJITa0zj+ZxwRc9Gih5W10I7CwnfOl4cKgOM8Jak=; b=PE5TEI1wL/I5lK6lLOqrlOBbvQM3YPT8PMiBPZDUQrCmlmQpj/uVk4V1MxH74QoHrx xk5HckRVuQdPwBg7dlMeGLgYLLLT8xGG43A/2Q852HziMbeo4Qk1CMtrJ4cdTw9eQxHj 38zwHaN8Z3Oy64L7jMMSrC+NgiVSRrGzwypy30aePqW28eJh1uaG+MApMztISmaIMdVV sZucJrPe6/Nr8PoLE72HQwRNomW3DRPMQ5w/nsfNCQ/XJTDI5RLeqbLI5etz4dzlbT6R 57rzez48XJdZHzNdSy9IJXKXSfcprqgkf1snCaMQqD9114ZFMDHxQWk7Nys23NryG041 rfhg== X-Gm-Message-State: AOAM531KrHmAIxNwLnT7VueRCnnP2KHtK359bM0w09Bs5N1ays1KcedQ CgoY02vK/2qRG4audNS5fFb5Csj9+WoMJg770F9ov9yZVB1RNCX2GM4gQ92VkPogvq2kS+1jakV SFCz/oBI2P7PzMwt2M7XbNoQb3krVtYlYUoW/8evH6BoOvydhKXs59BHJzSsqHPtKJ/3U9v242l U= X-Received: by 2002:aa7:cb43:: with SMTP id w3mr638052edt.287.1619715871129; Thu, 29 Apr 2021 10:04:31 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwGz/RNIvo/sUJWQbAcMQStAvsBU9UzDSLIz39PQAq1ChXhQPiWwcyxtuwIpZkvdPjQglWlXw== X-Received: by 2002:aa7:cb43:: with SMTP id w3mr638017edt.287.1619715870888; Thu, 29 Apr 2021 10:04:30 -0700 (PDT) Received: from lore-desk.redhat.com ([151.66.28.185]) by smtp.gmail.com with ESMTPSA id re26sm299250ejb.3.2021.04.29.10.04.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Apr 2021 10:04:30 -0700 (PDT) From: Lorenzo Bianconi To: dev@openvswitch.org Date: Thu, 29 Apr 2021 19:04:17 +0200 Message-Id: <075a2b9054edd352dd17ec34b45c32a643b7fb20.1619715319.git.lorenzo.bianconi@redhat.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: References: MIME-Version: 1.0 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=lorenzo.bianconi@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Cc: dceara@redhat.com Subject: [ovs-dev] [PATCH ovn 4/5] ovn-northd: Extend metering to Controller-Events 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: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Dumitru Ceara Co-authored-by: Lorenzo Bianconi Signed-off-by: Lorenzo Bianconi Signed-off-by: Dumitru Ceara --- include/ovn/actions.h | 1 - lib/actions.c | 50 ++++++++----------------------------------- northd/ovn-northd.c | 18 ++++++++-------- tests/ovn.at | 4 ++-- 4 files changed, 20 insertions(+), 53 deletions(-) diff --git a/include/ovn/actions.h b/include/ovn/actions.h index ab03df12c..b2f2f57c6 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -393,7 +393,6 @@ struct ovnact_controller_event { int event_type; /* controller event type */ struct ovnact_gen_option *options; size_t n_options; - char *meter; }; /* OVNACT_BIND_VPORT. */ diff --git a/lib/actions.c b/lib/actions.c index 155b4a45a..f0291afef 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -1613,9 +1613,6 @@ format_TRIGGER_EVENT(const struct ovnact_controller_event *event, { ds_put_format(s, "trigger_event(event = \"%s\"", event_to_string(event->event_type)); - if (event->meter) { - ds_put_format(s, ", meter = \"%s\"", event->meter); - } for (const struct ovnact_gen_option *o = event->options; o < &event->options[event->n_options]; o++) { ds_put_cstr(s, ", "); @@ -1790,24 +1787,11 @@ encode_event_empty_lb_backends_opts(struct ofpbuf *ofpacts, static void encode_TRIGGER_EVENT(const struct ovnact_controller_event *event, - const struct ovnact_encode_params *ep OVS_UNUSED, + const struct ovnact_encode_params *ep, struct ofpbuf *ofpacts) { - uint32_t meter_id = NX_CTLR_NO_METER; - size_t oc_offset; - - if (event->meter) { - meter_id = ovn_extend_table_assign_id(ep->meter_table, event->meter, - ep->lflow_uuid); - if (meter_id == EXT_TABLE_ID_INVALID) { - VLOG_WARN("Unable to assign id for trigger meter: %s", - event->meter); - return; - } - } - - oc_offset = encode_start_controller_op(ACTION_OPCODE_EVENT, false, - meter_id, ofpacts); + size_t oc_offset = encode_start_controller_op(ACTION_OPCODE_EVENT, false, + ep->ctrl_meter_id, ofpacts); ovs_be32 ofs = htonl(event->event_type); ofpbuf_put(ofpacts, &ofs, sizeof ofs); @@ -2341,27 +2325,12 @@ parse_trigger_event(struct action_context *ctx, sizeof *event->options); } - if (lexer_match_id(ctx->lexer, "meter")) { - if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) { - return; - } - /* If multiple meters are given, use the most recent. */ - if (ctx->lexer->token.type == LEX_T_STRING && - strlen(ctx->lexer->token.s)) { - free(event->meter); - event->meter = xstrdup(ctx->lexer->token.s); - } else if (ctx->lexer->token.type != LEX_T_STRING) { - lexer_syntax_error(ctx->lexer, "expecting string"); - return; - } - lexer_get(ctx->lexer); - } else { - struct ovnact_gen_option *o = &event->options[event->n_options++]; - memset(o, 0, sizeof *o); - parse_gen_opt(ctx, o, - &ctx->pp->controller_event_opts->event_opts[event_type], - event_to_string(event_type)); - } + struct ovnact_gen_option *o = &event->options[event->n_options++]; + memset(o, 0, sizeof *o); + parse_gen_opt(ctx, o, + &ctx->pp->controller_event_opts->event_opts[event_type], + event_to_string(event_type)); + if (ctx->lexer->error) { return; } @@ -2382,7 +2351,6 @@ static void ovnact_controller_event_free(struct ovnact_controller_event *event) { free_gen_options(event->options, event->n_options); - free(event->meter); } static void diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 93b431f4c..a3eb8f646 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -5083,11 +5083,7 @@ build_empty_lb_event_flow(struct ovn_datapath *od, struct hmap *lflows, bool ipv4 = IN6_IS_ADDR_V4MAPPED(&lb_vip->vip); struct ds match = DS_EMPTY_INITIALIZER; - char *meter = "", *action; - - if (meter_groups && shash_find(meter_groups, "event-elb")) { - meter = "event-elb"; - } + char *action; ds_put_format(&match, "ip%s.dst == %s && %s", ipv4 ? "4": "6", lb_vip->vip_str, lb->protocol); @@ -5101,14 +5097,18 @@ build_empty_lb_event_flow(struct ovn_datapath *od, struct hmap *lflows, } action = xasprintf("trigger_event(event = \"%s\", " - "meter = \"%s\", vip = \"%s\", " + "vip = \"%s\", " "protocol = \"%s\", " "load_balancer = \"" UUID_FMT "\");", event_to_string(OVN_EVENT_EMPTY_LB_BACKENDS), - meter, vip, lb->protocol, + vip, lb->protocol, UUID_ARGS(&lb->header_.uuid)); - ovn_lflow_add_with_hint(lflows, od, pl, 130, ds_cstr(&match), action, - &lb->header_); + + const struct nbrec_copp *copp = (od->nbr ? od->nbr->copp : od->nbs->copp); + ovn_lflow_add_with_hint__(lflows, od, pl, 130, ds_cstr(&match), action, + copp_meter_get(COPP_EVENT_ELB, copp, + meter_groups), + &lb->header_); ds_destroy(&match); if (lb_vip->vip_port) { free(vip); diff --git a/tests/ovn.at b/tests/ovn.at index ae1b472e4..aff520f3a 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -1661,8 +1661,7 @@ trigger_event(event = "empty_lb_backends", vip = "10.0.0.1:80", protocol = "tcp" encodes as controller(userdata=00.00.00.0f.00.00.00.00.00.00.00.00.00.01.00.0b.31.30.2e.30.2e.30.2e.31.3a.38.30.00.02.00.03.74.63.70.00.03.00.24.31.32.33.34.35.36.37.38.2d.61.62.63.64.2d.39.38.37.36.2d.66.65.64.63.2d.31.31.31.31.39.66.38.65.37.64.36.63) trigger_event(event = "empty_lb_backends", meter="event-elb" vip = "10.0.0.1:80", protocol = "tcp", load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c"); - formats as trigger_event(event = "empty_lb_backends", meter = "event-elb", vip = "10.0.0.1:80", protocol = "tcp", load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c"); - encodes as controller(userdata=00.00.00.0f.00.00.00.00.00.00.00.00.00.01.00.0b.31.30.2e.30.2e.30.2e.31.3a.38.30.00.02.00.03.74.63.70.00.03.00.24.31.32.33.34.35.36.37.38.2d.61.62.63.64.2d.39.38.37.36.2d.66.65.64.63.2d.31.31.31.31.39.66.38.65.37.64.36.63,meter_id=5) + Syntax error at `meter' expecting empty_lb_backends option name. # Testing invalid vip results in extra error messages from socket-util.c trigger_event(event = "empty_lb_backends", vip = "10.0.0.1:80", protocol = "aarp", load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c"); @@ -17629,6 +17628,7 @@ ovn-nbctl ls-lb-add sw0 lb2 uuid_lb2=$(ovn-nbctl --bare --columns=_uuid find load_balancer name=lb2) ovn-nbctl --wait=hv meter-add event-elb drop 100 pktps 10 +ovn-nbctl --wait=hv ls-copp-add sw0 event-elb event-elb OVN_POPULATE_ARP wait_for_ports_up From patchwork Thu Apr 29 17:04:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1471791 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=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=auK9TOdk; dkim-atps=neutral Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FWMLR4Jb8z9t0G for ; Fri, 30 Apr 2021 03:04:47 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 17E1B84DF5; Thu, 29 Apr 2021 17:04:45 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id GGj7XddXnVGg; Thu, 29 Apr 2021 17:04:44 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTP id 4129A84479; Thu, 29 Apr 2021 17:04:43 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 08671C002A; Thu, 29 Apr 2021 17:04:42 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 12D2CC000E for ; Thu, 29 Apr 2021 17:04:39 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 659956F71E for ; Thu, 29 Apr 2021 17:04:37 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp3.osuosl.org (amavisd-new); dkim=pass (1024-bit key) header.d=redhat.com Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id AdArDITI3xeu for ; Thu, 29 Apr 2021 17:04:36 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp3.osuosl.org (Postfix) with ESMTPS id B3C706F71A for ; Thu, 29 Apr 2021 17:04:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1619715875; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=SkmfPEEeSMpru7vcjYlKwq7lcoPmko9D6J+Ivt9Ayfk=; b=auK9TOdkfOtVlsCJAEXnFevWROLzxxWZxBQsR+fIMIOoSh1vKv4GmS5lYDLhLzGtapbBQ5 RKmkYd6pSIs5SGVE9/+kVFhKzRWAK+uNZ/l1YPqbDpCfx2y4WdPrChGjUEaBsIWDvDQU14 9P1leGWBxZvR/vr9gRzrV6bj5CL4CDA= Received: from mail-ed1-f72.google.com (mail-ed1-f72.google.com [209.85.208.72]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-472-eaM0sioYMA25aZTKlY8Ndw-1; Thu, 29 Apr 2021 13:04:33 -0400 X-MC-Unique: eaM0sioYMA25aZTKlY8Ndw-1 Received: by mail-ed1-f72.google.com with SMTP id i2-20020a0564020542b02903875c5e7a00so9654964edx.6 for ; Thu, 29 Apr 2021 10:04:33 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=SkmfPEEeSMpru7vcjYlKwq7lcoPmko9D6J+Ivt9Ayfk=; b=ryT6mm6SjETBMSNi8814fLT7XHNTqs+MJ7Xotu5JOGEGoD67SogsLDqNlICLYQ0mgG 283cy7zZc0TH6cnpzEcMw6+/Ls0ZG5OKWkgu+RgI+LsrwUnXWR1p/ki7+SoqDbI60d6N H3qzvHS2PBfAVK1OdMypWaGrQ2WIgGBB7wUatqTRDIutkrR4IyX6QWQV/YhUxdl5DwVn FeMDCUcq3xF0Qbue+IIvbIwswjeIew2l0V9IfUBK+908UnTdYc/pptRQIsaBd5Ijwq/C /qgGFrtmDKqJDN/B7Blb3aEZKcIdgwccX9NcmxlysBG2Pt6eaG/wPDR2/THBt6r0D5Wn Dvlw== X-Gm-Message-State: AOAM5328YV4Rx+Wk8VhyfryUf9vuvBrS3FlA4b27Q0CAAg0hCj45vDWz 7oP5tMXFNl4Rwd8nDKYLhHZwEF4yiPSUE4d24WIjhu8CcPg/zQF4DHPl3Z5sePZ9Jyl785DdLlq AISwRspJiw1ps0eHpXBUG7rE10EXRsS6aDq/Nhp+2ijbuGKv0Njv1TEOX3KhFIBczeb8GjzMLN0 8= X-Received: by 2002:a17:906:2dc6:: with SMTP id h6mr867043eji.477.1619715872408; Thu, 29 Apr 2021 10:04:32 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxiWTfEVtxZ+VR8F40uJKWurO38xiBvUjOMFkX59+WH7s2cCEWD/VP932+1QpLBpAoLtIxaKA== X-Received: by 2002:a17:906:2dc6:: with SMTP id h6mr867020eji.477.1619715872232; Thu, 29 Apr 2021 10:04:32 -0700 (PDT) Received: from lore-desk.redhat.com ([151.66.28.185]) by smtp.gmail.com with ESMTPSA id re26sm299250ejb.3.2021.04.29.10.04.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Apr 2021 10:04:31 -0700 (PDT) From: Lorenzo Bianconi To: dev@openvswitch.org Date: Thu, 29 Apr 2021 19:04:18 +0200 Message-Id: <75b9a627304407260bf583a4851cab6182cc9210.1619715319.git.lorenzo.bianconi@redhat.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: References: MIME-Version: 1.0 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=lorenzo.bianconi@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Cc: dceara@redhat.com Subject: [ovs-dev] [PATCH ovn 5/5] NEWS: Add CoPP support. 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: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Dumitru Ceara Signed-off-by: Dumitru Ceara Signed-off-by: Lorenzo Bianconi --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index 1ddde15f8..de6f492c9 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,7 @@ Post-v21.03.0 'use_parallel_build' to enable it. It is disabled by default. - Support vlan-passthru mode for tag=0 localnet ports. - Support custom 802.11ad EthType for localnet ports. + - Added Control Plane Protection support (control plane traffic metering). OVN v21.03.0 - 12 Mar 2021 -------------------------