blob: c2d43c28d76e3aa0ca880788eac98d9269a3d146 [file] [log] [blame]
Andreas Wundsam27303462013-07-16 12:52:35 -07001# 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
Andreas Wundsam40e14f72013-05-06 14:49:08 -070028# Prototype of an Intermediate Object model for the java code generator
29# A lot of this stuff could/should probably be merged with the python utilities
30
Andreas Wundsam27303462013-07-16 12:52:35 -070031import collections
Andreas Wundsam5204de22013-07-30 11:34:45 -070032from collections import namedtuple, defaultdict, OrderedDict
Andreas Wundsam27303462013-07-16 12:52:35 -070033import logging
Andreas Wundsam40e14f72013-05-06 14:49:08 -070034import os
35import pdb
36import re
37
Andreas Wundsam5204de22013-07-30 11:34:45 -070038from generic_utils import find, memoize, OrderedSet, OrderedDefaultDict
Andreas Wundsam27303462013-07-16 12:52:35 -070039import of_g
40from loxi_ir import *
Andreas Wundsam40e14f72013-05-06 14:49:08 -070041import loxi_front_end.type_maps as type_maps
Andreas Wundsam5204de22013-07-30 11:34:45 -070042import loxi_utils.loxi_utils as loxi_utils
Andreas Wundsam40e14f72013-05-06 14:49:08 -070043import py_gen.util as py_utils
Andreas Wundsam5204de22013-07-30 11:34:45 -070044import test_data
Andreas Wundsam40e14f72013-05-06 14:49:08 -070045
Andreas Wundsam27303462013-07-16 12:52:35 -070046import java_gen.java_type as java_type
Andreas Wundsame0d52be2013-08-22 07:52:13 -070047from java_gen.java_type import erase_type_annotation
Andreas Wundsam40e14f72013-05-06 14:49:08 -070048
Andreas Wundsam27303462013-07-16 12:52:35 -070049class JavaModel(object):
Andreas Wundsamf1949682013-09-23 14:48:31 -070050 # registry for enums that should not be generated
51 # set(${java_enum_name})
Andreas Wundsamacd57d52013-10-18 17:35:01 -070052 enum_blacklist = set(("OFDefinitions", "OFPortNo", "OFVlanId", "OFGroup"))
Andreas Wundsamf1949682013-09-23 14:48:31 -070053 # registry for enum *entry* that should not be generated
54 # map: ${java_enum_name} -> set(${java_entry_entry_name})
Andreas Wundsam43526532013-08-01 22:03:50 -070055 enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
Andreas Wundsamf1949682013-09-23 14:48:31 -070056
57 # registry of interfaces that should not be generated
58 # set(java_names)
Andreas Wundsambe168f72013-08-03 22:49:35 -070059 # OFUint structs are there for god-knows what in loci. We certainly don't need them.
60 interface_blacklist = set( ("OFUint8", "OFUint32",))
Andreas Wundsamf1949682013-09-23 14:48:31 -070061 # registry of interface properties that should not be generated
62 # map: $java_type -> set(java_name_property)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070063 read_blacklist = defaultdict(lambda: set(), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070064 # map: $java_type -> set(java_name_property)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070065 write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070066 # interfaces that are virtual
Andreas Wundsam001b1822013-08-02 22:25:55 -070067 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070068
Andreas Wundsam2be7da52013-08-22 07:34:25 -070069 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
Yotam Harchole5d92972013-08-22 14:18:36 -070070 oxm_map = { "OFOxmInPort": OxmMapEntry("OFPort", "IN_PORT", False),
71 "OFOxmInPortMasked": OxmMapEntry("OFPort", "IN_PORT", True),
72 "OFOxmInPhyPort": OxmMapEntry("OFPort", "IN_PHY_PORT", False),
73 "OFOxmInPhyPortMasked": OxmMapEntry("OFPort", "IN_PHY_PORT", True),
74 "OFOxmMetadata": OxmMapEntry("OFMetadata", "METADATA", False),
75 "OFOxmMetadataMasked": OxmMapEntry("OFMetadata", "METADATA", True),
76 "OFOxmEthDst": OxmMapEntry("MacAddress", "ETH_DST", False),
77 "OFOxmEthDstMasked": OxmMapEntry("MacAddress", "ETH_DST", True),
78 "OFOxmEthSrc": OxmMapEntry("MacAddress", "ETH_SRC", False),
79 "OFOxmEthSrcMasked": OxmMapEntry("MacAddress", "ETH_SRC", True),
80 "OFOxmEthType": OxmMapEntry("EthType", "ETH_TYPE", False),
81 "OFOxmEthTypeMasked": OxmMapEntry("EthType", "ETH_TYPE", True),
82 "OFOxmVlanVid": OxmMapEntry("VlanVid", "VLAN_VID", False),
83 "OFOxmVlanVidMasked": OxmMapEntry("VlanVid", "VLAN_VID", True),
84 "OFOxmVlanPcp": OxmMapEntry("VlanPcp", "VLAN_PCP", False),
85 "OFOxmVlanPcpMasked": OxmMapEntry("VlanPcp", "VLAN_PCP", True),
86 "OFOxmIpDscp": OxmMapEntry("IpDscp", "IP_DSCP", False),
87 "OFOxmIpDscpMasked": OxmMapEntry("IpDscp", "IP_DSCP", True),
88 "OFOxmIpEcn": OxmMapEntry("IpEcn", "IP_ECN", False),
89 "OFOxmIpEcnMasked": OxmMapEntry("IpEcn", "IP_ECN", True),
90 "OFOxmIpProto": OxmMapEntry("IpProtocol", "IP_PROTO", False),
91 "OFOxmIpProtoMasked": OxmMapEntry("IpProtocol", "IP_PROTO", True),
Yotam Harchola289d552013-09-16 10:10:40 -070092 "OFOxmIpv4Src": OxmMapEntry("IPv4Address", "IPV4_SRC", False),
93 "OFOxmIpv4SrcMasked": OxmMapEntry("IPv4Address", "IPV4_SRC", True),
94 "OFOxmIpv4Dst": OxmMapEntry("IPv4Address", "IPV4_DST", False),
95 "OFOxmIpv4DstMasked": OxmMapEntry("IPv4Address", "IPV4_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -070096 "OFOxmTcpSrc": OxmMapEntry("TransportPort", "TCP_SRC", False),
97 "OFOxmTcpSrcMasked": OxmMapEntry("TransportPort", "TCP_SRC", True),
98 "OFOxmTcpDst": OxmMapEntry("TransportPort", "TCP_DST", False),
99 "OFOxmTcpDstMasked": OxmMapEntry("TransportPort", "TCP_DST", True),
100 "OFOxmUdpSrc": OxmMapEntry("TransportPort", "UDP_SRC", False),
101 "OFOxmUdpSrcMasked": OxmMapEntry("TransportPort", "UDP_SRC", True),
102 "OFOxmUdpDst": OxmMapEntry("TransportPort", "UDP_DST", False),
103 "OFOxmUdpDstMasked": OxmMapEntry("TransportPort", "UDP_DST", True),
104 "OFOxmSctpSrc": OxmMapEntry("TransportPort", "SCTP_SRC", False),
105 "OFOxmSctpSrcMasked": OxmMapEntry("TransportPort", "SCTP_SRC", True),
106 "OFOxmSctpDst": OxmMapEntry("TransportPort", "SCTP_DST", False),
107 "OFOxmSctpDstMasked": OxmMapEntry("TransportPort", "SCTP_DST", True),
108 "OFOxmIcmpv4Type": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", False),
109 "OFOxmIcmpv4TypeMasked": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", True),
110 "OFOxmIcmpv4Code": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", False),
111 "OFOxmIcmpv4CodeMasked": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", True),
112 "OFOxmArpOp": OxmMapEntry("ArpOpcode", "ARP_OP", False),
113 "OFOxmArpOpMasked": OxmMapEntry("ArpOpcode", "ARP_OP", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700114 "OFOxmArpSpa": OxmMapEntry("IPv4Address", "ARP_SPA", False),
115 "OFOxmArpSpaMasked": OxmMapEntry("IPv4Address", "ARP_SPA", True),
116 "OFOxmArpTpa": OxmMapEntry("IPv4Address", "ARP_TPA", False),
117 "OFOxmArpTpaMasked": OxmMapEntry("IPv4Address", "ARP_TPA", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700118 "OFOxmArpSha": OxmMapEntry("MacAddress", "ARP_SHA", False),
119 "OFOxmArpShaMasked": OxmMapEntry("MacAddress", "ARP_SHA", True),
120 "OFOxmArpTha": OxmMapEntry("MacAddress", "ARP_THA", False),
121 "OFOxmArpThaMasked": OxmMapEntry("MacAddress", "ARP_THA", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700122 "OFOxmIpv6Src": OxmMapEntry("IPv6Address", "IPV6_SRC", False),
123 "OFOxmIpv6SrcMasked": OxmMapEntry("IPv6Address", "IPV6_SRC", True),
124 "OFOxmIpv6Dst": OxmMapEntry("IPv6Address", "IPV6_DST", False),
125 "OFOxmIpv6DstMasked": OxmMapEntry("IPv6Address", "IPV6_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700126 "OFOxmIpv6Flabel": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", False),
Yotam Harchola86e4252013-09-06 15:36:28 -0700127 "OFOxmIpv6FlabelMasked": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True),
128 "OFOxmIcmpv6Type": OxmMapEntry("U8", "ICMPV6_TYPE", False),
129 "OFOxmIcmpv6TypeMasked": OxmMapEntry("U8", "ICMPV6_TYPE", True),
130 "OFOxmIcmpv6Code": OxmMapEntry("U8", "ICMPV6_CODE", False),
131 "OFOxmIcmpv6CodeMasked": OxmMapEntry("U8", "ICMPV6_CODE", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700132 "OFOxmIpv6NdTarget": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", False),
133 "OFOxmIpv6NdTargetMasked": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", True),
Yotam Harchola86e4252013-09-06 15:36:28 -0700134 "OFOxmIpv6NdSll": OxmMapEntry("MacAddress", "IPV6_ND_SLL", False),
135 "OFOxmIpv6NdSllMasked": OxmMapEntry("MacAddress", "IPV6_ND_SLL", True),
136 "OFOxmIpv6NdTll": OxmMapEntry("MacAddress", "IPV6_ND_TLL", False),
137 "OFOxmIpv6NdTllMasked": OxmMapEntry("MacAddress", "IPV6_ND_TLL", True),
138 "OFOxmMplsLabel": OxmMapEntry("U32", "MPLS_LABEL", False),
139 "OFOxmMplsLabelMasked": OxmMapEntry("U32", "MPLS_LABEL", True),
140 "OFOxmMplsTc": OxmMapEntry("U8", "MPLS_TC", False),
Yotam Harchola11f38b2013-09-26 15:38:17 -0700141 "OFOxmMplsTcMasked": OxmMapEntry("U8", "MPLS_TC", True),
Yotam Harchol2c535582013-10-01 15:50:20 -0700142 "OFOxmBsnInPorts128": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", False),
Rich Lane1424d0b2013-10-24 17:16:24 -0700143 "OFOxmBsnInPorts128Masked": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", True),
Rich Lane376cafe2013-10-27 21:49:14 -0700144 "OFOxmBsnLagId": OxmMapEntry("LagId", "BSN_LAG_ID", False),
145 "OFOxmBsnLagIdMasked": OxmMapEntry("LagId", "BSN_LAG_ID", True),
Rich Laneeb21c4f2013-10-28 17:34:41 -0700146 "OFOxmBsnVrf": OxmMapEntry("VRF", "BSN_VRF", False),
147 "OFOxmBsnVrfMasked": OxmMapEntry("VRF", "BSN_VRF", True),
Rich Lane9c27b5d2013-10-30 17:14:32 -0700148 "OFOxmBsnGlobalVrfAllowed": OxmMapEntry("OFBooleanValue", "BSN_GLOBAL_VRF_ALLOWED", False),
149 "OFOxmBsnGlobalVrfAllowedMasked": OxmMapEntry("OFBooleanValue", "BSN_GLOBAL_VRF_ALLOWED", True),
Rich Laneeb21c4f2013-10-28 17:34:41 -0700150 "OFOxmBsnL3InterfaceClassId": OxmMapEntry("ClassId", "BSN_L3_INTERFACE_CLASS_ID", False),
151 "OFOxmBsnL3InterfaceClassIdMasked": OxmMapEntry("ClassId", "BSN_L3_INTERFACE_CLASS_ID", True),
152 "OFOxmBsnL3SrcClassId": OxmMapEntry("ClassId", "BSN_L3_SRC_CLASS_ID", False),
153 "OFOxmBsnL3SrcClassIdMasked": OxmMapEntry("ClassId", "BSN_L3_SRC_CLASS_ID", True),
154 "OFOxmBsnL3DstClassId": OxmMapEntry("ClassId", "BSN_L3_DST_CLASS_ID", False),
155 "OFOxmBsnL3DstClassIdMasked": OxmMapEntry("ClassId", "BSN_L3_DST_CLASS_ID", True),
Yotam Harchola86e4252013-09-06 15:36:28 -0700156 }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700157
Andreas Wundsamf1949682013-09-23 14:48:31 -0700158 # Registry of nullable properties:
159 # ${java_class_name} -> set(${java_property_name})
160 nullable_map = defaultdict(lambda: set(),
161 )
162
163 # represents a subgroup of a bitmask enum that is actualy a normal enumerable within a masked part of the enum
164 # e.g., the flags STP.* in OF1.0 port state are bit mask entries, but instead enumerables according to the mask "STP_MASK"
165 # name: a name for the group
166 # mask: java name of the enum entry that defines the mask
167 # members: set of names of the members of the group
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700168 MaskedEnumGroup = namedtuple("MaskedEnumGroup", ("name", "mask", "members"))
169
Andreas Wundsamf1949682013-09-23 14:48:31 -0700170 # registry of MaskedEnumGroups (see above).
171 # map: ${java_enum_name}: tuple(MaskedEnumGroup)
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700172 masked_enum_groups = defaultdict(lambda: (),
Andreas Wundsamaebe5182013-09-24 13:01:07 -0700173 OFPortState = (MaskedEnumGroup("stp_flags", mask="STP_MASK", members=set(("STP_LISTEN", "STP_LEARN", "STP_FORWARD", "STP_BLOCK"))), ),
174 OFConfigFlags = (
175 MaskedEnumGroup("frag_flags", mask="FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
Andreas Wundsam376cef52013-09-24 13:52:18 -0700176 ),
177 OFTableConfig = (
178 MaskedEnumGroup("table_miss_flags", mask="TABLE_MISS_MASK", members=set(("TABLE_MISS_CONTROLLER", "TABLE_MISS_CONTINUE", "TABLE_MISS_DROP"))),
179 ),
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700180 )
181
Andreas Wundsamf1949682013-09-23 14:48:31 -0700182 # represents a metadata property associated with an EnumClass
183 # name:
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700184 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700185 """
186 represents a metadata property associated with an Enum Class
187 @param name name of metadata property
188 @param type java_type instance describing the type
189 @value: Generator function f(entry) that generates the value
190 """
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700191 @property
192 def variable_name(self):
193 return self.name[0].lower() + self.name[1:]
194
195 @property
196 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700197 prefix = "is" if self.type == java_type.boolean else "get"
198 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700199
Andreas Wundsamf1949682013-09-23 14:48:31 -0700200 """ Metadata container. """
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700201 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
202
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700203 def gen_port_speed(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700204 """ Generator function for OFortFeatures.PortSpeed"""
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700205 splits = enum_entry.name.split("_")
206 if len(splits)>=2:
207 m = re.match(r'\d+[MGTP]B', splits[1])
208 if m:
209 return "PortSpeed.SPEED_{}".format(splits[1])
210 return "PortSpeed.SPEED_NONE";
211
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700212 def gen_stp_state(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700213 """ Generator function for OFPortState.StpState"""
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700214 splits = enum_entry.name.split("_")
215 if len(splits)>=1:
216 if splits[0] == "STP":
217 return "true"
218 return "false"
219
Andreas Wundsamf1949682013-09-23 14:48:31 -0700220 # registry for metadata properties for enums
221 # map: ${java_enum_name}: OFEnumMetadata
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700222 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700223 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
224 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700225 )
226
Andreas Wundsam27303462013-07-16 12:52:35 -0700227 @property
228 @memoize
229 def versions(self):
230 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
231
232 @property
233 @memoize
234 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700235 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700236
237 for raw_version, of_protocol in of_g.ir.items():
238 jversion = JavaOFVersion(of_protocol.wire_version)
239
240 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700241 if not of_class.name in version_map_per_class:
242 version_map_per_class[of_class.name] = collections.OrderedDict()
243
Andreas Wundsam27303462013-07-16 12:52:35 -0700244 version_map_per_class[of_class.name][jversion] = of_class
245
246 interfaces = []
247 for class_name, version_map in version_map_per_class.items():
248 interfaces.append(JavaOFInterface(class_name, version_map))
249
Andreas Wundsambe168f72013-08-03 22:49:35 -0700250 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
251
Andreas Wundsam27303462013-07-16 12:52:35 -0700252 return interfaces
253
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700254 @memoize
255 def interface_by_name(self, name):
256 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
257
Andreas Wundsam27303462013-07-16 12:52:35 -0700258 @property
259 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700260 def all_classes(self):
261 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
262
263 @property
264 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700265 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700266 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700267
268 for version in self.versions:
269 of_protocol = of_g.ir[version.int_version]
270 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700271 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700272
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700273 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
274 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700275
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700276 # inelegant - need java name here
277 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700278 return enums
279
280 @memoize
281 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700282 res = find(lambda e: e.name == name, self.enums)
283 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700284 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700285 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700286
Andreas Wundsam5204de22013-07-30 11:34:45 -0700287 @property
288 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700289 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700290 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700291
292 factories = OrderedDict()
293
294 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
295 for base_class in sub_factory_classes:
296 package = base_class[2:].lower()
297 remove_prefix = base_class[2].lower() + base_class[3:]
298
299 # HACK need to have a better way to deal with parameterized base classes
300 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
301
302 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700303 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={}, xid_generator=False)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700304
305 factories[""] = OFFactory(
306 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700307 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700308 remove_prefix="",
309 members=[], base_class="OFMessage", sub_factories=OrderedDict(
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700310 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ),
311 xid_generator=True)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700312
313 for i in self.interfaces:
314 for n, factory in factories.items():
315 if n == "":
316 factory.members.append(i)
317 break
318 else:
319 super_class = self.interface_by_name(n)
320 if i.is_instance_of(super_class):
321 factory.members.append(i)
322 break
323 return factories.values()
Yotam Harchol595c6442013-09-27 16:29:08 -0700324
325 @memoize
326 def factory_of(self, interface):
327 for factory in self.of_factories:
328 if interface in factory.members:
329 return factory
330 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700331
332 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700333 """ return wether or not to generate implementation class clazz.
334 Now true for everything except OFTableModVer10.
335 @param clazz JavaOFClass instance
336 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700337 if clazz.interface.name.startswith("OFMatchV"):
338 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700339 elif clazz.name == "OFTableModVer10":
340 # tablemod ver 10 is a hack and has no oftype defined
341 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700342 if loxi_utils.class_is_message(clazz.interface.c_name):
343 return True
344 if loxi_utils.class_is_oxm(clazz.interface.c_name):
345 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700346 if loxi_utils.class_is_action(clazz.interface.c_name):
347 return True
348 if loxi_utils.class_is_instruction(clazz.interface.c_name):
349 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700350 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700351 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700352
353
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700354class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories", "xid_generator"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700355 @property
356 def factory_classes(self):
357 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700358 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700359 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700360 interface=self,
361 version=version
362 ) for version in model.versions ]
363
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700364 def method_name(self, member, builder=True):
365 n = member.variable_name
366 if n.startswith(self.remove_prefix):
367 n = n[len(self.remove_prefix):]
368 n = n[0].lower() + n[1:]
369 if builder:
370 return "build" + n[0].upper() + n[1:]
371 else:
372 return n
Yotam Harchol595c6442013-09-27 16:29:08 -0700373
374 def of_version(self, version):
375 for fc in self.factory_classes:
376 if fc.version == version:
377 return fc
378 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700379
380OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700381class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
382 @property
383 def base_class(self):
384 return self.interface.base_class
385
386 @property
387 def versioned_base_class(self):
388 base_class_interface = model.interface_by_name(self.interface.base_class)
389 if base_class_interface and base_class_interface.has_version(self.version):
390 return base_class_interface.versioned_class(self.version)
391 else:
392 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700393
Andreas Wundsam27303462013-07-16 12:52:35 -0700394model = JavaModel()
395
396#######################################################################
397### OFVersion
398#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700399
400class JavaOFVersion(object):
401 """ Models a version of OpenFlow. contains methods to convert the internal
402 Loxi version to a java constant / a string """
403 def __init__(self, int_version):
404 self.int_version = int(int_version)
405
406 @property
407 def of_version(self):
408 return "1" + str(int(self.int_version) - 1)
409
410 @property
411 def constant_version(self):
412 return "OF_" + self.of_version
413
Andreas Wundsam27303462013-07-16 12:52:35 -0700414 def __repr__(self):
415 return "JavaOFVersion(%d)" % self.int_version
416
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700417 def __str__(self):
418 return of_g.param_version_names[self.int_version]
419
Andreas Wundsam27303462013-07-16 12:52:35 -0700420 def __hash__(self):
421 return hash(self.int_version)
422
423 def __eq__(self, other):
424 if other is None or type(self) != type(other):
425 return False
426 return (self.int_version,) == (other.int_version,)
427
428#######################################################################
429### Interface
430#######################################################################
431
432class JavaOFInterface(object):
433 """ Models an OpenFlow Message class for the purpose of the java class.
434 Version agnostic, in contrast to the loxi_ir python model.
435 """
436 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700437 """"
438 @param c_name: loxi style name (e.g., of_flow_add)
439 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
440 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700441 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700442 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700443 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700444 self.name = java_type.name_c_to_caps_camel(c_name) if c_name != "of_header" else "OFMessage"
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700445 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700446 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700447 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700448 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700449 self.constant_name = c_name.upper().replace("OF_", "")
450
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700451 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700452 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700453 if self.name != parent_interface:
454 self.parent_interface = parent_interface
455 else:
456 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700457
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700458 @property
459 @memoize
460 def all_parent_interfaces(self):
461 return [ "OFObject" ] + \
462 ([ self.parent_interface ] if self.parent_interface else [] )+ \
463 self.additional_parent_interfaces
464 @property
465 @memoize
466 def additional_parent_interfaces(self):
467 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
468 m = re.match(r'(.*)Request$', self.name)
469 if m:
470 reply_name = m.group(1) + "Reply"
471 if model.interface_by_name(reply_name):
472 return ["OFRequest<%s>" % reply_name ]
473 return []
474
475
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700476 def is_instance_of(self, other_class):
477 if self == other_class:
478 return True
479 parent = self.super_class
480 if parent is None:
481 return False
482 else:
483 return parent.is_instance_of(other_class)
484
485 @property
486 def super_class(self):
487 if not self.parent_interface:
488 return None
489 else:
490 return model.interface_by_name(self.parent_interface)
491
492
493 def inherited_declaration(self, type_spec="?"):
494 if self.type_annotation:
495 return "%s<%s>" % (self.name, type_spec)
496 else:
497 return "%s" % self.name
498
499 @property
500 def type_variable(self):
501 if self.type_annotation:
502 return "<T>"
503 else:
504 return "";
505
Andreas Wundsam27303462013-07-16 12:52:35 -0700506 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700507 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
508 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
509 # model (note, that the loxi model is on versioned classes). Should check/infer the
510 # inheritance information from the versioned lox_ir classes.
Andreas Wundsamd6b0cb02013-09-28 18:55:56 -0700511 if re.match(r'OFStatsRequest$', self.name):
512 return ("", "OFMessage", "T extends OFStatsReply")
513 elif re.match(r'OF.+StatsRequest$', self.name):
514 return ("", "OFStatsRequest<{}>".format(re.sub(r'Request$', 'Reply', self.name)), None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700515 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700516 return ("", "OFStatsReply", None)
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700517 elif re.match(r'OF.+ErrorMsg$', self.name):
518 return ("", "OFErrorMsg", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700519 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700520 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700521 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFBsn.+$', self.name) and self.name != "OFBsnHeader":
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700522 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700523 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFNicira.+$', self.name) and self.name != "OFNiciraHeader":
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700524 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700525 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
526 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700527 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700528 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700529 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700530 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700531 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700532 if re.match(r'OFActionBsn.+', self.name):
533 return ("action", "OFActionBsn", None)
534 elif re.match(r'OFActionNicira.+', self.name):
535 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700536 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
537 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700538 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700539 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700540 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700541 return ("", "OFBsnVport", None)
542 elif self.name == "OFOxm":
543 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700544 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700545 if self.name in model.oxm_map:
546 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
547 else:
548 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700549 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700550 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700551 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700552 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700553 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700554 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700555 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700556 return ("", "OFHelloElem", None)
Rich Lane26847562013-10-08 13:44:47 -0700557 elif loxi_utils.class_is_table_feature_prop(self.c_name):
558 return ("", "OFTableFeatureProp", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700559 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700560 return ("", None, None)
561
562 @property
563 @memoize
564 def writeable_members(self):
565 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700566
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700567 @memoize
568 def member_by_name(self, name):
569 return find(lambda m: m.name == name, self.members)
570
Andreas Wundsam27303462013-07-16 12:52:35 -0700571 @property
572 @memoize
573 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700574 return self.ir_model_members + self.virtual_members
575
576 @property
577 @memoize
578 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700579 """return a list of all members to be exposed by this interface. Corresponds to
580 the union of the members of the vesioned classes without length, fieldlength
581 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700582 all_versions = []
583 member_map = collections.OrderedDict()
584
585 for (version, of_class) in self.version_map.items():
586 for of_member in of_class.members:
587 if isinstance(of_member, OFLengthMember) or \
588 isinstance(of_member, OFFieldLengthMember) or \
589 isinstance(of_member, OFPadMember):
590 continue
591 if of_member.name not in member_map:
592 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
593
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700594 return tuple(m for m in member_map.values() if m.name not in model.read_blacklist[self.name])
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700595
596 @property
597 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700598 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700599 if self.name == "OFOxm":
Andreas Wundsama0981022013-10-02 18:15:06 -0700600 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700601 JavaVirtualMember(self, "value", java_type.generic_t),
602 JavaVirtualMember(self, "mask", java_type.generic_t),
603 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
604 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsama0981022013-10-02 18:15:06 -0700605 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700606 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
607 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
608 if self.name in model.oxm_map \
609 else java_type.make_match_field_jtype()
610
Andreas Wundsama0981022013-10-02 18:15:06 -0700611 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700612 JavaVirtualMember(self, "matchField", field_type),
613 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsama0981022013-10-02 18:15:06 -0700614 ]
615 if not find(lambda x: x.name == "mask", self.ir_model_members):
616 virtual_members.append(JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type))
617
618 if not find(lambda m: m.name == "version", self.ir_model_members):
619 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version))
620
621 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700622
623 @property
624 @memoize
625 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700626 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700627 return self.name in model.virtual_interfaces or all(ir_class.virtual for ir_class in self.version_map.values())
Andreas Wundsam27303462013-07-16 12:52:35 -0700628
629 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700630 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700631 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700632 return len(self.all_versions) == len(model.versions)
633
634 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700635 @memoize
636 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700637 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700638 return self.version_map.keys()
639
Andreas Wundsam5204de22013-07-30 11:34:45 -0700640 def has_version(self, version):
641 return version in self.version_map
642
Andreas Wundsam27303462013-07-16 12:52:35 -0700643 def versioned_class(self, version):
644 return JavaOFClass(self, version, self.version_map[version])
645
646 @property
647 @memoize
648 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700649 return [ self.versioned_class(version) for version in self.all_versions ]
650
651#######################################################################
652### (Versioned) Classes
653#######################################################################
654
655class JavaOFClass(object):
656 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700657 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700658 """
659 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700660 """
661 @param interface JavaOFInterface instance of the parent interface
662 @param version JavaOFVersion
663 @param ir_class OFClass from loxi_ir
664 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700665 self.interface = interface
666 self.ir_class = ir_class
667 self.c_name = self.ir_class.name
668 self.version = version
669 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700670 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700671 self.generated = False
672
673 @property
674 @memoize
675 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700676 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700677
678 @property
679 def name(self):
680 return "%sVer%s" % (self.interface.name, self.version.of_version)
681
682 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700683 def variable_name(self):
Andreas Wundsam781d99f2013-10-23 15:25:56 -0700684 return self.name[2].lower() + self.name[3:]
Andreas Wundsam5204de22013-07-30 11:34:45 -0700685
686 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700687 def length(self):
688 if self.is_fixed_length:
689 return self.min_length
690 else:
691 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
692
693 @property
694 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700695 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700696 id_tuple = (self.ir_class.name, self.version.int_version)
697 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
698
699 @property
700 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700701 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700702 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
703 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700704
705 def all_properties(self):
706 return self.interface.members
707
708 def get_member(self, name):
709 for m in self.members:
710 if m.name == name:
711 return m
712
713 @property
714 @memoize
715 def data_members(self):
716 return [ prop for prop in self.members if prop.is_data ]
717
718 @property
719 @memoize
720 def fixed_value_members(self):
721 return [ prop for prop in self.members if prop.is_fixed_value ]
722
723 @property
724 @memoize
725 def public_members(self):
726 return [ prop for prop in self.members if prop.is_public ]
727
728 @property
729 @memoize
730 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700731 return self.ir_model_members + self.virtual_members
732
733 @property
Andreas Wundsama0981022013-10-02 18:15:06 -0700734 @memoize
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700735 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700736 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700737 return tuple(members)
738
739 @property
740 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700741 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700742 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
743 if self.interface.name in model.oxm_map:
744 oxm_entry = model.oxm_map[self.interface.name]
Andreas Wundsama0981022013-10-02 18:15:06 -0700745 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700746 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
747 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
Andreas Wundsama0981022013-10-02 18:15:06 -0700748 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700749 else:
Andreas Wundsama0981022013-10-02 18:15:06 -0700750 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700751 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
752 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
Andreas Wundsama0981022013-10-02 18:15:06 -0700753 ]
754
755 if not find(lambda m: m.name == "version", self.ir_model_members):
756 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version, "OFVersion.%s" % self.version.constant_version))
757
758 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700759
760 def all_versions(self):
761 return [ JavaOFVersion(int_version)
762 for int_version in of_g.unified[self.c_name]
763 if int_version != 'union' and int_version != 'object_id' ]
764
765 def version_is_inherited(self, version):
766 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
767
768 def inherited_from(self, version):
769 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
770
771 @property
772 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700773 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
774
775 @property
776 def discriminator(self):
777 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700778
779 @property
780 def is_extension(self):
781 return type_maps.message_is_extension(self.c_name, -1)
782
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700783 @property
784 def align(self):
785 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
786
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700787 @property
Andreas Wundsam5da68512013-10-22 22:18:00 -0700788 def length_includes_align(self):
789 return self.ir_class.params['length_includes_align'] == "True" if 'length_includes_align' in self.ir_class.params else False
790
791 @property
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700792 @memoize
793 def superclass(self):
794 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
795
796 @property
797 @memoize
798 def subclasses(self):
799 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
800
Andreas Wundsam27303462013-07-16 12:52:35 -0700801#######################################################################
802### Member
803#######################################################################
804
805
806class JavaMember(object):
807 """ Models a property (member) of an openflow class. """
808 def __init__(self, msg, name, java_type, member):
809 self.msg = msg
810 self.name = name
811 self.java_type = java_type
812 self.member = member
813 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700814
815 @property
816 def title_name(self):
817 return self.name[0].upper() + self.name[1:]
818
819 @property
820 def constant_name(self):
821 return self.c_name.upper()
822
823 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700824 def getter_name(self):
825 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
826
827 @property
828 def setter_name(self):
829 return "set" + self.title_name
830
831 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700832 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700833 if self.is_fixed_value:
834 return self.constant_name
835 else:
836 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700837
838 @property
839 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700840 if self.is_fixed_value:
841 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700842 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700843 default = self.java_type.default_op(self.msg.version)
844 if default == "null" and not self.is_nullable:
845 return None
846 else:
847 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700848
849 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700850 def enum_value(self):
851 if self.name == "version":
852 return "OFVersion.%s" % self.msg.version.constant_version
853
854 java_type = self.java_type.public_type;
855 try:
856 global model
857 enum = model.enum_by_name(java_type)
858 entry = enum.entry_by_version_value(self.msg.version, self.value)
859 return "%s.%s" % ( enum.name, entry.name)
860 except KeyError, e:
861 print e.message
862 return self.value
863
864 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700865 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700866 return isinstance(self.member, OFPadMember)
867
868 def is_type_value(self, version=None):
869 if(version==None):
870 return any(self.is_type_value(version) for version in self.msg.all_versions)
871 try:
872 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
873 except:
874 return False
875
876 @property
877 def is_field_length_value(self):
878 return isinstance(self.member, OFFieldLengthMember)
879
880 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700881 def is_discriminator(self):
882 return isinstance(self.member, OFDiscriminatorMember)
883
884 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700885 def is_length_value(self):
886 return isinstance(self.member, OFLengthMember)
887
888 @property
889 def is_public(self):
890 return not (self.is_pad or self.is_length_value)
891
892 @property
893 def is_data(self):
894 return isinstance(self.member, OFDataMember) and self.name != "version"
895
896 @property
897 def is_fixed_value(self):
898 return hasattr(self.member, "value") or self.name == "version" \
899 or ( self.name == "length" and self.msg.is_fixed_length) \
900 or ( self.name == "len" and self.msg.is_fixed_length)
901
902 @property
903 def value(self):
904 if self.name == "version":
905 return self.msg.version.int_version
906 elif self.name == "length" or self.name == "len":
907 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700908 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700909 return self.java_type.format_value(self.member.value)
910
911 @property
912 def priv_value(self):
913 if self.name == "version":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700914 return self.java_type.format_value(self.msg.version.int_version, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700915 elif self.name == "length" or self.name == "len":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700916 return self.java_type.format_value(self.msg.length, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700917 else:
918 return self.java_type.format_value(self.member.value, pub_type=False)
919
Andreas Wundsam27303462013-07-16 12:52:35 -0700920
921 @property
922 def is_writeable(self):
923 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
924
925 def get_type_value_info(self, version):
926 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700927
928 @property
929 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700930 if hasattr(self.member, "length"):
931 return self.member.length
932 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700933 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700934 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700935
936 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700937 def for_of_member(java_class, member):
938 if isinstance(member, OFPadMember):
939 return JavaMember(None, "", None, member)
940 else:
941 if member.name == 'len':
942 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700943 elif member.name == 'value_mask':
944 name = 'mask'
Andreas Wundsamacd57d52013-10-18 17:35:01 -0700945 elif member.name == 'group_id':
946 name = 'group'
Andreas Wundsam27303462013-07-16 12:52:35 -0700947 else:
948 name = java_type.name_c_to_camel(member.name)
949 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
950 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700951
952 @property
953 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700954 if not self.msg.c_name in of_g.unified:
955 print("%s not self.unified" % self.msg.c_name)
956 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700957 for version in of_g.unified[self.msg.c_name]:
958 if version == 'union' or version =='object_id':
959 continue
960 if 'use_version' in of_g.unified[self.msg.c_name][version]:
961 continue
962
Andreas Wundsam27303462013-07-16 12:52:35 -0700963 if not self.member.name in (f['name'] for f in of_g.unified[self.msg.c_name][version]['members']):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700964 return False
965 return True
966
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700967 @property
968 def is_virtual(self):
969 return False
970
Andreas Wundsam27303462013-07-16 12:52:35 -0700971 def __hash__(self):
972 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700973
Andreas Wundsam27303462013-07-16 12:52:35 -0700974 def __eq__(self, other):
975 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700976 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700977 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700978
Andreas Wundsamf1949682013-09-23 14:48:31 -0700979 @property
980 def is_nullable(self):
981 return self.name in model.nullable_map[self.msg.name]
982
983
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700984class JavaVirtualMember(JavaMember):
985 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
Andreas Wundsam4b8661f2013-11-05 17:17:28 -0800986 def __init__(self, msg, name, java_type, value=None, custom_template=None):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700987 JavaMember.__init__(self, msg, name, java_type, member=None)
988 self._value = value
Andreas Wundsam4b8661f2013-11-05 17:17:28 -0800989 self.custom_template = custom_template
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700990
991 @property
992 def is_fixed_value(self):
993 return True
994
995 @property
996 def value(self):
997 return self._value
998
999 @property
1000 def priv_value(self):
1001 return self._value
1002
1003
1004 @property
1005 def is_universal(self):
1006 return True
1007
1008 @property
1009 def is_virtual(self):
1010 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001011
1012#######################################################################
1013### Unit Test
1014#######################################################################
1015
Yotam Harchol466b3212013-08-15 12:14:46 -07001016class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001017 def __init__(self, java_class):
1018 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -07001019 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001020 name=java_class.c_name[3:])
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001021 glob_file_name = "of{version}/{name}__*.data".format(version=java_class.version.of_version,
1022 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -07001023 test_class_name = self.java_class.name + "Test"
1024 self.test_units = []
1025 if test_data.exists(first_data_file_name):
1026 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001027
Yotam Harchol466b3212013-08-15 12:14:46 -07001028 i = 1
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001029 for f in test_data.glob(glob_file_name):
1030 m = re.match(".*__(.*).data", f)
1031 if m:
1032 suffix = java_type.name_c_to_caps_camel(m.group(1))
1033 else:
1034 suffix = str(i)
1035 i += 1
1036 test_class_name = self.java_class.name + suffix + "Test"
1037 self.test_units.append(JavaUnitTest(java_class, f, test_class_name))
Andreas Wundsamf1949682013-09-23 14:48:31 -07001038
Yotam Harchol466b3212013-08-15 12:14:46 -07001039 @property
1040 def package(self):
1041 return self.java_class.package
1042
1043 @property
1044 def has_test_data(self):
1045 return len(self.test_units) > 0
1046
1047 @property
1048 def length(self):
1049 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -07001050
Yotam Harchol466b3212013-08-15 12:14:46 -07001051 def get_test_unit(self, i):
1052 return self.test_units[i]
1053
1054
1055class JavaUnitTest(object):
1056 def __init__(self, java_class, file_name=None, test_class_name=None):
1057 self.java_class = java_class
1058 if file_name is None:
1059 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
1060 name=java_class.c_name[3:])
1061 else:
1062 self.data_file_name = file_name
1063 if test_class_name is None:
1064 self.test_class_name = self.java_class.name + "Test"
1065 else:
1066 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001067
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001068 @property
1069 def package(self):
1070 return self.java_class.package
1071
1072 @property
1073 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001074 return self.test_class_name
Yotam Harchol595c6442013-09-27 16:29:08 -07001075
1076 @property
1077 def interface(self):
1078 return self.java_class.interface
1079
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001080 @property
1081 def has_test_data(self):
1082 return test_data.exists(self.data_file_name)
1083
1084 @property
1085 @memoize
1086 def test_data(self):
1087 return test_data.read(self.data_file_name)
1088
1089
Andreas Wundsam27303462013-07-16 12:52:35 -07001090#######################################################################
1091### Enums
1092#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001093
Andreas Wundsam27303462013-07-16 12:52:35 -07001094class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001095 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001096 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001097
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001098 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001099
Andreas Wundsam27303462013-07-16 12:52:35 -07001100 # Port_features has constants that start with digits
1101 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001102
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001103 self.version_enums = version_enum_map
1104
1105 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1106 for version, ir_enum in version_enum_map.items():
1107 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001108 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1109
Andreas Wundsam27303462013-07-16 12:52:35 -07001110 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001111 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001112
1113 self.entries = [ e for e in self.entries if e.name not in model.enum_entry_blacklist[self.name] ]
Yotam Harchol791e4882013-09-05 16:32:56 -07001114 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001115
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001116 self.metadata = model.enum_metadata_map[self.name]
1117
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001118 def wire_type(self, version):
1119 ir_enum = self.version_enums[version]
1120 if "wire_type" in ir_enum.params:
1121 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1122 else:
1123 return java_type.u8
1124
1125 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001126 @memoize
1127 def is_bitmask(self):
1128 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1129
1130 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001131 def versions(self):
1132 return self.version_enums.keys()
1133
Andreas Wundsam27303462013-07-16 12:52:35 -07001134 @memoize
1135 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001136 res = find(lambda e: e.name == name, self.entries)
1137 if res:
1138 return res
1139 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001140 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1141
1142 @memoize
1143 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001144 res = find(lambda e: e.c_name == name, self.entries)
1145 if res:
1146 return res
1147 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001148 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1149
1150 @memoize
1151 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001152 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1153 if res:
1154 return res
1155 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001156 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1157
1158# values: Map JavaVersion->Value
1159class JavaEnumEntry(object):
1160 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001161 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001162 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1163 self.values = values
1164
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001165 @property
1166 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001167 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001168
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001169 def has_value(self, version):
1170 return version in self.values
1171
Andreas Wundsam27303462013-07-16 12:52:35 -07001172 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001173 return self.values[version]
1174
1175 def format_value(self, version):
1176 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001177 return res
1178
Andreas Wundsam27303462013-07-16 12:52:35 -07001179 def all_values(self, versions, not_present=None):
1180 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001181
1182 @property
1183 @memoize
1184 def masked_enum_group(self):
1185 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1186 return group
1187
1188 @property
1189 @memoize
1190 def is_mask(self):
1191 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])