void nfp_flower_cmsg_process_rx(struct work_struct *work)
 {
+       struct sk_buff_head cmsg_joined;
        struct nfp_flower_priv *priv;
        struct sk_buff *skb;
 
        priv = container_of(work, struct nfp_flower_priv, cmsg_work);
+       skb_queue_head_init(&cmsg_joined);
 
-       while ((skb = skb_dequeue(&priv->cmsg_skbs)))
+       spin_lock_bh(&priv->cmsg_skbs_high.lock);
+       skb_queue_splice_tail_init(&priv->cmsg_skbs_high, &cmsg_joined);
+       spin_unlock_bh(&priv->cmsg_skbs_high.lock);
+
+       spin_lock_bh(&priv->cmsg_skbs_low.lock);
+       skb_queue_splice_tail_init(&priv->cmsg_skbs_low, &cmsg_joined);
+       spin_unlock_bh(&priv->cmsg_skbs_low.lock);
+
+       while ((skb = __skb_dequeue(&cmsg_joined)))
                nfp_flower_cmsg_process_one_rx(priv->app, skb);
 }
 
-void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb)
+static void
+nfp_flower_queue_ctl_msg(struct nfp_app *app, struct sk_buff *skb, int type)
 {
        struct nfp_flower_priv *priv = app->priv;
+       struct sk_buff_head *skb_head;
+
+       if (type == NFP_FLOWER_CMSG_TYPE_PORT_REIFY ||
+           type == NFP_FLOWER_CMSG_TYPE_PORT_MOD)
+               skb_head = &priv->cmsg_skbs_high;
+       else
+               skb_head = &priv->cmsg_skbs_low;
+
+       if (skb_queue_len(skb_head) >= NFP_FLOWER_WORKQ_MAX_SKBS) {
+               nfp_flower_cmsg_warn(app, "Dropping queued control messages\n");
+               dev_kfree_skb_any(skb);
+               return;
+       }
+
+       skb_queue_tail(skb_head, skb);
+       schedule_work(&priv->cmsg_work);
+}
+
+void nfp_flower_cmsg_rx(struct nfp_app *app, struct sk_buff *skb)
+{
        struct nfp_flower_cmsg_hdr *cmsg_hdr;
 
        cmsg_hdr = nfp_flower_cmsg_get_hdr(skb);
                /* Acks from the NFP that the route is added - ignore. */
                dev_consume_skb_any(skb);
        } else {
-               skb_queue_tail(&priv->cmsg_skbs, skb);
-               schedule_work(&priv->cmsg_work);
+               nfp_flower_queue_ctl_msg(app, skb, cmsg_hdr->type);
        }
 }
 
 
        app->priv = app_priv;
        app_priv->app = app;
-       skb_queue_head_init(&app_priv->cmsg_skbs);
+       skb_queue_head_init(&app_priv->cmsg_skbs_high);
+       skb_queue_head_init(&app_priv->cmsg_skbs_low);
        INIT_WORK(&app_priv->cmsg_work, nfp_flower_cmsg_process_rx);
        init_waitqueue_head(&app_priv->reify_wait_queue);
 
 {
        struct nfp_flower_priv *app_priv = app->priv;
 
-       skb_queue_purge(&app_priv->cmsg_skbs);
+       skb_queue_purge(&app_priv->cmsg_skbs_high);
+       skb_queue_purge(&app_priv->cmsg_skbs_low);
        flush_work(&app_priv->cmsg_work);
 
        nfp_flower_metadata_cleanup(app);
 
  * @mask_table:                Hash table used to store masks
  * @flow_table:                Hash table used to store flower rules
  * @cmsg_work:         Workqueue for control messages processing
- * @cmsg_skbs:         List of skbs for control message processing
+ * @cmsg_skbs_high:    List of higher priority skbs for control message
+ *                     processing
+ * @cmsg_skbs_low:     List of lower priority skbs for control message
+ *                     processing
  * @nfp_mac_off_list:  List of MAC addresses to offload
  * @nfp_mac_index_list:        List of unique 8-bit indexes for non NFP netdevs
  * @nfp_ipv4_off_list: List of IPv4 addresses to offload
        DECLARE_HASHTABLE(mask_table, NFP_FLOWER_MASK_HASH_BITS);
        DECLARE_HASHTABLE(flow_table, NFP_FLOWER_HASH_BITS);
        struct work_struct cmsg_work;
-       struct sk_buff_head cmsg_skbs;
+       struct sk_buff_head cmsg_skbs_high;
+       struct sk_buff_head cmsg_skbs_low;
        struct list_head nfp_mac_off_list;
        struct list_head nfp_mac_index_list;
        struct list_head nfp_ipv4_off_list;