blob: 9fab4221bf44b4a4ada3067f04d148aff5a0e4fb [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 Wundsam43526532013-08-01 22:03:50 -070050 enum_blacklist = set(("OFDefinitions",))
51 enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
Andreas Wundsambe168f72013-08-03 22:49:35 -070052 # OFUint structs are there for god-knows what in loci. We certainly don't need them.
53 interface_blacklist = set( ("OFUint8", "OFUint32",))
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070054 read_blacklist = defaultdict(lambda: set(), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
55 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 Wundsam001b1822013-08-02 22:25:55 -070056 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070057
Andreas Wundsam2be7da52013-08-22 07:34:25 -070058 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
Yotam Harchole5d92972013-08-22 14:18:36 -070059 oxm_map = { "OFOxmInPort": OxmMapEntry("OFPort", "IN_PORT", False),
60 "OFOxmInPortMasked": OxmMapEntry("OFPort", "IN_PORT", True),
61 "OFOxmInPhyPort": OxmMapEntry("OFPort", "IN_PHY_PORT", False),
62 "OFOxmInPhyPortMasked": OxmMapEntry("OFPort", "IN_PHY_PORT", True),
63 "OFOxmMetadata": OxmMapEntry("OFMetadata", "METADATA", False),
64 "OFOxmMetadataMasked": OxmMapEntry("OFMetadata", "METADATA", True),
65 "OFOxmEthDst": OxmMapEntry("MacAddress", "ETH_DST", False),
66 "OFOxmEthDstMasked": OxmMapEntry("MacAddress", "ETH_DST", True),
67 "OFOxmEthSrc": OxmMapEntry("MacAddress", "ETH_SRC", False),
68 "OFOxmEthSrcMasked": OxmMapEntry("MacAddress", "ETH_SRC", True),
69 "OFOxmEthType": OxmMapEntry("EthType", "ETH_TYPE", False),
70 "OFOxmEthTypeMasked": OxmMapEntry("EthType", "ETH_TYPE", True),
71 "OFOxmVlanVid": OxmMapEntry("VlanVid", "VLAN_VID", False),
72 "OFOxmVlanVidMasked": OxmMapEntry("VlanVid", "VLAN_VID", True),
73 "OFOxmVlanPcp": OxmMapEntry("VlanPcp", "VLAN_PCP", False),
74 "OFOxmVlanPcpMasked": OxmMapEntry("VlanPcp", "VLAN_PCP", True),
75 "OFOxmIpDscp": OxmMapEntry("IpDscp", "IP_DSCP", False),
76 "OFOxmIpDscpMasked": OxmMapEntry("IpDscp", "IP_DSCP", True),
77 "OFOxmIpEcn": OxmMapEntry("IpEcn", "IP_ECN", False),
78 "OFOxmIpEcnMasked": OxmMapEntry("IpEcn", "IP_ECN", True),
79 "OFOxmIpProto": OxmMapEntry("IpProtocol", "IP_PROTO", False),
80 "OFOxmIpProtoMasked": OxmMapEntry("IpProtocol", "IP_PROTO", True),
Yotam Harchola289d552013-09-16 10:10:40 -070081 "OFOxmIpv4Src": OxmMapEntry("IPv4Address", "IPV4_SRC", False),
82 "OFOxmIpv4SrcMasked": OxmMapEntry("IPv4Address", "IPV4_SRC", True),
83 "OFOxmIpv4Dst": OxmMapEntry("IPv4Address", "IPV4_DST", False),
84 "OFOxmIpv4DstMasked": OxmMapEntry("IPv4Address", "IPV4_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -070085 "OFOxmTcpSrc": OxmMapEntry("TransportPort", "TCP_SRC", False),
86 "OFOxmTcpSrcMasked": OxmMapEntry("TransportPort", "TCP_SRC", True),
87 "OFOxmTcpDst": OxmMapEntry("TransportPort", "TCP_DST", False),
88 "OFOxmTcpDstMasked": OxmMapEntry("TransportPort", "TCP_DST", True),
89 "OFOxmUdpSrc": OxmMapEntry("TransportPort", "UDP_SRC", False),
90 "OFOxmUdpSrcMasked": OxmMapEntry("TransportPort", "UDP_SRC", True),
91 "OFOxmUdpDst": OxmMapEntry("TransportPort", "UDP_DST", False),
92 "OFOxmUdpDstMasked": OxmMapEntry("TransportPort", "UDP_DST", True),
93 "OFOxmSctpSrc": OxmMapEntry("TransportPort", "SCTP_SRC", False),
94 "OFOxmSctpSrcMasked": OxmMapEntry("TransportPort", "SCTP_SRC", True),
95 "OFOxmSctpDst": OxmMapEntry("TransportPort", "SCTP_DST", False),
96 "OFOxmSctpDstMasked": OxmMapEntry("TransportPort", "SCTP_DST", True),
97 "OFOxmIcmpv4Type": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", False),
98 "OFOxmIcmpv4TypeMasked": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", True),
99 "OFOxmIcmpv4Code": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", False),
100 "OFOxmIcmpv4CodeMasked": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", True),
101 "OFOxmArpOp": OxmMapEntry("ArpOpcode", "ARP_OP", False),
102 "OFOxmArpOpMasked": OxmMapEntry("ArpOpcode", "ARP_OP", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700103 "OFOxmArpSpa": OxmMapEntry("IPv4Address", "ARP_SPA", False),
104 "OFOxmArpSpaMasked": OxmMapEntry("IPv4Address", "ARP_SPA", True),
105 "OFOxmArpTpa": OxmMapEntry("IPv4Address", "ARP_TPA", False),
106 "OFOxmArpTpaMasked": OxmMapEntry("IPv4Address", "ARP_TPA", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700107 "OFOxmArpSha": OxmMapEntry("MacAddress", "ARP_SHA", False),
108 "OFOxmArpShaMasked": OxmMapEntry("MacAddress", "ARP_SHA", True),
109 "OFOxmArpTha": OxmMapEntry("MacAddress", "ARP_THA", False),
110 "OFOxmArpThaMasked": OxmMapEntry("MacAddress", "ARP_THA", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700111 "OFOxmIpv6Src": OxmMapEntry("IPv6Address", "IPV6_SRC", False),
112 "OFOxmIpv6SrcMasked": OxmMapEntry("IPv6Address", "IPV6_SRC", True),
113 "OFOxmIpv6Dst": OxmMapEntry("IPv6Address", "IPV6_DST", False),
114 "OFOxmIpv6DstMasked": OxmMapEntry("IPv6Address", "IPV6_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700115 "OFOxmIpv6Flabel": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", False),
Yotam Harchola86e4252013-09-06 15:36:28 -0700116 "OFOxmIpv6FlabelMasked": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True),
117 "OFOxmIcmpv6Type": OxmMapEntry("U8", "ICMPV6_TYPE", False),
118 "OFOxmIcmpv6TypeMasked": OxmMapEntry("U8", "ICMPV6_TYPE", True),
119 "OFOxmIcmpv6Code": OxmMapEntry("U8", "ICMPV6_CODE", False),
120 "OFOxmIcmpv6CodeMasked": OxmMapEntry("U8", "ICMPV6_CODE", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700121 "OFOxmIpv6NdTarget": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", False),
122 "OFOxmIpv6NdTargetMasked": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", True),
Yotam Harchola86e4252013-09-06 15:36:28 -0700123 "OFOxmIpv6NdSll": OxmMapEntry("MacAddress", "IPV6_ND_SLL", False),
124 "OFOxmIpv6NdSllMasked": OxmMapEntry("MacAddress", "IPV6_ND_SLL", True),
125 "OFOxmIpv6NdTll": OxmMapEntry("MacAddress", "IPV6_ND_TLL", False),
126 "OFOxmIpv6NdTllMasked": OxmMapEntry("MacAddress", "IPV6_ND_TLL", True),
127 "OFOxmMplsLabel": OxmMapEntry("U32", "MPLS_LABEL", False),
128 "OFOxmMplsLabelMasked": OxmMapEntry("U32", "MPLS_LABEL", True),
129 "OFOxmMplsTc": OxmMapEntry("U8", "MPLS_TC", False),
130 "OFOxmMplsTcMasked": OxmMapEntry("U8", "MPLS_TC", True)
131 }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700132
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700133 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700134 @property
135 def variable_name(self):
136 return self.name[0].lower() + self.name[1:]
137
138 @property
139 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700140 prefix = "is" if self.type == java_type.boolean else "get"
141 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700142
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700143 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
144
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700145 def gen_port_speed(enum_entry):
146 splits = enum_entry.name.split("_")
147 if len(splits)>=2:
148 m = re.match(r'\d+[MGTP]B', splits[1])
149 if m:
150 return "PortSpeed.SPEED_{}".format(splits[1])
151 return "PortSpeed.SPEED_NONE";
152
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700153 def gen_stp_state(enum_entry):
154 splits = enum_entry.name.split("_")
155 if len(splits)>=1:
156 if splits[0] == "STP":
157 return "true"
158 return "false"
159
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700160 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700161 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
162 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700163 )
164
Andreas Wundsam27303462013-07-16 12:52:35 -0700165 @property
166 @memoize
167 def versions(self):
168 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
169
170 @property
171 @memoize
172 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700173 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700174
175 for raw_version, of_protocol in of_g.ir.items():
176 jversion = JavaOFVersion(of_protocol.wire_version)
177
178 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700179 if not of_class.name in version_map_per_class:
180 version_map_per_class[of_class.name] = collections.OrderedDict()
181
Andreas Wundsam27303462013-07-16 12:52:35 -0700182 version_map_per_class[of_class.name][jversion] = of_class
183
184 interfaces = []
185 for class_name, version_map in version_map_per_class.items():
186 interfaces.append(JavaOFInterface(class_name, version_map))
187
Andreas Wundsambe168f72013-08-03 22:49:35 -0700188 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
189
Andreas Wundsam27303462013-07-16 12:52:35 -0700190 return interfaces
191
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700192 @memoize
193 def interface_by_name(self, name):
194 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
195
Andreas Wundsam27303462013-07-16 12:52:35 -0700196 @property
197 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700198 def all_classes(self):
199 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
200
201 @property
202 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700203 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700204 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700205
206 for version in self.versions:
207 of_protocol = of_g.ir[version.int_version]
208 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700209 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700210
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700211 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
212 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700213
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700214 # inelegant - need java name here
215 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700216 return enums
217
218 @memoize
219 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700220 res = find(lambda e: e.name == name, self.enums)
221 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700222 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700223 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700224
Andreas Wundsam5204de22013-07-30 11:34:45 -0700225 @property
226 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700227 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700228 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700229
230 factories = OrderedDict()
231
232 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
233 for base_class in sub_factory_classes:
234 package = base_class[2:].lower()
235 remove_prefix = base_class[2].lower() + base_class[3:]
236
237 # HACK need to have a better way to deal with parameterized base classes
238 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
239
240 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
241 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
242
243 factories[""] = OFFactory(
244 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700245 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700246 remove_prefix="",
247 members=[], base_class="OFMessage", sub_factories=OrderedDict(
248 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
249
250 for i in self.interfaces:
251 for n, factory in factories.items():
252 if n == "":
253 factory.members.append(i)
254 break
255 else:
256 super_class = self.interface_by_name(n)
257 if i.is_instance_of(super_class):
258 factory.members.append(i)
259 break
260 return factories.values()
Andreas Wundsam5204de22013-07-30 11:34:45 -0700261
262 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700263 """ return wether or not to generate implementation class clazz.
264 Now true for everything except OFTableModVer10.
265 @param clazz JavaOFClass instance
266 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700267 if clazz.interface.name.startswith("OFMatchV"):
268 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700269 elif clazz.name == "OFTableModVer10":
270 # tablemod ver 10 is a hack and has no oftype defined
271 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700272 if loxi_utils.class_is_message(clazz.interface.c_name):
273 return True
274 if loxi_utils.class_is_oxm(clazz.interface.c_name):
275 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700276 if loxi_utils.class_is_action(clazz.interface.c_name):
277 return True
278 if loxi_utils.class_is_instruction(clazz.interface.c_name):
279 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700280 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700281 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700282
283
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700284class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700285 @property
286 def factory_classes(self):
287 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700288 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700289 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700290 interface=self,
291 version=version
292 ) for version in model.versions ]
293
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700294 def method_name(self, member, builder=True):
295 n = member.variable_name
296 if n.startswith(self.remove_prefix):
297 n = n[len(self.remove_prefix):]
298 n = n[0].lower() + n[1:]
299 if builder:
300 return "build" + n[0].upper() + n[1:]
301 else:
302 return n
Andreas Wundsam5204de22013-07-30 11:34:45 -0700303
304OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700305class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
306 @property
307 def base_class(self):
308 return self.interface.base_class
309
310 @property
311 def versioned_base_class(self):
312 base_class_interface = model.interface_by_name(self.interface.base_class)
313 if base_class_interface and base_class_interface.has_version(self.version):
314 return base_class_interface.versioned_class(self.version)
315 else:
316 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700317
Andreas Wundsam27303462013-07-16 12:52:35 -0700318model = JavaModel()
319
320#######################################################################
321### OFVersion
322#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700323
324class JavaOFVersion(object):
325 """ Models a version of OpenFlow. contains methods to convert the internal
326 Loxi version to a java constant / a string """
327 def __init__(self, int_version):
328 self.int_version = int(int_version)
329
330 @property
331 def of_version(self):
332 return "1" + str(int(self.int_version) - 1)
333
334 @property
335 def constant_version(self):
336 return "OF_" + self.of_version
337
Andreas Wundsam27303462013-07-16 12:52:35 -0700338 def __repr__(self):
339 return "JavaOFVersion(%d)" % self.int_version
340
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700341 def __str__(self):
342 return of_g.param_version_names[self.int_version]
343
Andreas Wundsam27303462013-07-16 12:52:35 -0700344 def __hash__(self):
345 return hash(self.int_version)
346
347 def __eq__(self, other):
348 if other is None or type(self) != type(other):
349 return False
350 return (self.int_version,) == (other.int_version,)
351
352#######################################################################
353### Interface
354#######################################################################
355
356class JavaOFInterface(object):
357 """ Models an OpenFlow Message class for the purpose of the java class.
358 Version agnostic, in contrast to the loxi_ir python model.
359 """
360 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700361 """"
362 @param c_name: loxi style name (e.g., of_flow_add)
363 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
364 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700365 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700366 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700367 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700368 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 -0700369 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700370 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700371 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700372 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700373 self.constant_name = c_name.upper().replace("OF_", "")
374
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700375 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700376 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700377 if self.name != parent_interface:
378 self.parent_interface = parent_interface
379 else:
380 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700381
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700382 @property
383 @memoize
384 def all_parent_interfaces(self):
385 return [ "OFObject" ] + \
386 ([ self.parent_interface ] if self.parent_interface else [] )+ \
387 self.additional_parent_interfaces
388 @property
389 @memoize
390 def additional_parent_interfaces(self):
391 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
392 m = re.match(r'(.*)Request$', self.name)
393 if m:
394 reply_name = m.group(1) + "Reply"
395 if model.interface_by_name(reply_name):
396 return ["OFRequest<%s>" % reply_name ]
397 return []
398
399
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700400 def is_instance_of(self, other_class):
401 if self == other_class:
402 return True
403 parent = self.super_class
404 if parent is None:
405 return False
406 else:
407 return parent.is_instance_of(other_class)
408
409 @property
410 def super_class(self):
411 if not self.parent_interface:
412 return None
413 else:
414 return model.interface_by_name(self.parent_interface)
415
416
417 def inherited_declaration(self, type_spec="?"):
418 if self.type_annotation:
419 return "%s<%s>" % (self.name, type_spec)
420 else:
421 return "%s" % self.name
422
423 @property
424 def type_variable(self):
425 if self.type_annotation:
426 return "<T>"
427 else:
428 return "";
429
Andreas Wundsam27303462013-07-16 12:52:35 -0700430 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700431 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
432 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
433 # model (note, that the loxi model is on versioned classes). Should check/infer the
434 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700435 if re.match(r'OF.+StatsRequest$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700436 return ("", "OFStatsRequest", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700437 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700438 return ("", "OFStatsReply", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700439 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700440 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700441 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 -0700442 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700443 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 -0700444 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700445 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
446 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700447 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700448 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700449 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700450 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700451 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700452 if re.match(r'OFActionBsn.+', self.name):
453 return ("action", "OFActionBsn", None)
454 elif re.match(r'OFActionNicira.+', self.name):
455 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700456 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
457 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700458 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700459 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700460 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700461 return ("", "OFBsnVport", None)
462 elif self.name == "OFOxm":
463 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700464 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700465 if self.name in model.oxm_map:
466 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
467 else:
468 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700469 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700470 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700471 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700472 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700473 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700474 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700475 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700476 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700477 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700478 return ("", None, None)
479
480 @property
481 @memoize
482 def writeable_members(self):
483 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700484
485 @property
486 @memoize
487 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700488 return self.ir_model_members + self.virtual_members
489
490 @property
491 @memoize
492 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700493 """return a list of all members to be exposed by this interface. Corresponds to
494 the union of the members of the vesioned classes without length, fieldlength
495 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700496 all_versions = []
497 member_map = collections.OrderedDict()
498
499 for (version, of_class) in self.version_map.items():
500 for of_member in of_class.members:
501 if isinstance(of_member, OFLengthMember) or \
502 isinstance(of_member, OFFieldLengthMember) or \
503 isinstance(of_member, OFPadMember):
504 continue
505 if of_member.name not in member_map:
506 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
507
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700508 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 -0700509
510 @property
511 def virtual_members(self):
512 if self.name == "OFOxm":
513 return (
514 JavaVirtualMember(self, "value", java_type.generic_t),
515 JavaVirtualMember(self, "mask", java_type.generic_t),
516 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
517 JavaVirtualMember(self, "masked", java_type.boolean),
518 )
519 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
520 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
521 if self.name in model.oxm_map \
522 else java_type.make_match_field_jtype()
523
524 return (
525 JavaVirtualMember(self, "matchField", field_type),
526 JavaVirtualMember(self, "masked", java_type.boolean),
527 ) \
528 + \
529 (
530 ( 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
531 ()
532 )
533 else:
534 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700535
536 @property
537 @memoize
538 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700539 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700540 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 -0700541
542 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700543 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700544 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700545 return len(self.all_versions) == len(model.versions)
546
547 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700548 @memoize
549 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700550 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700551 return self.version_map.keys()
552
Andreas Wundsam5204de22013-07-30 11:34:45 -0700553 def has_version(self, version):
554 return version in self.version_map
555
Andreas Wundsam27303462013-07-16 12:52:35 -0700556 def versioned_class(self, version):
557 return JavaOFClass(self, version, self.version_map[version])
558
559 @property
560 @memoize
561 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700562 return [ self.versioned_class(version) for version in self.all_versions ]
563
564#######################################################################
565### (Versioned) Classes
566#######################################################################
567
568class JavaOFClass(object):
569 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700570 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700571 """
572 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700573 """
574 @param interface JavaOFInterface instance of the parent interface
575 @param version JavaOFVersion
576 @param ir_class OFClass from loxi_ir
577 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700578 self.interface = interface
579 self.ir_class = ir_class
580 self.c_name = self.ir_class.name
581 self.version = version
582 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700583 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700584 self.generated = False
585
586 @property
587 @memoize
588 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700589 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700590
591 @property
592 def name(self):
593 return "%sVer%s" % (self.interface.name, self.version.of_version)
594
595 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700596 def variable_name(self):
597 return self.name[3:]
598
599 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700600 def length(self):
601 if self.is_fixed_length:
602 return self.min_length
603 else:
604 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
605
606 @property
607 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700608 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700609 id_tuple = (self.ir_class.name, self.version.int_version)
610 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
611
612 @property
613 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700614 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700615 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
616 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700617
618 def all_properties(self):
619 return self.interface.members
620
621 def get_member(self, name):
622 for m in self.members:
623 if m.name == name:
624 return m
625
626 @property
627 @memoize
628 def data_members(self):
629 return [ prop for prop in self.members if prop.is_data ]
630
631 @property
632 @memoize
633 def fixed_value_members(self):
634 return [ prop for prop in self.members if prop.is_fixed_value ]
635
636 @property
637 @memoize
638 def public_members(self):
639 return [ prop for prop in self.members if prop.is_public ]
640
641 @property
642 @memoize
643 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700644 return self.ir_model_members + self.virtual_members
645
646 @property
647 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700648 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700649 return tuple(members)
650
651 @property
652 def virtual_members(self):
653 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
654 if self.interface.name in model.oxm_map:
655 oxm_entry = model.oxm_map[self.interface.name]
656 return (
657 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
658 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
659 )
660 else:
661 return (
662 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
663 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
664 )
665 else:
666 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700667
668 def all_versions(self):
669 return [ JavaOFVersion(int_version)
670 for int_version in of_g.unified[self.c_name]
671 if int_version != 'union' and int_version != 'object_id' ]
672
673 def version_is_inherited(self, version):
674 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
675
676 def inherited_from(self, version):
677 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
678
679 @property
680 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700681 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
682
683 @property
684 def discriminator(self):
685 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700686
687 @property
688 def is_extension(self):
689 return type_maps.message_is_extension(self.c_name, -1)
690
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700691 @property
692 def align(self):
693 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
694
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700695 @property
696 @memoize
697 def superclass(self):
698 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
699
700 @property
701 @memoize
702 def subclasses(self):
703 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
704
Andreas Wundsam27303462013-07-16 12:52:35 -0700705#######################################################################
706### Member
707#######################################################################
708
709
710class JavaMember(object):
711 """ Models a property (member) of an openflow class. """
712 def __init__(self, msg, name, java_type, member):
713 self.msg = msg
714 self.name = name
715 self.java_type = java_type
716 self.member = member
717 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700718
719 @property
720 def title_name(self):
721 return self.name[0].upper() + self.name[1:]
722
723 @property
724 def constant_name(self):
725 return self.c_name.upper()
726
727 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700728 def getter_name(self):
729 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
730
731 @property
732 def setter_name(self):
733 return "set" + self.title_name
734
735 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700736 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700737 if self.is_fixed_value:
738 return self.constant_name
739 else:
740 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700741
742 @property
743 def default_value(self):
744 java_type = self.java_type.public_type;
745
Andreas Wundsam27303462013-07-16 12:52:35 -0700746 if self.is_fixed_value:
747 return self.enum_value
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700748 elif java_type == "OFOxmList":
749 return "OFOxmList.EMPTY"
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700750 elif re.match(r'Set.*', java_type):
751 return "Collections.emptySet()"
Andreas Wundsam27303462013-07-16 12:52:35 -0700752 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700753 return "Collections.emptyList()"
754 elif java_type == "boolean":
755 return "false";
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700756 elif self.java_type.is_array:
757 return "new %s[0]" % java_type[:-2]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700758 elif java_type in ("byte", "char", "short", "int", "long"):
759 return "({0}) 0".format(java_type);
760 else:
761 return "null";
762
763 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700764 def enum_value(self):
765 if self.name == "version":
766 return "OFVersion.%s" % self.msg.version.constant_version
767
768 java_type = self.java_type.public_type;
769 try:
770 global model
771 enum = model.enum_by_name(java_type)
772 entry = enum.entry_by_version_value(self.msg.version, self.value)
773 return "%s.%s" % ( enum.name, entry.name)
774 except KeyError, e:
775 print e.message
776 return self.value
777
778 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700779 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700780 return isinstance(self.member, OFPadMember)
781
782 def is_type_value(self, version=None):
783 if(version==None):
784 return any(self.is_type_value(version) for version in self.msg.all_versions)
785 try:
786 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
787 except:
788 return False
789
790 @property
791 def is_field_length_value(self):
792 return isinstance(self.member, OFFieldLengthMember)
793
794 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700795 def is_discriminator(self):
796 return isinstance(self.member, OFDiscriminatorMember)
797
798 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700799 def is_length_value(self):
800 return isinstance(self.member, OFLengthMember)
801
802 @property
803 def is_public(self):
804 return not (self.is_pad or self.is_length_value)
805
806 @property
807 def is_data(self):
808 return isinstance(self.member, OFDataMember) and self.name != "version"
809
810 @property
811 def is_fixed_value(self):
812 return hasattr(self.member, "value") or self.name == "version" \
813 or ( self.name == "length" and self.msg.is_fixed_length) \
814 or ( self.name == "len" and self.msg.is_fixed_length)
815
816 @property
817 def value(self):
818 if self.name == "version":
819 return self.msg.version.int_version
820 elif self.name == "length" or self.name == "len":
821 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700822 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700823 return self.java_type.format_value(self.member.value)
824
825 @property
826 def priv_value(self):
827 if self.name == "version":
828 return self.msg.version.int_version
829 elif self.name == "length" or self.name == "len":
830 return self.msg.length
831 else:
832 return self.java_type.format_value(self.member.value, pub_type=False)
833
Andreas Wundsam27303462013-07-16 12:52:35 -0700834
835 @property
836 def is_writeable(self):
837 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
838
839 def get_type_value_info(self, version):
840 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700841
842 @property
843 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700844 if hasattr(self.member, "length"):
845 return self.member.length
846 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700847 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700848 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700849
850 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700851 def for_of_member(java_class, member):
852 if isinstance(member, OFPadMember):
853 return JavaMember(None, "", None, member)
854 else:
855 if member.name == 'len':
856 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700857 elif member.name == 'value_mask':
858 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700859 else:
860 name = java_type.name_c_to_camel(member.name)
861 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
862 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700863
864 @property
865 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700866 if not self.msg.c_name in of_g.unified:
867 print("%s not self.unified" % self.msg.c_name)
868 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700869 for version in of_g.unified[self.msg.c_name]:
870 if version == 'union' or version =='object_id':
871 continue
872 if 'use_version' in of_g.unified[self.msg.c_name][version]:
873 continue
874
Andreas Wundsam27303462013-07-16 12:52:35 -0700875 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 -0700876 return False
877 return True
878
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700879 @property
880 def is_virtual(self):
881 return False
882
Andreas Wundsam27303462013-07-16 12:52:35 -0700883 def __hash__(self):
884 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700885
Andreas Wundsam27303462013-07-16 12:52:35 -0700886 def __eq__(self, other):
887 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700888 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700889 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700890
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700891class JavaVirtualMember(JavaMember):
892 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
893 def __init__(self, msg, name, java_type, value=None):
894 JavaMember.__init__(self, msg, name, java_type, member=None)
895 self._value = value
896
897 @property
898 def is_fixed_value(self):
899 return True
900
901 @property
902 def value(self):
903 return self._value
904
905 @property
906 def priv_value(self):
907 return self._value
908
909
910 @property
911 def is_universal(self):
912 return True
913
914 @property
915 def is_virtual(self):
916 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700917
918#######################################################################
919### Unit Test
920#######################################################################
921
Yotam Harchol466b3212013-08-15 12:14:46 -0700922class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700923 def __init__(self, java_class):
924 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700925 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700926 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700927 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
928 name=java_class.c_name[3:]) + "{i}.data"
929 test_class_name = self.java_class.name + "Test"
930 self.test_units = []
931 if test_data.exists(first_data_file_name):
932 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
933 i = 1
934 while test_data.exists(data_file_template.format(i=i)):
935 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
936 i = i + 1
937
938 @property
939 def package(self):
940 return self.java_class.package
941
942 @property
943 def has_test_data(self):
944 return len(self.test_units) > 0
945
946 @property
947 def length(self):
948 return len(self.test_units)
949
950 def get_test_unit(self, i):
951 return self.test_units[i]
952
953
954class JavaUnitTest(object):
955 def __init__(self, java_class, file_name=None, test_class_name=None):
956 self.java_class = java_class
957 if file_name is None:
958 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
959 name=java_class.c_name[3:])
960 else:
961 self.data_file_name = file_name
962 if test_class_name is None:
963 self.test_class_name = self.java_class.name + "Test"
964 else:
965 self.test_class_name = test_class_name
966
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700967 @property
968 def package(self):
969 return self.java_class.package
970
971 @property
972 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700973 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700974
975 @property
976 def has_test_data(self):
977 return test_data.exists(self.data_file_name)
978
979 @property
980 @memoize
981 def test_data(self):
982 return test_data.read(self.data_file_name)
983
984
Andreas Wundsam27303462013-07-16 12:52:35 -0700985#######################################################################
986### Enums
987#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700988
Andreas Wundsam27303462013-07-16 12:52:35 -0700989class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700990 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -0700991 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -0700992
993 if c_name == "of_stats_types":
994 self.name = "OFStatsType"
995 else:
996 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700997
Andreas Wundsam27303462013-07-16 12:52:35 -0700998 # Port_features has constants that start with digits
999 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001000
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001001 self.version_enums = version_enum_map
1002
1003 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1004 for version, ir_enum in version_enum_map.items():
1005 for ir_entry in ir_enum.entries:
1006 if "virtual" in ir_entry.params:
1007 continue
1008 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1009
Andreas Wundsam27303462013-07-16 12:52:35 -07001010 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001011 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001012
1013 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 -07001014 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001015
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001016 self.metadata = model.enum_metadata_map[self.name]
1017
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001018 def wire_type(self, version):
1019 ir_enum = self.version_enums[version]
1020 if "wire_type" in ir_enum.params:
1021 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1022 else:
1023 return java_type.u8
1024
1025 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001026 @memoize
1027 def is_bitmask(self):
1028 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1029
1030 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001031 def versions(self):
1032 return self.version_enums.keys()
1033
Andreas Wundsam27303462013-07-16 12:52:35 -07001034 @memoize
1035 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001036 res = find(lambda e: e.name == name, self.entries)
1037 if res:
1038 return res
1039 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001040 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1041
1042 @memoize
1043 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001044 res = find(lambda e: e.c_name == name, self.entries)
1045 if res:
1046 return res
1047 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001048 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1049
1050 @memoize
1051 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001052 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1053 if res:
1054 return res
1055 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001056 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1057
1058# values: Map JavaVersion->Value
1059class JavaEnumEntry(object):
1060 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001061 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001062 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1063 self.values = values
1064
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001065 @property
1066 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001067 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001068
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001069 def has_value(self, version):
1070 return version in self.values
1071
Andreas Wundsam27303462013-07-16 12:52:35 -07001072 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001073 return self.values[version]
1074
1075 def format_value(self, version):
1076 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001077 return res
1078
Andreas Wundsam27303462013-07-16 12:52:35 -07001079 def all_values(self, versions, not_present=None):
1080 return [ self.values[version] if version in self.values else not_present for version in versions ]