diff --git a/SOURCES/openvswitch-2.13.0.patch b/SOURCES/openvswitch-2.13.0.patch index 6435404..2a07c43 100644 --- a/SOURCES/openvswitch-2.13.0.patch +++ b/SOURCES/openvswitch-2.13.0.patch @@ -40,10 +40,21 @@ index abd2a9117a..1dca2045ce 100644 script: ./.travis/${TRAVIS_OS_NAME}-build.sh $OPTS diff --git a/.travis/linux-build.sh b/.travis/linux-build.sh -index bb47b3ee19..dd89eab5f8 100755 +index bb47b3ee19..6ad2894f53 100755 --- a/.travis/linux-build.sh +++ b/.travis/linux-build.sh -@@ -159,13 +159,24 @@ function build_ovs() +@@ -35,7 +35,9 @@ function install_kernel() + + url="${base_url}/linux-${version}.tar.xz" + # Download kernel sources. Try direct link on CDN failure. +- wget ${url} || wget ${url} || wget ${url/cdn/www} ++ wget ${url} || ++ (rm -f linux-${version}.tar.xz && wget ${url}) || ++ (rm -f linux-${version}.tar.xz && wget ${url/cdn/www}) + + tar xvf linux-${version}.tar.xz > /dev/null + pushd linux-${version} +@@ -159,13 +161,24 @@ function build_ovs() fi } @@ -193,7 +204,7 @@ index 6702c58a2b..41e1315a4c 100644 Q: Are all the DPDK releases that OVS versions work with maintained? diff --git a/Documentation/intro/install/dpdk.rst b/Documentation/intro/install/dpdk.rst -index dbf88ec43f..90eaa8aa2c 100644 +index dbf88ec43f..86ee19d4c4 100644 --- a/Documentation/intro/install/dpdk.rst +++ b/Documentation/intro/install/dpdk.rst @@ -42,7 +42,7 @@ Build requirements @@ -218,6 +229,35 @@ index dbf88ec43f..90eaa8aa2c 100644 $ cd $DPDK_DIR #. (Optional) Configure DPDK as a shared library +@@ -687,6 +687,15 @@ Limitations + around is temporary and is expected to be removed once a method is provided + by DPDK to query the upper bound MTU value for a given device. + ++- Flow Control: When using i40e devices (Intel(R) 700 Series) it is recommended ++ to set Link State Change detection to interrupt mode. Otherwise it has been ++ observed that using the default polling mode, flow control changes may not be ++ applied, and flow control states will not be reflected correctly. ++ The issue is under investigation, this is a temporary work around. ++ ++ For information about setting Link State Change detection, refer to ++ :ref:`lsc-detection`. ++ + Reporting Bugs + -------------- + +diff --git a/Documentation/topics/dpdk/phy.rst b/Documentation/topics/dpdk/phy.rst +index 38e52c8deb..55a98e2b0e 100644 +--- a/Documentation/topics/dpdk/phy.rst ++++ b/Documentation/topics/dpdk/phy.rst +@@ -385,6 +385,8 @@ Jumbo Frames + DPDK physical ports can be configured to use Jumbo Frames. For more + information, refer to :doc:`jumbo-frames`. + ++.. _lsc-detection: ++ + Link State Change (LSC) detection configuration + ----------------------------------------------- + diff --git a/Documentation/topics/dpdk/vhost-user.rst b/Documentation/topics/dpdk/vhost-user.rst index c6c6fd8bde..4bc5aef59d 100644 --- a/Documentation/topics/dpdk/vhost-user.rst @@ -286,14 +326,22 @@ index b279303d18..27ef9e4b48 100644 if WIN32 psep=";" diff --git a/NEWS b/NEWS -index dab94e924d..1a40ee19f4 100644 +index dab94e924d..e0f5fa9717 100644 --- a/NEWS +++ b/NEWS -@@ -1,3 +1,18 @@ +@@ -1,3 +1,26 @@ +v2.13.2 - xx xxx xxxx +--------------------- + - IPsec: + * Fixed support of strongswan 5.7+ in ovs-ipsec-monitor. ++ - OVSDB: ++ * New unixctl command 'ovsdb-server/memory-trim-on-compaction on|off'. ++ If turned on, ovsdb-server will try to reclaim all the unused memory ++ after every DB compaction back to OS. Disabled by default. ++ * Maximum backlog on RAFT connections limited to 500 messages or 4GB. ++ Once threshold reached, connection is dropped (and re-established). ++ Use the 'cluster/set-backlog-threshold' command to change limits. ++ * Fixed SHA-1 hash computation for databases larger than 512 MB. + - DPDK: + * Fixed support of 'net_virtio' devices. + @@ -309,7 +357,7 @@ index dab94e924d..1a40ee19f4 100644 --------------------- - OVN: diff --git a/acinclude.m4 b/acinclude.m4 -index c1470ccc6b..7f028836f5 100644 +index c1470ccc6b..12fd6c4a51 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -250,6 +250,18 @@ AC_DEFUN([OVS_CHECK_LINUX_SCTP_CT], [ @@ -365,7 +413,16 @@ index c1470ccc6b..7f028836f5 100644 OVS_GREP_IFELSE([$KSRC/include/net/rtnetlink.h], [get_link_net]) OVS_GREP_IFELSE([$KSRC/include/net/rtnetlink.h], [name_assign_type]) -@@ -1294,11 +1314,11 @@ AC_DEFUN([OVS_ENABLE_SPARSE], +@@ -918,8 +938,6 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ + + OVS_GREP_IFELSE([$KSRC/include/net/sock.h], [sk_no_check_tx]) + OVS_GREP_IFELSE([$KSRC/include/linux/udp.h], [no_check6_tx]) +- OVS_GREP_IFELSE([$KSRC/include/linux/utsrelease.h], [el6], +- [OVS_DEFINE([HAVE_RHEL6_PER_CPU])]) + OVS_FIND_PARAM_IFELSE([$KSRC/include/net/protocol.h], + [udp_add_offload], [net], + [OVS_DEFINE([HAVE_UDP_ADD_OFFLOAD_TAKES_NET])]) +@@ -1294,11 +1312,11 @@ AC_DEFUN([OVS_ENABLE_SPARSE], dnl OVS_CTAGS_IDENTIFIERS dnl @@ -381,7 +438,7 @@ index c1470ccc6b..7f028836f5 100644 dnl OVS_PTHREAD_SET_NAME dnl diff --git a/configure.ac b/configure.ac -index 92b52f6712..67942bbfb7 100644 +index 92b52f6712..72aa36b443 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ @@ -393,7 +450,15 @@ index 92b52f6712..67942bbfb7 100644 AC_CONFIG_SRCDIR([datapath/datapath.c]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([build-aux]) -@@ -188,6 +188,7 @@ OVS_CHECK_LINUX +@@ -100,6 +100,7 @@ OVS_CHECK_IF_DL + OVS_CHECK_STRTOK_R + OVS_CHECK_LINUX_AF_XDP + AC_CHECK_DECLS([sys_siglist], [], [], [[#include ]]) ++AC_CHECK_DECLS([malloc_trim], [], [], [[#include ]]) + AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec], + [], [], [[#include ]]) + AC_CHECK_MEMBERS([struct ifreq.ifr_flagshigh], [], [], [[#include ]]) +@@ -188,6 +189,7 @@ OVS_CHECK_LINUX OVS_CHECK_LINUX_NETLINK OVS_CHECK_LINUX_TC OVS_CHECK_LINUX_SCTP_CT @@ -687,6 +752,55 @@ index c044b14896..bf995aa83a 100644 #endif netdev_dbg(dev, "no route to %pI6\n", &fl6->daddr); return ERR_PTR(-ENETUNREACH); +diff --git a/datapath/linux/compat/include/linux/percpu.h b/datapath/linux/compat/include/linux/percpu.h +index 7c346aa31a..a039142e22 100644 +--- a/datapath/linux/compat/include/linux/percpu.h ++++ b/datapath/linux/compat/include/linux/percpu.h +@@ -7,12 +7,6 @@ + #define this_cpu_ptr(ptr) per_cpu_ptr(ptr, smp_processor_id()) + #endif + +-#ifdef HAVE_RHEL6_PER_CPU +-#undef this_cpu_read +-#undef this_cpu_inc +-#undef this_cpu_dec +-#endif +- + #if !defined this_cpu_read + #define this_cpu_read(ptr) percpu_read(ptr) + #endif +diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h +index 63972891bf..f276898b20 100644 +--- a/datapath/linux/compat/include/linux/skbuff.h ++++ b/datapath/linux/compat/include/linux/skbuff.h +@@ -278,7 +278,7 @@ static inline void skb_clear_hash(struct sk_buff *skb) + #ifdef HAVE_RXHASH + skb->rxhash = 0; + #endif +-#if defined(HAVE_L4_RXHASH) && !defined(HAVE_RHEL_OVS_HOOK) ++#if defined(HAVE_L4_RXHASH) + skb->l4_rxhash = 0; + #endif + } +diff --git a/datapath/linux/compat/nf_conntrack_reasm.c b/datapath/linux/compat/nf_conntrack_reasm.c +index ced9fba98b..77b4b25485 100644 +--- a/datapath/linux/compat/nf_conntrack_reasm.c ++++ b/datapath/linux/compat/nf_conntrack_reasm.c +@@ -57,10 +57,13 @@ + #include + #include "datapath.h" + +-#ifdef OVS_NF_DEFRAG6_BACKPORT ++#if defined(HAVE_INET_FRAGS_WITH_FRAGS_WORK) || !defined(HAVE_INET_FRAGS_RND) + + static const char nf_frags_cache_name[] = "ovs-frag6"; + ++#endif ++ ++#ifdef OVS_NF_DEFRAG6_BACKPORT + struct nf_ct_frag6_skb_cb + { + struct inet6_skb_parm h; diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c index 23118e8b63..05ccfb9288 100644 --- a/datapath/linux/compat/vxlan.c @@ -38675,6 +38789,18 @@ index db2b1f8961..09ae97f25c 100644 } determine_dpif_flow_dump_types(&dump_types, &dpif_dump_types); +diff --git a/lib/dpif-netdev-private.h b/lib/dpif-netdev-private.h +index 68c33a0f96..9b251f81fa 100644 +--- a/lib/dpif-netdev-private.h ++++ b/lib/dpif-netdev-private.h +@@ -1,6 +1,6 @@ + /* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2015 Nicira, Inc. +- * Copyright (c) 2019 Intel Corperation. ++ * Copyright (c) 2019 Intel Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index d393aab5e3..42e1c44ae8 100644 --- a/lib/dpif-netdev.c @@ -38913,6 +39039,317 @@ index 5b5c96d727..f9c732886f 100644 if (!del_err) { /* Delete from hw success, so old flow was offloaded. +diff --git a/lib/jsonrpc.c b/lib/jsonrpc.c +index ed748dbde7..9b297a38ce 100644 +--- a/lib/jsonrpc.c ++++ b/lib/jsonrpc.c +@@ -50,6 +50,10 @@ struct jsonrpc { + struct ovs_list output; /* Contains "struct ofpbuf"s. */ + size_t output_count; /* Number of elements in "output". */ + size_t backlog; ++ ++ /* Limits. */ ++ size_t max_output; /* 'output_count' disconnection threshold. */ ++ size_t max_backlog; /* 'backlog' disconnection threshold. */ + }; + + /* Rate limit for error messages. */ +@@ -178,6 +182,17 @@ jsonrpc_get_backlog(const struct jsonrpc *rpc) + return rpc->status ? 0 : rpc->backlog; + } + ++/* Sets thresholds for send backlog. If send backlog contains more than ++ * 'max_n_msgs' messages or is larger than 'max_backlog_bytes' bytes, ++ * connection will be dropped. */ ++void ++jsonrpc_set_backlog_threshold(struct jsonrpc *rpc, ++ size_t max_n_msgs, size_t max_backlog_bytes) ++{ ++ rpc->max_output = max_n_msgs; ++ rpc->max_backlog = max_backlog_bytes; ++} ++ + /* Returns the number of bytes that have been received on 'rpc''s underlying + * stream. (The value wraps around if it exceeds UINT_MAX.) */ + unsigned int +@@ -261,9 +276,26 @@ jsonrpc_send(struct jsonrpc *rpc, struct jsonrpc_msg *msg) + rpc->backlog += length; + + if (rpc->output_count >= 50) { +- VLOG_INFO_RL(&rl, "excessive sending backlog, jsonrpc: %s, num of" ++ static struct vlog_rate_limit bl_rl = VLOG_RATE_LIMIT_INIT(5, 5); ++ bool disconnect = false; ++ ++ VLOG_INFO_RL(&bl_rl, "excessive sending backlog, jsonrpc: %s, num of" + " msgs: %"PRIuSIZE", backlog: %"PRIuSIZE".", rpc->name, + rpc->output_count, rpc->backlog); ++ if (rpc->max_output && rpc->output_count > rpc->max_output) { ++ disconnect = true; ++ VLOG_WARN("sending backlog exceeded maximum number of messages (%" ++ PRIuSIZE" > %"PRIuSIZE"), disconnecting, jsonrpc: %s.", ++ rpc->output_count, rpc->max_output, rpc->name); ++ } else if (rpc->max_backlog && rpc->backlog > rpc->max_backlog) { ++ disconnect = true; ++ VLOG_WARN("sending backlog exceeded maximum size (%"PRIuSIZE" > %" ++ PRIuSIZE" bytes), disconnecting, jsonrpc: %s.", ++ rpc->backlog, rpc->max_backlog, rpc->name); ++ } ++ if (disconnect) { ++ jsonrpc_error(rpc, E2BIG); ++ } + } + + if (rpc->backlog == length) { +@@ -787,6 +819,10 @@ struct jsonrpc_session { + int last_error; + unsigned int seqno; + uint8_t dscp; ++ ++ /* Limits for jsonrpc. */ ++ size_t max_n_msgs; ++ size_t max_backlog_bytes; + }; + + static void +@@ -840,6 +876,8 @@ jsonrpc_session_open_multiple(const struct svec *remotes, bool retry) + s->dscp = 0; + s->last_error = 0; + ++ jsonrpc_session_set_backlog_threshold(s, 0, 0); ++ + const char *name = reconnect_get_name(s->reconnect); + if (!pstream_verify_name(name)) { + reconnect_set_passive(s->reconnect, true, time_msec()); +@@ -880,6 +918,7 @@ jsonrpc_session_open_unreliably(struct jsonrpc *jsonrpc, uint8_t dscp) + s->pstream = NULL; + s->seqno = 1; + ++ jsonrpc_session_set_backlog_threshold(s, 0, 0); + return s; + } + +@@ -968,6 +1007,8 @@ jsonrpc_session_run(struct jsonrpc_session *s) + } + reconnect_connected(s->reconnect, time_msec()); + s->rpc = jsonrpc_open(stream); ++ jsonrpc_set_backlog_threshold(s->rpc, s->max_n_msgs, ++ s->max_backlog_bytes); + s->seqno++; + } else if (error != EAGAIN) { + reconnect_listen_error(s->reconnect, time_msec(), error); +@@ -1008,6 +1049,8 @@ jsonrpc_session_run(struct jsonrpc_session *s) + if (!error) { + reconnect_connected(s->reconnect, time_msec()); + s->rpc = jsonrpc_open(s->stream); ++ jsonrpc_set_backlog_threshold(s->rpc, s->max_n_msgs, ++ s->max_backlog_bytes); + s->stream = NULL; + s->seqno++; + } else if (error != EAGAIN) { +@@ -1248,3 +1291,18 @@ jsonrpc_session_set_dscp(struct jsonrpc_session *s, uint8_t dscp) + jsonrpc_session_force_reconnect(s); + } + } ++ ++/* Sets thresholds for send backlog. If send backlog contains more than ++ * 'max_n_msgs' messages or is larger than 'max_backlog_bytes' bytes, ++ * connection will be closed (then reconnected, if that feature is enabled). */ ++void ++jsonrpc_session_set_backlog_threshold(struct jsonrpc_session *s, ++ size_t max_n_msgs, ++ size_t max_backlog_bytes) ++{ ++ s->max_n_msgs = max_n_msgs; ++ s->max_backlog_bytes = max_backlog_bytes; ++ if (s->rpc) { ++ jsonrpc_set_backlog_threshold(s->rpc, max_n_msgs, max_backlog_bytes); ++ } ++} +diff --git a/lib/jsonrpc.h b/lib/jsonrpc.h +index a44114e8dc..d75d66b863 100644 +--- a/lib/jsonrpc.h ++++ b/lib/jsonrpc.h +@@ -51,6 +51,9 @@ void jsonrpc_wait(struct jsonrpc *); + + int jsonrpc_get_status(const struct jsonrpc *); + size_t jsonrpc_get_backlog(const struct jsonrpc *); ++void jsonrpc_set_backlog_threshold(struct jsonrpc *, size_t max_n_msgs, ++ size_t max_backlog_bytes); ++ + unsigned int jsonrpc_get_received_bytes(const struct jsonrpc *); + const char *jsonrpc_get_name(const struct jsonrpc *); + +@@ -140,6 +143,9 @@ void jsonrpc_session_set_probe_interval(struct jsonrpc_session *, + int probe_interval); + void jsonrpc_session_set_dscp(struct jsonrpc_session *, + uint8_t dscp); ++void jsonrpc_session_set_backlog_threshold(struct jsonrpc_session *, ++ size_t max_n_msgs, ++ size_t max_backlog_bytes); + const char *jsonrpc_session_get_id(const struct jsonrpc_session *); + + #endif /* jsonrpc.h */ +diff --git a/lib/lldp/lldp.c b/lib/lldp/lldp.c +index 74f747fcdc..e5755307fb 100644 +--- a/lib/lldp/lldp.c ++++ b/lib/lldp/lldp.c +@@ -59,7 +59,7 @@ VLOG_DEFINE_THIS_MODULE(lldp); + } while (0) + #define PEEK_DISCARD_UINT8 PEEK_DISCARD(1) + #define PEEK_DISCARD_UINT16 PEEK_DISCARD(2) +-#define PEEK_DISCARD_UINT32 PEEK_DISCARD(3) ++#define PEEK_DISCARD_UINT32 PEEK_DISCARD(4) + #define PEEK_CMP(value, bytes) \ + (length -= (bytes), \ + pos += (bytes), \ +@@ -341,6 +341,12 @@ lldp_send(struct lldpd *global OVS_UNUSED, + + return dp_packet_size(p); + } ++#define CHECK_TLV_MAX_SIZE(x, name) \ ++ do { if (tlv_size > (x)) { \ ++ VLOG_WARN(name " TLV too large received on %s", \ ++ hardware->h_ifname); \ ++ goto malformed; \ ++ } } while (0) + + int + lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, +@@ -359,7 +365,7 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, + int length, af; + bool gotend = false; + bool ttl_received = false; +- int tlv_size, tlv_type, tlv_subtype; ++ int tlv_size, tlv_type, tlv_subtype, tlv_count = 0; + u_int8_t *pos, *tlv; + void *b; + struct lldpd_aa_isid_vlan_maps_tlv *isid_vlan_map = NULL; +@@ -411,6 +417,31 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, + hardware->h_ifname); + goto malformed; + } ++ /* Check order for mandatory TLVs */ ++ tlv_count++; ++ switch (tlv_type) { ++ case LLDP_TLV_CHASSIS_ID: ++ if (tlv_count != 1) { ++ VLOG_WARN("first TLV should be a chassis ID on %s, not %d", ++ hardware->h_ifname, tlv_type); ++ goto malformed; ++ } ++ break; ++ case LLDP_TLV_PORT_ID: ++ if (tlv_count != 2) { ++ VLOG_WARN("second TLV should be a port ID on %s, not %d", ++ hardware->h_ifname, tlv_type); ++ goto malformed; ++ } ++ break; ++ case LLDP_TLV_TTL: ++ if (tlv_count != 3) { ++ VLOG_WARN("third TLV should be a TTL on %s, not %d", ++ hardware->h_ifname, tlv_type); ++ goto malformed; ++ } ++ break; ++ } + + switch (tlv_type) { + case LLDP_TLV_END: +@@ -428,7 +459,8 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, + + case LLDP_TLV_CHASSIS_ID: + case LLDP_TLV_PORT_ID: +- CHECK_TLV_SIZE(2, "Port Id"); ++ CHECK_TLV_SIZE(2, "Port/Chassis Id"); ++ CHECK_TLV_MAX_SIZE(256, "Port/Chassis Id"); + tlv_subtype = PEEK_UINT8; + if (tlv_subtype == 0 || tlv_subtype > 7) { + VLOG_WARN("unknown subtype for tlv id received on %s", +@@ -438,10 +470,22 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, + b = xzalloc(tlv_size - 1); + PEEK_BYTES(b, tlv_size - 1); + if (tlv_type == LLDP_TLV_PORT_ID) { ++ if (port->p_id != NULL) { ++ VLOG_WARN("Port ID TLV received twice on %s", ++ hardware->h_ifname); ++ free(b); ++ goto malformed; ++ } + port->p_id_subtype = tlv_subtype; + port->p_id = b; + port->p_id_len = tlv_size - 1; + } else { ++ if (chassis->c_id != NULL) { ++ VLOG_WARN("Chassis ID TLV received twice on %s", ++ hardware->h_ifname); ++ free(b); ++ goto malformed; ++ } + chassis->c_id_subtype = tlv_subtype; + chassis->c_id = b; + chassis->c_id_len = tlv_size - 1; +@@ -449,6 +493,11 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, + break; + + case LLDP_TLV_TTL: ++ if (ttl_received) { ++ VLOG_WARN("TTL TLV received twice on %s", ++ hardware->h_ifname); ++ goto malformed; ++ } + CHECK_TLV_SIZE(2, "TTL"); + chassis->c_ttl = PEEK_UINT16; + ttl_received = true; +@@ -481,6 +530,11 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, + case LLDP_TLV_MGMT_ADDR: + CHECK_TLV_SIZE(1, "Management address"); + addr_str_length = PEEK_UINT8; ++ if (addr_str_length > sizeof(addr_str_buffer)) { ++ VLOG_WARN("too large management address on %s", ++ hardware->h_ifname); ++ goto malformed; ++ } + CHECK_TLV_SIZE(1 + addr_str_length, "Management address"); + PEEK_BYTES(addr_str_buffer, addr_str_length); + addr_length = addr_str_length - 1; +@@ -505,7 +559,7 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, + break; + + case LLDP_TLV_ORG: +- CHECK_TLV_SIZE(4, "Organisational"); ++ CHECK_TLV_SIZE(1 + sizeof orgid, "Organisational"); + PEEK_BYTES(orgid, sizeof orgid); + tlv_subtype = PEEK_UINT8; + if (memcmp(dot1, orgid, sizeof orgid) == 0) { +@@ -625,6 +679,7 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, + VLOG_WARN("unknown tlv (%d) received on %s", + tlv_type, + hardware->h_ifname); ++ hardware->h_rx_unrecognized_cnt++; + goto malformed; + } + if (pos > tlv + tlv_size) { +diff --git a/lib/lldp/lldpd.c b/lib/lldp/lldpd.c +index 19e9305266..34738535db 100644 +--- a/lib/lldp/lldpd.c ++++ b/lib/lldp/lldpd.c +@@ -244,6 +244,7 @@ lldpd_decode(struct lldpd *cfg, char *frame, int s, + + if (s < sizeof(struct eth_header) + 4) { + /* Too short, just discard it */ ++ hw->h_rx_discarded_cnt++; + return; + } + +@@ -284,6 +285,7 @@ lldpd_decode(struct lldpd *cfg, char *frame, int s, + VLOG_DBG("function for %s protocol did not " + "decode this frame", + cfg->g_protocols[i].name); ++ hw->h_rx_discarded_cnt++; + return; + } + chassis->c_protocol = port->p_protocol = cfg->g_protocols[i].mode; diff --git a/lib/meta-flow.c b/lib/meta-flow.c index 8b62e6d968..80063b933d 100644 --- a/lib/meta-flow.c @@ -39196,10 +39633,27 @@ index c6f3d27409..8d779945a1 100644 } diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c -index f8c46bbaad..4538baf5e6 100644 +index f8c46bbaad..b42d314b65 100644 --- a/lib/netdev-offload-dpdk.c +++ b/lib/netdev-offload-dpdk.c -@@ -565,8 +565,18 @@ parse_flow_match(struct flow_patterns *patterns, +@@ -76,7 +76,7 @@ ufid_to_rte_flow_data_find(const ovs_u128 *ufid) + return NULL; + } + +-static inline void ++static inline struct ufid_to_rte_flow_data * + ufid_to_rte_flow_associate(const ovs_u128 *ufid, + struct rte_flow *rte_flow, bool actions_offloaded) + { +@@ -101,6 +101,7 @@ ufid_to_rte_flow_associate(const ovs_u128 *ufid, + + cmap_insert(&ufid_to_rte_flow, + CONST_CAST(struct cmap_node *, &data->node), hash); ++ return data; + } + + static inline void +@@ -565,8 +566,18 @@ parse_flow_match(struct flow_patterns *patterns, uint8_t proto = 0; /* Eth */ @@ -39220,7 +39674,7 @@ index f8c46bbaad..4538baf5e6 100644 struct rte_flow_item_eth *spec, *mask; spec = xzalloc(sizeof *spec); -@@ -581,15 +591,6 @@ parse_flow_match(struct flow_patterns *patterns, +@@ -581,15 +592,6 @@ parse_flow_match(struct flow_patterns *patterns, mask->type = match->wc.masks.dl_type; add_flow_pattern(patterns, RTE_FLOW_ITEM_TYPE_ETH, spec, mask); @@ -39236,11 +39690,107 @@ index f8c46bbaad..4538baf5e6 100644 } /* VLAN */ +@@ -1037,7 +1039,7 @@ out: + return flow; + } + +-static int ++static struct ufid_to_rte_flow_data * + netdev_offload_dpdk_add_flow(struct netdev *netdev, + const struct match *match, + struct nlattr *nl_actions, +@@ -1046,12 +1048,11 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev, + struct offload_info *info) + { + struct flow_patterns patterns = { .items = NULL, .cnt = 0 }; ++ struct ufid_to_rte_flow_data *flows_data = NULL; + bool actions_offloaded = true; + struct rte_flow *flow; +- int ret = 0; + +- ret = parse_flow_match(&patterns, match); +- if (ret) { ++ if (parse_flow_match(&patterns, match)) { + goto out; + } + +@@ -1067,16 +1068,15 @@ netdev_offload_dpdk_add_flow(struct netdev *netdev, + } + + if (!flow) { +- ret = -1; + goto out; + } +- ufid_to_rte_flow_associate(ufid, flow, actions_offloaded); ++ flows_data = ufid_to_rte_flow_associate(ufid, flow, actions_offloaded); + VLOG_DBG("%s: installed flow %p by ufid "UUID_FMT"\n", + netdev_get_name(netdev), flow, UUID_ARGS((struct uuid *)ufid)); + + out: + free_flow_patterns(&patterns); +- return ret; ++ return flows_data; + } + + /* +@@ -1179,14 +1179,19 @@ netdev_offload_dpdk_flow_put(struct netdev *netdev, struct match *match, + struct dpif_flow_stats *stats) + { + struct ufid_to_rte_flow_data *rte_flow_data; ++ struct dpif_flow_stats old_stats; ++ bool modification = false; + int ret; + + /* + * If an old rte_flow exists, it means it's a flow modification. + * Here destroy the old rte flow first before adding a new one. ++ * Keep the stats for the newly created rule. + */ + rte_flow_data = ufid_to_rte_flow_data_find(ufid); + if (rte_flow_data && rte_flow_data->rte_flow) { ++ old_stats = rte_flow_data->stats; ++ modification = true; + ret = netdev_offload_dpdk_destroy_flow(netdev, ufid, + rte_flow_data->rte_flow); + if (ret < 0) { +@@ -1199,11 +1204,18 @@ netdev_offload_dpdk_flow_put(struct netdev *netdev, struct match *match, + return ret; + } + ++ rte_flow_data = netdev_offload_dpdk_add_flow(netdev, match, actions, ++ actions_len, ufid, info); ++ if (!rte_flow_data) { ++ return -1; ++ } ++ if (modification) { ++ rte_flow_data->stats = old_stats; ++ } + if (stats) { +- memset(stats, 0, sizeof *stats); ++ *stats = rte_flow_data->stats; + } +- return netdev_offload_dpdk_add_flow(netdev, match, actions, +- actions_len, ufid, info); ++ return 0; + } + + static int diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c -index 550e440b3a..e188e63e56 100644 +index 550e440b3a..a1d7ffad70 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c -@@ -1727,7 +1727,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, +@@ -198,7 +198,9 @@ del_filter_and_ufid_mapping(struct tcf_id *id, const ovs_u128 *ufid) + int err; + + err = tc_del_filter(id); +- del_ufid_tc_mapping(ufid); ++ if (!err) { ++ del_ufid_tc_mapping(ufid); ++ } + return err; + } + +@@ -1727,7 +1729,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, if (get_ufid_tc_mapping(ufid, &id) == 0) { VLOG_DBG_RL(&rl, "updating old handle: %d prio: %d", id.handle, id.prio); @@ -39249,7 +39799,7 @@ index 550e440b3a..e188e63e56 100644 } prio = get_prio_for_tc_flower(&flower); -@@ -1907,6 +1907,7 @@ netdev_tc_init_flow_api(struct netdev *netdev) +@@ -1907,6 +1909,7 @@ netdev_tc_init_flow_api(struct netdev *netdev) static struct ovsthread_once block_once = OVSTHREAD_ONCE_INITIALIZER; enum tc_qdisc_hook hook = get_tc_qdisc_hook(netdev); uint32_t block_id = 0; @@ -39257,7 +39807,7 @@ index 550e440b3a..e188e63e56 100644 int ifindex; int error; -@@ -1917,11 +1918,21 @@ netdev_tc_init_flow_api(struct netdev *netdev) +@@ -1917,11 +1920,21 @@ netdev_tc_init_flow_api(struct netdev *netdev) return -ifindex; } @@ -39279,7 +39829,7 @@ index 550e440b3a..e188e63e56 100644 ovsthread_once_done(&block_once); } -@@ -1930,7 +1941,6 @@ netdev_tc_init_flow_api(struct netdev *netdev) +@@ -1930,7 +1943,6 @@ netdev_tc_init_flow_api(struct netdev *netdev) ovsthread_once_done(&multi_mask_once); } @@ -39365,6 +39915,34 @@ index f95b19af4d..8c44eee8e9 100644 } return true; +diff --git a/lib/netlink.c b/lib/netlink.c +index de3ebcd0e7..26ab20bb4b 100644 +--- a/lib/netlink.c ++++ b/lib/netlink.c +@@ -498,6 +498,7 @@ void + nl_msg_end_nested(struct ofpbuf *msg, size_t offset) + { + struct nlattr *attr = ofpbuf_at_assert(msg, offset, sizeof *attr); ++ ovs_assert(!nl_attr_oversized(msg->size - offset - NLA_HDRLEN)); + attr->nla_len = msg->size - offset; + } + +diff --git a/lib/nx-match.c b/lib/nx-match.c +index 0432ad4de6..260f30d13e 100644 +--- a/lib/nx-match.c ++++ b/lib/nx-match.c +@@ -1133,6 +1133,11 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, + mpls_lse_to_bos(flow->mpls_lse[0])); + } + ++ if (match->wc.masks.mpls_lse[0] & htonl(MPLS_TTL_MASK)) { ++ nxm_put_8(&ctx, MFF_MPLS_TTL, oxm, ++ mpls_lse_to_ttl(flow->mpls_lse[0])); ++ } ++ + if (match->wc.masks.mpls_lse[0] & htonl(MPLS_LABEL_MASK)) { + nxm_put_32(&ctx, MFF_MPLS_LABEL, oxm, + htonl(mpls_lse_to_label(flow->mpls_lse[0]))); diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 42d3335f0f..97320a4dba 100644 --- a/lib/odp-execute.c @@ -39384,10 +39962,34 @@ index 42d3335f0f..97320a4dba 100644 } else { a = attrs[OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL]; diff --git a/lib/odp-util.c b/lib/odp-util.c -index 746d1e97d4..6baa2a8a70 100644 +index 746d1e97d4..9109c75dc5 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c -@@ -6225,7 +6225,9 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms, +@@ -5428,13 +5428,16 @@ erspan_to_attr(struct ofpbuf *a, const void *data_) + do { \ + len = 0; + +-#define SCAN_END_NESTED() \ +- SCAN_FINISH(); \ +- nl_msg_end_nested(key, key_offset); \ +- if (mask) { \ +- nl_msg_end_nested(mask, mask_offset); \ +- } \ +- return s - start; \ ++#define SCAN_END_NESTED() \ ++ SCAN_FINISH(); \ ++ if (nl_attr_oversized(key->size - key_offset - NLA_HDRLEN)) { \ ++ return -E2BIG; \ ++ } \ ++ nl_msg_end_nested(key, key_offset); \ ++ if (mask) { \ ++ nl_msg_end_nested(mask, mask_offset); \ ++ } \ ++ return s - start; \ + } + + #define SCAN_FIELD_NESTED__(NAME, TYPE, SCAN_AS, ATTR, FUNC) \ +@@ -6225,7 +6228,9 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms, struct ovs_key_nd_extensions *nd_ext_key; if (data->igmp_group_ip4 != 0 || data->tcp_flags != 0) { @@ -39398,7 +40000,7 @@ index 746d1e97d4..6baa2a8a70 100644 OVS_KEY_ATTR_ND_EXTENSIONS, sizeof *nd_ext_key); nd_ext_key->nd_reserved = data->igmp_group_ip4; -@@ -6275,6 +6277,10 @@ odp_key_from_dp_packet(struct ofpbuf *buf, const struct dp_packet *packet) +@@ -6275,6 +6280,10 @@ odp_key_from_dp_packet(struct ofpbuf *buf, const struct dp_packet *packet) nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, md->skb_priority); @@ -39409,7 +40011,7 @@ index 746d1e97d4..6baa2a8a70 100644 if (flow_tnl_dst_is_set(&md->tunnel)) { tun_key_to_attr(buf, &md->tunnel, &md->tunnel, NULL, NULL); } -@@ -7565,6 +7571,28 @@ struct offsetof_sizeof { +@@ -7565,6 +7574,28 @@ struct offsetof_sizeof { int size; }; @@ -39438,7 +40040,7 @@ index 746d1e97d4..6baa2a8a70 100644 /* Compares each of the fields in 'key0' and 'key1'. The fields are specified * in 'offsetof_sizeof_arr', which is an array terminated by a 0-size field. * Returns true if all of the fields are equal, false if at least one differs. -@@ -7643,9 +7671,10 @@ commit_set_ether_action(const struct flow *flow, struct flow *base_flow, +@@ -7643,9 +7674,10 @@ commit_set_ether_action(const struct flow *flow, struct flow *base_flow, struct flow_wildcards *wc, bool use_masked) { @@ -39450,7 +40052,7 @@ index 746d1e97d4..6baa2a8a70 100644 if (flow->packet_type != htonl(PT_ETH)) { return; } -@@ -7653,11 +7682,13 @@ commit_set_ether_action(const struct flow *flow, struct flow *base_flow, +@@ -7653,11 +7685,13 @@ commit_set_ether_action(const struct flow *flow, struct flow *base_flow, get_ethernet_key(flow, &key); get_ethernet_key(base_flow, &base); get_ethernet_key(&wc->masks, &mask); @@ -39464,7 +40066,7 @@ index 746d1e97d4..6baa2a8a70 100644 put_ethernet_key(&mask, &wc->masks); } } -@@ -7781,7 +7812,7 @@ commit_set_ipv4_action(const struct flow *flow, struct flow *base_flow, +@@ -7781,7 +7815,7 @@ commit_set_ipv4_action(const struct flow *flow, struct flow *base_flow, struct ofpbuf *odp_actions, struct flow_wildcards *wc, bool use_masked) { @@ -39473,7 +40075,7 @@ index 746d1e97d4..6baa2a8a70 100644 struct offsetof_sizeof ovs_key_ipv4_offsetof_sizeof_arr[] = OVS_KEY_IPV4_OFFSETOF_SIZEOF_ARR; -@@ -7792,6 +7823,7 @@ commit_set_ipv4_action(const struct flow *flow, struct flow *base_flow, +@@ -7792,6 +7826,7 @@ commit_set_ipv4_action(const struct flow *flow, struct flow *base_flow, get_ipv4_key(flow, &key, false); get_ipv4_key(base_flow, &base, false); get_ipv4_key(&wc->masks, &mask, true); @@ -39481,7 +40083,7 @@ index 746d1e97d4..6baa2a8a70 100644 mask.ipv4_proto = 0; /* Not writeable. */ mask.ipv4_frag = 0; /* Not writable. */ -@@ -7803,9 +7835,8 @@ commit_set_ipv4_action(const struct flow *flow, struct flow *base_flow, +@@ -7803,9 +7838,8 @@ commit_set_ipv4_action(const struct flow *flow, struct flow *base_flow, if (commit(OVS_KEY_ATTR_IPV4, use_masked, &key, &base, &mask, sizeof key, ovs_key_ipv4_offsetof_sizeof_arr, odp_actions)) { put_ipv4_key(&base, base_flow, false); @@ -39493,7 +40095,7 @@ index 746d1e97d4..6baa2a8a70 100644 } } -@@ -7838,7 +7869,7 @@ commit_set_ipv6_action(const struct flow *flow, struct flow *base_flow, +@@ -7838,7 +7872,7 @@ commit_set_ipv6_action(const struct flow *flow, struct flow *base_flow, struct ofpbuf *odp_actions, struct flow_wildcards *wc, bool use_masked) { @@ -39502,7 +40104,7 @@ index 746d1e97d4..6baa2a8a70 100644 struct offsetof_sizeof ovs_key_ipv6_offsetof_sizeof_arr[] = OVS_KEY_IPV6_OFFSETOF_SIZEOF_ARR; -@@ -7849,6 +7880,7 @@ commit_set_ipv6_action(const struct flow *flow, struct flow *base_flow, +@@ -7849,6 +7883,7 @@ commit_set_ipv6_action(const struct flow *flow, struct flow *base_flow, get_ipv6_key(flow, &key, false); get_ipv6_key(base_flow, &base, false); get_ipv6_key(&wc->masks, &mask, true); @@ -39510,7 +40112,7 @@ index 746d1e97d4..6baa2a8a70 100644 mask.ipv6_proto = 0; /* Not writeable. */ mask.ipv6_frag = 0; /* Not writable. */ mask.ipv6_label &= htonl(IPV6_LABEL_MASK); /* Not writable. */ -@@ -7861,9 +7893,8 @@ commit_set_ipv6_action(const struct flow *flow, struct flow *base_flow, +@@ -7861,9 +7896,8 @@ commit_set_ipv6_action(const struct flow *flow, struct flow *base_flow, if (commit(OVS_KEY_ATTR_IPV6, use_masked, &key, &base, &mask, sizeof key, ovs_key_ipv6_offsetof_sizeof_arr, odp_actions)) { put_ipv6_key(&base, base_flow, false); @@ -39522,7 +40124,7 @@ index 746d1e97d4..6baa2a8a70 100644 } } -@@ -7894,17 +7925,19 @@ static enum slow_path_reason +@@ -7894,17 +7928,19 @@ static enum slow_path_reason commit_set_arp_action(const struct flow *flow, struct flow *base_flow, struct ofpbuf *odp_actions, struct flow_wildcards *wc) { @@ -39543,7 +40145,7 @@ index 746d1e97d4..6baa2a8a70 100644 put_arp_key(&mask, &wc->masks); return SLOW_ACTION; } -@@ -7931,7 +7964,7 @@ static enum slow_path_reason +@@ -7931,7 +7967,7 @@ static enum slow_path_reason commit_set_icmp_action(const struct flow *flow, struct flow *base_flow, struct ofpbuf *odp_actions, struct flow_wildcards *wc) { @@ -39552,7 +40154,7 @@ index 746d1e97d4..6baa2a8a70 100644 struct offsetof_sizeof ovs_key_icmp_offsetof_sizeof_arr[] = OVS_KEY_ICMP_OFFSETOF_SIZEOF_ARR; enum ovs_key_attr attr; -@@ -7947,10 +7980,12 @@ commit_set_icmp_action(const struct flow *flow, struct flow *base_flow, +@@ -7947,10 +7983,12 @@ commit_set_icmp_action(const struct flow *flow, struct flow *base_flow, get_icmp_key(flow, &key); get_icmp_key(base_flow, &base); get_icmp_key(&wc->masks, &mask); @@ -39565,7 +40167,7 @@ index 746d1e97d4..6baa2a8a70 100644 put_icmp_key(&mask, &wc->masks); return SLOW_ACTION; } -@@ -7998,17 +8033,19 @@ commit_set_nd_action(const struct flow *flow, struct flow *base_flow, +@@ -7998,17 +8036,19 @@ commit_set_nd_action(const struct flow *flow, struct flow *base_flow, struct ofpbuf *odp_actions, struct flow_wildcards *wc, bool use_masked) { @@ -39586,7 +40188,7 @@ index 746d1e97d4..6baa2a8a70 100644 put_nd_key(&mask, &wc->masks); return SLOW_ACTION; } -@@ -8022,18 +8059,20 @@ commit_set_nd_extensions_action(const struct flow *flow, +@@ -8022,18 +8062,20 @@ commit_set_nd_extensions_action(const struct flow *flow, struct ofpbuf *odp_actions, struct flow_wildcards *wc, bool use_masked) { @@ -39608,7 +40210,7 @@ index 746d1e97d4..6baa2a8a70 100644 put_nd_extensions_key(&mask, &wc->masks); return SLOW_ACTION; } -@@ -8248,7 +8287,7 @@ commit_set_port_action(const struct flow *flow, struct flow *base_flow, +@@ -8248,7 +8290,7 @@ commit_set_port_action(const struct flow *flow, struct flow *base_flow, bool use_masked) { enum ovs_key_attr key_type; @@ -39617,7 +40219,7 @@ index 746d1e97d4..6baa2a8a70 100644 struct offsetof_sizeof ovs_key_tp_offsetof_sizeof_arr[] = OVS_KEY_TCP_OFFSETOF_SIZEOF_ARR; -@@ -8274,10 +8313,12 @@ commit_set_port_action(const struct flow *flow, struct flow *base_flow, +@@ -8274,10 +8316,12 @@ commit_set_port_action(const struct flow *flow, struct flow *base_flow, get_tp_key(flow, &key); get_tp_key(base_flow, &base); get_tp_key(&wc->masks, &mask); @@ -39630,7 +40232,7 @@ index 746d1e97d4..6baa2a8a70 100644 put_tp_key(&mask, &wc->masks); } } -@@ -8301,7 +8342,7 @@ commit_set_priority_action(const struct flow *flow, struct flow *base_flow, +@@ -8301,7 +8345,7 @@ commit_set_priority_action(const struct flow *flow, struct flow *base_flow, if (commit(OVS_KEY_ATTR_PRIORITY, use_masked, &key, &base, &mask, sizeof key, ovs_key_prio_offsetof_sizeof_arr, odp_actions)) { base_flow->skb_priority = base; @@ -39639,7 +40241,7 @@ index 746d1e97d4..6baa2a8a70 100644 } } -@@ -8325,7 +8366,7 @@ commit_set_pkt_mark_action(const struct flow *flow, struct flow *base_flow, +@@ -8325,7 +8369,7 @@ commit_set_pkt_mark_action(const struct flow *flow, struct flow *base_flow, sizeof key, ovs_key_pkt_mark_offsetof_sizeof_arr, odp_actions)) { base_flow->pkt_mark = base; @@ -39660,6 +40262,27 @@ index ddef3b0c87..ef8b2b4527 100644 return xasprintf("input too big"); } +diff --git a/lib/ofp-ed-props.c b/lib/ofp-ed-props.c +index 28382e0123..02a9235d51 100644 +--- a/lib/ofp-ed-props.c ++++ b/lib/ofp-ed-props.c +@@ -49,7 +49,7 @@ decode_ed_prop(const struct ofp_ed_prop_header **ofp_prop, + return OFPERR_NXBAC_BAD_ED_PROP; + } + struct ofpact_ed_prop_nsh_md_type *pnmt = +- ofpbuf_put_uninit(out, sizeof(*pnmt)); ++ ofpbuf_put_zeros(out, sizeof *pnmt); + pnmt->header.prop_class = prop_class; + pnmt->header.type = prop_type; + pnmt->header.len = len; +@@ -108,6 +108,7 @@ encode_ed_prop(const struct ofpact_ed_prop **prop, + opnmt->header.len = + offsetof(struct ofp_ed_prop_nsh_md_type, pad); + opnmt->md_type = pnmt->md_type; ++ memset(opnmt->pad, 0, sizeof opnmt->pad); + prop_len = sizeof(*pnmt); + break; + } diff --git a/lib/ovs-rcu.c b/lib/ovs-rcu.c index ebc8120f0f..cde1e925ba 100644 --- a/lib/ovs-rcu.c @@ -39748,7 +40371,7 @@ index 30d1d08eba..00497d940c 100644 struct ovsdb_idl_class { diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c -index 190143f363..5abe40f6d8 100644 +index 190143f363..1bc6f574db 100644 --- a/lib/ovsdb-idl.c +++ b/lib/ovsdb-idl.c @@ -240,6 +240,10 @@ static void ovsdb_idl_send_monitor_request(struct ovsdb_idl *, @@ -39834,7 +40457,7 @@ index 190143f363..5abe40f6d8 100644 ovsdb_idl_send_cond_change(idl); idl->data.cond_seqno++; break; -@@ -1495,30 +1510,60 @@ ovsdb_idl_condition_equals(const struct ovsdb_idl_condition *a, +@@ -1495,17 +1510,34 @@ ovsdb_idl_condition_equals(const struct ovsdb_idl_condition *a, } static void @@ -39857,9 +40480,9 @@ index 190143f363..5abe40f6d8 100644 HMAP_FOR_EACH (clause, hmap_node, &src->clauses) { - ovsdb_idl_condition_add_clause__(dst, clause, clause->hmap_node.hash); + ovsdb_idl_condition_add_clause__(*dst, clause, clause->hmap_node.hash); - } - } - ++ } ++} ++ +static void +ovsdb_idl_condition_move(struct ovsdb_idl_condition **dst, + struct ovsdb_idl_condition **src) @@ -39867,19 +40490,19 @@ index 190143f363..5abe40f6d8 100644 + if (*dst) { + ovsdb_idl_condition_destroy(*dst); + free(*dst); -+ } + } + *dst = *src; + *src = NULL; -+} -+ + } + static unsigned int - ovsdb_idl_db_set_condition(struct ovsdb_idl_db *db, +@@ -1513,17 +1545,33 @@ ovsdb_idl_db_set_condition(struct ovsdb_idl_db *db, const struct ovsdb_idl_table_class *tc, const struct ovsdb_idl_condition *condition) { + struct ovsdb_idl_condition *table_cond; struct ovsdb_idl_table *table = ovsdb_idl_db_table_from_class(db, tc); - unsigned int seqno = db->cond_seqno; +- unsigned int seqno = db->cond_seqno; - if (!ovsdb_idl_condition_equals(condition, &table->condition)) { - ovsdb_idl_condition_destroy(&table->condition); - ovsdb_idl_condition_clone(&table->condition, condition); @@ -39901,9 +40524,20 @@ index 190143f363..5abe40f6d8 100644 + ovsdb_idl_condition_clone(&table->new_cond, condition); + db->cond_changed = true; poll_immediate_wake(); - return seqno + 1; +- return seqno + 1; ++ return db->cond_seqno + 1; ++ } else if (table_cond != table->ack_cond) { ++ /* 'condition' was already set but has not been "acked" yet. The IDL ++ * will be up to date when db->cond_seqno gets incremented. */ ++ return db->cond_seqno + 1; } -@@ -1563,9 +1608,8 @@ ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition *cnd) + +- return seqno; ++ return db->cond_seqno; + } + + /* Sets the replication condition for 'tc' in 'idl' to 'condition' and +@@ -1563,9 +1611,8 @@ ovsdb_idl_condition_to_json(const struct ovsdb_idl_condition *cnd) } static struct json * @@ -39914,7 +40548,7 @@ index 190143f363..5abe40f6d8 100644 struct json *monitor_cond_change_request = json_object_create(); struct json *cond_json = ovsdb_idl_condition_to_json(cond); -@@ -1585,8 +1629,12 @@ ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db *db) +@@ -1585,8 +1632,12 @@ ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db *db) for (size_t i = 0; i < db->class_->n_tables; i++) { struct ovsdb_idl_table *table = &db->tables[i]; @@ -39929,7 +40563,7 @@ index 190143f363..5abe40f6d8 100644 if (req) { if (!monitor_cond_change_requests) { monitor_cond_change_requests = json_object_create(); -@@ -1595,7 +1643,11 @@ ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db *db) +@@ -1595,7 +1646,11 @@ ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db *db) table->class_->name, json_array_create_1(req)); } @@ -39942,7 +40576,7 @@ index 190143f363..5abe40f6d8 100644 } } -@@ -1610,6 +1662,73 @@ ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db *db) +@@ -1610,6 +1665,73 @@ ovsdb_idl_db_compose_cond_change(struct ovsdb_idl_db *db) return jsonrpc_create_request("monitor_cond_change", params, NULL); } @@ -40016,7 +40650,19 @@ index 190143f363..5abe40f6d8 100644 static void ovsdb_idl_send_cond_change(struct ovsdb_idl *idl) { -@@ -2064,13 +2183,15 @@ ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl, struct ovsdb_idl_db *db, +@@ -1823,6 +1945,11 @@ ovsdb_idl_db_track_clear(struct ovsdb_idl_db *db) + free(row->updated); + row->updated = NULL; + } ++ ++ row->change_seqno[OVSDB_IDL_CHANGE_INSERT] = ++ row->change_seqno[OVSDB_IDL_CHANGE_MODIFY] = ++ row->change_seqno[OVSDB_IDL_CHANGE_DELETE] = 0; ++ + ovs_list_remove(&row->track_node); + ovs_list_init(&row->track_node); + if (ovsdb_idl_row_is_orphan(row) && row->tracked_old_datum) { +@@ -2064,13 +2191,15 @@ ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl, struct ovsdb_idl_db *db, monitor_request = json_object_create(); json_object_put(monitor_request, "columns", columns); @@ -40035,7 +40681,7 @@ index 190143f363..5abe40f6d8 100644 } json_object_put(monitor_requests, tc->name, json_array_create_1(monitor_request)); -@@ -2078,8 +2199,6 @@ ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl, struct ovsdb_idl_db *db, +@@ -2078,8 +2207,6 @@ ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl, struct ovsdb_idl_db *db, } free_schema(schema); @@ -40044,6 +40690,68 @@ index 190143f363..5abe40f6d8 100644 struct json *params = json_array_create_3( json_string_create(db->class_->database), json_clone(db->monitor_id), +@@ -2504,22 +2631,25 @@ ovsdb_idl_process_update2(struct ovsdb_idl_table *table, + return true; + } + +-/* Recursively add rows to tracked change lists for current row +- * and the rows that reference this row. */ ++/* Recursively add rows to tracked change lists for all rows that reference ++ 'row'. */ + static void + add_tracked_change_for_references(struct ovsdb_idl_row *row) + { +- if (ovs_list_is_empty(&row->track_node) && +- ovsdb_idl_track_is_set(row->table)) { +- ovs_list_push_back(&row->table->track_list, +- &row->track_node); +- row->change_seqno[OVSDB_IDL_CHANGE_MODIFY] +- = row->table->change_seqno[OVSDB_IDL_CHANGE_MODIFY] +- = row->table->db->change_seqno + 1; +- +- const struct ovsdb_idl_arc *arc; +- LIST_FOR_EACH (arc, dst_node, &row->dst_arcs) { +- add_tracked_change_for_references(arc->src); ++ const struct ovsdb_idl_arc *arc; ++ LIST_FOR_EACH (arc, dst_node, &row->dst_arcs) { ++ struct ovsdb_idl_row *ref = arc->src; ++ ++ if (ovs_list_is_empty(&ref->track_node) && ++ ovsdb_idl_track_is_set(ref->table)) { ++ ovs_list_push_back(&ref->table->track_list, ++ &ref->track_node); ++ ++ ref->change_seqno[OVSDB_IDL_CHANGE_MODIFY] ++ = ref->table->change_seqno[OVSDB_IDL_CHANGE_MODIFY] ++ = ref->table->db->change_seqno + 1; ++ ++ add_tracked_change_for_references(ref); + } + } + } +@@ -2587,7 +2717,14 @@ ovsdb_idl_row_change__(struct ovsdb_idl_row *row, const struct json *row_json, + row->change_seqno[change] + = row->table->change_seqno[change] + = row->table->db->change_seqno + 1; ++ + if (table->modes[column_idx] & OVSDB_IDL_TRACK) { ++ if (ovs_list_is_empty(&row->track_node) && ++ ovsdb_idl_track_is_set(row->table)) { ++ ovs_list_push_back(&row->table->track_list, ++ &row->track_node); ++ } ++ + add_tracked_change_for_references(row); + if (!row->updated) { + row->updated = bitmap_allocate(class->n_columns); +@@ -4663,6 +4800,7 @@ ovsdb_idl_txn_insert(struct ovsdb_idl_txn *txn, + hmap_insert(&row->table->rows, &row->hmap_node, uuid_hash(&row->uuid)); + hmap_insert(&txn->txn_rows, &row->txn_node, uuid_hash(&row->uuid)); + ovsdb_idl_add_to_indexes(row); ++ + return row; + } + diff --git a/lib/pvector.c b/lib/pvector.c index aaeee92147..cc527fdc41 100644 --- a/lib/pvector.c @@ -40121,6 +40829,44 @@ index b990ed9d59..0d3290dc37 100644 cursor.vector = impl->vector; cursor.entry_idx = -1; +diff --git a/lib/sha1.c b/lib/sha1.c +index 4f48ef2102..87360d9cd0 100644 +--- a/lib/sha1.c ++++ b/lib/sha1.c +@@ -197,7 +197,7 @@ sha1_init(struct sha1_ctx *sha_info) + * inputLen: The length of the input buffer. + */ + void +-sha1_update(struct sha1_ctx *ctx, const void *buffer_, size_t count) ++sha1_update(struct sha1_ctx *ctx, const void *buffer_, uint32_t count) + { + const uint8_t *buffer = buffer_; + unsigned int i; +@@ -274,7 +274,7 @@ sha1_final(struct sha1_ctx *ctx, uint8_t digest[SHA1_DIGEST_SIZE]) + + /* Computes the hash of 'n' bytes in 'data' into 'digest'. */ + void +-sha1_bytes(const void *data, size_t n, uint8_t digest[SHA1_DIGEST_SIZE]) ++sha1_bytes(const void *data, uint32_t n, uint8_t digest[SHA1_DIGEST_SIZE]) + { + struct sha1_ctx ctx; + +diff --git a/lib/sha1.h b/lib/sha1.h +index eda265dfc5..a635ff7689 100644 +--- a/lib/sha1.h ++++ b/lib/sha1.h +@@ -45,9 +45,9 @@ struct sha1_ctx { + }; + + void sha1_init(struct sha1_ctx *); +-void sha1_update(struct sha1_ctx *, const void *, size_t); ++void sha1_update(struct sha1_ctx *, const void *, uint32_t size); + void sha1_final(struct sha1_ctx *, uint8_t digest[SHA1_DIGEST_SIZE]); +-void sha1_bytes(const void *, size_t, uint8_t digest[SHA1_DIGEST_SIZE]); ++void sha1_bytes(const void *, uint32_t size, uint8_t digest[SHA1_DIGEST_SIZE]); + + #define SHA1_FMT \ + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \ diff --git a/lib/tc.c b/lib/tc.c index 12af0192b6..cc8c2d849e 100644 --- a/lib/tc.c @@ -40432,6 +41178,19 @@ index e45f3d6796..3a0dad5d0a 100644 if (timeout_msec < 0) { error = ovsdb_syntax_error(timeout, NULL, "timeout must be nonnegative"); +diff --git a/ovsdb/log.c b/ovsdb/log.c +index c82a79c9ff..f35faadfe0 100644 +--- a/ovsdb/log.c ++++ b/ovsdb/log.c +@@ -212,7 +212,7 @@ ovsdb_log_open(const char *name, const char *magic, + if (!strcmp(name, "/dev/stdin") && open_mode == OVSDB_LOG_READ_ONLY) { + fd = dup(STDIN_FILENO); + } else { +- fd = open(name, flags, 0666); ++ fd = open(name, flags, 0660); + } + if (fd < 0) { + const char *op = (open_mode == OVSDB_LOG_CREATE_EXCL ? "create" diff --git a/ovsdb/ovsdb-doc b/ovsdb/ovsdb-doc index 406c293114..10d0c0c134 100755 --- a/ovsdb/ovsdb-doc @@ -40445,11 +41204,114 @@ index 406c293114..10d0c0c134 100755 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. +diff --git a/ovsdb/ovsdb-idlc.in b/ovsdb/ovsdb-idlc.in +index c285ee4b3c..e296bb6d4f 100755 +--- a/ovsdb/ovsdb-idlc.in ++++ b/ovsdb/ovsdb-idlc.in +@@ -279,13 +279,21 @@ const struct %(s)s *%(s)s_table_track_get_first(const struct %(s)s_table *); + (ROW) = %(s)s_track_get_next(ROW)) + + +-/* Returns true if 'row' was inserted since the last change tracking reset. */ ++/* Returns true if 'row' was inserted since the last change tracking reset. ++ * ++ * Note: This can only be used to test rows of tracked changes. This cannot be ++ * used to test if an uncommitted row that has been added locally is new or it ++ * may given unexpected results. */ + static inline bool %(s)s_is_new(const struct %(s)s *row) + { +- return %(s)s_row_get_seqno(row, OVSDB_IDL_CHANGE_MODIFY) == 0; ++ return %(s)s_row_get_seqno(row, OVSDB_IDL_CHANGE_INSERT) > 0; + } + +-/* Returns true if 'row' was deleted since the last change tracking reset. */ ++/* Returns true if 'row' was deleted since the last change tracking reset. ++ * ++ * Note: This can only be used to test rows of tracked changes. This cannot be ++ * used to test if an uncommitted row that has been added locally has been ++ * deleted or it may given unexpected results. */ + static inline bool %(s)s_is_deleted(const struct %(s)s *row) + { + return %(s)s_row_get_seqno(row, OVSDB_IDL_CHANGE_DELETE) > 0; +@@ -333,6 +341,14 @@ struct %(s)s *%(s)s_cursor_data(struct ovsdb_idl_cursor *); + void %(s)s_init(struct %(s)s *); + void %(s)s_delete(const struct %(s)s *); + struct %(s)s *%(s)s_insert(struct ovsdb_idl_txn *); ++ ++/* Returns true if the tracked column referenced by 'enum %(s)s_column_id' of ++ * the row referenced by 'struct %(s)s *' was updated since the last change ++ * tracking reset. ++ * ++ * Note: This can only be used to test rows of tracked changes. This cannot be ++ * used to test if an uncommitted row that has been added locally has been ++ * updated or it may given unexpected results. */ + bool %(s)s_is_updated(const struct %(s)s *, enum %(s)s_column_id); + ''' % {'s': structName, 'S': structName.upper()}) + +diff --git a/ovsdb/ovsdb-server.1.in b/ovsdb/ovsdb-server.1.in +index 338f3bc299..b8bd1c2d57 100644 +--- a/ovsdb/ovsdb-server.1.in ++++ b/ovsdb/ovsdb-server.1.in +@@ -206,6 +206,10 @@ but not before 100 commits have been added or 10 minutes have elapsed + since the last compaction. It will also be compacted automatically + after 24 hours since the last compaction if 100 commits were added + regardless of its size. ++.IP "\fBovsdb\-server/memory-trim-on-compaction\fR \fIon\fR|\fIoff\fR" ++If this option is \fIon\fR, ovsdb-server will try to reclaim all unused ++heap memory back to the system after each successful database compaction ++to reduce the memory consumption of the process. \fIoff\fR by default. + . + .IP "\fBovsdb\-server/reconnect\fR" + Makes \fBovsdb\-server\fR drop all of the JSON\-RPC +@@ -372,6 +376,11 @@ This command must be executed on the leader. It initiates the change to the + cluster. To see if the change takes effect (committed), use + \fBcluster/status\fR to show the current setting. Once a change is committed, + it persists at server restarts. ++.IP "\fBcluster/set\-backlog\-threshold \fIdb\fR \fIn_msgs\fR \fIn_bytes\fR" ++Sets the backlog limits for \fIdb\fR's RAFT connections to a maximum of ++\fIn_msgs\fR messages or \fIn_bytes\fR bytes. If the backlog on one of the ++connections reaches the limit, it will be disconnected (and re-established). ++Values are checked only if the backlog contains more than 50 messages. + . + .so lib/vlog-unixctl.man + .so lib/memory-unixctl.man diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c -index b6957d7300..fd7891a729 100644 +index b6957d7300..54ed7c4283 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c -@@ -540,7 +540,7 @@ close_db(struct server_config *config, struct db *db, char *comment) +@@ -76,8 +76,12 @@ static char *ssl_protocols; + static char *ssl_ciphers; + static bool bootstrap_ca_cert; + ++/* Try to reclaim heap memory back to system after DB compaction. */ ++static bool trim_memory = false; ++ + static unixctl_cb_func ovsdb_server_exit; + static unixctl_cb_func ovsdb_server_compact; ++static unixctl_cb_func ovsdb_server_memory_trim_on_compaction; + static unixctl_cb_func ovsdb_server_reconnect; + static unixctl_cb_func ovsdb_server_perf_counters_clear; + static unixctl_cb_func ovsdb_server_perf_counters_show; +@@ -242,7 +246,7 @@ main_loop(struct server_config *config, + xasprintf("removing database %s because storage " + "disconnected permanently", node->name)); + } else if (ovsdb_storage_should_snapshot(db->db->storage)) { +- log_and_free_error(ovsdb_snapshot(db->db)); ++ log_and_free_error(ovsdb_snapshot(db->db, trim_memory)); + } + } + if (run_process) { +@@ -409,6 +413,9 @@ main(int argc, char *argv[]) + unixctl_command_register("exit", "", 0, 0, ovsdb_server_exit, &exiting); + unixctl_command_register("ovsdb-server/compact", "", 0, 1, + ovsdb_server_compact, &all_dbs); ++ unixctl_command_register("ovsdb-server/memory-trim-on-compaction", ++ "on|off", 1, 1, ++ ovsdb_server_memory_trim_on_compaction, NULL); + unixctl_command_register("ovsdb-server/reconnect", "", 0, 0, + ovsdb_server_reconnect, jsonrpc); + +@@ -540,7 +547,7 @@ close_db(struct server_config *config, struct db *db, char *comment) static struct ovsdb_error * OVS_WARN_UNUSED_RESULT parse_txn(struct server_config *config, struct db *db, @@ -40458,7 +41320,7 @@ index b6957d7300..fd7891a729 100644 const struct uuid *txnid) { if (schema) { -@@ -548,7 +548,9 @@ parse_txn(struct server_config *config, struct db *db, +@@ -548,7 +555,9 @@ parse_txn(struct server_config *config, struct db *db, * (first grabbing its storage), then replace it with the new schema. * The transaction must also include the replacement data. * @@ -40469,7 +41331,7 @@ index b6957d7300..fd7891a729 100644 ovs_assert(txn_json); ovs_assert(ovsdb_storage_is_clustered(db->db->storage)); -@@ -558,13 +560,17 @@ parse_txn(struct server_config *config, struct db *db, +@@ -558,13 +567,17 @@ parse_txn(struct server_config *config, struct db *db, return error; } @@ -40493,7 +41355,7 @@ index b6957d7300..fd7891a729 100644 /* Force update to schema in _Server database. */ db->row_uuid = UUID_ZERO; -@@ -613,6 +619,7 @@ read_db(struct server_config *config, struct db *db) +@@ -613,6 +626,7 @@ read_db(struct server_config *config, struct db *db) } else { error = parse_txn(config, db, schema, txn_json, &txnid); json_destroy(txn_json); @@ -40501,11 +41363,68 @@ index b6957d7300..fd7891a729 100644 if (error) { break; } +@@ -1481,7 +1495,8 @@ ovsdb_server_compact(struct unixctl_conn *conn, int argc, + VLOG_INFO("compacting %s database by user request", + node->name); + +- struct ovsdb_error *error = ovsdb_snapshot(db->db); ++ struct ovsdb_error *error = ovsdb_snapshot(db->db, ++ trim_memory); + if (error) { + char *s = ovsdb_error_to_string(error); + ds_put_format(&reply, "%s\n", s); +@@ -1504,6 +1519,35 @@ ovsdb_server_compact(struct unixctl_conn *conn, int argc, + ds_destroy(&reply); + } + ++/* "ovsdb-server/memory-trim-on-compaction": controls whether ovsdb-server ++ * tries to reclaim heap memory back to system using malloc_trim() after ++ * compaction. */ ++static void ++ovsdb_server_memory_trim_on_compaction(struct unixctl_conn *conn, ++ int argc OVS_UNUSED, ++ const char *argv[], ++ void *arg OVS_UNUSED) ++{ ++ const char *command = argv[1]; ++ ++#if !HAVE_DECL_MALLOC_TRIM ++ unixctl_command_reply_error(conn, "memory trimming is not supported"); ++ return; ++#endif ++ ++ if (!strcmp(command, "on")) { ++ trim_memory = true; ++ } else if (!strcmp(command, "off")) { ++ trim_memory = false; ++ } else { ++ unixctl_command_reply_error(conn, "invalid argument"); ++ return; ++ } ++ VLOG_INFO("memory trimming after compaction %s.", ++ trim_memory ? "enabled" : "disabled"); ++ unixctl_command_reply(conn, NULL); ++} ++ + /* "ovsdb-server/reconnect": makes ovsdb-server drop all of its JSON-RPC + * connections and reconnect. */ + static void diff --git a/ovsdb/ovsdb.c b/ovsdb/ovsdb.c -index cfc96b32f8..2da117cb36 100644 +index cfc96b32f8..9042658fa8 100644 --- a/ovsdb/ovsdb.c +++ b/ovsdb/ovsdb.c -@@ -414,7 +414,7 @@ ovsdb_create(struct ovsdb_schema *schema, struct ovsdb_storage *storage) +@@ -17,6 +17,10 @@ + + #include "ovsdb.h" + ++#if HAVE_DECL_MALLOC_TRIM ++#include ++#endif ++ + #include "column.h" + #include "file.h" + #include "monitor.h" +@@ -414,7 +418,7 @@ ovsdb_create(struct ovsdb_schema *schema, struct ovsdb_storage *storage) db->storage = storage; ovs_list_init(&db->monitors); ovs_list_init(&db->triggers); @@ -40514,7 +41433,7 @@ index cfc96b32f8..2da117cb36 100644 shash_init(&db->tables); if (schema) { -@@ -502,6 +502,10 @@ ovsdb_get_memory_usage(const struct ovsdb *db, struct simap *usage) +@@ -502,6 +506,10 @@ ovsdb_get_memory_usage(const struct ovsdb *db, struct simap *usage) } simap_increase(usage, "cells", cells); @@ -40525,8 +41444,30 @@ index cfc96b32f8..2da117cb36 100644 } struct ovsdb_table * +@@ -511,7 +519,7 @@ ovsdb_get_table(const struct ovsdb *db, const char *name) + } + + struct ovsdb_error * OVS_WARN_UNUSED_RESULT +-ovsdb_snapshot(struct ovsdb *db) ++ovsdb_snapshot(struct ovsdb *db, bool trim_memory OVS_UNUSED) + { + if (!db->storage) { + return NULL; +@@ -523,6 +531,12 @@ ovsdb_snapshot(struct ovsdb *db) + schema, data); + json_destroy(schema); + json_destroy(data); ++ ++#if HAVE_DECL_MALLOC_TRIM ++ if (!error && trim_memory) { ++ malloc_trim(0); ++ } ++#endif + return error; + } + diff --git a/ovsdb/ovsdb.h b/ovsdb/ovsdb.h -index 32e5333163..5c30a83d92 100644 +index 32e5333163..72e127c847 100644 --- a/ovsdb/ovsdb.h +++ b/ovsdb/ovsdb.h @@ -83,6 +83,7 @@ struct ovsdb { @@ -40537,20 +41478,18 @@ index 32e5333163..5c30a83d92 100644 struct ovsdb_table *rbac_role; -diff --git a/ovsdb/raft-private.c b/ovsdb/raft-private.c -index 26d39a087f..9468fdaf4a 100644 ---- a/ovsdb/raft-private.c -+++ b/ovsdb/raft-private.c -@@ -137,6 +137,7 @@ raft_server_destroy(struct raft_server *s) - if (s) { - free(s->address); - free(s->nickname); -+ free(s->last_install_snapshot_request); - free(s); - } - } +@@ -111,7 +112,8 @@ struct json *ovsdb_execute(struct ovsdb *, const struct ovsdb_session *, + long long int elapsed_msec, + long long int *timeout_msec); + +-struct ovsdb_error *ovsdb_snapshot(struct ovsdb *) OVS_WARN_UNUSED_RESULT; ++struct ovsdb_error *ovsdb_snapshot(struct ovsdb *, bool trim_memory) ++ OVS_WARN_UNUSED_RESULT; + + void ovsdb_replace(struct ovsdb *dst, struct ovsdb *src); + diff --git a/ovsdb/raft-private.h b/ovsdb/raft-private.h -index ac8656d42f..1f366b4ab3 100644 +index ac8656d42f..76b097b891 100644 --- a/ovsdb/raft-private.h +++ b/ovsdb/raft-private.h @@ -27,6 +27,7 @@ @@ -40565,8 +41504,8 @@ index ac8656d42f..1f366b4ab3 100644 bool replied; /* Reply to append_request was received from this node during current election_timeout interval. */ -+ /* Copy of the last install_snapshot_request sent to this server. */ -+ struct raft_install_snapshot_request *last_install_snapshot_request; ++ /* install_snapshot_request has been sent, but there is no response yet. */ ++ bool install_snapshot_request_in_progress; + /* For use in adding and removing servers: */ struct uuid requester_sid; /* Nonzero if requested via RPC. */ @@ -40586,7 +41525,7 @@ index 18c83fe9c2..dd14d81091 100644 struct hmap servers; struct ovsdb_error *error = diff --git a/ovsdb/raft.c b/ovsdb/raft.c -index 4789bc4f22..8df386fa19 100644 +index 4789bc4f22..ff06add0bf 100644 --- a/ovsdb/raft.c +++ b/ovsdb/raft.c @@ -36,6 +36,7 @@ @@ -40607,7 +41546,7 @@ index 4789bc4f22..8df386fa19 100644 }; static enum raft_failure_test failure_test; -@@ -298,6 +300,11 @@ struct raft { +@@ -298,6 +300,17 @@ struct raft { bool had_leader; /* There has been leader elected since last election initiated. This is to help setting candidate_retrying. */ @@ -40616,18 +41555,36 @@ index 4789bc4f22..8df386fa19 100644 + bool ever_had_leader; /* There has been leader elected since the raft + is initialized, meaning it is ever + connected. */ ++ ++ /* Connection backlog limits. */ ++#define DEFAULT_MAX_BACKLOG_N_MSGS 500 ++#define DEFAULT_MAX_BACKLOG_N_BYTES UINT32_MAX ++ size_t conn_backlog_max_n_msgs; /* Number of messages. */ ++ size_t conn_backlog_max_n_bytes; /* Number of bytes. */ }; /* All Raft structures. */ -@@ -932,6 +939,7 @@ raft_add_conn(struct raft *raft, struct jsonrpc_session *js, +@@ -405,6 +418,9 @@ raft_alloc(void) + + raft->election_timer = ELECTION_BASE_MSEC; + ++ raft->conn_backlog_max_n_msgs = DEFAULT_MAX_BACKLOG_N_MSGS; ++ raft->conn_backlog_max_n_bytes = DEFAULT_MAX_BACKLOG_N_BYTES; ++ + return raft; + } + +@@ -932,6 +948,9 @@ raft_add_conn(struct raft *raft, struct jsonrpc_session *js, &conn->sid); conn->incoming = incoming; conn->js_seqno = jsonrpc_session_get_seqno(conn->js); + jsonrpc_session_set_probe_interval(js, 0); ++ jsonrpc_session_set_backlog_threshold(js, raft->conn_backlog_max_n_msgs, ++ raft->conn_backlog_max_n_bytes); } /* Starts the local server in an existing Raft cluster, using the local copy of -@@ -1007,6 +1015,21 @@ raft_get_sid(const struct raft *raft) +@@ -1007,6 +1026,23 @@ raft_get_sid(const struct raft *raft) return &raft->sid; } @@ -40636,30 +41593,47 @@ index 4789bc4f22..8df386fa19 100644 +raft_get_memory_usage(const struct raft *raft, struct simap *usage) +{ + struct raft_conn *conn; ++ uint64_t backlog = 0; + int cnt = 0; + + LIST_FOR_EACH (conn, list_node, &raft->conns) { -+ simap_increase(usage, "raft-backlog", -+ jsonrpc_session_get_backlog(conn->js)); ++ backlog += jsonrpc_session_get_backlog(conn->js); + cnt++; + } ++ simap_increase(usage, "raft-backlog-kB", backlog / 1000); + simap_increase(usage, "raft-connections", cnt); ++ simap_increase(usage, "raft-log", raft->log_end - raft->log_start); +} + /* Returns true if 'raft' has completed joining its cluster, has not left or * initiated leaving the cluster, does not have failed disk storage, and is * apparently connected to the leader in a healthy way (or is itself the -@@ -1024,7 +1047,8 @@ raft_is_connected(const struct raft *raft) +@@ -1020,12 +1056,22 @@ raft_get_sid(const struct raft *raft) + bool + raft_is_connected(const struct raft *raft) + { ++ static bool last_state = false; + bool ret = (!raft->candidate_retrying && !raft->joining && !raft->leaving && !raft->left - && !raft->failed); +- VLOG_DBG("raft_is_connected: %s\n", ret? "true": "false"); + && !raft->failed + && raft->ever_had_leader); - VLOG_DBG("raft_is_connected: %s\n", ret? "true": "false"); ++ ++ if (!ret) { ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); ++ VLOG_DBG_RL(&rl, "raft_is_connected: false"); ++ } else if (!last_state) { ++ VLOG_DBG("raft_is_connected: true"); ++ } ++ last_state = ret; ++ return ret; } -@@ -1397,8 +1421,20 @@ raft_conn_run(struct raft *raft, struct raft_conn *conn) + +@@ -1397,8 +1443,19 @@ raft_conn_run(struct raft *raft, struct raft_conn *conn) jsonrpc_session_run(conn->js); unsigned int new_seqno = jsonrpc_session_get_seqno(conn->js); @@ -40669,19 +41643,18 @@ index 4789bc4f22..8df386fa19 100644 && jsonrpc_session_is_connected(conn->js)); + + if (reconnected) { -+ /* Clear 'last_install_snapshot_request' since it might not reach the -+ * destination or server was restarted. */ ++ /* Clear 'install_snapshot_request_in_progress' since it might not ++ * reach the destination or server was restarted. */ + struct raft_server *server = raft_find_server(raft, &conn->sid); + if (server) { -+ free(server->last_install_snapshot_request); -+ server->last_install_snapshot_request = NULL; ++ server->install_snapshot_request_in_progress = false; + } + } + conn->js_seqno = new_seqno; if (just_connected) { if (raft->joining) { -@@ -1641,6 +1677,7 @@ raft_start_election(struct raft *raft, bool leadership_transfer) +@@ -1641,6 +1698,7 @@ raft_start_election(struct raft *raft, bool leadership_transfer) } ovs_assert(raft->role != RAFT_LEADER); @@ -40689,7 +41662,7 @@ index 4789bc4f22..8df386fa19 100644 raft->role = RAFT_CANDIDATE; /* If there was no leader elected since last election, we know we are * retrying now. */ -@@ -1684,7 +1721,9 @@ raft_start_election(struct raft *raft, bool leadership_transfer) +@@ -1684,7 +1742,9 @@ raft_start_election(struct raft *raft, bool leadership_transfer) .leadership_transfer = leadership_transfer, }, }; @@ -40700,7 +41673,14 @@ index 4789bc4f22..8df386fa19 100644 } /* Vote for ourselves. */ -@@ -2519,7 +2558,7 @@ static void +@@ -2513,13 +2573,14 @@ raft_server_init_leader(struct raft *raft, struct raft_server *s) + s->match_index = 0; + s->phase = RAFT_PHASE_STABLE; + s->replied = false; ++ s->install_snapshot_request_in_progress = false; + } + + static void raft_set_leader(struct raft *raft, const struct uuid *sid) { raft->leader_sid = *sid; @@ -40709,7 +41689,7 @@ index 4789bc4f22..8df386fa19 100644 raft->candidate_retrying = false; } -@@ -2960,6 +2999,15 @@ raft_update_leader(struct raft *raft, const struct uuid *sid) +@@ -2960,6 +3021,15 @@ raft_update_leader(struct raft *raft, const struct uuid *sid) }; ignore(ovsdb_log_write_and_free(raft->log, raft_record_to_json(&r))); } @@ -40725,39 +41705,47 @@ index 4789bc4f22..8df386fa19 100644 return true; } -@@ -3260,6 +3308,31 @@ raft_send_install_snapshot_request(struct raft *raft, +@@ -3260,7 +3330,20 @@ raft_send_install_snapshot_request(struct raft *raft, .election_timer = raft->election_timer, /* use latest value */ } }; +- raft_send(raft, &rpc); + -+ if (s->last_install_snapshot_request) { -+ struct raft_install_snapshot_request *old, *new; -+ -+ old = s->last_install_snapshot_request; -+ new = &rpc.install_snapshot_request; -+ if ( old->term == new->term -+ && old->last_index == new->last_index -+ && old->last_term == new->last_term -+ && old->last_servers == new->last_servers -+ && old->data == new->data -+ && old->election_timer == new->election_timer -+ && uuid_equals(&old->last_eid, &new->last_eid)) { -+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); -+ -+ VLOG_WARN_RL(&rl, "not sending exact same install_snapshot_request" -+ " to server %s again", s->nickname); -+ return; -+ } ++ if (s->install_snapshot_request_in_progress) { ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); ++ ++ VLOG_INFO_RL(&rl, "not sending snapshot to server %s, " ++ "already in progress", s->nickname); ++ return; + } -+ free(s->last_install_snapshot_request); -+ CONST_CAST(struct raft_server *, s)->last_install_snapshot_request -+ = xmemdup(&rpc.install_snapshot_request, -+ sizeof rpc.install_snapshot_request); + - raft_send(raft, &rpc); ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); ++ VLOG_INFO_RL(&rl, "sending snapshot to server %s, %"PRIu64":%"PRIu64".", ++ s->nickname, raft->term, raft->log_start - 1); ++ CONST_CAST(struct raft_server *, s)->install_snapshot_request_in_progress ++ = raft_send(raft, &rpc); } -@@ -3992,8 +4065,9 @@ raft_handle_install_snapshot_reply( + static void +@@ -3913,7 +3996,7 @@ raft_handle_install_snapshot_request__( + struct ovsdb_error *error = raft_save_snapshot(raft, new_log_start, + &new_snapshot); + if (error) { +- char *error_s = ovsdb_error_to_string(error); ++ char *error_s = ovsdb_error_to_string_free(error); + VLOG_WARN("could not save snapshot: %s", error_s); + free(error_s); + return false; +@@ -3977,6 +4060,8 @@ raft_handle_install_snapshot_reply( + } + } + ++ s->install_snapshot_request_in_progress = false; ++ + if (rpy->last_index != raft->log_start - 1 || + rpy->last_term != raft->snap.term) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); +@@ -3992,8 +4077,9 @@ raft_handle_install_snapshot_reply( VLOG_INFO_RL(&rl, "cluster "CID_FMT": installed snapshot on server %s " " up to %"PRIu64":%"PRIu64, CID_ARGS(&raft->cid), s->nickname, rpy->last_term, rpy->last_index); @@ -40769,7 +41757,7 @@ index 4789bc4f22..8df386fa19 100644 } /* Returns true if 'raft' has grown enough since the last snapshot that -@@ -4143,9 +4217,7 @@ raft_handle_execute_command_request__( +@@ -4143,9 +4229,7 @@ raft_handle_execute_command_request__( cmd->sid = rq->common.sid; enum raft_command_status status = cmd->status; @@ -40780,7 +41768,50 @@ index 4789bc4f22..8df386fa19 100644 return status; } -@@ -4667,6 +4739,8 @@ raft_unixctl_failure_test(struct unixctl_conn *conn OVS_UNUSED, +@@ -4639,6 +4723,42 @@ raft_unixctl_change_election_timer(struct unixctl_conn *conn, + unixctl_command_reply(conn, "change of election timer initiated."); + } + ++static void ++raft_unixctl_set_backlog_threshold(struct unixctl_conn *conn, ++ int argc OVS_UNUSED, const char *argv[], ++ void *aux OVS_UNUSED) ++{ ++ const char *cluster_name = argv[1]; ++ unsigned long long n_msgs, n_bytes; ++ struct raft_conn *r_conn; ++ ++ struct raft *raft = raft_lookup_by_name(cluster_name); ++ if (!raft) { ++ unixctl_command_reply_error(conn, "unknown cluster"); ++ return; ++ } ++ ++ if (!str_to_ullong(argv[2], 10, &n_msgs) ++ || !str_to_ullong(argv[3], 10, &n_bytes)) { ++ unixctl_command_reply_error(conn, "invalid argument"); ++ return; ++ } ++ ++ if (n_msgs < 50 || n_msgs > SIZE_MAX || n_bytes > SIZE_MAX) { ++ unixctl_command_reply_error(conn, "values out of range"); ++ return; ++ } ++ ++ raft->conn_backlog_max_n_msgs = n_msgs; ++ raft->conn_backlog_max_n_bytes = n_bytes; ++ ++ LIST_FOR_EACH (r_conn, list_node, &raft->conns) { ++ jsonrpc_session_set_backlog_threshold(r_conn->js, n_msgs, n_bytes); ++ } ++ ++ unixctl_command_reply(conn, NULL); ++} ++ + static void + raft_unixctl_failure_test(struct unixctl_conn *conn OVS_UNUSED, + int argc OVS_UNUSED, const char *argv[], +@@ -4667,6 +4787,8 @@ raft_unixctl_failure_test(struct unixctl_conn *conn OVS_UNUSED, raft_reset_election_timer(raft); } } @@ -40789,6 +41820,16 @@ index 4789bc4f22..8df386fa19 100644 } else if (!strcmp(test, "clear")) { failure_test = FT_NO_TEST; unixctl_command_reply(conn, "test dismissed"); +@@ -4697,6 +4819,9 @@ raft_init(void) + raft_unixctl_kick, NULL); + unixctl_command_register("cluster/change-election-timer", "DB TIME", 2, 2, + raft_unixctl_change_election_timer, NULL); ++ unixctl_command_register("cluster/set-backlog-threshold", ++ "DB N_MSGS N_BYTES", 3, 3, ++ raft_unixctl_set_backlog_threshold, NULL); + unixctl_command_register("cluster/failure-test", "FAILURE SCENARIO", 1, 1, + raft_unixctl_failure_test, NULL); + ovsthread_once_done(&once); diff --git a/ovsdb/raft.h b/ovsdb/raft.h index 3d448995af..99d5307e54 100644 --- a/ovsdb/raft.h @@ -40923,6 +41964,53 @@ index b8027af863..a658823028 100755 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. +diff --git a/python/ovs/stream.py b/python/ovs/stream.py +index e9bb0c8548..f5a520862c 100644 +--- a/python/ovs/stream.py ++++ b/python/ovs/stream.py +@@ -132,6 +132,10 @@ class Stream(object): + IPTOS_PREC_INTERNETCONTROL = 0xc0 + DSCP_DEFAULT = IPTOS_PREC_INTERNETCONTROL >> 2 + ++ @staticmethod ++ def check_connection_completion(sock): ++ return ovs.socket_util.check_connection_completion(sock) ++ + @staticmethod + def open(name, dscp=DSCP_DEFAULT): + """Attempts to connect a stream to a remote peer. 'name' is a +@@ -189,7 +193,7 @@ class Stream(object): + if error: + return error, None + else: +- err = ovs.socket_util.check_connection_completion(sock) ++ err = cls.check_connection_completion(sock) + if err == errno.EAGAIN or err == errno.EINPROGRESS: + status = errno.EAGAIN + err = 0 +@@ -261,7 +265,7 @@ class Stream(object): + + def __scs_connecting(self): + if self.socket is not None: +- retval = ovs.socket_util.check_connection_completion(self.socket) ++ retval = self.check_connection_completion(self.socket) + assert retval != errno.EINPROGRESS + elif sys.platform == 'win32': + if self.retry_connect: +@@ -761,6 +765,13 @@ Stream.register_method("tcp", TCPStream) + + + class SSLStream(Stream): ++ @staticmethod ++ def check_connection_completion(sock): ++ try: ++ return Stream.check_connection_completion(sock) ++ except SSL.SysCallError as e: ++ return ovs.socket_util.get_exception_errno(e) ++ + @staticmethod + def needs_probes(): + return True diff --git a/rhel/openvswitch-fedora.spec.in b/rhel/openvswitch-fedora.spec.in index 7bc8c34b80..f6ec347c15 100644 --- a/rhel/openvswitch-fedora.spec.in @@ -41183,6 +42271,28 @@ index bee79fc50f..d08f7e7ead 100644 "simple": { "columns": { "b": { +diff --git a/tests/ofp-actions.at b/tests/ofp-actions.at +index 4893280a99..7cb09498e6 100644 +--- a/tests/ofp-actions.at ++++ b/tests/ofp-actions.at +@@ -766,6 +766,17 @@ dnl Check OpenFlow v1.3.4 Conformance Test: 430.510. + & 00000010 00 00 00 10 00 00 00 01- + 0019 0010 80000807 000102030405 000000000010 00000001 + ++dnl Check NSH encap (experimenter extension). ++# actions=encap(nsh(md_type=1)) ++ffff 0018 00002320 002e 0000 0001894f 0004 01 05 01 000000 ++ ++dnl NSH encap with non-zero padding. ++# actions=encap(nsh(md_type=1)) ++# 21: 12 -> 00 ++# 22: 34 -> 00 ++# 23: 56 -> 00 ++ffff 0018 00002320 002e 0000 0001894f 0004 01 05 01 123456 ++ + ]) + sed '/^[[#&]]/d' < test-data > input.txt + sed -n 's/^# //p; /^$/p' < test-data > expout diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index ff1cc93707..6415a8a04d 100644 --- a/tests/ofproto-dpif.at @@ -41317,6 +42427,34 @@ index ff1cc93707..6415a8a04d 100644 AT_SETUP([ofproto-dpif - conntrack - ofproto/trace]) OVS_VSWITCHD_START +diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at +index c8062c8acc..9466a8cc43 100644 +--- a/tests/ovs-ofctl.at ++++ b/tests/ovs-ofctl.at +@@ -101,6 +101,7 @@ for test_case in \ + 'mpls,mpls_label=5 NXM,OXM,OpenFlow11' \ + 'mpls,mpls_tc=1 NXM,OXM,OpenFlow11' \ + 'mpls,mpls_bos=0 NXM,OXM' \ ++ 'mpls,mpls_ttl=5 NXM,OXM' \ + 'ip,ip_src=1.2.3.4 any' \ + 'ip,ip_src=192.168.0.0/24 any' \ + 'ip,ip_src=192.0.168.0/255.0.255.0 NXM,OXM,OpenFlow11' \ +@@ -434,6 +435,7 @@ tcp,actions=fin_timeout(idle_timeout=5,hard_timeout=15) + actions=controller(max_len=123,reason=invalid_ttl,id=555) + actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678) + actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789) ++mpls,mpls_label=5,mpls_tc=1,mpls_ttl=1,mpls_bos=0,actions=drop + ip,actions=ct(commit,zone=5) + ip,actions=ct(commit,exec(load(1->NXM_NX_CT_MARK[]))) + ip,actions=ct(commit,exec(load(0x1->NXM_NX_CT_LABEL[]))) +@@ -490,6 +492,7 @@ NXT_FLOW_MOD: ADD table:255 tcp actions=fin_timeout(idle_timeout=5,hard_timeout= + NXT_FLOW_MOD: ADD table:255 actions=controller(reason=invalid_ttl,max_len=123,id=555) + NXT_FLOW_MOD: ADD table:255 actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678) + NXT_FLOW_MOD: ADD table:255 actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789) ++NXT_FLOW_MOD: ADD table:255 mpls,mpls_label=5,mpls_tc=1,mpls_ttl=1,mpls_bos=0 actions=drop + NXT_FLOW_MOD: ADD table:255 ip actions=ct(commit,zone=5) + NXT_FLOW_MOD: ADD table:255 ip actions=ct(commit,exec(load:0x1->NXM_NX_CT_MARK[])) + NXT_FLOW_MOD: ADD table:255 ip actions=ct(commit,exec(load:0x1->NXM_NX_CT_LABEL[0..63],load:0->NXM_NX_CT_LABEL[64..127])) diff --git a/tests/ovs-vsctl.at b/tests/ovs-vsctl.at index 55c7a6e179..c8babe3612 100644 --- a/tests/ovs-vsctl.at @@ -41534,7 +42672,7 @@ index 3a0bd4579e..e0758e954c 100644 AT_BANNER([OVSDB - cluster tests]) diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at -index cc38d69c10..e5397ff99d 100644 +index cc38d69c10..c12896c587 100644 --- a/tests/ovsdb-idl.at +++ b/tests/ovsdb-idl.at @@ -12,25 +12,6 @@ ovsdb_start_idltest () { @@ -41581,13 +42719,13 @@ index cc38d69c10..e5397ff99d 100644 + AT_CHECK([ovsdb-tool join-cluster s$i.db \ + $schema_name unix:s$i.raft unix:s1.raft]) + done ++ on_exit 'kill $(cat s*.pid)' + for i in $(seq $n); do + AT_CHECK([ovsdb-server -vraft -vconsole:warn --detach --no-chdir \ + --log-file=s$i.log --pidfile=s$i.pid --unixctl=s$i \ + --remote=punix:s$i.ovsdb \ + m4_if([$2], [], [], [--remote=$2]) s$i.db]) + done -+ on_exit 'kill $(cat s*.pid)' + + for i in $(seq $n); do + OVS_WAIT_UNTIL([ovs-appctl -t $(pwd)/s$i cluster/status ${schema_name} \ @@ -41607,7 +42745,88 @@ index cc38d69c10..e5397ff99d 100644 test-ovsdb|ovsdb_idl|idltest database lacks link2 table (database needs upgrade?) test-ovsdb|ovsdb_idl|idltest database lacks singleton table (database needs upgrade?) test-ovsdb|ovsdb_idl|link1 table in idltest database lacks l2 column (database needs upgrade?) -@@ -1798,7 +1809,7 @@ m4_define([OVSDB_CHECK_IDL_LEADER_ONLY_PY], +@@ -1150,6 +1161,7 @@ OVSDB_CHECK_IDL_TRACK([track, simple idl, initially populated], + "where": [], + "row": {"b": true}}]']], + [[000: i=1 r=2 b=true s=mystring u=<0> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<1> <2>] uuid=<3> ++000: inserted row: uuid=<3> + 000: updated columns: b ba i ia r ra s sa u ua + 001: {"error":null,"result":[{"count":2}]} + 002: i=0 r=0 b=true s= u=<4> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<5> +@@ -1212,6 +1224,7 @@ OVSDB_CHECK_IDL_TRACK([track, simple idl, initially empty, various ops], + [[000: empty + 001: {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]}]} + 002: i=1 r=2 b=true s=mystring u=<2> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<3> <4>] uuid=<0> ++002: inserted row: uuid=<0> + 002: updated columns: b ba i ia r ra s sa u ua + 003: {"error":null,"result":[{"count":2}]} + 004: i=0 r=0 b=true s= u=<5> ia=[] ra=[] ba=[] sa=[] ua=[] uuid=<1> +@@ -1223,6 +1236,7 @@ OVSDB_CHECK_IDL_TRACK([track, simple idl, initially empty, various ops], + 006: updated columns: r + 007: {"error":null,"result":[{"uuid":["uuid","<6>"]}]} + 008: i=-1 r=125 b=false s= u=<5> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6> ++008: inserted row: uuid=<6> + 008: updated columns: ba i ia r ra + 009: {"error":null,"result":[{"count":2}]} + 010: i=-1 r=125 b=false s=newstring u=<5> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6> +@@ -1230,7 +1244,7 @@ OVSDB_CHECK_IDL_TRACK([track, simple idl, initially empty, various ops], + 010: updated columns: s + 010: updated columns: s + 011: {"error":null,"result":[{"count":1}]} +-012: ##deleted## uuid=<1> ++012: deleted row: uuid=<1> + 013: reconnect + 014: i=-1 r=125 b=false s=newstring u=<5> ia=[1] ra=[1.5] ba=[false] sa=[] ua=[] uuid=<6> + 014: i=1 r=123.5 b=true s=mystring u=<2> ia=[1 2 3] ra=[-0.5] ba=[true] sa=[abc def] ua=[<3> <4>] uuid=<0> +@@ -1764,33 +1778,25 @@ OVSDB_CHECK_IDL_COMPOUND_INDEX_WITH_REF([set, simple3 idl-compound-index-with-re + ]]) + + m4_define([CHECK_STREAM_OPEN_BLOCK], +- [AT_SETUP([Check Stream open block - C - $1]) +- AT_SKIP_IF([test "$1" = "tcp6" && test "$IS_WIN32" = "yes"]) +- AT_SKIP_IF([test "$1" = "tcp6" && test "$HAVE_IPV6" = "no"]) +- AT_KEYWORDS([Check Stream open block $1]) +- AT_CHECK([ovsdb_start_idltest "ptcp:0:$2"]) ++ [AT_SETUP([Check stream open block - $1 - $3]) ++ AT_SKIP_IF([test "$3" = "tcp6" && test "$IS_WIN32" = "yes"]) ++ AT_SKIP_IF([test "$3" = "tcp6" && test "$HAVE_IPV6" = "no"]) ++ AT_KEYWORDS([ovsdb server stream open_block $3]) ++ AT_CHECK([ovsdb_start_idltest "ptcp:0:$4"]) + PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT]) + WRONG_PORT=$(($TCP_PORT + 101)) +- AT_CHECK([test-stream tcp:$2:$TCP_PORT], [0], [ignore]) +- AT_CHECK([test-stream tcp:$2:$WRONG_PORT], [1], [ignore], [ignore]) ++ AT_CHECK([$2 tcp:$4:$TCP_PORT], [0], [ignore]) ++ AT_CHECK([$2 tcp:$4:$WRONG_PORT], [1], [ignore], [ignore]) + OVSDB_SERVER_SHUTDOWN +- AT_CHECK([test-stream tcp:$2:$TCP_PORT], [1], [ignore], [ignore]) ++ AT_CHECK([$2 tcp:$4:$TCP_PORT], [1], [ignore], [ignore]) + AT_CLEANUP]) + +-CHECK_STREAM_OPEN_BLOCK([tcp], [127.0.0.1]) +-CHECK_STREAM_OPEN_BLOCK([tcp6], [[[::1]]]) +- +-m4_define([CHECK_STREAM_OPEN_BLOCK_PY], +- [AT_SETUP([$1 - Python3]) +- AT_KEYWORDS([Check PY Stream open block - $3]) +- AT_CHECK([ovsdb_start_idltest "ptcp:0:127.0.0.1"]) +- PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT]) +- WRONG_PORT=$(($TCP_PORT + 101)) +- AT_CHECK([$3 $srcdir/test-stream.py tcp:127.0.0.1:$TCP_PORT], [0], [ignore]) +- AT_CHECK([$3 $srcdir/test-stream.py tcp:127.0.0.1:$WRONG_PORT], [1], [ignore]) +- OVSDB_SERVER_SHUTDOWN +- AT_CHECK([$3 $srcdir/test-stream.py tcp:127.0.0.1:$TCP_PORT], [1], [ignore]) +- AT_CLEANUP]) ++CHECK_STREAM_OPEN_BLOCK([C], [test-stream], [tcp], [127.0.0.1]) ++CHECK_STREAM_OPEN_BLOCK([C], [test-stream], [tcp6], [[[::1]]]) ++CHECK_STREAM_OPEN_BLOCK([Python3], [$PYTHON3 $srcdir/test-stream.py], ++ [tcp], [127.0.0.1]) ++CHECK_STREAM_OPEN_BLOCK([Python3], [$PYTHON3 $srcdir/test-stream.py], ++ [tcp6], [[[::1]]]) + + # same as OVSDB_CHECK_IDL but uses Python IDL implementation with tcp + # with multiple remotes to assert the idl connects to the leader of the Raft cluster +@@ -1798,7 +1804,7 @@ m4_define([OVSDB_CHECK_IDL_LEADER_ONLY_PY], [AT_SETUP([$1 - Python3 (leader only)]) AT_KEYWORDS([ovsdb server idl Python leader_only with tcp socket]) m4_define([LPBK],[127.0.0.1]) @@ -41616,7 +42835,7 @@ index cc38d69c10..e5397ff99d 100644 PARSE_LISTENING_PORT([s2.log], [TCP_PORT_1]) PARSE_LISTENING_PORT([s3.log], [TCP_PORT_2]) PARSE_LISTENING_PORT([s1.log], [TCP_PORT_3]) -@@ -1814,3 +1825,59 @@ m4_define([OVSDB_CHECK_IDL_LEADER_ONLY_PY], +@@ -1814,3 +1820,59 @@ m4_define([OVSDB_CHECK_IDL_LEADER_ONLY_PY], OVSDB_CHECK_IDL_LEADER_ONLY_PY([Check Python IDL connects to leader], 3, ['remote']) OVSDB_CHECK_IDL_LEADER_ONLY_PY([Check Python IDL reconnects to leader], 3, ['remote' '+remotestop' 'remote']) @@ -41767,6 +42986,34 @@ index 4a39c929c2..3ed03d92b5 100644 OVS_APP_EXIT_AND_WAIT([ovs-ofctl]) OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP +diff --git a/tests/system-userspace-packet-type-aware.at b/tests/system-userspace-packet-type-aware.at +index c2246316de..974304758f 100644 +--- a/tests/system-userspace-packet-type-aware.at ++++ b/tests/system-userspace-packet-type-aware.at +@@ -129,6 +129,7 @@ AT_CHECK([ + ip addr add 10.0.0.1/24 dev br-p1 + ip link set br-p1 up + ], [0], [stdout]) ++OVS_WAIT_UNTIL([ovs-appctl ovs/route/show | grep -q br-p1]) + + AT_CHECK([ + ovs-appctl ovs/route/add 10.0.0.0/24 br-p1 +@@ -141,6 +142,7 @@ AT_CHECK([ + ip addr add 20.0.0.2/24 dev br-p2 + ip link set br-p2 up + ], [0], [stdout]) ++OVS_WAIT_UNTIL([ovs-appctl ovs/route/show | grep -q br-p2]) + + AT_CHECK([ + ovs-appctl ovs/route/add 20.0.0.0/24 br-p2 +@@ -153,6 +155,7 @@ AT_CHECK([ + ip addr add 30.0.0.3/24 dev br-p3 + ip link set br-p3 up + ], [0], [stdout]) ++OVS_WAIT_UNTIL([ovs-appctl ovs/route/show | grep -q br-p3]) + + AT_CHECK([ + ovs-appctl ovs/route/add 30.0.0.0/24 br-p3 diff --git a/tests/system-userspace-testsuite.at b/tests/system-userspace-testsuite.at index b40da9579e..2e9659a675 100644 --- a/tests/system-userspace-testsuite.at @@ -41826,6 +43073,128 @@ index d7854a1df3..32a77392c6 100755 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. +diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c +index b1a4be36bb..aade40f3fb 100644 +--- a/tests/test-ovsdb.c ++++ b/tests/test-ovsdb.c +@@ -2030,7 +2030,7 @@ print_idl(struct ovsdb_idl *idl, int step) + } + + static void +-print_idl_track(struct ovsdb_idl *idl, int step, unsigned int seqno) ++print_idl_track(struct ovsdb_idl *idl, int step) + { + const struct idltest_simple *s; + const struct idltest_link1 *l1; +@@ -2038,26 +2038,42 @@ print_idl_track(struct ovsdb_idl *idl, int step, unsigned int seqno) + int n = 0; + + IDLTEST_SIMPLE_FOR_EACH_TRACKED (s, idl) { +- if (idltest_simple_row_get_seqno(s, OVSDB_IDL_CHANGE_DELETE) >= seqno) { +- printf("%03d: ##deleted## uuid="UUID_FMT"\n", step, UUID_ARGS(&s->header_.uuid)); ++ if (idltest_simple_is_deleted(s)) { ++ printf("%03d: deleted row: uuid="UUID_FMT"\n", step, ++ UUID_ARGS(&s->header_.uuid)); + } else { + print_idl_row_simple(s, step); ++ if (idltest_simple_is_new(s)) { ++ printf("%03d: inserted row: uuid="UUID_FMT"\n", step, ++ UUID_ARGS(&s->header_.uuid)); ++ } + } + n++; + } + IDLTEST_LINK1_FOR_EACH_TRACKED (l1, idl) { +- if (idltest_simple_row_get_seqno(s, OVSDB_IDL_CHANGE_DELETE) >= seqno) { +- printf("%03d: ##deleted## uuid="UUID_FMT"\n", step, UUID_ARGS(&s->header_.uuid)); ++ if (idltest_link1_is_deleted(l1)) { ++ printf("%03d: deleted row: uuid="UUID_FMT"\n", step, ++ UUID_ARGS(&l1->header_.uuid)); + } else { + print_idl_row_link1(l1, step); ++ if (idltest_link1_is_new(l1)) { ++ printf("%03d: inserted row: uuid="UUID_FMT"\n", step, ++ UUID_ARGS(&l1->header_.uuid)); ++ } + } + n++; + } + IDLTEST_LINK2_FOR_EACH_TRACKED (l2, idl) { +- if (idltest_simple_row_get_seqno(s, OVSDB_IDL_CHANGE_DELETE) >= seqno) { +- printf("%03d: ##deleted## uuid="UUID_FMT"\n", step, UUID_ARGS(&s->header_.uuid)); ++ if (idltest_link2_is_deleted(l2)) { ++ printf("%03d: deleted row: uuid="UUID_FMT"\n", step, ++ UUID_ARGS(&l2->header_.uuid)); + } else { + print_idl_row_link2(l2, step); ++ if (idltest_link2_is_new(l2)) { ++ printf("%03d: inserted row: uuid="UUID_FMT"\n", step, ++ UUID_ARGS(&l2->header_.uuid)); ++ } ++ + } + n++; + } +@@ -2391,6 +2407,10 @@ update_conditions(struct ovsdb_idl *idl, char *commands) + if (seqno == next_seqno ) { + ovs_fatal(0, "condition unchanged"); + } ++ unsigned int new_next_seqno = ovsdb_idl_set_condition(idl, tc, &cond); ++ if (next_seqno != new_next_seqno) { ++ ovs_fatal(0, "condition expected seqno changed"); ++ } + ovsdb_idl_condition_destroy(&cond); + json_destroy(json); + } +@@ -2465,7 +2485,7 @@ do_idl(struct ovs_cmdl_context *ctx) + + /* Print update. */ + if (track) { +- print_idl_track(idl, step++, ovsdb_idl_get_seqno(idl)); ++ print_idl_track(idl, step++); + ovsdb_idl_track_clear(idl); + } else { + print_idl(idl, step++); +diff --git a/tests/tunnel.at b/tests/tunnel.at +index ce000a25e6..7a6b7f42c6 100644 +--- a/tests/tunnel.at ++++ b/tests/tunnel.at +@@ -110,6 +110,35 @@ Datapath actions: drop + OVS_VSWITCHD_STOP(["/dropping tunnel packet marked ECN CE but is not ECN capable/d"]) + AT_CLEANUP + ++AT_SETUP([tunnel - too long nested attributes]) ++OVS_VSWITCHD_START([add-port br0 p1 \ ++ -- set Interface p1 type=gre options:remote_ip=1.1.1.1 ofport_request=1 \ ++ -- add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2]) ++ ++AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl ++ br0 65534/100: (dummy-internal) ++ p1 1/1: (gre: remote_ip=1.1.1.1) ++ p2 2/2: (dummy) ++]) ++ ++dst_single="dst=1.1.1.1" ++dst_rep=${dst_single} ++dnl Size of one OVS_TUNNEL_KEY_ATTR_IPV4_DST is 4 bytes + NLA_HDRLEN (4 bytes). ++dnl One nested message has room for UINT16_MAX - NLA_HDRLEN (4) bytes, i.e. ++dnl (UINT16_MAX - NLA_HDRLEN) / (4 + NLA_HDRLEN) = 8191.375 of dst addresses. ++for i in `seq 1 8192` ; do ++ dst_rep="${dst_rep},${dst_single}" ++done ++ ++AT_CHECK([ovs-appctl dpctl/add-flow "tunnel(${dst_rep})" "2" 2>&1 | dnl ++ sed "s/${dst_single},//g"], [], [dnl ++ovs-vswitchd: parsing flow key (syntax error at tunnel(dst=1.1.1.1)) (Argument list too long) ++ovs-appctl: ovs-vswitchd: server returned an error ++]) ++ ++OVS_VSWITCHD_STOP ++AT_CLEANUP ++ + AT_SETUP([tunnel - output]) + OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=gre \ + options:remote_ip=1.1.1.1 options:local_ip=2.2.2.2 \ diff --git a/tests/uuidfilt.py b/tests/uuidfilt.py index bc49aa480e..39679dd444 100755 --- a/tests/uuidfilt.py @@ -41853,7 +43222,7 @@ index bc49aa480e..39679dd444 100755 import re import sys diff --git a/utilities/bugtool/ovs-bugtool.in b/utilities/bugtool/ovs-bugtool.in -index e55bfc2ed5..47f3c4629f 100755 +index e55bfc2ed5..987d211069 100755 --- a/utilities/bugtool/ovs-bugtool.in +++ b/utilities/bugtool/ovs-bugtool.in @@ -33,8 +33,7 @@ @@ -41912,12 +43281,25 @@ index e55bfc2ed5..47f3c4629f 100755 def main(argv=None): -@@ -704,7 +706,7 @@ exclude those logs from the archive. +@@ -682,8 +684,8 @@ exclude those logs from the archive. + ovs_info_caps = [CAP_NETWORK_STATUS, CAP_SYSTEM_LOGS, + CAP_OPENVSWITCH_LOGS, CAP_NETWORK_CONFIG] + ovs_info_list = ['process-tree'] +- # We cannot use iteritems, since we modify 'data' as we pass through +- for (k, v) in data.items(): ++ # We cannot use items(), since we modify 'data' as we pass through ++ for (k, v) in list(data.items()): + cap = v['cap'] + if 'filename' in v: + info = k[0] +@@ -703,8 +705,8 @@ exclude those logs from the archive. + pass # permit the user to filter out data - # We cannot use iteritems, since we modify 'data' as we pass through +- # We cannot use iteritems, since we modify 'data' as we pass through - for (k, v) in sorted(data.items()): -+ for (k, v) in data.items(): ++ # We cannot use items(), since we modify 'data' as we pass through ++ for (k, v) in list(data.items()): cap = v['cap'] if 'filename' in v: key = k[0] diff --git a/SPECS/openvswitch2.13.spec b/SPECS/openvswitch2.13.spec index c9a5805..22556ed 100644 --- a/SPECS/openvswitch2.13.spec +++ b/SPECS/openvswitch2.13.spec @@ -59,7 +59,7 @@ Summary: Open vSwitch Group: System Environment/Daemons daemon/database/utilities URL: http://www.openvswitch.org/ Version: 2.13.0 -Release: 60%{?commit0:.%{date}git%{shortcommit0}}%{?commit1:dpdk%{shortcommit1}}%{?dist} +Release: 71%{?commit0:.%{date}git%{shortcommit0}}%{?commit1:dpdk%{shortcommit1}}%{?dist} # Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the # lib/sflow*.[ch] files are SISSL @@ -111,6 +111,9 @@ ExclusiveArch: x86_64 aarch64 ppc64le s390x # Provides: openvswitch Conflicts: openvswitch < 2.13 Conflicts: openvswitch-dpdk < 2.13 +Conflicts: openvswitch2.10 +Conflicts: openvswitch2.11 +Conflicts: openvswitch2.12 # dpdk_mach_arch maps between rpm and dpdk arch name, often same as _target_cpu # dpdk_mach_tmpl is the config template dpdk_mach name, often "native" @@ -465,6 +468,9 @@ install -p -D -m 0755 \ $RPM_BUILD_ROOT%{_datadir}/openvswitch/scripts/ovs-systemd-reload touch $RPM_BUILD_ROOT%{_sysconfdir}/openvswitch/conf.db +# The db needs special permission as IPsec Pre-shared keys are stored in it. +chmod 0640 $RPM_BUILD_ROOT%{_sysconfdir}/openvswitch/conf.db + touch $RPM_BUILD_ROOT%{_sysconfdir}/openvswitch/system-id.conf # remove unpackaged files @@ -697,6 +703,50 @@ exit 0 %endif %changelog +* Mon Nov 16 2020 Open vSwitch CI - 2.13.0-71 +- Merging upstream branch-2.13 + [2aae1815250d0236b6ee7f074f864bf4d2af5537] + +* Wed Nov 11 2020 Flavio Leitner - 2.13.0-70 +- redhat: Fix conf.db permissions in the spec. + [46d36172986f80091292beb55e2124d1d7a80a6e] + +* Wed Nov 11 2020 Flavio Leitner - 2.13.0-69 +- Merging d43d10e10c netdev-offload-dpdk: Preserve HW statistics.. + [a779495d0366223d2cdfd62ccd878ba68d6568df] + +* Mon Nov 09 2020 Flavio Leitner - 2.13.0-68 +- Merging dc5b4e8f69 ovs-bugtool: Fix crash when enable --ovs. + [de7f5508d74813425812e10fe2bf59d1770e1f23] + +* Thu Nov 05 2020 Ilya Maximets - 2.13.0-67 +- Merging upstream branch-2.13 + [03753de14fe750a686db5eb0ce9a16df89e0d647] + +* Wed Nov 04 2020 Ilya Maximets - 2.13.0-66 +- Merging upstream branch-2.13 + [373b7e9f5192ac2d757e6750e9468746d2f6c52f] + +* Tue Oct 27 2020 Open vSwitch CI - 2.13.0-65 +- Merging upstream branch-2.13 + [f9a054c1b5f25a501106bec2fb5b9cf1259ddca0] + +* Sat Oct 24 2020 Open vSwitch CI - 2.13.0-64 +- Merging upstream branch-2.13 + [73eb33dcf1bf45fb35c125e4573bf130bc181d16] + +* Wed Oct 21 2020 Open vSwitch CI - 2.13.0-63 +- Merging upstream branch-2.13 + [6f80f8c230dadd1c4c8a6830aab018271b79f66e] + +* Wed Oct 21 2020 Timothy Redaelli - 2.13.0-62 +- redhat: Add conflicts for older versioned packages (#1886836) + [b1f563c73886c6bded2f4b076f52caa5b12cd026] + +* Fri Oct 09 2020 Open vSwitch CI - 2.13.0-61 +- Merging upstream branch-2.13 + [fa57a21817ef306b17d45fe9e64dda8ad86a806f] + * Wed Sep 16 2020 Open vSwitch CI - 2.13.0-60 - Merging upstream branch-2.13 [38d21cf4eb02e273ef28b46e63bcf877d5a672ea]