blob: 0f27f5e0ac88748407ef47466223fd62829db717 [file] [log] [blame]
Andreas Wundsamd30c1072013-11-15 13:36:57 -08001## List of mixed data types
2#
3# This is a list of data types which require special treatment
4# because the underlying datatype has changed between versions.
5# The main example is port which went from 16 to 32 bits. We
6# define per-version accessors for these types and those are
7# used in place of the normal ones.
8#
9# The wire protocol number is used to identify versions. For now,
10# the value is the name of the type to use for that version
11#
12# This is the map between the external type (like of_port_no_t)
13# which is used by customers of this code and the internal
14# datatypes (like uint16_t) that appear on the wire for a
15# particular version.
16#
17from collections import namedtuple
18import logging
19
20import loxi_front_end.frontend_ir as fe
21import loxi_ir.ir
22
23ofp_constants = dict(
24 OF_MAX_TABLE_NAME_LEN = 32,
25 OF_MAX_PORT_NAME_LEN = 16,
26 OF_ETH_ALEN = 6,
27 OF_DESC_STR_LEN = 256,
28 OF_SERIAL_NUM_LEN = 32
29)
30
31
32of_mixed_types = dict(
33 of_port_no_t = {
34 1: "uint16_t",
35 2: "uint32_t",
36 3: "uint32_t",
37 4: "uint32_t",
38 "short_name":"port_no"
39 },
40 of_port_desc_t = {
41 1: "of_port_desc_t",
42 2: "of_port_desc_t",
43 3: "of_port_desc_t",
44 4: "of_port_desc_t",
45 "short_name":"port_desc"
46 },
47 of_bsn_vport_t = {
48 1: "of_bsn_vport_t",
49 2: "of_bsn_vport_t",
50 3: "of_bsn_vport_t",
51 4: "of_bsn_vport_t",
52 "short_name":"bsn_vport"
53 },
54 of_fm_cmd_t = { # Flow mod command went from u16 to u8
55 1: "uint16_t",
56 2: "uint8_t",
57 3: "uint8_t",
58 4: "uint8_t",
59 "short_name":"fm_cmd"
60 },
61 of_wc_bmap_t = { # Wildcard bitmap
62 1: "uint32_t",
63 2: "uint32_t",
64 3: "uint64_t",
65 4: "uint64_t",
66 "short_name":"wc_bmap"
67 },
68 of_match_bmap_t = { # Match bitmap
69 1: "uint32_t",
70 2: "uint32_t",
71 3: "uint64_t",
72 4: "uint64_t",
73 "short_name":"match_bmap"
74 },
75 of_match_t = { # Match object
76 1: "of_match_v1_t",
77 2: "of_match_v2_t",
78 3: "of_match_v3_t",
79 4: "of_match_v3_t", # Currently uses same match as 1.2 (v3).
80 "short_name":"match"
81 },
82)
83
84## basic lengths
85of_base_lengths = dict(
86 char = (1, True),
87 uint8_t = (1, True),
88 uint16_t = (2, True),
89 uint32_t = (4, True),
90 uint64_t = (8, True),
91 of_mac_addr_t = (6, True),
92 of_ipv4_t = (4, True),
93 of_ipv6_t = (16, True),
94 of_port_name_t = (ofp_constants["OF_MAX_PORT_NAME_LEN"], True),
95 of_table_name_t = (ofp_constants["OF_MAX_TABLE_NAME_LEN"], True),
96 of_desc_str_t = (ofp_constants["OF_DESC_STR_LEN"], True),
97 of_serial_num_t = (ofp_constants["OF_SERIAL_NUM_LEN"], True),
98 of_match_v1_t = (40, True),
99 of_match_v2_t = (88, True),
100 of_match_v3_t = (8, False),
101 of_octets_t = (0, False),
102 of_bitmap_128_t = (16, True),
103)
104
105def type_dec_to_count_base(m_type):
106 """
107 Resolve a type declaration like uint8_t[4] to a count (4) and base_type
108 (uint8_t)
109
110 @param m_type The string type declaration to process
111 """
112 count = 1
113 chk_ar = m_type.split('[')
114 if len(chk_ar) > 1:
115 count_str = chk_ar[1].split(']')[0]
116 if count_str in ofp_constants:
117 count = ofp_constants[count_str]
118 else:
119 count = int(count_str)
120 base_type = chk_ar[0]
121 else:
122 base_type = m_type
123 return count, base_type
124
125
126LengthInfo = namedtuple("LengthInfo", ("offset", "base_length", "is_fixed_length"))
127
128def calc_lengths(version, fe_class, existing_classes, existing_enums):
129 offset_fixed = True
130 offset = 0
131
132 member_infos = {}
133 for member in fe_class.members:
134 member_offset = offset if offset_fixed else None
135
136 if isinstance(member, fe.OFPadMember):
137 member_base_length = member.length
138 member_fixed_length = True
139 else:
140 m_type = member.oftype
141 name = member.name
142
143 member_base_length = 0
144 if m_type.find("list(") == 0:
145 member_fixed_length = False
146 elif m_type.find("struct") == 0:
147 raise Exception("Error: recursive struct found: {}, {}"
148 .format(fe_class.name, name))
149 elif m_type == "octets":
150 member_fixed_length = False
151 else:
152 member_base_length, member_fixed_length = member_length(version, fe_class, member, existing_classes, existing_enums)
153
154 if not member_fixed_length:
155 offset_fixed = False
156
157 member_infos[member] = LengthInfo(member_offset, member_base_length,
158 member_fixed_length)
159 offset += member_base_length
160
161 base_length = offset
162 fixed_length = offset_fixed if not fe_class.virtual else False
163 return (base_length, fixed_length, member_infos)
164
165def member_length(version, fe_class, fe_member, existing_classes, existing_enums):
166 """
167 return the length of an ir member.
168
169 @return tuple (base_length, length_fixed)
170 """
171 count, base_type = type_dec_to_count_base(fe_member.oftype)
172
173 len_update = 0
174 if base_type in of_mixed_types:
175 base_type = of_mixed_types[base_type][version.wire_version]
176
177 base_class = base_type[:-2]
178 if base_class in existing_classes:
179 member_ir_class = existing_classes[base_class]
180 bytes = member_ir_class.base_length
181 length_fixed = member_ir_class.is_fixed_length
182 else:
183 if base_type in existing_enums:
184 enum = existing_enums[base_type]
185 base_type = enum.wire_type
186
187 if base_type in of_base_lengths:
188 bytes, length_fixed = of_base_lengths[base_type]
189 else:
190 raise Exception("Unknown type for {}.{}: {}".format(fe_class.name, fe_member.name, base_type))
191
192 return (count * bytes), length_fixed