Browse Source

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
Mitchell Jameson 5 years ago
  1. 43


@ -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):
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 ='Member of (?P<port_group>\S+)',
if port_group_info:
port_id ='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)'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
"""'Executing command on Arista EOS: %s'), commands)
# this returns array of return values for every command in
# full_command list
ret = server.execute(full_command)
# commands list
ret = server.execute(commands)'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})
raise arista_exc.AristaServicePluginRpcError(msg=msg)