blob: f7e0f81e389e19b92d8feff93b66bedbaae7cf05 [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
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700133 class OFEnumMetadata(namedtuple("OFEnumMetadata", ("name", "type", "value"))):
134 @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
143 def gen_port_speed(enum_entry):
144 splits = enum_entry.name.split("_")
145 if len(splits)>=2:
146 m = re.match(r'\d+[MGTP]B', splits[1])
147 if m:
148 return "PortSpeed.SPEED_{}".format(splits[1])
149 return "PortSpeed.SPEED_NONE";
150
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700151 def gen_stp_state(enum_entry):
152 splits = enum_entry.name.split("_")
153 if len(splits)>=1:
154 if splits[0] == "STP":
155 return "true"
156 return "false"
157
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700158 enum_metadata_map = defaultdict(lambda: (),
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700159 OFPortFeatures = ( OFEnumMetadata("PortSpeed", java_type.port_speed, gen_port_speed), ),
160 OFPortState = ( OFEnumMetadata("StpState", java_type.boolean, gen_stp_state), )
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700161 )
162
Andreas Wundsam27303462013-07-16 12:52:35 -0700163 @property
164 @memoize
165 def versions(self):
166 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
167
168 @property
169 @memoize
170 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700171 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700172
173 for raw_version, of_protocol in of_g.ir.items():
174 jversion = JavaOFVersion(of_protocol.wire_version)
175
176 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700177 if not of_class.name in version_map_per_class:
178 version_map_per_class[of_class.name] = collections.OrderedDict()
179
Andreas Wundsam27303462013-07-16 12:52:35 -0700180 version_map_per_class[of_class.name][jversion] = of_class
181
182 interfaces = []
183 for class_name, version_map in version_map_per_class.items():
184 interfaces.append(JavaOFInterface(class_name, version_map))
185
Andreas Wundsambe168f72013-08-03 22:49:35 -0700186 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
187
Andreas Wundsam27303462013-07-16 12:52:35 -0700188 return interfaces
189
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700190 @memoize
191 def interface_by_name(self, name):
192 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
193
Andreas Wundsam27303462013-07-16 12:52:35 -0700194 @property
195 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700196 def all_classes(self):
197 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
198
199 @property
200 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700201 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700202 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700203
204 for version in self.versions:
205 of_protocol = of_g.ir[version.int_version]
206 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700207 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700208
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700209 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
210 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700211
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700212 # inelegant - need java name here
213 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700214 return enums
215
216 @memoize
217 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700218 res = find(lambda e: e.name == name, self.enums)
219 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700220 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700221 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700222
Andreas Wundsam5204de22013-07-30 11:34:45 -0700223 @property
224 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700225 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700226 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700227
228 factories = OrderedDict()
229
230 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
231 for base_class in sub_factory_classes:
232 package = base_class[2:].lower()
233 remove_prefix = base_class[2].lower() + base_class[3:]
234
235 # HACK need to have a better way to deal with parameterized base classes
236 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
237
238 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
239 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
240
241 factories[""] = OFFactory(
242 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700243 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700244 remove_prefix="",
245 members=[], base_class="OFMessage", sub_factories=OrderedDict(
246 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
247
248 for i in self.interfaces:
249 for n, factory in factories.items():
250 if n == "":
251 factory.members.append(i)
252 break
253 else:
254 super_class = self.interface_by_name(n)
255 if i.is_instance_of(super_class):
256 factory.members.append(i)
257 break
258 return factories.values()
Andreas Wundsam5204de22013-07-30 11:34:45 -0700259
260 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700261 """ return wether or not to generate implementation class clazz.
262 Now true for everything except OFTableModVer10.
263 @param clazz JavaOFClass instance
264 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700265 if clazz.interface.name.startswith("OFMatchV"):
266 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700267 elif clazz.name == "OFTableModVer10":
268 # tablemod ver 10 is a hack and has no oftype defined
269 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700270 if loxi_utils.class_is_message(clazz.interface.c_name):
271 return True
272 if loxi_utils.class_is_oxm(clazz.interface.c_name):
273 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700274 if loxi_utils.class_is_action(clazz.interface.c_name):
275 return True
276 if loxi_utils.class_is_instruction(clazz.interface.c_name):
277 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700278 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700279 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700280
281
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700282class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700283 @property
284 def factory_classes(self):
285 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700286 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700287 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700288 interface=self,
289 version=version
290 ) for version in model.versions ]
291
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700292 def method_name(self, member, builder=True):
293 n = member.variable_name
294 if n.startswith(self.remove_prefix):
295 n = n[len(self.remove_prefix):]
296 n = n[0].lower() + n[1:]
297 if builder:
298 return "build" + n[0].upper() + n[1:]
299 else:
300 return n
Andreas Wundsam5204de22013-07-30 11:34:45 -0700301
302OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700303class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
304 @property
305 def base_class(self):
306 return self.interface.base_class
307
308 @property
309 def versioned_base_class(self):
310 base_class_interface = model.interface_by_name(self.interface.base_class)
311 if base_class_interface and base_class_interface.has_version(self.version):
312 return base_class_interface.versioned_class(self.version)
313 else:
314 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700315
Andreas Wundsam27303462013-07-16 12:52:35 -0700316model = JavaModel()
317
318#######################################################################
319### OFVersion
320#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700321
322class JavaOFVersion(object):
323 """ Models a version of OpenFlow. contains methods to convert the internal
324 Loxi version to a java constant / a string """
325 def __init__(self, int_version):
326 self.int_version = int(int_version)
327
328 @property
329 def of_version(self):
330 return "1" + str(int(self.int_version) - 1)
331
332 @property
333 def constant_version(self):
334 return "OF_" + self.of_version
335
Andreas Wundsam27303462013-07-16 12:52:35 -0700336 def __repr__(self):
337 return "JavaOFVersion(%d)" % self.int_version
338
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700339 def __str__(self):
340 return of_g.param_version_names[self.int_version]
341
Andreas Wundsam27303462013-07-16 12:52:35 -0700342 def __hash__(self):
343 return hash(self.int_version)
344
345 def __eq__(self, other):
346 if other is None or type(self) != type(other):
347 return False
348 return (self.int_version,) == (other.int_version,)
349
350#######################################################################
351### Interface
352#######################################################################
353
354class JavaOFInterface(object):
355 """ Models an OpenFlow Message class for the purpose of the java class.
356 Version agnostic, in contrast to the loxi_ir python model.
357 """
358 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700359 """"
360 @param c_name: loxi style name (e.g., of_flow_add)
361 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
362 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700363 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700364 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700365 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700366 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 -0700367 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700368 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700369 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700370 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700371 self.constant_name = c_name.upper().replace("OF_", "")
372
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700373 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700374 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700375 if self.name != parent_interface:
376 self.parent_interface = parent_interface
377 else:
378 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700379
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700380 @property
381 @memoize
382 def all_parent_interfaces(self):
383 return [ "OFObject" ] + \
384 ([ self.parent_interface ] if self.parent_interface else [] )+ \
385 self.additional_parent_interfaces
386 @property
387 @memoize
388 def additional_parent_interfaces(self):
389 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
390 m = re.match(r'(.*)Request$', self.name)
391 if m:
392 reply_name = m.group(1) + "Reply"
393 if model.interface_by_name(reply_name):
394 return ["OFRequest<%s>" % reply_name ]
395 return []
396
397
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700398 def is_instance_of(self, other_class):
399 if self == other_class:
400 return True
401 parent = self.super_class
402 if parent is None:
403 return False
404 else:
405 return parent.is_instance_of(other_class)
406
407 @property
408 def super_class(self):
409 if not self.parent_interface:
410 return None
411 else:
412 return model.interface_by_name(self.parent_interface)
413
414
415 def inherited_declaration(self, type_spec="?"):
416 if self.type_annotation:
417 return "%s<%s>" % (self.name, type_spec)
418 else:
419 return "%s" % self.name
420
421 @property
422 def type_variable(self):
423 if self.type_annotation:
424 return "<T>"
425 else:
426 return "";
427
Andreas Wundsam27303462013-07-16 12:52:35 -0700428 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700429 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
430 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
431 # model (note, that the loxi model is on versioned classes). Should check/infer the
432 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700433 if re.match(r'OF.+StatsRequest$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700434 return ("", "OFStatsRequest", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700435 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700436 return ("", "OFStatsReply", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700437 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700438 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700439 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 -0700440 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700441 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 -0700442 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700443 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
444 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700445 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700446 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700447 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700448 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700449 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700450 if re.match(r'OFActionBsn.+', self.name):
451 return ("action", "OFActionBsn", None)
452 elif re.match(r'OFActionNicira.+', self.name):
453 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700454 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
455 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700456 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700457 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700458 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700459 return ("", "OFBsnVport", None)
460 elif self.name == "OFOxm":
461 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700462 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700463 if self.name in model.oxm_map:
464 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
465 else:
466 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700467 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700468 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700469 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700470 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700471 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700472 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700473 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700474 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700475 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700476 return ("", None, None)
477
478 @property
479 @memoize
480 def writeable_members(self):
481 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700482
483 @property
484 @memoize
485 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700486 return self.ir_model_members + self.virtual_members
487
488 @property
489 @memoize
490 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700491 """return a list of all members to be exposed by this interface. Corresponds to
492 the union of the members of the vesioned classes without length, fieldlength
493 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700494 all_versions = []
495 member_map = collections.OrderedDict()
496
497 for (version, of_class) in self.version_map.items():
498 for of_member in of_class.members:
499 if isinstance(of_member, OFLengthMember) or \
500 isinstance(of_member, OFFieldLengthMember) or \
501 isinstance(of_member, OFPadMember):
502 continue
503 if of_member.name not in member_map:
504 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
505
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700506 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 -0700507
508 @property
509 def virtual_members(self):
510 if self.name == "OFOxm":
511 return (
512 JavaVirtualMember(self, "value", java_type.generic_t),
513 JavaVirtualMember(self, "mask", java_type.generic_t),
514 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
515 JavaVirtualMember(self, "masked", java_type.boolean),
516 )
517 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
518 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
519 if self.name in model.oxm_map \
520 else java_type.make_match_field_jtype()
521
522 return (
523 JavaVirtualMember(self, "matchField", field_type),
524 JavaVirtualMember(self, "masked", java_type.boolean),
525 ) \
526 + \
527 (
528 ( 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
529 ()
530 )
531 else:
532 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700533
534 @property
535 @memoize
536 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700537 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700538 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 -0700539
540 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700541 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700542 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700543 return len(self.all_versions) == len(model.versions)
544
545 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700546 @memoize
547 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700548 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700549 return self.version_map.keys()
550
Andreas Wundsam5204de22013-07-30 11:34:45 -0700551 def has_version(self, version):
552 return version in self.version_map
553
Andreas Wundsam27303462013-07-16 12:52:35 -0700554 def versioned_class(self, version):
555 return JavaOFClass(self, version, self.version_map[version])
556
557 @property
558 @memoize
559 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700560 return [ self.versioned_class(version) for version in self.all_versions ]
561
562#######################################################################
563### (Versioned) Classes
564#######################################################################
565
566class JavaOFClass(object):
567 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700568 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700569 """
570 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700571 """
572 @param interface JavaOFInterface instance of the parent interface
573 @param version JavaOFVersion
574 @param ir_class OFClass from loxi_ir
575 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700576 self.interface = interface
577 self.ir_class = ir_class
578 self.c_name = self.ir_class.name
579 self.version = version
580 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700581 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700582 self.generated = False
583
584 @property
585 @memoize
586 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700587 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700588
589 @property
590 def name(self):
591 return "%sVer%s" % (self.interface.name, self.version.of_version)
592
593 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700594 def variable_name(self):
595 return self.name[3:]
596
597 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700598 def length(self):
599 if self.is_fixed_length:
600 return self.min_length
601 else:
602 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
603
604 @property
605 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700606 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700607 id_tuple = (self.ir_class.name, self.version.int_version)
608 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
609
610 @property
611 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700612 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700613 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
614 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700615
616 def all_properties(self):
617 return self.interface.members
618
619 def get_member(self, name):
620 for m in self.members:
621 if m.name == name:
622 return m
623
624 @property
625 @memoize
626 def data_members(self):
627 return [ prop for prop in self.members if prop.is_data ]
628
629 @property
630 @memoize
631 def fixed_value_members(self):
632 return [ prop for prop in self.members if prop.is_fixed_value ]
633
634 @property
635 @memoize
636 def public_members(self):
637 return [ prop for prop in self.members if prop.is_public ]
638
639 @property
640 @memoize
641 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700642 return self.ir_model_members + self.virtual_members
643
644 @property
645 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700646 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700647 return tuple(members)
648
649 @property
650 def virtual_members(self):
651 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
652 if self.interface.name in model.oxm_map:
653 oxm_entry = model.oxm_map[self.interface.name]
654 return (
655 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
656 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
657 )
658 else:
659 return (
660 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
661 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
662 )
663 else:
664 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700665
666 def all_versions(self):
667 return [ JavaOFVersion(int_version)
668 for int_version in of_g.unified[self.c_name]
669 if int_version != 'union' and int_version != 'object_id' ]
670
671 def version_is_inherited(self, version):
672 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
673
674 def inherited_from(self, version):
675 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
676
677 @property
678 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700679 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
680
681 @property
682 def discriminator(self):
683 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700684
685 @property
686 def is_extension(self):
687 return type_maps.message_is_extension(self.c_name, -1)
688
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700689 @property
690 def align(self):
691 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
692
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700693 @property
694 @memoize
695 def superclass(self):
696 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
697
698 @property
699 @memoize
700 def subclasses(self):
701 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
702
Andreas Wundsam27303462013-07-16 12:52:35 -0700703#######################################################################
704### Member
705#######################################################################
706
707
708class JavaMember(object):
709 """ Models a property (member) of an openflow class. """
710 def __init__(self, msg, name, java_type, member):
711 self.msg = msg
712 self.name = name
713 self.java_type = java_type
714 self.member = member
715 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700716
717 @property
718 def title_name(self):
719 return self.name[0].upper() + self.name[1:]
720
721 @property
722 def constant_name(self):
723 return self.c_name.upper()
724
725 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700726 def getter_name(self):
727 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
728
729 @property
730 def setter_name(self):
731 return "set" + self.title_name
732
733 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700734 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700735 if self.is_fixed_value:
736 return self.constant_name
737 else:
738 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700739
740 @property
741 def default_value(self):
742 java_type = self.java_type.public_type;
743
Andreas Wundsam27303462013-07-16 12:52:35 -0700744 if self.is_fixed_value:
745 return self.enum_value
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700746 elif java_type == "OFOxmList":
747 return "OFOxmList.EMPTY"
Andreas Wundsam27303462013-07-16 12:52:35 -0700748 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700749 return "Collections.emptyList()"
750 elif java_type == "boolean":
751 return "false";
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700752 elif self.java_type.is_array:
753 return "new %s[0]" % java_type[:-2]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700754 elif java_type in ("byte", "char", "short", "int", "long"):
755 return "({0}) 0".format(java_type);
756 else:
757 return "null";
758
759 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700760 def enum_value(self):
761 if self.name == "version":
762 return "OFVersion.%s" % self.msg.version.constant_version
763
764 java_type = self.java_type.public_type;
765 try:
766 global model
767 enum = model.enum_by_name(java_type)
768 entry = enum.entry_by_version_value(self.msg.version, self.value)
769 return "%s.%s" % ( enum.name, entry.name)
770 except KeyError, e:
771 print e.message
772 return self.value
773
774 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700775 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700776 return isinstance(self.member, OFPadMember)
777
778 def is_type_value(self, version=None):
779 if(version==None):
780 return any(self.is_type_value(version) for version in self.msg.all_versions)
781 try:
782 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
783 except:
784 return False
785
786 @property
787 def is_field_length_value(self):
788 return isinstance(self.member, OFFieldLengthMember)
789
790 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700791 def is_discriminator(self):
792 return isinstance(self.member, OFDiscriminatorMember)
793
794 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700795 def is_length_value(self):
796 return isinstance(self.member, OFLengthMember)
797
798 @property
799 def is_public(self):
800 return not (self.is_pad or self.is_length_value)
801
802 @property
803 def is_data(self):
804 return isinstance(self.member, OFDataMember) and self.name != "version"
805
806 @property
807 def is_fixed_value(self):
808 return hasattr(self.member, "value") or self.name == "version" \
809 or ( self.name == "length" and self.msg.is_fixed_length) \
810 or ( self.name == "len" and self.msg.is_fixed_length)
811
812 @property
813 def value(self):
814 if self.name == "version":
815 return self.msg.version.int_version
816 elif self.name == "length" or self.name == "len":
817 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700818 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700819 return self.java_type.format_value(self.member.value)
820
821 @property
822 def priv_value(self):
823 if self.name == "version":
824 return self.msg.version.int_version
825 elif self.name == "length" or self.name == "len":
826 return self.msg.length
827 else:
828 return self.java_type.format_value(self.member.value, pub_type=False)
829
Andreas Wundsam27303462013-07-16 12:52:35 -0700830
831 @property
832 def is_writeable(self):
833 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
834
835 def get_type_value_info(self, version):
836 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700837
838 @property
839 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700840 if hasattr(self.member, "length"):
841 return self.member.length
842 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700843 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700844 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700845
846 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700847 def for_of_member(java_class, member):
848 if isinstance(member, OFPadMember):
849 return JavaMember(None, "", None, member)
850 else:
851 if member.name == 'len':
852 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700853 elif member.name == 'value_mask':
854 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700855 else:
856 name = java_type.name_c_to_camel(member.name)
857 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
858 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700859
860 @property
861 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700862 if not self.msg.c_name in of_g.unified:
863 print("%s not self.unified" % self.msg.c_name)
864 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700865 for version in of_g.unified[self.msg.c_name]:
866 if version == 'union' or version =='object_id':
867 continue
868 if 'use_version' in of_g.unified[self.msg.c_name][version]:
869 continue
870
Andreas Wundsam27303462013-07-16 12:52:35 -0700871 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 -0700872 return False
873 return True
874
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700875 @property
876 def is_virtual(self):
877 return False
878
Andreas Wundsam27303462013-07-16 12:52:35 -0700879 def __hash__(self):
880 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700881
Andreas Wundsam27303462013-07-16 12:52:35 -0700882 def __eq__(self, other):
883 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700884 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700885 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700886
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700887class JavaVirtualMember(JavaMember):
888 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
889 def __init__(self, msg, name, java_type, value=None):
890 JavaMember.__init__(self, msg, name, java_type, member=None)
891 self._value = value
892
893 @property
894 def is_fixed_value(self):
895 return True
896
897 @property
898 def value(self):
899 return self._value
900
901 @property
902 def priv_value(self):
903 return self._value
904
905
906 @property
907 def is_universal(self):
908 return True
909
910 @property
911 def is_virtual(self):
912 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700913
914#######################################################################
915### Unit Test
916#######################################################################
917
Yotam Harchol466b3212013-08-15 12:14:46 -0700918class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700919 def __init__(self, java_class):
920 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700921 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700922 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700923 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
924 name=java_class.c_name[3:]) + "{i}.data"
925 test_class_name = self.java_class.name + "Test"
926 self.test_units = []
927 if test_data.exists(first_data_file_name):
928 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
929 i = 1
930 while test_data.exists(data_file_template.format(i=i)):
931 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
932 i = i + 1
933
934 @property
935 def package(self):
936 return self.java_class.package
937
938 @property
939 def has_test_data(self):
940 return len(self.test_units) > 0
941
942 @property
943 def length(self):
944 return len(self.test_units)
945
946 def get_test_unit(self, i):
947 return self.test_units[i]
948
949
950class JavaUnitTest(object):
951 def __init__(self, java_class, file_name=None, test_class_name=None):
952 self.java_class = java_class
953 if file_name is None:
954 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
955 name=java_class.c_name[3:])
956 else:
957 self.data_file_name = file_name
958 if test_class_name is None:
959 self.test_class_name = self.java_class.name + "Test"
960 else:
961 self.test_class_name = test_class_name
962
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700963 @property
964 def package(self):
965 return self.java_class.package
966
967 @property
968 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700969 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700970
971 @property
972 def has_test_data(self):
973 return test_data.exists(self.data_file_name)
974
975 @property
976 @memoize
977 def test_data(self):
978 return test_data.read(self.data_file_name)
979
980
Andreas Wundsam27303462013-07-16 12:52:35 -0700981#######################################################################
982### Enums
983#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700984
Andreas Wundsam27303462013-07-16 12:52:35 -0700985class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700986 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -0700987 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -0700988
989 if c_name == "of_stats_types":
990 self.name = "OFStatsType"
991 else:
992 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700993
Andreas Wundsam27303462013-07-16 12:52:35 -0700994 # Port_features has constants that start with digits
995 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700996
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700997 self.version_enums = version_enum_map
998
999 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1000 for version, ir_enum in version_enum_map.items():
1001 for ir_entry in ir_enum.entries:
1002 if "virtual" in ir_entry.params:
1003 continue
1004 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1005
Andreas Wundsam27303462013-07-16 12:52:35 -07001006 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001007 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001008
1009 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 -07001010 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001011
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001012 self.metadata = model.enum_metadata_map[self.name]
1013
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001014 def wire_type(self, version):
1015 ir_enum = self.version_enums[version]
1016 if "wire_type" in ir_enum.params:
1017 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1018 else:
1019 return java_type.u8
1020
1021 @property
1022 def versions(self):
1023 return self.version_enums.keys()
1024
Andreas Wundsam27303462013-07-16 12:52:35 -07001025 @memoize
1026 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001027 res = find(lambda e: e.name == name, self.entries)
1028 if res:
1029 return res
1030 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001031 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1032
1033 @memoize
1034 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001035 res = find(lambda e: e.c_name == name, self.entries)
1036 if res:
1037 return res
1038 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001039 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1040
1041 @memoize
1042 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001043 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1044 if res:
1045 return res
1046 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001047 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1048
1049# values: Map JavaVersion->Value
1050class JavaEnumEntry(object):
1051 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001052 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001053 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1054 self.values = values
1055
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001056 @property
1057 def constructor_params(self):
1058 return [ m.value(self) for m in self.enum.metadata ]
1059
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001060 def has_value(self, version):
1061 return version in self.values
1062
Andreas Wundsam27303462013-07-16 12:52:35 -07001063 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001064 return self.values[version]
1065
1066 def format_value(self, version):
1067 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001068 return res
1069
Andreas Wundsam27303462013-07-16 12:52:35 -07001070 def all_values(self, versions, not_present=None):
1071 return [ self.values[version] if version in self.values else not_present for version in versions ]