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