blob: cc2b93833fc2c1617bc2ca2216bb542e92fef73a [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 Wundsam55b71ce2013-10-01 19:26:46 -070052 enum_blacklist = set(("OFDefinitions", "OFPortNo", "OFVlanId"))
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),
143 "OFOxmBsnInPorts128Masked": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", True)
Yotam Harchola86e4252013-09-06 15:36:28 -0700144 }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700145
Andreas Wundsamf1949682013-09-23 14:48:31 -0700146 # Registry of nullable properties:
147 # ${java_class_name} -> set(${java_property_name})
148 nullable_map = defaultdict(lambda: set(),
149 )
150
151 # represents a subgroup of a bitmask enum that is actualy a normal enumerable within a masked part of the enum
152 # e.g., the flags STP.* in OF1.0 port state are bit mask entries, but instead enumerables according to the mask "STP_MASK"
153 # name: a name for the group
154 # mask: java name of the enum entry that defines the mask
155 # members: set of names of the members of the group
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700156 MaskedEnumGroup = namedtuple("MaskedEnumGroup", ("name", "mask", "members"))
157
Andreas Wundsamf1949682013-09-23 14:48:31 -0700158 # registry of MaskedEnumGroups (see above).
159 # map: ${java_enum_name}: tuple(MaskedEnumGroup)
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700160 masked_enum_groups = defaultdict(lambda: (),
Andreas Wundsamaebe5182013-09-24 13:01:07 -0700161 OFPortState = (MaskedEnumGroup("stp_flags", mask="STP_MASK", members=set(("STP_LISTEN", "STP_LEARN", "STP_FORWARD", "STP_BLOCK"))), ),
162 OFConfigFlags = (
163 MaskedEnumGroup("frag_flags", mask="FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
Andreas Wundsam376cef52013-09-24 13:52:18 -0700164 ),
165 OFTableConfig = (
166 MaskedEnumGroup("table_miss_flags", mask="TABLE_MISS_MASK", members=set(("TABLE_MISS_CONTROLLER", "TABLE_MISS_CONTINUE", "TABLE_MISS_DROP"))),
167 ),
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700168 )
169
Andreas Wundsamf1949682013-09-23 14:48:31 -0700170 # represents a metadata property associated with an EnumClass
171 # name:
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700172 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700173 """
174 represents a metadata property associated with an Enum Class
175 @param name name of metadata property
176 @param type java_type instance describing the type
177 @value: Generator function f(entry) that generates the value
178 """
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700179 @property
180 def variable_name(self):
181 return self.name[0].lower() + self.name[1:]
182
183 @property
184 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700185 prefix = "is" if self.type == java_type.boolean else "get"
186 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700187
Andreas Wundsamf1949682013-09-23 14:48:31 -0700188 """ Metadata container. """
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700189 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
190
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700191 def gen_port_speed(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700192 """ Generator function for OFortFeatures.PortSpeed"""
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700193 splits = enum_entry.name.split("_")
194 if len(splits)>=2:
195 m = re.match(r'\d+[MGTP]B', splits[1])
196 if m:
197 return "PortSpeed.SPEED_{}".format(splits[1])
198 return "PortSpeed.SPEED_NONE";
199
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700200 def gen_stp_state(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700201 """ Generator function for OFPortState.StpState"""
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700202 splits = enum_entry.name.split("_")
203 if len(splits)>=1:
204 if splits[0] == "STP":
205 return "true"
206 return "false"
207
Andreas Wundsamf1949682013-09-23 14:48:31 -0700208 # registry for metadata properties for enums
209 # map: ${java_enum_name}: OFEnumMetadata
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700210 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700211 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
212 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700213 )
214
Andreas Wundsam27303462013-07-16 12:52:35 -0700215 @property
216 @memoize
217 def versions(self):
218 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
219
220 @property
221 @memoize
222 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700223 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700224
225 for raw_version, of_protocol in of_g.ir.items():
226 jversion = JavaOFVersion(of_protocol.wire_version)
227
228 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700229 if not of_class.name in version_map_per_class:
230 version_map_per_class[of_class.name] = collections.OrderedDict()
231
Andreas Wundsam27303462013-07-16 12:52:35 -0700232 version_map_per_class[of_class.name][jversion] = of_class
233
234 interfaces = []
235 for class_name, version_map in version_map_per_class.items():
236 interfaces.append(JavaOFInterface(class_name, version_map))
237
Andreas Wundsambe168f72013-08-03 22:49:35 -0700238 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
239
Andreas Wundsam27303462013-07-16 12:52:35 -0700240 return interfaces
241
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700242 @memoize
243 def interface_by_name(self, name):
244 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
245
Andreas Wundsam27303462013-07-16 12:52:35 -0700246 @property
247 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700248 def all_classes(self):
249 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
250
251 @property
252 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700253 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700254 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700255
256 for version in self.versions:
257 of_protocol = of_g.ir[version.int_version]
258 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700259 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700260
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700261 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
262 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700263
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700264 # inelegant - need java name here
265 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700266 return enums
267
268 @memoize
269 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700270 res = find(lambda e: e.name == name, self.enums)
271 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700272 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700273 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700274
Andreas Wundsam5204de22013-07-30 11:34:45 -0700275 @property
276 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700277 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700278 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700279
280 factories = OrderedDict()
281
282 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
283 for base_class in sub_factory_classes:
284 package = base_class[2:].lower()
285 remove_prefix = base_class[2].lower() + base_class[3:]
286
287 # HACK need to have a better way to deal with parameterized base classes
288 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
289
290 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700291 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 -0700292
293 factories[""] = OFFactory(
294 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700295 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700296 remove_prefix="",
297 members=[], base_class="OFMessage", sub_factories=OrderedDict(
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700298 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ),
299 xid_generator=True)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700300
301 for i in self.interfaces:
302 for n, factory in factories.items():
303 if n == "":
304 factory.members.append(i)
305 break
306 else:
307 super_class = self.interface_by_name(n)
308 if i.is_instance_of(super_class):
309 factory.members.append(i)
310 break
311 return factories.values()
Yotam Harchol595c6442013-09-27 16:29:08 -0700312
313 @memoize
314 def factory_of(self, interface):
315 for factory in self.of_factories:
316 if interface in factory.members:
317 return factory
318 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700319
320 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700321 """ return wether or not to generate implementation class clazz.
322 Now true for everything except OFTableModVer10.
323 @param clazz JavaOFClass instance
324 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700325 if clazz.interface.name.startswith("OFMatchV"):
326 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700327 elif clazz.name == "OFTableModVer10":
328 # tablemod ver 10 is a hack and has no oftype defined
329 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700330 if loxi_utils.class_is_message(clazz.interface.c_name):
331 return True
332 if loxi_utils.class_is_oxm(clazz.interface.c_name):
333 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700334 if loxi_utils.class_is_action(clazz.interface.c_name):
335 return True
336 if loxi_utils.class_is_instruction(clazz.interface.c_name):
337 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700338 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700339 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700340
341
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700342class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories", "xid_generator"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700343 @property
344 def factory_classes(self):
345 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700346 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700347 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700348 interface=self,
349 version=version
350 ) for version in model.versions ]
351
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700352 def method_name(self, member, builder=True):
353 n = member.variable_name
354 if n.startswith(self.remove_prefix):
355 n = n[len(self.remove_prefix):]
356 n = n[0].lower() + n[1:]
357 if builder:
358 return "build" + n[0].upper() + n[1:]
359 else:
360 return n
Yotam Harchol595c6442013-09-27 16:29:08 -0700361
362 def of_version(self, version):
363 for fc in self.factory_classes:
364 if fc.version == version:
365 return fc
366 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700367
368OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700369class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
370 @property
371 def base_class(self):
372 return self.interface.base_class
373
374 @property
375 def versioned_base_class(self):
376 base_class_interface = model.interface_by_name(self.interface.base_class)
377 if base_class_interface and base_class_interface.has_version(self.version):
378 return base_class_interface.versioned_class(self.version)
379 else:
380 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700381
Andreas Wundsam27303462013-07-16 12:52:35 -0700382model = JavaModel()
383
384#######################################################################
385### OFVersion
386#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700387
388class JavaOFVersion(object):
389 """ Models a version of OpenFlow. contains methods to convert the internal
390 Loxi version to a java constant / a string """
391 def __init__(self, int_version):
392 self.int_version = int(int_version)
393
394 @property
395 def of_version(self):
396 return "1" + str(int(self.int_version) - 1)
397
398 @property
399 def constant_version(self):
400 return "OF_" + self.of_version
401
Andreas Wundsam27303462013-07-16 12:52:35 -0700402 def __repr__(self):
403 return "JavaOFVersion(%d)" % self.int_version
404
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700405 def __str__(self):
406 return of_g.param_version_names[self.int_version]
407
Andreas Wundsam27303462013-07-16 12:52:35 -0700408 def __hash__(self):
409 return hash(self.int_version)
410
411 def __eq__(self, other):
412 if other is None or type(self) != type(other):
413 return False
414 return (self.int_version,) == (other.int_version,)
415
416#######################################################################
417### Interface
418#######################################################################
419
420class JavaOFInterface(object):
421 """ Models an OpenFlow Message class for the purpose of the java class.
422 Version agnostic, in contrast to the loxi_ir python model.
423 """
424 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700425 """"
426 @param c_name: loxi style name (e.g., of_flow_add)
427 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
428 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700429 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700430 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700431 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700432 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 -0700433 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700434 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700435 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700436 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700437 self.constant_name = c_name.upper().replace("OF_", "")
438
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700439 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700440 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700441 if self.name != parent_interface:
442 self.parent_interface = parent_interface
443 else:
444 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700445
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700446 @property
447 @memoize
448 def all_parent_interfaces(self):
449 return [ "OFObject" ] + \
450 ([ self.parent_interface ] if self.parent_interface else [] )+ \
451 self.additional_parent_interfaces
452 @property
453 @memoize
454 def additional_parent_interfaces(self):
455 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
456 m = re.match(r'(.*)Request$', self.name)
457 if m:
458 reply_name = m.group(1) + "Reply"
459 if model.interface_by_name(reply_name):
460 return ["OFRequest<%s>" % reply_name ]
461 return []
462
463
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700464 def is_instance_of(self, other_class):
465 if self == other_class:
466 return True
467 parent = self.super_class
468 if parent is None:
469 return False
470 else:
471 return parent.is_instance_of(other_class)
472
473 @property
474 def super_class(self):
475 if not self.parent_interface:
476 return None
477 else:
478 return model.interface_by_name(self.parent_interface)
479
480
481 def inherited_declaration(self, type_spec="?"):
482 if self.type_annotation:
483 return "%s<%s>" % (self.name, type_spec)
484 else:
485 return "%s" % self.name
486
487 @property
488 def type_variable(self):
489 if self.type_annotation:
490 return "<T>"
491 else:
492 return "";
493
Andreas Wundsam27303462013-07-16 12:52:35 -0700494 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700495 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
496 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
497 # model (note, that the loxi model is on versioned classes). Should check/infer the
498 # inheritance information from the versioned lox_ir classes.
Andreas Wundsamd6b0cb02013-09-28 18:55:56 -0700499 if re.match(r'OFStatsRequest$', self.name):
500 return ("", "OFMessage", "T extends OFStatsReply")
501 elif re.match(r'OF.+StatsRequest$', self.name):
502 return ("", "OFStatsRequest<{}>".format(re.sub(r'Request$', 'Reply', self.name)), None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700503 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700504 return ("", "OFStatsReply", None)
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700505 elif re.match(r'OF.+ErrorMsg$', self.name):
506 return ("", "OFErrorMsg", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700507 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700508 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700509 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 -0700510 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700511 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 -0700512 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700513 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
514 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700515 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700516 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700517 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700518 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700519 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700520 if re.match(r'OFActionBsn.+', self.name):
521 return ("action", "OFActionBsn", None)
522 elif re.match(r'OFActionNicira.+', self.name):
523 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700524 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
525 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700526 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700527 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700528 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700529 return ("", "OFBsnVport", None)
530 elif self.name == "OFOxm":
531 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700532 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700533 if self.name in model.oxm_map:
534 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
535 else:
536 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700537 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700538 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700539 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700540 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700541 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700542 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700543 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700544 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700545 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700546 return ("", None, None)
547
548 @property
549 @memoize
550 def writeable_members(self):
551 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700552
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700553 @memoize
554 def member_by_name(self, name):
555 return find(lambda m: m.name == name, self.members)
556
Andreas Wundsam27303462013-07-16 12:52:35 -0700557 @property
558 @memoize
559 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700560 return self.ir_model_members + self.virtual_members
561
562 @property
563 @memoize
564 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700565 """return a list of all members to be exposed by this interface. Corresponds to
566 the union of the members of the vesioned classes without length, fieldlength
567 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700568 all_versions = []
569 member_map = collections.OrderedDict()
570
571 for (version, of_class) in self.version_map.items():
572 for of_member in of_class.members:
573 if isinstance(of_member, OFLengthMember) or \
574 isinstance(of_member, OFFieldLengthMember) or \
575 isinstance(of_member, OFPadMember):
576 continue
577 if of_member.name not in member_map:
578 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
579
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700580 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 -0700581
582 @property
583 def virtual_members(self):
584 if self.name == "OFOxm":
585 return (
586 JavaVirtualMember(self, "value", java_type.generic_t),
587 JavaVirtualMember(self, "mask", java_type.generic_t),
588 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
589 JavaVirtualMember(self, "masked", java_type.boolean),
590 )
591 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
592 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
593 if self.name in model.oxm_map \
594 else java_type.make_match_field_jtype()
595
596 return (
597 JavaVirtualMember(self, "matchField", field_type),
598 JavaVirtualMember(self, "masked", java_type.boolean),
599 ) \
600 + \
601 (
602 ( JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type), ) if not find(lambda x: x.name == "mask", self.ir_model_members) else
603 ()
604 )
605 else:
606 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700607
608 @property
609 @memoize
610 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700611 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700612 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 -0700613
614 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700615 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700616 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700617 return len(self.all_versions) == len(model.versions)
618
619 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700620 @memoize
621 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700622 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700623 return self.version_map.keys()
624
Andreas Wundsam5204de22013-07-30 11:34:45 -0700625 def has_version(self, version):
626 return version in self.version_map
627
Andreas Wundsam27303462013-07-16 12:52:35 -0700628 def versioned_class(self, version):
629 return JavaOFClass(self, version, self.version_map[version])
630
631 @property
632 @memoize
633 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700634 return [ self.versioned_class(version) for version in self.all_versions ]
635
636#######################################################################
637### (Versioned) Classes
638#######################################################################
639
640class JavaOFClass(object):
641 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700642 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700643 """
644 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700645 """
646 @param interface JavaOFInterface instance of the parent interface
647 @param version JavaOFVersion
648 @param ir_class OFClass from loxi_ir
649 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700650 self.interface = interface
651 self.ir_class = ir_class
652 self.c_name = self.ir_class.name
653 self.version = version
654 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700655 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700656 self.generated = False
657
658 @property
659 @memoize
660 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700661 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700662
663 @property
664 def name(self):
665 return "%sVer%s" % (self.interface.name, self.version.of_version)
666
667 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700668 def variable_name(self):
669 return self.name[3:]
670
671 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700672 def length(self):
673 if self.is_fixed_length:
674 return self.min_length
675 else:
676 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
677
678 @property
679 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700680 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700681 id_tuple = (self.ir_class.name, self.version.int_version)
682 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
683
684 @property
685 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700686 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700687 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
688 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700689
690 def all_properties(self):
691 return self.interface.members
692
693 def get_member(self, name):
694 for m in self.members:
695 if m.name == name:
696 return m
697
698 @property
699 @memoize
700 def data_members(self):
701 return [ prop for prop in self.members if prop.is_data ]
702
703 @property
704 @memoize
705 def fixed_value_members(self):
706 return [ prop for prop in self.members if prop.is_fixed_value ]
707
708 @property
709 @memoize
710 def public_members(self):
711 return [ prop for prop in self.members if prop.is_public ]
712
713 @property
714 @memoize
715 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700716 return self.ir_model_members + self.virtual_members
717
718 @property
719 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700720 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700721 return tuple(members)
722
723 @property
724 def virtual_members(self):
725 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
726 if self.interface.name in model.oxm_map:
727 oxm_entry = model.oxm_map[self.interface.name]
728 return (
729 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
730 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
731 )
732 else:
733 return (
734 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
735 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
736 )
737 else:
738 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700739
740 def all_versions(self):
741 return [ JavaOFVersion(int_version)
742 for int_version in of_g.unified[self.c_name]
743 if int_version != 'union' and int_version != 'object_id' ]
744
745 def version_is_inherited(self, version):
746 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
747
748 def inherited_from(self, version):
749 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
750
751 @property
752 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700753 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
754
755 @property
756 def discriminator(self):
757 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700758
759 @property
760 def is_extension(self):
761 return type_maps.message_is_extension(self.c_name, -1)
762
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700763 @property
764 def align(self):
765 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
766
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700767 @property
768 @memoize
769 def superclass(self):
770 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
771
772 @property
773 @memoize
774 def subclasses(self):
775 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
776
Andreas Wundsam27303462013-07-16 12:52:35 -0700777#######################################################################
778### Member
779#######################################################################
780
781
782class JavaMember(object):
783 """ Models a property (member) of an openflow class. """
784 def __init__(self, msg, name, java_type, member):
785 self.msg = msg
786 self.name = name
787 self.java_type = java_type
788 self.member = member
789 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700790
791 @property
792 def title_name(self):
793 return self.name[0].upper() + self.name[1:]
794
795 @property
796 def constant_name(self):
797 return self.c_name.upper()
798
799 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700800 def getter_name(self):
801 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
802
803 @property
804 def setter_name(self):
805 return "set" + self.title_name
806
807 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700808 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700809 if self.is_fixed_value:
810 return self.constant_name
811 else:
812 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700813
814 @property
815 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700816 if self.is_fixed_value:
817 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700818 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700819 default = self.java_type.default_op(self.msg.version)
820 if default == "null" and not self.is_nullable:
821 return None
822 else:
823 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700824
825 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700826 def enum_value(self):
827 if self.name == "version":
828 return "OFVersion.%s" % self.msg.version.constant_version
829
830 java_type = self.java_type.public_type;
831 try:
832 global model
833 enum = model.enum_by_name(java_type)
834 entry = enum.entry_by_version_value(self.msg.version, self.value)
835 return "%s.%s" % ( enum.name, entry.name)
836 except KeyError, e:
837 print e.message
838 return self.value
839
840 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700841 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700842 return isinstance(self.member, OFPadMember)
843
844 def is_type_value(self, version=None):
845 if(version==None):
846 return any(self.is_type_value(version) for version in self.msg.all_versions)
847 try:
848 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
849 except:
850 return False
851
852 @property
853 def is_field_length_value(self):
854 return isinstance(self.member, OFFieldLengthMember)
855
856 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700857 def is_discriminator(self):
858 return isinstance(self.member, OFDiscriminatorMember)
859
860 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700861 def is_length_value(self):
862 return isinstance(self.member, OFLengthMember)
863
864 @property
865 def is_public(self):
866 return not (self.is_pad or self.is_length_value)
867
868 @property
869 def is_data(self):
870 return isinstance(self.member, OFDataMember) and self.name != "version"
871
872 @property
873 def is_fixed_value(self):
874 return hasattr(self.member, "value") or self.name == "version" \
875 or ( self.name == "length" and self.msg.is_fixed_length) \
876 or ( self.name == "len" and self.msg.is_fixed_length)
877
878 @property
879 def value(self):
880 if self.name == "version":
881 return self.msg.version.int_version
882 elif self.name == "length" or self.name == "len":
883 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700884 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700885 return self.java_type.format_value(self.member.value)
886
887 @property
888 def priv_value(self):
889 if self.name == "version":
890 return self.msg.version.int_version
891 elif self.name == "length" or self.name == "len":
892 return self.msg.length
893 else:
894 return self.java_type.format_value(self.member.value, pub_type=False)
895
Andreas Wundsam27303462013-07-16 12:52:35 -0700896
897 @property
898 def is_writeable(self):
899 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
900
901 def get_type_value_info(self, version):
902 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700903
904 @property
905 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700906 if hasattr(self.member, "length"):
907 return self.member.length
908 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700909 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700910 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700911
912 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700913 def for_of_member(java_class, member):
914 if isinstance(member, OFPadMember):
915 return JavaMember(None, "", None, member)
916 else:
917 if member.name == 'len':
918 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700919 elif member.name == 'value_mask':
920 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700921 else:
922 name = java_type.name_c_to_camel(member.name)
923 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
924 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700925
926 @property
927 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700928 if not self.msg.c_name in of_g.unified:
929 print("%s not self.unified" % self.msg.c_name)
930 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700931 for version in of_g.unified[self.msg.c_name]:
932 if version == 'union' or version =='object_id':
933 continue
934 if 'use_version' in of_g.unified[self.msg.c_name][version]:
935 continue
936
Andreas Wundsam27303462013-07-16 12:52:35 -0700937 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 -0700938 return False
939 return True
940
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700941 @property
942 def is_virtual(self):
943 return False
944
Andreas Wundsam27303462013-07-16 12:52:35 -0700945 def __hash__(self):
946 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700947
Andreas Wundsam27303462013-07-16 12:52:35 -0700948 def __eq__(self, other):
949 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700950 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700951 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700952
Andreas Wundsamf1949682013-09-23 14:48:31 -0700953 @property
954 def is_nullable(self):
955 return self.name in model.nullable_map[self.msg.name]
956
957
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700958class JavaVirtualMember(JavaMember):
959 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
960 def __init__(self, msg, name, java_type, value=None):
961 JavaMember.__init__(self, msg, name, java_type, member=None)
962 self._value = value
963
964 @property
965 def is_fixed_value(self):
966 return True
967
968 @property
969 def value(self):
970 return self._value
971
972 @property
973 def priv_value(self):
974 return self._value
975
976
977 @property
978 def is_universal(self):
979 return True
980
981 @property
982 def is_virtual(self):
983 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700984
985#######################################################################
986### Unit Test
987#######################################################################
988
Yotam Harchol466b3212013-08-15 12:14:46 -0700989class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700990 def __init__(self, java_class):
991 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700992 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700993 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700994 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
995 name=java_class.c_name[3:]) + "{i}.data"
996 test_class_name = self.java_class.name + "Test"
997 self.test_units = []
998 if test_data.exists(first_data_file_name):
999 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
1000 i = 1
1001 while test_data.exists(data_file_template.format(i=i)):
1002 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
1003 i = i + 1
Andreas Wundsamf1949682013-09-23 14:48:31 -07001004
Yotam Harchol466b3212013-08-15 12:14:46 -07001005 @property
1006 def package(self):
1007 return self.java_class.package
1008
1009 @property
1010 def has_test_data(self):
1011 return len(self.test_units) > 0
1012
1013 @property
1014 def length(self):
1015 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -07001016
Yotam Harchol466b3212013-08-15 12:14:46 -07001017 def get_test_unit(self, i):
1018 return self.test_units[i]
1019
1020
1021class JavaUnitTest(object):
1022 def __init__(self, java_class, file_name=None, test_class_name=None):
1023 self.java_class = java_class
1024 if file_name is None:
1025 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
1026 name=java_class.c_name[3:])
1027 else:
1028 self.data_file_name = file_name
1029 if test_class_name is None:
1030 self.test_class_name = self.java_class.name + "Test"
1031 else:
1032 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001033
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001034 @property
1035 def package(self):
1036 return self.java_class.package
1037
1038 @property
1039 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001040 return self.test_class_name
Yotam Harchol595c6442013-09-27 16:29:08 -07001041
1042 @property
1043 def interface(self):
1044 return self.java_class.interface
1045
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001046 @property
1047 def has_test_data(self):
1048 return test_data.exists(self.data_file_name)
1049
1050 @property
1051 @memoize
1052 def test_data(self):
1053 return test_data.read(self.data_file_name)
1054
1055
Andreas Wundsam27303462013-07-16 12:52:35 -07001056#######################################################################
1057### Enums
1058#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001059
Andreas Wundsam27303462013-07-16 12:52:35 -07001060class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001061 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001062 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001063
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001064 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001065
Andreas Wundsam27303462013-07-16 12:52:35 -07001066 # Port_features has constants that start with digits
1067 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001068
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001069 self.version_enums = version_enum_map
1070
1071 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1072 for version, ir_enum in version_enum_map.items():
1073 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001074 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1075
Andreas Wundsam27303462013-07-16 12:52:35 -07001076 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001077 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001078
1079 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 -07001080 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001081
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001082 self.metadata = model.enum_metadata_map[self.name]
1083
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001084 def wire_type(self, version):
1085 ir_enum = self.version_enums[version]
1086 if "wire_type" in ir_enum.params:
1087 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1088 else:
1089 return java_type.u8
1090
1091 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001092 @memoize
1093 def is_bitmask(self):
1094 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1095
1096 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001097 def versions(self):
1098 return self.version_enums.keys()
1099
Andreas Wundsam27303462013-07-16 12:52:35 -07001100 @memoize
1101 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001102 res = find(lambda e: e.name == name, self.entries)
1103 if res:
1104 return res
1105 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001106 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1107
1108 @memoize
1109 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001110 res = find(lambda e: e.c_name == name, self.entries)
1111 if res:
1112 return res
1113 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001114 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1115
1116 @memoize
1117 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001118 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1119 if res:
1120 return res
1121 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001122 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1123
1124# values: Map JavaVersion->Value
1125class JavaEnumEntry(object):
1126 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001127 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001128 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1129 self.values = values
1130
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001131 @property
1132 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001133 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001134
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001135 def has_value(self, version):
1136 return version in self.values
1137
Andreas Wundsam27303462013-07-16 12:52:35 -07001138 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001139 return self.values[version]
1140
1141 def format_value(self, version):
1142 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001143 return res
1144
Andreas Wundsam27303462013-07-16 12:52:35 -07001145 def all_values(self, versions, not_present=None):
1146 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001147
1148 @property
1149 @memoize
1150 def masked_enum_group(self):
1151 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1152 return group
1153
1154 @property
1155 @memoize
1156 def is_mask(self):
1157 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])