blob: ee76a640d9cbcfaecab20ccb8fa94d0afde9a8e8 [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 Wundsam27303462013-07-16 12:52:35 -0700750 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700751 return "Collections.emptyList()"
752 elif java_type == "boolean":
753 return "false";
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700754 elif self.java_type.is_array:
755 return "new %s[0]" % java_type[:-2]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700756 elif java_type in ("byte", "char", "short", "int", "long"):
757 return "({0}) 0".format(java_type);
758 else:
759 return "null";
760
761 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700762 def enum_value(self):
763 if self.name == "version":
764 return "OFVersion.%s" % self.msg.version.constant_version
765
766 java_type = self.java_type.public_type;
767 try:
768 global model
769 enum = model.enum_by_name(java_type)
770 entry = enum.entry_by_version_value(self.msg.version, self.value)
771 return "%s.%s" % ( enum.name, entry.name)
772 except KeyError, e:
773 print e.message
774 return self.value
775
776 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700777 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700778 return isinstance(self.member, OFPadMember)
779
780 def is_type_value(self, version=None):
781 if(version==None):
782 return any(self.is_type_value(version) for version in self.msg.all_versions)
783 try:
784 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
785 except:
786 return False
787
788 @property
789 def is_field_length_value(self):
790 return isinstance(self.member, OFFieldLengthMember)
791
792 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700793 def is_discriminator(self):
794 return isinstance(self.member, OFDiscriminatorMember)
795
796 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700797 def is_length_value(self):
798 return isinstance(self.member, OFLengthMember)
799
800 @property
801 def is_public(self):
802 return not (self.is_pad or self.is_length_value)
803
804 @property
805 def is_data(self):
806 return isinstance(self.member, OFDataMember) and self.name != "version"
807
808 @property
809 def is_fixed_value(self):
810 return hasattr(self.member, "value") or self.name == "version" \
811 or ( self.name == "length" and self.msg.is_fixed_length) \
812 or ( self.name == "len" and self.msg.is_fixed_length)
813
814 @property
815 def value(self):
816 if self.name == "version":
817 return self.msg.version.int_version
818 elif self.name == "length" or self.name == "len":
819 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700820 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700821 return self.java_type.format_value(self.member.value)
822
823 @property
824 def priv_value(self):
825 if self.name == "version":
826 return self.msg.version.int_version
827 elif self.name == "length" or self.name == "len":
828 return self.msg.length
829 else:
830 return self.java_type.format_value(self.member.value, pub_type=False)
831
Andreas Wundsam27303462013-07-16 12:52:35 -0700832
833 @property
834 def is_writeable(self):
835 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
836
837 def get_type_value_info(self, version):
838 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700839
840 @property
841 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700842 if hasattr(self.member, "length"):
843 return self.member.length
844 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700845 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700846 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700847
848 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700849 def for_of_member(java_class, member):
850 if isinstance(member, OFPadMember):
851 return JavaMember(None, "", None, member)
852 else:
853 if member.name == 'len':
854 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700855 elif member.name == 'value_mask':
856 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700857 else:
858 name = java_type.name_c_to_camel(member.name)
859 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
860 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700861
862 @property
863 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700864 if not self.msg.c_name in of_g.unified:
865 print("%s not self.unified" % self.msg.c_name)
866 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700867 for version in of_g.unified[self.msg.c_name]:
868 if version == 'union' or version =='object_id':
869 continue
870 if 'use_version' in of_g.unified[self.msg.c_name][version]:
871 continue
872
Andreas Wundsam27303462013-07-16 12:52:35 -0700873 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 -0700874 return False
875 return True
876
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700877 @property
878 def is_virtual(self):
879 return False
880
Andreas Wundsam27303462013-07-16 12:52:35 -0700881 def __hash__(self):
882 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700883
Andreas Wundsam27303462013-07-16 12:52:35 -0700884 def __eq__(self, other):
885 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700886 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700887 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700888
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700889class JavaVirtualMember(JavaMember):
890 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
891 def __init__(self, msg, name, java_type, value=None):
892 JavaMember.__init__(self, msg, name, java_type, member=None)
893 self._value = value
894
895 @property
896 def is_fixed_value(self):
897 return True
898
899 @property
900 def value(self):
901 return self._value
902
903 @property
904 def priv_value(self):
905 return self._value
906
907
908 @property
909 def is_universal(self):
910 return True
911
912 @property
913 def is_virtual(self):
914 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700915
916#######################################################################
917### Unit Test
918#######################################################################
919
Yotam Harchol466b3212013-08-15 12:14:46 -0700920class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700921 def __init__(self, java_class):
922 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700923 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700924 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700925 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
926 name=java_class.c_name[3:]) + "{i}.data"
927 test_class_name = self.java_class.name + "Test"
928 self.test_units = []
929 if test_data.exists(first_data_file_name):
930 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
931 i = 1
932 while test_data.exists(data_file_template.format(i=i)):
933 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
934 i = i + 1
935
936 @property
937 def package(self):
938 return self.java_class.package
939
940 @property
941 def has_test_data(self):
942 return len(self.test_units) > 0
943
944 @property
945 def length(self):
946 return len(self.test_units)
947
948 def get_test_unit(self, i):
949 return self.test_units[i]
950
951
952class JavaUnitTest(object):
953 def __init__(self, java_class, file_name=None, test_class_name=None):
954 self.java_class = java_class
955 if file_name is None:
956 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
957 name=java_class.c_name[3:])
958 else:
959 self.data_file_name = file_name
960 if test_class_name is None:
961 self.test_class_name = self.java_class.name + "Test"
962 else:
963 self.test_class_name = test_class_name
964
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700965 @property
966 def package(self):
967 return self.java_class.package
968
969 @property
970 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700971 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700972
973 @property
974 def has_test_data(self):
975 return test_data.exists(self.data_file_name)
976
977 @property
978 @memoize
979 def test_data(self):
980 return test_data.read(self.data_file_name)
981
982
Andreas Wundsam27303462013-07-16 12:52:35 -0700983#######################################################################
984### Enums
985#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700986
Andreas Wundsam27303462013-07-16 12:52:35 -0700987class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700988 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -0700989 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -0700990
991 if c_name == "of_stats_types":
992 self.name = "OFStatsType"
993 else:
994 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700995
Andreas Wundsam27303462013-07-16 12:52:35 -0700996 # Port_features has constants that start with digits
997 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700998
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700999 self.version_enums = version_enum_map
1000
1001 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1002 for version, ir_enum in version_enum_map.items():
1003 for ir_entry in ir_enum.entries:
1004 if "virtual" in ir_entry.params:
1005 continue
1006 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1007
Andreas Wundsam27303462013-07-16 12:52:35 -07001008 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001009 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001010
1011 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 -07001012 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001013
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001014 self.metadata = model.enum_metadata_map[self.name]
1015
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001016 def wire_type(self, version):
1017 ir_enum = self.version_enums[version]
1018 if "wire_type" in ir_enum.params:
1019 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1020 else:
1021 return java_type.u8
1022
1023 @property
1024 def versions(self):
1025 return self.version_enums.keys()
1026
Andreas Wundsam27303462013-07-16 12:52:35 -07001027 @memoize
1028 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001029 res = find(lambda e: e.name == name, self.entries)
1030 if res:
1031 return res
1032 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001033 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1034
1035 @memoize
1036 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001037 res = find(lambda e: e.c_name == name, self.entries)
1038 if res:
1039 return res
1040 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001041 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1042
1043 @memoize
1044 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001045 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1046 if res:
1047 return res
1048 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001049 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1050
1051# values: Map JavaVersion->Value
1052class JavaEnumEntry(object):
1053 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001054 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001055 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1056 self.values = values
1057
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001058 @property
1059 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001060 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001061
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001062 def has_value(self, version):
1063 return version in self.values
1064
Andreas Wundsam27303462013-07-16 12:52:35 -07001065 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001066 return self.values[version]
1067
1068 def format_value(self, version):
1069 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001070 return res
1071
Andreas Wundsam27303462013-07-16 12:52:35 -07001072 def all_values(self, versions, not_present=None):
1073 return [ self.values[version] if version in self.values else not_present for version in versions ]