From bd77f9a38ae42be60651b08bd67135cd20ee9be6 Mon Sep 17 00:00:00 2001 From: Taoyu Li Date: Tue, 21 Mar 2017 21:42:07 -0700 Subject: [PATCH] [sonic-cfggen]: Read ACL interfaces information from minigrap (#419) * Enable translate_acl to read acl attaching from minigraph * Add AclInterfaces into test t0 graph * Expose minigraph_ports according --- src/sonic-config-engine/minigraph.py | 31 ++++++++++++--- .../tests/t0-sample-graph.xml | 9 ++++- src/sonic-config-engine/tests/test_cfggen.py | 6 +++ src/sonic-config-engine/translate_acl | 38 ++++++++++++++----- 4 files changed, 68 insertions(+), 16 deletions(-) diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 54f9efe3c16e..144593557aac 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 - - - return intfs, lo_intfs, mgmt_intf, vlan_intfs, pc_intfs, vlans, pcs - return None, None, None, None, None + 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, 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 413aedf7e234..41e62dca29c2 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 894f069c1ef8..0d0570acf44e 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -8,6 +8,7 @@ def setUp(self): 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 @@ def test_render_template(self): 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 29b4597b9c9c..f706fe1f52e4 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) + 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: - aclset = yang_acl.acl.acl_sets.acl_set[aclsetname] - generate_table_json(aclset, aclsetname, port, max_priority, output_path) + 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()