From 53670e1fb201cf1d27b01b4bc796ff097f82552d Mon Sep 17 00:00:00 2001
From: Viacheslav Hletenko <v.gletenko@vyos.io>
Date: Wed, 24 Jan 2024 13:41:33 +0000
Subject: T5941: Migration policy delete orphaned interface policy

We can get orphaned interface policy when the policy name was
removed from the interface but the node `policy` still attached
to the interface

For exmaple we have orphaned node policy on interface:
```
set interfaces bonding bond0 vif 995 policy
```

This causes of incorrect migration and we do not see VLANs on
the bonding interface after update.

Delete policy from all interfaces if policy does not exist
---
 src/migration-scripts/policy/4-to-5 | 48 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/src/migration-scripts/policy/4-to-5 b/src/migration-scripts/policy/4-to-5
index f6f889c35..5b8fee17e 100755
--- a/src/migration-scripts/policy/4-to-5
+++ b/src/migration-scripts/policy/4-to-5
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 VyOS maintainers and contributors
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License version 2 or later as
@@ -37,7 +37,53 @@ base4 = ['policy', 'route']
 base6 = ['policy', 'route6']
 config = ConfigTree(config_file)
 
+
+def delete_orphaned_interface_policy(config, iftype, ifname, vif=None, vifs=None, vifc=None):
+    """Delete unexpected policy on interfaces in cases when
+       policy does not exist but inreface has a policy configuration
+       Example T5941:
+         set interfaces bonding bond0 vif 995 policy
+    """
+    if_path = ['interfaces', iftype, ifname]
+
+    if vif:
+        if_path += ['vif', vif]
+    elif vifs:
+        if_path += ['vif-s', vifs]
+        if vifc:
+            if_path += ['vif-c', vifc]
+
+    if not config.exists(if_path + ['policy']):
+        return
+
+    config.delete(if_path + ['policy'])
+
+
 if not config.exists(base4) and not config.exists(base6):
+    # Delete orphaned nodes on interfaces T5941
+    for iftype in config.list_nodes(['interfaces']):
+        for ifname in config.list_nodes(['interfaces', iftype]):
+            delete_orphaned_interface_policy(config, iftype, ifname)
+
+            if config.exists(['interfaces', iftype, ifname, 'vif']):
+                for vif in config.list_nodes(['interfaces', iftype, ifname, 'vif']):
+                    delete_orphaned_interface_policy(config, iftype, ifname, vif=vif)
+
+            if config.exists(['interfaces', iftype, ifname, 'vif-s']):
+                for vifs in config.list_nodes(['interfaces', iftype, ifname, 'vif-s']):
+                    delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs)
+
+                    if config.exists(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+                        for vifc in config.list_nodes(['interfaces', iftype, ifname, 'vif-s', vifs, 'vif-c']):
+                            delete_orphaned_interface_policy(config, iftype, ifname, vifs=vifs, vifc=vifc)
+
+    try:
+        with open(file_name, 'w') as f:
+            f.write(config.to_string())
+    except OSError as e:
+        print("Failed to save the modified config: {}".format(e))
+        exit(1)
+
     # Nothing to do
     exit(0)
 
-- 
cgit v1.2.3