Index: linux-4.19.118/net/bridge/br_private.h
===================================================================
--- linux-4.19.118.orig/net/bridge/br_private.h
+++ linux-4.19.118/net/bridge/br_private.h
@@ -176,6 +176,7 @@ struct net_bridge_fdb_key {
 struct net_bridge_fdb_entry {
 	struct rhash_head		rhnode;
 	struct net_bridge_port		*dst;
+	struct net_bridge_port		*old_dst;
 
 	struct net_bridge_fdb_key	key;
 	struct hlist_node		fdb_node;
@@ -183,11 +184,15 @@ struct net_bridge_fdb_entry {
 					is_static:1,
 					added_by_user:1,
 					added_by_external_learn:1,
-					offloaded:1;
+					offloaded:1,
+					quiesce:1;
 
 	/* write-heavy members should not affect lookups */
 	unsigned long			updated ____cacheline_aligned_in_smp;
 	unsigned long			used;
+	unsigned long			quiesce_flips;
+	unsigned long			quiesce_detect;
+	unsigned long			quiesce_hold;
 
 	struct rcu_head			rcu;
 };
@@ -281,6 +286,12 @@ struct net_bridge_port {
 #ifdef CONFIG_NET_SWITCHDEV
 	int				offload_fwd_mark;
 #endif
+	unsigned long			quiesce_hold;
+	unsigned long			quiesce_window;
+	unsigned long			quiesce_detect;
+	u16				quiesce_times;
+
+
 	u16				group_fwd_mask;
 	u16				backup_redirected_cnt;
 };
@@ -413,6 +424,13 @@ struct net_bridge {
 #ifdef CONFIG_NET_SWITCHDEV
 	int offload_fwd_mark;
 #endif
+
+	bool				quiescing;
+	unsigned long			quiesce_hold;
+	unsigned long			quiesce_window;
+	unsigned long			quiesce_detect;
+	u16				quiesce_times;
+
 	bool				neigh_suppress_enabled;
 	bool				mtu_set_by_user;
 	bool				flood_check;
@@ -545,6 +563,8 @@ struct net_bridge_fdb_entry *br_fdb_find
 int br_fdb_test_addr(struct net_device *dev, unsigned char *addr);
 int br_fdb_fillbuf(struct net_bridge *br, void *buf, unsigned long count,
 		   unsigned long off);
+int br_fdb_quiesce_fillbuf(struct net_bridge *br, void *buf, unsigned long count,
+		   unsigned long off);
 int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
 		  const unsigned char *addr, u16 vid);
 void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
Index: linux-4.19.118/include/linux/if_bridge.h
===================================================================
--- linux-4.19.118.orig/include/linux/if_bridge.h
+++ linux-4.19.118/include/linux/if_bridge.h
@@ -52,6 +52,7 @@ struct br_ip_list {
 #define BR_NEIGH_SUPPRESS	BIT(15)
 #define BR_ISOLATED		BIT(16)
 #define BR_FLOOD_CHECK		BIT(17)
+#define BR_QUIESCING		BIT(18)
 
 #define BR_DEFAULT_AGEING_TIME	(300 * HZ)
 
Index: linux-4.19.118/net/bridge/br_sysfs_if.c
===================================================================
--- linux-4.19.118.orig/net/bridge/br_sysfs_if.c
+++ linux-4.19.118/net/bridge/br_sysfs_if.c
@@ -167,6 +167,59 @@ static ssize_t show_hold_timer(struct ne
 }
 static BRPORT_ATTR(hold_timer, 0444, show_hold_timer, NULL);
 
+static ssize_t show_quiesce_hold(struct net_bridge_port *p,
+					   char *buf)
+{
+	return sprintf(buf, "%ld\n", jiffies_to_clock_t(p->quiesce_hold));
+}
+
+static int store_quiesce_hold(struct net_bridge_port *p, unsigned long v)
+{
+	p->quiesce_hold = clock_t_to_jiffies(v);
+	return 0;
+}
+
+static BRPORT_ATTR(quiesce_hold, 0644, show_quiesce_hold, store_quiesce_hold);
+
+static ssize_t show_quiesce_window(struct net_bridge_port *p,
+					   char *buf)
+{
+	return sprintf(buf, "%ld\n", jiffies_to_clock_t(p->quiesce_window));
+}
+
+static int store_quiesce_window(struct net_bridge_port *p, unsigned long v)
+{
+	p->quiesce_window = clock_t_to_jiffies(v);
+	return 0;
+}
+static BRPORT_ATTR(quiesce_window, 0644, show_quiesce_window, store_quiesce_window);
+
+static ssize_t show_quiesce_detect(struct net_bridge_port *p,
+					   char *buf)
+{
+	return sprintf(buf, "%ld\n", jiffies_to_clock_t(p->quiesce_detect));
+}
+
+static int store_quiesce_detect(struct net_bridge_port *p, unsigned long v)
+{
+	p->quiesce_detect = clock_t_to_jiffies(v);
+	return 0;
+}
+
+static BRPORT_ATTR(quiesce_detect, 0644, show_quiesce_detect, store_quiesce_detect);
+
+static ssize_t show_quiesce_times(struct net_bridge_port *p, char *buf)
+{
+	return sprintf(buf, "%d\n", p->quiesce_times);
+}
+
+static int store_quiesce_times(struct net_bridge_port *p, unsigned long v)
+{
+	p->quiesce_times = (u16) v;
+	return 0;
+}
+static BRPORT_ATTR(quiesce_times, 0644, show_quiesce_times, store_quiesce_times);
+
 static int store_flush(struct net_bridge_port *p, unsigned long v)
 {
 	br_fdb_delete_by_port(p->br, p, 0, 0); // Don't delete local entry
@@ -235,6 +288,7 @@ BRPORT_ATTR_FLAG(broadcast_flood, BR_BCA
 BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS);
 BRPORT_ATTR_FLAG(isolated, BR_ISOLATED);
 BRPORT_ATTR_FLAG(flood_check, BR_FLOOD_CHECK);
+BRPORT_ATTR_FLAG(quiescing, BR_QUIESCING);
 
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
@@ -287,6 +341,11 @@ static const struct brport_attribute *br
 	&brport_attr_group_fwd_mask,
 	&brport_attr_neigh_suppress,
 	&brport_attr_isolated,
+	&brport_attr_quiescing,
+	&brport_attr_quiesce_hold,
+	&brport_attr_quiesce_window,
+	&brport_attr_quiesce_detect,
+	&brport_attr_quiesce_times,
 	&brport_attr_flood_check,
 	&brport_attr_backup_port,
 	NULL
Index: linux-4.19.118/net/bridge/br_fdb.c
===================================================================
--- linux-4.19.118.orig/net/bridge/br_fdb.c
+++ linux-4.19.118/net/bridge/br_fdb.c
@@ -485,6 +485,93 @@ int br_fdb_fillbuf(struct net_bridge *br
 	return num;
 }
 
+/*
+ * Fill buffer with forwarding table records in
+ * the API format with quiescing information.
+ */
+int br_fdb_quiesce_fillbuf(struct net_bridge *br, void *buf,
+		   unsigned long maxnum, unsigned long skip)
+{
+	struct net_bridge_fdb_entry *f;
+	struct __fdb_quiesce_entry *fqe = buf;
+	struct __fdb_entry *fe;
+	int num = 0;
+	unsigned long now = jiffies;
+
+	memset(buf, 0, maxnum*sizeof(struct __fdb_quiesce_entry));
+
+	rcu_read_lock();
+	hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
+		if (num >= maxnum)
+			break;
+
+		if (has_expired(br, f))
+			continue;
+
+		/* ignore pseudo entry for local MAC address */
+		if (!f->dst)
+			continue;
+
+		if (skip) {
+			--skip;
+			continue;
+		}
+
+		fe = &(fqe->fe);
+
+		/* convert from internal format to API */
+		memcpy(fe->mac_addr, f->key.addr.addr, ETH_ALEN);
+
+		/* due to ABI compat need to split into hi/lo */
+		fe->port_no = f->dst->port_no;
+		fe->port_hi = f->dst->port_no >> 8;
+		memcpy(fqe->port_name,f->dst->dev->name,sizeof(fqe->port_name));
+		if (f->old_dst) {
+			fqe->has_old = 1;
+			fqe->old_port_no = f->old_dst->port_no;
+			fqe->old_port_hi = f->old_dst->port_no >> 8;
+			memcpy(fqe->old_port_name,f->old_dst->dev->name,sizeof(fqe->old_port_name));
+		}
+
+		fe->is_local = f->is_local;
+		if (!f->is_static)
+			fe->ageing_timer_value = jiffies_delta_to_clock_t(now - f->used);
+		if (!f->is_static && f->old_dst) {
+			if (f->quiesce_detect) {
+			       if (!time_after(now, f->quiesce_detect)) {
+					fqe->quiesce_detect_timer_value = jiffies_delta_to_clock_t(
+							f->quiesce_detect - now);
+				} else {
+					fqe->quiesce_detect_timer_value = jiffies_delta_to_clock_t(
+							now - f->quiesce_detect);
+					fqe->qdtv_past = 1;
+				}
+			}
+			if (f->quiesce_hold) {
+				if (!time_after(now, f->quiesce_hold)) {
+					fqe->quiesce_hold_timer_value = jiffies_delta_to_clock_t(
+							f->quiesce_hold - now);
+				} else {
+					fqe->quiesce_hold_timer_value = jiffies_delta_to_clock_t(
+							now - f->quiesce_hold);
+					fqe->qhtv_past = 1;
+				}
+			}
+			fqe->quiesce_flips = f->quiesce_flips;
+			fqe->quiesce = f->quiesce;
+		}
+		fqe->is_static = f->is_static;
+		fqe->updated_timer_value = jiffies_delta_to_clock_t(jiffies - f->updated);
+		fqe->vlan_id = f->key.vlan_id;
+
+
+		++fqe;
+		++num;
+	}
+	rcu_read_unlock();
+
+	return num;
+}
 static struct net_bridge_fdb_entry *fdb_create(struct net_bridge *br,
 					       struct net_bridge_port *source,
 					       const unsigned char *addr,
@@ -498,12 +585,17 @@ static struct net_bridge_fdb_entry *fdb_
 	if (fdb) {
 		memcpy(fdb->key.addr.addr, addr, ETH_ALEN);
 		fdb->dst = source;
+		fdb->old_dst = NULL;
 		fdb->key.vlan_id = vid;
 		fdb->is_local = is_local;
 		fdb->is_static = is_static;
 		fdb->added_by_user = 0;
 		fdb->added_by_external_learn = 0;
 		fdb->offloaded = 0;
+		fdb->quiesce = 0;
+		fdb->quiesce_flips = 0;
+		fdb->quiesce_detect = 0;
+		fdb->quiesce_hold = 0;
 		fdb->updated = fdb->used = jiffies;
 		if (rhashtable_lookup_insert_fast(&br->fdb_hash_tbl,
 						  &fdb->rhnode,
@@ -558,6 +650,80 @@ int br_fdb_insert(struct net_bridge *br,
 	return ret;
 }
 
+static int br_fdb_quiesce(struct net_bridge *br, struct net_bridge_port *source,
+		   struct net_bridge_fdb_entry *fdb,
+		   const unsigned char *addr, u16 vid, bool added_by_user)
+{
+	unsigned long quiesce_window, quiesce_detect, quiesce_hold;
+	unsigned long now = jiffies;
+	u16 quiesce_times;
+	int i = 1;
+
+	if (likely(!(br->quiescing || (source->flags & BR_QUIESCING)) ||
+		    fdb->old_dst != source || fdb->added_by_user))
+		return 0;
+
+	quiesce_window = (source->quiesce_window) ? source->quiesce_window : br->quiesce_window;
+	quiesce_detect = (source->quiesce_detect) ? source->quiesce_detect : br->quiesce_detect;
+	quiesce_hold = (source->quiesce_hold) ? source->quiesce_hold : br->quiesce_hold;
+	quiesce_times = (source->quiesce_times) ? source->quiesce_times : br->quiesce_times;
+
+	netdev_dbg_ratelimited(br->dev, "quiesce:%d %s (addr:%pM, vlan:%u), quiesce %u,"
+		                        " flips %lu, quiesce_detect %lu, quiesce_hold %lu\n",
+		i++, source->dev->name, addr, vid, fdb->quiesce, fdb->quiesce_flips,
+		fdb->quiesce_detect, fdb->quiesce_hold );
+
+	if (time_after(now, fdb->updated + quiesce_window))
+		fdb->quiesce_flips = 1;
+
+	if (fdb->quiesce) {
+		if (fdb->quiesce_detect) {
+			if (time_after(now,fdb->quiesce_detect)) {
+				fdb->quiesce_hold = now + quiesce_hold;
+				fdb->quiesce_detect = 0;
+			} else
+				fdb->quiesce = 0;
+		} else if (fdb->quiesce_hold) {
+			if (time_after(now, fdb->quiesce_hold)) {
+				fdb->quiesce_hold = 0;
+				fdb->quiesce_detect = now + quiesce_detect;
+			 } else {
+				if (time_after(fdb->updated, now - quiesce_detect))
+					fdb->quiesce_hold = min(fdb->quiesce_hold + quiesce_window,
+								fdb->updated + (quiesce_hold * 2));
+				else
+					fdb->quiesce_hold -= (quiesce_window + quiesce_detect);
+			}
+		} else
+			fdb->quiesce = 0;
+	}
+
+	netdev_dbg_ratelimited(br->dev, "quiesce:%d %s (addr:%pM, vlan:%u), quiesce %u,"
+		       		        " flips %lu, quiesce_detect %lu, quiesce_hold %lu\n",
+		i++, source->dev->name, addr, vid, fdb->quiesce, fdb->quiesce_flips,
+		fdb->quiesce_detect, fdb->quiesce_hold );
+
+	if (fdb->quiesce)
+		return 1;
+
+	fdb->quiesce_hold = 0;
+	fdb->quiesce_detect = 0;
+
+	if((++fdb->quiesce_flips) >= quiesce_times) {
+		fdb->quiesce = 1;
+		fdb->quiesce_detect = now + quiesce_detect;
+		fdb->quiesce_flips = 0;
+	}
+
+	netdev_dbg_ratelimited(br->dev, "quiesce:%d %s (addr:%pM, vlan:%u), quiesce %u,"
+			                " flips %lu, quiesce_detect %lu, quiesce_hold %lu\n",
+		i++, source->dev->name, addr, vid, fdb->quiesce, fdb->quiesce_flips,
+		fdb->quiesce_detect, fdb->quiesce_hold );
+
+	return fdb->quiesce;
+}
+
+
 void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
 		   const unsigned char *addr, u16 vid, bool added_by_user)
 {
@@ -582,22 +748,29 @@ void br_fdb_update(struct net_bridge *br
 					source->dev->name, addr, vid);
 		} else {
 			unsigned long now = jiffies;
+			int quiesce = 0;
 
 			/* fastpath: update of existing entry */
 			if (unlikely(source != fdb->dst)) {
-				fdb->dst = source;
-				fdb_modified = true;
-				/* Take over HW learned entry */
-				if (unlikely(fdb->added_by_external_learn))
-					fdb->added_by_external_learn = 0;
+				quiesce = br_fdb_quiesce(br, source, fdb, addr, vid, added_by_user);
+				if (!quiesce) {
+					fdb->old_dst = fdb->dst;
+					fdb->dst = source;
+					fdb_modified = true;
+					/* Take over HW learned entry */
+					if (unlikely(fdb->added_by_external_learn))
+						fdb->added_by_external_learn = 0;
+				}
 			}
-			if (now != fdb->updated)
-				fdb->updated = now;
-			if (unlikely(added_by_user))
-				fdb->added_by_user = 1;
-			if (unlikely(fdb_modified)) {
-				trace_br_fdb_update(br, source, addr, vid, added_by_user);
-				fdb_notify(br, fdb, RTM_NEWNEIGH, true);
+			if (!quiesce) {
+				if (now != fdb->updated)
+					fdb->updated = now;
+				if (unlikely(added_by_user))
+					fdb->added_by_user = 1;
+				if (unlikely(fdb_modified)) {
+					trace_br_fdb_update(br, source, addr, vid, added_by_user);
+					fdb_notify(br, fdb, RTM_NEWNEIGH, true);
+				}
 			}
 		}
 	} else {
Index: linux-4.19.118/net/bridge/br_forward.c
===================================================================
--- linux-4.19.118.orig/net/bridge/br_forward.c
+++ linux-4.19.118/net/bridge/br_forward.c
@@ -240,6 +240,47 @@ void br_flood(struct net_bridge *br, str
 			break;
 		}
 
+		if (br->quiescing || (p->flags & BR_QUIESCING)) {
+			/* Enable flooding misbehavior management*/
+			struct net_bridge_fdb_entry *src;
+			u16 vid = 0;
+			int skip = 0;
+
+			if ((0 != br_vlan_get_tag(skb, &vid)) ||
+			    eth_hdr(skb)->h_proto == htons(ETH_P_8021Q) ||
+			    eth_hdr(skb)->h_proto == htons(ETH_P_8021AD))  {
+				struct vlan_hdr *vhdr = (struct vlan_hdr *)skb->data;
+				vid = ntohs(vhdr->h_vlan_TCI);
+			}
+
+			src = br_fdb_find_rcu(br, eth_hdr(skb)->h_source, vid);
+			if (src && src->quiesce) {
+				netdev_dbg_ratelimited(br->dev,
+					"quiesce: %s flooding, (addr:%pM, vlan:%u), srcdst %d, src->quiesce %d, time_after %d",
+					(p && p->dev) ? p->dev->name : "no-dev-name",
+					eth_hdr(skb)->h_source, vid,
+					(src->old_dst == p), src->quiesce,
+					time_after(src->quiesce_detect, jiffies));
+
+				/* enable detecting whether our floods trigger misbehavior */
+				if (src->old_dst == p && src->quiesce_detect &&
+				    time_after(src->quiesce_detect, jiffies))
+					skip = 1;
+				if (prev && src->old_dst == prev && src->quiesce_detect &&
+				    time_after(src->quiesce_detect, jiffies))
+					prev = NULL;
+				/* dont flood to ports we believe the src is already on */
+				if (src->dst == p && src->quiesce_hold &&
+				    time_after(src->quiesce_hold, jiffies))
+					skip = 1;
+				if (prev && src->dst == prev && src->quiesce_hold &&
+				    time_after(src->quiesce_hold, jiffies))
+					prev = NULL;
+				if (skip)
+					continue;
+			}
+		}
+
 		/* Do not flood to ports that enable proxy ARP */
 		if (p->flags & BR_PROXYARP)
 			continue;
Index: linux-4.19.118/net/bridge/br_sysfs_br.c
===================================================================
--- linux-4.19.118.orig/net/bridge/br_sysfs_br.c
+++ linux-4.19.118/net/bridge/br_sysfs_br.c
@@ -349,6 +349,110 @@ static ssize_t flush_store(struct device
 }
 static DEVICE_ATTR_WO(flush);
 
+static ssize_t quiescing_show(
+	struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct net_bridge *br = to_bridge(d);
+	return sprintf(buf, "%u\n", br->quiescing);
+}
+
+static int set_quiescing(struct net_bridge *br, unsigned long val)
+{
+	br->quiescing = val ? true : false;
+	return 0;
+}
+
+static ssize_t quiescing_store(
+	struct device *d, struct device_attribute *attr, const char *buf,
+	size_t len)
+{
+	return store_bridge_parm(d, buf, len, set_quiescing);
+}
+static DEVICE_ATTR_RW(quiescing);
+
+static ssize_t quiesce_window_show(
+	struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct net_bridge *br = to_bridge(d);
+	return sprintf(buf, "%ld\n", jiffies_to_clock_t(br->quiesce_window));
+}
+
+static int set_quiesce_window(struct net_bridge *br, unsigned long val)
+{
+	br->quiesce_window = clock_t_to_jiffies(val);
+	return 0;
+}
+
+static ssize_t quiesce_window_store(
+	struct device *d, struct device_attribute *attr, const char *buf,
+	size_t len)
+{
+	return store_bridge_parm(d, buf, len, set_quiesce_window);
+}
+static DEVICE_ATTR_RW(quiesce_window);
+
+static ssize_t quiesce_detect_show(
+	struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct net_bridge *br = to_bridge(d);
+	return sprintf(buf, "%ld\n", jiffies_to_clock_t(br->quiesce_detect));
+}
+
+static int set_quiesce_detect(struct net_bridge *br, unsigned long val)
+{
+	br->quiesce_detect = clock_t_to_jiffies(val);
+	return 0;
+}
+
+static ssize_t quiesce_detect_store(
+	struct device *d, struct device_attribute *attr, const char *buf,
+	size_t len)
+{
+	return store_bridge_parm(d, buf, len, set_quiesce_detect);
+}
+static DEVICE_ATTR_RW(quiesce_detect);
+
+static ssize_t quiesce_hold_show(
+	struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct net_bridge *br = to_bridge(d);
+	return sprintf(buf, "%ld\n", jiffies_to_clock_t(br->quiesce_hold));
+}
+
+static int set_quiesce_hold(struct net_bridge *br, unsigned long val)
+{
+	br->quiesce_hold = clock_t_to_jiffies(val);
+	return 0;
+}
+
+static ssize_t quiesce_hold_store(
+	struct device *d, struct device_attribute *attr, const char *buf,
+	size_t len)
+{
+	return store_bridge_parm(d, buf, len, set_quiesce_hold);
+}
+static DEVICE_ATTR_RW(quiesce_hold);
+
+static ssize_t quiesce_times_show(
+	struct device *d, struct device_attribute *attr, char *buf)
+{
+	struct net_bridge *br = to_bridge(d);
+	return sprintf(buf, "%d\n", br->quiesce_times);
+}
+
+static int set_quiesce_times(struct net_bridge *br, unsigned long val)
+{
+	br->quiesce_times = (u16) val;
+	return 0;
+}
+
+static ssize_t quiesce_times_store(
+	struct device *d, struct device_attribute *attr, const char *buf,
+	size_t len)
+{
+	return store_bridge_parm(d, buf, len, set_quiesce_times);
+}
+static DEVICE_ATTR_RW(quiesce_times);
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 static ssize_t multicast_router_show(struct device *d,
 				     struct device_attribute *attr, char *buf)
@@ -844,6 +948,11 @@ static struct attribute *bridge_attrs[]
 	&dev_attr_gc_timer.attr,
 	&dev_attr_group_addr.attr,
 	&dev_attr_flush.attr,
+	&dev_attr_quiescing.attr,
+	&dev_attr_quiesce_window.attr,
+	&dev_attr_quiesce_detect.attr,
+	&dev_attr_quiesce_hold.attr,
+	&dev_attr_quiesce_times.attr,
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 	&dev_attr_multicast_router.attr,
 	&dev_attr_multicast_snooping.attr,
@@ -920,6 +1029,39 @@ static struct bin_attribute bridge_forwa
 };
 
 /*
+ * Export the forwarding information table with quiescing as a binary file
+ * The records are struct __fdb_quiesce_entry.
+ *
+ * Returns the number of bytes read.
+ */
+static ssize_t brforward_quiesce_read(struct file *filp, struct kobject *kobj,
+			      struct bin_attribute *bin_attr,
+			      char *buf, loff_t off, size_t count)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct net_bridge *br = to_bridge(dev);
+	int n;
+
+	/* must read whole records */
+	if (off % sizeof(struct __fdb_quiesce_entry) != 0)
+		return -EINVAL;
+
+	n =  br_fdb_quiesce_fillbuf(br, buf,
+			    count / sizeof(struct __fdb_quiesce_entry),
+			    off / sizeof(struct __fdb_quiesce_entry));
+
+	if (n > 0)
+		n *= sizeof(struct __fdb_quiesce_entry);
+
+	return n;
+}
+
+static struct bin_attribute bridge_quiesce_forward = {
+	.attr = { .name = SYSFS_BRIDGE_QUIESCE_FDB,
+		  .mode = 0444, },
+	.read = brforward_quiesce_read,
+};
+/*
  * Add entries in sysfs onto the existing network class device
  * for the bridge.
  *   Adds a attribute group "bridge" containing tuning parameters.
@@ -950,14 +1092,23 @@ int br_sysfs_addbr(struct net_device *de
 		goto out2;
 	}
 
+	err = sysfs_create_bin_file(brobj, &bridge_quiesce_forward);
+	if (err) {
+		pr_info("%s: can't create attribute file %s/%s\n",
+			__func__, dev->name, bridge_quiesce_forward.attr.name);
+		goto out3;
+	}
+
 	br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, brobj);
 	if (!br->ifobj) {
 		pr_info("%s: can't add kobject (directory) %s/%s\n",
 			__func__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR);
 		err = -ENOMEM;
-		goto out3;
+		goto out4;
 	}
 	return 0;
+ out4:
+	sysfs_remove_bin_file(&dev->dev.kobj, &bridge_quiesce_forward);
  out3:
 	sysfs_remove_bin_file(&dev->dev.kobj, &bridge_forward);
  out2:
@@ -974,5 +1125,6 @@ void br_sysfs_delbr(struct net_device *d
 
 	kobject_put(br->ifobj);
 	sysfs_remove_bin_file(kobj, &bridge_forward);
+	sysfs_remove_bin_file(kobj, &bridge_quiesce_forward);
 	sysfs_remove_group(kobj, &bridge_group);
 }
Index: linux-4.19.118/net/bridge/br_device.c
===================================================================
--- linux-4.19.118.orig/net/bridge/br_device.c
+++ linux-4.19.118/net/bridge/br_device.c
@@ -448,6 +448,11 @@ void br_dev_setup(struct net_device *dev
 	br->bridge_hello_time = br->hello_time = 2 * HZ;
 	br->bridge_forward_delay = br->forward_delay = 15 * HZ;
 	br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME;
+	br->quiescing = false;
+	br->quiesce_window = BR_DEFAULT_AGEING_TIME / 10;
+	br->quiesce_detect = BR_DEFAULT_AGEING_TIME / 30;
+	br->quiesce_hold = BR_DEFAULT_AGEING_TIME * 2;
+	br->quiesce_times = 10;
 	dev->max_mtu = ETH_MAX_MTU;
 
 	br_netfilter_rtable_init(br);
Index: linux-4.19.118/net/bridge/br_if.c
===================================================================
--- linux-4.19.118.orig/net/bridge/br_if.c
+++ linux-4.19.118/net/bridge/br_if.c
@@ -431,6 +431,8 @@ static struct net_bridge_port *new_nbp(s
 	p->priority = 0x8000 >> BR_PORT_BITS;
 	p->port_no = index;
 	p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
+	if (br->quiescing)
+		p->flags |= BR_QUIESCING;
 	br_init_port(p);
 	br_set_state(p, BR_STATE_DISABLED);
 	br_stp_port_timer_init(p);
Index: linux-4.19.118/include/uapi/linux/if_bridge.h
===================================================================
--- linux-4.19.118.orig/include/uapi/linux/if_bridge.h
+++ linux-4.19.118/include/uapi/linux/if_bridge.h
@@ -20,6 +20,7 @@
 
 #define SYSFS_BRIDGE_ATTR	"bridge"
 #define SYSFS_BRIDGE_FDB	"brforward"
+#define SYSFS_BRIDGE_QUIESCE_FDB	"brforward_quiesce"
 #define SYSFS_BRIDGE_PORT_SUBDIR "brif"
 #define SYSFS_BRIDGE_PORT_ATTR	"brport"
 #define SYSFS_BRIDGE_PORT_LINK	"bridge"
@@ -100,6 +101,24 @@ struct __fdb_entry {
 	__u16 unused;
 };
 
+struct __fdb_quiesce_entry {
+	struct __fdb_entry fe;
+	__u8 port_name[IFNAMSIZ];
+	__u8 has_old;
+	__u8 old_port_name[IFNAMSIZ];
+	__u8 old_port_no;
+	__u8 old_port_hi;
+	__u32 updated_timer_value;
+	__u16 vlan_id;
+	__u8 is_static;
+	__u8 quiesce;
+	__u32 quiesce_flips;
+	__u8 qdtv_past;
+	__u32 quiesce_detect_timer_value;
+	__u8 qhtv_past;
+	__u32 quiesce_hold_timer_value;
+};
+
 /* Bridge Flags */
 #define BRIDGE_FLAGS_MASTER	1	/* Bridge command to/from master */
 #define BRIDGE_FLAGS_SELF	2	/* Bridge command to/from lowerdev */
