blob: 8498dab8d4909c799af692721f1c405a169bc2a0 [file] [log] [blame]
Andreas Wundsam27303462013-07-16 12:52:35 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
Andreas Wundsam40e14f72013-05-06 14:49:08 -070028# Prototype of an Intermediate Object model for the java code generator
29# A lot of this stuff could/should probably be merged with the python utilities
30
Andreas Wundsam27303462013-07-16 12:52:35 -070031import collections
Andreas Wundsam5204de22013-07-30 11:34:45 -070032from collections import namedtuple, defaultdict, OrderedDict
Andreas Wundsam27303462013-07-16 12:52:35 -070033import logging
Andreas Wundsam40e14f72013-05-06 14:49:08 -070034import os
35import pdb
36import re
37
Andreas Wundsam5204de22013-07-30 11:34:45 -070038from generic_utils import find, memoize, OrderedSet, OrderedDefaultDict
Andreas Wundsam27303462013-07-16 12:52:35 -070039import of_g
40from loxi_ir import *
Andreas Wundsam40e14f72013-05-06 14:49:08 -070041import loxi_front_end.type_maps as type_maps
Andreas Wundsam5204de22013-07-30 11:34:45 -070042import loxi_utils.loxi_utils as loxi_utils
Andreas Wundsam40e14f72013-05-06 14:49:08 -070043import py_gen.util as py_utils
Andreas Wundsam5204de22013-07-30 11:34:45 -070044import test_data
Andreas Wundsam40e14f72013-05-06 14:49:08 -070045
Andreas Wundsam27303462013-07-16 12:52:35 -070046import java_gen.java_type as java_type
Andreas Wundsame0d52be2013-08-22 07:52:13 -070047from java_gen.java_type import erase_type_annotation
Andreas Wundsam40e14f72013-05-06 14:49:08 -070048
Andreas Wundsam27303462013-07-16 12:52:35 -070049class JavaModel(object):
Andreas Wundsamf1949682013-09-23 14:48:31 -070050 # registry for enums that should not be generated
51 # set(${java_enum_name})
Rob Vaterlausfbd5b6b2013-09-24 15:55:47 -070052 enum_blacklist = set(("OFDefinitions", "OFPortNo",))
Andreas Wundsamf1949682013-09-23 14:48:31 -070053 # registry for enum *entry* that should not be generated
54 # map: ${java_enum_name} -> set(${java_entry_entry_name})
Andreas Wundsam43526532013-08-01 22:03:50 -070055 enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
Andreas Wundsamf1949682013-09-23 14:48:31 -070056
57 # registry of interfaces that should not be generated
58 # set(java_names)
Andreas Wundsambe168f72013-08-03 22:49:35 -070059 # OFUint structs are there for god-knows what in loci. We certainly don't need them.
60 interface_blacklist = set( ("OFUint8", "OFUint32",))
Andreas Wundsamf1949682013-09-23 14:48:31 -070061 # registry of interface properties that should not be generated
62 # map: $java_type -> set(java_name_property)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070063 read_blacklist = defaultdict(lambda: set(), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070064 # map: $java_type -> set(java_name_property)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070065 write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070066 # interfaces that are virtual
Andreas Wundsam001b1822013-08-02 22:25:55 -070067 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070068
Andreas Wundsam2be7da52013-08-22 07:34:25 -070069 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
Yotam Harchole5d92972013-08-22 14:18:36 -070070 oxm_map = { "OFOxmInPort": OxmMapEntry("OFPort", "IN_PORT", False),
71 "OFOxmInPortMasked": OxmMapEntry("OFPort", "IN_PORT", True),
72 "OFOxmInPhyPort": OxmMapEntry("OFPort", "IN_PHY_PORT", False),
73 "OFOxmInPhyPortMasked": OxmMapEntry("OFPort", "IN_PHY_PORT", True),
74 "OFOxmMetadata": OxmMapEntry("OFMetadata", "METADATA", False),
75 "OFOxmMetadataMasked": OxmMapEntry("OFMetadata", "METADATA", True),
76 "OFOxmEthDst": OxmMapEntry("MacAddress", "ETH_DST", False),
77 "OFOxmEthDstMasked": OxmMapEntry("MacAddress", "ETH_DST", True),
78 "OFOxmEthSrc": OxmMapEntry("MacAddress", "ETH_SRC", False),
79 "OFOxmEthSrcMasked": OxmMapEntry("MacAddress", "ETH_SRC", True),
80 "OFOxmEthType": OxmMapEntry("EthType", "ETH_TYPE", False),
81 "OFOxmEthTypeMasked": OxmMapEntry("EthType", "ETH_TYPE", True),
82 "OFOxmVlanVid": OxmMapEntry("VlanVid", "VLAN_VID", False),
83 "OFOxmVlanVidMasked": OxmMapEntry("VlanVid", "VLAN_VID", True),
84 "OFOxmVlanPcp": OxmMapEntry("VlanPcp", "VLAN_PCP", False),
85 "OFOxmVlanPcpMasked": OxmMapEntry("VlanPcp", "VLAN_PCP", True),
86 "OFOxmIpDscp": OxmMapEntry("IpDscp", "IP_DSCP", False),
87 "OFOxmIpDscpMasked": OxmMapEntry("IpDscp", "IP_DSCP", True),
88 "OFOxmIpEcn": OxmMapEntry("IpEcn", "IP_ECN", False),
89 "OFOxmIpEcnMasked": OxmMapEntry("IpEcn", "IP_ECN", True),
90 "OFOxmIpProto": OxmMapEntry("IpProtocol", "IP_PROTO", False),
91 "OFOxmIpProtoMasked": OxmMapEntry("IpProtocol", "IP_PROTO", True),
Yotam Harchola289d552013-09-16 10:10:40 -070092 "OFOxmIpv4Src": OxmMapEntry("IPv4Address", "IPV4_SRC", False),
93 "OFOxmIpv4SrcMasked": OxmMapEntry("IPv4Address", "IPV4_SRC", True),
94 "OFOxmIpv4Dst": OxmMapEntry("IPv4Address", "IPV4_DST", False),
95 "OFOxmIpv4DstMasked": OxmMapEntry("IPv4Address", "IPV4_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -070096 "OFOxmTcpSrc": OxmMapEntry("TransportPort", "TCP_SRC", False),
97 "OFOxmTcpSrcMasked": OxmMapEntry("TransportPort", "TCP_SRC", True),
98 "OFOxmTcpDst": OxmMapEntry("TransportPort", "TCP_DST", False),
99 "OFOxmTcpDstMasked": OxmMapEntry("TransportPort", "TCP_DST", True),
100 "OFOxmUdpSrc": OxmMapEntry("TransportPort", "UDP_SRC", False),
101 "OFOxmUdpSrcMasked": OxmMapEntry("TransportPort", "UDP_SRC", True),
102 "OFOxmUdpDst": OxmMapEntry("TransportPort", "UDP_DST", False),
103 "OFOxmUdpDstMasked": OxmMapEntry("TransportPort", "UDP_DST", True),
104 "OFOxmSctpSrc": OxmMapEntry("TransportPort", "SCTP_SRC", False),
105 "OFOxmSctpSrcMasked": OxmMapEntry("TransportPort", "SCTP_SRC", True),
106 "OFOxmSctpDst": OxmMapEntry("TransportPort", "SCTP_DST", False),
107 "OFOxmSctpDstMasked": OxmMapEntry("TransportPort", "SCTP_DST", True),
108 "OFOxmIcmpv4Type": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", False),
109 "OFOxmIcmpv4TypeMasked": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", True),
110 "OFOxmIcmpv4Code": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", False),
111 "OFOxmIcmpv4CodeMasked": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", True),
112 "OFOxmArpOp": OxmMapEntry("ArpOpcode", "ARP_OP", False),
113 "OFOxmArpOpMasked": OxmMapEntry("ArpOpcode", "ARP_OP", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700114 "OFOxmArpSpa": OxmMapEntry("IPv4Address", "ARP_SPA", False),
115 "OFOxmArpSpaMasked": OxmMapEntry("IPv4Address", "ARP_SPA", True),
116 "OFOxmArpTpa": OxmMapEntry("IPv4Address", "ARP_TPA", False),
117 "OFOxmArpTpaMasked": OxmMapEntry("IPv4Address", "ARP_TPA", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700118 "OFOxmArpSha": OxmMapEntry("MacAddress", "ARP_SHA", False),
119 "OFOxmArpShaMasked": OxmMapEntry("MacAddress", "ARP_SHA", True),
120 "OFOxmArpTha": OxmMapEntry("MacAddress", "ARP_THA", False),
121 "OFOxmArpThaMasked": OxmMapEntry("MacAddress", "ARP_THA", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700122 "OFOxmIpv6Src": OxmMapEntry("IPv6Address", "IPV6_SRC", False),
123 "OFOxmIpv6SrcMasked": OxmMapEntry("IPv6Address", "IPV6_SRC", True),
124 "OFOxmIpv6Dst": OxmMapEntry("IPv6Address", "IPV6_DST", False),
125 "OFOxmIpv6DstMasked": OxmMapEntry("IPv6Address", "IPV6_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700126 "OFOxmIpv6Flabel": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", False),
Yotam Harchola86e4252013-09-06 15:36:28 -0700127 "OFOxmIpv6FlabelMasked": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True),
128 "OFOxmIcmpv6Type": OxmMapEntry("U8", "ICMPV6_TYPE", False),
129 "OFOxmIcmpv6TypeMasked": OxmMapEntry("U8", "ICMPV6_TYPE", True),
130 "OFOxmIcmpv6Code": OxmMapEntry("U8", "ICMPV6_CODE", False),
131 "OFOxmIcmpv6CodeMasked": OxmMapEntry("U8", "ICMPV6_CODE", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700132 "OFOxmIpv6NdTarget": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", False),
133 "OFOxmIpv6NdTargetMasked": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", True),
Yotam Harchola86e4252013-09-06 15:36:28 -0700134 "OFOxmIpv6NdSll": OxmMapEntry("MacAddress", "IPV6_ND_SLL", False),
135 "OFOxmIpv6NdSllMasked": OxmMapEntry("MacAddress", "IPV6_ND_SLL", True),
136 "OFOxmIpv6NdTll": OxmMapEntry("MacAddress", "IPV6_ND_TLL", False),
137 "OFOxmIpv6NdTllMasked": OxmMapEntry("MacAddress", "IPV6_ND_TLL", True),
138 "OFOxmMplsLabel": OxmMapEntry("U32", "MPLS_LABEL", False),
139 "OFOxmMplsLabelMasked": OxmMapEntry("U32", "MPLS_LABEL", True),
140 "OFOxmMplsTc": OxmMapEntry("U8", "MPLS_TC", False),
141 "OFOxmMplsTcMasked": OxmMapEntry("U8", "MPLS_TC", True)
142 }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700143
Andreas Wundsamf1949682013-09-23 14:48:31 -0700144 # Registry of nullable properties:
145 # ${java_class_name} -> set(${java_property_name})
146 nullable_map = defaultdict(lambda: set(),
147 )
148
149 # represents a subgroup of a bitmask enum that is actualy a normal enumerable within a masked part of the enum
150 # e.g., the flags STP.* in OF1.0 port state are bit mask entries, but instead enumerables according to the mask "STP_MASK"
151 # name: a name for the group
152 # mask: java name of the enum entry that defines the mask
153 # members: set of names of the members of the group
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700154 MaskedEnumGroup = namedtuple("MaskedEnumGroup", ("name", "mask", "members"))
155
Andreas Wundsamf1949682013-09-23 14:48:31 -0700156 # registry of MaskedEnumGroups (see above).
157 # map: ${java_enum_name}: tuple(MaskedEnumGroup)
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700158 masked_enum_groups = defaultdict(lambda: (),
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)
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700487 elif re.match(r'OF.+ErrorMsg$', self.name):
488 return ("", "OFErrorMsg", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700489 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700490 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700491 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 -0700492 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700493 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 -0700494 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700495 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
496 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700497 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700498 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700499 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700500 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700501 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700502 if re.match(r'OFActionBsn.+', self.name):
503 return ("action", "OFActionBsn", None)
504 elif re.match(r'OFActionNicira.+', self.name):
505 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700506 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
507 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700508 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700509 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700510 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700511 return ("", "OFBsnVport", None)
512 elif self.name == "OFOxm":
513 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700514 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700515 if self.name in model.oxm_map:
516 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
517 else:
518 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700519 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700520 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700521 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700522 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700523 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700524 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700525 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700526 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700527 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700528 return ("", None, None)
529
530 @property
531 @memoize
532 def writeable_members(self):
533 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700534
535 @property
536 @memoize
537 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700538 return self.ir_model_members + self.virtual_members
539
540 @property
541 @memoize
542 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700543 """return a list of all members to be exposed by this interface. Corresponds to
544 the union of the members of the vesioned classes without length, fieldlength
545 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700546 all_versions = []
547 member_map = collections.OrderedDict()
548
549 for (version, of_class) in self.version_map.items():
550 for of_member in of_class.members:
551 if isinstance(of_member, OFLengthMember) or \
552 isinstance(of_member, OFFieldLengthMember) or \
553 isinstance(of_member, OFPadMember):
554 continue
555 if of_member.name not in member_map:
556 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
557
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700558 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 -0700559
560 @property
561 def virtual_members(self):
562 if self.name == "OFOxm":
563 return (
564 JavaVirtualMember(self, "value", java_type.generic_t),
565 JavaVirtualMember(self, "mask", java_type.generic_t),
566 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
567 JavaVirtualMember(self, "masked", java_type.boolean),
568 )
569 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
570 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
571 if self.name in model.oxm_map \
572 else java_type.make_match_field_jtype()
573
574 return (
575 JavaVirtualMember(self, "matchField", field_type),
576 JavaVirtualMember(self, "masked", java_type.boolean),
577 ) \
578 + \
579 (
580 ( 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
581 ()
582 )
583 else:
584 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700585
586 @property
587 @memoize
588 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700589 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700590 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 -0700591
592 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700593 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700594 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700595 return len(self.all_versions) == len(model.versions)
596
597 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700598 @memoize
599 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700600 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700601 return self.version_map.keys()
602
Andreas Wundsam5204de22013-07-30 11:34:45 -0700603 def has_version(self, version):
604 return version in self.version_map
605
Andreas Wundsam27303462013-07-16 12:52:35 -0700606 def versioned_class(self, version):
607 return JavaOFClass(self, version, self.version_map[version])
608
609 @property
610 @memoize
611 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700612 return [ self.versioned_class(version) for version in self.all_versions ]
613
614#######################################################################
615### (Versioned) Classes
616#######################################################################
617
618class JavaOFClass(object):
619 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700620 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700621 """
622 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700623 """
624 @param interface JavaOFInterface instance of the parent interface
625 @param version JavaOFVersion
626 @param ir_class OFClass from loxi_ir
627 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700628 self.interface = interface
629 self.ir_class = ir_class
630 self.c_name = self.ir_class.name
631 self.version = version
632 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700633 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700634 self.generated = False
635
636 @property
637 @memoize
638 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700639 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700640
641 @property
642 def name(self):
643 return "%sVer%s" % (self.interface.name, self.version.of_version)
644
645 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700646 def variable_name(self):
647 return self.name[3:]
648
649 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700650 def length(self):
651 if self.is_fixed_length:
652 return self.min_length
653 else:
654 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
655
656 @property
657 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700658 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700659 id_tuple = (self.ir_class.name, self.version.int_version)
660 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
661
662 @property
663 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700664 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700665 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
666 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700667
668 def all_properties(self):
669 return self.interface.members
670
671 def get_member(self, name):
672 for m in self.members:
673 if m.name == name:
674 return m
675
676 @property
677 @memoize
678 def data_members(self):
679 return [ prop for prop in self.members if prop.is_data ]
680
681 @property
682 @memoize
683 def fixed_value_members(self):
684 return [ prop for prop in self.members if prop.is_fixed_value ]
685
686 @property
687 @memoize
688 def public_members(self):
689 return [ prop for prop in self.members if prop.is_public ]
690
691 @property
692 @memoize
693 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700694 return self.ir_model_members + self.virtual_members
695
696 @property
697 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700698 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700699 return tuple(members)
700
701 @property
702 def virtual_members(self):
703 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
704 if self.interface.name in model.oxm_map:
705 oxm_entry = model.oxm_map[self.interface.name]
706 return (
707 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
708 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
709 )
710 else:
711 return (
712 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
713 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
714 )
715 else:
716 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700717
718 def all_versions(self):
719 return [ JavaOFVersion(int_version)
720 for int_version in of_g.unified[self.c_name]
721 if int_version != 'union' and int_version != 'object_id' ]
722
723 def version_is_inherited(self, version):
724 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
725
726 def inherited_from(self, version):
727 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
728
729 @property
730 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700731 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
732
733 @property
734 def discriminator(self):
735 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700736
737 @property
738 def is_extension(self):
739 return type_maps.message_is_extension(self.c_name, -1)
740
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700741 @property
742 def align(self):
743 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
744
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700745 @property
746 @memoize
747 def superclass(self):
748 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
749
750 @property
751 @memoize
752 def subclasses(self):
753 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
754
Andreas Wundsam27303462013-07-16 12:52:35 -0700755#######################################################################
756### Member
757#######################################################################
758
759
760class JavaMember(object):
761 """ Models a property (member) of an openflow class. """
762 def __init__(self, msg, name, java_type, member):
763 self.msg = msg
764 self.name = name
765 self.java_type = java_type
766 self.member = member
767 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700768
769 @property
770 def title_name(self):
771 return self.name[0].upper() + self.name[1:]
772
773 @property
774 def constant_name(self):
775 return self.c_name.upper()
776
777 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700778 def getter_name(self):
779 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
780
781 @property
782 def setter_name(self):
783 return "set" + self.title_name
784
785 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700786 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700787 if self.is_fixed_value:
788 return self.constant_name
789 else:
790 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700791
792 @property
793 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700794 if self.is_fixed_value:
795 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700796 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700797 default = self.java_type.default_op(self.msg.version)
798 if default == "null" and not self.is_nullable:
799 return None
800 else:
801 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700802
803 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700804 def enum_value(self):
805 if self.name == "version":
806 return "OFVersion.%s" % self.msg.version.constant_version
807
808 java_type = self.java_type.public_type;
809 try:
810 global model
811 enum = model.enum_by_name(java_type)
812 entry = enum.entry_by_version_value(self.msg.version, self.value)
813 return "%s.%s" % ( enum.name, entry.name)
814 except KeyError, e:
815 print e.message
816 return self.value
817
818 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700819 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700820 return isinstance(self.member, OFPadMember)
821
822 def is_type_value(self, version=None):
823 if(version==None):
824 return any(self.is_type_value(version) for version in self.msg.all_versions)
825 try:
826 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
827 except:
828 return False
829
830 @property
831 def is_field_length_value(self):
832 return isinstance(self.member, OFFieldLengthMember)
833
834 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700835 def is_discriminator(self):
836 return isinstance(self.member, OFDiscriminatorMember)
837
838 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700839 def is_length_value(self):
840 return isinstance(self.member, OFLengthMember)
841
842 @property
843 def is_public(self):
844 return not (self.is_pad or self.is_length_value)
845
846 @property
847 def is_data(self):
848 return isinstance(self.member, OFDataMember) and self.name != "version"
849
850 @property
851 def is_fixed_value(self):
852 return hasattr(self.member, "value") or self.name == "version" \
853 or ( self.name == "length" and self.msg.is_fixed_length) \
854 or ( self.name == "len" and self.msg.is_fixed_length)
855
856 @property
857 def value(self):
858 if self.name == "version":
859 return self.msg.version.int_version
860 elif self.name == "length" or self.name == "len":
861 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700862 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700863 return self.java_type.format_value(self.member.value)
864
865 @property
866 def priv_value(self):
867 if self.name == "version":
868 return self.msg.version.int_version
869 elif self.name == "length" or self.name == "len":
870 return self.msg.length
871 else:
872 return self.java_type.format_value(self.member.value, pub_type=False)
873
Andreas Wundsam27303462013-07-16 12:52:35 -0700874
875 @property
876 def is_writeable(self):
877 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
878
879 def get_type_value_info(self, version):
880 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700881
882 @property
883 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700884 if hasattr(self.member, "length"):
885 return self.member.length
886 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700887 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700888 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700889
890 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700891 def for_of_member(java_class, member):
892 if isinstance(member, OFPadMember):
893 return JavaMember(None, "", None, member)
894 else:
895 if member.name == 'len':
896 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700897 elif member.name == 'value_mask':
898 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700899 else:
900 name = java_type.name_c_to_camel(member.name)
901 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
902 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700903
904 @property
905 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700906 if not self.msg.c_name in of_g.unified:
907 print("%s not self.unified" % self.msg.c_name)
908 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700909 for version in of_g.unified[self.msg.c_name]:
910 if version == 'union' or version =='object_id':
911 continue
912 if 'use_version' in of_g.unified[self.msg.c_name][version]:
913 continue
914
Andreas Wundsam27303462013-07-16 12:52:35 -0700915 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 -0700916 return False
917 return True
918
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700919 @property
920 def is_virtual(self):
921 return False
922
Andreas Wundsam27303462013-07-16 12:52:35 -0700923 def __hash__(self):
924 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700925
Andreas Wundsam27303462013-07-16 12:52:35 -0700926 def __eq__(self, other):
927 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700928 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700929 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700930
Andreas Wundsamf1949682013-09-23 14:48:31 -0700931 @property
932 def is_nullable(self):
933 return self.name in model.nullable_map[self.msg.name]
934
935
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700936class JavaVirtualMember(JavaMember):
937 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
938 def __init__(self, msg, name, java_type, value=None):
939 JavaMember.__init__(self, msg, name, java_type, member=None)
940 self._value = value
941
942 @property
943 def is_fixed_value(self):
944 return True
945
946 @property
947 def value(self):
948 return self._value
949
950 @property
951 def priv_value(self):
952 return self._value
953
954
955 @property
956 def is_universal(self):
957 return True
958
959 @property
960 def is_virtual(self):
961 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700962
963#######################################################################
964### Unit Test
965#######################################################################
966
Yotam Harchol466b3212013-08-15 12:14:46 -0700967class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700968 def __init__(self, java_class):
969 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700970 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700971 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700972 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
973 name=java_class.c_name[3:]) + "{i}.data"
974 test_class_name = self.java_class.name + "Test"
975 self.test_units = []
976 if test_data.exists(first_data_file_name):
977 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
978 i = 1
979 while test_data.exists(data_file_template.format(i=i)):
980 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
981 i = i + 1
Andreas Wundsamf1949682013-09-23 14:48:31 -0700982
Yotam Harchol466b3212013-08-15 12:14:46 -0700983 @property
984 def package(self):
985 return self.java_class.package
986
987 @property
988 def has_test_data(self):
989 return len(self.test_units) > 0
990
991 @property
992 def length(self):
993 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -0700994
Yotam Harchol466b3212013-08-15 12:14:46 -0700995 def get_test_unit(self, i):
996 return self.test_units[i]
997
998
999class JavaUnitTest(object):
1000 def __init__(self, java_class, file_name=None, test_class_name=None):
1001 self.java_class = java_class
1002 if file_name is None:
1003 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
1004 name=java_class.c_name[3:])
1005 else:
1006 self.data_file_name = file_name
1007 if test_class_name is None:
1008 self.test_class_name = self.java_class.name + "Test"
1009 else:
1010 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001011
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001012 @property
1013 def package(self):
1014 return self.java_class.package
1015
1016 @property
1017 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001018 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001019
1020 @property
1021 def has_test_data(self):
1022 return test_data.exists(self.data_file_name)
1023
1024 @property
1025 @memoize
1026 def test_data(self):
1027 return test_data.read(self.data_file_name)
1028
1029
Andreas Wundsam27303462013-07-16 12:52:35 -07001030#######################################################################
1031### Enums
1032#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001033
Andreas Wundsam27303462013-07-16 12:52:35 -07001034class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001035 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001036 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001037
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001038 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001039
Andreas Wundsam27303462013-07-16 12:52:35 -07001040 # Port_features has constants that start with digits
1041 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001042
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001043 self.version_enums = version_enum_map
1044
1045 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1046 for version, ir_enum in version_enum_map.items():
1047 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001048 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1049
Andreas Wundsam27303462013-07-16 12:52:35 -07001050 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001051 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001052
1053 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 -07001054 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001055
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001056 self.metadata = model.enum_metadata_map[self.name]
1057
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001058 def wire_type(self, version):
1059 ir_enum = self.version_enums[version]
1060 if "wire_type" in ir_enum.params:
1061 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1062 else:
1063 return java_type.u8
1064
1065 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001066 @memoize
1067 def is_bitmask(self):
1068 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1069
1070 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001071 def versions(self):
1072 return self.version_enums.keys()
1073
Andreas Wundsam27303462013-07-16 12:52:35 -07001074 @memoize
1075 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001076 res = find(lambda e: e.name == name, self.entries)
1077 if res:
1078 return res
1079 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001080 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1081
1082 @memoize
1083 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001084 res = find(lambda e: e.c_name == name, self.entries)
1085 if res:
1086 return res
1087 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001088 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1089
1090 @memoize
1091 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001092 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1093 if res:
1094 return res
1095 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001096 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1097
1098# values: Map JavaVersion->Value
1099class JavaEnumEntry(object):
1100 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001101 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001102 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1103 self.values = values
1104
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001105 @property
1106 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001107 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001108
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001109 def has_value(self, version):
1110 return version in self.values
1111
Andreas Wundsam27303462013-07-16 12:52:35 -07001112 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001113 return self.values[version]
1114
1115 def format_value(self, version):
1116 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001117 return res
1118
Andreas Wundsam27303462013-07-16 12:52:35 -07001119 def all_values(self, versions, not_present=None):
1120 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001121
1122 @property
1123 @memoize
1124 def masked_enum_group(self):
1125 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1126 return group
1127
1128 @property
1129 @memoize
1130 def is_mask(self):
1131 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])