+static int mlxsw_sp_netdevice_ipip_vrf_event(struct mlxsw_sp *mlxsw_sp,
+ struct net_device *ol_dev)
+{
+ struct mlxsw_sp_fib_entry *decap_fib_entry;
+ struct mlxsw_sp_ipip_entry *ipip_entry;
+ struct mlxsw_sp_rif_ipip_lb *lb_rif;
+
+ ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
+ if (!ipip_entry)
+ return 0;
+
+ /* When a tunneling device is moved to a different VRF, we need to
+ * update the backing loopback. Since RIFs can't be edited, we need to
+ * destroy and recreate it. That might create a window of opportunity
+ * where RALUE and RATR registers end up referencing a RIF that's
+ * already gone. RATRs are handled by the RIF destroy, and to take care
+ * of RALUE, demote the decap route back.
+ */
+ if (ipip_entry->decap_fib_entry)
+ mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp, ipip_entry);
+
+ lb_rif = mlxsw_sp_ipip_ol_ipip_lb_create(mlxsw_sp, ipip_entry->ipipt,
+ ol_dev);
+ if (IS_ERR(lb_rif))
+ return PTR_ERR(lb_rif);
+ mlxsw_sp_rif_destroy(&ipip_entry->ol_lb->common);
+ ipip_entry->ol_lb = lb_rif;
+
+ if (ol_dev->flags & IFF_UP) {
+ decap_fib_entry = mlxsw_sp_ipip_entry_find_decap(mlxsw_sp,
+ ipip_entry);
+ if (decap_fib_entry)
+ mlxsw_sp_ipip_entry_promote_decap(mlxsw_sp, ipip_entry,
+ decap_fib_entry);
+ }
+
+ return 0;
+}
+