From patchwork Thu Jul 11 15:48:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1130863 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45l11z5nn3z9sNF for ; Fri, 12 Jul 2019 01:58:47 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 9458E5260; Thu, 11 Jul 2019 15:58:09 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id B200651B1 for ; Thu, 11 Jul 2019 15:49:32 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-wr1-f45.google.com (mail-wr1-f45.google.com [209.85.221.45]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 54DF587C for ; Thu, 11 Jul 2019 15:49:31 +0000 (UTC) Received: by mail-wr1-f45.google.com with SMTP id g17so6854633wrr.5 for ; Thu, 11 Jul 2019 08:49:31 -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=SHKI5kvPKUyUkgR21soDFVXFwoEdfltvSkZDciQZ//4=; b=LRp3ql4y4cvuh7imCscxF1eY8s2lTzu57UEHCNByZTxLrA4R0GAAoMVokAaMpTHjGL V3bhNW6Diu8x33Jue0GxEaGc5EVuhZAmkOoo67pdPK9iT8zRxzsZDnP3waXanvWWMoct /TbNI22D+hE/7OHx5BcCSpBv6/5DpKLG4vi7QargkuCkrWONmi7Skjc3EIsqjjqAbnDZ tYKLta+HhTN2bN3xBdIOk+vafEgrSxHeHFO9R/n3uANpME3a0pC7FeCVU9gITswN0ZDH TiBBbUHRZ1/J5KUDELWtZQ+yTQzCK3Ov0UjIWK6/MDqSQODbyTSLdqi9t9aVOTzZkToR Y6bw== X-Gm-Message-State: APjAAAURgpkJKK3dIslZzNhZJ549SvbhGo4oqpVW7cjJKmmWBWDCsoBY tIbcCuTle0HIpRwp7wX7CcR2GaZp6mE= X-Google-Smtp-Source: APXvYqwBxOIUJsHmcHYI7H2UtDs+0pzUHhF4F++hfM8AkJzazBb2DxQewordKmHck+1WOKboCCcCcQ== X-Received: by 2002:adf:b1d0:: with SMTP id r16mr6032386wra.332.1562860169675; Thu, 11 Jul 2019 08:49:29 -0700 (PDT) Received: from localhost.localdomain.com (nat-pool-mxp-t.redhat.com. [149.6.153.186]) by smtp.gmail.com with ESMTPSA id e6sm6507334wrw.23.2019.07.11.08.49.26 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Thu, 11 Jul 2019 08:49:27 -0700 (PDT) From: Lorenzo Bianconi To: ovs-dev@openvswitch.org Date: Thu, 11 Jul 2019 17:48:43 +0200 Message-Id: <5b98c53626870def25bf96042f8e632d6e749d64.1562858727.git.lorenzo.bianconi@redhat.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 1/3] OVN: introduce Controller_Event table X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Add Controller_Event table to OVN SBDB in order to report CMS related event. Introduce event_table hashmap array and controller_event related structures to ovn-controller in order to track pending events forwarded by ovs-vswitchd. Moreover integrate event_table hashmap array with event_table ovn-sbdb table Signed-off-by: Mark Michelson Co-authored-by: Mark Michelson Signed-off-by: Lorenzo Bianconi --- include/ovn/logical-fields.h | 7 ++ ovn/controller/ovn-controller.c | 10 +++ ovn/controller/pinctrl.c | 151 ++++++++++++++++++++++++++++++++ ovn/controller/pinctrl.h | 2 + ovn/lib/logical-fields.c | 21 +++++ ovn/ovn-sb.ovsschema | 20 ++++- ovn/ovn-sb.xml | 40 +++++++++ 7 files changed, 248 insertions(+), 3 deletions(-) diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h index 164b338b5..9bac8e027 100644 --- a/include/ovn/logical-fields.h +++ b/include/ovn/logical-fields.h @@ -20,6 +20,11 @@ struct shash; +enum ovn_controller_event { + OVN_EVENT_EMPTY_LB_BACKENDS = 0, + OVN_EVENT_MAX, +}; + /* Logical fields. * * These values are documented in ovn-architecture(7), please update the @@ -118,6 +123,8 @@ ovn_field_from_id(enum ovn_field_id id) return &ovn_fields[id]; } +const char *event_to_string(enum ovn_controller_event event); +int string_to_event(const char *s); const struct ovn_field *ovn_field_from_name(const char *name); void ovn_destroy_ovnfields(void); #endif /* ovn/lib/logical-fields.h */ diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c index c4883aa6d..1a90b702e 100644 --- a/ovn/controller/ovn-controller.c +++ b/ovn/controller/ovn-controller.c @@ -133,6 +133,8 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl, * Monitor Logical_Flow, MAC_Binding, Multicast_Group, and DNS tables for * local datapaths. * + * Monitor Controller_Event rows for local chassis. + * * We always monitor patch ports because they allow us to see the linkages * between related logical datapaths. That way, when we know that we have * a VIF on a particular logical switch, we immediately know to monitor all @@ -142,6 +144,7 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl, struct ovsdb_idl_condition mb = OVSDB_IDL_CONDITION_INIT(&mb); struct ovsdb_idl_condition mg = OVSDB_IDL_CONDITION_INIT(&mg); struct ovsdb_idl_condition dns = OVSDB_IDL_CONDITION_INIT(&dns); + struct ovsdb_idl_condition ce = OVSDB_IDL_CONDITION_INIT(&ce); sbrec_port_binding_add_clause_type(&pb, OVSDB_F_EQ, "patch"); /* XXX: We can optimize this, if we find a way to only monitor * ports that have a Gateway_Chassis that point's to our own @@ -165,6 +168,9 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl, sbrec_port_binding_add_clause_options(&pb, OVSDB_F_INCLUDES, &l2); const struct smap l3 = SMAP_CONST1(&l3, "l3gateway-chassis", id); sbrec_port_binding_add_clause_options(&pb, OVSDB_F_INCLUDES, &l3); + + sbrec_controller_event_add_clause_chassis(&ce, OVSDB_F_EQ, + &chassis->header_.uuid); } if (local_ifaces) { const char *name; @@ -191,11 +197,13 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl, sbrec_mac_binding_set_condition(ovnsb_idl, &mb); sbrec_multicast_group_set_condition(ovnsb_idl, &mg); sbrec_dns_set_condition(ovnsb_idl, &dns); + sbrec_controller_event_set_condition(ovnsb_idl, &ce); ovsdb_idl_condition_destroy(&pb); ovsdb_idl_condition_destroy(&lf); ovsdb_idl_condition_destroy(&mb); ovsdb_idl_condition_destroy(&mg); ovsdb_idl_condition_destroy(&dns); + ovsdb_idl_condition_destroy(&ce); } static const char * @@ -1981,6 +1989,8 @@ main(int argc, char *argv[]) sbrec_port_binding_by_name, sbrec_mac_binding_by_lport_ip, sbrec_dns_table_get(ovnsb_idl_loop.idl), + sbrec_controller_event_table_get( + ovnsb_idl_loop.idl), br_int, chassis, &ed_runtime_data.local_datapaths, &ed_runtime_data.active_tunnels); diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c index a442738a0..b8ed375fe 100644 --- a/ovn/controller/pinctrl.c +++ b/ovn/controller/pinctrl.c @@ -226,6 +226,153 @@ static bool may_inject_pkts(void); COVERAGE_DEFINE(pinctrl_drop_put_mac_binding); COVERAGE_DEFINE(pinctrl_drop_buffered_packets_map); +COVERAGE_DEFINE(pinctrl_drop_controller_event); + +struct empty_lb_backends_event { + struct hmap_node hmap_node; + long long int timestamp; + + char *vip; + char *protocol; + char *load_balancer; +}; + +static struct hmap event_table[OVN_EVENT_MAX]; +static int64_t event_seq_num; + +static void +init_event_table(void) +{ + for (size_t i = 0; i < OVN_EVENT_MAX; i++) { + hmap_init(&event_table[i]); + } +} + +#define EVENT_TIMEOUT 10000 +static void +empty_lb_backends_event_gc(bool flush) +{ + struct empty_lb_backends_event *cur_ce, *next_ce; + long long int now = time_msec(); + + HMAP_FOR_EACH_SAFE (cur_ce, next_ce, hmap_node, + &event_table[OVN_EVENT_EMPTY_LB_BACKENDS]) { + if ((now < cur_ce->timestamp + EVENT_TIMEOUT) && !flush) { + continue; + } + + free(cur_ce->vip); + free(cur_ce->protocol); + free(cur_ce->load_balancer); + hmap_remove(&event_table[OVN_EVENT_EMPTY_LB_BACKENDS], + &cur_ce->hmap_node); + free(cur_ce); + } +} + +static void +event_table_gc(bool flush) +{ + empty_lb_backends_event_gc(flush); +} + +static void +event_table_destroy(void) +{ + event_table_gc(true); + for (size_t i = 0; i < OVN_EVENT_MAX; i++) { + hmap_destroy(&event_table[i]); + } +} + +static struct empty_lb_backends_event * +pinctrl_find_empty_lb_backends_event(char *vip, char *protocol, + char *load_balancer, uint32_t hash) +{ + struct empty_lb_backends_event *ce; + HMAP_FOR_EACH_WITH_HASH (ce, hmap_node, hash, + &event_table[OVN_EVENT_EMPTY_LB_BACKENDS]) { + if (!strcmp(ce->vip, vip) && + !strcmp(ce->protocol, protocol) && + !strcmp(ce->load_balancer, load_balancer)) { + return ce; + } + } + return NULL; +} + +static const struct sbrec_controller_event * +empty_lb_backends_lookup(struct empty_lb_backends_event *event, + const struct sbrec_controller_event_table *ce_table, + const struct sbrec_chassis *chassis) +{ + const struct sbrec_controller_event *sbrec_event; + const char *event_type = event_to_string(OVN_EVENT_EMPTY_LB_BACKENDS); + char ref_uuid[UUID_LEN + 1]; + sprintf(ref_uuid, UUID_FMT, UUID_ARGS(&chassis->header_.uuid)); + + SBREC_CONTROLLER_EVENT_TABLE_FOR_EACH (sbrec_event, ce_table) { + if (strcmp(sbrec_event->event_type, event_type)) { + continue; + } + + char chassis_uuid[UUID_LEN + 1]; + sprintf(chassis_uuid, UUID_FMT, + UUID_ARGS(&sbrec_event->chassis->header_.uuid)); + if (strcmp(ref_uuid, chassis_uuid)) { + continue; + } + + const char *vip = smap_get(&sbrec_event->event_info, "vip"); + const char *protocol = smap_get(&sbrec_event->event_info, "protocol"); + const char *load_balancer = smap_get(&sbrec_event->event_info, + "load_balancer"); + + if (!strcmp(event->vip, vip) && + !strcmp(event->protocol, protocol) && + !strcmp(event->load_balancer, load_balancer)) { + return sbrec_event; + } + } + + return NULL; +} + +static void +controller_event_run(struct ovsdb_idl_txn *ovnsb_idl_txn, + const struct sbrec_controller_event_table *ce_table, + const struct sbrec_chassis *chassis) + OVS_REQUIRES(pinctrl_mutex) +{ + if (!ovnsb_idl_txn) { + goto out; + } + + struct empty_lb_backends_event *empty_lbs; + HMAP_FOR_EACH (empty_lbs, hmap_node, + &event_table[OVN_EVENT_EMPTY_LB_BACKENDS]) { + const struct sbrec_controller_event *event; + + event = empty_lb_backends_lookup(empty_lbs, ce_table, chassis); + if (!event) { + struct smap event_info = SMAP_INITIALIZER(&event_info); + + smap_add(&event_info, "vip", empty_lbs->vip); + smap_add(&event_info, "protocol", empty_lbs->protocol); + smap_add(&event_info, "load_balancer", empty_lbs->load_balancer); + + event = sbrec_controller_event_insert(ovnsb_idl_txn); + sbrec_controller_event_set_event_type(event, + event_to_string(OVN_EVENT_EMPTY_LB_BACKENDS)); + sbrec_controller_event_set_seq_num(event, ++event_seq_num); + sbrec_controller_event_set_event_info(event, &event_info); + sbrec_controller_event_set_chassis(event, chassis); + } + } + +out: + event_table_gc(!!ovnsb_idl_txn); +} void pinctrl_init(void) @@ -234,6 +381,7 @@ pinctrl_init(void) init_send_garps(); init_ipv6_ras(); init_buffered_packets_map(); + init_event_table(); pinctrl.br_int_name = NULL; pinctrl_handler_seq = seq_create(); pinctrl_main_seq = seq_create(); @@ -1897,6 +2045,7 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, struct ovsdb_idl_index *sbrec_port_binding_by_name, struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, const struct sbrec_dns_table *dns_table, + const struct sbrec_controller_event_table *ce_table, const struct ovsrec_bridge *br_int, const struct sbrec_chassis *chassis, const struct hmap *local_datapaths, @@ -1922,6 +2071,7 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, prepare_ipv6_ras(sbrec_port_binding_by_datapath, sbrec_port_binding_by_name, local_datapaths); sync_dns_cache(dns_table); + controller_event_run(ovnsb_idl_txn, ce_table, chassis); run_buffered_binding(sbrec_port_binding_by_datapath, sbrec_mac_binding_by_lport_ip, local_datapaths); @@ -2270,6 +2420,7 @@ pinctrl_destroy(void) destroy_send_garps(); destroy_ipv6_ras(); destroy_buffered_packets_map(); + event_table_destroy(); destroy_put_mac_bindings(); destroy_dns_cache(); seq_destroy(pinctrl_main_seq); diff --git a/ovn/controller/pinctrl.h b/ovn/controller/pinctrl.h index f61d7056e..fdef27a6d 100644 --- a/ovn/controller/pinctrl.h +++ b/ovn/controller/pinctrl.h @@ -29,6 +29,7 @@ struct ovsdb_idl_txn; struct ovsrec_bridge; struct sbrec_chassis; struct sbrec_dns_table; +struct sbrec_controller_event_table; void pinctrl_init(void); void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, @@ -38,6 +39,7 @@ void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, struct ovsdb_idl_index *sbrec_port_binding_by_name, struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip, const struct sbrec_dns_table *, + const struct sbrec_controller_event_table *, const struct ovsrec_bridge *, const struct sbrec_chassis *, const struct hmap *local_datapaths, const struct sset *active_tunnels); diff --git a/ovn/lib/logical-fields.c b/ovn/lib/logical-fields.c index 579537d6b..adcbbe02d 100644 --- a/ovn/lib/logical-fields.c +++ b/ovn/lib/logical-fields.c @@ -225,6 +225,27 @@ ovn_init_symtab(struct shash *symtab) expr_symtab_add_ovn_field(symtab, "icmp4.frag_mtu", OVN_ICMP4_FRAG_MTU); } +const char * +event_to_string(enum ovn_controller_event event) +{ + switch (event) { + case OVN_EVENT_EMPTY_LB_BACKENDS: + return "empty_lb_backends"; + case OVN_EVENT_MAX: + default: + return ""; + } +} + +int +string_to_event(const char *s) +{ + if (!strcmp(s, "empty_lb_backends")) { + return OVN_EVENT_EMPTY_LB_BACKENDS; + } + return -1; +} + const struct ovn_field * ovn_field_from_name(const char *name) { diff --git a/ovn/ovn-sb.ovsschema b/ovn/ovn-sb.ovsschema index 2b543c6f5..eced7c4ed 100644 --- a/ovn/ovn-sb.ovsschema +++ b/ovn/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "2.3.0", - "cksum": "3092285199 17409", + "version": "2.4.0", + "cksum": "1795697952 18106", "tables": { "SB_Global": { "columns": { @@ -349,4 +349,18 @@ "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, "indexes": [["name"]], - "isRoot": true}}} + "isRoot": true}, + "Controller_Event": { + "columns": { + "event_type": {"type": {"key": {"type": "string", + "enum": ["set", ["empty_lb_backends"]]}}}, + "event_info": {"type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}, + "chassis": {"type": {"key": {"type": "uuid", + "refTable": "Chassis", + "refType": "weak"}, + "min": 0, "max": 1}}, + "seq_num": {"type": {"key": "integer"}} + }, + "isRoot": true + }}} diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml index c2faa2c5f..91f867ffb 100644 --- a/ovn/ovn-sb.xml +++ b/ovn/ovn-sb.xml @@ -3494,4 +3494,44 @@ tcp.flags = RST; + +

+ Database table used by ovn-controller to report CMS + related events. Please note there is no guarantee a given event is + written exactly once in the db. It is CMS responsibility to squash + duplicated lines or to filter out duplicated events +

+ + Event type occurred + + +

+ Key-value pairs used to specify event info to the CMS. + Possible values are: +

+
    +
  • + vip: VIP reported for the empty_lb_backends + event +
  • +
  • + protocol: Transport protocol reported for the + empty_lb_backends event +
  • +
  • + load_balancer: UUID of the load balancer reported for + the empty_lb_backends event +
  • +
+
+ + This column is a record to identify the chassis + that has managed a given event. + + + Event sequence number. Global counter for controller generated events. + It can be used by the CMS to detect possible duplication of the same + event. + +
From patchwork Thu Jul 11 15:48:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1130864 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45l12j0Sv8z9sNF for ; Fri, 12 Jul 2019 01:59:25 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 70B745263; Thu, 11 Jul 2019 15:58:10 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id D476151B1 for ; Thu, 11 Jul 2019 15:49:34 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-wm1-f67.google.com (mail-wm1-f67.google.com [209.85.128.67]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 1127F87C for ; Thu, 11 Jul 2019 15:49:32 +0000 (UTC) Received: by mail-wm1-f67.google.com with SMTP id z23so1981178wma.4 for ; Thu, 11 Jul 2019 08:49: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=Gf3S62cfdGi7ENKy8HXvyLA/TvVaSRPFKu6H97sh4NE=; b=h8+4/STxsyezSxYux8Z96l+MfPG3OlgDWwCn5/z9f5bOy3BHFnJHDbNFiO4DjiSdzw 06u7xHCek1ZgAar5Fcy7URUcBmDcCo015Nxm+jkgVDojBIlB4ZjLS3JXXNJm6R4/J/Vq SJXTGXBvfYXcA6NQbek2ypB/rrENL62zlfdwp/5vETTJHRRt/Gk7TCupmHSxtk4FOTJV XHHDwEMRES0QKotufJNJBMvdcCe0tfDYa4VaGzdQnUJQnwuxI6ilKzPJkWyOiCpTC3kw 7Q6J8RMa5QwMRuf8I3+vu6OKG9aCuzoLIzvyTV6NEZQ+CToM+MbiMwVORBlaPOFUJrbA H63A== X-Gm-Message-State: APjAAAV4HCVqwb0Vyw7/8cBkUe4yZ6mA0cxXL9W5W0PAHhSaKNbEm7pf DSvjfPTl7mRVUxyhZD2dRENrMNug/F8= X-Google-Smtp-Source: APXvYqyReCX8Q/+1487S4W5C6RnExzKp/xCmpizEpx3+l3fqaudI7FTzOjj2OBkknephzFI0z0lcrA== X-Received: by 2002:a1c:544d:: with SMTP id p13mr5076967wmi.78.1562860171104; Thu, 11 Jul 2019 08:49:31 -0700 (PDT) Received: from localhost.localdomain.com (nat-pool-mxp-t.redhat.com. [149.6.153.186]) by smtp.gmail.com with ESMTPSA id e6sm6507334wrw.23.2019.07.11.08.49.30 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Thu, 11 Jul 2019 08:49:30 -0700 (PDT) From: Lorenzo Bianconi To: ovs-dev@openvswitch.org Date: Thu, 11 Jul 2019 17:48:44 +0200 Message-Id: <2ea075d4d0b1ed6f3498387198ac9a1b47680790.1562858727.git.lorenzo.bianconi@redhat.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 2/3] OVN: introduce trigger_event() action X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Add trigger_event() ovn action in order to allow ovs-vswitchd to report CMS related events. This commit introduces a new event, empty_lb_backends. This event is raised if a received packet is destined for a load balancer VIP that has no configured backend destinations. For this event, the event info includes the load balancer VIP, the load balancer UUID, and the transport protocol. The use case for this particular event is for the CMS to supply backend resources to handle this traffic. For example, in Openshift, this event can be used to spin up new containers to handle the incoming traffic. Signed-off-by: Mark Michelson Co-authored-by: Mark Michelson Signed-off-by: Lorenzo Bianconi --- include/ovn/actions.h | 18 +++- ovn/controller/lflow.c | 26 +++++- ovn/controller/pinctrl.c | 114 ++++++++++++++++++++++++ ovn/lib/actions.c | 176 ++++++++++++++++++++++++++++++++++++++ ovn/lib/ovn-l7.h | 46 ++++++++++ ovn/ovn-sb.xml | 21 +++++ ovn/utilities/ovn-trace.c | 3 + tests/ovn.at | 10 +++ tests/test-ovn.c | 11 ++- 9 files changed, 419 insertions(+), 6 deletions(-) diff --git a/include/ovn/actions.h b/include/ovn/actions.h index f42bbc277..5ed70e798 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -83,7 +83,8 @@ struct ovn_extend_table; OVNACT(ND_NS, ovnact_nest) \ OVNACT(SET_METER, ovnact_set_meter) \ OVNACT(OVNFIELD_LOAD, ovnact_load) \ - OVNACT(CHECK_PKT_LARGER, ovnact_check_pkt_larger) + OVNACT(CHECK_PKT_LARGER, ovnact_check_pkt_larger) \ + OVNACT(TRIGGER_EVENT, ovnact_controller_event) /* enum ovnact_type, with a member OVNACT_ for each action. */ enum OVS_PACKED_ENUM ovnact_type { @@ -318,6 +319,14 @@ struct ovnact_check_pkt_larger { struct expr_field dst; /* 1-bit destination field. */ }; +/* OVNACT_EVENT. */ +struct ovnact_controller_event { + struct ovnact ovnact; + int event_type; /* controller event type */ + struct ovnact_gen_option *options; + size_t n_options; +}; + /* Internal use by the helpers below. */ void ovnact_init(struct ovnact *, enum ovnact_type, size_t len); void *ovnact_put(struct ofpbuf *, enum ovnact_type, size_t len); @@ -486,6 +495,9 @@ enum action_opcode { * The actions, in OpenFlow 1.3 format, follow the action_header. */ ACTION_OPCODE_ICMP4_ERROR, + + /* "trigger_event (event_type)" */ + ACTION_OPCODE_EVENT, }; /* Header. */ @@ -515,6 +527,10 @@ struct ovnact_parse_params { /* hmap of 'struct gen_opts_map' to support 'put_nd_ra_opts' action */ const struct hmap *nd_ra_opts; + /* Array of hmap of 'struct gen_opts_map' to support 'trigger_event' + * action */ + const struct controller_event_options *controller_event_opts; + /* Each OVN flow exists in a logical table within a logical pipeline. * These parameters express this context for a set of OVN actions being * parsed: diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c index feb8f8ff7..1aafafb33 100644 --- a/ovn/controller/lflow.c +++ b/ovn/controller/lflow.c @@ -70,6 +70,7 @@ static bool consider_logical_flow( struct hmap *dhcp_opts, struct hmap *dhcpv6_opts, struct hmap *nd_ra_opts, + struct controller_event_options *controller_event_opts, const struct shash *addr_sets, const struct shash *port_groups, const struct sset *active_tunnels, @@ -297,12 +298,16 @@ add_logical_flows( struct hmap nd_ra_opts = HMAP_INITIALIZER(&nd_ra_opts); nd_ra_opts_init(&nd_ra_opts); + struct controller_event_options controller_event_opts; + controller_event_opts_init(&controller_event_opts); + SBREC_LOGICAL_FLOW_TABLE_FOR_EACH (lflow, logical_flow_table) { if (!consider_logical_flow(sbrec_multicast_group_by_name_datapath, sbrec_port_binding_by_name, lflow, local_datapaths, chassis, &dhcp_opts, &dhcpv6_opts, - &nd_ra_opts, addr_sets, port_groups, + &nd_ra_opts, &controller_event_opts, + addr_sets, port_groups, active_tunnels, local_lport_ids, flow_table, group_table, meter_table, lfrr, conj_id_ofs)) { @@ -315,6 +320,7 @@ add_logical_flows( dhcp_opts_destroy(&dhcp_opts); dhcp_opts_destroy(&dhcpv6_opts); nd_ra_opts_destroy(&nd_ra_opts); + controller_event_opts_destroy(&controller_event_opts); } bool @@ -371,6 +377,10 @@ lflow_handle_changed_flows( lflow_resource_destroy_lflow(lfrr, &lflow->header_.uuid); } } + + struct controller_event_options controller_event_opts; + controller_event_opts_init(&controller_event_opts); + SBREC_LOGICAL_FLOW_TABLE_FOR_EACH_TRACKED (lflow, logical_flow_table) { if (!sbrec_logical_flow_is_deleted(lflow)) { /* Now, add/modify existing flows. If the logical @@ -389,7 +399,8 @@ lflow_handle_changed_flows( sbrec_port_binding_by_name, lflow, local_datapaths, chassis, &dhcp_opts, &dhcpv6_opts, - &nd_ra_opts, addr_sets, port_groups, + &nd_ra_opts, &controller_event_opts, + addr_sets, port_groups, active_tunnels, local_lport_ids, flow_table, group_table, meter_table, lfrr, conj_id_ofs)) { @@ -401,6 +412,7 @@ lflow_handle_changed_flows( dhcp_opts_destroy(&dhcp_opts); dhcp_opts_destroy(&dhcpv6_opts); nd_ra_opts_destroy(&nd_ra_opts); + controller_event_opts_destroy(&controller_event_opts); return ret; } @@ -466,6 +478,9 @@ lflow_handle_changed_ref( struct hmap nd_ra_opts = HMAP_INITIALIZER(&nd_ra_opts); nd_ra_opts_init(&nd_ra_opts); + struct controller_event_options controller_event_opts; + controller_event_opts_init(&controller_event_opts); + /* Re-parse the related lflows. */ LIST_FOR_EACH (lrln, ref_list, &rlfn->ref_lflow_head) { const struct sbrec_logical_flow *lflow = @@ -483,11 +498,13 @@ lflow_handle_changed_ref( UUID_ARGS(&lrln->lflow_uuid), ref_type, ref_name); ofctrl_remove_flows(flow_table, &lrln->lflow_uuid); + if (!consider_logical_flow(sbrec_multicast_group_by_name_datapath, sbrec_port_binding_by_name, lflow, local_datapaths, chassis, &dhcp_opts, &dhcpv6_opts, - &nd_ra_opts, addr_sets, port_groups, + &nd_ra_opts, &controller_event_opts, + addr_sets, port_groups, active_tunnels, local_lport_ids, flow_table, group_table, meter_table, lfrr, conj_id_ofs)) { @@ -506,6 +523,7 @@ lflow_handle_changed_ref( dhcp_opts_destroy(&dhcp_opts); dhcp_opts_destroy(&dhcpv6_opts); nd_ra_opts_destroy(&nd_ra_opts); + controller_event_opts_destroy(&controller_event_opts); return ret; } @@ -530,6 +548,7 @@ consider_logical_flow( struct hmap *dhcp_opts, struct hmap *dhcpv6_opts, struct hmap *nd_ra_opts, + struct controller_event_options *controller_event_opts, const struct shash *addr_sets, const struct shash *port_groups, const struct sset *active_tunnels, @@ -574,6 +593,7 @@ consider_logical_flow( .dhcp_opts = dhcp_opts, .dhcpv6_opts = dhcpv6_opts, .nd_ra_opts = nd_ra_opts, + .controller_event_opts = controller_event_opts, .pipeline = ingress ? OVNACT_P_INGRESS : OVNACT_P_EGRESS, .n_tables = LOG_PIPELINE_LEN, diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c index b8ed375fe..81b91cf68 100644 --- a/ovn/controller/pinctrl.c +++ b/ovn/controller/pinctrl.c @@ -211,6 +211,10 @@ static void pinctrl_handle_put_icmp4_frag_mtu(struct rconn *swconn, struct ofputil_packet_in *pin, struct ofpbuf *userdata, struct ofpbuf *continuation); +static void +pinctrl_handle_event(struct ofpbuf *userdata) + OVS_REQUIRES(pinctrl_mutex); +static void wait_controller_event(struct ovsdb_idl_txn *ovnsb_idl_txn); static void init_ipv6_ras(void); static void destroy_ipv6_ras(void); static void ipv6_ra_wait(long long int send_ipv6_ra_time); @@ -1897,6 +1901,12 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg) &pin, &userdata, &continuation); break; + case ACTION_OPCODE_EVENT: + ovs_mutex_lock(&pinctrl_mutex); + pinctrl_handle_event(&userdata); + ovs_mutex_unlock(&pinctrl_mutex); + break; + default: VLOG_WARN_RL(&rl, "unrecognized packet-in opcode %"PRIu32, ntohl(ah->opcode)); @@ -2405,6 +2415,7 @@ void pinctrl_wait(struct ovsdb_idl_txn *ovnsb_idl_txn) { wait_put_mac_bindings(ovnsb_idl_txn); + wait_controller_event(ovnsb_idl_txn); int64_t new_seq = seq_read(pinctrl_main_seq); seq_wait(pinctrl_main_seq, new_seq); } @@ -3448,3 +3459,106 @@ exit: dp_packet_delete(pkt_out); } } + +static void +wait_controller_event(struct ovsdb_idl_txn *ovnsb_idl_txn) +{ + if (!ovnsb_idl_txn) { + return; + } + + for (size_t i = 0; i < OVN_EVENT_MAX; i++) { + if (!hmap_is_empty(&event_table[i])) { + poll_immediate_wake(); + break; + } + } +} + +static bool +pinctrl_handle_empty_lb_backends_opts(struct ofpbuf *userdata) +{ + struct controller_event_opt_header *userdata_opt; + uint32_t hash = 0; + char *vip = NULL; + char *protocol = NULL; + char *load_balancer = NULL; + + while (userdata->size) { + userdata_opt = ofpbuf_try_pull(userdata, sizeof *userdata_opt); + if (!userdata_opt) { + return false; + } + size_t size = ntohs(userdata_opt->size); + char *userdata_opt_data = ofpbuf_try_pull(userdata, size); + if (!userdata_opt_data) { + return false; + } + switch (ntohs(userdata_opt->opt_code)) { + case EMPTY_LB_VIP: + vip = xmemdup0(userdata_opt_data, size); + break; + case EMPTY_LB_PROTOCOL: + protocol = xmemdup0(userdata_opt_data, size); + break; + case EMPTY_LB_LOAD_BALANCER: + load_balancer = xmemdup0(userdata_opt_data, size); + break; + default: + OVS_NOT_REACHED(); + } + hash = hash_bytes(userdata_opt_data, size, hash); + } + if (!vip || !protocol || !load_balancer) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "missing lb parameters in userdata"); + return false; + } + + struct empty_lb_backends_event *event; + + event = pinctrl_find_empty_lb_backends_event(vip, protocol, + load_balancer, hash); + if (!event) { + if (hmap_count(&event_table[OVN_EVENT_EMPTY_LB_BACKENDS]) >= 1000) { + COVERAGE_INC(pinctrl_drop_controller_event); + return false; + } + + event = xzalloc(sizeof *event); + hmap_insert(&event_table[OVN_EVENT_EMPTY_LB_BACKENDS], + &event->hmap_node, hash); + event->vip = vip; + event->protocol = protocol; + event->load_balancer = load_balancer; + event->timestamp = time_msec(); + notify_pinctrl_main(); + } else { + free(vip); + free(protocol); + free(load_balancer); + } + return true; +} + +static void +pinctrl_handle_event(struct ofpbuf *userdata) + OVS_REQUIRES(pinctrl_mutex) +{ + ovs_be32 *pevent; + + pevent = ofpbuf_try_pull(userdata, sizeof *pevent); + if (!pevent) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "event not present in the userdata"); + return; + } + + switch (ntohl(*pevent)) { + case OVN_EVENT_EMPTY_LB_BACKENDS: + pinctrl_handle_empty_lb_backends_opts(userdata); + break; + default: + return; + } +} diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c index d132214bf..041fd1a3f 100644 --- a/ovn/lib/actions.c +++ b/ovn/lib/actions.c @@ -38,6 +38,8 @@ #include "packets.h" #include "openvswitch/shash.h" #include "simap.h" +#include "uuid.h" +#include "socket-util.h" VLOG_DEFINE_THIS_MODULE(actions); @@ -1259,6 +1261,21 @@ format_CLONE(const struct ovnact_nest *nest, struct ds *s) format_nested_action(nest, "clone", s); } +static void +format_TRIGGER_EVENT(const struct ovnact_controller_event *event, + struct ds *s) +{ + ds_put_format(s, "trigger_event(event = \"%s\"", + event_to_string(event->event_type)); + for (const struct ovnact_gen_option *o = event->options; + o < &event->options[event->n_options]; o++) { + ds_put_cstr(s, ", "); + ds_put_format(s, "%s = ", o->option->name); + expr_constant_set_format(&o->value, s); + } + ds_put_cstr(s, ");"); +} + static void encode_nested_actions(const struct ovnact_nest *on, const struct ovnact_encode_params *ep, @@ -1362,6 +1379,52 @@ encode_CLONE(const struct ovnact_nest *on, ofpact_finish_CLONE(ofpacts, &clone); } +static void +encode_event_empty_lb_backends_opts(struct ofpbuf *ofpacts, + const struct ovnact_controller_event *event) +{ + for (const struct ovnact_gen_option *o = event->options; + o < &event->options[event->n_options]; o++) { + struct controller_event_opt_header *hdr = + ofpbuf_put_uninit(ofpacts, sizeof *hdr); + const union expr_constant *c = o->value.values; + size_t size; + hdr->opt_code = htons(o->option->code); + if (!strcmp(o->option->type, "str")) { + size = strlen(c->string); + hdr->size = htons(size); + ofpbuf_put(ofpacts, c->string, size); + } else { + /* All empty_lb_backends fields are of type 'str' */ + OVS_NOT_REACHED(); + } + } +} + +static void +encode_TRIGGER_EVENT(const struct ovnact_controller_event *event, + const struct ovnact_encode_params *ep OVS_UNUSED, + struct ofpbuf *ofpacts) +{ + size_t oc_offset; + + oc_offset = encode_start_controller_op(ACTION_OPCODE_EVENT, false, + NX_CTLR_NO_METER, ofpacts); + ovs_be32 ofs = htonl(event->event_type); + ofpbuf_put(ofpacts, &ofs, sizeof ofs); + + switch (event->event_type) { + case OVN_EVENT_EMPTY_LB_BACKENDS: + encode_event_empty_lb_backends_opts(ofpacts, event); + break; + case OVN_EVENT_MAX: + default: + OVS_NOT_REACHED(); + } + + encode_finish_controller_op(oc_offset, ofpacts); +} + static void ovnact_nest_free(struct ovnact_nest *on) { @@ -1576,6 +1639,117 @@ free_gen_options(struct ovnact_gen_option *options, size_t n) free(options); } +static void +validate_empty_lb_backends(struct action_context *ctx, + const struct ovnact_gen_option *options, + size_t n_options) +{ + for (const struct ovnact_gen_option *o = options; + o < &options[n_options]; o++) { + const union expr_constant *c = o->value.values; + struct sockaddr_storage ss; + struct uuid uuid; + + if (o->value.n_values > 1 || !c->string) { + lexer_error(ctx->lexer, "Invalid value for \"%s\" option", + o->option->name); + return; + } + + switch (o->option->code) { + case EMPTY_LB_VIP: + if (!inet_parse_active(c->string, 0, &ss, false)) { + lexer_error(ctx->lexer, "Invalid load balancer VIP '%s'", + c->string); + return; + } + break; + case EMPTY_LB_PROTOCOL: + if (strcmp(c->string, "tcp") && strcmp(c->string, "udp")) { + lexer_error(ctx->lexer, + "Load balancer protocol '%s' is not 'tcp' or 'udp'", + c->string); + return; + } + break; + case EMPTY_LB_LOAD_BALANCER: + if (!uuid_from_string(&uuid, c->string)) { + lexer_error(ctx->lexer, "Load balancer '%s' is not a UUID", + c->string); + return; + } + break; + } + } +} + +static void +parse_trigger_event(struct action_context *ctx, + struct ovnact_controller_event *event) +{ + int event_type = 0; + + lexer_force_match(ctx->lexer, LEX_T_LPAREN); + + /* Event type must be listed first */ + if (!lexer_match_id(ctx->lexer, "event")) { + lexer_syntax_error(ctx->lexer, "Expecting 'event' option"); + return; + } + if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) { + return; + } + + if (ctx->lexer->token.type != LEX_T_STRING || + strlen(ctx->lexer->token.s) >= 64) { + lexer_syntax_error(ctx->lexer, "Expecting string"); + return; + } + + event_type = string_to_event(ctx->lexer->token.s); + if (event_type < 0 || event_type >= OVN_EVENT_MAX) { + lexer_syntax_error(ctx->lexer, "Unknown event '%d'", event_type); + return; + } + + event->event_type = event_type; + lexer_get(ctx->lexer); + + lexer_match(ctx->lexer, LEX_T_COMMA); + + size_t allocated_options = 0; + while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) { + if (event->n_options >= allocated_options) { + event->options = x2nrealloc(event->options, &allocated_options, + sizeof *event->options); + } + + 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; + } + + lexer_match(ctx->lexer, LEX_T_COMMA); + } + + switch (event_type) { + case OVN_EVENT_EMPTY_LB_BACKENDS: + validate_empty_lb_backends(ctx, event->options, event->n_options); + break; + default: + OVS_NOT_REACHED(); + } +} + +static void +ovnact_controller_event_free(struct ovnact_controller_event *event OVS_UNUSED) +{ +} + static void parse_put_opts(struct action_context *ctx, const struct expr_field *dst, struct ovnact_put_opts *po, const struct hmap *gen_opts, @@ -2514,6 +2688,8 @@ parse_action(struct action_context *ctx) parse_LOG(ctx); } else if (lexer_match_id(ctx->lexer, "set_meter")) { parse_set_meter_action(ctx); + } else if (lexer_match_id(ctx->lexer, "trigger_event")) { + parse_trigger_event(ctx, ovnact_put_TRIGGER_EVENT(ctx->ovnacts)); } else { lexer_syntax_error(ctx->lexer, "expecting action"); } diff --git a/ovn/lib/ovn-l7.h b/ovn/lib/ovn-l7.h index 362f537da..c93def450 100644 --- a/ovn/lib/ovn-l7.h +++ b/ovn/lib/ovn-l7.h @@ -22,6 +22,7 @@ #include #include "openvswitch/hmap.h" #include "hash.h" +#include "ovn/logical-fields.h" /* Generic options map which is used to store dhcpv4 opts and dhcpv6 opts. */ struct gen_opts_map { @@ -273,4 +274,49 @@ nd_ra_opts_init(struct hmap *nd_ra_opts) nd_ra_opt_add(nd_ra_opts, "mtu", ND_OPT_MTU, "uint32"); } +#define EMPTY_LB_VIP 1 +#define EMPTY_LB_PROTOCOL 2 +#define EMPTY_LB_LOAD_BALANCER 3 + +/* Used in the OpenFlow PACKET_IN userdata */ +struct controller_event_opt_header { + ovs_be16 opt_code; + ovs_be16 size; +}; + +struct controller_event_options { + struct hmap event_opts[OVN_EVENT_MAX]; +}; + +static inline void +controller_event_opt_add(struct controller_event_options *event_opts, + enum ovn_controller_event event_type, char *opt_name, + size_t opt_code, char *opt_type) +{ + gen_opt_add(&event_opts->event_opts[event_type], opt_name, opt_code, + opt_type); +} + +static inline void +controller_event_opts_init(struct controller_event_options *opts) +{ + for (size_t i = 0; i < OVN_EVENT_MAX; i++) { + hmap_init(&opts->event_opts[i]); + } + controller_event_opt_add(opts, OVN_EVENT_EMPTY_LB_BACKENDS, "vip", + EMPTY_LB_VIP, "str"); + controller_event_opt_add(opts, OVN_EVENT_EMPTY_LB_BACKENDS, "protocol", + EMPTY_LB_PROTOCOL, "str"); + controller_event_opt_add(opts, OVN_EVENT_EMPTY_LB_BACKENDS, + "load_balancer", EMPTY_LB_LOAD_BALANCER, "str"); +} + +static inline void +controller_event_opts_destroy(struct controller_event_options *opts) +{ + for (size_t i = 0; i < OVN_EVENT_MAX; i++) { + gen_opts_destroy(&opts->event_opts[i]); + } +} + #endif /* OVN_DHCP_H */ diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml index 91f867ffb..51383b286 100644 --- a/ovn/ovn-sb.xml +++ b/ovn/ovn-sb.xml @@ -1988,6 +1988,27 @@ tcp.flags = RST;

Prerequisite: tcp

+ +
trigger_event;
+
+

+ This action is used to allow ovs-vswitchd to report CMS related + events writing them in table. + Supported event: +

+ +
    +
  • +

    + empty_lb_backends. This event is raised if a + received packet is destined for a load balancer VIP that has + no configured backend destinations. For this event, the event + info includes the load balancer VIP, the load balancer UUID, + and the transport protocol. +

    +
  • +
+
diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c index fff432d61..91503871f 100644 --- a/ovn/utilities/ovn-trace.c +++ b/ovn/utilities/ovn-trace.c @@ -2135,6 +2135,9 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len, execute_ovnfield_load(ovnact_get_OVNFIELD_LOAD(a), super); break; + case OVNACT_TRIGGER_EVENT: + break; + case OVNACT_CHECK_PKT_LARGER: break; } diff --git a/tests/ovn.at b/tests/ovn.at index 4da7059b3..e9ec715df 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -1333,6 +1333,16 @@ tcp_reset { }; encodes as controller(userdata=00.00.00.0b.00.00.00.00) has prereqs tcp +# trigger_event +trigger_event(event = "empty_lb_backends", 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) + +# 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 = "sctp", load_balancer = "12345678-abcd-9876-fedc-11119f8e7d6c"); + Load balancer protocol 'sctp' is not 'tcp' or 'udp' +trigger_event(event = "empty_lb_backends", vip = "10.0.0.1:80", protocol = "tcp", load_balancer = "bacon"); + Load balancer 'bacon' is not a UUID + # Contradictionary prerequisites (allowed but not useful): ip4.src = ip6.src[0..31]; encodes as move:NXM_NX_IPV6_SRC[0..31]->NXM_OF_IP_SRC[] diff --git a/tests/test-ovn.c b/tests/test-ovn.c index 27e65266d..0b9e8246e 100644 --- a/tests/test-ovn.c +++ b/tests/test-ovn.c @@ -157,7 +157,8 @@ create_symtab(struct shash *symtab) static void create_gen_opts(struct hmap *dhcp_opts, struct hmap *dhcpv6_opts, - struct hmap *nd_ra_opts) + struct hmap *nd_ra_opts, + struct controller_event_options *event_opts) { hmap_init(dhcp_opts); dhcp_opt_add(dhcp_opts, "offerip", 0, "ipv4"); @@ -197,6 +198,9 @@ create_gen_opts(struct hmap *dhcp_opts, struct hmap *dhcpv6_opts, /* IPv6 ND RA options. */ hmap_init(nd_ra_opts); nd_ra_opts_init(nd_ra_opts); + + /* OVN controller events options. */ + controller_event_opts_init(event_opts); } static void @@ -1229,12 +1233,13 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED) struct hmap dhcp_opts; struct hmap dhcpv6_opts; struct hmap nd_ra_opts; + struct controller_event_options event_opts; struct simap ports; struct ds input; bool ok = true; create_symtab(&symtab); - create_gen_opts(&dhcp_opts, &dhcpv6_opts, &nd_ra_opts); + create_gen_opts(&dhcp_opts, &dhcpv6_opts, &nd_ra_opts, &event_opts); /* Initialize group ids. */ struct ovn_extend_table group_table; @@ -1264,6 +1269,7 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED) .dhcp_opts = &dhcp_opts, .dhcpv6_opts = &dhcpv6_opts, .nd_ra_opts = &nd_ra_opts, + .controller_event_opts = &event_opts, .n_tables = 24, .cur_ltable = 10, }; @@ -1351,6 +1357,7 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED) dhcp_opts_destroy(&dhcp_opts); dhcp_opts_destroy(&dhcpv6_opts); nd_ra_opts_destroy(&nd_ra_opts); + controller_event_opts_destroy(&event_opts); ovn_extend_table_destroy(&group_table); ovn_extend_table_destroy(&meter_table); exit(ok ? EXIT_SUCCESS : EXIT_FAILURE); From patchwork Thu Jul 11 15:48:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 1130865 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45l13T3fsjz9sNF for ; Fri, 12 Jul 2019 02:00:05 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 311375258; Thu, 11 Jul 2019 15:58:11 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 11B4051B1 for ; Thu, 11 Jul 2019 15:49:35 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-wm1-f66.google.com (mail-wm1-f66.google.com [209.85.128.66]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 4EA80891 for ; Thu, 11 Jul 2019 15:49:34 +0000 (UTC) Received: by mail-wm1-f66.google.com with SMTP id s3so6179788wms.2 for ; Thu, 11 Jul 2019 08:49:34 -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=WbR9N4qtcaLeTLYJMu8IFrhkJyHj3nCt2+Uazt96QPQ=; b=Zmvvjs6knjwbjB71TuhD5YHUHpzhJHKAb1XA1Te9YPSrvgZo+Ev6HuS1uQ2pIyWfu9 mcHLZB3D0MvQSa+2a4D1PcEaXf2efTYYnnMwuDDPjAtNCY5bL+sFrpKS/nQxU9eHBbBX bR0iwXq7tJZyssRyqR1v14o1b/qKF6D37eeHvc2Vndm+k0mQ0Sy2nQedj+PQA42tX9f3 FlbD6R85XZK/dEbYxlno0KWMhrlG8w/PrqIzG07xA9e/c4RHHKbIIb7UXYBKffj/Z38W FHuBku6aXf1vDhv06cagvv5TaY0CZ1UbV/I54A3o5G2heGWWOpzI/Mesm2AoUh7znre2 jc/A== X-Gm-Message-State: APjAAAXlq4TWC0ujDcWtv6sD/gJO1Qc6XK4bAtgvl9FHbjsGLtg6fzmE VpIw69/KofoWz7dgx7V26kgnPeKJjlM= X-Google-Smtp-Source: APXvYqx/YouXUN+C51hL4u566++YSzgkp3hD3iGgTGJa+pnE2nc4+6nzyRdDTNXPhXn46fCiMmJCLg== X-Received: by 2002:a7b:c206:: with SMTP id x6mr4856277wmi.156.1562860172675; Thu, 11 Jul 2019 08:49:32 -0700 (PDT) Received: from localhost.localdomain.com (nat-pool-mxp-t.redhat.com. [149.6.153.186]) by smtp.gmail.com with ESMTPSA id e6sm6507334wrw.23.2019.07.11.08.49.31 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Thu, 11 Jul 2019 08:49:32 -0700 (PDT) From: Lorenzo Bianconi To: ovs-dev@openvswitch.org Date: Thu, 11 Jul 2019 17:48:45 +0200 Message-Id: <820908df8684bf5a21b7bded05b2718c1697162b.1562858727.git.lorenzo.bianconi@redhat.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v2 3/3] OVN: use trigger_event action to report 'empty_lb_rule' events X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Add northd logical flows in order to reports that the controller received an IP packet for LB rule witn no backends. This configuration is used by OpenShift to spin up a idle POD Signed-off-by: Mark Michelson Co-authored-by: Mark Michelson Signed-off-by: Lorenzo Bianconi --- ovn/northd/ovn-northd.c | 33 +++++++++++++++++++++ ovn/ovn-nb.xml | 11 +++++++ tests/ovn.at | 65 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index ce382ac89..4929fb666 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -70,6 +70,8 @@ static const char *unixctl_path; static struct hmap macam = HMAP_INITIALIZER(&macam); static struct eth_addr mac_prefix; +static bool controller_event_en; + #define MAX_OVN_TAGS 4096 /* Pipeline stages. */ @@ -3626,6 +3628,34 @@ build_pre_lb(struct ovn_datapath *od, struct hmap *lflows) sset_add(&all_ips, ip_address); } + if (controller_event_en && !node->value[0]) { + struct ds match = DS_EMPTY_INITIALIZER; + char *action; + + if (addr_family == AF_INET) { + ds_put_format(&match, "ip4.dst == %s && %s", + ip_address, lb->protocol); + } else { + ds_put_format(&match, "ip6.dst == %s && %s", + ip_address, lb->protocol); + } + if (port) { + ds_put_format(&match, " && %s.dst == %u", lb->protocol, + port); + } + action = xasprintf("trigger_event(event = \"%s\", " + "vip = \"%s\", protocol = \"%s\", " + "load_balancer = \"" UUID_FMT "\");", + event_to_string(OVN_EVENT_EMPTY_LB_BACKENDS), + node->key, lb->protocol, + UUID_ARGS(&lb->header_.uuid)); + ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 120, + ds_cstr(&match), action); + ds_destroy(&match); + free(action); + continue; + } + free(ip_address); /* Ignore L4 port information in the key because fragmented packets @@ -8115,6 +8145,9 @@ ovnnb_db_run(struct northd_context *ctx, smap_destroy(&options); } + controller_event_en = smap_get_bool(&nb->options, + "controller_event", false); + cleanup_macam(&macam); } diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml index 318379c1f..b0287563b 100644 --- a/ovn/ovn-nb.xml +++ b/ovn/ovn-nb.xml @@ -107,6 +107,17 @@ Configure a given OUI to be used as prefix when L2 address is dynamically assigned, e.g. 00:11:22 + + + Value set by the CMS to enable/disable ovn-controller event reporting. + Traffic into OVS can raise a 'controller' event that results in a + Controller_Event being written to the + table in SBDB. When the CMS has seen the event and taken appropriate + action, it can remove the correponding row in + table. + The intention is for a CMS to see the events and take some sort of + action. Please see the table in SBDB. + diff --git a/tests/ovn.at b/tests/ovn.at index e9ec715df..d2823d77a 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -14344,3 +14344,68 @@ AT_CHECK([ovn-nbctl ls-add sw1], [1], [ignore], ]) AT_CLEANUP + +AT_SETUP([ovn -- controller event]) +AT_KEYWORDS([ovn_controller_event]) +ovn_start + +# Create hypervisors hv[12]. +# Add vif1[12] to hv1, vif2[12] to hv2 +# Add all of the vifs to a single logical switch sw0. + +net_add n1 +ovn-nbctl ls-add sw0 +for i in 1 2; do + sim_add hv$i + as hv$i + ovs-vsctl add-br br-phys + ovn_attach n1 br-phys 192.168.0.$i + + for j in 1 2; do + ovn-nbctl lsp-add sw0 sw0-p$i$j -- \ + lsp-set-addresses sw0-p$i$j "00:00:00:00:00:$i$j 192.168.1.$i$j" + + ovs-vsctl -- add-port br-int vif$i$j -- \ + set interface vif$i$j \ + external-ids:iface-id=sw0-p$i$j \ + options:tx_pcap=hv$i/vif$i$j-tx.pcap \ + options:rxq_pcap=hv$i/vif$i$j-rx.pcap \ + ofport-request=$i$j + done +done + +ovn-nbctl --wait=hv set NB_Global . options:controller_event=true +ovn-nbctl lb-add lb0 192.168.1.100:80 "" +ovn-nbctl ls-lb-add sw0 lb0 +uuid_lb=$(ovn-nbctl --bare --columns=_uuid find load_balancer name=lb0) + +OVN_POPULATE_ARP +ovn-nbctl --timeout=3 --wait=hv sync +ovn-sbctl lflow-list +as hv1 ovs-ofctl dump-flows br-int + +packet="inport==\"sw0-p11\" && eth.src==00:00:00:00:00:11 && eth.dst==00:00:00:00:00:21 && + ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==192.168.1.100 && + tcp && tcp.src==10000 && tcp.dst==80" +as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet" + +ovn-sbctl list controller_event +uuid=$(ovn-sbctl list controller_event | awk '/_uuid/{print $3}') +AT_CHECK([ovn-sbctl get controller_event $uuid event_type], [0], [dnl +empty_lb_backends +]) +AT_CHECK([ovn-sbctl get controller_event $uuid event_info:vip], [0], [dnl +"192.168.1.100:80" +]) +AT_CHECK([ovn-sbctl get controller_event $uuid event_info:protocol], [0], [dnl +tcp +]) +AT_CHECK_UNQUOTED([ovn-sbctl get controller_event $uuid event_info:load_balancer], [0], [dnl +"$uuid_lb" +]) +AT_CHECK([ovn-sbctl get controller_event $uuid seq_num], [0], [dnl +1 +]) + +OVN_CLEANUP([hv1], [hv2]) +AT_CLEANUP