def test_inheritance(self): ast = parser.parse(""" #version 1 struct of_queue_prop { uint16_t type == ?; uint16_t len; pad(4); }; struct of_queue_prop_min_rate : of_queue_prop { uint16_t type == 1; uint16_t len; pad(4); uint16_t rate; pad(6); }; """) # Not testing the parser, just making sure the AST is what we expect expected_ast = [ ['metadata', 'version', '1'], [ 'struct', 'of_queue_prop', [], None, [['discriminator', ['scalar', 'uint16_t'], 'type'], ['data', ['scalar', 'uint16_t'], 'len'], ['pad', 4]] ], [ 'struct', 'of_queue_prop_min_rate', [], 'of_queue_prop', [['type', ['scalar', 'uint16_t'], 'type', 1], ['data', ['scalar', 'uint16_t'], 'len'], ['pad', 4], ['data', ['scalar', 'uint16_t'], 'rate'], ['pad', 6]] ], ] self.assertEquals(expected_ast, ast) ofinput = frontend.create_ofinput(ast) expected_classes = [ OFClass(name='of_queue_prop', superclass=None, members=[ OFDiscriminatorMember('type', 'uint16_t'), OFLengthMember('len', 'uint16_t'), OFPadMember(4) ], virtual=True, params={}), OFClass(name='of_queue_prop_min_rate', superclass='of_queue_prop', members=[ OFTypeMember('type', 'uint16_t', 1), OFLengthMember('len', 'uint16_t'), OFPadMember(4), OFDataMember('rate', 'uint16_t'), OFPadMember(6) ], virtual=False, params={}), ] self.assertEquals(expected_classes, ofinput.classes)
def test_empty(self): src = """\ enum foo { }; """ ast = parser.parse(src) self.assertEqual(ast, [['enum', 'foo', [], []]])
def test_empty(self): src = """\ enum foo { }; """ ast = parser.parse(src) self.assertEquals(ast, [['enum', 'foo', [], []]])
def process_input_file(filename): """ Process an input file Does not modify global state. @param filename The input filename @returns An OFInput object """ # Parse the input file try: with open(filename, 'r') as f: ast = parser.parse(f.read()) except pyparsing.ParseBaseException as e: print "Parse error in %s: %s" % (os.path.basename(filename), str(e)) sys.exit(1) # Create the OFInput from the AST try: ofinput = frontend.create_ofinput(ast) except frontend.InputError as e: print "Error in %s: %s" % (os.path.basename(filename), str(e)) sys.exit(1) return ofinput
def test_multiple_structs(self): src = """\ struct foo { }; struct bar { }; """ ast = parser.parse(src) self.assertEquals(ast.asList(), [['struct', 'foo', []], ['struct', 'bar', []]])
def test_one(self): src = """\ enum foo { BAR = 1 }; """ ast = parser.parse(src) self.assertEqual(ast, [['enum', 'foo', [], [['BAR', [], 1]]]])
def test_pad_member(self): src = """\ struct foo { pad(1); }; """ ast = parser.parse(src) self.assertEqual(ast, [['struct', 'foo', [], None, [['pad', 1]]]])
def test_one(self): src = """\ enum foo { BAR = 1 }; """ ast = parser.parse(src) self.assertEquals(ast, [['enum', 'foo', [], [['BAR', [], 1]]]])
def test_multiple_structs(self): src = """\ struct foo { }; struct bar { }; """ ast = parser.parse(src) self.assertEquals(ast, [['struct', 'foo', [], None, []], ['struct', 'bar', [], None, []]])
def test_discriminator(self): src = """\ struct foo { uint16_t foo == ?; }; """ ast = parser.parse(src) self.assertEquals(ast, [['struct', 'foo', [], None, [['discriminator', ['scalar', 'uint16_t'], 'foo']]]])
def test_inheritance(self): src = """\ struct foo : bar { uint16_t foo == 0x10; }; """ ast = parser.parse(src) self.assertEquals(ast, [['struct', 'foo', [], 'bar', [['type', ['scalar', 'uint16_t'], 'foo', 0x10]]]])
def test_type_member(self): src = """\ struct foo { uint16_t foo == 0x10; }; """ ast = parser.parse(src) self.assertEquals(ast, [['struct', 'foo', [], None, [['type', ['scalar', 'uint16_t'], 'foo', 0x10]]]])
def test_pad_member(self): src = """\ struct foo { pad(1); }; """ ast = parser.parse(src) self.assertEquals(ast, [['struct', 'foo', [], None, [['pad', 1]]]])
def test_list_type(self): src = """\ struct foo { list(of_action_t) bar; }; """ ast = parser.parse(src) self.assertEquals(ast.asList(), [['struct', 'foo', [['list(of_action_t)', 'bar']]]])
def test_array_type(self): src = """\ struct foo { uint32_t[4] bar; }; """ ast = parser.parse(src) self.assertEquals(ast.asList(), [['struct', 'foo', [['uint32_t[4]', 'bar']]]])
def test_one_field(self): src = """\ struct foo { uint32_t bar; }; """ ast = parser.parse(src) self.assertEquals(ast.asList(), [['struct', 'foo', [['uint32_t', 'bar']]]])
def test_one_field(self): src = """\ struct foo { uint32_t bar; }; """ ast = parser.parse(src) self.assertEquals(ast, [['struct', 'foo', [], None, [['data', ['scalar', 'uint32_t'], 'bar']]]])
def test_struct_align_arg(self): src = """\ struct foo(align=8) { uint32_t bar; }; """ ast = parser.parse(src) self.assertEquals(ast, [['struct', 'foo', [['align', '8']], None, [['data', ['scalar', 'uint32_t'], 'bar']]]])
def test_array_type(self): src = """\ struct foo { uint32_t[4] bar; }; """ ast = parser.parse(src) self.assertEquals(ast, [['struct', 'foo', [], None, [['data', ['array', 'uint32_t[4]'], 'bar']]]])
def test_list_type(self): src = """\ struct foo { list(of_action_t) bar; }; """ ast = parser.parse(src) self.assertEquals(ast, [['struct', 'foo', [], None, [['data', ['list', 'list(of_action_t)'], 'bar']]]])
def test_params(self): src = """\ enum foo(wire_type=uint32, bitmask=False, complete=False) { BAR = 1 }; """ ast = parser.parse(src) self.assertEquals(ast, [['enum', 'foo', [ ['wire_type', 'uint32'], ['bitmask','False'], ['complete', 'False']], [['BAR', [], 1]]]])
def test_multiple(self): src = """\ enum foo { OFP_A = 1, OFP_B = 2, OFP_C = 3 }; """ ast = parser.parse(src) self.assertEquals(ast, [['enum', 'foo', [], [['OFP_A', [], 1], ['OFP_B', [], 2], ['OFP_C', [], 3]]]])
def test_trailing_comma(self): src = """\ enum foo { OFP_A = 1, OFP_B = 2, OFP_C = 3, }; """ ast = parser.parse(src) self.assertEquals(ast, [['enum', 'foo', [], [['OFP_A', [], 1], ['OFP_B', [], 2], ['OFP_C', [], 3]]]])
def test_trailing_comma(self): src = """\ enum foo { OFP_A = 1, OFP_B = 2, OFP_C = 3, }; """ ast = parser.parse(src) self.assertEquals(ast.asList(), [['enum', 'foo', [['OFP_A', 1], ['OFP_B', 2], ['OFP_C', 3]]]])
def test_discriminator(self): src = """\ struct foo { uint16_t foo == ?; }; """ ast = parser.parse(src) self.assertEqual(ast, [[ 'struct', 'foo', [], None, [['discriminator', ['scalar', 'uint16_t'], 'foo']] ]])
def test_type_member(self): src = """\ struct foo { uint16_t foo == 0x10; }; """ ast = parser.parse(src) self.assertEqual(ast, [[ 'struct', 'foo', [], None, [['type', ['scalar', 'uint16_t'], 'foo', 0x10]] ]])
def test_inheritance(self): src = """\ struct foo : bar { uint16_t foo == 0x10; }; """ ast = parser.parse(src) self.assertEqual(ast, [[ 'struct', 'foo', [], 'bar', [['type', ['scalar', 'uint16_t'], 'foo', 0x10]] ]])
def test_array_type(self): src = """\ struct foo { uint32_t[4] bar; }; """ ast = parser.parse(src) self.assertEqual(ast, [[ 'struct', 'foo', [], None, [['data', ['array', 'uint32_t[4]'], 'bar']] ]])
def test_list_type(self): src = """\ struct foo { list(of_action_t) bar; }; """ ast = parser.parse(src) self.assertEqual(ast, [[ 'struct', 'foo', [], None, [['data', ['list', 'list(of_action_t)'], 'bar']] ]])
def test_one_field(self): src = """\ struct foo { uint32_t bar; }; """ ast = parser.parse(src) self.assertEqual(ast, [[ 'struct', 'foo', [], None, [['data', ['scalar', 'uint32_t'], 'bar']] ]])
def test_struct_align_arg(self): src = """\ struct foo(align=8) { uint32_t bar; }; """ ast = parser.parse(src) self.assertEqual(ast, [[ 'struct', 'foo', [['align', '8']], None, [['data', ['scalar', 'uint32_t'], 'bar']] ]])
def test_field_length(self): src = """\ struct foo { uint16_t list_len == length(list); list(of_uint32_t) list; }; """ ast = parser.parse(src) self.assertEquals(ast, [['struct', 'foo', [], None, [ ['field_length', ['scalar', 'uint16_t'], 'list_len', 'list'], ['data', ['list', 'list(of_uint32_t)'], 'list']]]])
def test_params(self): src = """\ enum foo(wire_type=uint32, bitmask=False, complete=False) { BAR = 1 }; """ ast = parser.parse(src) self.assertEqual(ast, [[ 'enum', 'foo', [['wire_type', 'uint32'], ['bitmask', 'False'], ['complete', 'False']], [['BAR', [], 1]] ]])
def test_mixed(self): src = """\ #version 1 struct foo { }; #version 2 struct bar { }; """ ast = parser.parse(src) self.assertEqual( ast, [['metadata', 'version', '1'], ['struct', 'foo', [], None, []], ['metadata', 'version', '2'], ['struct', 'bar', [], None, []]])
def process_input_file(filename): """ Process an input file @param filename The input filename @returns (wire_version, classes), where wire_version is the integer wire protocol number and classes is the dict of all classes processed from the file. """ # Parse the input file try: ast = parser.parse(open(filename, 'r').read()) except pyparsing.ParseBaseException as e: print "Parse error in %s: %s" % (os.path.basename(filename), str(e)) sys.exit(1) ofinput = of_g.OFInput() # Now for each structure, generate lists for each member for s in ast: if s[0] == 'struct': name = s[1].replace("ofp_", "of_", 1) members = [dict(m_type=x[0], name=x[1]) for x in s[2]] ofinput.classes[name] = members ofinput.ordered_classes.append(name) if name in type_maps.inheritance_map: # Clone class into header class and add to list ofinput.classes[name + "_header"] = members[:] ofinput.ordered_classes.append(name + "_header") if s[0] == 'enum': name = s[1] members = s[2] ofinput.enums[name] = [(x[0], x[1]) for x in members] elif s[0] == 'metadata': if s[1] == 'version': log("Found version: wire version " + s[2]) if s[2] == 'any': ofinput.wire_versions.update(of_g.wire_ver_map.keys()) elif int(s[2]) in of_g.supported_wire_protos: ofinput.wire_versions.add(int(s[2])) else: debug("Unrecognized wire protocol version") sys.exit(1) found_wire_version = True if not ofinput.wire_versions: debug("Missing #version metadata") sys.exit(1) return ofinput
def test_field_length(self): src = """\ struct foo { uint16_t list_len == length(list); list(of_uint32_t) list; }; """ ast = parser.parse(src) self.assertEqual(ast, [[ 'struct', 'foo', [], None, [['field_length', ['scalar', 'uint16_t'], 'list_len', 'list'], ['data', ['list', 'list(of_uint32_t)'], 'list']] ]])
def test_comments(self): src = """\ // comment 1 struct foo { //comment 2 // comment 3 uint32_t a; //comment 5 // comment 6 }; // comment 4 """ ast = parser.parse(src) self.assertEquals(ast.asList(), [['struct', 'foo', [['uint32_t', 'a']]]])
def test_comments(self): src = """\ // comment 1 struct foo { //comment 2 // comment 3 uint32_t a; //comment 5 // comment 6 }; // comment 4 """ ast = parser.parse(src) self.assertEquals(ast, [['struct', 'foo', [], None, [['data', ['scalar', 'uint32_t'], 'a']]]])
def test_mixed(self): src = """\ #version 1 struct foo { }; #version 2 struct bar { }; """ ast = parser.parse(src) self.assertEquals(ast, [['metadata', 'version', '1'], ['struct', 'foo', [], None, []], ['metadata', 'version', '2'], ['struct', 'bar', [], None, []]])
def test_multiple(self): src = """\ enum foo { OFP_A = 1, OFP_B = 2, OFP_C = 3 }; """ ast = parser.parse(src) self.assertEqual(ast, [[ 'enum', 'foo', [], [['OFP_A', [], 1], ['OFP_B', [], 2], ['OFP_C', [], 3]] ]])
def test_inheritance(self): ast = parser.parse(""" #version 1 struct of_queue_prop { uint16_t type == ?; uint16_t len; pad(4); }; struct of_queue_prop_min_rate : of_queue_prop { uint16_t type == 1; uint16_t len; pad(4); uint16_t rate; pad(6); }; """) # Not testing the parser, just making sure the AST is what we expect expected_ast = [ ['metadata', 'version', '1'], ['struct', 'of_queue_prop', [], None, [ ['discriminator', ['scalar', 'uint16_t'], 'type'], ['data', ['scalar', 'uint16_t'], 'len'], ['pad', 4]]], ['struct', 'of_queue_prop_min_rate', [], 'of_queue_prop', [ ['type', ['scalar', 'uint16_t'], 'type', 1], ['data', ['scalar', 'uint16_t'], 'len'], ['pad', 4], ['data', ['scalar', 'uint16_t'], 'rate'], ['pad', 6]]], ] self.assertEquals(expected_ast, ast) ofinput = frontend.create_ofinput(ast) expected_classes = [ OFClass(name='of_queue_prop', superclass=None, members=[ OFDiscriminatorMember('type', 'uint16_t'), OFLengthMember('len', 'uint16_t'), OFPadMember(4)], virtual=True, params={}), OFClass(name='of_queue_prop_min_rate', superclass='of_queue_prop', members= [ OFTypeMember('type', 'uint16_t', 1), OFLengthMember('len', 'uint16_t'), OFPadMember(4), OFDataMember('rate', 'uint16_t'), OFPadMember(6)], virtual=False, params= {}), ] self.assertEquals(expected_classes, ofinput.classes)
def test_multiple_fields(self): src = """\ struct foo { uint32_t bar; uint8_t baz; uint64_t abc; }; """ ast = parser.parse(src) self.assertEquals(ast.asList(), [['struct', 'foo', [['uint32_t', 'bar'], ['uint8_t', 'baz'], ['uint64_t', 'abc']]]])
def test_comments(self): src = """\ // comment 1 struct foo { //comment 2 // comment 3 uint32_t a; //comment 5 // comment 6 }; // comment 4 """ ast = parser.parse(src) self.assertEqual(ast, [[ 'struct', 'foo', [], None, [['data', ['scalar', 'uint32_t'], 'a']] ]])
def test_multiple_fields(self): src = """\ struct foo { uint32_t bar; uint8_t baz; uint64_t abc; }; """ ast = parser.parse(src) self.assertEquals(ast, [['struct', 'foo', [], None, [['data', ['scalar', 'uint32_t'], 'bar'], ['data', ['scalar', 'uint8_t'], 'baz'], ['data', ['scalar', 'uint64_t'], 'abc']]]])
def test_multiple_fields(self): src = """\ struct foo { uint32_t bar; uint8_t baz; uint64_t abc; }; """ ast = parser.parse(src) self.assertEqual(ast, [[ 'struct', 'foo', [], None, [['data', ['scalar', 'uint32_t'], 'bar'], ['data', ['scalar', 'uint8_t'], 'baz'], ['data', ['scalar', 'uint64_t'], 'abc']] ]])
def test_field_length(self): ast = parser.parse(""" #version 1 struct of_test_entry { uint32_t x; }; struct of_test { uint16_t list_len == length(list); list(of_test_entry_t) list; }; """) # Not testing the parser, just making sure the AST is what we expect expected_ast = [ ['metadata', 'version', '1'], [ 'struct', 'of_test_entry', [], None, [['data', ['scalar', 'uint32_t'], 'x']] ], [ 'struct', 'of_test', [], None, [['field_length', ['scalar', 'uint16_t'], 'list_len', 'list'], ['data', ['list', 'list(of_test_entry_t)'], 'list']] ] ] self.assertEqual(expected_ast, ast) ofinput = frontend.create_ofinput("standard-1.0", ast) expected_classes = [ OFClass(name='of_test_entry', superclass=None, virtual=False, params={}, members=[OFDataMember('x', 'uint32_t')]), OFClass(name='of_test', superclass=None, virtual=False, params={}, members=[ OFFieldLengthMember('list_len', 'uint16_t', 'list'), OFDataMember('list', 'list(of_test_entry_t)') ]) ] self.assertEqual(expected_classes, ofinput.classes)
def test_field_length(self): ast = parser.parse(""" #version 1 struct of_test_entry { uint32_t x; }; struct of_test { uint16_t list_len == length(list); list(of_test_entry_t) list; }; """) # Not testing the parser, just making sure the AST is what we expect expected_ast = [ ['metadata', 'version', '1'], ['struct', 'of_test_entry', [], None, [ ['data', ['scalar', 'uint32_t'], 'x']]], ['struct', 'of_test', [], None, [ ['field_length', ['scalar', 'uint16_t'], 'list_len', 'list'], ['data', ['list', 'list(of_test_entry_t)'], 'list']]] ] self.assertEquals(expected_ast, ast) ofinput = frontend.create_ofinput("standard-1.0", ast) expected_classes = [ OFClass(name='of_test_entry', superclass=None, virtual=False, params={}, members=[ OFDataMember('x', 'uint32_t')]), OFClass(name='of_test', superclass=None, virtual=False, params={}, members=[ OFFieldLengthMember('list_len', 'uint16_t', 'list'), OFDataMember('list', 'list(of_test_entry_t)')]) ] self.assertEquals(expected_classes, ofinput.classes)
def test_simple(self): ast = parser.parse(""" #version 1 enum ofp_port_config { OFPPC_PORT_DOWN = 0x1, OFPPC_NO_STP = 0x2, OFPPC_NO_RECV = 0x4, OFPPC_NO_RECV_STP = 0x8, OFPPC_NO_FLOOD = 0x10, OFPPC_NO_FWD = 0x20, OFPPC_NO_PACKET_IN = 0x40, }; #version 2 struct of_echo_reply(align=8) { uint8_t version; uint8_t type == 3; uint16_t length; uint32_t xid; of_octets_t data; }; enum ofp_queue_op_failed_code(wire_type=uint32, bitmask=False, complete=True) { OFPQOFC_BAD_PORT = 0, OFPQOFC_BAD_QUEUE = 1, OFPQOFC_EPERM = 2, }; struct of_packet_queue { uint32_t queue_id; uint16_t len; pad(2); list(of_queue_prop_t) properties; }; """) # Not testing the parser, just making sure the AST is what we expect expected_ast = [ ['metadata', 'version', '1'], ['enum', 'ofp_port_config', [], [ ['OFPPC_PORT_DOWN', [], 1], ['OFPPC_NO_STP', [], 2], ['OFPPC_NO_RECV', [], 4], ['OFPPC_NO_RECV_STP', [], 8], ['OFPPC_NO_FLOOD', [], 16], ['OFPPC_NO_FWD', [], 32], ['OFPPC_NO_PACKET_IN', [], 64]]], ['metadata', 'version', '2'], ['struct', 'of_echo_reply', [['align', '8']], None, [ ['data', ['scalar', 'uint8_t'], 'version'], ['type', ['scalar', 'uint8_t'], 'type', 3], ['data', ['scalar', 'uint16_t'], 'length'], ['data', ['scalar', 'uint32_t'], 'xid'], ['data', ['scalar', 'of_octets_t'], 'data']]], ['enum', 'ofp_queue_op_failed_code', [['wire_type', 'uint32'], ['bitmask','False'], ['complete', 'True']], [ ['OFPQOFC_BAD_PORT', [], 0], ['OFPQOFC_BAD_QUEUE', [], 1], ['OFPQOFC_EPERM', [], 2]]], ['struct', 'of_packet_queue', [], None, [ ['data', ['scalar', 'uint32_t'], 'queue_id'], ['data', ['scalar', 'uint16_t'], 'len'], ['pad', 2], ['data', ['list', 'list(of_queue_prop_t)'], 'properties']]], ] self.assertEquals(expected_ast, ast) ofinput = frontend.create_ofinput(ast) self.assertEquals(set([1, 2]), ofinput.wire_versions) expected_classes = [ OFClass(name='of_echo_reply', superclass=None, members=[ OFDataMember('version', 'uint8_t'), # XXX OFTypeMember('type', 'uint8_t', 3), OFLengthMember('length', 'uint16_t'), OFDataMember('xid', 'uint32_t'), OFDataMember('data', 'of_octets_t')], virtual=False, params={'align': '8'}), OFClass(name='of_packet_queue', superclass=None, members=[ OFDataMember('queue_id', 'uint32_t'), OFLengthMember('len', 'uint16_t'), OFPadMember(2), OFDataMember('properties', 'list(of_queue_prop_t)')], virtual=False, params={}), ] self.assertEquals(expected_classes, ofinput.classes) expected_enums = [ OFEnum(name='ofp_port_config', entries=[ OFEnumEntry('OFPPC_PORT_DOWN', 1, {}), OFEnumEntry('OFPPC_NO_STP', 2, {}), OFEnumEntry('OFPPC_NO_RECV', 4, {}), OFEnumEntry('OFPPC_NO_RECV_STP', 8, {}), OFEnumEntry('OFPPC_NO_FLOOD', 16, {}), OFEnumEntry('OFPPC_NO_FWD', 32, {}), OFEnumEntry('OFPPC_NO_PACKET_IN', 64, {})], params={}), OFEnum(name='ofp_queue_op_failed_code', entries=[ OFEnumEntry('OFPQOFC_BAD_PORT', 0, {}), OFEnumEntry('OFPQOFC_BAD_QUEUE', 1, {}), OFEnumEntry('OFPQOFC_EPERM', 2, {})], params={'wire_type': 'uint32', 'bitmask': 'False', 'complete': 'True'}), ] self.assertEquals(expected_enums, ofinput.enums)
def syntax_error(self, src, regex): with self.assertRaisesRegexp(pyparsing.ParseSyntaxException, regex): parser.parse(src)
def test_empty(self): src = """\ struct foo { }; """ ast = parser.parse(src) self.assertEqual(ast, [['struct', 'foo', [], None, []]])
def syntax_error(self, src, regex): with self.assertRaisesRegex(pyparsing.ParseSyntaxException, regex): parser.parse(src)
def test_empty(self): src = """\ struct foo { }; """ ast = parser.parse(src) self.assertEquals(ast, [['struct', 'foo', [], None, []]])
def test_version(self): src = """\ #version 1 """ ast = parser.parse(src) self.assertEqual(ast, [['metadata', 'version', '1']])