diff options
author | Tibor Frank <tifrank@cisco.com> | 2016-06-16 09:05:45 +0200 |
---|---|---|
committer | Jan Gelety <jgelety@cisco.com> | 2016-06-23 12:53:58 +0000 |
commit | 95253bdf705a06ec01c2a04f437bae2ef23355c3 (patch) | |
tree | 0c8ac3978d87b29dd705fe817d38ebf7346223b5 | |
parent | 33e58e512b91d57f0ccab05d6e57de11d7c9fd37 (diff) |
Add tests for Honeycomb L2 FIB support
JIRA: CSIT-168
- add tests for Honeycomb L2 FIB support
- add keywords for Honeycomb L2 FIB support
- fix typos
Change-Id: I81292c10e26e7ad05725034c1db1db0a81d29283
Signed-off-by: Tibor Frank <tifrank@cisco.com>
-rw-r--r-- | resources/libraries/python/L2Util.py | 75 | ||||
-rw-r--r-- | resources/libraries/python/honeycomb/HcAPIKwBridgeDomain.py | 152 | ||||
-rw-r--r-- | resources/libraries/python/honeycomb/HcAPIKwInterfaces.py | 23 | ||||
-rw-r--r-- | resources/libraries/robot/honeycomb/bridge_domain.robot | 135 | ||||
-rw-r--r-- | resources/libraries/robot/honeycomb/l2_fib.robot | 187 | ||||
-rw-r--r-- | resources/templates/vat/l2_bridge_domain_delete.vat | 1 | ||||
-rw-r--r-- | resources/templates/vat/l2_fib_entry_delete.vat | 1 | ||||
-rw-r--r-- | resources/templates/vat/l2_fib_table_dump.vat | 1 | ||||
-rw-r--r-- | tests/suites/honeycomb/3 - bridge_domain.robot | 2 | ||||
-rw-r--r-- | tests/suites/honeycomb/6 - sub_interface.robot | 4 | ||||
-rw-r--r-- | tests/suites/honeycomb/9 - l2_fib.robot | 229 | ||||
-rw-r--r-- | tests/suites/honeycomb/resources/l2_fib.py | 142 |
12 files changed, 922 insertions, 30 deletions
diff --git a/resources/libraries/python/L2Util.py b/resources/libraries/python/L2Util.py index e44a6b360a..db550f0640 100644 --- a/resources/libraries/python/L2Util.py +++ b/resources/libraries/python/L2Util.py @@ -307,3 +307,78 @@ class L2Util(object): tag_rewrite_method= tag_rewrite_method, tag1_optional=tag1_id) + + @staticmethod + def delete_bridge_domain_vat(node, bd_id): + """Delete the specified bridge domain from the node. + + :param node: VPP node to delete a bridge domain from. + :param bd_id: Bridge domain ID. + :type node: dict + :type bd_id: int + """ + + with VatTerminal(node) as vat: + vat.vat_terminal_exec_cmd_from_template( + "l2_bridge_domain_delete.vat", bd_id=bd_id) + + @staticmethod + def delete_l2_fib_entry(node, bd_id, mac): + """Delete the specified L2 FIB entry. + + :param node: VPP node. + :param bd_id: Bridge domain ID. + :param mac: MAC address used as the key in L2 FIB entry. + :type node: dict + :type bd_id: int + :type mac: str + """ + + with VatTerminal(node) as vat: + vat.vat_terminal_exec_cmd_from_template("l2_fib_entry_delete.vat", + mac=mac, + bd_id=bd_id) + + @staticmethod + def get_l2_fib_table_vat(node, bd_index): + """Retrieves the L2 FIB table using VAT. + + :param node: VPP node. + :param bd_index: Index of the bridge domain. + :type node: dict + :type bd_index: int + :return: L2 FIB table. + :rtype: list + """ + + bd_data = L2Util.vpp_get_bridge_domain_data(node) + bd_id = bd_data[bd_index-1]["bd_id"] + + try: + with VatTerminal(node) as vat: + table = vat.vat_terminal_exec_cmd_from_template( + "l2_fib_table_dump.vat", bd_id=bd_id) + + return table[0] + except ValueError: + return [] + + @staticmethod + def get_l2_fib_entry_vat(node, bd_index, mac): + """Retrieves the L2 FIB entry specified by MAC address using VAT. + + :param node: VPP node. + :param bd_index: Index of the bridge domain. + :param mac: MAC address used as the key in L2 FIB data structure. + :type node: dict + :type bd_index: int + :type mac: str + :return: L2 FIB entry + :rtype: dict + """ + + table = L2Util.get_l2_fib_table_vat(node, bd_index) + for entry in table: + if entry["mac"] == mac: + return entry + return {} diff --git a/resources/libraries/python/honeycomb/HcAPIKwBridgeDomain.py b/resources/libraries/python/honeycomb/HcAPIKwBridgeDomain.py index 0906d5c762..e3fd6fb4fc 100644 --- a/resources/libraries/python/honeycomb/HcAPIKwBridgeDomain.py +++ b/resources/libraries/python/honeycomb/HcAPIKwBridgeDomain.py @@ -99,6 +99,7 @@ class BridgeDomainKeywords(object): new_data = HcUtil.set_item_value(resp, path, new_value) else: new_data = HcUtil.remove_item(resp, path) + return BridgeDomainKeywords._configure_bd(node, bd_name, new_data) @staticmethod @@ -328,3 +329,154 @@ class BridgeDomainKeywords(object): path = ("bridge-domains", ("bridge-domain", "name", bd_name), param) return BridgeDomainKeywords.\ _set_bd_properties(node, bd_name, path, value) + + @staticmethod + def add_l2_fib_entry(node, bd_name, l2_fib_entry): + """Add an L2 FIB entry to the bridge domain's list of L2 FIB entries. + + :param node: Honeycomb node. + :param bd_name: Bridge domain's name. + :param l2_fib_entry: L2 FIB entry to be added to the L2 FIB table. + :type node: dict + :type bd_name: str + :type l2_fib_entry: dict + :return: Content of response. + :rtype: bytearray + """ + + path = ("bridge-domains", + ("bridge-domain", "name", bd_name), + "l2-fib-table", + "l2-fib-entry") + + new_l2_fib_entry = [l2_fib_entry, ] + return BridgeDomainKeywords._set_bd_properties( + node, bd_name, path, new_l2_fib_entry) + + @staticmethod + def modify_l2_fib_entry(node, bd_name, mac, param, value): + """Modify an existing L2 FIB entry in the bridge domain's L2 FIB table. + The L2 FIB entry is specified by MAC address. + + :param node: Honeycomb node. + :param bd_name: Bridge domain's name. + :param mac: MAC address used as the key in L2 FIB data structure. + :param param: The parameter to be modified. + :param value: The new value of the parameter. + :type node: dict + :type bd_name: str + :type mac: str + :type param: str + :type value: str or int + :return: Content of response. + :rtype: bytearray + """ + + path = ("bridge-domains", + ("bridge-domain", "name", bd_name), + "l2-fib-table", + ("l2-fib-entry", "phys-address", mac), + param) + + return BridgeDomainKeywords._set_bd_properties( + node, bd_name, path, value) + + @staticmethod + def remove_l2_fib_entry(node, bd_name, mac): + """Remove an L2 FIB entry from bridge domain's L2 FIB table. The + entry is specified by MAC address. + + :param node: Honeycomb node. + :param bd_name: Bridge domain's name. + :param mac: MAC address used as the key in L2 FIB data structure. + :type node: dict + :type bd_name: str + :type mac: str + :return: Content of response. + :rtype: bytearray + :raises HoneycombError: If it is not possible to remove the specified + entry. + """ + + path = ("bridge-domains", + ("bridge-domain", "name", bd_name), + "l2-fib-table", + ("l2-fib-entry", "phys-address", str(mac))) + + status_code, resp = HcUtil.\ + get_honeycomb_data(node, "config_bridge_domain") + if status_code != HTTPCodes.OK: + raise HoneycombError("Not possible to get configuration information" + " about the L2 FIB entry {0} from bridge " + "domain {1}. Status code: {2}.". + format(mac, bd_name, status_code)) + + new_data = HcUtil.remove_item(resp, path) + status_code, resp = HcUtil.\ + put_honeycomb_data(node, "config_bridge_domain", new_data) + if status_code != HTTPCodes.OK: + raise HoneycombError("Not possible to remove L2 FIB entry {0} from " + "bridge domain {1}. Status code: {2}.". + format(mac, bd_name, status_code)) + return resp + + + @staticmethod + def remove_all_l2_fib_entries(node, bd_name): + """Remove all entries from the bridge domain's L2 FIB table. + + :param node: Honeycomb node. + :param bd_name: Bridge domain's name. + :type node: dict + :type bd_name: str + :return: Content of response. + :rtype: bytearray + """ + + path = ("bridge-domains", + ("bridge-domain", "name", bd_name), + "l2-fib-table") + + return BridgeDomainKeywords._set_bd_properties( + node, bd_name, path, None) + + @staticmethod + def get_all_l2_fib_entries(node, bd_name): + """Retrieves all entries from the bridge domain's L2 FIB table. + + :param node: Honeycomb node. + :param bd_name: Bridge domain's name. + :type node: dict + :type bd_name: str + :return: Bridge domain's L2 FIB table or empty list if the table does + not exist or it is empty. + :rtype: list + """ + + bd_data = BridgeDomainKeywords.get_bd_oper_data(node, bd_name) + try: + return bd_data["l2-fib-table"]["l2-fib-entry"] + except KeyError: + return [] + + @staticmethod + def get_l2_fib_entry(node, bd_name, mac): + """Retrieves an entry from bridge domain's L2 FIB table. The entry is + specified by MAC address. + + :param node: Honeycomb node. + :param bd_name: Bridge domain's name. + :param mac: MAC address used as the key in L2 FIB data structure. + :type node: dict + :type bd_name: str + :type mac: str + :return: The requested entry from bridge domain's L2 FIB table or empty + dictionary if it does not exist in the L2 FIB table. + :rtype: dict + """ + + l2_fib = BridgeDomainKeywords.get_all_l2_fib_entries(node, bd_name) + for entry in l2_fib: + if entry["phys-address"] == mac: + return entry + return {} diff --git a/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py b/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py index e2be81e877..afd6076c7b 100644 --- a/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py +++ b/resources/libraries/python/honeycomb/HcAPIKwInterfaces.py @@ -301,6 +301,29 @@ class InterfaceKeywords(object): node, interface, path, v3po_l2) @staticmethod + def get_bd_oper_data_from_interface(node, interface): + """Returns operational data about bridge domain settings in the + interface. + + :param node: Honeycomb node. + :param interface: The name of interface. + :type interface: str + :type param: str + :return: Operational data about bridge domain settings in the + interface. + :rtype: dict + """ + + if_data = InterfaceKeywords.get_interface_oper_data(node, interface) + + if if_data: + try: + return if_data["v3po:l2"] + except KeyError: + return {} + return {} + + @staticmethod def configure_interface_base(node, interface, param, value): """Configure the base parameters of interface. diff --git a/resources/libraries/robot/honeycomb/bridge_domain.robot b/resources/libraries/robot/honeycomb/bridge_domain.robot index 29510bdd7a..4c455ff50d 100644 --- a/resources/libraries/robot/honeycomb/bridge_domain.robot +++ b/resources/libraries/robot/honeycomb/bridge_domain.robot @@ -16,6 +16,8 @@ | Library | resources.libraries.python.honeycomb.HcAPIKwBridgeDomain.BridgeDomainKeywords | Library | resources.libraries.python.honeycomb.HcAPIKwInterfaces.InterfaceKeywords | ... | WITH NAME | InterfaceAPI +| Library | resources.libraries.python.InterfaceUtil +| ... | WITH NAME | interfaceCLI *** Keywords *** | Honeycomb creates first L2 bridge domain @@ -23,9 +25,9 @@ | | ... | VPP node. Any other bridge domains will be removed in the process. | | ... | | ... | *Arguments:* -| | ... | - node - information about a DUT node. Type: dictionary -| | ... | - bd_name - name of the created bridge domain. Type: string -| | ... | - settings - settings for the created bridge domain. Type: dictionary +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - bd_name - Name of the created bridge domain. Type: string +| | ... | - settings - Settings for the created bridge domain. Type: dictionary | | ... | | ... | *Example:* | | ... @@ -39,9 +41,9 @@ | | ... | VPP node. | | ... | | ... | *Arguments:* -| | ... | - node - information about a DUT node. Type: dictionary -| | ... | - bd_name - name of the created bridge domain. Type: string -| | ... | - settings - settings for the created bridge domain. Type: dictionary +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - bd_name - Name of the created bridge domain. Type: string +| | ... | - settings - Settings for the created bridge domain. Type: dictionary | | ... | | ... | *Example:* | | ... @@ -55,9 +57,9 @@ | | ... | against provided values. | | ... | | ... | *Arguments:* -| | ... | - node - information about a DUT node. Type: dictionary -| | ... | - bd_name - name of the bridge domain. Type: string -| | ... | - settings - expected settings for the bridge domain. Type: dictionary +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - bd_name - Name of the bridge domain. Type: string +| | ... | - settings - Expected settings for the bridge domain. Type: dictionary | | ... | | ... | *Example:* | | ... @@ -73,9 +75,9 @@ | | ... | against provided values. | | ... | | ... | *Arguments:* -| | ... | - node - information about a DUT node. Type: dictionary -| | ... | - bd_name - name of the bridge domain. Type: string -| | ... | - settings - expected settings for the bridge domain. Type: dictionary +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - bd_name - Name of the bridge domain. Type: string +| | ... | - settings - Expected settings for the bridge domain. Type: dictionary | | ... | | ... | *Example:* | | ... @@ -93,11 +95,11 @@ | | ... | domain. | | ... | | ... | *Arguments:* -| | ... | - node - information about a DUT node. Type: dictionary -| | ... | - interface1, interface2 - names of interfaces to assign to bridge\ +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - interface1, interface2 - Names of interfaces to assign to bridge\ | | ... | domain. Type: string -| | ... | - bd_name - name of the bridge domain. Type: string -| | ... | - settings - bridge domain specific interface settings.\ +| | ... | - bd_name - Name of the bridge domain. Type: string +| | ... | - settings - Bridge domain specific interface settings.\ | | ... | Type: dictionary | | ... | | ... | *Example:* @@ -117,11 +119,11 @@ | | ... | bridge domain. | | ... | | ... | *Arguments:* -| | ... | - node - information about a DUT node. Type: dictionary -| | ... | - interface1, interface2 - names of interfaces to assign to bridge\ +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - interface1, interface2 - Names of interfaces to assign to bridge\ | | ... | domain. Type: string -| | ... | - bd_name - name of the bridge domain. Type: string -| | ... | - settings - bridge domain specific interface settings.\ +| | ... | - bd_name - Name of the bridge domain. Type: string +| | ... | - settings - Bridge domain specific interface settings.\ | | ... | Type: dictionary | | ... | | ... | *Example:* @@ -149,12 +151,12 @@ | | ... | bridge domain. | | ... | | ... | *Arguments:* -| | ... | - node - information about a DUT node. Type: dictionary -| | ... | - index - index of bridge domains on VPP node. Starts from 0,\ +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - index - Index of bridge domains on VPP node. Starts from 0,\ | | ... | new BDs reuse numbers after a bridge domain is removed. Type: int -| | ... | - interface1, interface2 - names of interfaces to assign to bridge\ +| | ... | - interface1, interface2 - Names of interfaces to assign to bridge\ | | ... | domain. Type: string -| | ... | - settings - bridge domain specific interface settings.\ +| | ... | - settings - Bridge domain specific interface settings.\ | | ... | Type: dictionary | | ... | | ... | *Example:* @@ -179,7 +181,7 @@ | | ... | VPP node. | | ... | | ... | *Arguments:* -| | ... | - node - information about a DUT node. Type: dictionary +| | ... | - node - Information about a DUT node. Type: dictionary | | ... | | ... | *Example:* | | ... @@ -192,7 +194,7 @@ | | ... | bridge domains. | | ... | | ... | *Arguments:* -| | ... | - node - information about a DUT node. Type: dictionary +| | ... | - node - Information about a DUT node. Type: dictionary | | ... | | ... | *Example:* | | ... @@ -205,7 +207,7 @@ | | [Documentation] | Uses VAT to verify the removal of all bridge domains. | | ... | | ... | *Arguments:* -| | ... | - node - information about a DUT node. Type: dictionary +| | ... | - node - Information about a DUT node. Type: dictionary | | ... | | ... | *Example:* | | ... @@ -213,3 +215,82 @@ | | [Arguments] | ${node} | | Run Keyword And Expect Error | ValueError: No JSON object could be decoded | | ... | VPP get bridge domain data | ${node} + +| Honeycomb adds interface to bridge domain +| | [Documentation] | Uses Honeycomb API to assign interface to a bridge\ +| | ... | domain. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - interface - Name of interface to assign to bridge domain.\ +| | ... | Type: string +| | ... | - bd_name - Name of the bridge domain. Type: string +| | ... | - settings - Bridge domain specific interface settings.\ +| | ... | Type: dictionary +| | ... +| | ... | *Example:* +| | ... +| | ... | \| Honeycomb adds interfaces to bridge domain \| ${nodes['DUT1']} \ +| | ... | \| GigabitEthernet0/8/0 \| bd-04 \ +| | ... | \| ${{split_horizon_group:2, bvi:False}} \| +| | ... +| | [Arguments] | ${node} | ${interface} | ${bd_name} | ${settings} +| | ... +| | interfaceAPI.Add bridge domain to interface +| | ... | ${node} | ${interface} | ${settings['bridge-domain']} +| | ... | ${settings['split-horizon-group']} +| | ... | ${settings['bridged-virtual-interface']} + +| Bridge domain configuration in interface operational data should be empty +| | [Documentation] | Get interface operational data and retrieve bridge +| | ... | domain configuration from it. It should be empty. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - interface - Name of interface where the bridge domain parameters \ +| | ... | will be checked.Type: string +| | ... +| | ... | *Example:* +| | ... | \| Bridge domain configuration in interface operational data should \ +| | ... | be empty \| ${nodes['DUT1']} \| GigabitEthernet0/8/0 \| +| | ... +| | [Arguments] | ${node} | ${interface} +| | ... +| | ${if_data}= | interfaceAPI.Get BD Oper Data From Interface +| | ... | ${node} | ${interface} +| | Should be empty | ${if_data} + +| Bridge domain configuration in interface operational data should be +| | [Documentation] | Get interface operational data and retrieve bridge +| | ... | domain configuration from it. Compare the data to the expected one. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - interface - Name of interface where the bridge domain parameters \ +| | ... | will be checked. Type: string +| | ... | - bd_settings - The referential bridge domain data. Type: dictionary +| | ... +| | ... | *Example:* +| | ... | \| Bridge domain configuration in interface operational data should \ +| | ... | be \| ${nodes['DUT1']} \| GigabitEthernet0/8/0 \| ${if_bd_settings} \| +| | ... +| | [Arguments] | ${node} | ${interface} | ${bd_settings} +| | ... +| | ${if_data}= | interfaceAPI.Get BD Oper Data From Interface +| | ... | ${node} | ${interface} +| | interfaceAPI.Compare Data Structures | ${if_data} | ${bd_settings} + +| VAT removes bridge domain +| | [Documentation] Remove the specified bridge domain using VAT. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - bd_id - Bridge domain ID. Type: integer +| | ... +| | ... | *Example:* +| | ... | \| VAT removes bridge domain \ +| | ... | \| ${nodes['DUT1']} \| 1 \| +| | ... +| | [Arguments] | ${node} | ${bd_id} +| | ... +| | Delete Bridge Domain VAT | ${node} | ${bd_id} diff --git a/resources/libraries/robot/honeycomb/l2_fib.robot b/resources/libraries/robot/honeycomb/l2_fib.robot new file mode 100644 index 0000000000..e63f299d11 --- /dev/null +++ b/resources/libraries/robot/honeycomb/l2_fib.robot @@ -0,0 +1,187 @@ +# Copyright (c) 2016 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +*** Settings *** +| Library | resources.libraries.python.L2Util +| Library | resources.libraries.python.honeycomb.HcAPIKwBridgeDomain.BridgeDomainKeywords +| Library | resources.libraries.python.honeycomb.HcAPIKwInterfaces.InterfaceKeywords +| ... | WITH NAME | InterfaceAPI + +*** Keywords *** +| Honeycomb adds L2 FIB entry to bridge domain +| | [Documentation] | Add L2 FIB entry to the specified bridge domain using \ +| | ... | Honyecomb API. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - bd_name - Name of the bridge domain. Type: string +| | ... | - l2_fib_settings - The parameters of the new L2 FIB entry. \ +| | ... | Type: dictionary +| | ... +| | ... | *Example:* +| | ... | \| Honeycomb adds L2 FIB entry to bridge domain \ +| | ... | \| ${nodes['DUT1']} \| test_bd \| ${l2_fib_forward_cfg} \| +| | ... +| | [Arguments] | ${node} | ${bd_name} | ${l2_fib_settings} +| | ... +| | Add L2 FIB Entry | ${node} | ${bd_name} | ${l2_fib_settings} + +| L2 FIB Table from Honeycomb should be empty +| | [Documentation] | Check if the L2 FIB table in the specified bridge domain \ +| | ... | is empty. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - bd_name - Name of the bridge domain. Type: string +| | ... +| | ... | *Example:* +| | ... | \| L2 FIB Table from Honeycomb should be empty \ +| | ... | \| ${nodes['DUT1']} \| test_bd \| +| | ... +| | [Arguments] | ${node} | ${bd_name} +| | ... +| | ${l2_fib_data}= | Get All L2 FIB Entries | ${node} | ${bd_name} +| | Should be empty | ${l2_fib_data} + +| L2 FIB Entry from Honeycomb should be +| | [Documentation] | Retrieves the operational data about the specified L2 \ +| | ... | FIB entry and checks if they are as expected. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - bd_name - Name of the bridge domain. Type: string +| | ... | - l2_fib_ref_data - L2 FIB entry referential data. Type: dictionay +| | ... +| | ... | *Example:* +| | ... | \| L2 FIB Entry from Honeycomb should be \ +| | ... | \| ${nodes['DUT1']} \| test_bd \| ${l2_fib_forward_oper} \| +| | ... +| | [Arguments] | ${node} | ${bd_name} | ${l2_fib_ref_data} +| | ... +| | ${l2_fib_data}= | Get L2 FIB Entry | ${node} | ${bd_name} +| | ... | ${l2_fib_ref_data['phys-address']} +| | interfaceAPI.Compare Data Structures | ${l2_fib_data} | ${l2_fib_ref_data} + +| Honeycomb removes L2 FIB entry +| | [Documentation] | Remove the specified L2 FIB entry from the bridge \ +| | ... | domain's L2 FIB table. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - bd_name - Name of the bridge domain. Type: string +| | ... | - mac - MAC address used as the key in L2 FIB data structure. \ +| | ... | Type: string +| | ... +| | ... | *Example:* +| | ... | \| Honeycomb removes L2 FIB entry \ +| | ... | \| ${nodes['DUT1']} \| test_bd \ +| | ... | \| ${l2_fib_forward_oper['phys-address']} \| +| | ... +| | [Arguments] | ${node} | ${bd_name} | ${mac} +| | ... +| | Remove L2 FIB Entry | ${node} | ${bd_name} | ${mac} + +| Honeycomb removes all L2 FIB entries +| | [Documentation] | Remove all L2 FIB enties from the bridge domain's L2 FIB \ +| | ... | table. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - bd_name - Name of the bridge domain. Type: string +| | ... +| | ... | *Example:* +| | ... | \| Honeycomb removes all L2 FIB entries \ +| | ... | \| ${nodes['DUT1']} \| test_bd \| +| | ... +| | [Arguments] | ${node} | ${bd_name} +| | ... +| | Remove all L2 FIB entries | ${node} | ${bd_name} + +| Honeycomb fails to add wrong L2 FIB entry +| | [Documentation] | Honeycomb tries to add a wrong L2 FIB entry and expects \ +| | ... | that it fails. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - bd_name - Name of the bridge domain. Type: string +| | ... | - l2_fib_settings - The wrong parameters of the new L2 FIB entry. \ +| | ... | Type: dictionary +| | ... +| | ... | *Example:* +| | ... | \| Honeycomb fails to add wrong L2 FIB entry \ +| | ... | \| ${nodes['DUT1']} \| test_bd \| ${l2_fib_wrong_cfg} \| +| | ... +| | [Arguments] | ${node} | ${bd_name} | ${l2_fib_settings} +| | ... +| | Run keyword and expect error | *HoneycombError: * was not successful. *00. +| | ... | Add L2 FIB Entry | ${node} | ${bd_name} | ${l2_fib_settings} + +| Honeycomb fails to modify L2 FIB entry +| | [Documentation] | Honeycomb tries to modify an existing L2 FIB entry and \ +| | ... | expects to fail. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - bd_name - Name of the bridge domain. Type: string +| | ... | - mac - MAC address used as the key in L2 FIB data structure. \ +| | ... | Type: string +| | ... | - param - The parameter to be modified. Type: string +| | ... | - value - The new value of the parameter. Type: string or integer +| | ... +| | ... | *Example:* +| | ... | \| Honeycomb fails to modify L2 FIB entry \ +| | ... | \| ${nodes['DUT1']} \| test_bd \ +| | ... | \| ${l2_fib_forward_oper['phys-address']} \| action \ +| | ... | \| l2-fib-forward \| +| | ... +| | [Arguments] | ${node} | ${bd_name} | ${mac} | ${param} | ${value} +| | ... +| | Run keyword and expect error | *HoneycombError: * was not successful. *00. +| | ... | Modify L2 FIB Entry +| | ... | ${node} | ${bd_name} | ${mac} | ${param} | ${value} + +| L2 FIB entry from VAT should be +| | [Documentation] | Retrieves the operational data about the specified L2 \ +| | ... | FIB entry using VAT and checks if it is as expected. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - bd_index - Index of the bridge domain. Type: integer +| | ... | - l2_fib_ref_data - L2 FIB entry referential data. Type: dictionay +| | ... +| | ... | *Example:* +| | ... | \| L2 FIB entry from VAT should be \ +| | ... | \| ${nodes['DUT1']} \| test_bd \| ${l2_fib_forward_oper} \| +| | ... +| | [Arguments] | ${node} | ${bd_index} | ${l2_fib_ref_data} +| | ... +| | ${l2_fib_data}= | Get L2 FIB entry VAT | ${node} | ${bd_index} +| | ... | ${l2_fib_ref_data['mac']} +| | interfaceAPI.Compare Data Structures | ${l2_fib_data} | ${l2_fib_ref_data} + +| L2 FIB Table from VAT should be empty +| | [Documentation] | Check if the L2 FIB table in the specified bridge domain \ +| | ... | is empty. VAT is used to get operational data. +| | ... +| | ... | *Arguments:* +| | ... | - node - Information about a DUT node. Type: dictionary +| | ... | - bd_index - Index of the bridge domain. Type: integer +| | ... +| | ... | *Example:* +| | ... | \| L2 FIB Table from VAT should be empty \ +| | ... | \| ${nodes['DUT1']} \| test_bd \| +| | ... +| | [Arguments] | ${node} | ${bd_index} +| | ... +| | ${l2_fib_data}= | Get L2 FIB table VAT | ${node} | ${bd_index} +| | Should be empty | ${l2_fib_data} diff --git a/resources/templates/vat/l2_bridge_domain_delete.vat b/resources/templates/vat/l2_bridge_domain_delete.vat new file mode 100644 index 0000000000..354f1acd52 --- /dev/null +++ b/resources/templates/vat/l2_bridge_domain_delete.vat @@ -0,0 +1 @@ +bridge_domain_add_del bd_id {bd_id} delete
\ No newline at end of file diff --git a/resources/templates/vat/l2_fib_entry_delete.vat b/resources/templates/vat/l2_fib_entry_delete.vat new file mode 100644 index 0000000000..a2fdf16aed --- /dev/null +++ b/resources/templates/vat/l2_fib_entry_delete.vat @@ -0,0 +1 @@ +l2fib_add_del mac {mac} bd_id {bd_id} delete
\ No newline at end of file diff --git a/resources/templates/vat/l2_fib_table_dump.vat b/resources/templates/vat/l2_fib_table_dump.vat new file mode 100644 index 0000000000..83db7d0691 --- /dev/null +++ b/resources/templates/vat/l2_fib_table_dump.vat @@ -0,0 +1 @@ +l2_fib_table_dump bd_id {bd_id}
\ No newline at end of file diff --git a/tests/suites/honeycomb/3 - bridge_domain.robot b/tests/suites/honeycomb/3 - bridge_domain.robot index 61a67cc901..8eea9fb359 100644 --- a/tests/suites/honeycomb/3 - bridge_domain.robot +++ b/tests/suites/honeycomb/3 - bridge_domain.robot @@ -21,7 +21,7 @@ | ${bd2_name}= | bd-02 | &{bd_settings}= | flood=${True} | forward=${True} | learn=${True} | ... | unknown-unicast-flood=${True} | arp-termination=${True} -| &{if_settings}= | split_horizon_group=${1} | bvi=${True} +| &{if_settings}= | split_horizon_group=${1} | bvi=${False} *** Settings *** | Resource | resources/libraries/robot/default.robot diff --git a/tests/suites/honeycomb/6 - sub_interface.robot b/tests/suites/honeycomb/6 - sub_interface.robot index 6938082c16..8913814320 100644 --- a/tests/suites/honeycomb/6 - sub_interface.robot +++ b/tests/suites/honeycomb/6 - sub_interface.robot @@ -327,7 +327,7 @@ | | ... | this order. | | ... | | ... | *Arguments:* -| | ... | - node - information about a DUT node. Type: dictionary +| | ... | - node - Information about a DUT node. Type: dictionary | | ... | - super_interface - Super interface. Type: string | | ... | - identifier - Sub-interface identifier. Type: integer or string | | ... @@ -347,7 +347,7 @@ | | ... | this order. | | ... | | ... | *Arguments:* -| | ... | - node - information about a DUT node. Type: dictionary +| | ... | - node - Information about a DUT node. Type: dictionary | | ... | - super_interface - Super interface. Type: string | | ... | - identifier - Sub-interface identifier. Type: integer or string | | ... diff --git a/tests/suites/honeycomb/9 - l2_fib.robot b/tests/suites/honeycomb/9 - l2_fib.robot new file mode 100644 index 0000000000..bc56f4e85c --- /dev/null +++ b/tests/suites/honeycomb/9 - l2_fib.robot @@ -0,0 +1,229 @@ +# Copyright (c) 2016 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +*** Settings *** +| Resource | resources/libraries/robot/default.robot +| Resource | resources/libraries/robot/honeycomb/interfaces.robot +| Resource | resources/libraries/robot/honeycomb/bridge_domain.robot +| Resource | resources/libraries/robot/honeycomb/l2_fib.robot +| Variables | tests/suites/honeycomb/resources/l2_fib.py +| Documentation | *Honeycomb L2 FIB management test suite.* +| Suite Setup | Run keywords +| ... | Set test interface down +| ... | AND +| ... | Honeycomb removes all bridge domains | ${node} +| Suite Teardown | Honeycomb removes all bridge domains | ${node} +| Force tags | honeycomb_sanity + +*** Variables *** +# Node and interface used in tests. +| ${node}= | ${nodes['DUT1']} +| ${interface}= | GigabitEthernet0/8/0 + +*** Test Cases *** +| Honeycomb adds L2 FIB entry (forward) +| | [Documentation] | Honeycomb creates a bridge domain and assignes an \ +| | ... | interface to it. Then adds an L2 FIB entry (forward) to the bridge \ +| | ... | domain. +| | ... +| | [Teardown] | Honeycomb removes L2 FIB entry +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_oper['phys-address']} +| | ... +| | Given Interface state from Honeycomb should be +| | ... | ${node} | ${interface} | down +| | When Honeycomb sets interface state +| | ... | ${node} | ${interface} | up +| | Then Interface state from Honeycomb should be +| | ... | ${node} | ${interface} | up +| | When Honeycomb creates first l2 bridge domain +| | ... | ${node} | ${bd_name} | ${bd_settings} +| | Then Bridge domain configuration from Honeycomb should be +| | ... | ${node} | ${bd_name} | ${bd_settings} +| | Given Bridge domain configuration in interface operational data should be empty +| | ... | ${node} | ${interface} +| | When Honeycomb adds interface to bridge domain +| | ... | ${node} | ${interface} | ${bd_name} | ${if_bd_settings} +| | Then Bridge domain configuration in interface operational data should be +| | ... | ${node} | ${interface} | ${if_bd_settings} +| | Given L2 FIB Table from Honeycomb should be empty +| | ... | ${node} | ${bd_name} +| | And L2 FIB Table from VAT should be empty +| | ... | ${node} | ${bd_index} +| | When Honeycomb adds L2 FIB entry to bridge domain +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_cfg} +| | Then L2 FIB Entry from Honeycomb should be +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_oper} +| | And L2 FIB entry from VAT should be +| | ... | ${node} | ${bd_index} | ${l2_fib_forward_vat} + +| Honeycomb adds L2 FIB entry (static, forward) +| | [Documentation] | Honeycomb adds an L2 FIB entry (static, forward) to the \ +| | ... | bridge domain. +| | ... +| | [Teardown] | Honeycomb removes L2 FIB entry +| | ... | ${node} | ${bd_name} | ${l2_fib_static_forward_oper['phys-address']} +| | ... +| | Given Bridge domain configuration in interface operational data should be +| | ... | ${node} | ${interface} | ${if_bd_settings} +| | And L2 FIB Table from Honeycomb should be empty +| | ... | ${node} | ${bd_name} +| | And L2 FIB Table from VAT should be empty +| | ... | ${node} | ${bd_index} +| | When Honeycomb adds L2 FIB entry to bridge domain +| | ... | ${node} | ${bd_name} | ${l2_fib_static_forward_cfg} +| | Then L2 FIB Entry from Honeycomb should be +| | ... | ${node} | ${bd_name} | ${l2_fib_static_forward_oper} +| | And L2 FIB entry from VAT should be +| | ... | ${node} | ${bd_index} | ${l2_fib_static_forward_vat} + +| Honeycomb adds L2 FIB entry (static, filter) +| | [Documentation] | Honeycomb adds an L2 FIB entry (static, filter) to the \ +| | ... | bridge domain. +| | ... +| | [Teardown] | Honeycomb removes L2 FIB entry +| | ... | ${node} | ${bd_name} | ${l2_fib_filter_oper['phys-address']} +| | ... +| | Given Bridge domain configuration in interface operational data should be +| | ... | ${node} | ${interface} | ${if_bd_settings} +| | And L2 FIB Table from Honeycomb should be empty +| | ... | ${node} | ${bd_name} +| | And L2 FIB Table from VAT should be empty +| | ... | ${node} | ${bd_index} +| | When Honeycomb adds L2 FIB entry to bridge domain +| | ... | ${node} | ${bd_name} | ${l2_fib_filter_cfg} +| | Then L2 FIB Entry from Honeycomb should be +| | ... | ${node} | ${bd_name} | ${l2_fib_filter_oper} +| | And L2 FIB entry from VAT should be +| | ... | ${node} | ${bd_index} | ${l2_fib_filter_vat} + +| Honeycomb adds and removes L2 FIB entry (forward) +| | [Documentation] | Honeycomb adds an L2 FIB entry (forward) to the bridge \ +| | ... | domain and then Honeycomb removes it from the bridge domain. +| | ... +| | [Teardown] | Honeycomb removes L2 FIB entry +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_oper['phys-address']} +| | ... +| | Given Bridge domain configuration in interface operational data should be +| | ... | ${node} | ${interface} | ${if_bd_settings} +| | And L2 FIB Table from Honeycomb should be empty +| | ... | ${node} | ${bd_name} +| | And L2 FIB Table from VAT should be empty +| | ... | ${node} | ${bd_index} +| | When Honeycomb adds L2 FIB entry to bridge domain +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_cfg} +| | Then L2 FIB Entry from Honeycomb should be +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_oper} +| | And L2 FIB entry from VAT should be +| | ... | ${node} | ${bd_index} | ${l2_fib_forward_vat} +| | When Honeycomb removes L2 FIB entry +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_oper['phys-address']} +| | Then L2 FIB Table from Honeycomb should be empty +| | ... | ${node} | ${bd_name} +| | And L2 FIB Table from VAT should be empty +| | ... | ${node} | ${bd_index} + +| Honeycomb adds more than one L2 FIB entry +| | [Documentation] | Honeycomb adds three L2 FIB entries to the bridge domain. +| | ... +| | [Teardown] | Honeycomb removes all L2 FIB entries +| | ... | ${node} | ${bd_name} +| | ... +| | Given Bridge domain configuration in interface operational data should be +| | ... | ${node} | ${interface} | ${if_bd_settings} +| | And L2 FIB Table from Honeycomb should be empty +| | ... | ${node} | ${bd_name} +| | And L2 FIB Table from VAT should be empty +| | ... | ${node} | ${bd_index} +| | When Honeycomb adds L2 FIB entry to bridge domain +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_cfg} +| | And Honeycomb adds L2 FIB entry to bridge domain +| | ... | ${node} | ${bd_name} | ${l2_fib_static_forward_cfg} +| | And Honeycomb adds L2 FIB entry to bridge domain +| | ... | ${node} | ${bd_name} | ${l2_fib_filter_cfg} +| | Then L2 FIB Entry from Honeycomb should be +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_oper} +| | And L2 FIB Entry from Honeycomb should be +| | ... | ${node} | ${bd_name} | ${l2_fib_static_forward_oper} +| | And L2 FIB Entry from Honeycomb should be +| | ... | ${node} | ${bd_name} | ${l2_fib_filter_oper} +| | And L2 FIB entry from VAT should be +| | ... | ${node} | ${bd_index} | ${l2_fib_forward_vat} +| | And L2 FIB entry from VAT should be +| | ... | ${node} | ${bd_index} | ${l2_fib_static_forward_vat} +| | And L2 FIB entry from VAT should be +| | ... | ${node} | ${bd_index} | ${l2_fib_filter_vat} + +| Honeycomb fails to set wrong L2 FIB entry +| | [Documentation] | Honeycomb tries to add an L2 FIB entry with wrong \ +| | ... | parameters to the bridge domain. It must fail. +| | ... +| | [Teardown] | Honeycomb removes all L2 FIB entries +| | ... | ${node} | ${bd_name} +| | ... +| | Given Bridge domain configuration in interface operational data should be +| | ... | ${node} | ${interface} | ${if_bd_settings} +| | And L2 FIB Table from Honeycomb should be empty +| | ... | ${node} | ${bd_name} +| | And L2 FIB Table from VAT should be empty +| | ... | ${node} | ${bd_index} +| | When Honeycomb fails to add wrong L2 FIB entry +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_cfg_wrong_mac} +| | Then L2 FIB Table from Honeycomb should be empty +| | ... | ${node} | ${bd_name} +| | And L2 FIB Table from VAT should be empty +| | ... | ${node} | ${bd_index} +| | When Honeycomb fails to add wrong L2 FIB entry +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_cfg_wrong_if} +| | Then L2 FIB Table from Honeycomb should be empty +| | ... | ${node} | ${bd_name} +| | And L2 FIB Table from VAT should be empty +| | ... | ${node} | ${bd_index} +| | When Honeycomb fails to add wrong L2 FIB entry +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_cfg_wrong_action} +| | Then L2 FIB Table from Honeycomb should be empty +| | ... | ${node} | ${bd_name} +| | And L2 FIB Table from VAT should be empty +| | ... | ${node} | ${bd_index} + +| Honeycomb fails to modify existing L2 FIB entry +| | [Documentation] | Honeycomb tries to modify an existing L2 FIB entry. It \ +| | ... | must fail. +| | ... +| | [Teardown] | Honeycomb removes all L2 FIB entries +| | ... | ${node} | ${bd_name} +| | ... +| | Given Bridge domain configuration in interface operational data should be +| | ... | ${node} | ${interface} | ${if_bd_settings} +| | And L2 FIB Table from Honeycomb should be empty +| | ... | ${node} | ${bd_name} +| | And L2 FIB Table from VAT should be empty +| | ... | ${node} | ${bd_index} +| | When Honeycomb adds L2 FIB entry to bridge domain +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_cfg} +| | Then L2 FIB Entry from Honeycomb should be +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_oper} +| | When Honeycomb fails to modify L2 FIB entry +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_oper['phys-address']} +| | ... | outgoing-interface +| | ... | ${l2_fib_forward_modified_cfg['outgoing-interface']} +| | Then L2 FIB Entry from Honeycomb should be +| | ... | ${node} | ${bd_name} | ${l2_fib_forward_oper} +| | And L2 FIB entry from VAT should be +| | ... | ${node} | ${bd_index} | ${l2_fib_forward_vat} + +*** Keywords *** +| Set test interface down +| | [Documentation] | Set the interface used in tests down. +| | ... +| | Honeycomb sets interface state +| | ... | ${node} | ${interface} | down diff --git a/tests/suites/honeycomb/resources/l2_fib.py b/tests/suites/honeycomb/resources/l2_fib.py new file mode 100644 index 0000000000..b06193ad1d --- /dev/null +++ b/tests/suites/honeycomb/resources/l2_fib.py @@ -0,0 +1,142 @@ +# Copyright (c) 2016 Cisco and/or its affiliates. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Test variables for Honeycomb L2 FIB test suite.""" + +# Bridge domain name. +bd_name = 'test-l2-bd' +bd_index = 1 + +# Bridge domain settings used while creating a test bridge domain. +bd_settings = { + 'flood': True, + 'forward': True, + 'learn': True, + 'unknown-unicast-flood': True, + 'arp-termination': True +} + +# Bridge domain configuration used while adding the bridge domain to an +# interface. +if_bd_settings = { + 'bridge-domain': bd_name, + 'split-horizon-group': 1, + 'bridged-virtual-interface': False +} + +# Add L2 FIB entry (forward). +# Configuration data: +l2_fib_forward_cfg = { + "phys-address": "aa:bb:cc:dd:ee:ff", + "outgoing-interface": "GigabitEthernet0/8/0", + "action": "l2-fib-forward" +} + +# Expected operational data: +l2_fib_forward_oper = { + "phys-address": "aa:bb:cc:dd:ee:ff", + "outgoing-interface": "GigabitEthernet0/8/0", + "bridged-virtual-interface": False, + "action": "v3po:l2-fib-forward", + "static-config": False +} + +# Expected VAT data: +l2_fib_forward_vat = { + "mac": int("".join(l2_fib_forward_oper["phys-address"].split(':')), 16), + "static_mac": 0, + "filter_mac": 0, + "bvi_mac": 0 + } + +# Add L2 FIB entry (static, forward). +# Configuration data: +l2_fib_static_forward_cfg = { + "phys-address": "22:22:33:44:55:66", + "outgoing-interface": "GigabitEthernet0/8/0", + "static-config": True, + "action": "l2-fib-forward" +} + +# Expected operational data: +l2_fib_static_forward_oper = { + "phys-address": "22:22:33:44:55:66", + "outgoing-interface": "GigabitEthernet0/8/0", + "bridged-virtual-interface": False, + "action": "v3po:l2-fib-forward", + "static-config": True +} + +# Expected VAT data: +l2_fib_static_forward_vat = { + "mac": int("".join(l2_fib_static_forward_oper["phys-address"]. + split(':')), 16), + "sw_if_index": 5, + "static_mac": 1, + "filter_mac": 0, + "bvi_mac": 0 +} + +# Add L2 FIB entry (filter). +# Configuration data: +l2_fib_filter_cfg = { + "phys-address": "00:01:02:03:04:05", + "outgoing-interface": "GigabitEthernet0/8/0", + "static-config": True, + "action": "l2-fib-filter" +} + +# Expected operational data: +l2_fib_filter_oper = { + "phys-address": "00:01:02:03:04:05", + "outgoing-interface": "GigabitEthernet0/8/0", + "bridged-virtual-interface": False, + "action": "v3po:l2-fib-filter", + "static-config": True +} + +# Expected VAT data: +l2_fib_filter_vat = { + "mac": int("".join(l2_fib_filter_oper["phys-address"].split(':')), 16), + "sw_if_index": 5, + "static_mac": 1, + "filter_mac": 1, + "bvi_mac": 0 +} + +# WRONG configuration data - Add L2 FIB entry. +l2_fib_forward_cfg_wrong_mac = { + "phys-address": "WRONG-MAC", + "outgoing-interface": "GigabitEthernet0/8/0", + "action": "l2-fib-forward" +} + +l2_fib_forward_cfg_wrong_if = { + "phys-address": "aa:bb:cc:dd:ee:ff", + "outgoing-interface": "WRONG-INTERFACE", + "action": "l2-fib-forward" +} + +l2_fib_forward_cfg_wrong_action = { + "phys-address": "aa:bb:cc:dd:ee:ff", + "outgoing-interface": "GigabitEthernet0/8/0", + "action": "WRONG-ACTION" +} + +# Modify L2 FIB entry (forward). +# Configuration data: +l2_fib_forward_modified_cfg = { + "phys-address": "aa:bb:cc:dd:ee:ff", + "outgoing-interface": "GigabitEthernet0/9/0", + "action": "l2-fib-forward" +} |