1 # Copyright (c) 2016 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
6 # http://www.apache.org/licenses/LICENSE-2.0
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
14 """L2 Utilities Library."""
16 from robot.api.deco import keyword
18 from resources.libraries.python.topology import Topology
19 from resources.libraries.python.VatExecutor import VatExecutor, VatTerminal
20 from resources.libraries.python.ssh import exec_cmd_no_error
24 """Utilities for l2 configuration."""
27 def vpp_add_l2fib_entry(node, mac, interface, bd_id):
28 """ Create a static L2FIB entry on a vpp node.
30 :param node: Node to add L2FIB entry on.
31 :param mac: Destination mac address.
32 :param interface: Interface name or sw_if_index.
33 :param bd_id: Bridge domain id.
36 :type interface: str or int
39 if isinstance(interface, basestring):
40 sw_if_index = Topology.get_interface_sw_index(node, interface)
42 sw_if_index = interface
43 VatExecutor.cmd_from_template(node, "add_l2_fib_entry.vat",
45 interface=sw_if_index)
48 def create_l2_bd(node, bd_id, flood=1, uu_flood=1, forward=1, learn=1,
50 """Create a l2 bridge domain on the chosen VPP node
52 Execute "bridge_domain_add_del bd_id {bd_id} flood {flood} uu-flood 1
53 forward {forward} learn {learn} arp-term {arp_term}" VAT command on
56 :param node: Node where we wish to crate the l2 bridge domain.
57 :param bd_id: Bridge domain index number.
58 :param flood: Enable flooding.
59 :param uu_flood: Enable uu_flood.
60 :param forward: Enable forwarding.
61 :param learn: Enable mac address learning to fib.
62 :param arp_term: Enable arp_termination.
71 VatExecutor.cmd_from_template(node, "l2_bd_create.vat",
72 bd_id=bd_id, flood=flood,
73 uu_flood=uu_flood, forward=forward,
74 learn=learn, arp_term=arp_term)
77 def add_interface_to_l2_bd(node, interface, bd_id, shg=0):
78 """Add a interface to the l2 bridge domain.
80 Get SW IF ID and add it to the bridge domain.
82 :param node: Node where we want to execute the command that does this.
83 :param interface: Interface name.
84 :param bd_id: Bridge domain index number to add Interface name to.
85 :param shg: Split horizon group.
91 sw_if_index = Topology.get_interface_sw_index(node, interface)
92 L2Util.add_sw_if_index_to_l2_bd(node, sw_if_index, bd_id, shg)
95 def add_sw_if_index_to_l2_bd(node, sw_if_index, bd_id, shg=0):
96 """Add interface with sw_if_index to l2 bridge domain.
98 Execute the "sw_interface_set_l2_bridge sw_if_index {sw_if_index}
99 bd_id {bd_id} shg {shg} enable" VAT command on the given node.
101 :param node: Node where we want to execute the command that does this.
102 :param sw_if_index: Interface index.
103 :param bd_id: Bridge domain index number to add SW IF ID to.
104 :param shg: Split horizon group.
106 :type sw_if_index: int
111 VatExecutor.cmd_from_template(node, "l2_bd_add_sw_if_index.vat",
112 bd_id=bd_id, sw_if_index=sw_if_index,
116 @keyword('Create dict used in bridge domain template file for node '
117 '"${node}" with links "${link_names}" and bd_id "${bd_id}"')
118 def create_bridge_domain_vat_dict(node, link_names, bd_id):
119 """Create dictionary that can be used in l2 bridge domain template.
121 The resulting dictionary looks like this:
122 'interface1': interface name of first interface
123 'interface2': interface name of second interface
124 'bd_id': bridge domain index
126 :param node: Node data dictionary.
127 :param link_names: List of names of links the bridge domain should be
129 :param bd_id: Bridge domain index number.
131 :type link_names: list
132 :return: Dictionary used to generate l2 bridge domain VAT configuration
136 bd_dict = Topology().get_interfaces_by_link_names(node, link_names)
137 bd_dict['bd_id'] = bd_id
141 def vpp_add_l2_bridge_domain(node, bd_id, port_1, port_2, learn=True):
142 """Add L2 bridge domain with 2 interfaces to the VPP node.
144 :param node: Node to add L2BD on.
145 :param bd_id: Bridge domain ID.
146 :param port_1: First interface name added to L2BD.
147 :param port_2: Second interface name added to L2BD.
148 :param learn: Enable/disable MAC learn.
155 sw_if_index1 = Topology.get_interface_sw_index(node, port_1)
156 sw_if_index2 = Topology.get_interface_sw_index(node, port_2)
157 VatExecutor.cmd_from_template(node,
158 'l2_bridge_domain.vat',
159 sw_if_id1=sw_if_index1,
160 sw_if_id2=sw_if_index2,
165 def vpp_setup_bidirectional_cross_connect(node, interface1, interface2):
166 """Create bidirectional cross-connect between 2 interfaces on vpp node.
168 :param node: Node to add bidirectional cross-connect.
169 :param interface1: First interface name or sw_if_index.
170 :param interface2: Second interface name or sw_if_index.
172 :type interface1: str or int
173 :type interface2: str or int
176 if isinstance(interface1, basestring):
177 sw_iface1 = Topology().get_interface_sw_index(node, interface1)
179 sw_iface1 = interface1
181 if isinstance(interface2, basestring):
182 sw_iface2 = Topology().get_interface_sw_index(node, interface2)
184 sw_iface2 = interface2
186 with VatTerminal(node) as vat:
187 vat.vat_terminal_exec_cmd_from_template('l2_xconnect.vat',
188 interface1=sw_iface1,
189 interface2=sw_iface2)
190 vat.vat_terminal_exec_cmd_from_template('l2_xconnect.vat',
191 interface1=sw_iface2,
192 interface2=sw_iface1)
195 def linux_add_bridge(node, br_name, if_1, if_2, set_up=True):
196 """Bridge two interfaces on linux node.
198 :param node: Node to add bridge on.
199 :param br_name: Bridge name.
200 :param if_1: First interface to be added to the bridge.
201 :param if_2: Second interface to be added to the bridge.
202 :param set_up: Change bridge interface state to up after create bridge.
203 Optional. Default: True.
210 cmd = 'brctl addbr {0}'.format(br_name)
211 exec_cmd_no_error(node, cmd, sudo=True)
212 cmd = 'brctl addif {0} {1}'.format(br_name, if_1)
213 exec_cmd_no_error(node, cmd, sudo=True)
214 cmd = 'brctl addif {0} {1}'.format(br_name, if_2)
215 exec_cmd_no_error(node, cmd, sudo=True)
217 cmd = 'ip link set dev {0} up'.format(br_name)
218 exec_cmd_no_error(node, cmd, sudo=True)
221 def linux_del_bridge(node, br_name, set_down=True):
222 """Delete bridge from linux node.
224 :param node: Node to delete bridge from.
225 :param br_name: Bridge name.
226 :param set_down: Change bridge interface state to down before delbr
227 command. Optional. Default: True.
231 ..note:: The network interface corresponding to the bridge must be
232 down before it can be deleted!
235 cmd = 'ip link set dev {0} down'.format(br_name)
236 exec_cmd_no_error(node, cmd, sudo=True)
237 cmd = 'brctl delbr {0}'.format(br_name)
238 exec_cmd_no_error(node, cmd, sudo=True)
241 def vpp_get_bridge_domain_data(node, bd_id=None):
242 """Get all bridge domain data from a VPP node. If a domain ID number is
243 provided, return only data for the matching bridge domain.
245 :param node: VPP node to get bridge domain data from.
246 :param bd_id: Numeric ID of a specific bridge domain.
249 :return: List of dictionaries containing data for each bridge domain, or
250 a single dictionary for the specified bridge domain.
253 with VatTerminal(node) as vat:
254 response = vat.vat_terminal_exec_cmd_from_template("l2_bd_dump.vat")
258 if bd_id is not None:
259 for bridge_domain in data:
260 if bridge_domain["bd_id"] == bd_id:
267 def l2_vlan_tag_rewrite(node, interface, tag_rewrite_method,
268 push_dot1q=True, tag1_id=None, tag2_id=None):
269 """Rewrite tags in ethernet frame.
271 :param node: Node to rewrite tags.
272 :param interface: Interface on which rewrite tags.
273 :param tag_rewrite_method: Method of tag rewrite.
274 :param push_dot1q: Optional parameter to disable to push dot1q tag
276 :param tag1_id: Optional tag1 ID for VLAN.
277 :param tag2_id: Optional tag2 ID for VLAN.
279 :type interface: str or int
280 :type tag_rewrite_method: str
281 :type push_dot1q: bool
285 push_dot1q = 'push_dot1q 0' if not push_dot1q else ''
287 tag1_id = 'tag1 {0}'.format(tag1_id) if tag1_id else ''
288 tag2_id = 'tag2 {0}'.format(tag2_id) if tag2_id else ''
290 if isinstance(interface, basestring):
291 iface_key = Topology.get_interface_by_name(node, interface)
292 sw_if_index = Topology.get_interface_sw_index(node, iface_key)
294 sw_if_index = interface
296 with VatTerminal(node) as vat:
297 vat.vat_terminal_exec_cmd_from_template("l2_vlan_tag_rewrite.vat",
298 sw_if_index=sw_if_index,
301 push_dot1q=push_dot1q,
302 tag1_optional=tag1_id,
303 tag2_optional=tag2_id)
306 def delete_bridge_domain_vat(node, bd_id):
307 """Delete the specified bridge domain from the node.
309 :param node: VPP node to delete a bridge domain from.
310 :param bd_id: Bridge domain ID.
315 with VatTerminal(node) as vat:
316 vat.vat_terminal_exec_cmd_from_template(
317 "l2_bridge_domain_delete.vat", bd_id=bd_id)
320 def delete_l2_fib_entry(node, bd_id, mac):
321 """Delete the specified L2 FIB entry.
323 :param node: VPP node.
324 :param bd_id: Bridge domain ID.
325 :param mac: MAC address used as the key in L2 FIB entry.
331 with VatTerminal(node) as vat:
332 vat.vat_terminal_exec_cmd_from_template("l2_fib_entry_delete.vat",
337 def get_l2_fib_table_vat(node, bd_index):
338 """Retrieves the L2 FIB table using VAT.
340 :param node: VPP node.
341 :param bd_index: Index of the bridge domain.
344 :return: L2 FIB table.
348 bd_data = L2Util.vpp_get_bridge_domain_data(node)
349 bd_id = bd_data[bd_index-1]["bd_id"]
352 with VatTerminal(node) as vat:
353 table = vat.vat_terminal_exec_cmd_from_template(
354 "l2_fib_table_dump.vat", bd_id=bd_id)
361 def get_l2_fib_entry_vat(node, bd_index, mac):
362 """Retrieves the L2 FIB entry specified by MAC address using VAT.
364 :param node: VPP node.
365 :param bd_index: Index of the bridge domain.
366 :param mac: MAC address used as the key in L2 FIB data structure.
370 :return: L2 FIB entry
374 table = L2Util.get_l2_fib_table_vat(node, bd_index)
376 if entry["mac"] == mac: