diff --git a/SOURCES/openvswitch-3.1.0.patch b/SOURCES/openvswitch-3.1.0.patch
index 07a8c47..0eebf8f 100644
--- a/SOURCES/openvswitch-3.1.0.patch
+++ b/SOURCES/openvswitch-3.1.0.patch
@@ -488,6 +488,21 @@ index 524670e45..8cf7779c6 100644
      }
  
      ct->next_sweep = (i < N_EXP_LISTS) ? i : 0;
+diff --git a/lib/cpu.c b/lib/cpu.c
+index 0292f715e..fbbea4005 100644
+--- a/lib/cpu.c
++++ b/lib/cpu.c
+@@ -37,7 +37,9 @@ static bool x86_has_isa(uint32_t leaf, enum x86_reg reg, uint32_t bit)
+ {
+     uint32_t regs[4];
+ 
+-    ovs_assert(__get_cpuid_max(leaf & X86_LEAF_MASK, NULL) >= leaf);
++    if (__get_cpuid_max(leaf & X86_LEAF_MASK, NULL) < leaf) {
++        return false;
++    }
+ 
+     __cpuid_count(leaf, 0, regs[EAX], regs[EBX], regs[ECX], regs[EDX]);
+     return (regs[reg] & ((uint32_t) 1 << bit)) != 0;
 diff --git a/lib/db-ctl-base.c b/lib/db-ctl-base.c
 index 134496ef3..5d2635946 100644
 --- a/lib/db-ctl-base.c
@@ -777,6 +792,91 @@ index ab5b8223e..ac182436b 100644
      bool reuse = false;
  
      ovs_mutex_lock(&dpdk_mp_mutex);
+diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
+index 65bdd51db..94b99a7be 100644
+--- a/lib/netdev-linux.c
++++ b/lib/netdev-linux.c
+@@ -2712,8 +2712,16 @@ tc_add_matchall_policer(struct netdev *netdev, uint32_t kbits_rate,
+ 
+     err = tc_transact(&request, &reply);
+     if (!err) {
+-        struct tcmsg *tc =
+-            ofpbuf_at_assert(reply, NLMSG_HDRLEN, sizeof *tc);
++        struct ofpbuf b = ofpbuf_const_initializer(reply->data, reply->size);
++        struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
++        struct tcmsg *tc = ofpbuf_try_pull(&b, sizeof *tc);
++
++        if (!nlmsg || !tc) {
++            VLOG_ERR_RL(&rl,
++                        "Failed to add match all policer, malformed reply");
++            ofpbuf_delete(reply);
++            return EPROTO;
++        }
+         ofpbuf_delete(reply);
+     }
+ 
+@@ -5732,26 +5740,27 @@ static int
+ tc_update_policer_action_stats(struct ofpbuf *msg,
+                                struct ofputil_meter_stats *stats)
+ {
++    struct ofpbuf b = ofpbuf_const_initializer(msg->data, msg->size);
++    struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
++    struct tcamsg *tca = ofpbuf_try_pull(&b, sizeof *tca);
+     struct ovs_flow_stats stats_dropped;
+     struct ovs_flow_stats stats_hw;
+     struct ovs_flow_stats stats_sw;
+     const struct nlattr *act;
+     struct nlattr *prio;
+-    struct tcamsg *tca;
+     int error = 0;
+ 
+     if (!stats) {
+         goto exit;
+     }
+ 
+-    if (NLMSG_HDRLEN + sizeof *tca > msg->size) {
++    if (!nlmsg || !tca) {
+         VLOG_ERR_RL(&rl, "Failed to get action stats, size error");
+         error = EPROTO;
+         goto exit;
+     }
+ 
+-    tca = ofpbuf_at_assert(msg, NLMSG_HDRLEN, sizeof *tca);
+-    act = nl_attr_find(msg, NLMSG_HDRLEN + sizeof *tca, TCA_ACT_TAB);
++    act = nl_attr_find(&b, 0, TCA_ACT_TAB);
+     if (!act) {
+         VLOG_ERR_RL(&rl, "Failed to get action stats, can't find attribute");
+         error = EPROTO;
+@@ -6016,20 +6025,26 @@ static int
+ tc_parse_class(const struct ofpbuf *msg, unsigned int *handlep,
+                struct nlattr **options, struct netdev_queue_stats *stats)
+ {
++    struct ofpbuf b = ofpbuf_const_initializer(msg->data, msg->size);
++    struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
++    struct tcmsg *tc = ofpbuf_try_pull(&b, sizeof *tc);
+     static const struct nl_policy tca_policy[] = {
+         [TCA_OPTIONS] = { .type = NL_A_NESTED, .optional = false },
+         [TCA_STATS2] = { .type = NL_A_NESTED, .optional = false },
+     };
+     struct nlattr *ta[ARRAY_SIZE(tca_policy)];
+ 
+-    if (!nl_policy_parse(msg, NLMSG_HDRLEN + sizeof(struct tcmsg),
+-                         tca_policy, ta, ARRAY_SIZE(ta))) {
++    if (!nlmsg || !tc) {
++        VLOG_ERR_RL(&rl, "failed to parse class message, malformed reply");
++        goto error;
++    }
++
++    if (!nl_policy_parse(&b, 0, tca_policy, ta, ARRAY_SIZE(ta))) {
+         VLOG_WARN_RL(&rl, "failed to parse class message");
+         goto error;
+     }
+ 
+     if (handlep) {
+-        struct tcmsg *tc = ofpbuf_at_assert(msg, NLMSG_HDRLEN, sizeof *tc);
+         *handlep = tc->tcm_handle;
+     }
+ 
 diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c
 index b89dfdd52..6c9094638 100644
 --- a/lib/netdev-native-tnl.c
@@ -2059,10 +2159,114 @@ index 62da9febb..86747e58b 100644
      SSL_CTX_set_tmp_dh_callback(ctx, tmp_dh_callback);
  #else
 diff --git a/lib/tc.c b/lib/tc.c
-index 4c07e2216..5c32c6f97 100644
+index 4c07e2216..270dc95ce 100644
 --- a/lib/tc.c
 +++ b/lib/tc.c
-@@ -2354,7 +2354,9 @@ tc_del_filter(struct tcf_id *id, const char *kind)
+@@ -36,6 +36,7 @@
+ #include <unistd.h>
+ 
+ #include "byte-order.h"
++#include "coverage.h"
+ #include "netlink-socket.h"
+ #include "netlink.h"
+ #include "openvswitch/ofpbuf.h"
+@@ -67,6 +68,8 @@
+ 
+ VLOG_DEFINE_THIS_MODULE(tc);
+ 
++COVERAGE_DEFINE(tc_netlink_malformed_reply);
++
+ static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);
+ 
+ static enum tc_offload_policy tc_policy = TC_POLICY_NONE;
+@@ -2190,18 +2193,19 @@ int
+ parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tcf_id *id,
+                            struct tc_flower *flower, bool terse)
+ {
+-    struct tcmsg *tc;
++    struct ofpbuf b = ofpbuf_const_initializer(reply->data, reply->size);
++    struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
++    struct tcmsg *tc = ofpbuf_try_pull(&b, sizeof *tc);
+     struct nlattr *ta[ARRAY_SIZE(tca_policy)];
+     const char *kind;
+ 
+-    if (NLMSG_HDRLEN + sizeof *tc > reply->size) {
++    if (!nlmsg || !tc) {
++        COVERAGE_INC(tc_netlink_malformed_reply);
+         return EPROTO;
+     }
+ 
+     memset(flower, 0, sizeof *flower);
+ 
+-    tc = ofpbuf_at_assert(reply, NLMSG_HDRLEN, sizeof *tc);
+-
+     flower->key.eth_type = (OVS_FORCE ovs_be16) tc_get_minor(tc->tcm_info);
+     flower->mask.eth_type = OVS_BE16_MAX;
+     id->prio = tc_get_major(tc->tcm_info);
+@@ -2215,8 +2219,7 @@ parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tcf_id *id,
+         return EAGAIN;
+     }
+ 
+-    if (!nl_policy_parse(reply, NLMSG_HDRLEN + sizeof *tc,
+-                         tca_policy, ta, ARRAY_SIZE(ta))) {
++    if (!nl_policy_parse(&b, 0, tca_policy, ta, ARRAY_SIZE(ta))) {
+         VLOG_ERR_RL(&error_rl, "failed to parse tca policy");
+         return EPROTO;
+     }
+@@ -2237,13 +2240,17 @@ parse_netlink_to_tc_flower(struct ofpbuf *reply, struct tcf_id *id,
+ int
+ parse_netlink_to_tc_chain(struct ofpbuf *reply, uint32_t *chain)
+ {
++    struct ofpbuf b = ofpbuf_const_initializer(reply->data, reply->size);
++    struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
++    struct tcmsg *tc = ofpbuf_try_pull(&b, sizeof *tc);
+     struct nlattr *ta[ARRAY_SIZE(tca_chain_policy)];
+-    struct tcmsg *tc;
+ 
+-    tc = ofpbuf_at_assert(reply, NLMSG_HDRLEN, sizeof *tc);
++    if (!nlmsg || !tc) {
++        COVERAGE_INC(tc_netlink_malformed_reply);
++        return EPROTO;
++    }
+ 
+-    if (!nl_policy_parse(reply, NLMSG_HDRLEN + sizeof *tc,
+-                         tca_chain_policy, ta, ARRAY_SIZE(ta))) {
++    if (!nl_policy_parse(&b, 0, tca_chain_policy, ta, ARRAY_SIZE(ta))) {
+         VLOG_ERR_RL(&error_rl, "failed to parse tca chain policy");
+         return EINVAL;
+     }
+@@ -2307,21 +2314,27 @@ int
+ parse_netlink_to_tc_policer(struct ofpbuf *reply, uint32_t police_idx[])
+ {
+     static struct nl_policy actions_orders_policy[TCA_ACT_MAX_PRIO] = {};
++    struct ofpbuf b = ofpbuf_const_initializer(reply->data, reply->size);
+     struct nlattr *actions_orders[ARRAY_SIZE(actions_orders_policy)];
++    struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
+     const int max_size = ARRAY_SIZE(actions_orders_policy);
++    struct tcamsg *tca = ofpbuf_try_pull(&b, sizeof *tca);
+     const struct nlattr *actions;
+     struct tc_flower flower;
+-    struct tcamsg *tca;
+     int i, cnt = 0;
+     int err;
+ 
++    if (!nlmsg || !tca) {
++        COVERAGE_INC(tc_netlink_malformed_reply);
++        return EPROTO;
++    }
++
+     for (i = 0; i < max_size; i++) {
+         actions_orders_policy[i].type = NL_A_NESTED;
+         actions_orders_policy[i].optional = true;
+     }
+ 
+-    tca = ofpbuf_at_assert(reply, NLMSG_HDRLEN, sizeof *tca);
+-    actions = nl_attr_find(reply, NLMSG_HDRLEN + sizeof *tca, TCA_ACT_TAB);
++    actions = nl_attr_find(&b, 0, TCA_ACT_TAB);
+     if (!actions || !nl_parse_nested(actions, actions_orders_policy,
+                                      actions_orders, max_size)) {
+         VLOG_ERR_RL(&error_rl,
+@@ -2354,7 +2367,9 @@ tc_del_filter(struct tcf_id *id, const char *kind)
      struct ofpbuf request;
  
      request_from_tcf_id(id, 0, RTM_DELTFILTER, NLM_F_ACK, &request);
@@ -2073,6 +2277,24 @@ index 4c07e2216..5c32c6f97 100644
      return tc_transact(&request, NULL);
  }
  
+@@ -3821,8 +3836,15 @@ tc_replace_flower(struct tcf_id *id, struct tc_flower *flower)
+ 
+     error = tc_transact(&request, &reply);
+     if (!error) {
+-        struct tcmsg *tc =
+-            ofpbuf_at_assert(reply, NLMSG_HDRLEN, sizeof *tc);
++        struct ofpbuf b = ofpbuf_const_initializer(reply->data, reply->size);
++        struct nlmsghdr *nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg);
++        struct tcmsg *tc = ofpbuf_try_pull(&b, sizeof *tc);
++
++        if (!nlmsg || !tc) {
++            COVERAGE_INC(tc_netlink_malformed_reply);
++            ofpbuf_delete(reply);
++            return EPROTO;
++        }
+ 
+         id->prio = tc_get_major(tc->tcm_info);
+         id->handle = tc->tcm_handle;
 diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c
 index 742eed399..f13478a88 100644
 --- a/ofproto/ofproto-dpif-ipfix.c
diff --git a/SPECS/openvswitch3.1.spec b/SPECS/openvswitch3.1.spec
index 7616c72..2799cc7 100644
--- a/SPECS/openvswitch3.1.spec
+++ b/SPECS/openvswitch3.1.spec
@@ -57,7 +57,7 @@ Summary: Open vSwitch
 Group: System Environment/Daemons daemon/database/utilities
 URL: http://www.openvswitch.org/
 Version: 3.1.0
-Release: 28%{?dist}
+Release: 30%{?dist}
 
 # Nearly all of openvswitch is ASL 2.0.  The bugtool is LGPLv2+, and the
 # lib/sflow*.[ch] files are SISSL
@@ -754,6 +754,17 @@ exit 0
 %endif
 
 %changelog
+* Wed Jun 07 2023 Open vSwitch CI <ovs-ci@redhat.com> - 3.1.0-30
+- Merging upstream branch-3.1 [RH git: a29d6e27ae]
+    Commit list:
+    3fcb817840 cpu: Fix cpuid check for some AMD processors. (#2211747)
+    01f0668fdf tc: Fix crash on malformed reply from kernel.
+
+
+* Wed Jun 07 2023 Timothy Redaelli <tredaelli@redhat.com> - 3.1.0-29
+- redhat: Fix an unwanted change that prevent rh-fail-if-dirty to work [RH git: 9c39a6c81f]
+
+
 * Fri Jun 02 2023 Open vSwitch CI <ovs-ci@redhat.com> - 3.1.0-28
 - Merging upstream branch-3.1 [RH git: 0f2e734497]
     Commit list: