diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py
index 54f9efe3c1..144593557a 100644
--- a/src/sonic-config-engine/minigraph.py
+++ b/src/sonic-config-engine/minigraph.py
@@ -124,6 +124,7 @@ def parse_dpg(dpg, hname):
ipintfs = child.find(str(QName(ns, "IPInterfaces")))
intfs = []
+ intfnames = {}
vlan_map = {}
pc_map = {}
for ipintf in ipintfs.findall(str(QName(ns, "IPInterface"))):
@@ -177,6 +178,7 @@ def parse_dpg(dpg, hname):
if peer_addr_val is not None:
intf['peer_addr'] = ipaddress.IPAddress(peer_addr_val)
intfs.append(intf)
+ intfnames[intf['alias']] = { 'alias': intf['name'] }
pcintfs = child.find(str(QName(ns, "PortChannelInterfaces")))
pc_intfs = []
@@ -237,10 +239,27 @@ def parse_dpg(dpg, hname):
vlan_attributes.update(addrtuple)
vlan_intfs.append(copy.deepcopy(vlan_attributes))
vlans[vintfname] = vlan_attributes
+ aclintfs = child.find(str(QName(ns, "AclInterfaces")))
+ acls = {}
+ for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))):
+ aclname = aclintf.find(str(QName(ns, "InAcl"))).text
+ aclattach = aclintf.find(str(QName(ns, "AttachTo"))).text.split(';')
+ acl_intfs = []
+ for member in aclattach:
+ member = member.strip()
+ if port_alias_map.has_key(member):
+ member = port_alias_map[member]
+ if pcs.has_key(member):
+ acl_intfs.extend(pcs[member]['members']) # For ACL attaching to port channels, we break them into port channel members
+ elif vlans.has_key(member):
+ print >> sys.stderr, "Warning: ACL "+aclname+" is attached to a Vlan interface, which is currently not supported"
+ elif intfnames.has_key(member):
+ acl_intfs.append(member)
+ if acl_intfs:
+ acls[aclname] = acl_intfs
-
- return intfs, lo_intfs, mgmt_intf, vlan_intfs, pc_intfs, vlans, pcs
- return None, None, None, None, None
+ return intfs, lo_intfs, mgmt_intf, vlan_intfs, pc_intfs, intfnames, vlans, pcs, acls
+ return None, None, None, None, None, None, None, None
def parse_cpg(cpg, hname):
bgp_sessions = []
@@ -394,7 +413,7 @@ def parse_xml(filename, platform=None, port_config_file=None):
for child in root:
if child.tag == str(QName(ns, "DpgDec")):
- (intfs, lo_intfs, mgmt_intf, vlan_intfs, pc_intfs, vlans, pcs) = parse_dpg(child, hostname)
+ (intfs, lo_intfs, mgmt_intf, vlan_intfs, pc_intfs, ports, vlans, pcs, acls) = parse_dpg(child, hostname)
elif child.tag == str(QName(ns, "CpgDec")):
(bgp_sessions, bgp_asn) = parse_cpg(child, hostname)
elif child.tag == str(QName(ns, "PngDec")):
@@ -418,9 +437,11 @@ def parse_xml(filename, platform=None, port_config_file=None):
results['minigraph_vlan_interfaces'] = vlan_intfs
results['minigraph_portchannel_interfaces'] = pc_intfs
results['minigraph_vlans'] = vlans
+ results['minigraph_ports'] = ports
results['minigraph_portchannels'] = pcs
results['minigraph_mgmt_interface'] = mgmt_intf
results['minigraph_lo_interfaces'] = lo_intfs
+ results['minigraph_acls'] = acls
results['minigraph_neighbors'] = neighbors
results['minigraph_devices'] = devices
results['minigraph_underlay_neighbors'] = u_neighbors
diff --git a/src/sonic-config-engine/tests/t0-sample-graph.xml b/src/sonic-config-engine/tests/t0-sample-graph.xml
index 413aedf7e2..41e62dca29 100644
--- a/src/sonic-config-engine/tests/t0-sample-graph.xml
+++ b/src/sonic-config-engine/tests/t0-sample-graph.xml
@@ -251,7 +251,14 @@
-
+
+
+
+ PortChannel01;PortChannel02;PortChannel03;PortChannel04
+
+ DataAcl
+
+
diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py
index 894f069c1e..0d0570acf4 100644
--- a/src/sonic-config-engine/tests/test_cfggen.py
+++ b/src/sonic-config-engine/tests/test_cfggen.py
@@ -8,6 +8,7 @@ class TestCfgGen(TestCase):
self.test_dir = os.path.dirname(os.path.realpath(__file__))
self.script_file = os.path.join(self.test_dir, '..', 'sonic-cfggen')
self.sample_graph = os.path.join(self.test_dir, 'sample_graph.xml')
+ self.sample_graph_t0 = os.path.join(self.test_dir, 't0-sample-graph.xml')
def run_script(self, argument):
print '\n Running sonic-cfggen ' + argument
@@ -59,3 +60,8 @@ class TestCfgGen(TestCase):
output = self.run_script(argument)
self.assertEqual(output.strip(), 'value1\nvalue2')
+ def test_minigraph_acl(self):
+ argument = '-m "' + self.sample_graph_t0 + '" -v minigraph_acls'
+ output = self.run_script(argument)
+ self.assertEqual(output.strip(), "{'DataAcl': ['Ethernet112', 'Ethernet116', 'Ethernet120', 'Ethernet124']}")
+
diff --git a/src/sonic-config-engine/translate_acl b/src/sonic-config-engine/translate_acl
index 29b4597b9c..f706fe1f52 100755
--- a/src/sonic-config-engine/translate_acl
+++ b/src/sonic-config-engine/translate_acl
@@ -1,13 +1,14 @@
#!/usr/bin/env python
-import openconfig_acl
-import pyangbind.lib.pybindJSON as pybindJSON
-
import sys
import os.path
import json
import argparse
+import openconfig_acl
+import pyangbind.lib.pybindJSON as pybindJSON
+from minigraph import parse_xml
+
def dump_json(filename, data):
with open(filename, 'w') as outfile:
json.dump(data, outfile, indent=4, sort_keys=True, separators=(',', ':'))
@@ -97,7 +98,7 @@ def generate_rule_json(table_name, rule, max_priority):
return rule_data
def generate_table_json(aclset, aclname, port, max_priority, output_path='.'):
- table_name = aclname.replace(" ", "_")
+ table_name = aclname.replace(" ", "_").replace("-", "_")
#table_name = generate_random_table_name()
table_props = {}
@@ -119,21 +120,38 @@ def generate_table_json(aclset, aclname, port, max_priority, output_path='.'):
dump_json(os.path.join(output_path, "rules_for_"+table_name+".json"), rule_data)
-def translate_acl(filename, output_path, port, max_priority):
+def translate_acl_fixed_port(filename, output_path, port, max_priority):
yang_acl = pybindJSON.load(filename, openconfig_acl, "openconfig_acl")
for aclsetname in yang_acl.acl.acl_sets.acl_set:
- aclset = yang_acl.acl.acl_sets.acl_set[aclsetname]
- generate_table_json(aclset, aclsetname, port, max_priority, output_path)
+ aclset = yang_acl.acl.acl_sets.acl_set[aclsetname]
+ generate_table_json(aclset, aclsetname, port, max_priority, output_path)
+ return
+
+def translate_acl(filename, output_path, attach_to, max_priority):
+ yang_acl = pybindJSON.load(filename, openconfig_acl, "openconfig_acl")
+ print attach_to.keys()
+ for aclsetname in yang_acl.acl.acl_sets.acl_set:
+ tablename = aclsetname.replace(" ", "_").replace("-", "_")
+ if attach_to.has_key(tablename):
+ port = ','.join(attach_to[tablename])
+ aclset = yang_acl.acl.acl_sets.acl_set[aclsetname]
+ generate_table_json(aclset, aclsetname, port, max_priority, output_path)
return
def main():
parser = argparse.ArgumentParser(description="Translate openconfig ACL json into SONiC ACL jsons")
parser.add_argument('input', metavar='INPUT', help='input json file in openconfig format')
- parser.add_argument('-p', '--port', default='Ethernet0', help='the port(s) that this ACL is binding to')
- parser.add_argument('-m', '--max-priority', type=int, default=10000, help='the priority number of the first rule in ACL entries')
+ group = parser.add_mutually_exclusive_group(required=True)
+ group.add_argument('-p', '--port', help='the port(s) that this ACL is attached to')
+ group.add_argument('-m', '--minigraph', help='read ACL attaching information from minigraph')
+ parser.add_argument('-n', '--max-priority', type=int, default=10000, help='the priority number of the first rule in ACL entries')
parser.add_argument('-o', '--output-path', default='.', help='output directory where SONiC ACL jsons will be generated')
args = parser.parse_args()
- translate_acl(args.input, args.output_path, args.port, args.max_priority)
+ if args.port:
+ translate_acl_fixed_port(args.input, args.output_path, args.port, args.max_priority)
+ elif args.minigraph:
+ mini_data = parse_xml(args.minigraph)
+ translate_acl(args.input, args.output_path, mini_data['minigraph_acls'], args.max_priority)
if __name__ == "__main__":
main()