Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 1 | # Copyright 2013, Big Switch Networks, Inc. |
| 2 | # |
| 3 | # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with |
| 4 | # the following special exception: |
| 5 | # |
| 6 | # LOXI Exception |
| 7 | # |
| 8 | # As a special exception to the terms of the EPL, you may distribute libraries |
| 9 | # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided |
| 10 | # that copyright and licensing notices generated by LoxiGen are not altered or removed |
| 11 | # from the LoxiGen Libraries and the notice provided below is (i) included in |
| 12 | # the LoxiGen Libraries, if distributed in source code form and (ii) included in any |
| 13 | # documentation for the LoxiGen Libraries, if distributed in binary form. |
| 14 | # |
| 15 | # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler." |
| 16 | # |
| 17 | # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain |
| 18 | # a copy of the EPL at: |
| 19 | # |
| 20 | # http://www.eclipse.org/legal/epl-v10.html |
| 21 | # |
| 22 | # Unless required by applicable law or agreed to in writing, software |
| 23 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 24 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 25 | # EPL for the specific language governing permissions and limitations |
| 26 | # under the EPL. |
| 27 | |
| 28 | # @brief Match data representation |
| 29 | # |
| 30 | # @fixme This still has lots of C specific code that should be moved into c_gen |
| 31 | |
| 32 | import sys |
Andreas Wundsam | 542a13c | 2013-11-15 13:28:55 -0800 | [diff] [blame] | 33 | import c_gen.of_g_legacy as of_g |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 34 | from generic_utils import * |
Andreas Wundsam | 542a13c | 2013-11-15 13:28:55 -0800 | [diff] [blame] | 35 | import c_gen.loxi_utils_legacy as loxi_utils |
Rich Lane | b4a63a5 | 2014-05-22 14:41:57 -0700 | [diff] [blame] | 36 | import loxi_globals |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 37 | |
| 38 | # |
| 39 | # Use 1.2 match semantics for common case |
| 40 | # |
| 41 | # Generate maps between generic match and version specific matches |
| 42 | # Generate dump functions for generic match |
| 43 | # Generate dump functions for version specific matches |
| 44 | |
| 45 | ## @var of_match_members |
| 46 | # The dictionary from unified match members to type and indexing info |
| 47 | # |
| 48 | # Keys: |
| 49 | # name The unified name used for the member |
| 50 | # m_type The data type used for the object in unified structure |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 51 | # order Used to define an order for readability |
| 52 | # v1_wc_shift The WC shift in OF 1.0 |
| 53 | # v2_wc_shift The WC shift in OF 1.1 |
| 54 | # |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 55 | # We use the 1.2 names and alias older names |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 56 | |
Rich Lane | b4a63a5 | 2014-05-22 14:41:57 -0700 | [diff] [blame] | 57 | of_match_members = dict() |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 58 | |
| 59 | of_v1_keys = [ |
| 60 | "eth_dst", |
| 61 | "eth_src", |
| 62 | "eth_type", |
| 63 | "in_port", |
| 64 | "ipv4_dst", |
| 65 | "ip_proto", |
| 66 | "ipv4_src", |
| 67 | "ip_dscp", |
| 68 | "tcp_dst", # Means UDP too for 1.0 and 1.1 |
| 69 | "tcp_src", # Means UDP too for 1.0 and 1.1 |
| 70 | "vlan_pcp", |
Rob Sherwood | 53989c8 | 2013-07-03 16:49:50 -0700 | [diff] [blame] | 71 | "vlan_vid" |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 72 | ] |
| 73 | |
Rich Lane | b4a63a5 | 2014-05-22 14:41:57 -0700 | [diff] [blame] | 74 | v1_wc_shifts = dict( |
| 75 | in_port=0, |
| 76 | vlan_vid=1, |
| 77 | eth_src=2, |
| 78 | eth_dst=3, |
| 79 | eth_type=4, |
| 80 | ip_proto=5, |
| 81 | tcp_src=6, |
| 82 | tcp_dst=7, |
| 83 | ipv4_src=8, |
| 84 | ipv4_dst=14, |
| 85 | vlan_pcp=20, |
| 86 | ip_dscp=21, |
| 87 | ) |
| 88 | |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 89 | of_v2_keys = [ |
| 90 | "eth_dst", |
| 91 | "eth_src", |
| 92 | "eth_type", |
| 93 | "in_port", |
| 94 | "ipv4_dst", |
| 95 | "ip_proto", |
| 96 | "ipv4_src", |
| 97 | "ip_dscp", |
| 98 | "tcp_dst", # Means UDP too for 1.0 and 1.1 |
| 99 | "tcp_src", # Means UDP too for 1.0 and 1.1 |
| 100 | "vlan_pcp", |
| 101 | "vlan_vid", |
| 102 | "mpls_label", |
| 103 | "mpls_tc", |
| 104 | "metadata" |
| 105 | ] |
| 106 | |
| 107 | of_v2_full_mask = [ |
| 108 | "eth_dst", |
| 109 | "eth_src", |
| 110 | "ipv4_dst", |
| 111 | "ipv4_src", |
| 112 | "metadata" |
| 113 | ] |
| 114 | |
Rich Lane | b4a63a5 | 2014-05-22 14:41:57 -0700 | [diff] [blame] | 115 | v2_wc_shifts = dict( |
| 116 | in_port=0, |
| 117 | vlan_vid=1, |
| 118 | vlan_pcp=2, |
| 119 | eth_type=3, |
| 120 | ip_dscp=4, |
| 121 | ip_proto=5, |
| 122 | tcp_src=6, |
| 123 | tcp_dst=7, |
| 124 | mpls_label=8, |
| 125 | mpls_tc=9, |
| 126 | ) |
| 127 | |
| 128 | # Map from wire version to list of match keys for that version |
| 129 | match_keys = { |
| 130 | 1: of_v1_keys, |
| 131 | 2: of_v2_keys, |
| 132 | 3: [], |
| 133 | 4: [], |
| 134 | } |
| 135 | |
| 136 | # Complete list of match keys, sorted by the standard order |
| 137 | match_keys_sorted = [] |
| 138 | |
| 139 | # Generate the of_match_members, match_keys, and match_keys_sorted |
| 140 | # datastructures from the IR and the v1/v2 tables above |
| 141 | def build(): |
Rich Lane | b4a63a5 | 2014-05-22 14:41:57 -0700 | [diff] [blame] | 142 | for uclass in loxi_globals.unified.classes: |
| 143 | if not uclass.is_oxm or uclass.name == 'of_oxm': |
| 144 | continue |
| 145 | if uclass.name.endswith('_masked'): |
| 146 | continue |
| 147 | |
| 148 | name = uclass.name[7:] # of_oxm_* |
| 149 | value_member = uclass.member_by_name('value') |
| 150 | type_len = uclass.member_by_name('type_len').value |
| 151 | |
| 152 | # Order match keys by their type_len |
| 153 | if (type_len & 0xffff0000) == 0x80000000: |
| 154 | # OpenFlow Basic comes first |
| 155 | order = type_len & 0x0000ffff |
| 156 | else: |
| 157 | order = type_len |
| 158 | |
| 159 | match_member = dict( |
| 160 | name=name, |
| 161 | m_type=value_member.oftype, |
| 162 | order=order) |
| 163 | if name in v1_wc_shifts: |
| 164 | match_member['v1_wc_shift'] = v1_wc_shifts[name] |
| 165 | if name in v2_wc_shifts: |
| 166 | match_member['v2_wc_shift'] = v2_wc_shifts[name] |
| 167 | |
| 168 | of_match_members[name] = match_member |
| 169 | |
| 170 | for version in uclass.version_classes: |
Rich Lane | f42da58 | 2014-05-23 09:57:35 -0700 | [diff] [blame] | 171 | assert name not in match_keys[version.wire_version] |
Rich Lane | b4a63a5 | 2014-05-22 14:41:57 -0700 | [diff] [blame] | 172 | match_keys[version.wire_version].append(name) |
| 173 | |
Rich Lane | f42da58 | 2014-05-23 09:57:35 -0700 | [diff] [blame] | 174 | match_keys_sorted.extend( |
| 175 | sorted(of_match_members.keys(), |
| 176 | key=lambda entry:of_match_members[entry]["order"])) |
Rich Lane | b4a63a5 | 2014-05-22 14:41:57 -0700 | [diff] [blame] | 177 | |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 178 | ## |
| 179 | # Check that all members in the hash are recognized as match keys |
| 180 | def match_sanity_check(): |
| 181 | count = 0 |
| 182 | for match_v in ["of_match_v1", "of_match_v2"]: |
| 183 | count += 1 |
| 184 | for mm in of_g.unified[match_v][count]["members"]: |
| 185 | key = mm["name"] |
| 186 | if key.find("_mask") >= 0: |
| 187 | continue |
| 188 | if loxi_utils.skip_member_name(key): |
| 189 | continue |
| 190 | if key == "wildcards": |
| 191 | continue |
| 192 | if not key in of_match_members: |
| 193 | print "Key %s not found in match struct, v %s" % (key, match_v) |
| 194 | sys.exit(1) |
| 195 | |
Rich Lane | 883919c | 2013-05-09 17:53:18 -0700 | [diff] [blame] | 196 | # Generate list of OXM names from the unified classes |
| 197 | oxm_names = [x[7:] for x in of_g.unified.keys() if |
| 198 | x.startswith('of_oxm_') and |
| 199 | x.find('masked') < 0 and |
| 200 | x.find('header') < 0] |
| 201 | |
| 202 | # Check that all OXMs are in the match members |
| 203 | for key in oxm_names: |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 204 | if not key in of_match_members: |
| 205 | if not (key.find("_masked") > 0): |
Rich Lane | 883919c | 2013-05-09 17:53:18 -0700 | [diff] [blame] | 206 | debug("Key %s in OXM, not of_match_members" % key) |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 207 | sys.exit(1) |
| 208 | if not key[:-7] in of_match_members: |
Rich Lane | 883919c | 2013-05-09 17:53:18 -0700 | [diff] [blame] | 209 | debug("Key %s in OXM, but %s not in of_match_members" |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 210 | % (key, key[:-7])) |
| 211 | sys.exit(1) |
| 212 | |
Rich Lane | 883919c | 2013-05-09 17:53:18 -0700 | [diff] [blame] | 213 | # Check that all match members are in the OXMs |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 214 | for key in of_match_members: |
Rich Lane | 883919c | 2013-05-09 17:53:18 -0700 | [diff] [blame] | 215 | if not key in oxm_names: |
| 216 | debug("Key %s in of_match_members, not in OXM" % key) |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 217 | sys.exit(1) |
Rich Lane | 883919c | 2013-05-09 17:53:18 -0700 | [diff] [blame] | 218 | oxm_type = of_g.unified['of_oxm_%s' % key]['union']['value']['m_type'] |
| 219 | if of_match_members[key]["m_type"] != oxm_type: |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 220 | debug("Type mismatch for key %s in oxm data: %s vs %s" % |
Rich Lane | 883919c | 2013-05-09 17:53:18 -0700 | [diff] [blame] | 221 | (key, of_match_members[key]["m_type"], oxm_type)) |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 222 | sys.exit(1) |