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", |
| 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 |
| 85 | of_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), |
Rich Lane | 5183398 | 2013-12-03 13:02:45 -0800 | [diff] [blame] | 103 | of_checksum_128_t = (16, True), |
Andreas Wundsam | d30c107 | 2013-11-15 13:36:57 -0800 | [diff] [blame] | 104 | ) |
| 105 | |
| 106 | def type_dec_to_count_base(m_type): |
| 107 | """ |
| 108 | Resolve a type declaration like uint8_t[4] to a count (4) and base_type |
| 109 | (uint8_t) |
| 110 | |
| 111 | @param m_type The string type declaration to process |
| 112 | """ |
| 113 | count = 1 |
| 114 | chk_ar = m_type.split('[') |
| 115 | if len(chk_ar) > 1: |
| 116 | count_str = chk_ar[1].split(']')[0] |
| 117 | if count_str in ofp_constants: |
| 118 | count = ofp_constants[count_str] |
| 119 | else: |
| 120 | count = int(count_str) |
| 121 | base_type = chk_ar[0] |
| 122 | else: |
| 123 | base_type = m_type |
| 124 | return count, base_type |
| 125 | |
| 126 | |
| 127 | LengthInfo = namedtuple("LengthInfo", ("offset", "base_length", "is_fixed_length")) |
| 128 | |
| 129 | def calc_lengths(version, fe_class, existing_classes, existing_enums): |
| 130 | offset_fixed = True |
| 131 | offset = 0 |
| 132 | |
| 133 | member_infos = {} |
| 134 | for member in fe_class.members: |
| 135 | member_offset = offset if offset_fixed else None |
| 136 | |
| 137 | if isinstance(member, fe.OFPadMember): |
| 138 | member_base_length = member.length |
| 139 | member_fixed_length = True |
| 140 | else: |
| 141 | m_type = member.oftype |
| 142 | name = member.name |
| 143 | |
| 144 | member_base_length = 0 |
| 145 | if m_type.find("list(") == 0: |
| 146 | member_fixed_length = False |
| 147 | elif m_type.find("struct") == 0: |
| 148 | raise Exception("Error: recursive struct found: {}, {}" |
| 149 | .format(fe_class.name, name)) |
| 150 | elif m_type == "octets": |
| 151 | member_fixed_length = False |
| 152 | else: |
| 153 | member_base_length, member_fixed_length = member_length(version, fe_class, member, existing_classes, existing_enums) |
| 154 | |
| 155 | if not member_fixed_length: |
| 156 | offset_fixed = False |
| 157 | |
| 158 | member_infos[member] = LengthInfo(member_offset, member_base_length, |
| 159 | member_fixed_length) |
| 160 | offset += member_base_length |
| 161 | |
| 162 | base_length = offset |
| 163 | fixed_length = offset_fixed if not fe_class.virtual else False |
| 164 | return (base_length, fixed_length, member_infos) |
| 165 | |
| 166 | def member_length(version, fe_class, fe_member, existing_classes, existing_enums): |
| 167 | """ |
| 168 | return the length of an ir member. |
| 169 | |
| 170 | @return tuple (base_length, length_fixed) |
| 171 | """ |
| 172 | count, base_type = type_dec_to_count_base(fe_member.oftype) |
| 173 | |
| 174 | len_update = 0 |
| 175 | if base_type in of_mixed_types: |
| 176 | base_type = of_mixed_types[base_type][version.wire_version] |
| 177 | |
| 178 | base_class = base_type[:-2] |
| 179 | if base_class in existing_classes: |
| 180 | member_ir_class = existing_classes[base_class] |
| 181 | bytes = member_ir_class.base_length |
| 182 | length_fixed = member_ir_class.is_fixed_length |
| 183 | else: |
| 184 | if base_type in existing_enums: |
| 185 | enum = existing_enums[base_type] |
| 186 | base_type = enum.wire_type |
| 187 | |
| 188 | if base_type in of_base_lengths: |
| 189 | bytes, length_fixed = of_base_lengths[base_type] |
| 190 | else: |
| 191 | raise Exception("Unknown type for {}.{}: {}".format(fe_class.name, fe_member.name, base_type)) |
| 192 | |
| 193 | return (count * bytes), length_fixed |