blob: 76a584cf9ea0444103ca807ddc1663bffe4d0cd4 [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: (),
Andreas Wundsamaebe5182013-09-24 13:01:07 -0700159 OFPortState = (MaskedEnumGroup("stp_flags", mask="STP_MASK", members=set(("STP_LISTEN", "STP_LEARN", "STP_FORWARD", "STP_BLOCK"))), ),
160 OFConfigFlags = (
161 MaskedEnumGroup("frag_flags", mask="FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
162 )
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700163 )
164
Andreas Wundsamf1949682013-09-23 14:48:31 -0700165 # represents a metadata property associated with an EnumClass
166 # name:
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700167 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700168 """
169 represents a metadata property associated with an Enum Class
170 @param name name of metadata property
171 @param type java_type instance describing the type
172 @value: Generator function f(entry) that generates the value
173 """
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700174 @property
175 def variable_name(self):
176 return self.name[0].lower() + self.name[1:]
177
178 @property
179 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700180 prefix = "is" if self.type == java_type.boolean else "get"
181 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700182
Andreas Wundsamf1949682013-09-23 14:48:31 -0700183 """ Metadata container. """
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700184 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
185
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700186 def gen_port_speed(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700187 """ Generator function for OFortFeatures.PortSpeed"""
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700188 splits = enum_entry.name.split("_")
189 if len(splits)>=2:
190 m = re.match(r'\d+[MGTP]B', splits[1])
191 if m:
192 return "PortSpeed.SPEED_{}".format(splits[1])
193 return "PortSpeed.SPEED_NONE";
194
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700195 def gen_stp_state(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700196 """ Generator function for OFPortState.StpState"""
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700197 splits = enum_entry.name.split("_")
198 if len(splits)>=1:
199 if splits[0] == "STP":
200 return "true"
201 return "false"
202
Andreas Wundsamf1949682013-09-23 14:48:31 -0700203 # registry for metadata properties for enums
204 # map: ${java_enum_name}: OFEnumMetadata
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700205 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700206 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
207 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700208 )
209
Andreas Wundsam27303462013-07-16 12:52:35 -0700210 @property
211 @memoize
212 def versions(self):
213 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
214
215 @property
216 @memoize
217 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700218 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700219
220 for raw_version, of_protocol in of_g.ir.items():
221 jversion = JavaOFVersion(of_protocol.wire_version)
222
223 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700224 if not of_class.name in version_map_per_class:
225 version_map_per_class[of_class.name] = collections.OrderedDict()
226
Andreas Wundsam27303462013-07-16 12:52:35 -0700227 version_map_per_class[of_class.name][jversion] = of_class
228
229 interfaces = []
230 for class_name, version_map in version_map_per_class.items():
231 interfaces.append(JavaOFInterface(class_name, version_map))
232
Andreas Wundsambe168f72013-08-03 22:49:35 -0700233 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
234
Andreas Wundsam27303462013-07-16 12:52:35 -0700235 return interfaces
236
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700237 @memoize
238 def interface_by_name(self, name):
239 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
240
Andreas Wundsam27303462013-07-16 12:52:35 -0700241 @property
242 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700243 def all_classes(self):
244 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
245
246 @property
247 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700248 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700249 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700250
251 for version in self.versions:
252 of_protocol = of_g.ir[version.int_version]
253 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700254 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700255
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700256 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
257 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700258
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700259 # inelegant - need java name here
260 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700261 return enums
262
263 @memoize
264 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700265 res = find(lambda e: e.name == name, self.enums)
266 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700267 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700268 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700269
Andreas Wundsam5204de22013-07-30 11:34:45 -0700270 @property
271 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700272 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700273 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700274
275 factories = OrderedDict()
276
277 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
278 for base_class in sub_factory_classes:
279 package = base_class[2:].lower()
280 remove_prefix = base_class[2].lower() + base_class[3:]
281
282 # HACK need to have a better way to deal with parameterized base classes
283 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
284
285 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
286 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
287
288 factories[""] = OFFactory(
289 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700290 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700291 remove_prefix="",
292 members=[], base_class="OFMessage", sub_factories=OrderedDict(
293 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
294
295 for i in self.interfaces:
296 for n, factory in factories.items():
297 if n == "":
298 factory.members.append(i)
299 break
300 else:
301 super_class = self.interface_by_name(n)
302 if i.is_instance_of(super_class):
303 factory.members.append(i)
304 break
305 return factories.values()
Andreas Wundsam5204de22013-07-30 11:34:45 -0700306
307 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700308 """ return wether or not to generate implementation class clazz.
309 Now true for everything except OFTableModVer10.
310 @param clazz JavaOFClass instance
311 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700312 if clazz.interface.name.startswith("OFMatchV"):
313 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700314 elif clazz.name == "OFTableModVer10":
315 # tablemod ver 10 is a hack and has no oftype defined
316 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700317 if loxi_utils.class_is_message(clazz.interface.c_name):
318 return True
319 if loxi_utils.class_is_oxm(clazz.interface.c_name):
320 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700321 if loxi_utils.class_is_action(clazz.interface.c_name):
322 return True
323 if loxi_utils.class_is_instruction(clazz.interface.c_name):
324 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700325 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700326 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700327
328
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700329class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700330 @property
331 def factory_classes(self):
332 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700333 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700334 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700335 interface=self,
336 version=version
337 ) for version in model.versions ]
338
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700339 def method_name(self, member, builder=True):
340 n = member.variable_name
341 if n.startswith(self.remove_prefix):
342 n = n[len(self.remove_prefix):]
343 n = n[0].lower() + n[1:]
344 if builder:
345 return "build" + n[0].upper() + n[1:]
346 else:
347 return n
Andreas Wundsam5204de22013-07-30 11:34:45 -0700348
349OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700350class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
351 @property
352 def base_class(self):
353 return self.interface.base_class
354
355 @property
356 def versioned_base_class(self):
357 base_class_interface = model.interface_by_name(self.interface.base_class)
358 if base_class_interface and base_class_interface.has_version(self.version):
359 return base_class_interface.versioned_class(self.version)
360 else:
361 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700362
Andreas Wundsam27303462013-07-16 12:52:35 -0700363model = JavaModel()
364
365#######################################################################
366### OFVersion
367#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700368
369class JavaOFVersion(object):
370 """ Models a version of OpenFlow. contains methods to convert the internal
371 Loxi version to a java constant / a string """
372 def __init__(self, int_version):
373 self.int_version = int(int_version)
374
375 @property
376 def of_version(self):
377 return "1" + str(int(self.int_version) - 1)
378
379 @property
380 def constant_version(self):
381 return "OF_" + self.of_version
382
Andreas Wundsam27303462013-07-16 12:52:35 -0700383 def __repr__(self):
384 return "JavaOFVersion(%d)" % self.int_version
385
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700386 def __str__(self):
387 return of_g.param_version_names[self.int_version]
388
Andreas Wundsam27303462013-07-16 12:52:35 -0700389 def __hash__(self):
390 return hash(self.int_version)
391
392 def __eq__(self, other):
393 if other is None or type(self) != type(other):
394 return False
395 return (self.int_version,) == (other.int_version,)
396
397#######################################################################
398### Interface
399#######################################################################
400
401class JavaOFInterface(object):
402 """ Models an OpenFlow Message class for the purpose of the java class.
403 Version agnostic, in contrast to the loxi_ir python model.
404 """
405 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700406 """"
407 @param c_name: loxi style name (e.g., of_flow_add)
408 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
409 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700410 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700411 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700412 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700413 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 -0700414 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700415 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700416 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700417 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700418 self.constant_name = c_name.upper().replace("OF_", "")
419
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700420 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700421 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700422 if self.name != parent_interface:
423 self.parent_interface = parent_interface
424 else:
425 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700426
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700427 @property
428 @memoize
429 def all_parent_interfaces(self):
430 return [ "OFObject" ] + \
431 ([ self.parent_interface ] if self.parent_interface else [] )+ \
432 self.additional_parent_interfaces
433 @property
434 @memoize
435 def additional_parent_interfaces(self):
436 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
437 m = re.match(r'(.*)Request$', self.name)
438 if m:
439 reply_name = m.group(1) + "Reply"
440 if model.interface_by_name(reply_name):
441 return ["OFRequest<%s>" % reply_name ]
442 return []
443
444
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700445 def is_instance_of(self, other_class):
446 if self == other_class:
447 return True
448 parent = self.super_class
449 if parent is None:
450 return False
451 else:
452 return parent.is_instance_of(other_class)
453
454 @property
455 def super_class(self):
456 if not self.parent_interface:
457 return None
458 else:
459 return model.interface_by_name(self.parent_interface)
460
461
462 def inherited_declaration(self, type_spec="?"):
463 if self.type_annotation:
464 return "%s<%s>" % (self.name, type_spec)
465 else:
466 return "%s" % self.name
467
468 @property
469 def type_variable(self):
470 if self.type_annotation:
471 return "<T>"
472 else:
473 return "";
474
Andreas Wundsam27303462013-07-16 12:52:35 -0700475 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700476 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
477 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
478 # model (note, that the loxi model is on versioned classes). Should check/infer the
479 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700480 if re.match(r'OF.+StatsRequest$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700481 return ("", "OFStatsRequest", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700482 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700483 return ("", "OFStatsReply", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700484 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700485 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700486 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 -0700487 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700488 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 -0700489 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700490 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
491 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700492 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700493 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700494 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700495 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700496 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700497 if re.match(r'OFActionBsn.+', self.name):
498 return ("action", "OFActionBsn", None)
499 elif re.match(r'OFActionNicira.+', self.name):
500 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700501 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
502 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700503 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700504 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700505 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700506 return ("", "OFBsnVport", None)
507 elif self.name == "OFOxm":
508 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700509 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700510 if self.name in model.oxm_map:
511 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
512 else:
513 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700514 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700515 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700516 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700517 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700518 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700519 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700520 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700521 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700522 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700523 return ("", None, None)
524
525 @property
526 @memoize
527 def writeable_members(self):
528 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700529
530 @property
531 @memoize
532 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700533 return self.ir_model_members + self.virtual_members
534
535 @property
536 @memoize
537 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700538 """return a list of all members to be exposed by this interface. Corresponds to
539 the union of the members of the vesioned classes without length, fieldlength
540 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700541 all_versions = []
542 member_map = collections.OrderedDict()
543
544 for (version, of_class) in self.version_map.items():
545 for of_member in of_class.members:
546 if isinstance(of_member, OFLengthMember) or \
547 isinstance(of_member, OFFieldLengthMember) or \
548 isinstance(of_member, OFPadMember):
549 continue
550 if of_member.name not in member_map:
551 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
552
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700553 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 -0700554
555 @property
556 def virtual_members(self):
557 if self.name == "OFOxm":
558 return (
559 JavaVirtualMember(self, "value", java_type.generic_t),
560 JavaVirtualMember(self, "mask", java_type.generic_t),
561 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
562 JavaVirtualMember(self, "masked", java_type.boolean),
563 )
564 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
565 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
566 if self.name in model.oxm_map \
567 else java_type.make_match_field_jtype()
568
569 return (
570 JavaVirtualMember(self, "matchField", field_type),
571 JavaVirtualMember(self, "masked", java_type.boolean),
572 ) \
573 + \
574 (
575 ( 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
576 ()
577 )
578 else:
579 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700580
581 @property
582 @memoize
583 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700584 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700585 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 -0700586
587 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700588 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700589 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700590 return len(self.all_versions) == len(model.versions)
591
592 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700593 @memoize
594 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700595 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700596 return self.version_map.keys()
597
Andreas Wundsam5204de22013-07-30 11:34:45 -0700598 def has_version(self, version):
599 return version in self.version_map
600
Andreas Wundsam27303462013-07-16 12:52:35 -0700601 def versioned_class(self, version):
602 return JavaOFClass(self, version, self.version_map[version])
603
604 @property
605 @memoize
606 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700607 return [ self.versioned_class(version) for version in self.all_versions ]
608
609#######################################################################
610### (Versioned) Classes
611#######################################################################
612
613class JavaOFClass(object):
614 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700615 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700616 """
617 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700618 """
619 @param interface JavaOFInterface instance of the parent interface
620 @param version JavaOFVersion
621 @param ir_class OFClass from loxi_ir
622 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700623 self.interface = interface
624 self.ir_class = ir_class
625 self.c_name = self.ir_class.name
626 self.version = version
627 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700628 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700629 self.generated = False
630
631 @property
632 @memoize
633 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700634 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700635
636 @property
637 def name(self):
638 return "%sVer%s" % (self.interface.name, self.version.of_version)
639
640 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700641 def variable_name(self):
642 return self.name[3:]
643
644 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700645 def length(self):
646 if self.is_fixed_length:
647 return self.min_length
648 else:
649 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
650
651 @property
652 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700653 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700654 id_tuple = (self.ir_class.name, self.version.int_version)
655 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
656
657 @property
658 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700659 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700660 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
661 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700662
663 def all_properties(self):
664 return self.interface.members
665
666 def get_member(self, name):
667 for m in self.members:
668 if m.name == name:
669 return m
670
671 @property
672 @memoize
673 def data_members(self):
674 return [ prop for prop in self.members if prop.is_data ]
675
676 @property
677 @memoize
678 def fixed_value_members(self):
679 return [ prop for prop in self.members if prop.is_fixed_value ]
680
681 @property
682 @memoize
683 def public_members(self):
684 return [ prop for prop in self.members if prop.is_public ]
685
686 @property
687 @memoize
688 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700689 return self.ir_model_members + self.virtual_members
690
691 @property
692 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700693 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700694 return tuple(members)
695
696 @property
697 def virtual_members(self):
698 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
699 if self.interface.name in model.oxm_map:
700 oxm_entry = model.oxm_map[self.interface.name]
701 return (
702 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
703 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
704 )
705 else:
706 return (
707 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
708 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
709 )
710 else:
711 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700712
713 def all_versions(self):
714 return [ JavaOFVersion(int_version)
715 for int_version in of_g.unified[self.c_name]
716 if int_version != 'union' and int_version != 'object_id' ]
717
718 def version_is_inherited(self, version):
719 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
720
721 def inherited_from(self, version):
722 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
723
724 @property
725 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700726 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
727
728 @property
729 def discriminator(self):
730 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700731
732 @property
733 def is_extension(self):
734 return type_maps.message_is_extension(self.c_name, -1)
735
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700736 @property
737 def align(self):
738 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
739
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700740 @property
741 @memoize
742 def superclass(self):
743 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
744
745 @property
746 @memoize
747 def subclasses(self):
748 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
749
Andreas Wundsam27303462013-07-16 12:52:35 -0700750#######################################################################
751### Member
752#######################################################################
753
754
755class JavaMember(object):
756 """ Models a property (member) of an openflow class. """
757 def __init__(self, msg, name, java_type, member):
758 self.msg = msg
759 self.name = name
760 self.java_type = java_type
761 self.member = member
762 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700763
764 @property
765 def title_name(self):
766 return self.name[0].upper() + self.name[1:]
767
768 @property
769 def constant_name(self):
770 return self.c_name.upper()
771
772 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700773 def getter_name(self):
774 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
775
776 @property
777 def setter_name(self):
778 return "set" + self.title_name
779
780 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700781 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700782 if self.is_fixed_value:
783 return self.constant_name
784 else:
785 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700786
787 @property
788 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700789 if self.is_fixed_value:
790 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700791 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700792 default = self.java_type.default_op(self.msg.version)
793 if default == "null" and not self.is_nullable:
794 return None
795 else:
796 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700797
798 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700799 def enum_value(self):
800 if self.name == "version":
801 return "OFVersion.%s" % self.msg.version.constant_version
802
803 java_type = self.java_type.public_type;
804 try:
805 global model
806 enum = model.enum_by_name(java_type)
807 entry = enum.entry_by_version_value(self.msg.version, self.value)
808 return "%s.%s" % ( enum.name, entry.name)
809 except KeyError, e:
810 print e.message
811 return self.value
812
813 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700814 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700815 return isinstance(self.member, OFPadMember)
816
817 def is_type_value(self, version=None):
818 if(version==None):
819 return any(self.is_type_value(version) for version in self.msg.all_versions)
820 try:
821 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
822 except:
823 return False
824
825 @property
826 def is_field_length_value(self):
827 return isinstance(self.member, OFFieldLengthMember)
828
829 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700830 def is_discriminator(self):
831 return isinstance(self.member, OFDiscriminatorMember)
832
833 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700834 def is_length_value(self):
835 return isinstance(self.member, OFLengthMember)
836
837 @property
838 def is_public(self):
839 return not (self.is_pad or self.is_length_value)
840
841 @property
842 def is_data(self):
843 return isinstance(self.member, OFDataMember) and self.name != "version"
844
845 @property
846 def is_fixed_value(self):
847 return hasattr(self.member, "value") or self.name == "version" \
848 or ( self.name == "length" and self.msg.is_fixed_length) \
849 or ( self.name == "len" and self.msg.is_fixed_length)
850
851 @property
852 def value(self):
853 if self.name == "version":
854 return self.msg.version.int_version
855 elif self.name == "length" or self.name == "len":
856 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700857 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700858 return self.java_type.format_value(self.member.value)
859
860 @property
861 def priv_value(self):
862 if self.name == "version":
863 return self.msg.version.int_version
864 elif self.name == "length" or self.name == "len":
865 return self.msg.length
866 else:
867 return self.java_type.format_value(self.member.value, pub_type=False)
868
Andreas Wundsam27303462013-07-16 12:52:35 -0700869
870 @property
871 def is_writeable(self):
872 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
873
874 def get_type_value_info(self, version):
875 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700876
877 @property
878 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700879 if hasattr(self.member, "length"):
880 return self.member.length
881 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700882 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700883 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700884
885 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700886 def for_of_member(java_class, member):
887 if isinstance(member, OFPadMember):
888 return JavaMember(None, "", None, member)
889 else:
890 if member.name == 'len':
891 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700892 elif member.name == 'value_mask':
893 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700894 else:
895 name = java_type.name_c_to_camel(member.name)
896 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
897 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700898
899 @property
900 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700901 if not self.msg.c_name in of_g.unified:
902 print("%s not self.unified" % self.msg.c_name)
903 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700904 for version in of_g.unified[self.msg.c_name]:
905 if version == 'union' or version =='object_id':
906 continue
907 if 'use_version' in of_g.unified[self.msg.c_name][version]:
908 continue
909
Andreas Wundsam27303462013-07-16 12:52:35 -0700910 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 -0700911 return False
912 return True
913
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700914 @property
915 def is_virtual(self):
916 return False
917
Andreas Wundsam27303462013-07-16 12:52:35 -0700918 def __hash__(self):
919 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700920
Andreas Wundsam27303462013-07-16 12:52:35 -0700921 def __eq__(self, other):
922 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700923 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700924 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700925
Andreas Wundsamf1949682013-09-23 14:48:31 -0700926 @property
927 def is_nullable(self):
928 return self.name in model.nullable_map[self.msg.name]
929
930
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700931class JavaVirtualMember(JavaMember):
932 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
933 def __init__(self, msg, name, java_type, value=None):
934 JavaMember.__init__(self, msg, name, java_type, member=None)
935 self._value = value
936
937 @property
938 def is_fixed_value(self):
939 return True
940
941 @property
942 def value(self):
943 return self._value
944
945 @property
946 def priv_value(self):
947 return self._value
948
949
950 @property
951 def is_universal(self):
952 return True
953
954 @property
955 def is_virtual(self):
956 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700957
958#######################################################################
959### Unit Test
960#######################################################################
961
Yotam Harchol466b3212013-08-15 12:14:46 -0700962class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700963 def __init__(self, java_class):
964 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700965 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700966 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700967 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
968 name=java_class.c_name[3:]) + "{i}.data"
969 test_class_name = self.java_class.name + "Test"
970 self.test_units = []
971 if test_data.exists(first_data_file_name):
972 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
973 i = 1
974 while test_data.exists(data_file_template.format(i=i)):
975 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
976 i = i + 1
Andreas Wundsamf1949682013-09-23 14:48:31 -0700977
Yotam Harchol466b3212013-08-15 12:14:46 -0700978 @property
979 def package(self):
980 return self.java_class.package
981
982 @property
983 def has_test_data(self):
984 return len(self.test_units) > 0
985
986 @property
987 def length(self):
988 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -0700989
Yotam Harchol466b3212013-08-15 12:14:46 -0700990 def get_test_unit(self, i):
991 return self.test_units[i]
992
993
994class JavaUnitTest(object):
995 def __init__(self, java_class, file_name=None, test_class_name=None):
996 self.java_class = java_class
997 if file_name is None:
998 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
999 name=java_class.c_name[3:])
1000 else:
1001 self.data_file_name = file_name
1002 if test_class_name is None:
1003 self.test_class_name = self.java_class.name + "Test"
1004 else:
1005 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001006
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001007 @property
1008 def package(self):
1009 return self.java_class.package
1010
1011 @property
1012 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001013 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001014
1015 @property
1016 def has_test_data(self):
1017 return test_data.exists(self.data_file_name)
1018
1019 @property
1020 @memoize
1021 def test_data(self):
1022 return test_data.read(self.data_file_name)
1023
1024
Andreas Wundsam27303462013-07-16 12:52:35 -07001025#######################################################################
1026### Enums
1027#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001028
Andreas Wundsam27303462013-07-16 12:52:35 -07001029class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001030 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001031 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001032
1033 if c_name == "of_stats_types":
1034 self.name = "OFStatsType"
1035 else:
1036 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001037
Andreas Wundsam27303462013-07-16 12:52:35 -07001038 # Port_features has constants that start with digits
1039 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001040
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001041 self.version_enums = version_enum_map
1042
1043 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1044 for version, ir_enum in version_enum_map.items():
1045 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001046 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1047
Andreas Wundsam27303462013-07-16 12:52:35 -07001048 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001049 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001050
1051 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 -07001052 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001053
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001054 self.metadata = model.enum_metadata_map[self.name]
1055
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001056 def wire_type(self, version):
1057 ir_enum = self.version_enums[version]
1058 if "wire_type" in ir_enum.params:
1059 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1060 else:
1061 return java_type.u8
1062
1063 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001064 @memoize
1065 def is_bitmask(self):
1066 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1067
1068 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001069 def versions(self):
1070 return self.version_enums.keys()
1071
Andreas Wundsam27303462013-07-16 12:52:35 -07001072 @memoize
1073 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001074 res = find(lambda e: e.name == name, self.entries)
1075 if res:
1076 return res
1077 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001078 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1079
1080 @memoize
1081 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001082 res = find(lambda e: e.c_name == name, self.entries)
1083 if res:
1084 return res
1085 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001086 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1087
1088 @memoize
1089 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001090 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1091 if res:
1092 return res
1093 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001094 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1095
1096# values: Map JavaVersion->Value
1097class JavaEnumEntry(object):
1098 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001099 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001100 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1101 self.values = values
1102
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001103 @property
1104 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001105 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001106
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001107 def has_value(self, version):
1108 return version in self.values
1109
Andreas Wundsam27303462013-07-16 12:52:35 -07001110 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001111 return self.values[version]
1112
1113 def format_value(self, version):
1114 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001115 return res
1116
Andreas Wundsam27303462013-07-16 12:52:35 -07001117 def all_values(self, versions, not_present=None):
1118 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001119
1120 @property
1121 @memoize
1122 def masked_enum_group(self):
1123 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1124 return group
1125
1126 @property
1127 @memoize
1128 def is_mask(self):
1129 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])