blob: 4f773909f7aae4718238b9e85e2ad4cb3efc95b0 [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),
81 "OFOxmIpv4Src": OxmMapEntry("IPv4", "IPV4_SRC", False),
82 "OFOxmIpv4SrcMasked": OxmMapEntry("IPv4", "IPV4_SRC", True),
83 "OFOxmIpv4Dst": OxmMapEntry("IPv4", "IPV4_DST", False),
84 "OFOxmIpv4DstMasked": OxmMapEntry("IPv4", "IPV4_DST", True),
85 "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),
103 "OFOxmArpSpa": OxmMapEntry("IPv4", "ARP_SPA", False),
104 "OFOxmArpSpaMasked": OxmMapEntry("IPv4", "ARP_SPA", True),
105 "OFOxmArpTpa": OxmMapEntry("IPv4", "ARP_TPA", False),
106 "OFOxmArpTpaMasked": OxmMapEntry("IPv4", "ARP_TPA", True),
107 "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),
111 "OFOxmIpv6Src": OxmMapEntry("IPv6", "IPV6_SRC", False),
112 "OFOxmIpv6SrcMasked": OxmMapEntry("IPv6", "IPV6_SRC", True),
113 "OFOxmIpv6Dst": OxmMapEntry("IPv6", "IPV6_DST", False),
114 "OFOxmIpv6DstMasked": OxmMapEntry("IPv6", "IPV6_DST", True),
115 "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),
121 "OFOxmIpv6NdTarget": OxmMapEntry("IPv6", "IPV6_ND_TARGET", False),
122 "OFOxmIpv6NdTargetMasked": OxmMapEntry("IPv6", "IPV6_ND_TARGET", True),
123 "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 Wundsam27303462013-07-16 12:52:35 -0700133 @property
134 @memoize
135 def versions(self):
136 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
137
138 @property
139 @memoize
140 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700141 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700142
143 for raw_version, of_protocol in of_g.ir.items():
144 jversion = JavaOFVersion(of_protocol.wire_version)
145
146 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700147 if not of_class.name in version_map_per_class:
148 version_map_per_class[of_class.name] = collections.OrderedDict()
149
Andreas Wundsam27303462013-07-16 12:52:35 -0700150 version_map_per_class[of_class.name][jversion] = of_class
151
152 interfaces = []
153 for class_name, version_map in version_map_per_class.items():
154 interfaces.append(JavaOFInterface(class_name, version_map))
155
Andreas Wundsambe168f72013-08-03 22:49:35 -0700156 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
157
Andreas Wundsam27303462013-07-16 12:52:35 -0700158 return interfaces
159
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700160 @memoize
161 def interface_by_name(self, name):
162 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
163
Andreas Wundsam27303462013-07-16 12:52:35 -0700164 @property
165 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700166 def all_classes(self):
167 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
168
169 @property
170 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700171 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700172 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700173
174 for version in self.versions:
175 of_protocol = of_g.ir[version.int_version]
176 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700177 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700178
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700179 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
180 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700181
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700182 # inelegant - need java name here
183 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700184 return enums
185
186 @memoize
187 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700188 res = find(lambda e: e.name == name, self.enums)
189 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700190 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700191 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700192
Andreas Wundsam5204de22013-07-30 11:34:45 -0700193 @property
194 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700195 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700196 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700197
198 factories = OrderedDict()
199
200 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
201 for base_class in sub_factory_classes:
202 package = base_class[2:].lower()
203 remove_prefix = base_class[2].lower() + base_class[3:]
204
205 # HACK need to have a better way to deal with parameterized base classes
206 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
207
208 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
209 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
210
211 factories[""] = OFFactory(
212 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700213 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700214 remove_prefix="",
215 members=[], base_class="OFMessage", sub_factories=OrderedDict(
216 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
217
218 for i in self.interfaces:
219 for n, factory in factories.items():
220 if n == "":
221 factory.members.append(i)
222 break
223 else:
224 super_class = self.interface_by_name(n)
225 if i.is_instance_of(super_class):
226 factory.members.append(i)
227 break
228 return factories.values()
Andreas Wundsam5204de22013-07-30 11:34:45 -0700229
230 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700231 """ return wether or not to generate implementation class clazz.
232 Now true for everything except OFTableModVer10.
233 @param clazz JavaOFClass instance
234 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700235 if clazz.interface.name.startswith("OFMatchV"):
236 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700237 elif clazz.name == "OFTableModVer10":
238 # tablemod ver 10 is a hack and has no oftype defined
239 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700240 if loxi_utils.class_is_message(clazz.interface.c_name):
241 return True
242 if loxi_utils.class_is_oxm(clazz.interface.c_name):
243 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700244 if loxi_utils.class_is_action(clazz.interface.c_name):
245 return True
246 if loxi_utils.class_is_instruction(clazz.interface.c_name):
247 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700248 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700249 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700250
251
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700252class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700253 @property
254 def factory_classes(self):
255 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700256 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700257 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700258 interface=self,
259 version=version
260 ) for version in model.versions ]
261
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700262 def method_name(self, member, builder=True):
263 n = member.variable_name
264 if n.startswith(self.remove_prefix):
265 n = n[len(self.remove_prefix):]
266 n = n[0].lower() + n[1:]
267 if builder:
268 return "build" + n[0].upper() + n[1:]
269 else:
270 return n
Andreas Wundsam5204de22013-07-30 11:34:45 -0700271
272OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700273class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
274 @property
275 def base_class(self):
276 return self.interface.base_class
277
278 @property
279 def versioned_base_class(self):
280 base_class_interface = model.interface_by_name(self.interface.base_class)
281 if base_class_interface and base_class_interface.has_version(self.version):
282 return base_class_interface.versioned_class(self.version)
283 else:
284 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700285
Andreas Wundsam27303462013-07-16 12:52:35 -0700286model = JavaModel()
287
288#######################################################################
289### OFVersion
290#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700291
292class JavaOFVersion(object):
293 """ Models a version of OpenFlow. contains methods to convert the internal
294 Loxi version to a java constant / a string """
295 def __init__(self, int_version):
296 self.int_version = int(int_version)
297
298 @property
299 def of_version(self):
300 return "1" + str(int(self.int_version) - 1)
301
302 @property
303 def constant_version(self):
304 return "OF_" + self.of_version
305
Andreas Wundsam27303462013-07-16 12:52:35 -0700306 def __repr__(self):
307 return "JavaOFVersion(%d)" % self.int_version
308
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700309 def __str__(self):
310 return of_g.param_version_names[self.int_version]
311
Andreas Wundsam27303462013-07-16 12:52:35 -0700312 def __hash__(self):
313 return hash(self.int_version)
314
315 def __eq__(self, other):
316 if other is None or type(self) != type(other):
317 return False
318 return (self.int_version,) == (other.int_version,)
319
320#######################################################################
321### Interface
322#######################################################################
323
324class JavaOFInterface(object):
325 """ Models an OpenFlow Message class for the purpose of the java class.
326 Version agnostic, in contrast to the loxi_ir python model.
327 """
328 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700329 """"
330 @param c_name: loxi style name (e.g., of_flow_add)
331 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
332 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700333 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700334 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700335 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700336 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 -0700337 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700338 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700339 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700340 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700341 self.constant_name = c_name.upper().replace("OF_", "")
342
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700343 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700344 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700345 if self.name != parent_interface:
346 self.parent_interface = parent_interface
347 else:
348 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700349
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700350 @property
351 @memoize
352 def all_parent_interfaces(self):
353 return [ "OFObject" ] + \
354 ([ self.parent_interface ] if self.parent_interface else [] )+ \
355 self.additional_parent_interfaces
356 @property
357 @memoize
358 def additional_parent_interfaces(self):
359 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
360 m = re.match(r'(.*)Request$', self.name)
361 if m:
362 reply_name = m.group(1) + "Reply"
363 if model.interface_by_name(reply_name):
364 return ["OFRequest<%s>" % reply_name ]
365 return []
366
367
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700368 def is_instance_of(self, other_class):
369 if self == other_class:
370 return True
371 parent = self.super_class
372 if parent is None:
373 return False
374 else:
375 return parent.is_instance_of(other_class)
376
377 @property
378 def super_class(self):
379 if not self.parent_interface:
380 return None
381 else:
382 return model.interface_by_name(self.parent_interface)
383
384
385 def inherited_declaration(self, type_spec="?"):
386 if self.type_annotation:
387 return "%s<%s>" % (self.name, type_spec)
388 else:
389 return "%s" % self.name
390
391 @property
392 def type_variable(self):
393 if self.type_annotation:
394 return "<T>"
395 else:
396 return "";
397
Andreas Wundsam27303462013-07-16 12:52:35 -0700398 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700399 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
400 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
401 # model (note, that the loxi model is on versioned classes). Should check/infer the
402 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700403 if re.match(r'OF.+StatsRequest$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700404 return ("", "OFStatsRequest", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700405 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700406 return ("", "OFStatsReply", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700407 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700408 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700409 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 -0700410 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700411 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 -0700412 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700413 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
414 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700415 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700416 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700417 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700418 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700419 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700420 if re.match(r'OFActionBsn.+', self.name):
421 return ("action", "OFActionBsn", None)
422 elif re.match(r'OFActionNicira.+', self.name):
423 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700424 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
425 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700426 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700427 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700428 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700429 return ("", "OFBsnVport", None)
430 elif self.name == "OFOxm":
431 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700432 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700433 if self.name in model.oxm_map:
434 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
435 else:
436 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700437 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700438 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700439 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700440 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700441 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700442 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700443 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700444 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700445 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700446 return ("", None, None)
447
448 @property
449 @memoize
450 def writeable_members(self):
451 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700452
453 @property
454 @memoize
455 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700456 return self.ir_model_members + self.virtual_members
457
458 @property
459 @memoize
460 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700461 """return a list of all members to be exposed by this interface. Corresponds to
462 the union of the members of the vesioned classes without length, fieldlength
463 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700464 all_versions = []
465 member_map = collections.OrderedDict()
466
467 for (version, of_class) in self.version_map.items():
468 for of_member in of_class.members:
469 if isinstance(of_member, OFLengthMember) or \
470 isinstance(of_member, OFFieldLengthMember) or \
471 isinstance(of_member, OFPadMember):
472 continue
473 if of_member.name not in member_map:
474 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
475
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700476 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 -0700477
478 @property
479 def virtual_members(self):
480 if self.name == "OFOxm":
481 return (
482 JavaVirtualMember(self, "value", java_type.generic_t),
483 JavaVirtualMember(self, "mask", java_type.generic_t),
484 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
485 JavaVirtualMember(self, "masked", java_type.boolean),
486 )
487 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
488 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
489 if self.name in model.oxm_map \
490 else java_type.make_match_field_jtype()
491
492 return (
493 JavaVirtualMember(self, "matchField", field_type),
494 JavaVirtualMember(self, "masked", java_type.boolean),
495 ) \
496 + \
497 (
498 ( 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
499 ()
500 )
501 else:
502 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700503
504 @property
505 @memoize
506 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700507 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700508 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 -0700509
510 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700511 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700512 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700513 return len(self.all_versions) == len(model.versions)
514
515 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700516 @memoize
517 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700518 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700519 return self.version_map.keys()
520
Andreas Wundsam5204de22013-07-30 11:34:45 -0700521 def has_version(self, version):
522 return version in self.version_map
523
Andreas Wundsam27303462013-07-16 12:52:35 -0700524 def versioned_class(self, version):
525 return JavaOFClass(self, version, self.version_map[version])
526
527 @property
528 @memoize
529 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700530 return [ self.versioned_class(version) for version in self.all_versions ]
531
532#######################################################################
533### (Versioned) Classes
534#######################################################################
535
536class JavaOFClass(object):
537 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700538 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700539 """
540 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700541 """
542 @param interface JavaOFInterface instance of the parent interface
543 @param version JavaOFVersion
544 @param ir_class OFClass from loxi_ir
545 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700546 self.interface = interface
547 self.ir_class = ir_class
548 self.c_name = self.ir_class.name
549 self.version = version
550 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700551 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700552 self.generated = False
553
554 @property
555 @memoize
556 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700557 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700558
559 @property
560 def name(self):
561 return "%sVer%s" % (self.interface.name, self.version.of_version)
562
563 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700564 def variable_name(self):
565 return self.name[3:]
566
567 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700568 def length(self):
569 if self.is_fixed_length:
570 return self.min_length
571 else:
572 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
573
574 @property
575 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700576 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700577 id_tuple = (self.ir_class.name, self.version.int_version)
578 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
579
580 @property
581 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700582 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700583 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
584 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700585
586 def all_properties(self):
587 return self.interface.members
588
589 def get_member(self, name):
590 for m in self.members:
591 if m.name == name:
592 return m
593
594 @property
595 @memoize
596 def data_members(self):
597 return [ prop for prop in self.members if prop.is_data ]
598
599 @property
600 @memoize
601 def fixed_value_members(self):
602 return [ prop for prop in self.members if prop.is_fixed_value ]
603
604 @property
605 @memoize
606 def public_members(self):
607 return [ prop for prop in self.members if prop.is_public ]
608
609 @property
610 @memoize
611 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700612 return self.ir_model_members + self.virtual_members
613
614 @property
615 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700616 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700617 return tuple(members)
618
619 @property
620 def virtual_members(self):
621 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
622 if self.interface.name in model.oxm_map:
623 oxm_entry = model.oxm_map[self.interface.name]
624 return (
625 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
626 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
627 )
628 else:
629 return (
630 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
631 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
632 )
633 else:
634 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700635
636 def all_versions(self):
637 return [ JavaOFVersion(int_version)
638 for int_version in of_g.unified[self.c_name]
639 if int_version != 'union' and int_version != 'object_id' ]
640
641 def version_is_inherited(self, version):
642 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
643
644 def inherited_from(self, version):
645 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
646
647 @property
648 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700649 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
650
651 @property
652 def discriminator(self):
653 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700654
655 @property
656 def is_extension(self):
657 return type_maps.message_is_extension(self.c_name, -1)
658
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700659 @property
660 def align(self):
661 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
662
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700663 @property
664 @memoize
665 def superclass(self):
666 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
667
668 @property
669 @memoize
670 def subclasses(self):
671 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
672
Andreas Wundsam27303462013-07-16 12:52:35 -0700673#######################################################################
674### Member
675#######################################################################
676
677
678class JavaMember(object):
679 """ Models a property (member) of an openflow class. """
680 def __init__(self, msg, name, java_type, member):
681 self.msg = msg
682 self.name = name
683 self.java_type = java_type
684 self.member = member
685 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700686
687 @property
688 def title_name(self):
689 return self.name[0].upper() + self.name[1:]
690
691 @property
692 def constant_name(self):
693 return self.c_name.upper()
694
695 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700696 def getter_name(self):
697 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
698
699 @property
700 def setter_name(self):
701 return "set" + self.title_name
702
703 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700704 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700705 if self.is_fixed_value:
706 return self.constant_name
707 else:
708 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700709
710 @property
711 def default_value(self):
712 java_type = self.java_type.public_type;
713
Andreas Wundsam27303462013-07-16 12:52:35 -0700714 if self.is_fixed_value:
715 return self.enum_value
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700716 elif java_type == "OFOxmList":
717 return "OFOxmList.EMPTY"
Andreas Wundsam27303462013-07-16 12:52:35 -0700718 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700719 return "Collections.emptyList()"
720 elif java_type == "boolean":
721 return "false";
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700722 elif self.java_type.is_array:
723 return "new %s[0]" % java_type[:-2]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700724 elif java_type in ("byte", "char", "short", "int", "long"):
725 return "({0}) 0".format(java_type);
726 else:
727 return "null";
728
729 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700730 def enum_value(self):
731 if self.name == "version":
732 return "OFVersion.%s" % self.msg.version.constant_version
733
734 java_type = self.java_type.public_type;
735 try:
736 global model
737 enum = model.enum_by_name(java_type)
738 entry = enum.entry_by_version_value(self.msg.version, self.value)
739 return "%s.%s" % ( enum.name, entry.name)
740 except KeyError, e:
741 print e.message
742 return self.value
743
744 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700745 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700746 return isinstance(self.member, OFPadMember)
747
748 def is_type_value(self, version=None):
749 if(version==None):
750 return any(self.is_type_value(version) for version in self.msg.all_versions)
751 try:
752 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
753 except:
754 return False
755
756 @property
757 def is_field_length_value(self):
758 return isinstance(self.member, OFFieldLengthMember)
759
760 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700761 def is_discriminator(self):
762 return isinstance(self.member, OFDiscriminatorMember)
763
764 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700765 def is_length_value(self):
766 return isinstance(self.member, OFLengthMember)
767
768 @property
769 def is_public(self):
770 return not (self.is_pad or self.is_length_value)
771
772 @property
773 def is_data(self):
774 return isinstance(self.member, OFDataMember) and self.name != "version"
775
776 @property
777 def is_fixed_value(self):
778 return hasattr(self.member, "value") or self.name == "version" \
779 or ( self.name == "length" and self.msg.is_fixed_length) \
780 or ( self.name == "len" and self.msg.is_fixed_length)
781
782 @property
783 def value(self):
784 if self.name == "version":
785 return self.msg.version.int_version
786 elif self.name == "length" or self.name == "len":
787 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700788 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700789 return self.java_type.format_value(self.member.value)
790
791 @property
792 def priv_value(self):
793 if self.name == "version":
794 return self.msg.version.int_version
795 elif self.name == "length" or self.name == "len":
796 return self.msg.length
797 else:
798 return self.java_type.format_value(self.member.value, pub_type=False)
799
Andreas Wundsam27303462013-07-16 12:52:35 -0700800
801 @property
802 def is_writeable(self):
803 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
804
805 def get_type_value_info(self, version):
806 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700807
808 @property
809 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700810 if hasattr(self.member, "length"):
811 return self.member.length
812 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700813 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700814 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700815
816 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700817 def for_of_member(java_class, member):
818 if isinstance(member, OFPadMember):
819 return JavaMember(None, "", None, member)
820 else:
821 if member.name == 'len':
822 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700823 elif member.name == 'value_mask':
824 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700825 else:
826 name = java_type.name_c_to_camel(member.name)
827 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
828 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700829
830 @property
831 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700832 if not self.msg.c_name in of_g.unified:
833 print("%s not self.unified" % self.msg.c_name)
834 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700835 for version in of_g.unified[self.msg.c_name]:
836 if version == 'union' or version =='object_id':
837 continue
838 if 'use_version' in of_g.unified[self.msg.c_name][version]:
839 continue
840
Andreas Wundsam27303462013-07-16 12:52:35 -0700841 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 -0700842 return False
843 return True
844
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700845 @property
846 def is_virtual(self):
847 return False
848
Andreas Wundsam27303462013-07-16 12:52:35 -0700849 def __hash__(self):
850 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700851
Andreas Wundsam27303462013-07-16 12:52:35 -0700852 def __eq__(self, other):
853 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700854 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700855 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700856
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700857class JavaVirtualMember(JavaMember):
858 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
859 def __init__(self, msg, name, java_type, value=None):
860 JavaMember.__init__(self, msg, name, java_type, member=None)
861 self._value = value
862
863 @property
864 def is_fixed_value(self):
865 return True
866
867 @property
868 def value(self):
869 return self._value
870
871 @property
872 def priv_value(self):
873 return self._value
874
875
876 @property
877 def is_universal(self):
878 return True
879
880 @property
881 def is_virtual(self):
882 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700883
884#######################################################################
885### Unit Test
886#######################################################################
887
Yotam Harchol466b3212013-08-15 12:14:46 -0700888class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700889 def __init__(self, java_class):
890 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700891 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700892 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700893 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
894 name=java_class.c_name[3:]) + "{i}.data"
895 test_class_name = self.java_class.name + "Test"
896 self.test_units = []
897 if test_data.exists(first_data_file_name):
898 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
899 i = 1
900 while test_data.exists(data_file_template.format(i=i)):
901 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
902 i = i + 1
903
904 @property
905 def package(self):
906 return self.java_class.package
907
908 @property
909 def has_test_data(self):
910 return len(self.test_units) > 0
911
912 @property
913 def length(self):
914 return len(self.test_units)
915
916 def get_test_unit(self, i):
917 return self.test_units[i]
918
919
920class JavaUnitTest(object):
921 def __init__(self, java_class, file_name=None, test_class_name=None):
922 self.java_class = java_class
923 if file_name is None:
924 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
925 name=java_class.c_name[3:])
926 else:
927 self.data_file_name = file_name
928 if test_class_name is None:
929 self.test_class_name = self.java_class.name + "Test"
930 else:
931 self.test_class_name = test_class_name
932
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700933 @property
934 def package(self):
935 return self.java_class.package
936
937 @property
938 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700939 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700940
941 @property
942 def has_test_data(self):
943 return test_data.exists(self.data_file_name)
944
945 @property
946 @memoize
947 def test_data(self):
948 return test_data.read(self.data_file_name)
949
950
Andreas Wundsam27303462013-07-16 12:52:35 -0700951#######################################################################
952### Enums
953#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700954
Andreas Wundsam27303462013-07-16 12:52:35 -0700955class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700956 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -0700957 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -0700958
959 if c_name == "of_stats_types":
960 self.name = "OFStatsType"
961 else:
962 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700963
Andreas Wundsam27303462013-07-16 12:52:35 -0700964 # Port_features has constants that start with digits
965 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700966
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700967 self.version_enums = version_enum_map
968
969 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
970 for version, ir_enum in version_enum_map.items():
971 for ir_entry in ir_enum.entries:
972 if "virtual" in ir_entry.params:
973 continue
974 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
975
Andreas Wundsam27303462013-07-16 12:52:35 -0700976 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700977 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -0700978
979 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 -0700980 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700981
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700982 def wire_type(self, version):
983 ir_enum = self.version_enums[version]
984 if "wire_type" in ir_enum.params:
985 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
986 else:
987 return java_type.u8
988
989 @property
990 def versions(self):
991 return self.version_enums.keys()
992
Andreas Wundsam27303462013-07-16 12:52:35 -0700993 @memoize
994 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700995 res = find(lambda e: e.name == name, self.entries)
996 if res:
997 return res
998 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700999 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1000
1001 @memoize
1002 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001003 res = find(lambda e: e.c_name == name, self.entries)
1004 if res:
1005 return res
1006 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001007 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1008
1009 @memoize
1010 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001011 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1012 if res:
1013 return res
1014 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001015 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1016
1017# values: Map JavaVersion->Value
1018class JavaEnumEntry(object):
1019 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001020 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001021 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1022 self.values = values
1023
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001024 def has_value(self, version):
1025 return version in self.values
1026
Andreas Wundsam27303462013-07-16 12:52:35 -07001027 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001028 return self.values[version]
1029
1030 def format_value(self, version):
1031 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001032 return res
1033
Andreas Wundsam27303462013-07-16 12:52:35 -07001034 def all_values(self, versions, not_present=None):
1035 return [ self.values[version] if version in self.values else not_present for version in versions ]