|
| 1 | +import pytest |
| 2 | +import time |
| 3 | +import buffer_model |
| 4 | +from dvslib.dvs_common import PollingConfig |
| 5 | + |
| 6 | +# the port to be removed and add |
| 7 | +PORT_A = "Ethernet64" |
| 8 | +PORT_B = "Ethernet68" |
| 9 | + |
| 10 | +""" |
| 11 | +DELETE_CREATE_ITERATIONS defines the number of iteration of delete and create to ports, |
| 12 | +we add different timeouts between delete/create to catch potential race condition that can lead to system crush |
| 13 | +
|
| 14 | +Add \ Remove of Buffers can be done only when the model is dynamic. |
| 15 | +""" |
| 16 | +DELETE_CREATE_ITERATIONS = 10 |
| 17 | + |
| 18 | +@pytest.yield_fixture |
| 19 | +def dynamic_buffer(dvs): |
| 20 | + buffer_model.enable_dynamic_buffer(dvs.get_config_db(), dvs.runcmd) |
| 21 | + yield |
| 22 | + buffer_model.disable_dynamic_buffer(dvs.get_config_db(), dvs.runcmd) |
| 23 | + |
| 24 | + |
| 25 | +@pytest.mark.usefixtures('dvs_port_manager') |
| 26 | +@pytest.mark.usefixtures("dynamic_buffer") |
| 27 | +class TestPortAddRemove(object): |
| 28 | + |
| 29 | + def set_mmu(self,dvs): |
| 30 | + state_db = dvs.get_state_db() |
| 31 | + # set mmu size |
| 32 | + fvs = {"mmu_size": "12766208"} |
| 33 | + state_db.create_entry("BUFFER_MAX_PARAM_TABLE", "global", fvs) |
| 34 | + |
| 35 | + |
| 36 | + def test_remove_add_remove_port_with_buffer_cfg(self, dvs, testlog): |
| 37 | + config_db = dvs.get_config_db() |
| 38 | + asic_db = dvs.get_asic_db() |
| 39 | + state_db = dvs.get_state_db() |
| 40 | + app_db = dvs.get_app_db() |
| 41 | + |
| 42 | + # set mmu size |
| 43 | + self.set_mmu(dvs) |
| 44 | + |
| 45 | + # Startup interface |
| 46 | + dvs.port_admin_set(PORT_A, 'up') |
| 47 | + |
| 48 | + # get port info |
| 49 | + port_info = config_db.get_entry("PORT", PORT_A) |
| 50 | + |
| 51 | + # get the number of ports before removal |
| 52 | + num_of_ports = len(asic_db.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT")) |
| 53 | + |
| 54 | + # remove buffer pg cfg for the port (record the buffer pgs before removing them) |
| 55 | + pgs = config_db.get_keys('BUFFER_PG') |
| 56 | + buffer_pgs = {} |
| 57 | + for key in pgs: |
| 58 | + if PORT_A in key: |
| 59 | + buffer_pgs[key] = config_db.get_entry('BUFFER_PG', key) |
| 60 | + config_db.delete_entry('BUFFER_PG', key) |
| 61 | + app_db.wait_for_deleted_entry("BUFFER_PG_TABLE", key) |
| 62 | + |
| 63 | + # modify buffer queue entry to egress_lossless_profile instead of egress_lossy_profile |
| 64 | + config_db.update_entry("BUFFER_QUEUE", "%s|0-2"%PORT_A, {"profile": "egress_lossless_profile"}) |
| 65 | + |
| 66 | + # remove buffer queue cfg for the port |
| 67 | + queues = config_db.get_keys('BUFFER_QUEUE') |
| 68 | + buffer_queues = {} |
| 69 | + for key in queues: |
| 70 | + if PORT_A in key: |
| 71 | + buffer_queues[key] = config_db.get_entry('BUFFER_QUEUE', key) |
| 72 | + config_db.delete_entry('BUFFER_QUEUE', key) |
| 73 | + app_db.wait_for_deleted_entry('BUFFER_QUEUE_TABLE', key) |
| 74 | + |
| 75 | + # Shutdown interface |
| 76 | + dvs.port_admin_set(PORT_A, 'down') |
| 77 | + |
| 78 | + # try to remove this port |
| 79 | + config_db.delete_entry('PORT', PORT_A) |
| 80 | + num = asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT", |
| 81 | + num_of_ports-1, |
| 82 | + polling_config = PollingConfig(polling_interval = 1, timeout = 5.00, strict = True)) |
| 83 | + |
| 84 | + # verify that the port was removed properly since all buffer configuration was removed also |
| 85 | + assert len(num) == num_of_ports - 1 |
| 86 | + |
| 87 | + # set back the port |
| 88 | + config_db.update_entry("PORT", PORT_A, port_info) |
| 89 | + |
| 90 | + # verify that the port has been readded |
| 91 | + num = asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT", |
| 92 | + num_of_ports, |
| 93 | + polling_config = PollingConfig(polling_interval = 1, timeout = 5.00, strict = True)) |
| 94 | + |
| 95 | + assert len(num) == num_of_ports |
| 96 | + |
| 97 | + # re-add buffer pg and queue cfg to the port |
| 98 | + for key, pg in buffer_pgs.items(): |
| 99 | + config_db.update_entry("BUFFER_PG", key, pg) |
| 100 | + |
| 101 | + for key, queue in buffer_queues.items(): |
| 102 | + config_db.update_entry("BUFFER_QUEUE", key, queue) |
| 103 | + |
| 104 | + time.sleep(5) |
| 105 | + |
| 106 | + # Remove the port with buffer configuration |
| 107 | + config_db.delete_entry('PORT', PORT_A) |
| 108 | + num = asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT", |
| 109 | + num_of_ports-1, |
| 110 | + polling_config = PollingConfig(polling_interval = 1, timeout = 5.00, strict = False)) |
| 111 | + |
| 112 | + # verify that the port wasn't removed since we still have buffer cfg |
| 113 | + assert len(num) == num_of_ports |
| 114 | + |
| 115 | + # Remove buffer pgs |
| 116 | + for key in buffer_pgs.keys(): |
| 117 | + config_db.delete_entry('BUFFER_PG', key) |
| 118 | + app_db.wait_for_deleted_entry("BUFFER_PG_TABLE", key) |
| 119 | + |
| 120 | + num = asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT", |
| 121 | + num_of_ports-1, |
| 122 | + polling_config = PollingConfig(polling_interval = 1, timeout = 5.00, strict = False)) |
| 123 | + |
| 124 | + # verify that the port wasn't removed since we still have buffer cfg |
| 125 | + assert len(num) == num_of_ports |
| 126 | + |
| 127 | + # Remove buffer queue |
| 128 | + for key in buffer_queues.keys(): |
| 129 | + config_db.delete_entry('BUFFER_QUEUE', key) |
| 130 | + app_db.wait_for_deleted_entry('BUFFER_QUEUE_TABLE', key) |
| 131 | + |
| 132 | + num = asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT", |
| 133 | + num_of_ports-1, |
| 134 | + polling_config = PollingConfig(polling_interval = 1, timeout = 5.00, strict = True)) |
| 135 | + |
| 136 | + # verify that the port wasn't removed since we still have buffer cfg |
| 137 | + assert len(num) == num_of_ports - 1 |
| 138 | + |
| 139 | + # set back the port as it is required for next test |
| 140 | + config_db.update_entry("PORT", PORT_A, port_info) |
| 141 | + |
| 142 | + |
| 143 | + |
| 144 | + @pytest.mark.parametrize("scenario", ["one_port", "all_ports"]) |
| 145 | + def test_add_remove_all_the_ports(self, dvs, testlog, scenario): |
| 146 | + config_db = dvs.get_config_db() |
| 147 | + state_db = dvs.get_state_db() |
| 148 | + asic_db = dvs.get_asic_db() |
| 149 | + app_db = dvs.get_app_db() |
| 150 | + |
| 151 | + # set mmu size |
| 152 | + self.set_mmu(dvs) |
| 153 | + |
| 154 | + # get the number of ports before removal |
| 155 | + num_of_ports = len(asic_db.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT")) |
| 156 | + |
| 157 | + # remove buffer pg cfg for the port |
| 158 | + if scenario == "all_ports": |
| 159 | + ports = config_db.get_keys('PORT') |
| 160 | + elif scenario == "one_port": |
| 161 | + ports = [PORT_A] |
| 162 | + else: |
| 163 | + assert False |
| 164 | + |
| 165 | + # delete all PGs and QUEUEs from the relevant ports |
| 166 | + pgs = config_db.get_keys('BUFFER_PG') |
| 167 | + queues = config_db.get_keys('BUFFER_QUEUE') |
| 168 | + |
| 169 | + for port in ports: |
| 170 | + for key in pgs: |
| 171 | + if port in key: |
| 172 | + config_db.delete_entry('BUFFER_PG', key) |
| 173 | + app_db.wait_for_deleted_entry('BUFFER_PG_TABLE', key) |
| 174 | + |
| 175 | + for key in queues: |
| 176 | + if port in key: |
| 177 | + config_db.delete_entry('BUFFER_QUEUE', key) |
| 178 | + app_db.wait_for_deleted_entry('BUFFER_QUEUE_TABLE', key) |
| 179 | + |
| 180 | + ports_info = {} |
| 181 | + |
| 182 | + for key in ports: |
| 183 | + # read port info and save it |
| 184 | + ports_info[key] = config_db.get_entry("PORT", key) |
| 185 | + |
| 186 | + |
| 187 | + for i in range(DELETE_CREATE_ITERATIONS): |
| 188 | + # remove ports |
| 189 | + for key in ports: |
| 190 | + config_db.delete_entry('PORT',key) |
| 191 | + app_db.wait_for_deleted_entry("PORT_TABLE", key) |
| 192 | + |
| 193 | + # verify remove port |
| 194 | + num = asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT", |
| 195 | + num_of_ports-len(ports)) |
| 196 | + |
| 197 | + assert len(num) == num_of_ports-len(ports) |
| 198 | + |
| 199 | + # add port |
| 200 | + """ |
| 201 | + DELETE_CREATE_ITERATIONS defines the number of iteration of delete and create to ports, |
| 202 | + we add different timeouts between delete/create to catch potential race condition that can lead to system crush. |
| 203 | + """ |
| 204 | + time.sleep(i%3) |
| 205 | + for key in ports: |
| 206 | + config_db.update_entry("PORT", key, ports_info[key]) |
| 207 | + app_db.wait_for_entry('PORT_TABLE',key) |
| 208 | + |
| 209 | + # verify add port |
| 210 | + num = asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT", |
| 211 | + num_of_ports) |
| 212 | + |
| 213 | + assert len(num) == num_of_ports |
| 214 | + |
| 215 | + time.sleep((i%2)+1) |
| 216 | + |
| 217 | + # run ping |
| 218 | + dvs.setup_db() |
| 219 | + |
| 220 | + dvs.create_vlan("6") |
| 221 | + dvs.create_vlan_member("6", PORT_A) |
| 222 | + dvs.create_vlan_member("6", PORT_B) |
| 223 | + |
| 224 | + port_entry_a = state_db.get_entry("PORT_TABLE",PORT_A) |
| 225 | + port_entry_b = state_db.get_entry("PORT_TABLE",PORT_B) |
| 226 | + port_admin_a = port_entry_a['admin_status'] |
| 227 | + port_admin_b = port_entry_b['admin_status'] |
| 228 | + |
| 229 | + dvs.set_interface_status("Vlan6", "up") |
| 230 | + dvs.add_ip_address("Vlan6", "6.6.6.1/24") |
| 231 | + dvs.set_interface_status(PORT_A, "up") |
| 232 | + dvs.set_interface_status(PORT_B, "up") |
| 233 | + |
| 234 | + dvs.servers[16].runcmd("ifconfig eth0 6.6.6.6/24 up") |
| 235 | + dvs.servers[16].runcmd("ip route add default via 6.6.6.1") |
| 236 | + dvs.servers[17].runcmd("ifconfig eth0 6.6.6.7/24 up") |
| 237 | + dvs.servers[17].runcmd("ip route add default via 6.6.6.1") |
| 238 | + |
| 239 | + time.sleep(2) |
| 240 | + |
| 241 | + rc = dvs.servers[16].runcmd("ping -c 1 6.6.6.7") |
| 242 | + assert rc == 0 |
| 243 | + |
| 244 | + rc = dvs.servers[17].runcmd("ping -c 1 6.6.6.6") |
| 245 | + assert rc == 0 |
| 246 | + |
| 247 | + dvs.set_interface_status(PORT_A, port_admin_a) |
| 248 | + dvs.set_interface_status(PORT_B, port_admin_b) |
| 249 | + dvs.remove_vlan_member("6", PORT_A) |
| 250 | + dvs.remove_vlan_member("6", PORT_B) |
| 251 | + dvs.remove_vlan("6") |
0 commit comments