From 7b3a973710b46283863be9e028685011b12da76f Mon Sep 17 00:00:00 2001 From: Mitchell Jameson Date: Fri, 27 Oct 2017 14:26:08 -0700 Subject: [PATCH] Fix support for security groups on Port-Channels When an interface is a member of a Port-Channel, we should apply ACLs to the Port-Channel rather than the interface as only the ACLs on the Port-Channel have any effect on traffic. Change-Id: I8661d4c15a7aaa2d2d1c9b15857e0a151d557e48 --- networking_arista/ml2/arista_sec_gp.py | 43 ++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/networking_arista/ml2/arista_sec_gp.py b/networking_arista/ml2/arista_sec_gp.py index 020a3adb..6aa334b8 100644 --- a/networking_arista/ml2/arista_sec_gp.py +++ b/networking_arista/ml2/arista_sec_gp.py @@ -13,6 +13,7 @@ # under the License. import json +import re from oslo_config import cfg from oslo_log import log as logging @@ -113,6 +114,25 @@ class AristaSecGroupSwitchDriver(object): LOG.exception(msg) raise arista_exc.AristaConfigError(msg=msg) + def _get_port_for_acl(self, port_id, server): + """Gets interface name for ACLs + + Finds the Port-Channel name if port_id is in a Port-Channel, otherwise + ACLs are applied to Ethernet interface. + + :param port_id: Name of port from ironic db + :param server: Server endpoint on the Arista switch to be configured + """ + all_intf_info = self._run_eos_cmds( + ['show interfaces %s' % port_id], server)[0] + intf_info = all_intf_info.get('interfaces', {}).get(port_id, {}) + member_info = intf_info.get('interfaceMembership', '') + port_group_info = re.search('Member of (?P\S+)', + member_info) + if port_group_info: + port_id = port_group_info.group('port_group') + return port_id + def _create_acl_on_eos(self, in_cmds, out_cmds, protocol, cidr, from_port, to_port, direction): """Creates an ACL on Arista HW Device. @@ -239,7 +259,7 @@ class AristaSecGroupSwitchDriver(object): :param server: Server endpoint on the Arista switch to be configured """ cmds = [] - + port_id = self._get_port_for_acl(port_id, server) for c in self.aclApplyDict[direction]: cmds.append(c.format(port_id, name)) @@ -255,6 +275,7 @@ class AristaSecGroupSwitchDriver(object): """ cmds = [] + port_id = self._get_port_for_acl(port_id, server) acl_cmd = self.aclApplyDict['rm_ingress'] if direction == 'egress': acl_cmd = self.aclApplyDict['rm_egress'] @@ -528,19 +549,29 @@ class AristaSecGroupSwitchDriver(object): command_start = ['enable', 'configure'] command_end = ['exit'] full_command = command_start + commands + command_end + return self._run_eos_cmds(full_command, server) - LOG.info(_LI('Executing command on Arista EOS: %s'), full_command) + def _run_eos_cmds(self, commands, server): + """Execute/sends a CAPI (Command API) command to EOS. + + This method is useful for running show commands that require no + prefix or postfix commands. + + :param commands : List of commands to be executed on EOS. + :param server: Server endpoint on the Arista switch to be configured + """ + LOG.info(_LI('Executing command on Arista EOS: %s'), commands) try: # this returns array of return values for every command in - # full_command list - ret = server.execute(full_command) + # commands list + ret = server.execute(commands) LOG.info(_LI('Results of execution on Arista EOS: %s'), ret) - + return ret except Exception: msg = (_('Error occurred while trying to execute ' 'commands %(cmd)s on EOS %(host)s') % - {'cmd': full_command, 'host': server}) + {'cmd': commands, 'host': server}) LOG.exception(msg) raise arista_exc.AristaServicePluginRpcError(msg=msg)