blob: 68c231677b08a768f394721350f41616885dd796 [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 Wundsamf1949682013-09-23 14:48:31 -070050 # registry for enums that should not be generated
51 # set(${java_enum_name})
Rob Vaterlausfbd5b6b2013-09-24 15:55:47 -070052 enum_blacklist = set(("OFDefinitions", "OFPortNo",))
Andreas Wundsamf1949682013-09-23 14:48:31 -070053 # registry for enum *entry* that should not be generated
54 # map: ${java_enum_name} -> set(${java_entry_entry_name})
Andreas Wundsam43526532013-08-01 22:03:50 -070055 enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
Andreas Wundsamf1949682013-09-23 14:48:31 -070056
57 # registry of interfaces that should not be generated
58 # set(java_names)
Andreas Wundsambe168f72013-08-03 22:49:35 -070059 # OFUint structs are there for god-knows what in loci. We certainly don't need them.
60 interface_blacklist = set( ("OFUint8", "OFUint32",))
Andreas Wundsamf1949682013-09-23 14:48:31 -070061 # registry of interface properties that should not be generated
62 # map: $java_type -> set(java_name_property)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070063 read_blacklist = defaultdict(lambda: set(), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070064 # map: $java_type -> set(java_name_property)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070065 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 Wundsamf1949682013-09-23 14:48:31 -070066 # interfaces that are virtual
Andreas Wundsam001b1822013-08-02 22:25:55 -070067 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070068
Andreas Wundsam2be7da52013-08-22 07:34:25 -070069 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
Yotam Harchole5d92972013-08-22 14:18:36 -070070 oxm_map = { "OFOxmInPort": OxmMapEntry("OFPort", "IN_PORT", False),
71 "OFOxmInPortMasked": OxmMapEntry("OFPort", "IN_PORT", True),
72 "OFOxmInPhyPort": OxmMapEntry("OFPort", "IN_PHY_PORT", False),
73 "OFOxmInPhyPortMasked": OxmMapEntry("OFPort", "IN_PHY_PORT", True),
74 "OFOxmMetadata": OxmMapEntry("OFMetadata", "METADATA", False),
75 "OFOxmMetadataMasked": OxmMapEntry("OFMetadata", "METADATA", True),
76 "OFOxmEthDst": OxmMapEntry("MacAddress", "ETH_DST", False),
77 "OFOxmEthDstMasked": OxmMapEntry("MacAddress", "ETH_DST", True),
78 "OFOxmEthSrc": OxmMapEntry("MacAddress", "ETH_SRC", False),
79 "OFOxmEthSrcMasked": OxmMapEntry("MacAddress", "ETH_SRC", True),
80 "OFOxmEthType": OxmMapEntry("EthType", "ETH_TYPE", False),
81 "OFOxmEthTypeMasked": OxmMapEntry("EthType", "ETH_TYPE", True),
82 "OFOxmVlanVid": OxmMapEntry("VlanVid", "VLAN_VID", False),
83 "OFOxmVlanVidMasked": OxmMapEntry("VlanVid", "VLAN_VID", True),
84 "OFOxmVlanPcp": OxmMapEntry("VlanPcp", "VLAN_PCP", False),
85 "OFOxmVlanPcpMasked": OxmMapEntry("VlanPcp", "VLAN_PCP", True),
86 "OFOxmIpDscp": OxmMapEntry("IpDscp", "IP_DSCP", False),
87 "OFOxmIpDscpMasked": OxmMapEntry("IpDscp", "IP_DSCP", True),
88 "OFOxmIpEcn": OxmMapEntry("IpEcn", "IP_ECN", False),
89 "OFOxmIpEcnMasked": OxmMapEntry("IpEcn", "IP_ECN", True),
90 "OFOxmIpProto": OxmMapEntry("IpProtocol", "IP_PROTO", False),
91 "OFOxmIpProtoMasked": OxmMapEntry("IpProtocol", "IP_PROTO", True),
Yotam Harchola289d552013-09-16 10:10:40 -070092 "OFOxmIpv4Src": OxmMapEntry("IPv4Address", "IPV4_SRC", False),
93 "OFOxmIpv4SrcMasked": OxmMapEntry("IPv4Address", "IPV4_SRC", True),
94 "OFOxmIpv4Dst": OxmMapEntry("IPv4Address", "IPV4_DST", False),
95 "OFOxmIpv4DstMasked": OxmMapEntry("IPv4Address", "IPV4_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -070096 "OFOxmTcpSrc": OxmMapEntry("TransportPort", "TCP_SRC", False),
97 "OFOxmTcpSrcMasked": OxmMapEntry("TransportPort", "TCP_SRC", True),
98 "OFOxmTcpDst": OxmMapEntry("TransportPort", "TCP_DST", False),
99 "OFOxmTcpDstMasked": OxmMapEntry("TransportPort", "TCP_DST", True),
100 "OFOxmUdpSrc": OxmMapEntry("TransportPort", "UDP_SRC", False),
101 "OFOxmUdpSrcMasked": OxmMapEntry("TransportPort", "UDP_SRC", True),
102 "OFOxmUdpDst": OxmMapEntry("TransportPort", "UDP_DST", False),
103 "OFOxmUdpDstMasked": OxmMapEntry("TransportPort", "UDP_DST", True),
104 "OFOxmSctpSrc": OxmMapEntry("TransportPort", "SCTP_SRC", False),
105 "OFOxmSctpSrcMasked": OxmMapEntry("TransportPort", "SCTP_SRC", True),
106 "OFOxmSctpDst": OxmMapEntry("TransportPort", "SCTP_DST", False),
107 "OFOxmSctpDstMasked": OxmMapEntry("TransportPort", "SCTP_DST", True),
108 "OFOxmIcmpv4Type": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", False),
109 "OFOxmIcmpv4TypeMasked": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", True),
110 "OFOxmIcmpv4Code": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", False),
111 "OFOxmIcmpv4CodeMasked": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", True),
112 "OFOxmArpOp": OxmMapEntry("ArpOpcode", "ARP_OP", False),
113 "OFOxmArpOpMasked": OxmMapEntry("ArpOpcode", "ARP_OP", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700114 "OFOxmArpSpa": OxmMapEntry("IPv4Address", "ARP_SPA", False),
115 "OFOxmArpSpaMasked": OxmMapEntry("IPv4Address", "ARP_SPA", True),
116 "OFOxmArpTpa": OxmMapEntry("IPv4Address", "ARP_TPA", False),
117 "OFOxmArpTpaMasked": OxmMapEntry("IPv4Address", "ARP_TPA", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700118 "OFOxmArpSha": OxmMapEntry("MacAddress", "ARP_SHA", False),
119 "OFOxmArpShaMasked": OxmMapEntry("MacAddress", "ARP_SHA", True),
120 "OFOxmArpTha": OxmMapEntry("MacAddress", "ARP_THA", False),
121 "OFOxmArpThaMasked": OxmMapEntry("MacAddress", "ARP_THA", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700122 "OFOxmIpv6Src": OxmMapEntry("IPv6Address", "IPV6_SRC", False),
123 "OFOxmIpv6SrcMasked": OxmMapEntry("IPv6Address", "IPV6_SRC", True),
124 "OFOxmIpv6Dst": OxmMapEntry("IPv6Address", "IPV6_DST", False),
125 "OFOxmIpv6DstMasked": OxmMapEntry("IPv6Address", "IPV6_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700126 "OFOxmIpv6Flabel": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", False),
Yotam Harchola86e4252013-09-06 15:36:28 -0700127 "OFOxmIpv6FlabelMasked": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True),
128 "OFOxmIcmpv6Type": OxmMapEntry("U8", "ICMPV6_TYPE", False),
129 "OFOxmIcmpv6TypeMasked": OxmMapEntry("U8", "ICMPV6_TYPE", True),
130 "OFOxmIcmpv6Code": OxmMapEntry("U8", "ICMPV6_CODE", False),
131 "OFOxmIcmpv6CodeMasked": OxmMapEntry("U8", "ICMPV6_CODE", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700132 "OFOxmIpv6NdTarget": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", False),
133 "OFOxmIpv6NdTargetMasked": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", True),
Yotam Harchola86e4252013-09-06 15:36:28 -0700134 "OFOxmIpv6NdSll": OxmMapEntry("MacAddress", "IPV6_ND_SLL", False),
135 "OFOxmIpv6NdSllMasked": OxmMapEntry("MacAddress", "IPV6_ND_SLL", True),
136 "OFOxmIpv6NdTll": OxmMapEntry("MacAddress", "IPV6_ND_TLL", False),
137 "OFOxmIpv6NdTllMasked": OxmMapEntry("MacAddress", "IPV6_ND_TLL", True),
138 "OFOxmMplsLabel": OxmMapEntry("U32", "MPLS_LABEL", False),
139 "OFOxmMplsLabelMasked": OxmMapEntry("U32", "MPLS_LABEL", True),
140 "OFOxmMplsTc": OxmMapEntry("U8", "MPLS_TC", False),
141 "OFOxmMplsTcMasked": OxmMapEntry("U8", "MPLS_TC", True)
142 }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700143
Andreas Wundsamf1949682013-09-23 14:48:31 -0700144 # Registry of nullable properties:
145 # ${java_class_name} -> set(${java_property_name})
146 nullable_map = defaultdict(lambda: set(),
147 )
148
149 # represents a subgroup of a bitmask enum that is actualy a normal enumerable within a masked part of the enum
150 # e.g., the flags STP.* in OF1.0 port state are bit mask entries, but instead enumerables according to the mask "STP_MASK"
151 # name: a name for the group
152 # mask: java name of the enum entry that defines the mask
153 # members: set of names of the members of the group
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700154 MaskedEnumGroup = namedtuple("MaskedEnumGroup", ("name", "mask", "members"))
155
Andreas Wundsamf1949682013-09-23 14:48:31 -0700156 # registry of MaskedEnumGroups (see above).
157 # map: ${java_enum_name}: tuple(MaskedEnumGroup)
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700158 masked_enum_groups = defaultdict(lambda: (),
159 OFPortState= (MaskedEnumGroup("stp_flags", mask="STP_MASK", members=set(("STP_LISTEN", "STP_LEARN", "STP_FORWARD", "STP_BLOCK"))), )
160 )
161
Andreas Wundsamf1949682013-09-23 14:48:31 -0700162 # represents a metadata property associated with an EnumClass
163 # name:
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700164 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700165 """
166 represents a metadata property associated with an Enum Class
167 @param name name of metadata property
168 @param type java_type instance describing the type
169 @value: Generator function f(entry) that generates the value
170 """
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700171 @property
172 def variable_name(self):
173 return self.name[0].lower() + self.name[1:]
174
175 @property
176 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700177 prefix = "is" if self.type == java_type.boolean else "get"
178 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700179
Andreas Wundsamf1949682013-09-23 14:48:31 -0700180 """ Metadata container. """
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700181 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
182
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700183 def gen_port_speed(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700184 """ Generator function for OFortFeatures.PortSpeed"""
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700185 splits = enum_entry.name.split("_")
186 if len(splits)>=2:
187 m = re.match(r'\d+[MGTP]B', splits[1])
188 if m:
189 return "PortSpeed.SPEED_{}".format(splits[1])
190 return "PortSpeed.SPEED_NONE";
191
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700192 def gen_stp_state(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700193 """ Generator function for OFPortState.StpState"""
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700194 splits = enum_entry.name.split("_")
195 if len(splits)>=1:
196 if splits[0] == "STP":
197 return "true"
198 return "false"
199
Andreas Wundsamf1949682013-09-23 14:48:31 -0700200 # registry for metadata properties for enums
201 # map: ${java_enum_name}: OFEnumMetadata
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700202 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700203 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
204 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700205 )
206
Andreas Wundsam27303462013-07-16 12:52:35 -0700207 @property
208 @memoize
209 def versions(self):
210 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
211
212 @property
213 @memoize
214 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700215 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700216
217 for raw_version, of_protocol in of_g.ir.items():
218 jversion = JavaOFVersion(of_protocol.wire_version)
219
220 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700221 if not of_class.name in version_map_per_class:
222 version_map_per_class[of_class.name] = collections.OrderedDict()
223
Andreas Wundsam27303462013-07-16 12:52:35 -0700224 version_map_per_class[of_class.name][jversion] = of_class
225
226 interfaces = []
227 for class_name, version_map in version_map_per_class.items():
228 interfaces.append(JavaOFInterface(class_name, version_map))
229
Andreas Wundsambe168f72013-08-03 22:49:35 -0700230 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
231
Andreas Wundsam27303462013-07-16 12:52:35 -0700232 return interfaces
233
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700234 @memoize
235 def interface_by_name(self, name):
236 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
237
Andreas Wundsam27303462013-07-16 12:52:35 -0700238 @property
239 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700240 def all_classes(self):
241 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
242
243 @property
244 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700245 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700246 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700247
248 for version in self.versions:
249 of_protocol = of_g.ir[version.int_version]
250 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700251 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700252
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700253 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
254 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700255
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700256 # inelegant - need java name here
257 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700258 return enums
259
260 @memoize
261 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700262 res = find(lambda e: e.name == name, self.enums)
263 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700264 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700265 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700266
Andreas Wundsam5204de22013-07-30 11:34:45 -0700267 @property
268 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700269 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700270 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700271
272 factories = OrderedDict()
273
274 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
275 for base_class in sub_factory_classes:
276 package = base_class[2:].lower()
277 remove_prefix = base_class[2].lower() + base_class[3:]
278
279 # HACK need to have a better way to deal with parameterized base classes
280 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
281
282 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
283 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
284
285 factories[""] = OFFactory(
286 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700287 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700288 remove_prefix="",
289 members=[], base_class="OFMessage", sub_factories=OrderedDict(
290 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
291
292 for i in self.interfaces:
293 for n, factory in factories.items():
294 if n == "":
295 factory.members.append(i)
296 break
297 else:
298 super_class = self.interface_by_name(n)
299 if i.is_instance_of(super_class):
300 factory.members.append(i)
301 break
302 return factories.values()
Andreas Wundsam5204de22013-07-30 11:34:45 -0700303
304 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700305 """ return wether or not to generate implementation class clazz.
306 Now true for everything except OFTableModVer10.
307 @param clazz JavaOFClass instance
308 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700309 if clazz.interface.name.startswith("OFMatchV"):
310 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700311 elif clazz.name == "OFTableModVer10":
312 # tablemod ver 10 is a hack and has no oftype defined
313 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700314 if loxi_utils.class_is_message(clazz.interface.c_name):
315 return True
316 if loxi_utils.class_is_oxm(clazz.interface.c_name):
317 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700318 if loxi_utils.class_is_action(clazz.interface.c_name):
319 return True
320 if loxi_utils.class_is_instruction(clazz.interface.c_name):
321 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700322 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700323 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700324
325
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700326class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700327 @property
328 def factory_classes(self):
329 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700330 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700331 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700332 interface=self,
333 version=version
334 ) for version in model.versions ]
335
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700336 def method_name(self, member, builder=True):
337 n = member.variable_name
338 if n.startswith(self.remove_prefix):
339 n = n[len(self.remove_prefix):]
340 n = n[0].lower() + n[1:]
341 if builder:
342 return "build" + n[0].upper() + n[1:]
343 else:
344 return n
Andreas Wundsam5204de22013-07-30 11:34:45 -0700345
346OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700347class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
348 @property
349 def base_class(self):
350 return self.interface.base_class
351
352 @property
353 def versioned_base_class(self):
354 base_class_interface = model.interface_by_name(self.interface.base_class)
355 if base_class_interface and base_class_interface.has_version(self.version):
356 return base_class_interface.versioned_class(self.version)
357 else:
358 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700359
Andreas Wundsam27303462013-07-16 12:52:35 -0700360model = JavaModel()
361
362#######################################################################
363### OFVersion
364#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700365
366class JavaOFVersion(object):
367 """ Models a version of OpenFlow. contains methods to convert the internal
368 Loxi version to a java constant / a string """
369 def __init__(self, int_version):
370 self.int_version = int(int_version)
371
372 @property
373 def of_version(self):
374 return "1" + str(int(self.int_version) - 1)
375
376 @property
377 def constant_version(self):
378 return "OF_" + self.of_version
379
Andreas Wundsam27303462013-07-16 12:52:35 -0700380 def __repr__(self):
381 return "JavaOFVersion(%d)" % self.int_version
382
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700383 def __str__(self):
384 return of_g.param_version_names[self.int_version]
385
Andreas Wundsam27303462013-07-16 12:52:35 -0700386 def __hash__(self):
387 return hash(self.int_version)
388
389 def __eq__(self, other):
390 if other is None or type(self) != type(other):
391 return False
392 return (self.int_version,) == (other.int_version,)
393
394#######################################################################
395### Interface
396#######################################################################
397
398class JavaOFInterface(object):
399 """ Models an OpenFlow Message class for the purpose of the java class.
400 Version agnostic, in contrast to the loxi_ir python model.
401 """
402 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700403 """"
404 @param c_name: loxi style name (e.g., of_flow_add)
405 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
406 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700407 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700408 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700409 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700410 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 -0700411 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700412 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700413 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700414 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700415 self.constant_name = c_name.upper().replace("OF_", "")
416
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700417 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700418 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700419 if self.name != parent_interface:
420 self.parent_interface = parent_interface
421 else:
422 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700423
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700424 @property
425 @memoize
426 def all_parent_interfaces(self):
427 return [ "OFObject" ] + \
428 ([ self.parent_interface ] if self.parent_interface else [] )+ \
429 self.additional_parent_interfaces
430 @property
431 @memoize
432 def additional_parent_interfaces(self):
433 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
434 m = re.match(r'(.*)Request$', self.name)
435 if m:
436 reply_name = m.group(1) + "Reply"
437 if model.interface_by_name(reply_name):
438 return ["OFRequest<%s>" % reply_name ]
439 return []
440
441
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700442 def is_instance_of(self, other_class):
443 if self == other_class:
444 return True
445 parent = self.super_class
446 if parent is None:
447 return False
448 else:
449 return parent.is_instance_of(other_class)
450
451 @property
452 def super_class(self):
453 if not self.parent_interface:
454 return None
455 else:
456 return model.interface_by_name(self.parent_interface)
457
458
459 def inherited_declaration(self, type_spec="?"):
460 if self.type_annotation:
461 return "%s<%s>" % (self.name, type_spec)
462 else:
463 return "%s" % self.name
464
465 @property
466 def type_variable(self):
467 if self.type_annotation:
468 return "<T>"
469 else:
470 return "";
471
Andreas Wundsam27303462013-07-16 12:52:35 -0700472 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700473 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
474 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
475 # model (note, that the loxi model is on versioned classes). Should check/infer the
476 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700477 if re.match(r'OF.+StatsRequest$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700478 return ("", "OFStatsRequest", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700479 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700480 return ("", "OFStatsReply", None)
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700481 elif re.match(r'OF.+ErrorMsg$', self.name):
482 return ("", "OFErrorMsg", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700483 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700484 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700485 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 -0700486 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700487 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 -0700488 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700489 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
490 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700491 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700492 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700493 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700494 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700495 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700496 if re.match(r'OFActionBsn.+', self.name):
497 return ("action", "OFActionBsn", None)
498 elif re.match(r'OFActionNicira.+', self.name):
499 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700500 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
501 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700502 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700503 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700504 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700505 return ("", "OFBsnVport", None)
506 elif self.name == "OFOxm":
507 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700508 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700509 if self.name in model.oxm_map:
510 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
511 else:
512 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700513 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700514 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700515 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700516 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700517 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700518 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700519 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700520 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700521 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700522 return ("", None, None)
523
524 @property
525 @memoize
526 def writeable_members(self):
527 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700528
529 @property
530 @memoize
531 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700532 return self.ir_model_members + self.virtual_members
533
534 @property
535 @memoize
536 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700537 """return a list of all members to be exposed by this interface. Corresponds to
538 the union of the members of the vesioned classes without length, fieldlength
539 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700540 all_versions = []
541 member_map = collections.OrderedDict()
542
543 for (version, of_class) in self.version_map.items():
544 for of_member in of_class.members:
545 if isinstance(of_member, OFLengthMember) or \
546 isinstance(of_member, OFFieldLengthMember) or \
547 isinstance(of_member, OFPadMember):
548 continue
549 if of_member.name not in member_map:
550 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
551
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700552 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 -0700553
554 @property
555 def virtual_members(self):
556 if self.name == "OFOxm":
557 return (
558 JavaVirtualMember(self, "value", java_type.generic_t),
559 JavaVirtualMember(self, "mask", java_type.generic_t),
560 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
561 JavaVirtualMember(self, "masked", java_type.boolean),
562 )
563 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
564 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
565 if self.name in model.oxm_map \
566 else java_type.make_match_field_jtype()
567
568 return (
569 JavaVirtualMember(self, "matchField", field_type),
570 JavaVirtualMember(self, "masked", java_type.boolean),
571 ) \
572 + \
573 (
574 ( 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
575 ()
576 )
577 else:
578 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700579
580 @property
581 @memoize
582 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700583 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700584 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 -0700585
586 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700587 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700588 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700589 return len(self.all_versions) == len(model.versions)
590
591 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700592 @memoize
593 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700594 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700595 return self.version_map.keys()
596
Andreas Wundsam5204de22013-07-30 11:34:45 -0700597 def has_version(self, version):
598 return version in self.version_map
599
Andreas Wundsam27303462013-07-16 12:52:35 -0700600 def versioned_class(self, version):
601 return JavaOFClass(self, version, self.version_map[version])
602
603 @property
604 @memoize
605 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700606 return [ self.versioned_class(version) for version in self.all_versions ]
607
608#######################################################################
609### (Versioned) Classes
610#######################################################################
611
612class JavaOFClass(object):
613 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700614 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700615 """
616 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700617 """
618 @param interface JavaOFInterface instance of the parent interface
619 @param version JavaOFVersion
620 @param ir_class OFClass from loxi_ir
621 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700622 self.interface = interface
623 self.ir_class = ir_class
624 self.c_name = self.ir_class.name
625 self.version = version
626 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700627 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700628 self.generated = False
629
630 @property
631 @memoize
632 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700633 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700634
635 @property
636 def name(self):
637 return "%sVer%s" % (self.interface.name, self.version.of_version)
638
639 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700640 def variable_name(self):
641 return self.name[3:]
642
643 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700644 def length(self):
645 if self.is_fixed_length:
646 return self.min_length
647 else:
648 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
649
650 @property
651 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700652 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700653 id_tuple = (self.ir_class.name, self.version.int_version)
654 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
655
656 @property
657 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700658 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700659 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
660 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700661
662 def all_properties(self):
663 return self.interface.members
664
665 def get_member(self, name):
666 for m in self.members:
667 if m.name == name:
668 return m
669
670 @property
671 @memoize
672 def data_members(self):
673 return [ prop for prop in self.members if prop.is_data ]
674
675 @property
676 @memoize
677 def fixed_value_members(self):
678 return [ prop for prop in self.members if prop.is_fixed_value ]
679
680 @property
681 @memoize
682 def public_members(self):
683 return [ prop for prop in self.members if prop.is_public ]
684
685 @property
686 @memoize
687 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700688 return self.ir_model_members + self.virtual_members
689
690 @property
691 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700692 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700693 return tuple(members)
694
695 @property
696 def virtual_members(self):
697 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
698 if self.interface.name in model.oxm_map:
699 oxm_entry = model.oxm_map[self.interface.name]
700 return (
701 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
702 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
703 )
704 else:
705 return (
706 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
707 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
708 )
709 else:
710 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700711
712 def all_versions(self):
713 return [ JavaOFVersion(int_version)
714 for int_version in of_g.unified[self.c_name]
715 if int_version != 'union' and int_version != 'object_id' ]
716
717 def version_is_inherited(self, version):
718 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
719
720 def inherited_from(self, version):
721 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
722
723 @property
724 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700725 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
726
727 @property
728 def discriminator(self):
729 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700730
731 @property
732 def is_extension(self):
733 return type_maps.message_is_extension(self.c_name, -1)
734
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700735 @property
736 def align(self):
737 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
738
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700739 @property
740 @memoize
741 def superclass(self):
742 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
743
744 @property
745 @memoize
746 def subclasses(self):
747 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
748
Andreas Wundsam27303462013-07-16 12:52:35 -0700749#######################################################################
750### Member
751#######################################################################
752
753
754class JavaMember(object):
755 """ Models a property (member) of an openflow class. """
756 def __init__(self, msg, name, java_type, member):
757 self.msg = msg
758 self.name = name
759 self.java_type = java_type
760 self.member = member
761 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700762
763 @property
764 def title_name(self):
765 return self.name[0].upper() + self.name[1:]
766
767 @property
768 def constant_name(self):
769 return self.c_name.upper()
770
771 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700772 def getter_name(self):
773 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
774
775 @property
776 def setter_name(self):
777 return "set" + self.title_name
778
779 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700780 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700781 if self.is_fixed_value:
782 return self.constant_name
783 else:
784 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700785
786 @property
787 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700788 if self.is_fixed_value:
789 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700790 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700791 default = self.java_type.default_op(self.msg.version)
792 if default == "null" and not self.is_nullable:
793 return None
794 else:
795 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700796
797 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700798 def enum_value(self):
799 if self.name == "version":
800 return "OFVersion.%s" % self.msg.version.constant_version
801
802 java_type = self.java_type.public_type;
803 try:
804 global model
805 enum = model.enum_by_name(java_type)
806 entry = enum.entry_by_version_value(self.msg.version, self.value)
807 return "%s.%s" % ( enum.name, entry.name)
808 except KeyError, e:
809 print e.message
810 return self.value
811
812 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700813 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700814 return isinstance(self.member, OFPadMember)
815
816 def is_type_value(self, version=None):
817 if(version==None):
818 return any(self.is_type_value(version) for version in self.msg.all_versions)
819 try:
820 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
821 except:
822 return False
823
824 @property
825 def is_field_length_value(self):
826 return isinstance(self.member, OFFieldLengthMember)
827
828 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700829 def is_discriminator(self):
830 return isinstance(self.member, OFDiscriminatorMember)
831
832 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700833 def is_length_value(self):
834 return isinstance(self.member, OFLengthMember)
835
836 @property
837 def is_public(self):
838 return not (self.is_pad or self.is_length_value)
839
840 @property
841 def is_data(self):
842 return isinstance(self.member, OFDataMember) and self.name != "version"
843
844 @property
845 def is_fixed_value(self):
846 return hasattr(self.member, "value") or self.name == "version" \
847 or ( self.name == "length" and self.msg.is_fixed_length) \
848 or ( self.name == "len" and self.msg.is_fixed_length)
849
850 @property
851 def value(self):
852 if self.name == "version":
853 return self.msg.version.int_version
854 elif self.name == "length" or self.name == "len":
855 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700856 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700857 return self.java_type.format_value(self.member.value)
858
859 @property
860 def priv_value(self):
861 if self.name == "version":
862 return self.msg.version.int_version
863 elif self.name == "length" or self.name == "len":
864 return self.msg.length
865 else:
866 return self.java_type.format_value(self.member.value, pub_type=False)
867
Andreas Wundsam27303462013-07-16 12:52:35 -0700868
869 @property
870 def is_writeable(self):
871 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
872
873 def get_type_value_info(self, version):
874 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700875
876 @property
877 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700878 if hasattr(self.member, "length"):
879 return self.member.length
880 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700881 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700882 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700883
884 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700885 def for_of_member(java_class, member):
886 if isinstance(member, OFPadMember):
887 return JavaMember(None, "", None, member)
888 else:
889 if member.name == 'len':
890 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700891 elif member.name == 'value_mask':
892 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700893 else:
894 name = java_type.name_c_to_camel(member.name)
895 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
896 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700897
898 @property
899 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700900 if not self.msg.c_name in of_g.unified:
901 print("%s not self.unified" % self.msg.c_name)
902 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700903 for version in of_g.unified[self.msg.c_name]:
904 if version == 'union' or version =='object_id':
905 continue
906 if 'use_version' in of_g.unified[self.msg.c_name][version]:
907 continue
908
Andreas Wundsam27303462013-07-16 12:52:35 -0700909 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 -0700910 return False
911 return True
912
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700913 @property
914 def is_virtual(self):
915 return False
916
Andreas Wundsam27303462013-07-16 12:52:35 -0700917 def __hash__(self):
918 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700919
Andreas Wundsam27303462013-07-16 12:52:35 -0700920 def __eq__(self, other):
921 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700922 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700923 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700924
Andreas Wundsamf1949682013-09-23 14:48:31 -0700925 @property
926 def is_nullable(self):
927 return self.name in model.nullable_map[self.msg.name]
928
929
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700930class JavaVirtualMember(JavaMember):
931 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
932 def __init__(self, msg, name, java_type, value=None):
933 JavaMember.__init__(self, msg, name, java_type, member=None)
934 self._value = value
935
936 @property
937 def is_fixed_value(self):
938 return True
939
940 @property
941 def value(self):
942 return self._value
943
944 @property
945 def priv_value(self):
946 return self._value
947
948
949 @property
950 def is_universal(self):
951 return True
952
953 @property
954 def is_virtual(self):
955 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700956
957#######################################################################
958### Unit Test
959#######################################################################
960
Yotam Harchol466b3212013-08-15 12:14:46 -0700961class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700962 def __init__(self, java_class):
963 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700964 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700965 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700966 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
967 name=java_class.c_name[3:]) + "{i}.data"
968 test_class_name = self.java_class.name + "Test"
969 self.test_units = []
970 if test_data.exists(first_data_file_name):
971 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
972 i = 1
973 while test_data.exists(data_file_template.format(i=i)):
974 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
975 i = i + 1
Andreas Wundsamf1949682013-09-23 14:48:31 -0700976
Yotam Harchol466b3212013-08-15 12:14:46 -0700977 @property
978 def package(self):
979 return self.java_class.package
980
981 @property
982 def has_test_data(self):
983 return len(self.test_units) > 0
984
985 @property
986 def length(self):
987 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -0700988
Yotam Harchol466b3212013-08-15 12:14:46 -0700989 def get_test_unit(self, i):
990 return self.test_units[i]
991
992
993class JavaUnitTest(object):
994 def __init__(self, java_class, file_name=None, test_class_name=None):
995 self.java_class = java_class
996 if file_name is None:
997 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
998 name=java_class.c_name[3:])
999 else:
1000 self.data_file_name = file_name
1001 if test_class_name is None:
1002 self.test_class_name = self.java_class.name + "Test"
1003 else:
1004 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001005
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001006 @property
1007 def package(self):
1008 return self.java_class.package
1009
1010 @property
1011 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001012 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001013
1014 @property
1015 def has_test_data(self):
1016 return test_data.exists(self.data_file_name)
1017
1018 @property
1019 @memoize
1020 def test_data(self):
1021 return test_data.read(self.data_file_name)
1022
1023
Andreas Wundsam27303462013-07-16 12:52:35 -07001024#######################################################################
1025### Enums
1026#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001027
Andreas Wundsam27303462013-07-16 12:52:35 -07001028class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001029 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001030 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001031
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001032 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001033
Andreas Wundsam27303462013-07-16 12:52:35 -07001034 # Port_features has constants that start with digits
1035 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001036
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001037 self.version_enums = version_enum_map
1038
1039 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1040 for version, ir_enum in version_enum_map.items():
1041 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001042 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1043
Andreas Wundsam27303462013-07-16 12:52:35 -07001044 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001045 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001046
1047 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 -07001048 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001049
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001050 self.metadata = model.enum_metadata_map[self.name]
1051
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001052 def wire_type(self, version):
1053 ir_enum = self.version_enums[version]
1054 if "wire_type" in ir_enum.params:
1055 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1056 else:
1057 return java_type.u8
1058
1059 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001060 @memoize
1061 def is_bitmask(self):
1062 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1063
1064 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001065 def versions(self):
1066 return self.version_enums.keys()
1067
Andreas Wundsam27303462013-07-16 12:52:35 -07001068 @memoize
1069 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001070 res = find(lambda e: e.name == name, self.entries)
1071 if res:
1072 return res
1073 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001074 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1075
1076 @memoize
1077 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001078 res = find(lambda e: e.c_name == name, self.entries)
1079 if res:
1080 return res
1081 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001082 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1083
1084 @memoize
1085 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001086 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1087 if res:
1088 return res
1089 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001090 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1091
1092# values: Map JavaVersion->Value
1093class JavaEnumEntry(object):
1094 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001095 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001096 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1097 self.values = values
1098
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001099 @property
1100 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001101 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001102
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001103 def has_value(self, version):
1104 return version in self.values
1105
Andreas Wundsam27303462013-07-16 12:52:35 -07001106 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001107 return self.values[version]
1108
1109 def format_value(self, version):
1110 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001111 return res
1112
Andreas Wundsam27303462013-07-16 12:52:35 -07001113 def all_values(self, versions, not_present=None):
1114 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001115
1116 @property
1117 @memoize
1118 def masked_enum_group(self):
1119 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1120 return group
1121
1122 @property
1123 @memoize
1124 def is_mask(self):
1125 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])