| # Copyright 2013, Big Switch Networks, Inc. |
| # |
| # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with |
| # the following special exception: |
| # |
| # LOXI Exception |
| # |
| # As a special exception to the terms of the EPL, you may distribute libraries |
| # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided |
| # that copyright and licensing notices generated by LoxiGen are not altered or removed |
| # from the LoxiGen Libraries and the notice provided below is (i) included in |
| # the LoxiGen Libraries, if distributed in source code form and (ii) included in any |
| # documentation for the LoxiGen Libraries, if distributed in binary form. |
| # |
| # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler." |
| # |
| # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain |
| # a copy of the EPL at: |
| # |
| # http://www.eclipse.org/legal/epl-v10.html |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # EPL for the specific language governing permissions and limitations |
| # under the EPL. |
| |
| # @brief Match data representation |
| # |
| # @fixme This still has lots of C specific code that should be moved into c_gen |
| |
| import sys |
| import c_gen.of_g_legacy as of_g |
| from generic_utils import * |
| import c_gen.loxi_utils_legacy as loxi_utils |
| import loxi_globals |
| |
| # |
| # Use 1.2 match semantics for common case |
| # |
| # Generate maps between generic match and version specific matches |
| # Generate dump functions for generic match |
| # Generate dump functions for version specific matches |
| |
| ## @var of_match_members |
| # The dictionary from unified match members to type and indexing info |
| # |
| # Keys: |
| # name The unified name used for the member |
| # m_type The data type used for the object in unified structure |
| # order Used to define an order for readability |
| # v1_wc_shift The WC shift in OF 1.0 |
| # v2_wc_shift The WC shift in OF 1.1 |
| # |
| # We use the 1.2 names and alias older names |
| |
| of_match_members = dict() |
| |
| of_v1_keys = [ |
| "eth_dst", |
| "eth_src", |
| "eth_type", |
| "in_port", |
| "ipv4_dst", |
| "ip_proto", |
| "ipv4_src", |
| "ip_dscp", |
| "tcp_dst", # Means UDP too for 1.0 and 1.1 |
| "tcp_src", # Means UDP too for 1.0 and 1.1 |
| "vlan_pcp", |
| "vlan_vid" |
| ] |
| |
| v1_wc_shifts = dict( |
| in_port=0, |
| vlan_vid=1, |
| eth_src=2, |
| eth_dst=3, |
| eth_type=4, |
| ip_proto=5, |
| tcp_src=6, |
| tcp_dst=7, |
| ipv4_src=8, |
| ipv4_dst=14, |
| vlan_pcp=20, |
| ip_dscp=21, |
| ) |
| |
| of_v2_keys = [ |
| "eth_dst", |
| "eth_src", |
| "eth_type", |
| "in_port", |
| "ipv4_dst", |
| "ip_proto", |
| "ipv4_src", |
| "ip_dscp", |
| "tcp_dst", # Means UDP too for 1.0 and 1.1 |
| "tcp_src", # Means UDP too for 1.0 and 1.1 |
| "vlan_pcp", |
| "vlan_vid", |
| "mpls_label", |
| "mpls_tc", |
| "metadata" |
| ] |
| |
| of_v2_full_mask = [ |
| "eth_dst", |
| "eth_src", |
| "ipv4_dst", |
| "ipv4_src", |
| "metadata" |
| ] |
| |
| v2_wc_shifts = dict( |
| in_port=0, |
| vlan_vid=1, |
| vlan_pcp=2, |
| eth_type=3, |
| ip_dscp=4, |
| ip_proto=5, |
| tcp_src=6, |
| tcp_dst=7, |
| mpls_label=8, |
| mpls_tc=9, |
| ) |
| |
| # Map from wire version to list of match keys for that version |
| match_keys = { |
| 1: of_v1_keys, |
| 2: of_v2_keys, |
| 3: [], |
| 4: [], |
| 5: [], |
| } |
| |
| # Complete list of match keys, sorted by the standard order |
| match_keys_sorted = [] |
| |
| # Generate the of_match_members, match_keys, and match_keys_sorted |
| # datastructures from the IR and the v1/v2 tables above |
| def build(): |
| for uclass in loxi_globals.unified.classes: |
| if not uclass.is_oxm or uclass.name == 'of_oxm': |
| continue |
| if uclass.name.endswith('_masked'): |
| continue |
| |
| name = uclass.name[7:] # of_oxm_* |
| value_member = uclass.member_by_name('value') |
| type_len = uclass.member_by_name('type_len').value |
| |
| # Order match keys by their type_len |
| if (type_len & 0xffff0000) == 0x80000000: |
| # OpenFlow Basic comes first |
| order = type_len & 0x0000ffff |
| else: |
| order = type_len |
| |
| match_member = dict( |
| name=name, |
| m_type=value_member.oftype, |
| order=order) |
| if name in v1_wc_shifts: |
| match_member['v1_wc_shift'] = v1_wc_shifts[name] |
| if name in v2_wc_shifts: |
| match_member['v2_wc_shift'] = v2_wc_shifts[name] |
| |
| of_match_members[name] = match_member |
| |
| for version in uclass.version_classes: |
| assert name not in match_keys[version.wire_version] |
| match_keys[version.wire_version].append(name) |
| |
| match_keys_sorted.extend( |
| sorted(of_match_members.keys(), |
| key=lambda entry:of_match_members[entry]["order"])) |
| |
| ## |
| # Check that all members in the hash are recognized as match keys |
| def match_sanity_check(): |
| count = 0 |
| for match_v in ["of_match_v1", "of_match_v2"]: |
| count += 1 |
| for mm in of_g.unified[match_v][count]["members"]: |
| key = mm["name"] |
| if key.find("_mask") >= 0: |
| continue |
| if loxi_utils.skip_member_name(key): |
| continue |
| if key == "wildcards": |
| continue |
| if not key in of_match_members: |
| print "Key %s not found in match struct, v %s" % (key, match_v) |
| sys.exit(1) |
| |
| # Generate list of OXM names from the unified classes |
| oxm_names = [x[7:] for x in of_g.unified.keys() if |
| x.startswith('of_oxm_') and |
| x.find('masked') < 0] |
| |
| # Check that all OXMs are in the match members |
| for key in oxm_names: |
| if not key in of_match_members: |
| if not (key.find("_masked") > 0): |
| debug("Key %s in OXM, not of_match_members" % key) |
| sys.exit(1) |
| if not key[:-7] in of_match_members: |
| debug("Key %s in OXM, but %s not in of_match_members" |
| % (key, key[:-7])) |
| sys.exit(1) |
| |
| # Check that all match members are in the OXMs |
| for key in of_match_members: |
| if not key in oxm_names: |
| debug("Key %s in of_match_members, not in OXM" % key) |
| sys.exit(1) |
| oxm_type = of_g.unified['of_oxm_%s' % key]['union']['value']['m_type'] |
| if of_match_members[key]["m_type"] != oxm_type: |
| debug("Type mismatch for key %s in oxm data: %s vs %s" % |
| (key, of_match_members[key]["m_type"], oxm_type)) |
| sys.exit(1) |