blob: 282cf981952f9c282f5028b2b803a434d9b01aaf [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})
Andreas Wundsam43526532013-08-01 22:03:50 -070052 enum_blacklist = set(("OFDefinitions",))
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)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700481 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700482 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700483 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 -0700484 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700485 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 -0700486 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700487 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
488 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700489 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700490 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700491 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700492 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700493 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700494 if re.match(r'OFActionBsn.+', self.name):
495 return ("action", "OFActionBsn", None)
496 elif re.match(r'OFActionNicira.+', self.name):
497 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700498 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
499 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700500 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700501 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700502 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700503 return ("", "OFBsnVport", None)
504 elif self.name == "OFOxm":
505 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700506 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700507 if self.name in model.oxm_map:
508 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
509 else:
510 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700511 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700512 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700513 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700514 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700515 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700516 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700517 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700518 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700519 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700520 return ("", None, None)
521
522 @property
523 @memoize
524 def writeable_members(self):
525 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700526
527 @property
528 @memoize
529 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700530 return self.ir_model_members + self.virtual_members
531
532 @property
533 @memoize
534 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700535 """return a list of all members to be exposed by this interface. Corresponds to
536 the union of the members of the vesioned classes without length, fieldlength
537 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700538 all_versions = []
539 member_map = collections.OrderedDict()
540
541 for (version, of_class) in self.version_map.items():
542 for of_member in of_class.members:
543 if isinstance(of_member, OFLengthMember) or \
544 isinstance(of_member, OFFieldLengthMember) or \
545 isinstance(of_member, OFPadMember):
546 continue
547 if of_member.name not in member_map:
548 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
549
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700550 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 -0700551
552 @property
553 def virtual_members(self):
554 if self.name == "OFOxm":
555 return (
556 JavaVirtualMember(self, "value", java_type.generic_t),
557 JavaVirtualMember(self, "mask", java_type.generic_t),
558 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
559 JavaVirtualMember(self, "masked", java_type.boolean),
560 )
561 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
562 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
563 if self.name in model.oxm_map \
564 else java_type.make_match_field_jtype()
565
566 return (
567 JavaVirtualMember(self, "matchField", field_type),
568 JavaVirtualMember(self, "masked", java_type.boolean),
569 ) \
570 + \
571 (
572 ( 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
573 ()
574 )
575 else:
576 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700577
578 @property
579 @memoize
580 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700581 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700582 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 -0700583
584 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700585 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700586 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700587 return len(self.all_versions) == len(model.versions)
588
589 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700590 @memoize
591 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700592 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700593 return self.version_map.keys()
594
Andreas Wundsam5204de22013-07-30 11:34:45 -0700595 def has_version(self, version):
596 return version in self.version_map
597
Andreas Wundsam27303462013-07-16 12:52:35 -0700598 def versioned_class(self, version):
599 return JavaOFClass(self, version, self.version_map[version])
600
601 @property
602 @memoize
603 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700604 return [ self.versioned_class(version) for version in self.all_versions ]
605
606#######################################################################
607### (Versioned) Classes
608#######################################################################
609
610class JavaOFClass(object):
611 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700612 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700613 """
614 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700615 """
616 @param interface JavaOFInterface instance of the parent interface
617 @param version JavaOFVersion
618 @param ir_class OFClass from loxi_ir
619 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700620 self.interface = interface
621 self.ir_class = ir_class
622 self.c_name = self.ir_class.name
623 self.version = version
624 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700625 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700626 self.generated = False
627
628 @property
629 @memoize
630 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700631 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700632
633 @property
634 def name(self):
635 return "%sVer%s" % (self.interface.name, self.version.of_version)
636
637 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700638 def variable_name(self):
639 return self.name[3:]
640
641 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700642 def length(self):
643 if self.is_fixed_length:
644 return self.min_length
645 else:
646 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
647
648 @property
649 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700650 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700651 id_tuple = (self.ir_class.name, self.version.int_version)
652 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
653
654 @property
655 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700656 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700657 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
658 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700659
660 def all_properties(self):
661 return self.interface.members
662
663 def get_member(self, name):
664 for m in self.members:
665 if m.name == name:
666 return m
667
668 @property
669 @memoize
670 def data_members(self):
671 return [ prop for prop in self.members if prop.is_data ]
672
673 @property
674 @memoize
675 def fixed_value_members(self):
676 return [ prop for prop in self.members if prop.is_fixed_value ]
677
678 @property
679 @memoize
680 def public_members(self):
681 return [ prop for prop in self.members if prop.is_public ]
682
683 @property
684 @memoize
685 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700686 return self.ir_model_members + self.virtual_members
687
688 @property
689 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700690 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700691 return tuple(members)
692
693 @property
694 def virtual_members(self):
695 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
696 if self.interface.name in model.oxm_map:
697 oxm_entry = model.oxm_map[self.interface.name]
698 return (
699 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
700 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
701 )
702 else:
703 return (
704 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
705 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
706 )
707 else:
708 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700709
710 def all_versions(self):
711 return [ JavaOFVersion(int_version)
712 for int_version in of_g.unified[self.c_name]
713 if int_version != 'union' and int_version != 'object_id' ]
714
715 def version_is_inherited(self, version):
716 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
717
718 def inherited_from(self, version):
719 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
720
721 @property
722 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700723 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
724
725 @property
726 def discriminator(self):
727 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700728
729 @property
730 def is_extension(self):
731 return type_maps.message_is_extension(self.c_name, -1)
732
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700733 @property
734 def align(self):
735 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
736
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700737 @property
738 @memoize
739 def superclass(self):
740 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
741
742 @property
743 @memoize
744 def subclasses(self):
745 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
746
Andreas Wundsam27303462013-07-16 12:52:35 -0700747#######################################################################
748### Member
749#######################################################################
750
751
752class JavaMember(object):
753 """ Models a property (member) of an openflow class. """
754 def __init__(self, msg, name, java_type, member):
755 self.msg = msg
756 self.name = name
757 self.java_type = java_type
758 self.member = member
759 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700760
761 @property
762 def title_name(self):
763 return self.name[0].upper() + self.name[1:]
764
765 @property
766 def constant_name(self):
767 return self.c_name.upper()
768
769 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700770 def getter_name(self):
771 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
772
773 @property
774 def setter_name(self):
775 return "set" + self.title_name
776
777 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700778 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700779 if self.is_fixed_value:
780 return self.constant_name
781 else:
782 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700783
784 @property
785 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700786 if self.is_fixed_value:
787 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700788 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700789 default = self.java_type.default_op(self.msg.version)
790 if default == "null" and not self.is_nullable:
791 return None
792 else:
793 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700794
795 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700796 def enum_value(self):
797 if self.name == "version":
798 return "OFVersion.%s" % self.msg.version.constant_version
799
800 java_type = self.java_type.public_type;
801 try:
802 global model
803 enum = model.enum_by_name(java_type)
804 entry = enum.entry_by_version_value(self.msg.version, self.value)
805 return "%s.%s" % ( enum.name, entry.name)
806 except KeyError, e:
807 print e.message
808 return self.value
809
810 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700811 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700812 return isinstance(self.member, OFPadMember)
813
814 def is_type_value(self, version=None):
815 if(version==None):
816 return any(self.is_type_value(version) for version in self.msg.all_versions)
817 try:
818 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
819 except:
820 return False
821
822 @property
823 def is_field_length_value(self):
824 return isinstance(self.member, OFFieldLengthMember)
825
826 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700827 def is_discriminator(self):
828 return isinstance(self.member, OFDiscriminatorMember)
829
830 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700831 def is_length_value(self):
832 return isinstance(self.member, OFLengthMember)
833
834 @property
835 def is_public(self):
836 return not (self.is_pad or self.is_length_value)
837
838 @property
839 def is_data(self):
840 return isinstance(self.member, OFDataMember) and self.name != "version"
841
842 @property
843 def is_fixed_value(self):
844 return hasattr(self.member, "value") or self.name == "version" \
845 or ( self.name == "length" and self.msg.is_fixed_length) \
846 or ( self.name == "len" and self.msg.is_fixed_length)
847
848 @property
849 def value(self):
850 if self.name == "version":
851 return self.msg.version.int_version
852 elif self.name == "length" or self.name == "len":
853 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700854 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700855 return self.java_type.format_value(self.member.value)
856
857 @property
858 def priv_value(self):
859 if self.name == "version":
860 return self.msg.version.int_version
861 elif self.name == "length" or self.name == "len":
862 return self.msg.length
863 else:
864 return self.java_type.format_value(self.member.value, pub_type=False)
865
Andreas Wundsam27303462013-07-16 12:52:35 -0700866
867 @property
868 def is_writeable(self):
869 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
870
871 def get_type_value_info(self, version):
872 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700873
874 @property
875 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700876 if hasattr(self.member, "length"):
877 return self.member.length
878 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700879 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700880 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700881
882 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700883 def for_of_member(java_class, member):
884 if isinstance(member, OFPadMember):
885 return JavaMember(None, "", None, member)
886 else:
887 if member.name == 'len':
888 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700889 elif member.name == 'value_mask':
890 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700891 else:
892 name = java_type.name_c_to_camel(member.name)
893 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
894 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700895
896 @property
897 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700898 if not self.msg.c_name in of_g.unified:
899 print("%s not self.unified" % self.msg.c_name)
900 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700901 for version in of_g.unified[self.msg.c_name]:
902 if version == 'union' or version =='object_id':
903 continue
904 if 'use_version' in of_g.unified[self.msg.c_name][version]:
905 continue
906
Andreas Wundsam27303462013-07-16 12:52:35 -0700907 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 -0700908 return False
909 return True
910
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700911 @property
912 def is_virtual(self):
913 return False
914
Andreas Wundsam27303462013-07-16 12:52:35 -0700915 def __hash__(self):
916 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700917
Andreas Wundsam27303462013-07-16 12:52:35 -0700918 def __eq__(self, other):
919 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700920 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700921 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700922
Andreas Wundsamf1949682013-09-23 14:48:31 -0700923 @property
924 def is_nullable(self):
925 return self.name in model.nullable_map[self.msg.name]
926
927
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700928class JavaVirtualMember(JavaMember):
929 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
930 def __init__(self, msg, name, java_type, value=None):
931 JavaMember.__init__(self, msg, name, java_type, member=None)
932 self._value = value
933
934 @property
935 def is_fixed_value(self):
936 return True
937
938 @property
939 def value(self):
940 return self._value
941
942 @property
943 def priv_value(self):
944 return self._value
945
946
947 @property
948 def is_universal(self):
949 return True
950
951 @property
952 def is_virtual(self):
953 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700954
955#######################################################################
956### Unit Test
957#######################################################################
958
Yotam Harchol466b3212013-08-15 12:14:46 -0700959class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700960 def __init__(self, java_class):
961 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700962 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700963 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700964 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
965 name=java_class.c_name[3:]) + "{i}.data"
966 test_class_name = self.java_class.name + "Test"
967 self.test_units = []
968 if test_data.exists(first_data_file_name):
969 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
970 i = 1
971 while test_data.exists(data_file_template.format(i=i)):
972 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
973 i = i + 1
Andreas Wundsamf1949682013-09-23 14:48:31 -0700974
Yotam Harchol466b3212013-08-15 12:14:46 -0700975 @property
976 def package(self):
977 return self.java_class.package
978
979 @property
980 def has_test_data(self):
981 return len(self.test_units) > 0
982
983 @property
984 def length(self):
985 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -0700986
Yotam Harchol466b3212013-08-15 12:14:46 -0700987 def get_test_unit(self, i):
988 return self.test_units[i]
989
990
991class JavaUnitTest(object):
992 def __init__(self, java_class, file_name=None, test_class_name=None):
993 self.java_class = java_class
994 if file_name is None:
995 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
996 name=java_class.c_name[3:])
997 else:
998 self.data_file_name = file_name
999 if test_class_name is None:
1000 self.test_class_name = self.java_class.name + "Test"
1001 else:
1002 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001003
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001004 @property
1005 def package(self):
1006 return self.java_class.package
1007
1008 @property
1009 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001010 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001011
1012 @property
1013 def has_test_data(self):
1014 return test_data.exists(self.data_file_name)
1015
1016 @property
1017 @memoize
1018 def test_data(self):
1019 return test_data.read(self.data_file_name)
1020
1021
Andreas Wundsam27303462013-07-16 12:52:35 -07001022#######################################################################
1023### Enums
1024#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001025
Andreas Wundsam27303462013-07-16 12:52:35 -07001026class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001027 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001028 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001029
1030 if c_name == "of_stats_types":
1031 self.name = "OFStatsType"
1032 else:
1033 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001034
Andreas Wundsam27303462013-07-16 12:52:35 -07001035 # Port_features has constants that start with digits
1036 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001037
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001038 self.version_enums = version_enum_map
1039
1040 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1041 for version, ir_enum in version_enum_map.items():
1042 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001043 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1044
Andreas Wundsam27303462013-07-16 12:52:35 -07001045 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001046 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001047
1048 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 -07001049 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001050
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001051 self.metadata = model.enum_metadata_map[self.name]
1052
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001053 def wire_type(self, version):
1054 ir_enum = self.version_enums[version]
1055 if "wire_type" in ir_enum.params:
1056 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1057 else:
1058 return java_type.u8
1059
1060 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001061 @memoize
1062 def is_bitmask(self):
1063 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1064
1065 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001066 def versions(self):
1067 return self.version_enums.keys()
1068
Andreas Wundsam27303462013-07-16 12:52:35 -07001069 @memoize
1070 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001071 res = find(lambda e: e.name == name, self.entries)
1072 if res:
1073 return res
1074 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001075 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1076
1077 @memoize
1078 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001079 res = find(lambda e: e.c_name == name, self.entries)
1080 if res:
1081 return res
1082 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001083 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1084
1085 @memoize
1086 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001087 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1088 if res:
1089 return res
1090 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001091 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1092
1093# values: Map JavaVersion->Value
1094class JavaEnumEntry(object):
1095 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001096 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001097 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1098 self.values = values
1099
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001100 @property
1101 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001102 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001103
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001104 def has_value(self, version):
1105 return version in self.values
1106
Andreas Wundsam27303462013-07-16 12:52:35 -07001107 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001108 return self.values[version]
1109
1110 def format_value(self, version):
1111 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001112 return res
1113
Andreas Wundsam27303462013-07-16 12:52:35 -07001114 def all_values(self, versions, not_present=None):
1115 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001116
1117 @property
1118 @memoize
1119 def masked_enum_group(self):
1120 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1121 return group
1122
1123 @property
1124 @memoize
1125 def is_mask(self):
1126 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])