blob: 17a7fc8fa42d2d3c81f92236ac4dd621551f789e [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"))),
Andreas Wundsam376cef52013-09-24 13:52:18 -0700162 ),
163 OFTableConfig = (
164 MaskedEnumGroup("table_miss_flags", mask="TABLE_MISS_MASK", members=set(("TABLE_MISS_CONTROLLER", "TABLE_MISS_CONTINUE", "TABLE_MISS_DROP"))),
165 ),
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700166 )
167
Andreas Wundsamf1949682013-09-23 14:48:31 -0700168 # represents a metadata property associated with an EnumClass
169 # name:
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700170 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700171 """
172 represents a metadata property associated with an Enum Class
173 @param name name of metadata property
174 @param type java_type instance describing the type
175 @value: Generator function f(entry) that generates the value
176 """
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700177 @property
178 def variable_name(self):
179 return self.name[0].lower() + self.name[1:]
180
181 @property
182 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700183 prefix = "is" if self.type == java_type.boolean else "get"
184 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700185
Andreas Wundsamf1949682013-09-23 14:48:31 -0700186 """ Metadata container. """
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700187 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
188
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700189 def gen_port_speed(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700190 """ Generator function for OFortFeatures.PortSpeed"""
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700191 splits = enum_entry.name.split("_")
192 if len(splits)>=2:
193 m = re.match(r'\d+[MGTP]B', splits[1])
194 if m:
195 return "PortSpeed.SPEED_{}".format(splits[1])
196 return "PortSpeed.SPEED_NONE";
197
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700198 def gen_stp_state(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700199 """ Generator function for OFPortState.StpState"""
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700200 splits = enum_entry.name.split("_")
201 if len(splits)>=1:
202 if splits[0] == "STP":
203 return "true"
204 return "false"
205
Andreas Wundsamf1949682013-09-23 14:48:31 -0700206 # registry for metadata properties for enums
207 # map: ${java_enum_name}: OFEnumMetadata
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700208 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700209 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
210 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700211 )
212
Andreas Wundsam27303462013-07-16 12:52:35 -0700213 @property
214 @memoize
215 def versions(self):
216 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
217
218 @property
219 @memoize
220 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700221 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700222
223 for raw_version, of_protocol in of_g.ir.items():
224 jversion = JavaOFVersion(of_protocol.wire_version)
225
226 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700227 if not of_class.name in version_map_per_class:
228 version_map_per_class[of_class.name] = collections.OrderedDict()
229
Andreas Wundsam27303462013-07-16 12:52:35 -0700230 version_map_per_class[of_class.name][jversion] = of_class
231
232 interfaces = []
233 for class_name, version_map in version_map_per_class.items():
234 interfaces.append(JavaOFInterface(class_name, version_map))
235
Andreas Wundsambe168f72013-08-03 22:49:35 -0700236 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
237
Andreas Wundsam27303462013-07-16 12:52:35 -0700238 return interfaces
239
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700240 @memoize
241 def interface_by_name(self, name):
242 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
243
Andreas Wundsam27303462013-07-16 12:52:35 -0700244 @property
245 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700246 def all_classes(self):
247 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
248
249 @property
250 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700251 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700252 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700253
254 for version in self.versions:
255 of_protocol = of_g.ir[version.int_version]
256 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700257 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700258
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700259 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
260 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700261
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700262 # inelegant - need java name here
263 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700264 return enums
265
266 @memoize
267 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700268 res = find(lambda e: e.name == name, self.enums)
269 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700270 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700271 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700272
Andreas Wundsam5204de22013-07-30 11:34:45 -0700273 @property
274 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700275 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700276 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700277
278 factories = OrderedDict()
279
280 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
281 for base_class in sub_factory_classes:
282 package = base_class[2:].lower()
283 remove_prefix = base_class[2].lower() + base_class[3:]
284
285 # HACK need to have a better way to deal with parameterized base classes
286 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
287
288 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
289 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
290
291 factories[""] = OFFactory(
292 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700293 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700294 remove_prefix="",
295 members=[], base_class="OFMessage", sub_factories=OrderedDict(
296 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
297
298 for i in self.interfaces:
299 for n, factory in factories.items():
300 if n == "":
301 factory.members.append(i)
302 break
303 else:
304 super_class = self.interface_by_name(n)
305 if i.is_instance_of(super_class):
306 factory.members.append(i)
307 break
308 return factories.values()
Andreas Wundsam5204de22013-07-30 11:34:45 -0700309
310 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700311 """ return wether or not to generate implementation class clazz.
312 Now true for everything except OFTableModVer10.
313 @param clazz JavaOFClass instance
314 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700315 if clazz.interface.name.startswith("OFMatchV"):
316 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700317 elif clazz.name == "OFTableModVer10":
318 # tablemod ver 10 is a hack and has no oftype defined
319 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700320 if loxi_utils.class_is_message(clazz.interface.c_name):
321 return True
322 if loxi_utils.class_is_oxm(clazz.interface.c_name):
323 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700324 if loxi_utils.class_is_action(clazz.interface.c_name):
325 return True
326 if loxi_utils.class_is_instruction(clazz.interface.c_name):
327 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700328 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700329 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700330
331
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700332class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700333 @property
334 def factory_classes(self):
335 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700336 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700337 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700338 interface=self,
339 version=version
340 ) for version in model.versions ]
341
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700342 def method_name(self, member, builder=True):
343 n = member.variable_name
344 if n.startswith(self.remove_prefix):
345 n = n[len(self.remove_prefix):]
346 n = n[0].lower() + n[1:]
347 if builder:
348 return "build" + n[0].upper() + n[1:]
349 else:
350 return n
Andreas Wundsam5204de22013-07-30 11:34:45 -0700351
352OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700353class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
354 @property
355 def base_class(self):
356 return self.interface.base_class
357
358 @property
359 def versioned_base_class(self):
360 base_class_interface = model.interface_by_name(self.interface.base_class)
361 if base_class_interface and base_class_interface.has_version(self.version):
362 return base_class_interface.versioned_class(self.version)
363 else:
364 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700365
Andreas Wundsam27303462013-07-16 12:52:35 -0700366model = JavaModel()
367
368#######################################################################
369### OFVersion
370#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700371
372class JavaOFVersion(object):
373 """ Models a version of OpenFlow. contains methods to convert the internal
374 Loxi version to a java constant / a string """
375 def __init__(self, int_version):
376 self.int_version = int(int_version)
377
378 @property
379 def of_version(self):
380 return "1" + str(int(self.int_version) - 1)
381
382 @property
383 def constant_version(self):
384 return "OF_" + self.of_version
385
Andreas Wundsam27303462013-07-16 12:52:35 -0700386 def __repr__(self):
387 return "JavaOFVersion(%d)" % self.int_version
388
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700389 def __str__(self):
390 return of_g.param_version_names[self.int_version]
391
Andreas Wundsam27303462013-07-16 12:52:35 -0700392 def __hash__(self):
393 return hash(self.int_version)
394
395 def __eq__(self, other):
396 if other is None or type(self) != type(other):
397 return False
398 return (self.int_version,) == (other.int_version,)
399
400#######################################################################
401### Interface
402#######################################################################
403
404class JavaOFInterface(object):
405 """ Models an OpenFlow Message class for the purpose of the java class.
406 Version agnostic, in contrast to the loxi_ir python model.
407 """
408 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700409 """"
410 @param c_name: loxi style name (e.g., of_flow_add)
411 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
412 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700413 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700414 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700415 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700416 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 -0700417 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700418 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700419 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700420 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700421 self.constant_name = c_name.upper().replace("OF_", "")
422
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700423 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700424 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700425 if self.name != parent_interface:
426 self.parent_interface = parent_interface
427 else:
428 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700429
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700430 @property
431 @memoize
432 def all_parent_interfaces(self):
433 return [ "OFObject" ] + \
434 ([ self.parent_interface ] if self.parent_interface else [] )+ \
435 self.additional_parent_interfaces
436 @property
437 @memoize
438 def additional_parent_interfaces(self):
439 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
440 m = re.match(r'(.*)Request$', self.name)
441 if m:
442 reply_name = m.group(1) + "Reply"
443 if model.interface_by_name(reply_name):
444 return ["OFRequest<%s>" % reply_name ]
445 return []
446
447
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700448 def is_instance_of(self, other_class):
449 if self == other_class:
450 return True
451 parent = self.super_class
452 if parent is None:
453 return False
454 else:
455 return parent.is_instance_of(other_class)
456
457 @property
458 def super_class(self):
459 if not self.parent_interface:
460 return None
461 else:
462 return model.interface_by_name(self.parent_interface)
463
464
465 def inherited_declaration(self, type_spec="?"):
466 if self.type_annotation:
467 return "%s<%s>" % (self.name, type_spec)
468 else:
469 return "%s" % self.name
470
471 @property
472 def type_variable(self):
473 if self.type_annotation:
474 return "<T>"
475 else:
476 return "";
477
Andreas Wundsam27303462013-07-16 12:52:35 -0700478 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700479 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
480 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
481 # model (note, that the loxi model is on versioned classes). Should check/infer the
482 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700483 if re.match(r'OF.+StatsRequest$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700484 return ("", "OFStatsRequest", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700485 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700486 return ("", "OFStatsReply", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700487 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700488 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700489 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 -0700490 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700491 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 -0700492 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700493 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
494 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700495 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700496 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700497 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700498 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700499 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700500 if re.match(r'OFActionBsn.+', self.name):
501 return ("action", "OFActionBsn", None)
502 elif re.match(r'OFActionNicira.+', self.name):
503 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700504 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
505 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700506 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700507 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700508 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700509 return ("", "OFBsnVport", None)
510 elif self.name == "OFOxm":
511 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700512 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700513 if self.name in model.oxm_map:
514 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
515 else:
516 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700517 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700518 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700519 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700520 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700521 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700522 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700523 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700524 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700525 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700526 return ("", None, None)
527
528 @property
529 @memoize
530 def writeable_members(self):
531 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700532
533 @property
534 @memoize
535 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700536 return self.ir_model_members + self.virtual_members
537
538 @property
539 @memoize
540 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700541 """return a list of all members to be exposed by this interface. Corresponds to
542 the union of the members of the vesioned classes without length, fieldlength
543 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700544 all_versions = []
545 member_map = collections.OrderedDict()
546
547 for (version, of_class) in self.version_map.items():
548 for of_member in of_class.members:
549 if isinstance(of_member, OFLengthMember) or \
550 isinstance(of_member, OFFieldLengthMember) or \
551 isinstance(of_member, OFPadMember):
552 continue
553 if of_member.name not in member_map:
554 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
555
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700556 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 -0700557
558 @property
559 def virtual_members(self):
560 if self.name == "OFOxm":
561 return (
562 JavaVirtualMember(self, "value", java_type.generic_t),
563 JavaVirtualMember(self, "mask", java_type.generic_t),
564 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
565 JavaVirtualMember(self, "masked", java_type.boolean),
566 )
567 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
568 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
569 if self.name in model.oxm_map \
570 else java_type.make_match_field_jtype()
571
572 return (
573 JavaVirtualMember(self, "matchField", field_type),
574 JavaVirtualMember(self, "masked", java_type.boolean),
575 ) \
576 + \
577 (
578 ( 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
579 ()
580 )
581 else:
582 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700583
584 @property
585 @memoize
586 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700587 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700588 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 -0700589
590 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700591 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700592 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700593 return len(self.all_versions) == len(model.versions)
594
595 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700596 @memoize
597 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700598 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700599 return self.version_map.keys()
600
Andreas Wundsam5204de22013-07-30 11:34:45 -0700601 def has_version(self, version):
602 return version in self.version_map
603
Andreas Wundsam27303462013-07-16 12:52:35 -0700604 def versioned_class(self, version):
605 return JavaOFClass(self, version, self.version_map[version])
606
607 @property
608 @memoize
609 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700610 return [ self.versioned_class(version) for version in self.all_versions ]
611
612#######################################################################
613### (Versioned) Classes
614#######################################################################
615
616class JavaOFClass(object):
617 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700618 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700619 """
620 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700621 """
622 @param interface JavaOFInterface instance of the parent interface
623 @param version JavaOFVersion
624 @param ir_class OFClass from loxi_ir
625 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700626 self.interface = interface
627 self.ir_class = ir_class
628 self.c_name = self.ir_class.name
629 self.version = version
630 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700631 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700632 self.generated = False
633
634 @property
635 @memoize
636 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700637 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700638
639 @property
640 def name(self):
641 return "%sVer%s" % (self.interface.name, self.version.of_version)
642
643 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700644 def variable_name(self):
645 return self.name[3:]
646
647 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700648 def length(self):
649 if self.is_fixed_length:
650 return self.min_length
651 else:
652 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
653
654 @property
655 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700656 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700657 id_tuple = (self.ir_class.name, self.version.int_version)
658 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
659
660 @property
661 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700662 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700663 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
664 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700665
666 def all_properties(self):
667 return self.interface.members
668
669 def get_member(self, name):
670 for m in self.members:
671 if m.name == name:
672 return m
673
674 @property
675 @memoize
676 def data_members(self):
677 return [ prop for prop in self.members if prop.is_data ]
678
679 @property
680 @memoize
681 def fixed_value_members(self):
682 return [ prop for prop in self.members if prop.is_fixed_value ]
683
684 @property
685 @memoize
686 def public_members(self):
687 return [ prop for prop in self.members if prop.is_public ]
688
689 @property
690 @memoize
691 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700692 return self.ir_model_members + self.virtual_members
693
694 @property
695 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700696 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700697 return tuple(members)
698
699 @property
700 def virtual_members(self):
701 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
702 if self.interface.name in model.oxm_map:
703 oxm_entry = model.oxm_map[self.interface.name]
704 return (
705 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
706 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
707 )
708 else:
709 return (
710 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
711 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
712 )
713 else:
714 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700715
716 def all_versions(self):
717 return [ JavaOFVersion(int_version)
718 for int_version in of_g.unified[self.c_name]
719 if int_version != 'union' and int_version != 'object_id' ]
720
721 def version_is_inherited(self, version):
722 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
723
724 def inherited_from(self, version):
725 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
726
727 @property
728 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700729 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
730
731 @property
732 def discriminator(self):
733 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700734
735 @property
736 def is_extension(self):
737 return type_maps.message_is_extension(self.c_name, -1)
738
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700739 @property
740 def align(self):
741 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
742
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700743 @property
744 @memoize
745 def superclass(self):
746 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
747
748 @property
749 @memoize
750 def subclasses(self):
751 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
752
Andreas Wundsam27303462013-07-16 12:52:35 -0700753#######################################################################
754### Member
755#######################################################################
756
757
758class JavaMember(object):
759 """ Models a property (member) of an openflow class. """
760 def __init__(self, msg, name, java_type, member):
761 self.msg = msg
762 self.name = name
763 self.java_type = java_type
764 self.member = member
765 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700766
767 @property
768 def title_name(self):
769 return self.name[0].upper() + self.name[1:]
770
771 @property
772 def constant_name(self):
773 return self.c_name.upper()
774
775 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700776 def getter_name(self):
777 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
778
779 @property
780 def setter_name(self):
781 return "set" + self.title_name
782
783 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700784 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700785 if self.is_fixed_value:
786 return self.constant_name
787 else:
788 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700789
790 @property
791 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700792 if self.is_fixed_value:
793 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700794 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700795 default = self.java_type.default_op(self.msg.version)
796 if default == "null" and not self.is_nullable:
797 return None
798 else:
799 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700800
801 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700802 def enum_value(self):
803 if self.name == "version":
804 return "OFVersion.%s" % self.msg.version.constant_version
805
806 java_type = self.java_type.public_type;
807 try:
808 global model
809 enum = model.enum_by_name(java_type)
810 entry = enum.entry_by_version_value(self.msg.version, self.value)
811 return "%s.%s" % ( enum.name, entry.name)
812 except KeyError, e:
813 print e.message
814 return self.value
815
816 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700817 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700818 return isinstance(self.member, OFPadMember)
819
820 def is_type_value(self, version=None):
821 if(version==None):
822 return any(self.is_type_value(version) for version in self.msg.all_versions)
823 try:
824 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
825 except:
826 return False
827
828 @property
829 def is_field_length_value(self):
830 return isinstance(self.member, OFFieldLengthMember)
831
832 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700833 def is_discriminator(self):
834 return isinstance(self.member, OFDiscriminatorMember)
835
836 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700837 def is_length_value(self):
838 return isinstance(self.member, OFLengthMember)
839
840 @property
841 def is_public(self):
842 return not (self.is_pad or self.is_length_value)
843
844 @property
845 def is_data(self):
846 return isinstance(self.member, OFDataMember) and self.name != "version"
847
848 @property
849 def is_fixed_value(self):
850 return hasattr(self.member, "value") or self.name == "version" \
851 or ( self.name == "length" and self.msg.is_fixed_length) \
852 or ( self.name == "len" and self.msg.is_fixed_length)
853
854 @property
855 def value(self):
856 if self.name == "version":
857 return self.msg.version.int_version
858 elif self.name == "length" or self.name == "len":
859 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700860 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700861 return self.java_type.format_value(self.member.value)
862
863 @property
864 def priv_value(self):
865 if self.name == "version":
866 return self.msg.version.int_version
867 elif self.name == "length" or self.name == "len":
868 return self.msg.length
869 else:
870 return self.java_type.format_value(self.member.value, pub_type=False)
871
Andreas Wundsam27303462013-07-16 12:52:35 -0700872
873 @property
874 def is_writeable(self):
875 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
876
877 def get_type_value_info(self, version):
878 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700879
880 @property
881 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700882 if hasattr(self.member, "length"):
883 return self.member.length
884 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700885 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700886 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700887
888 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700889 def for_of_member(java_class, member):
890 if isinstance(member, OFPadMember):
891 return JavaMember(None, "", None, member)
892 else:
893 if member.name == 'len':
894 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700895 elif member.name == 'value_mask':
896 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700897 else:
898 name = java_type.name_c_to_camel(member.name)
899 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
900 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700901
902 @property
903 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700904 if not self.msg.c_name in of_g.unified:
905 print("%s not self.unified" % self.msg.c_name)
906 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700907 for version in of_g.unified[self.msg.c_name]:
908 if version == 'union' or version =='object_id':
909 continue
910 if 'use_version' in of_g.unified[self.msg.c_name][version]:
911 continue
912
Andreas Wundsam27303462013-07-16 12:52:35 -0700913 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 -0700914 return False
915 return True
916
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700917 @property
918 def is_virtual(self):
919 return False
920
Andreas Wundsam27303462013-07-16 12:52:35 -0700921 def __hash__(self):
922 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700923
Andreas Wundsam27303462013-07-16 12:52:35 -0700924 def __eq__(self, other):
925 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700926 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700927 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700928
Andreas Wundsamf1949682013-09-23 14:48:31 -0700929 @property
930 def is_nullable(self):
931 return self.name in model.nullable_map[self.msg.name]
932
933
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700934class JavaVirtualMember(JavaMember):
935 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
936 def __init__(self, msg, name, java_type, value=None):
937 JavaMember.__init__(self, msg, name, java_type, member=None)
938 self._value = value
939
940 @property
941 def is_fixed_value(self):
942 return True
943
944 @property
945 def value(self):
946 return self._value
947
948 @property
949 def priv_value(self):
950 return self._value
951
952
953 @property
954 def is_universal(self):
955 return True
956
957 @property
958 def is_virtual(self):
959 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700960
961#######################################################################
962### Unit Test
963#######################################################################
964
Yotam Harchol466b3212013-08-15 12:14:46 -0700965class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700966 def __init__(self, java_class):
967 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700968 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700969 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700970 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
971 name=java_class.c_name[3:]) + "{i}.data"
972 test_class_name = self.java_class.name + "Test"
973 self.test_units = []
974 if test_data.exists(first_data_file_name):
975 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
976 i = 1
977 while test_data.exists(data_file_template.format(i=i)):
978 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
979 i = i + 1
Andreas Wundsamf1949682013-09-23 14:48:31 -0700980
Yotam Harchol466b3212013-08-15 12:14:46 -0700981 @property
982 def package(self):
983 return self.java_class.package
984
985 @property
986 def has_test_data(self):
987 return len(self.test_units) > 0
988
989 @property
990 def length(self):
991 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -0700992
Yotam Harchol466b3212013-08-15 12:14:46 -0700993 def get_test_unit(self, i):
994 return self.test_units[i]
995
996
997class JavaUnitTest(object):
998 def __init__(self, java_class, file_name=None, test_class_name=None):
999 self.java_class = java_class
1000 if file_name is None:
1001 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
1002 name=java_class.c_name[3:])
1003 else:
1004 self.data_file_name = file_name
1005 if test_class_name is None:
1006 self.test_class_name = self.java_class.name + "Test"
1007 else:
1008 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001009
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001010 @property
1011 def package(self):
1012 return self.java_class.package
1013
1014 @property
1015 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001016 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001017
1018 @property
1019 def has_test_data(self):
1020 return test_data.exists(self.data_file_name)
1021
1022 @property
1023 @memoize
1024 def test_data(self):
1025 return test_data.read(self.data_file_name)
1026
1027
Andreas Wundsam27303462013-07-16 12:52:35 -07001028#######################################################################
1029### Enums
1030#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001031
Andreas Wundsam27303462013-07-16 12:52:35 -07001032class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001033 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001034 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001035
1036 if c_name == "of_stats_types":
1037 self.name = "OFStatsType"
1038 else:
1039 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001040
Andreas Wundsam27303462013-07-16 12:52:35 -07001041 # Port_features has constants that start with digits
1042 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001043
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001044 self.version_enums = version_enum_map
1045
1046 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1047 for version, ir_enum in version_enum_map.items():
1048 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001049 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1050
Andreas Wundsam27303462013-07-16 12:52:35 -07001051 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001052 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001053
1054 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 -07001055 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001056
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001057 self.metadata = model.enum_metadata_map[self.name]
1058
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001059 def wire_type(self, version):
1060 ir_enum = self.version_enums[version]
1061 if "wire_type" in ir_enum.params:
1062 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1063 else:
1064 return java_type.u8
1065
1066 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001067 @memoize
1068 def is_bitmask(self):
1069 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1070
1071 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001072 def versions(self):
1073 return self.version_enums.keys()
1074
Andreas Wundsam27303462013-07-16 12:52:35 -07001075 @memoize
1076 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001077 res = find(lambda e: e.name == name, self.entries)
1078 if res:
1079 return res
1080 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001081 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1082
1083 @memoize
1084 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001085 res = find(lambda e: e.c_name == name, self.entries)
1086 if res:
1087 return res
1088 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001089 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1090
1091 @memoize
1092 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001093 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1094 if res:
1095 return res
1096 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001097 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1098
1099# values: Map JavaVersion->Value
1100class JavaEnumEntry(object):
1101 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001102 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001103 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1104 self.values = values
1105
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001106 @property
1107 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001108 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001109
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001110 def has_value(self, version):
1111 return version in self.values
1112
Andreas Wundsam27303462013-07-16 12:52:35 -07001113 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001114 return self.values[version]
1115
1116 def format_value(self, version):
1117 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001118 return res
1119
Andreas Wundsam27303462013-07-16 12:52:35 -07001120 def all_values(self, versions, not_present=None):
1121 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001122
1123 @property
1124 @memoize
1125 def masked_enum_group(self):
1126 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1127 return group
1128
1129 @property
1130 @memoize
1131 def is_mask(self):
1132 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])