Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 1 | ## 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 | # |
| 17 | from collections import namedtuple |
| 18 | import logging |
| 19 | |
| 20 | import loxi_front_end.frontend_ir as fe |
| 21 | import loxi_ir.ir |
| 22 | |
| 23 | ofp_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, |
Praseed Balakrishnan | 7f71878 | 2014-09-18 17:02:48 -0700 | [diff] [blame] | 28 | OF_SERIAL_NUM_LEN = 32, |
| 29 | OF_APP_CODE_LEN = 15 |
Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 30 | ) |
| 31 | |
| 32 | |
| 33 | of_mixed_types = dict( |
| 34 | of_port_no_t = { |
| 35 | 1: "uint16_t", |
| 36 | 2: "uint32_t", |
| 37 | 3: "uint32_t", |
| 38 | 4: "uint32_t", |
alshabib | 9f50e48 | 2014-08-23 17:10:57 -0500 | [diff] [blame] | 39 | 5: "uint32_t", |
Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 40 | "short_name":"port_no" |
| 41 | }, |
| 42 | of_port_desc_t = { |
| 43 | 1: "of_port_desc_t", |
| 44 | 2: "of_port_desc_t", |
| 45 | 3: "of_port_desc_t", |
| 46 | 4: "of_port_desc_t", |
alshabib | 9f50e48 | 2014-08-23 17:10:57 -0500 | [diff] [blame] | 47 | 5: "of_port_desc_t", |
Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 48 | "short_name":"port_desc" |
| 49 | }, |
| 50 | of_bsn_vport_t = { |
| 51 | 1: "of_bsn_vport_t", |
| 52 | 2: "of_bsn_vport_t", |
| 53 | 3: "of_bsn_vport_t", |
| 54 | 4: "of_bsn_vport_t", |
alshabib | 9f50e48 | 2014-08-23 17:10:57 -0500 | [diff] [blame] | 55 | 5: "of_bsn_vport_t", |
Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 56 | "short_name":"bsn_vport" |
| 57 | }, |
| 58 | of_fm_cmd_t = { # Flow mod command went from u16 to u8 |
| 59 | 1: "uint16_t", |
| 60 | 2: "uint8_t", |
| 61 | 3: "uint8_t", |
| 62 | 4: "uint8_t", |
alshabib | 9f50e48 | 2014-08-23 17:10:57 -0500 | [diff] [blame] | 63 | 5: "uint8_t", |
Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 64 | "short_name":"fm_cmd" |
| 65 | }, |
| 66 | of_wc_bmap_t = { # Wildcard bitmap |
| 67 | 1: "uint32_t", |
| 68 | 2: "uint32_t", |
| 69 | 3: "uint64_t", |
| 70 | 4: "uint64_t", |
alshabib | 9f50e48 | 2014-08-23 17:10:57 -0500 | [diff] [blame] | 71 | 5: "uint64_t", |
Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 72 | "short_name":"wc_bmap" |
| 73 | }, |
| 74 | of_match_bmap_t = { # Match bitmap |
| 75 | 1: "uint32_t", |
| 76 | 2: "uint32_t", |
| 77 | 3: "uint64_t", |
| 78 | 4: "uint64_t", |
alshabib | 9f50e48 | 2014-08-23 17:10:57 -0500 | [diff] [blame] | 79 | 5: "uint64_t", |
Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 80 | "short_name":"match_bmap" |
| 81 | }, |
| 82 | of_match_t = { # Match object |
| 83 | 1: "of_match_v1_t", |
| 84 | 2: "of_match_v2_t", |
| 85 | 3: "of_match_v3_t", |
| 86 | 4: "of_match_v3_t", # Currently uses same match as 1.2 (v3). |
alshabib | 9f50e48 | 2014-08-23 17:10:57 -0500 | [diff] [blame] | 87 | 5: "of_match_v3_t", # Currently uses same match as 1.2 (v3). |
Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 88 | "short_name":"match" |
| 89 | }, |
| 90 | ) |
| 91 | |
| 92 | ## basic lengths |
| 93 | of_base_lengths = dict( |
| 94 | char = (1, True), |
| 95 | uint8_t = (1, True), |
| 96 | uint16_t = (2, True), |
| 97 | uint32_t = (4, True), |
| 98 | uint64_t = (8, True), |
| 99 | of_mac_addr_t = (6, True), |
| 100 | of_ipv4_t = (4, True), |
| 101 | of_ipv6_t = (16, True), |
| 102 | of_port_name_t = (ofp_constants["OF_MAX_PORT_NAME_LEN"], True), |
| 103 | of_table_name_t = (ofp_constants["OF_MAX_TABLE_NAME_LEN"], True), |
| 104 | of_desc_str_t = (ofp_constants["OF_DESC_STR_LEN"], True), |
| 105 | of_serial_num_t = (ofp_constants["OF_SERIAL_NUM_LEN"], True), |
Rich Lane | f8a3d00 | 2014-03-19 13:33:52 -0700 | [diff] [blame] | 106 | of_str64_t = (64, True), |
Brian O'Connor | 58a73e3 | 2015-05-28 11:51:27 -0700 | [diff] [blame] | 107 | of_str32_t = (32, True), |
| 108 | of_str6_t = (6, True), |
Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 109 | of_match_v1_t = (40, True), |
| 110 | of_match_v2_t = (88, True), |
| 111 | of_match_v3_t = (8, False), |
| 112 | of_octets_t = (0, False), |
| 113 | of_bitmap_128_t = (16, True), |
Rich Lane | 5183398 | 2013-12-03 13:02:45 -0800 | [diff] [blame] | 114 | of_checksum_128_t = (16, True), |
Praseed Balakrishnan | 7f71878 | 2014-09-18 17:02:48 -0700 | [diff] [blame] | 115 | of_app_code_t = (15,True), |
Praseed Balakrishnan | 2ed6da0 | 2014-09-18 17:02:48 -0700 | [diff] [blame] | 116 | of_sig_id_t = (6, True), |
Rich Lane | 931eab3 | 2014-11-13 15:42:29 -0800 | [diff] [blame] | 117 | of_bitmap_512_t = (64, True), |
Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 118 | ) |
| 119 | |
| 120 | def type_dec_to_count_base(m_type): |
| 121 | """ |
| 122 | Resolve a type declaration like uint8_t[4] to a count (4) and base_type |
| 123 | (uint8_t) |
| 124 | |
| 125 | @param m_type The string type declaration to process |
| 126 | """ |
| 127 | count = 1 |
| 128 | chk_ar = m_type.split('[') |
| 129 | if len(chk_ar) > 1: |
| 130 | count_str = chk_ar[1].split(']')[0] |
| 131 | if count_str in ofp_constants: |
| 132 | count = ofp_constants[count_str] |
| 133 | else: |
| 134 | count = int(count_str) |
| 135 | base_type = chk_ar[0] |
| 136 | else: |
| 137 | base_type = m_type |
| 138 | return count, base_type |
| 139 | |
| 140 | |
| 141 | LengthInfo = namedtuple("LengthInfo", ("offset", "base_length", "is_fixed_length")) |
| 142 | |
| 143 | def calc_lengths(version, fe_class, existing_classes, existing_enums): |
| 144 | offset_fixed = True |
| 145 | offset = 0 |
| 146 | |
| 147 | member_infos = {} |
| 148 | for member in fe_class.members: |
| 149 | member_offset = offset if offset_fixed else None |
| 150 | |
| 151 | if isinstance(member, fe.OFPadMember): |
| 152 | member_base_length = member.length |
| 153 | member_fixed_length = True |
| 154 | else: |
| 155 | m_type = member.oftype |
| 156 | name = member.name |
| 157 | |
| 158 | member_base_length = 0 |
| 159 | if m_type.find("list(") == 0: |
| 160 | member_fixed_length = False |
| 161 | elif m_type.find("struct") == 0: |
| 162 | raise Exception("Error: recursive struct found: {}, {}" |
| 163 | .format(fe_class.name, name)) |
| 164 | elif m_type == "octets": |
| 165 | member_fixed_length = False |
| 166 | else: |
| 167 | member_base_length, member_fixed_length = member_length(version, fe_class, member, existing_classes, existing_enums) |
| 168 | |
| 169 | if not member_fixed_length: |
| 170 | offset_fixed = False |
| 171 | |
| 172 | member_infos[member] = LengthInfo(member_offset, member_base_length, |
| 173 | member_fixed_length) |
| 174 | offset += member_base_length |
| 175 | |
| 176 | base_length = offset |
| 177 | fixed_length = offset_fixed if not fe_class.virtual else False |
| 178 | return (base_length, fixed_length, member_infos) |
| 179 | |
| 180 | def member_length(version, fe_class, fe_member, existing_classes, existing_enums): |
| 181 | """ |
| 182 | return the length of an ir member. |
| 183 | |
| 184 | @return tuple (base_length, length_fixed) |
| 185 | """ |
| 186 | count, base_type = type_dec_to_count_base(fe_member.oftype) |
| 187 | |
Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 188 | if base_type in of_mixed_types: |
| 189 | base_type = of_mixed_types[base_type][version.wire_version] |
| 190 | |
| 191 | base_class = base_type[:-2] |
| 192 | if base_class in existing_classes: |
| 193 | member_ir_class = existing_classes[base_class] |
| 194 | bytes = member_ir_class.base_length |
| 195 | length_fixed = member_ir_class.is_fixed_length |
Rich Lane | 824c088 | 2014-10-16 14:26:53 -0700 | [diff] [blame] | 196 | if member_ir_class.has_external_alignment: |
| 197 | bytes = (bytes + 7) & ~7 |
Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 198 | else: |
| 199 | if base_type in existing_enums: |
| 200 | enum = existing_enums[base_type] |
| 201 | base_type = enum.wire_type |
| 202 | |
| 203 | if base_type in of_base_lengths: |
| 204 | bytes, length_fixed = of_base_lengths[base_type] |
| 205 | else: |
| 206 | raise Exception("Unknown type for {}.{}: {}".format(fe_class.name, fe_member.name, base_type)) |
| 207 | |
| 208 | return (count * bytes), length_fixed |