diff --git a/SOURCES/openvswitch-2.17.0.patch b/SOURCES/openvswitch-2.17.0.patch index 0e63353..99cb42d 100644 --- a/SOURCES/openvswitch-2.17.0.patch +++ b/SOURCES/openvswitch-2.17.0.patch @@ -336,13 +336,19 @@ index 27be4aa412..1dc406170f 100644 +.. |emeritus-status| replace:: `Emeritus Status for OVS Committers + `__ diff --git a/NEWS b/NEWS -index c10e9bfacc..45b974ed22 100644 +index c10e9bfacc..095b0574f4 100644 --- a/NEWS +++ b/NEWS -@@ -1,3 +1,69 @@ -+v2.17.6 - xx xxx xxxx +@@ -1,3 +1,75 @@ ++v2.17.7 - xx xxx xxxx +--------------------- + ++v2.17.6 - 06 Apr 2023 ++--------------------- ++ - Bug fixes ++ - Security: ++ * Fixed vulnerability CVE-2023-1668. ++ +v2.17.5 - 20 Dec 2022 +--------------------- + - Bug fixes @@ -611,7 +617,7 @@ index 1884c99e1f..aca1dbca91 100755 +dhparam_to_c lib/dh4096.pem +echo "#endif" diff --git a/configure.ac b/configure.ac -index 4e9bcce272..64db07f27b 100644 +index 4e9bcce272..4b8c162067 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ @@ -619,7 +625,7 @@ index 4e9bcce272..64db07f27b 100644 AC_PREREQ(2.63) -AC_INIT(openvswitch, 2.17.0, bugs@openvswitch.org) -+AC_INIT(openvswitch, 2.17.6, bugs@openvswitch.org) ++AC_INIT(openvswitch, 2.17.7, bugs@openvswitch.org) AC_CONFIG_SRCDIR([datapath/datapath.c]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([build-aux]) @@ -871,15 +877,21 @@ index cc0840704a..2a206305ec 100644 completionList->dropNbl = NULL; completionList->dropNblNext = &completionList->dropNbl; diff --git a/debian/changelog b/debian/changelog -index 3e0d3a66e3..11de722a81 100644 +index 3e0d3a66e3..0c1940c6e7 100644 --- a/debian/changelog +++ b/debian/changelog -@@ -1,3 +1,39 @@ +@@ -1,3 +1,45 @@ ++openvswitch (2.17.7-1) unstable; urgency=low ++ [ Open vSwitch team ] ++ * New upstream version ++ ++ -- Open vSwitch team Thu, 06 Apr 2023 15:09:54 +0200 ++ +openvswitch (2.17.6-1) unstable; urgency=low + [ Open vSwitch team ] + * New upstream version + -+ -- Open vSwitch team Tue, 20 Dec 2022 20:06:56 +0100 ++ -- Open vSwitch team Thu, 06 Apr 2023 15:09:54 +0200 + +openvswitch (2.17.5-1) unstable; urgency=low + [ Open vSwitch team ] @@ -51108,6 +51120,26 @@ index d3b4601858..7f3e63c384 100644 } static bool +diff --git a/lib/conntrack-tp.h b/lib/conntrack-tp.h +index 4d411d19fd..7ece2eae2f 100644 +--- a/lib/conntrack-tp.h ++++ b/lib/conntrack-tp.h +@@ -17,8 +17,15 @@ + #ifndef CONNTRACK_TP_H + #define CONNTRACK_TP_H 1 + ++#include ++ + #define CT_DPIF_NETDEV_TP_MIN 30 ++ + enum ct_timeout; ++struct conn; ++struct conntrack; ++struct timeout_policy; ++ + void timeout_policy_init(struct conntrack *ct); + int timeout_policy_update(struct conntrack *ct, struct timeout_policy *tp); + int timeout_policy_delete(struct conntrack *ct, uint32_t tp_id); diff --git a/lib/conntrack.c b/lib/conntrack.c index 33a1a92953..fff8e77db1 100644 --- a/lib/conntrack.c @@ -54261,7 +54293,7 @@ index 94dc6a9b74..303b99daf4 100644 .queue = rss_data->queue, .key_len = 0, diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c -index 9845e8d3fe..efb92d5dd7 100644 +index 9845e8d3fe..6d918aebd6 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -44,6 +44,7 @@ @@ -54303,7 +54335,7 @@ index 9845e8d3fe..efb92d5dd7 100644 }; static void -@@ -198,13 +209,39 @@ del_ufid_tc_mapping(const ovs_u128 *ufid) +@@ -198,15 +209,42 @@ del_ufid_tc_mapping(const ovs_u128 *ufid) ovs_mutex_unlock(&ufid_lock); } @@ -54329,6 +54361,7 @@ index 9845e8d3fe..efb92d5dd7 100644 int err; - err = tc_del_filter(id); +- if (!err) { + if (stats) { + memset(stats, 0, sizeof *stats); + if (!tc_get_flower(id, &flower)) { @@ -54342,10 +54375,13 @@ index 9845e8d3fe..efb92d5dd7 100644 + } + + err = tc_del_flower_filter(id); - if (!err) { ++ if (!err || err == ENODEV) { del_ufid_tc_mapping(ufid); ++ return 0; } -@@ -214,7 +251,7 @@ del_filter_and_ufid_mapping(struct tcf_id *id, const ovs_u128 *ufid) + return err; + } +@@ -214,7 +252,7 @@ del_filter_and_ufid_mapping(struct tcf_id *id, const ovs_u128 *ufid) /* Add ufid entry to ufid_to_tc hashmap. */ static void add_ufid_tc_mapping(struct netdev *netdev, const ovs_u128 *ufid, @@ -54354,7 +54390,7 @@ index 9845e8d3fe..efb92d5dd7 100644 { struct ufid_tc_data *new_data = xzalloc(sizeof *new_data); size_t ufid_hash = hash_bytes(ufid, sizeof *ufid, 0); -@@ -226,6 +263,9 @@ add_ufid_tc_mapping(struct netdev *netdev, const ovs_u128 *ufid, +@@ -226,6 +264,9 @@ add_ufid_tc_mapping(struct netdev *netdev, const ovs_u128 *ufid, new_data->ufid = *ufid; new_data->id = *id; new_data->netdev = netdev_ref(netdev); @@ -54364,7 +54400,7 @@ index 9845e8d3fe..efb92d5dd7 100644 ovs_mutex_lock(&ufid_lock); hmap_insert(&ufid_to_tc, &new_data->ufid_to_tc_node, ufid_hash); -@@ -257,6 +297,30 @@ get_ufid_tc_mapping(const ovs_u128 *ufid, struct tcf_id *id) +@@ -257,6 +298,30 @@ get_ufid_tc_mapping(const ovs_u128 *ufid, struct tcf_id *id) return ENOENT; } @@ -54395,7 +54431,7 @@ index 9845e8d3fe..efb92d5dd7 100644 /* Find ufid entry in ufid_to_tc hashmap using tcf_id id. * The result is saved in ufid. * -@@ -405,7 +469,7 @@ delete_chains_from_netdev(struct netdev *netdev, struct tcf_id *id) +@@ -405,7 +470,7 @@ delete_chains_from_netdev(struct netdev *netdev, struct tcf_id *id) */ HMAP_FOR_EACH_POP (chain_node, node, &map) { id->chain = chain_node->chain; @@ -54404,7 +54440,7 @@ index 9845e8d3fe..efb92d5dd7 100644 free(chain_node); } } -@@ -417,16 +481,16 @@ delete_chains_from_netdev(struct netdev *netdev, struct tcf_id *id) +@@ -417,16 +482,16 @@ delete_chains_from_netdev(struct netdev *netdev, struct tcf_id *id) static int netdev_tc_flow_flush(struct netdev *netdev) { @@ -54424,7 +54460,7 @@ index 9845e8d3fe..efb92d5dd7 100644 if (!err) { del_ufid_tc_mapping_unlocked(&data->ufid); } -@@ -481,10 +545,10 @@ netdev_tc_flow_dump_destroy(struct netdev_flow_dump *dump) +@@ -481,10 +546,10 @@ netdev_tc_flow_dump_destroy(struct netdev_flow_dump *dump) static void parse_flower_rewrite_to_netlink_action(struct ofpbuf *buf, @@ -54438,7 +54474,7 @@ index 9845e8d3fe..efb92d5dd7 100644 for (int type = 0; type < ARRAY_SIZE(set_flower_map); type++) { char *put = NULL; -@@ -550,30 +614,42 @@ flower_tun_opt_to_match(struct match *match, struct tc_flower *flower) +@@ -550,30 +615,42 @@ flower_tun_opt_to_match(struct match *match, struct tc_flower *flower) struct geneve_opt *opt, *opt_mask; int len, cnt = 0; @@ -54488,7 +54524,7 @@ index 9845e8d3fe..efb92d5dd7 100644 } static void -@@ -585,8 +661,10 @@ parse_tc_flower_to_stats(struct tc_flower *flower, +@@ -585,8 +662,10 @@ parse_tc_flower_to_stats(struct tc_flower *flower, } memset(stats, 0, sizeof *stats); @@ -54501,7 +54537,7 @@ index 9845e8d3fe..efb92d5dd7 100644 stats->used = flower->lastused; } -@@ -616,7 +694,8 @@ parse_tc_flower_terse_to_match(struct tc_flower *flower, +@@ -616,7 +695,8 @@ parse_tc_flower_terse_to_match(struct tc_flower *flower, } static int @@ -54511,7 +54547,7 @@ index 9845e8d3fe..efb92d5dd7 100644 struct match *match, struct nlattr **actions, struct dpif_flow_stats *stats, -@@ -803,18 +882,24 @@ parse_tc_flower_to_match(struct tc_flower *flower, +@@ -803,18 +883,24 @@ parse_tc_flower_to_match(struct tc_flower *flower, &flower->key.tunnel.ipv6.ipv6_src, &flower->mask.tunnel.ipv6.ipv6_src); } @@ -54530,18 +54566,18 @@ index 9845e8d3fe..efb92d5dd7 100644 + if (flower->mask.tunnel.tp_src) { + match_set_tun_tp_dst_masked(match, flower->key.tunnel.tp_src, + flower->mask.tunnel.tp_src); - } -- if (flower->key.tunnel.metadata.present.len) { ++ } + if (flower->mask.tunnel.tp_dst) { + match_set_tun_tp_dst_masked(match, flower->key.tunnel.tp_dst, + flower->mask.tunnel.tp_dst); -+ } + } +- if (flower->key.tunnel.metadata.present.len) { + + if (!strcmp(netdev_get_type(netdev), "geneve")) { flower_tun_opt_to_match(match, flower); } } -@@ -877,7 +962,7 @@ parse_tc_flower_to_match(struct tc_flower *flower, +@@ -877,7 +963,7 @@ parse_tc_flower_to_match(struct tc_flower *flower, } break; case TC_ACT_PEDIT: { @@ -54550,7 +54586,7 @@ index 9845e8d3fe..efb92d5dd7 100644 } break; case TC_ACT_ENCAP: { -@@ -947,7 +1032,11 @@ parse_tc_flower_to_match(struct tc_flower *flower, +@@ -947,7 +1033,11 @@ parse_tc_flower_to_match(struct tc_flower *flower, ct_offset = nl_msg_start_nested(buf, OVS_ACTION_ATTR_CT); if (action->ct.commit) { @@ -54563,7 +54599,7 @@ index 9845e8d3fe..efb92d5dd7 100644 } if (action->ct.zone) { -@@ -965,13 +1054,13 @@ parse_tc_flower_to_match(struct tc_flower *flower, +@@ -965,13 +1055,13 @@ parse_tc_flower_to_match(struct tc_flower *flower, struct { ovs_u128 key; ovs_u128 mask; @@ -54583,7 +54619,7 @@ index 9845e8d3fe..efb92d5dd7 100644 } if (action->ct.nat_type) { -@@ -1048,23 +1137,28 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump, +@@ -1048,23 +1138,28 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump, get_tc_qdisc_hook(netdev)); while (nl_dump_next(dump->nl_dump, &nl_flow, rbuffer)) { @@ -54616,7 +54652,7 @@ index 9845e8d3fe..efb92d5dd7 100644 match->wc.masks.in_port.odp_port = u32_to_odp(UINT32_MAX); match->flow.in_port.odp_port = dump->port; match_set_recirc_id(match, id.chain); -@@ -1164,7 +1258,12 @@ parse_put_flow_ct_action(struct tc_flower *flower, +@@ -1164,7 +1259,12 @@ parse_put_flow_ct_action(struct tc_flower *flower, NL_ATTR_FOR_EACH_UNSAFE (ct_attr, ct_left, ct, ct_len) { switch (nl_attr_type(ct_attr)) { case OVS_CT_ATTR_COMMIT: { @@ -54630,7 +54666,7 @@ index 9845e8d3fe..efb92d5dd7 100644 } break; case OVS_CT_ATTR_ZONE: { -@@ -1194,15 +1293,20 @@ parse_put_flow_ct_action(struct tc_flower *flower, +@@ -1194,15 +1294,20 @@ parse_put_flow_ct_action(struct tc_flower *flower, break; case OVS_CT_ATTR_LABELS: { const struct { @@ -54655,7 +54691,7 @@ index 9845e8d3fe..efb92d5dd7 100644 } } -@@ -1222,8 +1326,8 @@ parse_put_flow_set_masked_action(struct tc_flower *flower, +@@ -1222,8 +1327,8 @@ parse_put_flow_set_masked_action(struct tc_flower *flower, uint64_t set_stub[1024 / 8]; struct ofpbuf set_buf = OFPBUF_STUB_INITIALIZER(set_stub); char *set_data, *set_mask; @@ -54666,7 +54702,7 @@ index 9845e8d3fe..efb92d5dd7 100644 const struct nlattr *attr; int i, j, type; size_t size; -@@ -1265,14 +1369,6 @@ parse_put_flow_set_masked_action(struct tc_flower *flower, +@@ -1265,14 +1370,6 @@ parse_put_flow_set_masked_action(struct tc_flower *flower, } } @@ -54681,7 +54717,7 @@ index 9845e8d3fe..efb92d5dd7 100644 if (hasmask && !is_all_zeros(set_mask, size)) { VLOG_DBG_RL(&rl, "unsupported sub attribute of set action type %d", type); -@@ -1281,6 +1377,8 @@ parse_put_flow_set_masked_action(struct tc_flower *flower, +@@ -1281,6 +1378,8 @@ parse_put_flow_set_masked_action(struct tc_flower *flower, } ofpbuf_uninit(&set_buf); @@ -54690,7 +54726,7 @@ index 9845e8d3fe..efb92d5dd7 100644 return 0; } -@@ -1288,6 +1386,7 @@ static int +@@ -1288,6 +1387,7 @@ static int parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action, const struct nlattr *set, size_t set_len) { @@ -54698,7 +54734,7 @@ index 9845e8d3fe..efb92d5dd7 100644 const struct nlattr *tunnel; const struct nlattr *tun_attr; size_t tun_left, tunnel_len; -@@ -1306,6 +1405,7 @@ parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action, +@@ -1306,6 +1406,7 @@ parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action, action->type = TC_ACT_ENCAP; action->encap.id_present = false; @@ -54706,7 +54742,7 @@ index 9845e8d3fe..efb92d5dd7 100644 flower->action_count++; NL_ATTR_FOR_EACH_UNSAFE(tun_attr, tun_left, tunnel, tunnel_len) { switch (nl_attr_type(tun_attr)) { -@@ -1330,6 +1430,18 @@ parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action, +@@ -1330,6 +1431,18 @@ parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action, action->encap.ttl = nl_attr_get_u8(tun_attr); } break; @@ -54725,7 +54761,7 @@ index 9845e8d3fe..efb92d5dd7 100644 case OVS_TUNNEL_KEY_ATTR_IPV6_SRC: { action->encap.ipv6.ipv6_src = nl_attr_get_in6_addr(tun_attr); -@@ -1354,12 +1466,31 @@ parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action, +@@ -1354,12 +1467,31 @@ parse_put_flow_set_action(struct tc_flower *flower, struct tc_action *action, action->encap.data.present.len = nl_attr_get_size(tun_attr); } break; @@ -54757,7 +54793,7 @@ index 9845e8d3fe..efb92d5dd7 100644 static int test_key_and_mask(struct match *match) { -@@ -1442,8 +1573,23 @@ test_key_and_mask(struct match *match) +@@ -1442,8 +1574,23 @@ test_key_and_mask(struct match *match) return EOPNOTSUPP; } @@ -54782,7 +54818,7 @@ index 9845e8d3fe..efb92d5dd7 100644 return EOPNOTSUPP; } -@@ -1452,18 +1598,51 @@ test_key_and_mask(struct match *match) +@@ -1452,18 +1599,51 @@ test_key_and_mask(struct match *match) static void flower_match_to_tun_opt(struct tc_flower *flower, const struct flow_tnl *tnl, @@ -54820,11 +54856,11 @@ index 9845e8d3fe..efb92d5dd7 100644 + flower->mask.tunnel.metadata.present.len = tnl->metadata.present.len; + memset(&tnl_mask->metadata.present.len, 0, + sizeof tnl_mask->metadata.present.len); - ++ + if (!tnl->metadata.present.len) { + return; + } -+ + + memcpy(flower->key.tunnel.metadata.opts.gnv, tnl->metadata.opts.gnv, + tnl->metadata.present.len); memcpy(flower->mask.tunnel.metadata.opts.gnv, tnl_mask->metadata.opts.gnv, @@ -54837,7 +54873,7 @@ index 9845e8d3fe..efb92d5dd7 100644 len = flower->key.tunnel.metadata.present.len; while (len) { opt = &flower->key.tunnel.metadata.opts.gnv[cnt]; -@@ -1474,8 +1653,6 @@ flower_match_to_tun_opt(struct tc_flower *flower, const struct flow_tnl *tnl, +@@ -1474,8 +1654,6 @@ flower_match_to_tun_opt(struct tc_flower *flower, const struct flow_tnl *tnl, cnt += sizeof(struct geneve_opt) / 4 + opt->length; len -= sizeof(struct geneve_opt) + opt->length * 4; } @@ -54846,7 +54882,7 @@ index 9845e8d3fe..efb92d5dd7 100644 } static void -@@ -1541,6 +1718,12 @@ parse_match_ct_state_to_flower(struct tc_flower *flower, struct match *match) +@@ -1541,6 +1719,12 @@ parse_match_ct_state_to_flower(struct tc_flower *flower, struct match *match) flower->key.ct_state &= ~(TCA_FLOWER_KEY_CT_FLAGS_NEW); flower->mask.ct_state &= ~(TCA_FLOWER_KEY_CT_FLAGS_NEW); } @@ -54859,7 +54895,7 @@ index 9845e8d3fe..efb92d5dd7 100644 } if (mask->ct_zone) { -@@ -1574,7 +1757,8 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, +@@ -1574,7 +1758,8 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, const struct flow *key = &match->flow; struct flow *mask = &match->wc.masks; const struct flow_tnl *tnl = &match->flow.tunnel; @@ -54869,7 +54905,7 @@ index 9845e8d3fe..efb92d5dd7 100644 struct tc_action *action; bool recirc_act = false; uint32_t block_id = 0; -@@ -1615,17 +1799,49 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, +@@ -1615,17 +1800,49 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, flower.key.tunnel.ttl = tnl->ip_ttl; flower.key.tunnel.tp_src = tnl->tp_src; flower.key.tunnel.tp_dst = tnl->tp_dst; @@ -54921,7 +54957,7 @@ index 9845e8d3fe..efb92d5dd7 100644 flower.key.eth_type = key->dl_type; flower.mask.eth_type = mask->dl_type; -@@ -1638,7 +1854,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, +@@ -1638,7 +1855,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, if (mask->vlans[0].tpid && eth_type_vlan(key->vlans[0].tpid)) { flower.key.encap_eth_type[0] = flower.key.eth_type; @@ -54930,7 +54966,7 @@ index 9845e8d3fe..efb92d5dd7 100644 flower.key.eth_type = key->vlans[0].tpid; flower.mask.eth_type = mask->vlans[0].tpid; } -@@ -1734,7 +1950,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, +@@ -1734,7 +1951,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, memset(&mask->arp_tha, 0, sizeof mask->arp_tha); } @@ -54939,7 +54975,7 @@ index 9845e8d3fe..efb92d5dd7 100644 flower.key.ip_proto = key->nw_proto; flower.mask.ip_proto = mask->nw_proto; mask->nw_proto = 0; -@@ -1841,7 +2057,25 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, +@@ -1841,7 +2058,25 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, VLOG_DBG_RL(&rl, "Can't find netdev for output port %d", port); return ENODEV; } @@ -54965,7 +55001,7 @@ index 9845e8d3fe..efb92d5dd7 100644 action->out.ingress = is_internal_port(netdev_get_type(outdev)); action->type = TC_ACT_OUTPUT; flower.action_count++; -@@ -1879,10 +2113,6 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, +@@ -1879,10 +2114,6 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, if (err) { return err; } @@ -54976,7 +55012,7 @@ index 9845e8d3fe..efb92d5dd7 100644 } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SET_MASKED) { const struct nlattr *set = nl_attr_get(nla); const size_t set_len = nl_attr_get_size(nla); -@@ -1929,10 +2159,12 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, +@@ -1929,10 +2160,12 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, return EOPNOTSUPP; } @@ -54990,7 +55026,7 @@ index 9845e8d3fe..efb92d5dd7 100644 } prio = get_prio_for_tc_flower(&flower); -@@ -1950,8 +2182,9 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, +@@ -1950,8 +2183,9 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, if (!err) { if (stats) { memset(stats, 0, sizeof *stats); @@ -55001,7 +55037,7 @@ index 9845e8d3fe..efb92d5dd7 100644 } return err; -@@ -1989,8 +2222,16 @@ netdev_tc_flow_get(struct netdev *netdev, +@@ -1989,8 +2223,16 @@ netdev_tc_flow_get(struct netdev *netdev, } in_port = netdev_ifindex_to_odp_port(id.ifindex); @@ -55019,7 +55055,7 @@ index 9845e8d3fe..efb92d5dd7 100644 match->wc.masks.in_port.odp_port = u32_to_odp(UINT32_MAX); match->flow.in_port.odp_port = in_port; match_set_recirc_id(match, id.chain); -@@ -2003,7 +2244,6 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, +@@ -2003,7 +2245,6 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, const ovs_u128 *ufid, struct dpif_flow_stats *stats) { @@ -55027,7 +55063,7 @@ index 9845e8d3fe..efb92d5dd7 100644 struct tcf_id id; int error; -@@ -2012,18 +2252,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, +@@ -2012,18 +2253,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, return error; } @@ -55047,7 +55083,7 @@ index 9845e8d3fe..efb92d5dd7 100644 } static int -@@ -2077,13 +2306,13 @@ probe_multi_mask_per_prio(int ifindex) +@@ -2077,13 +2307,13 @@ probe_multi_mask_per_prio(int ifindex) id2 = tc_make_tcf_id(ifindex, block_id, prio, TC_INGRESS); error = tc_replace_flower(&id2, &flower); @@ -55063,7 +55099,7 @@ index 9845e8d3fe..efb92d5dd7 100644 multi_mask_per_prio = true; VLOG_INFO("probe tc: multiple masks on single tc prio is supported."); -@@ -2135,7 +2364,7 @@ probe_ct_state_support(int ifindex) +@@ -2135,7 +2365,7 @@ probe_ct_state_support(int ifindex) goto out_del; } @@ -55072,7 +55108,7 @@ index 9845e8d3fe..efb92d5dd7 100644 ct_state_support = OVS_CS_F_NEW | OVS_CS_F_ESTABLISHED | OVS_CS_F_TRACKED | -@@ -2149,7 +2378,7 @@ probe_ct_state_support(int ifindex) +@@ -2149,7 +2379,7 @@ probe_ct_state_support(int ifindex) goto out_del; } @@ -55081,7 +55117,7 @@ index 9845e8d3fe..efb92d5dd7 100644 /* Test for ct_state INVALID support */ memset(&flower, 0, sizeof flower); -@@ -2160,7 +2389,7 @@ probe_ct_state_support(int ifindex) +@@ -2160,7 +2390,7 @@ probe_ct_state_support(int ifindex) goto out; } @@ -55090,7 +55126,7 @@ index 9845e8d3fe..efb92d5dd7 100644 ct_state_support |= OVS_CS_F_INVALID; /* Test for ct_state REPLY support */ -@@ -2176,7 +2405,7 @@ probe_ct_state_support(int ifindex) +@@ -2176,7 +2406,7 @@ probe_ct_state_support(int ifindex) ct_state_support |= OVS_CS_F_REPLY_DIR; out_del: @@ -55099,7 +55135,7 @@ index 9845e8d3fe..efb92d5dd7 100644 out: tc_add_del_qdisc(ifindex, false, 0, TC_INGRESS); VLOG_INFO("probe tc: supported ovs ct_state bits: 0x%x", ct_state_support); -@@ -2251,7 +2480,7 @@ netdev_tc_init_flow_api(struct netdev *netdev) +@@ -2251,7 +2481,7 @@ netdev_tc_init_flow_api(struct netdev *netdev) /* fallback here if delete chains fail */ if (!get_chain_supported) { @@ -60983,6 +61019,48 @@ index 0000000000..b502aea4cf + + + +diff --git a/ovsdb/log.c b/ovsdb/log.c +index 4a28fa3db6..981d33cc57 100644 +--- a/ovsdb/log.c ++++ b/ovsdb/log.c +@@ -551,6 +551,23 @@ ovsdb_log_truncate(struct ovsdb_log *file) + return error; + } + ++/* Removes all the data from the log by moving current offset to zero and ++ * truncating the file to zero bytes. After this operation the file is empty ++ * and in a write state. */ ++struct ovsdb_error * OVS_WARN_UNUSED_RESULT ++ovsdb_log_reset(struct ovsdb_log *file) ++{ ++ ovsdb_error_destroy(file->error); ++ file->offset = file->prev_offset = 0; ++ file->error = ovsdb_log_truncate(file); ++ if (file->error) { ++ file->state = OVSDB_LOG_WRITE_ERROR; ++ return ovsdb_error_clone(file->error); ++ } ++ file->state = OVSDB_LOG_WRITE; ++ return NULL; ++} ++ + /* Composes a log record for 'json' by filling 'header' with a header line and + * 'data' with a data line (each ending with a new-line). To write the record + * to a file, write 'header' followed by 'data'. +diff --git a/ovsdb/log.h b/ovsdb/log.h +index 90714ea131..63e5681a0b 100644 +--- a/ovsdb/log.h ++++ b/ovsdb/log.h +@@ -66,6 +66,9 @@ struct ovsdb_error *ovsdb_log_read(struct ovsdb_log *, struct json **) + OVS_WARN_UNUSED_RESULT; + void ovsdb_log_unread(struct ovsdb_log *); + ++struct ovsdb_error *ovsdb_log_reset(struct ovsdb_log *) ++ OVS_WARN_UNUSED_RESULT; ++ + void ovsdb_log_compose_record(const struct json *, const char *magic, + struct ds *header, struct ds *data); + diff --git a/ovsdb/monitor.c b/ovsdb/monitor.c index 0f222cc992..952fa902e4 100644 --- a/ovsdb/monitor.c @@ -61129,7 +61207,7 @@ index 10a70ae26f..13c5359395 100755 unsigned int %(s)s_get_seqno(const struct ovsdb_idl *); unsigned int %(s)s_row_get_seqno(const struct %(s)s *row, enum ovsdb_idl_change change); diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c -index 9fe90592ea..774416fc7a 100644 +index 9fe90592ea..ddb623dc1a 100644 --- a/ovsdb/ovsdb-server.c +++ b/ovsdb/ovsdb-server.c @@ -26,6 +26,7 @@ @@ -61184,7 +61262,123 @@ index 9fe90592ea..774416fc7a 100644 perf_counters_destroy(); service_stop(); return 0; -@@ -1240,8 +1242,8 @@ update_server_status(struct shash *all_dbs) +@@ -562,8 +564,9 @@ close_db(struct server_config *config, struct db *db, char *comment) + } + } + +-static void +-update_schema(struct ovsdb *db, const struct ovsdb_schema *schema, void *aux) ++static struct ovsdb_error * OVS_WARN_UNUSED_RESULT ++update_schema(struct ovsdb *db, const struct ovsdb_schema *schema, ++ bool conversion_with_no_data, void *aux) + { + struct server_config *config = aux; + +@@ -575,13 +578,27 @@ update_schema(struct ovsdb *db, const struct ovsdb_schema *schema, void *aux) + : xasprintf("database %s connected to storage", db->name))); + } + +- ovsdb_replace(db, ovsdb_create(ovsdb_schema_clone(schema), NULL)); ++ if (db->schema && conversion_with_no_data) { ++ struct ovsdb *new_db = NULL; ++ struct ovsdb_error *error; ++ ++ error = ovsdb_convert(db, schema, &new_db); ++ if (error) { ++ /* Should never happen, because conversion should have been ++ * checked before writing the schema to the storage. */ ++ return error; ++ } ++ ovsdb_replace(db, new_db); ++ } else { ++ ovsdb_replace(db, ovsdb_create(ovsdb_schema_clone(schema), NULL)); ++ } + + /* Force update to schema in _Server database. */ + struct db *dbp = shash_find_data(config->all_dbs, db->name); + if (dbp) { + dbp->row_uuid = UUID_ZERO; + } ++ return NULL; + } + + static struct ovsdb_error * OVS_WARN_UNUSED_RESULT +@@ -589,23 +606,30 @@ parse_txn(struct server_config *config, struct db *db, + const struct ovsdb_schema *schema, const struct json *txn_json, + const struct uuid *txnid) + { ++ struct ovsdb_error *error = NULL; ++ struct ovsdb_txn *txn = NULL; ++ + if (schema) { +- /* We're replacing the schema (and the data). Destroy the database +- * (first grabbing its storage), then replace it with the new schema. +- * The transaction must also include the replacement data. ++ /* We're replacing the schema (and the data). If transaction includes ++ * replacement data, destroy the database (first grabbing its storage), ++ * then replace it with the new schema. If not, it's a conversion ++ * without data specified. In this case, convert the current database ++ * to a new schema instead. + * + * Only clustered database schema changes and snapshot installs + * go through this path. + */ +- ovs_assert(txn_json); + ovs_assert(ovsdb_storage_is_clustered(db->db->storage)); + +- struct ovsdb_error *error = ovsdb_schema_check_for_ephemeral_columns( +- schema); ++ error = ovsdb_schema_check_for_ephemeral_columns(schema); ++ if (error) { ++ return error; ++ } ++ ++ error = update_schema(db->db, schema, txn_json == NULL, config); + if (error) { + return error; + } +- update_schema(db->db, schema, config); + } + + if (txn_json) { +@@ -613,24 +637,25 @@ parse_txn(struct server_config *config, struct db *db, + return ovsdb_error(NULL, "%s: data without schema", db->filename); + } + +- struct ovsdb_txn *txn; +- struct ovsdb_error *error; +- + error = ovsdb_file_txn_from_json(db->db, txn_json, false, &txn); +- if (!error) { +- ovsdb_txn_set_txnid(txnid, txn); +- log_and_free_error(ovsdb_txn_replay_commit(txn)); +- } +- if (!error && !uuid_is_zero(txnid)) { +- db->db->prereq = *txnid; +- } + if (error) { + ovsdb_storage_unread(db->db->storage); + return error; + } ++ } else if (schema) { ++ /* We just performed conversion without data. Transaction history ++ * was destroyed. Commit a dummy transaction to set the txnid. */ ++ txn = ovsdb_txn_create(db->db); + } + +- return NULL; ++ if (txn) { ++ ovsdb_txn_set_txnid(txnid, txn); ++ error = ovsdb_txn_replay_commit(txn); ++ if (!error && !uuid_is_zero(txnid)) { ++ db->db->prereq = *txnid; ++ } ++ } ++ return error; + } + + static void +@@ -1240,8 +1265,8 @@ update_server_status(struct shash *all_dbs) /* Update rows for databases that still exist. * Delete rows for databases that no longer exist. */ @@ -61196,10 +61390,61 @@ index 9fe90592ea..774416fc7a 100644 ovsdb_util_read_string_column(row, "name", &name); struct db *db = shash_find_data(all_dbs, name); diff --git a/ovsdb/ovsdb-tool.c b/ovsdb/ovsdb-tool.c -index d4a9e34cc4..df2e373c3c 100644 +index d4a9e34cc4..f9a423fba2 100644 --- a/ovsdb/ovsdb-tool.c +++ b/ovsdb/ovsdb-tool.c -@@ -1579,15 +1579,14 @@ do_check_cluster(struct ovs_cmdl_context *ctx) +@@ -1005,7 +1005,8 @@ raft_header_to_standalone_log(const struct raft_header *h, + } + + static void +-raft_record_to_standalone_log(const struct raft_record *r, ++raft_record_to_standalone_log(const char *db_file_name, ++ const struct raft_record *r, + struct ovsdb_log *db_log_data) + { + if (r->type == RAFT_REC_ENTRY) { +@@ -1017,7 +1018,40 @@ raft_record_to_standalone_log(const struct raft_record *r, + if (pa->n != 2) { + ovs_fatal(0, "Incorrect raft record array length"); + } ++ ++ struct json *schema_json = pa->elems[0]; + struct json *data_json = pa->elems[1]; ++ ++ if (schema_json->type != JSON_NULL) { ++ /* This is a database conversion record. Reset the log and ++ * write the new schema. */ ++ struct ovsdb_schema *schema; ++ ++ check_ovsdb_error(ovsdb_schema_from_json(schema_json, &schema)); ++ ++ if (data_json->type == JSON_NULL) { ++ /* We have a conversion request with no data. There is no ++ * other way as to read back what we have and convert. */ ++ struct ovsdb *old_db, *new_db; ++ ++ check_ovsdb_error(ovsdb_log_commit_block(db_log_data)); ++ ++ old_db = ovsdb_file_read(db_file_name, false); ++ check_ovsdb_error(ovsdb_convert(old_db, schema, &new_db)); ++ ovsdb_destroy(old_db); ++ ++ pa->elems[1] = ovsdb_to_txn_json( ++ new_db, "converted by ovsdb-tool"); ++ ovsdb_destroy(new_db); ++ ++ json_destroy(data_json); ++ data_json = pa->elems[1]; ++ } ++ ++ ovsdb_schema_destroy(schema); ++ check_ovsdb_error(ovsdb_log_reset(db_log_data)); ++ check_ovsdb_error(ovsdb_log_write(db_log_data, schema_json)); ++ } + if (data_json->type != JSON_NULL) { + check_ovsdb_error(ovsdb_log_write(db_log_data, data_json)); + } +@@ -1579,15 +1613,14 @@ do_check_cluster(struct ovs_cmdl_context *ctx) } free(c.servers); @@ -61218,6 +61463,34 @@ index d4a9e34cc4..df2e373c3c 100644 hmap_remove(&c.leaders, &leader->hmap_node); free(leader); } +@@ -1636,7 +1669,8 @@ do_compare_versions(struct ovs_cmdl_context *ctx) + } + + static void +-do_convert_to_standalone(struct ovsdb_log *log, struct ovsdb_log *db_log_data) ++do_convert_to_standalone(const char *db_file_name, ++ struct ovsdb_log *log, struct ovsdb_log *db_log_data) + { + for (unsigned int i = 0; ; i++) { + struct json *json; +@@ -1653,7 +1687,7 @@ do_convert_to_standalone(struct ovsdb_log *log, struct ovsdb_log *db_log_data) + } else { + struct raft_record r; + check_ovsdb_error(raft_record_from_json(&r, json)); +- raft_record_to_standalone_log(&r, db_log_data); ++ raft_record_to_standalone_log(db_file_name, &r, db_log_data); + raft_record_uninit(&r); + } + json_destroy(json); +@@ -1676,7 +1710,7 @@ do_cluster_standalone(struct ovs_cmdl_context *ctx) + if (strcmp(ovsdb_log_get_magic(log), RAFT_MAGIC) != 0) { + ovs_fatal(0, "Database is not clustered db.\n"); + } +- do_convert_to_standalone(log, db_log_data); ++ do_convert_to_standalone(db_file_name, log, db_log_data); + check_ovsdb_error(ovsdb_log_commit_block(db_log_data)); + ovsdb_log_close(db_log_data); + ovsdb_log_close(log); diff --git a/ovsdb/ovsdb.c b/ovsdb/ovsdb.c index e6d866182c..3eb6ce870a 100644 --- a/ovsdb/ovsdb.c @@ -61676,7 +61949,7 @@ index 1a3447a8dd..cf9edf35c6 100644 failure_test = FT_NO_TEST; unixctl_command_reply(conn, "test dismissed"); diff --git a/ovsdb/relay.c b/ovsdb/relay.c -index ef0e44d340..122ee8c52f 100644 +index ef0e44d340..423b98ee7c 100644 --- a/ovsdb/relay.c +++ b/ovsdb/relay.c @@ -269,9 +269,9 @@ ovsdb_relay_clear(struct ovsdb *db) @@ -61691,6 +61964,65 @@ index ef0e44d340..122ee8c52f 100644 ovsdb_txn_row_delete(txn, row); } } +@@ -283,6 +283,8 @@ static void + ovsdb_relay_parse_update(struct relay_ctx *ctx, + const struct ovsdb_cs_update_event *update) + { ++ struct ovsdb_error *error = NULL; ++ + if (!ctx->db) { + return; + } +@@ -290,15 +292,27 @@ ovsdb_relay_parse_update(struct relay_ctx *ctx, + if (update->monitor_reply && ctx->new_schema) { + /* There was a schema change. Updating a database with a new schema + * before processing monitor reply with the new data. */ +- ctx->schema_change_cb(ctx->db, ctx->new_schema, +- ctx->schema_change_aux); ++ error = ctx->schema_change_cb(ctx->db, ctx->new_schema, false, ++ ctx->schema_change_aux); ++ if (error) { ++ /* Should never happen, but handle this case anyway. */ ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); ++ char *s = ovsdb_error_to_string_free(error); ++ ++ VLOG_ERR_RL(&rl, "%s", s); ++ free(s); ++ ++ ovsdb_cs_flag_inconsistency(ctx->cs); ++ return; ++ } + ovsdb_schema_destroy(ctx->new_schema); + ctx->new_schema = NULL; + } + + struct ovsdb_cs_db_update *du; +- struct ovsdb_error *error = ovsdb_cs_parse_db_update(update->table_updates, +- update->version, &du); ++ ++ error = ovsdb_cs_parse_db_update(update->table_updates, ++ update->version, &du); + if (!error) { + if (update->clear) { + error = ovsdb_relay_clear(ctx->db); +diff --git a/ovsdb/relay.h b/ovsdb/relay.h +index 390ea70c82..2d66b5e5fa 100644 +--- a/ovsdb/relay.h ++++ b/ovsdb/relay.h +@@ -23,8 +23,11 @@ struct json; + struct ovsdb; + struct ovsdb_schema; + +-typedef void (*schema_change_callback)(struct ovsdb *, +- const struct ovsdb_schema *, void *aux); ++typedef struct ovsdb_error *(*schema_change_callback)( ++ struct ovsdb *, ++ const struct ovsdb_schema *, ++ bool conversion_with_no_data, ++ void *aux); + + void ovsdb_relay_add_db(struct ovsdb *, const char *remote, + schema_change_callback schema_change_cb, diff --git a/ovsdb/replication.c b/ovsdb/replication.c index d8b56d8131..477c69d701 100644 --- a/ovsdb/replication.c @@ -61718,6 +62050,61 @@ index d8b56d8131..477c69d701 100644 hmap_remove(&replication_dbs->map, &node->node); struct replication_db *rdb = node->data; if (rdb->active_db_schema) { +diff --git a/ovsdb/storage.c b/ovsdb/storage.c +index d4984be250..6069c4f102 100644 +--- a/ovsdb/storage.c ++++ b/ovsdb/storage.c +@@ -622,7 +622,7 @@ ovsdb_storage_store_snapshot(struct ovsdb_storage *storage, + + struct ovsdb_write * OVS_WARN_UNUSED_RESULT + ovsdb_storage_write_schema_change(struct ovsdb_storage *storage, +- const struct json *schema, ++ const struct ovsdb_schema *schema, + const struct json *data, + const struct uuid *prereq, + struct uuid *resultp) +@@ -632,13 +632,22 @@ ovsdb_storage_write_schema_change(struct ovsdb_storage *storage, + if (storage->error) { + w->error = ovsdb_error_clone(storage->error); + } else if (storage->raft) { +- struct json *txn_json = json_array_create_2(json_clone(schema), +- json_clone(data)); +- w->command = raft_command_execute(storage->raft, txn_json, +- prereq, &result); +- json_destroy(txn_json); ++ /* Clustered storage doesn't support ephemeral columns. */ ++ w->error = ovsdb_schema_check_for_ephemeral_columns(schema); ++ if (!w->error) { ++ struct json *schema_json, *txn_json; ++ ++ schema_json = ovsdb_schema_to_json(schema); ++ txn_json = json_array_create_2(schema_json, json_clone(data)); ++ w->command = raft_command_execute(storage->raft, txn_json, ++ prereq, &result); ++ json_destroy(txn_json); ++ } + } else if (storage->log) { +- w->error = ovsdb_storage_store_snapshot__(storage, schema, data); ++ struct json *schema_json = ovsdb_schema_to_json(schema); ++ ++ w->error = ovsdb_storage_store_snapshot__(storage, schema_json, data); ++ json_destroy(schema_json); + } else { + /* When 'error' and 'command' are both null, it indicates that the + * command is complete. This is fine since this unbacked storage drops +diff --git a/ovsdb/storage.h b/ovsdb/storage.h +index ff026b77fa..6c69e53134 100644 +--- a/ovsdb/storage.h ++++ b/ovsdb/storage.h +@@ -84,7 +84,7 @@ struct ovsdb_error *ovsdb_storage_store_snapshot(struct ovsdb_storage *storage, + + struct ovsdb_write *ovsdb_storage_write_schema_change( + struct ovsdb_storage *, +- const struct json *schema, const struct json *data, ++ const struct ovsdb_schema *, const struct json *data, + const struct uuid *prereq, struct uuid *result) + OVS_WARN_UNUSED_RESULT; + diff --git a/ovsdb/table.c b/ovsdb/table.c index 455a3663fe..2184701ec1 100644 --- a/ovsdb/table.c @@ -61774,7 +62161,7 @@ index d15f2f1d6d..963e937957 100644 } } diff --git a/ovsdb/transaction.c b/ovsdb/transaction.c -index db86d847c3..9adbabf808 100644 +index db86d847c3..8eafefa4bf 100644 --- a/ovsdb/transaction.c +++ b/ovsdb/transaction.c @@ -159,15 +159,15 @@ ovsdb_txn_row_abort(struct ovsdb_txn *txn OVS_UNUSED, @@ -62008,6 +62395,15 @@ index db86d847c3..9adbabf808 100644 if (r->old) { ovsdb_row_destroy(r->old); } +@@ -1189,7 +1191,7 @@ ovsdb_txn_precheck_prereq(const struct ovsdb *db) + + struct ovsdb_txn_progress * + ovsdb_txn_propose_schema_change(struct ovsdb *db, +- const struct json *schema, ++ const struct ovsdb_schema *schema, + const struct json *data) + { + struct ovsdb_txn_progress *progress = xzalloc(sizeof *progress); @@ -1549,19 +1551,19 @@ for_each_txn_row(struct ovsdb_txn *txn, serial++; @@ -62043,8 +62439,29 @@ index db86d847c3..9adbabf808 100644 ovs_list_remove(&txn_h_node->node); ovsdb_txn_destroy_cloned(txn_h_node->txn); free(txn_h_node); +diff --git a/ovsdb/transaction.h b/ovsdb/transaction.h +index 6b5bb7f24b..9991f34d24 100644 +--- a/ovsdb/transaction.h ++++ b/ovsdb/transaction.h +@@ -21,6 +21,7 @@ + + struct json; + struct ovsdb; ++struct ovsdb_schema; + struct ovsdb_table; + struct uuid; + +@@ -41,7 +42,7 @@ struct ovsdb_error *ovsdb_txn_propose_commit_block(struct ovsdb_txn *, + void ovsdb_txn_complete(struct ovsdb_txn *); + + struct ovsdb_txn_progress *ovsdb_txn_propose_schema_change( +- struct ovsdb *, const struct json *schema, const struct json *data); ++ struct ovsdb *, const struct ovsdb_schema *, const struct json *data); + + bool ovsdb_txn_progress_is_complete(const struct ovsdb_txn_progress *); + const struct ovsdb_error *ovsdb_txn_progress_get_error( diff --git a/ovsdb/trigger.c b/ovsdb/trigger.c -index 726c138bf0..7d3003bca3 100644 +index 726c138bf0..3a693855b9 100644 --- a/ovsdb/trigger.c +++ b/ovsdb/trigger.c @@ -146,14 +146,14 @@ ovsdb_trigger_prereplace_db(struct ovsdb_trigger *trigger) @@ -62064,6 +62481,26 @@ index 726c138bf0..7d3003bca3 100644 if (run_triggers || now - t->created >= t->timeout_msec || t->progress || t->txn_forward) { +@@ -274,8 +274,8 @@ ovsdb_trigger_try(struct ovsdb_trigger *t, long long int now) + if (!error) { + error = ovsdb_convert(t->db, new_schema, &newdb); + } +- ovsdb_schema_destroy(new_schema); + if (error) { ++ ovsdb_schema_destroy(new_schema); + trigger_convert_error(t, error); + return false; + } +@@ -286,7 +286,8 @@ ovsdb_trigger_try(struct ovsdb_trigger *t, long long int now) + + /* Propose the change. */ + t->progress = ovsdb_txn_propose_schema_change( +- t->db, new_schema_json, txn_json); ++ t->db, new_schema, txn_json); ++ ovsdb_schema_destroy(new_schema); + json_destroy(txn_json); + t->reply = jsonrpc_create_reply(json_object_create(), + t->request->id); diff --git a/python/ovs/_json.c b/python/ovs/_json.c index ef7bb4b8ee..c36a140a8e 100644 --- a/python/ovs/_json.c @@ -66861,6 +67298,90 @@ index 876cb836cd..4a183bf186 100644 --remote=ptcp:0:127.0.0.1 dnl db.tmp], [0], [stdout], [stderr]) PARSE_LISTENING_PORT([listener.log], [BAD_TCP_PORT]) +diff --git a/tests/ovsdb-tool.at b/tests/ovsdb-tool.at +index 12ad6fb3fc..5496ccda77 100644 +--- a/tests/ovsdb-tool.at ++++ b/tests/ovsdb-tool.at +@@ -465,6 +465,7 @@ AT_SETUP([ovsdb-tool convert-to-standalone]) + AT_KEYWORDS([ovsdb file positive]) + ordinal_schema > schema + AT_CHECK([ovsdb-tool create-cluster db schema unix:s1.raft], [0], [stdout], [ignore]) ++on_exit 'kill `cat ovsdb-server.pid`' + AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket --log-file db >/dev/null 2>&1]) + for txn in m4_foreach([txn], [[[["ordinals", + {"op": "insert", +@@ -498,3 +499,71 @@ OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + # Make sure both standalone and cluster db data matches. + AT_CHECK([diff standalonedump clusterdump]) + AT_CLEANUP ++ ++AT_SETUP([ovsdb-tool convert-to-standalone after schema conversion]) ++AT_KEYWORDS([ovsdb file positive]) ++ordinal_schema > schema ++AT_CHECK([ovsdb-tool create-cluster db schema unix:s1.raft], [0], [stdout], [ignore]) ++on_exit 'kill `cat ovsdb-server.pid`' ++AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --remote=punix:socket dnl ++ --log-file db >/dev/null 2>&1]) ++for txn in m4_foreach([txn], [[[["ordinals", ++ {"op": "insert", ++ "table": "ordinals", ++ "row": {"number": 0, "name": "zero"}}, ++ {"op": "insert", ++ "table": "ordinals", ++ "row": {"number": 1, "name": "one"}}, ++ {"op": "insert", ++ "table": "ordinals", ++ "row": {"number": 2, "name": "two"}}]]]], ['txn' ]); do ++ AT_CHECK([ovsdb-client transact unix:socket "$txn"], [0], [ignore], [ignore]) ++done ++ ++dnl Change the schema. ++AT_CHECK([sed 's/5\.1\.3/5.1.4/' < schema > schema2]) ++AT_CHECK([sed -i'back' -e '/.*"number":.*/a \ ++ "is_seven": {"type": "boolean"}, ++ ' schema2]) ++ ++dnl Convert the database. ++AT_CHECK([ovsdb-client convert unix:socket schema2]) ++ ++dnl Add a new row with a new column. ++AT_CHECK([ovsdb-client transact unix:socket dnl ++ '[["ordinals", ++ {"op": "insert", ++ "table": "ordinals", ++ "row": {"number": 7, "name": "seven", "is_seven": true} ++ }]]'], [0], [ignore], [ignore]) ++ ++AT_CHECK([ovsdb-client dump unix:socket > clusterdump]) ++ ++AT_CHECK([uuidfilt clusterdump], [0], [dnl ++ordinals table ++_uuid is_seven name number ++------------------------------------ -------- ----- ------ ++<0> false one 1 ++<1> false two 2 ++<2> false zero 0 ++<3> true seven 7 ++]) ++ ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++dnl Convert to standalone database from clustered database. ++AT_CHECK(ovsdb-tool cluster-to-standalone db1 db) ++ ++dnl Check it's a standalone db. ++AT_CHECK([ovsdb-tool db-is-standalone db1]) ++ ++dnl Dump the standalone db data. ++AT_CHECK([ovsdb-server -vconsole:off -vfile -vvlog:off --detach --no-chdir dnl ++ --pidfile --log-file --remote=punix:db.sock db1]) ++AT_CHECK([ovsdb_client_wait ordinals connected]) ++AT_CHECK([ovsdb-client dump > standalonedump]) ++OVS_APP_EXIT_AND_WAIT([ovsdb-server]) ++ ++dnl Make sure both standalone and cluster db data matches. ++AT_CHECK([diff standalonedump clusterdump]) ++AT_CLEANUP diff --git a/tests/packet-type-aware.at b/tests/packet-type-aware.at index 054dcc9ccf..d63528e69e 100644 --- a/tests/packet-type-aware.at @@ -67521,7 +68042,7 @@ index d21fd777dd..c37852b216 100644 OVS_VSWITCHD_STOP diff --git a/tests/system-offloads-traffic.at b/tests/system-offloads-traffic.at -index 80bc1dd5c3..84bab88be2 100644 +index 80bc1dd5c3..bf60e4cb27 100644 --- a/tests/system-offloads-traffic.at +++ b/tests/system-offloads-traffic.at @@ -90,7 +90,7 @@ AT_CHECK([tc -o -s -d filter show dev ovs-p0 ingress | @@ -67542,7 +68063,7 @@ index 80bc1dd5c3..84bab88be2 100644 OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP -@@ -168,3 +168,131 @@ matchall +@@ -168,3 +168,186 @@ matchall ]) OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP @@ -67674,6 +68195,61 @@ index 80bc1dd5c3..84bab88be2 100644 + +OVS_TRAFFIC_VSWITCHD_STOP +AT_CLEANUP ++ ++AT_SETUP([offloads - delete ufid mapping if device not exist - offloads enabled]) ++OVS_TRAFFIC_VSWITCHD_START([], [], [-- set Open_vSwitch . other_config:hw-offload=true]) ++ ++AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"]) ++ ++ADD_NAMESPACES(at_ns0, at_ns1, at_ns2) ++ ++dnl Disable IPv6 to skip unexpected flow ++AT_CHECK([sysctl -w net.ipv6.conf.br0.disable_ipv6=1], [0], [ignore]) ++NS_CHECK_EXEC([at_ns0], [sysctl -w net.ipv6.conf.all.disable_ipv6=1], [0], [ignore]) ++NS_CHECK_EXEC([at_ns1], [sysctl -w net.ipv6.conf.all.disable_ipv6=1], [0], [ignore]) ++NS_CHECK_EXEC([at_ns2], [sysctl -w net.ipv6.conf.all.disable_ipv6=1], [0], [ignore]) ++ ++ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24", "aa:1a:54:e9:c5:56") ++ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24") ++ ++NS_CHECK_EXEC([at_ns0], [ping -q -c 2 -i 0.2 10.1.1.2 | FORMAT_PING], [0], [dnl ++2 packets transmitted, 2 received, 0% packet loss, time 0ms ++]) ++ ++dnl Delete and add interface ovs-p0/p0 ++AT_CHECK([ip link del dev ovs-p0]) ++AT_CHECK([ip link add p0 type veth peer name ovs-p0 || return 77]) ++AT_CHECK([ip link set p0 netns at_ns0]) ++AT_CHECK([ip link set dev ovs-p0 up]) ++NS_CHECK_EXEC([at_ns0], [ip addr add dev p0 "10.1.1.1/24"]) ++NS_CHECK_EXEC([at_ns0], [ip link set dev p0 up]) ++NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address "aa:1a:54:e9:c5:56"]) ++ ++AT_CHECK([ovs-appctl revalidator/purge], [0]) ++ ++dnl Generate flows to trigger the hmap expand once ++ADD_VETH(p2, at_ns2, br0, "10.1.1.3/24") ++NS_CHECK_EXEC([at_ns0], [ping -q -c 2 -i 0.2 10.1.1.2 | FORMAT_PING], [0], [dnl ++2 packets transmitted, 2 received, 0% packet loss, time 0ms ++]) ++NS_CHECK_EXEC([at_ns0], [ping -q -c 2 -i 0.2 10.1.1.3 | FORMAT_PING], [0], [dnl ++2 packets transmitted, 2 received, 0% packet loss, time 0ms ++]) ++ ++AT_CHECK([ovs-appctl revalidator/purge], [0]) ++dnl Fix purge fail occasionally ++AT_CHECK([ovs-appctl revalidator/purge], [0]) ++ ++AT_CHECK([test $(ovs-appctl dpctl/dump-flows | grep -c "eth_type(0x0800)") -eq 0], [0], [ignore]) ++ ++OVS_TRAFFIC_VSWITCHD_STOP(["/could not open network device ovs-p0/d ++/on nonexistent port/d ++/failed to flow_get/d ++/Failed to acquire udpif_key/d ++/No such device/d ++/failed to offload flow/d ++"]) ++AT_CLEANUP diff --git a/tests/system-route.at b/tests/system-route.at index 1714273e35..270956d13f 100644 --- a/tests/system-route.at @@ -70301,7 +70877,7 @@ index 08957bdf46..779ea60aee 100755 $FUNCNAME: attach the default sandbox to an interconnection network usage: $FUNCNAME NETWORK BRIDGE diff --git a/utilities/ovs-tcpdump.in b/utilities/ovs-tcpdump.in -index 82d1bedfa6..a49ec9f942 100755 +index 82d1bedfa6..420c11eb8a 100755 --- a/utilities/ovs-tcpdump.in +++ b/utilities/ovs-tcpdump.in @@ -44,6 +44,7 @@ try: @@ -70392,7 +70968,21 @@ index 82d1bedfa6..a49ec9f942 100755 pipes = _doexec(*([dump_cmd, '-i', mirror_interface] + tcpdargs)) try: while pipes.poll() is None: -@@ -512,17 +541,6 @@ def main(): +@@ -509,20 +538,20 @@ def main(): + print(data.decode('utf-8')) + raise KeyboardInterrupt + except KeyboardInterrupt: ++ # If there is a pipe behind ovs-tcpdump (such as ovs-tcpdump ++ # -i eth0 | grep "192.168.1.1"), the pipe is no longer available ++ # after received Ctrl+C. ++ # If we write data to an unavailable pipe, a pipe error will be ++ # reported, so we turn off stdout to avoid subsequent flushing ++ # of data into the pipe. ++ try: ++ sys.stdout.close() ++ except IOError: ++ pass ++ if pipes.poll() is None: pipes.terminate() diff --git a/SPECS/openvswitch2.17.spec b/SPECS/openvswitch2.17.spec index 26e2dc4..fb1740a 100644 --- a/SPECS/openvswitch2.17.spec +++ b/SPECS/openvswitch2.17.spec @@ -57,7 +57,7 @@ Summary: Open vSwitch Group: System Environment/Daemons daemon/database/utilities URL: http://www.openvswitch.org/ Version: 2.17.0 -Release: 77%{?dist} +Release: 82%{?dist} # Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the # lib/sflow*.[ch] files are SISSL @@ -748,6 +748,40 @@ exit 0 %endif %changelog +* Mon Apr 24 2023 Open vSwitch CI - 2.17.0-82 +- Merging upstream branch-2.17 [RH git: 34bbf561db] + Commit list: + b082241945 ovsdb: Allow conversion records with no data in a clustered storage. + efcdf6c0de ovsdb: Check for ephemeral columns before writing a new schema. + bf39ea3c79 ovsdb-tool: Fix cluster-to-standalone for DB conversion records. + + +* Fri Apr 07 2023 Open vSwitch CI - 2.17.0-81 +- Merging upstream branch-2.17 [RH git: a1438ec598] + Commit list: + 4f82f89039 ovs-tcpdump: Stdout is shutdown before ovs-tcpdump exit. + + +* Thu Apr 06 2023 Open vSwitch CI - 2.17.0-80 +- Merging upstream branch-2.17 [RH git: a34e49c430] + Commit list: + 77116d9903 Prepare for 2.17.7. + a08bb41e3c Set release date for 2.17.6. + + +* Thu Apr 06 2023 Open vSwitch CI - 2.17.0-79 +- Merging upstream branch-2.17 [RH git: 6a73129db8] + Commit list: + 27fb5db7f7 ofproto-dpif-xlate: Always mask ip proto field. (#2134873) + + +* Tue Apr 04 2023 Open vSwitch CI - 2.17.0-78 +- Merging upstream branch-2.17 [RH git: dd004f4cf6] + Commit list: + c3684a0604 conntrack-tp: Fix clang warning. + be19308aaf netdev-offload-tc: Del ufid mapping if device not exist. + + * Tue Apr 04 2023 Timothy Redaelli - 2.17.0-77 - ofproto-dpif-xlate: Always mask ip proto field. [RH git: cfd5c61966] (#2134873) The ofproto layer currently treats nw_proto field as overloaded to mean