blob: 13a0d09706d61349318dd820745fc1ab03753c18 [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 Wundsamc1acfcc2013-09-20 13:10:20 -0700133 MaskedEnumGroup = namedtuple("MaskedEnumGroup", ("name", "mask", "members"))
134
135 masked_enum_groups = defaultdict(lambda: (),
136 OFPortState= (MaskedEnumGroup("stp_flags", mask="STP_MASK", members=set(("STP_LISTEN", "STP_LEARN", "STP_FORWARD", "STP_BLOCK"))), )
137 )
138
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700139 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700140 @property
141 def variable_name(self):
142 return self.name[0].lower() + self.name[1:]
143
144 @property
145 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700146 prefix = "is" if self.type == java_type.boolean else "get"
147 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700148
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700149 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
150
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700151 def gen_port_speed(enum_entry):
152 splits = enum_entry.name.split("_")
153 if len(splits)>=2:
154 m = re.match(r'\d+[MGTP]B', splits[1])
155 if m:
156 return "PortSpeed.SPEED_{}".format(splits[1])
157 return "PortSpeed.SPEED_NONE";
158
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700159 def gen_stp_state(enum_entry):
160 splits = enum_entry.name.split("_")
161 if len(splits)>=1:
162 if splits[0] == "STP":
163 return "true"
164 return "false"
165
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700166 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700167 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
168 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700169 )
170
Andreas Wundsam27303462013-07-16 12:52:35 -0700171 @property
172 @memoize
173 def versions(self):
174 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
175
176 @property
177 @memoize
178 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700179 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700180
181 for raw_version, of_protocol in of_g.ir.items():
182 jversion = JavaOFVersion(of_protocol.wire_version)
183
184 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700185 if not of_class.name in version_map_per_class:
186 version_map_per_class[of_class.name] = collections.OrderedDict()
187
Andreas Wundsam27303462013-07-16 12:52:35 -0700188 version_map_per_class[of_class.name][jversion] = of_class
189
190 interfaces = []
191 for class_name, version_map in version_map_per_class.items():
192 interfaces.append(JavaOFInterface(class_name, version_map))
193
Andreas Wundsambe168f72013-08-03 22:49:35 -0700194 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
195
Andreas Wundsam27303462013-07-16 12:52:35 -0700196 return interfaces
197
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700198 @memoize
199 def interface_by_name(self, name):
200 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
201
Andreas Wundsam27303462013-07-16 12:52:35 -0700202 @property
203 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700204 def all_classes(self):
205 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
206
207 @property
208 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700209 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700210 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700211
212 for version in self.versions:
213 of_protocol = of_g.ir[version.int_version]
214 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700215 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700216
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700217 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
218 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700219
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700220 # inelegant - need java name here
221 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700222 return enums
223
224 @memoize
225 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700226 res = find(lambda e: e.name == name, self.enums)
227 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700228 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700229 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700230
Andreas Wundsam5204de22013-07-30 11:34:45 -0700231 @property
232 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700233 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700234 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700235
236 factories = OrderedDict()
237
238 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
239 for base_class in sub_factory_classes:
240 package = base_class[2:].lower()
241 remove_prefix = base_class[2].lower() + base_class[3:]
242
243 # HACK need to have a better way to deal with parameterized base classes
244 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
245
246 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
247 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
248
249 factories[""] = OFFactory(
250 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700251 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700252 remove_prefix="",
253 members=[], base_class="OFMessage", sub_factories=OrderedDict(
254 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
255
256 for i in self.interfaces:
257 for n, factory in factories.items():
258 if n == "":
259 factory.members.append(i)
260 break
261 else:
262 super_class = self.interface_by_name(n)
263 if i.is_instance_of(super_class):
264 factory.members.append(i)
265 break
266 return factories.values()
Andreas Wundsam5204de22013-07-30 11:34:45 -0700267
268 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700269 """ return wether or not to generate implementation class clazz.
270 Now true for everything except OFTableModVer10.
271 @param clazz JavaOFClass instance
272 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700273 if clazz.interface.name.startswith("OFMatchV"):
274 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700275 elif clazz.name == "OFTableModVer10":
276 # tablemod ver 10 is a hack and has no oftype defined
277 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700278 if loxi_utils.class_is_message(clazz.interface.c_name):
279 return True
280 if loxi_utils.class_is_oxm(clazz.interface.c_name):
281 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700282 if loxi_utils.class_is_action(clazz.interface.c_name):
283 return True
284 if loxi_utils.class_is_instruction(clazz.interface.c_name):
285 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700286 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700287 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700288
289
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700290class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700291 @property
292 def factory_classes(self):
293 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700294 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700295 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700296 interface=self,
297 version=version
298 ) for version in model.versions ]
299
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700300 def method_name(self, member, builder=True):
301 n = member.variable_name
302 if n.startswith(self.remove_prefix):
303 n = n[len(self.remove_prefix):]
304 n = n[0].lower() + n[1:]
305 if builder:
306 return "build" + n[0].upper() + n[1:]
307 else:
308 return n
Andreas Wundsam5204de22013-07-30 11:34:45 -0700309
310OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700311class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
312 @property
313 def base_class(self):
314 return self.interface.base_class
315
316 @property
317 def versioned_base_class(self):
318 base_class_interface = model.interface_by_name(self.interface.base_class)
319 if base_class_interface and base_class_interface.has_version(self.version):
320 return base_class_interface.versioned_class(self.version)
321 else:
322 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700323
Andreas Wundsam27303462013-07-16 12:52:35 -0700324model = JavaModel()
325
326#######################################################################
327### OFVersion
328#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700329
330class JavaOFVersion(object):
331 """ Models a version of OpenFlow. contains methods to convert the internal
332 Loxi version to a java constant / a string """
333 def __init__(self, int_version):
334 self.int_version = int(int_version)
335
336 @property
337 def of_version(self):
338 return "1" + str(int(self.int_version) - 1)
339
340 @property
341 def constant_version(self):
342 return "OF_" + self.of_version
343
Andreas Wundsam27303462013-07-16 12:52:35 -0700344 def __repr__(self):
345 return "JavaOFVersion(%d)" % self.int_version
346
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700347 def __str__(self):
348 return of_g.param_version_names[self.int_version]
349
Andreas Wundsam27303462013-07-16 12:52:35 -0700350 def __hash__(self):
351 return hash(self.int_version)
352
353 def __eq__(self, other):
354 if other is None or type(self) != type(other):
355 return False
356 return (self.int_version,) == (other.int_version,)
357
358#######################################################################
359### Interface
360#######################################################################
361
362class JavaOFInterface(object):
363 """ Models an OpenFlow Message class for the purpose of the java class.
364 Version agnostic, in contrast to the loxi_ir python model.
365 """
366 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700367 """"
368 @param c_name: loxi style name (e.g., of_flow_add)
369 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
370 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700371 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700372 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700373 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700374 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 -0700375 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700376 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700377 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700378 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700379 self.constant_name = c_name.upper().replace("OF_", "")
380
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700381 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700382 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700383 if self.name != parent_interface:
384 self.parent_interface = parent_interface
385 else:
386 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700387
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700388 @property
389 @memoize
390 def all_parent_interfaces(self):
391 return [ "OFObject" ] + \
392 ([ self.parent_interface ] if self.parent_interface else [] )+ \
393 self.additional_parent_interfaces
394 @property
395 @memoize
396 def additional_parent_interfaces(self):
397 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
398 m = re.match(r'(.*)Request$', self.name)
399 if m:
400 reply_name = m.group(1) + "Reply"
401 if model.interface_by_name(reply_name):
402 return ["OFRequest<%s>" % reply_name ]
403 return []
404
405
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700406 def is_instance_of(self, other_class):
407 if self == other_class:
408 return True
409 parent = self.super_class
410 if parent is None:
411 return False
412 else:
413 return parent.is_instance_of(other_class)
414
415 @property
416 def super_class(self):
417 if not self.parent_interface:
418 return None
419 else:
420 return model.interface_by_name(self.parent_interface)
421
422
423 def inherited_declaration(self, type_spec="?"):
424 if self.type_annotation:
425 return "%s<%s>" % (self.name, type_spec)
426 else:
427 return "%s" % self.name
428
429 @property
430 def type_variable(self):
431 if self.type_annotation:
432 return "<T>"
433 else:
434 return "";
435
Andreas Wundsam27303462013-07-16 12:52:35 -0700436 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700437 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
438 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
439 # model (note, that the loxi model is on versioned classes). Should check/infer the
440 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700441 if re.match(r'OF.+StatsRequest$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700442 return ("", "OFStatsRequest", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700443 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700444 return ("", "OFStatsReply", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700445 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700446 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700447 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 -0700448 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700449 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 -0700450 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700451 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
452 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700453 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700454 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700455 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700456 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700457 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700458 if re.match(r'OFActionBsn.+', self.name):
459 return ("action", "OFActionBsn", None)
460 elif re.match(r'OFActionNicira.+', self.name):
461 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700462 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
463 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700464 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700465 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700466 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700467 return ("", "OFBsnVport", None)
468 elif self.name == "OFOxm":
469 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700470 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700471 if self.name in model.oxm_map:
472 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
473 else:
474 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700475 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700476 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700477 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700478 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700479 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700480 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700481 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700482 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700483 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700484 return ("", None, None)
485
486 @property
487 @memoize
488 def writeable_members(self):
489 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700490
491 @property
492 @memoize
493 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700494 return self.ir_model_members + self.virtual_members
495
496 @property
497 @memoize
498 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700499 """return a list of all members to be exposed by this interface. Corresponds to
500 the union of the members of the vesioned classes without length, fieldlength
501 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700502 all_versions = []
503 member_map = collections.OrderedDict()
504
505 for (version, of_class) in self.version_map.items():
506 for of_member in of_class.members:
507 if isinstance(of_member, OFLengthMember) or \
508 isinstance(of_member, OFFieldLengthMember) or \
509 isinstance(of_member, OFPadMember):
510 continue
511 if of_member.name not in member_map:
512 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
513
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700514 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 -0700515
516 @property
517 def virtual_members(self):
518 if self.name == "OFOxm":
519 return (
520 JavaVirtualMember(self, "value", java_type.generic_t),
521 JavaVirtualMember(self, "mask", java_type.generic_t),
522 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
523 JavaVirtualMember(self, "masked", java_type.boolean),
524 )
525 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
526 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
527 if self.name in model.oxm_map \
528 else java_type.make_match_field_jtype()
529
530 return (
531 JavaVirtualMember(self, "matchField", field_type),
532 JavaVirtualMember(self, "masked", java_type.boolean),
533 ) \
534 + \
535 (
536 ( 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
537 ()
538 )
539 else:
540 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700541
542 @property
543 @memoize
544 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700545 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700546 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 -0700547
548 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700549 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700550 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700551 return len(self.all_versions) == len(model.versions)
552
553 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700554 @memoize
555 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700556 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700557 return self.version_map.keys()
558
Andreas Wundsam5204de22013-07-30 11:34:45 -0700559 def has_version(self, version):
560 return version in self.version_map
561
Andreas Wundsam27303462013-07-16 12:52:35 -0700562 def versioned_class(self, version):
563 return JavaOFClass(self, version, self.version_map[version])
564
565 @property
566 @memoize
567 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700568 return [ self.versioned_class(version) for version in self.all_versions ]
569
570#######################################################################
571### (Versioned) Classes
572#######################################################################
573
574class JavaOFClass(object):
575 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700576 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700577 """
578 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700579 """
580 @param interface JavaOFInterface instance of the parent interface
581 @param version JavaOFVersion
582 @param ir_class OFClass from loxi_ir
583 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700584 self.interface = interface
585 self.ir_class = ir_class
586 self.c_name = self.ir_class.name
587 self.version = version
588 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700589 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700590 self.generated = False
591
592 @property
593 @memoize
594 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700595 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700596
597 @property
598 def name(self):
599 return "%sVer%s" % (self.interface.name, self.version.of_version)
600
601 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700602 def variable_name(self):
603 return self.name[3:]
604
605 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700606 def length(self):
607 if self.is_fixed_length:
608 return self.min_length
609 else:
610 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
611
612 @property
613 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700614 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700615 id_tuple = (self.ir_class.name, self.version.int_version)
616 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
617
618 @property
619 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700620 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700621 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
622 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700623
624 def all_properties(self):
625 return self.interface.members
626
627 def get_member(self, name):
628 for m in self.members:
629 if m.name == name:
630 return m
631
632 @property
633 @memoize
634 def data_members(self):
635 return [ prop for prop in self.members if prop.is_data ]
636
637 @property
638 @memoize
639 def fixed_value_members(self):
640 return [ prop for prop in self.members if prop.is_fixed_value ]
641
642 @property
643 @memoize
644 def public_members(self):
645 return [ prop for prop in self.members if prop.is_public ]
646
647 @property
648 @memoize
649 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700650 return self.ir_model_members + self.virtual_members
651
652 @property
653 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700654 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700655 return tuple(members)
656
657 @property
658 def virtual_members(self):
659 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
660 if self.interface.name in model.oxm_map:
661 oxm_entry = model.oxm_map[self.interface.name]
662 return (
663 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
664 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
665 )
666 else:
667 return (
668 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
669 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
670 )
671 else:
672 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700673
674 def all_versions(self):
675 return [ JavaOFVersion(int_version)
676 for int_version in of_g.unified[self.c_name]
677 if int_version != 'union' and int_version != 'object_id' ]
678
679 def version_is_inherited(self, version):
680 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
681
682 def inherited_from(self, version):
683 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
684
685 @property
686 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700687 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
688
689 @property
690 def discriminator(self):
691 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700692
693 @property
694 def is_extension(self):
695 return type_maps.message_is_extension(self.c_name, -1)
696
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700697 @property
698 def align(self):
699 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
700
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700701 @property
702 @memoize
703 def superclass(self):
704 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
705
706 @property
707 @memoize
708 def subclasses(self):
709 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
710
Andreas Wundsam27303462013-07-16 12:52:35 -0700711#######################################################################
712### Member
713#######################################################################
714
715
716class JavaMember(object):
717 """ Models a property (member) of an openflow class. """
718 def __init__(self, msg, name, java_type, member):
719 self.msg = msg
720 self.name = name
721 self.java_type = java_type
722 self.member = member
723 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700724
725 @property
726 def title_name(self):
727 return self.name[0].upper() + self.name[1:]
728
729 @property
730 def constant_name(self):
731 return self.c_name.upper()
732
733 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700734 def getter_name(self):
735 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
736
737 @property
738 def setter_name(self):
739 return "set" + self.title_name
740
741 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700742 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700743 if self.is_fixed_value:
744 return self.constant_name
745 else:
746 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700747
748 @property
749 def default_value(self):
750 java_type = self.java_type.public_type;
751
Andreas Wundsam27303462013-07-16 12:52:35 -0700752 if self.is_fixed_value:
753 return self.enum_value
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700754 elif java_type == "OFOxmList":
755 return "OFOxmList.EMPTY"
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700756 elif re.match(r'Set.*', java_type):
757 return "Collections.emptySet()"
Andreas Wundsam27303462013-07-16 12:52:35 -0700758 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700759 return "Collections.emptyList()"
760 elif java_type == "boolean":
761 return "false";
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700762 elif self.java_type.is_array:
763 return "new %s[0]" % java_type[:-2]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700764 elif java_type in ("byte", "char", "short", "int", "long"):
765 return "({0}) 0".format(java_type);
766 else:
767 return "null";
768
769 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700770 def enum_value(self):
771 if self.name == "version":
772 return "OFVersion.%s" % self.msg.version.constant_version
773
774 java_type = self.java_type.public_type;
775 try:
776 global model
777 enum = model.enum_by_name(java_type)
778 entry = enum.entry_by_version_value(self.msg.version, self.value)
779 return "%s.%s" % ( enum.name, entry.name)
780 except KeyError, e:
781 print e.message
782 return self.value
783
784 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700785 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700786 return isinstance(self.member, OFPadMember)
787
788 def is_type_value(self, version=None):
789 if(version==None):
790 return any(self.is_type_value(version) for version in self.msg.all_versions)
791 try:
792 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
793 except:
794 return False
795
796 @property
797 def is_field_length_value(self):
798 return isinstance(self.member, OFFieldLengthMember)
799
800 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700801 def is_discriminator(self):
802 return isinstance(self.member, OFDiscriminatorMember)
803
804 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700805 def is_length_value(self):
806 return isinstance(self.member, OFLengthMember)
807
808 @property
809 def is_public(self):
810 return not (self.is_pad or self.is_length_value)
811
812 @property
813 def is_data(self):
814 return isinstance(self.member, OFDataMember) and self.name != "version"
815
816 @property
817 def is_fixed_value(self):
818 return hasattr(self.member, "value") or self.name == "version" \
819 or ( self.name == "length" and self.msg.is_fixed_length) \
820 or ( self.name == "len" and self.msg.is_fixed_length)
821
822 @property
823 def value(self):
824 if self.name == "version":
825 return self.msg.version.int_version
826 elif self.name == "length" or self.name == "len":
827 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700828 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700829 return self.java_type.format_value(self.member.value)
830
831 @property
832 def priv_value(self):
833 if self.name == "version":
834 return self.msg.version.int_version
835 elif self.name == "length" or self.name == "len":
836 return self.msg.length
837 else:
838 return self.java_type.format_value(self.member.value, pub_type=False)
839
Andreas Wundsam27303462013-07-16 12:52:35 -0700840
841 @property
842 def is_writeable(self):
843 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
844
845 def get_type_value_info(self, version):
846 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700847
848 @property
849 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700850 if hasattr(self.member, "length"):
851 return self.member.length
852 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700853 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700854 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700855
856 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700857 def for_of_member(java_class, member):
858 if isinstance(member, OFPadMember):
859 return JavaMember(None, "", None, member)
860 else:
861 if member.name == 'len':
862 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700863 elif member.name == 'value_mask':
864 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700865 else:
866 name = java_type.name_c_to_camel(member.name)
867 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
868 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700869
870 @property
871 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700872 if not self.msg.c_name in of_g.unified:
873 print("%s not self.unified" % self.msg.c_name)
874 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700875 for version in of_g.unified[self.msg.c_name]:
876 if version == 'union' or version =='object_id':
877 continue
878 if 'use_version' in of_g.unified[self.msg.c_name][version]:
879 continue
880
Andreas Wundsam27303462013-07-16 12:52:35 -0700881 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 -0700882 return False
883 return True
884
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700885 @property
886 def is_virtual(self):
887 return False
888
Andreas Wundsam27303462013-07-16 12:52:35 -0700889 def __hash__(self):
890 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700891
Andreas Wundsam27303462013-07-16 12:52:35 -0700892 def __eq__(self, other):
893 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700894 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700895 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700896
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700897class JavaVirtualMember(JavaMember):
898 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
899 def __init__(self, msg, name, java_type, value=None):
900 JavaMember.__init__(self, msg, name, java_type, member=None)
901 self._value = value
902
903 @property
904 def is_fixed_value(self):
905 return True
906
907 @property
908 def value(self):
909 return self._value
910
911 @property
912 def priv_value(self):
913 return self._value
914
915
916 @property
917 def is_universal(self):
918 return True
919
920 @property
921 def is_virtual(self):
922 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700923
924#######################################################################
925### Unit Test
926#######################################################################
927
Yotam Harchol466b3212013-08-15 12:14:46 -0700928class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700929 def __init__(self, java_class):
930 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700931 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700932 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700933 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
934 name=java_class.c_name[3:]) + "{i}.data"
935 test_class_name = self.java_class.name + "Test"
936 self.test_units = []
937 if test_data.exists(first_data_file_name):
938 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
939 i = 1
940 while test_data.exists(data_file_template.format(i=i)):
941 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
942 i = i + 1
943
944 @property
945 def package(self):
946 return self.java_class.package
947
948 @property
949 def has_test_data(self):
950 return len(self.test_units) > 0
951
952 @property
953 def length(self):
954 return len(self.test_units)
955
956 def get_test_unit(self, i):
957 return self.test_units[i]
958
959
960class JavaUnitTest(object):
961 def __init__(self, java_class, file_name=None, test_class_name=None):
962 self.java_class = java_class
963 if file_name is None:
964 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
965 name=java_class.c_name[3:])
966 else:
967 self.data_file_name = file_name
968 if test_class_name is None:
969 self.test_class_name = self.java_class.name + "Test"
970 else:
971 self.test_class_name = test_class_name
972
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700973 @property
974 def package(self):
975 return self.java_class.package
976
977 @property
978 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700979 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700980
981 @property
982 def has_test_data(self):
983 return test_data.exists(self.data_file_name)
984
985 @property
986 @memoize
987 def test_data(self):
988 return test_data.read(self.data_file_name)
989
990
Andreas Wundsam27303462013-07-16 12:52:35 -0700991#######################################################################
992### Enums
993#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700994
Andreas Wundsam27303462013-07-16 12:52:35 -0700995class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700996 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -0700997 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -0700998
999 if c_name == "of_stats_types":
1000 self.name = "OFStatsType"
1001 else:
1002 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001003
Andreas Wundsam27303462013-07-16 12:52:35 -07001004 # Port_features has constants that start with digits
1005 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001006
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001007 self.version_enums = version_enum_map
1008
1009 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1010 for version, ir_enum in version_enum_map.items():
1011 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001012 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1013
Andreas Wundsam27303462013-07-16 12:52:35 -07001014 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001015 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001016
1017 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 -07001018 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001019
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001020 self.metadata = model.enum_metadata_map[self.name]
1021
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001022 def wire_type(self, version):
1023 ir_enum = self.version_enums[version]
1024 if "wire_type" in ir_enum.params:
1025 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1026 else:
1027 return java_type.u8
1028
1029 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001030 @memoize
1031 def is_bitmask(self):
1032 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1033
1034 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001035 def versions(self):
1036 return self.version_enums.keys()
1037
Andreas Wundsam27303462013-07-16 12:52:35 -07001038 @memoize
1039 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001040 res = find(lambda e: e.name == name, self.entries)
1041 if res:
1042 return res
1043 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001044 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1045
1046 @memoize
1047 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001048 res = find(lambda e: e.c_name == name, self.entries)
1049 if res:
1050 return res
1051 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001052 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1053
1054 @memoize
1055 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001056 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1057 if res:
1058 return res
1059 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001060 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1061
1062# values: Map JavaVersion->Value
1063class JavaEnumEntry(object):
1064 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001065 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001066 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1067 self.values = values
1068
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001069 @property
1070 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001071 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001072
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001073 def has_value(self, version):
1074 return version in self.values
1075
Andreas Wundsam27303462013-07-16 12:52:35 -07001076 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001077 return self.values[version]
1078
1079 def format_value(self, version):
1080 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001081 return res
1082
Andreas Wundsam27303462013-07-16 12:52:35 -07001083 def all_values(self, versions, not_present=None):
1084 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001085
1086 @property
1087 @memoize
1088 def masked_enum_group(self):
1089 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1090 return group
1091
1092 @property
1093 @memoize
1094 def is_mask(self):
1095 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])