blob: 1636a9e934bd7bb53351613d27fdf69f67596b4d [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 Wundsamacd57d52013-10-18 17:35:01 -070052 enum_blacklist = set(("OFDefinitions", "OFPortNo", "OFVlanId", "OFGroup"))
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),
Yotam Harchola11f38b2013-09-26 15:38:17 -0700141 "OFOxmMplsTcMasked": OxmMapEntry("U8", "MPLS_TC", True),
Yotam Harchol2c535582013-10-01 15:50:20 -0700142 "OFOxmBsnInPorts128": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", False),
143 "OFOxmBsnInPorts128Masked": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", True)
Yotam Harchola86e4252013-09-06 15:36:28 -0700144 }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700145
Andreas Wundsamf1949682013-09-23 14:48:31 -0700146 # Registry of nullable properties:
147 # ${java_class_name} -> set(${java_property_name})
148 nullable_map = defaultdict(lambda: set(),
149 )
150
151 # represents a subgroup of a bitmask enum that is actualy a normal enumerable within a masked part of the enum
152 # e.g., the flags STP.* in OF1.0 port state are bit mask entries, but instead enumerables according to the mask "STP_MASK"
153 # name: a name for the group
154 # mask: java name of the enum entry that defines the mask
155 # members: set of names of the members of the group
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700156 MaskedEnumGroup = namedtuple("MaskedEnumGroup", ("name", "mask", "members"))
157
Andreas Wundsamf1949682013-09-23 14:48:31 -0700158 # registry of MaskedEnumGroups (see above).
159 # map: ${java_enum_name}: tuple(MaskedEnumGroup)
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700160 masked_enum_groups = defaultdict(lambda: (),
Andreas Wundsamaebe5182013-09-24 13:01:07 -0700161 OFPortState = (MaskedEnumGroup("stp_flags", mask="STP_MASK", members=set(("STP_LISTEN", "STP_LEARN", "STP_FORWARD", "STP_BLOCK"))), ),
162 OFConfigFlags = (
163 MaskedEnumGroup("frag_flags", mask="FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
Andreas Wundsam376cef52013-09-24 13:52:18 -0700164 ),
165 OFTableConfig = (
166 MaskedEnumGroup("table_miss_flags", mask="TABLE_MISS_MASK", members=set(("TABLE_MISS_CONTROLLER", "TABLE_MISS_CONTINUE", "TABLE_MISS_DROP"))),
167 ),
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700168 )
169
Andreas Wundsamf1949682013-09-23 14:48:31 -0700170 # represents a metadata property associated with an EnumClass
171 # name:
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700172 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700173 """
174 represents a metadata property associated with an Enum Class
175 @param name name of metadata property
176 @param type java_type instance describing the type
177 @value: Generator function f(entry) that generates the value
178 """
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700179 @property
180 def variable_name(self):
181 return self.name[0].lower() + self.name[1:]
182
183 @property
184 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700185 prefix = "is" if self.type == java_type.boolean else "get"
186 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700187
Andreas Wundsamf1949682013-09-23 14:48:31 -0700188 """ Metadata container. """
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700189 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
190
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700191 def gen_port_speed(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700192 """ Generator function for OFortFeatures.PortSpeed"""
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700193 splits = enum_entry.name.split("_")
194 if len(splits)>=2:
195 m = re.match(r'\d+[MGTP]B', splits[1])
196 if m:
197 return "PortSpeed.SPEED_{}".format(splits[1])
198 return "PortSpeed.SPEED_NONE";
199
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700200 def gen_stp_state(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700201 """ Generator function for OFPortState.StpState"""
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700202 splits = enum_entry.name.split("_")
203 if len(splits)>=1:
204 if splits[0] == "STP":
205 return "true"
206 return "false"
207
Andreas Wundsamf1949682013-09-23 14:48:31 -0700208 # registry for metadata properties for enums
209 # map: ${java_enum_name}: OFEnumMetadata
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700210 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700211 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
212 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700213 )
214
Andreas Wundsam27303462013-07-16 12:52:35 -0700215 @property
216 @memoize
217 def versions(self):
218 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
219
220 @property
221 @memoize
222 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700223 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700224
225 for raw_version, of_protocol in of_g.ir.items():
226 jversion = JavaOFVersion(of_protocol.wire_version)
227
228 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700229 if not of_class.name in version_map_per_class:
230 version_map_per_class[of_class.name] = collections.OrderedDict()
231
Andreas Wundsam27303462013-07-16 12:52:35 -0700232 version_map_per_class[of_class.name][jversion] = of_class
233
234 interfaces = []
235 for class_name, version_map in version_map_per_class.items():
236 interfaces.append(JavaOFInterface(class_name, version_map))
237
Andreas Wundsambe168f72013-08-03 22:49:35 -0700238 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
239
Andreas Wundsam27303462013-07-16 12:52:35 -0700240 return interfaces
241
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700242 @memoize
243 def interface_by_name(self, name):
244 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
245
Andreas Wundsam27303462013-07-16 12:52:35 -0700246 @property
247 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700248 def all_classes(self):
249 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
250
251 @property
252 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700253 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700254 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700255
256 for version in self.versions:
257 of_protocol = of_g.ir[version.int_version]
258 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700259 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700260
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700261 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
262 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700263
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700264 # inelegant - need java name here
265 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700266 return enums
267
268 @memoize
269 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700270 res = find(lambda e: e.name == name, self.enums)
271 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700272 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700273 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700274
Andreas Wundsam5204de22013-07-30 11:34:45 -0700275 @property
276 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700277 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700278 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700279
280 factories = OrderedDict()
281
282 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
283 for base_class in sub_factory_classes:
284 package = base_class[2:].lower()
285 remove_prefix = base_class[2].lower() + base_class[3:]
286
287 # HACK need to have a better way to deal with parameterized base classes
288 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
289
290 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700291 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={}, xid_generator=False)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700292
293 factories[""] = OFFactory(
294 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700295 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700296 remove_prefix="",
297 members=[], base_class="OFMessage", sub_factories=OrderedDict(
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700298 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ),
299 xid_generator=True)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700300
301 for i in self.interfaces:
302 for n, factory in factories.items():
303 if n == "":
304 factory.members.append(i)
305 break
306 else:
307 super_class = self.interface_by_name(n)
308 if i.is_instance_of(super_class):
309 factory.members.append(i)
310 break
311 return factories.values()
Yotam Harchol595c6442013-09-27 16:29:08 -0700312
313 @memoize
314 def factory_of(self, interface):
315 for factory in self.of_factories:
316 if interface in factory.members:
317 return factory
318 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700319
320 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700321 """ return wether or not to generate implementation class clazz.
322 Now true for everything except OFTableModVer10.
323 @param clazz JavaOFClass instance
324 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700325 if clazz.interface.name.startswith("OFMatchV"):
326 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700327 elif clazz.name == "OFTableModVer10":
328 # tablemod ver 10 is a hack and has no oftype defined
329 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700330 if loxi_utils.class_is_message(clazz.interface.c_name):
331 return True
332 if loxi_utils.class_is_oxm(clazz.interface.c_name):
333 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700334 if loxi_utils.class_is_action(clazz.interface.c_name):
335 return True
336 if loxi_utils.class_is_instruction(clazz.interface.c_name):
337 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700338 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700339 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700340
341
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700342class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories", "xid_generator"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700343 @property
344 def factory_classes(self):
345 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700346 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700347 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700348 interface=self,
349 version=version
350 ) for version in model.versions ]
351
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700352 def method_name(self, member, builder=True):
353 n = member.variable_name
354 if n.startswith(self.remove_prefix):
355 n = n[len(self.remove_prefix):]
356 n = n[0].lower() + n[1:]
357 if builder:
358 return "build" + n[0].upper() + n[1:]
359 else:
360 return n
Yotam Harchol595c6442013-09-27 16:29:08 -0700361
362 def of_version(self, version):
363 for fc in self.factory_classes:
364 if fc.version == version:
365 return fc
366 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700367
368OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700369class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
370 @property
371 def base_class(self):
372 return self.interface.base_class
373
374 @property
375 def versioned_base_class(self):
376 base_class_interface = model.interface_by_name(self.interface.base_class)
377 if base_class_interface and base_class_interface.has_version(self.version):
378 return base_class_interface.versioned_class(self.version)
379 else:
380 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700381
Andreas Wundsam27303462013-07-16 12:52:35 -0700382model = JavaModel()
383
384#######################################################################
385### OFVersion
386#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700387
388class JavaOFVersion(object):
389 """ Models a version of OpenFlow. contains methods to convert the internal
390 Loxi version to a java constant / a string """
391 def __init__(self, int_version):
392 self.int_version = int(int_version)
393
394 @property
395 def of_version(self):
396 return "1" + str(int(self.int_version) - 1)
397
398 @property
399 def constant_version(self):
400 return "OF_" + self.of_version
401
Andreas Wundsam27303462013-07-16 12:52:35 -0700402 def __repr__(self):
403 return "JavaOFVersion(%d)" % self.int_version
404
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700405 def __str__(self):
406 return of_g.param_version_names[self.int_version]
407
Andreas Wundsam27303462013-07-16 12:52:35 -0700408 def __hash__(self):
409 return hash(self.int_version)
410
411 def __eq__(self, other):
412 if other is None or type(self) != type(other):
413 return False
414 return (self.int_version,) == (other.int_version,)
415
416#######################################################################
417### Interface
418#######################################################################
419
420class JavaOFInterface(object):
421 """ Models an OpenFlow Message class for the purpose of the java class.
422 Version agnostic, in contrast to the loxi_ir python model.
423 """
424 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700425 """"
426 @param c_name: loxi style name (e.g., of_flow_add)
427 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
428 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700429 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700430 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700431 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700432 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 -0700433 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700434 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700435 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700436 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700437 self.constant_name = c_name.upper().replace("OF_", "")
438
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700439 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700440 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700441 if self.name != parent_interface:
442 self.parent_interface = parent_interface
443 else:
444 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700445
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700446 @property
447 @memoize
448 def all_parent_interfaces(self):
449 return [ "OFObject" ] + \
450 ([ self.parent_interface ] if self.parent_interface else [] )+ \
451 self.additional_parent_interfaces
452 @property
453 @memoize
454 def additional_parent_interfaces(self):
455 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
456 m = re.match(r'(.*)Request$', self.name)
457 if m:
458 reply_name = m.group(1) + "Reply"
459 if model.interface_by_name(reply_name):
460 return ["OFRequest<%s>" % reply_name ]
461 return []
462
463
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700464 def is_instance_of(self, other_class):
465 if self == other_class:
466 return True
467 parent = self.super_class
468 if parent is None:
469 return False
470 else:
471 return parent.is_instance_of(other_class)
472
473 @property
474 def super_class(self):
475 if not self.parent_interface:
476 return None
477 else:
478 return model.interface_by_name(self.parent_interface)
479
480
481 def inherited_declaration(self, type_spec="?"):
482 if self.type_annotation:
483 return "%s<%s>" % (self.name, type_spec)
484 else:
485 return "%s" % self.name
486
487 @property
488 def type_variable(self):
489 if self.type_annotation:
490 return "<T>"
491 else:
492 return "";
493
Andreas Wundsam27303462013-07-16 12:52:35 -0700494 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700495 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
496 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
497 # model (note, that the loxi model is on versioned classes). Should check/infer the
498 # inheritance information from the versioned lox_ir classes.
Andreas Wundsamd6b0cb02013-09-28 18:55:56 -0700499 if re.match(r'OFStatsRequest$', self.name):
500 return ("", "OFMessage", "T extends OFStatsReply")
501 elif re.match(r'OF.+StatsRequest$', self.name):
502 return ("", "OFStatsRequest<{}>".format(re.sub(r'Request$', 'Reply', self.name)), None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700503 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700504 return ("", "OFStatsReply", None)
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700505 elif re.match(r'OF.+ErrorMsg$', self.name):
506 return ("", "OFErrorMsg", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700507 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700508 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700509 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 -0700510 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700511 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 -0700512 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700513 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
514 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700515 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700516 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700517 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700518 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700519 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700520 if re.match(r'OFActionBsn.+', self.name):
521 return ("action", "OFActionBsn", None)
522 elif re.match(r'OFActionNicira.+', self.name):
523 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700524 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
525 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700526 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700527 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700528 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700529 return ("", "OFBsnVport", None)
530 elif self.name == "OFOxm":
531 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700532 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700533 if self.name in model.oxm_map:
534 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
535 else:
536 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700537 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700538 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700539 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700540 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700541 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700542 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700543 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700544 return ("", "OFHelloElem", None)
Rich Lane26847562013-10-08 13:44:47 -0700545 elif loxi_utils.class_is_table_feature_prop(self.c_name):
546 return ("", "OFTableFeatureProp", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700547 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700548 return ("", None, None)
549
550 @property
551 @memoize
552 def writeable_members(self):
553 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700554
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700555 @memoize
556 def member_by_name(self, name):
557 return find(lambda m: m.name == name, self.members)
558
Andreas Wundsam27303462013-07-16 12:52:35 -0700559 @property
560 @memoize
561 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700562 return self.ir_model_members + self.virtual_members
563
564 @property
565 @memoize
566 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700567 """return a list of all members to be exposed by this interface. Corresponds to
568 the union of the members of the vesioned classes without length, fieldlength
569 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700570 all_versions = []
571 member_map = collections.OrderedDict()
572
573 for (version, of_class) in self.version_map.items():
574 for of_member in of_class.members:
575 if isinstance(of_member, OFLengthMember) or \
576 isinstance(of_member, OFFieldLengthMember) or \
577 isinstance(of_member, OFPadMember):
578 continue
579 if of_member.name not in member_map:
580 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
581
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700582 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 -0700583
584 @property
585 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700586 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700587 if self.name == "OFOxm":
Andreas Wundsama0981022013-10-02 18:15:06 -0700588 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700589 JavaVirtualMember(self, "value", java_type.generic_t),
590 JavaVirtualMember(self, "mask", java_type.generic_t),
591 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
592 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsama0981022013-10-02 18:15:06 -0700593 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700594 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
595 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
596 if self.name in model.oxm_map \
597 else java_type.make_match_field_jtype()
598
Andreas Wundsama0981022013-10-02 18:15:06 -0700599 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700600 JavaVirtualMember(self, "matchField", field_type),
601 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsama0981022013-10-02 18:15:06 -0700602 ]
603 if not find(lambda x: x.name == "mask", self.ir_model_members):
604 virtual_members.append(JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type))
605
606 if not find(lambda m: m.name == "version", self.ir_model_members):
607 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version))
608
609 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700610
611 @property
612 @memoize
613 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700614 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700615 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 -0700616
617 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700618 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700619 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700620 return len(self.all_versions) == len(model.versions)
621
622 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700623 @memoize
624 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700625 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700626 return self.version_map.keys()
627
Andreas Wundsam5204de22013-07-30 11:34:45 -0700628 def has_version(self, version):
629 return version in self.version_map
630
Andreas Wundsam27303462013-07-16 12:52:35 -0700631 def versioned_class(self, version):
632 return JavaOFClass(self, version, self.version_map[version])
633
634 @property
635 @memoize
636 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700637 return [ self.versioned_class(version) for version in self.all_versions ]
638
639#######################################################################
640### (Versioned) Classes
641#######################################################################
642
643class JavaOFClass(object):
644 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700645 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700646 """
647 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700648 """
649 @param interface JavaOFInterface instance of the parent interface
650 @param version JavaOFVersion
651 @param ir_class OFClass from loxi_ir
652 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700653 self.interface = interface
654 self.ir_class = ir_class
655 self.c_name = self.ir_class.name
656 self.version = version
657 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700658 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700659 self.generated = False
660
661 @property
662 @memoize
663 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700664 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700665
666 @property
667 def name(self):
668 return "%sVer%s" % (self.interface.name, self.version.of_version)
669
670 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700671 def variable_name(self):
672 return self.name[3:]
673
674 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700675 def length(self):
676 if self.is_fixed_length:
677 return self.min_length
678 else:
679 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
680
681 @property
682 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700683 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700684 id_tuple = (self.ir_class.name, self.version.int_version)
685 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
686
687 @property
688 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700689 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700690 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
691 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700692
693 def all_properties(self):
694 return self.interface.members
695
696 def get_member(self, name):
697 for m in self.members:
698 if m.name == name:
699 return m
700
701 @property
702 @memoize
703 def data_members(self):
704 return [ prop for prop in self.members if prop.is_data ]
705
706 @property
707 @memoize
708 def fixed_value_members(self):
709 return [ prop for prop in self.members if prop.is_fixed_value ]
710
711 @property
712 @memoize
713 def public_members(self):
714 return [ prop for prop in self.members if prop.is_public ]
715
716 @property
717 @memoize
718 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700719 return self.ir_model_members + self.virtual_members
720
721 @property
Andreas Wundsama0981022013-10-02 18:15:06 -0700722 @memoize
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700723 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700724 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700725 return tuple(members)
726
727 @property
728 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700729 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700730 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
731 if self.interface.name in model.oxm_map:
732 oxm_entry = model.oxm_map[self.interface.name]
Andreas Wundsama0981022013-10-02 18:15:06 -0700733 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700734 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
735 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
Andreas Wundsama0981022013-10-02 18:15:06 -0700736 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700737 else:
Andreas Wundsama0981022013-10-02 18:15:06 -0700738 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700739 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
740 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
Andreas Wundsama0981022013-10-02 18:15:06 -0700741 ]
742
743 if not find(lambda m: m.name == "version", self.ir_model_members):
744 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version, "OFVersion.%s" % self.version.constant_version))
745
746 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700747
748 def all_versions(self):
749 return [ JavaOFVersion(int_version)
750 for int_version in of_g.unified[self.c_name]
751 if int_version != 'union' and int_version != 'object_id' ]
752
753 def version_is_inherited(self, version):
754 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
755
756 def inherited_from(self, version):
757 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
758
759 @property
760 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700761 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
762
763 @property
764 def discriminator(self):
765 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700766
767 @property
768 def is_extension(self):
769 return type_maps.message_is_extension(self.c_name, -1)
770
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700771 @property
772 def align(self):
773 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
774
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700775 @property
776 @memoize
777 def superclass(self):
778 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
779
780 @property
781 @memoize
782 def subclasses(self):
783 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
784
Andreas Wundsam27303462013-07-16 12:52:35 -0700785#######################################################################
786### Member
787#######################################################################
788
789
790class JavaMember(object):
791 """ Models a property (member) of an openflow class. """
792 def __init__(self, msg, name, java_type, member):
793 self.msg = msg
794 self.name = name
795 self.java_type = java_type
796 self.member = member
797 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700798
799 @property
800 def title_name(self):
801 return self.name[0].upper() + self.name[1:]
802
803 @property
804 def constant_name(self):
805 return self.c_name.upper()
806
807 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700808 def getter_name(self):
809 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
810
811 @property
812 def setter_name(self):
813 return "set" + self.title_name
814
815 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700816 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700817 if self.is_fixed_value:
818 return self.constant_name
819 else:
820 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700821
822 @property
823 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700824 if self.is_fixed_value:
825 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700826 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700827 default = self.java_type.default_op(self.msg.version)
828 if default == "null" and not self.is_nullable:
829 return None
830 else:
831 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700832
833 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700834 def enum_value(self):
835 if self.name == "version":
836 return "OFVersion.%s" % self.msg.version.constant_version
837
838 java_type = self.java_type.public_type;
839 try:
840 global model
841 enum = model.enum_by_name(java_type)
842 entry = enum.entry_by_version_value(self.msg.version, self.value)
843 return "%s.%s" % ( enum.name, entry.name)
844 except KeyError, e:
845 print e.message
846 return self.value
847
848 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700849 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700850 return isinstance(self.member, OFPadMember)
851
852 def is_type_value(self, version=None):
853 if(version==None):
854 return any(self.is_type_value(version) for version in self.msg.all_versions)
855 try:
856 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
857 except:
858 return False
859
860 @property
861 def is_field_length_value(self):
862 return isinstance(self.member, OFFieldLengthMember)
863
864 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700865 def is_discriminator(self):
866 return isinstance(self.member, OFDiscriminatorMember)
867
868 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700869 def is_length_value(self):
870 return isinstance(self.member, OFLengthMember)
871
872 @property
873 def is_public(self):
874 return not (self.is_pad or self.is_length_value)
875
876 @property
877 def is_data(self):
878 return isinstance(self.member, OFDataMember) and self.name != "version"
879
880 @property
881 def is_fixed_value(self):
882 return hasattr(self.member, "value") or self.name == "version" \
883 or ( self.name == "length" and self.msg.is_fixed_length) \
884 or ( self.name == "len" and self.msg.is_fixed_length)
885
886 @property
887 def value(self):
888 if self.name == "version":
889 return self.msg.version.int_version
890 elif self.name == "length" or self.name == "len":
891 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700892 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700893 return self.java_type.format_value(self.member.value)
894
895 @property
896 def priv_value(self):
897 if self.name == "version":
898 return self.msg.version.int_version
899 elif self.name == "length" or self.name == "len":
900 return self.msg.length
901 else:
902 return self.java_type.format_value(self.member.value, pub_type=False)
903
Andreas Wundsam27303462013-07-16 12:52:35 -0700904
905 @property
906 def is_writeable(self):
907 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
908
909 def get_type_value_info(self, version):
910 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700911
912 @property
913 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700914 if hasattr(self.member, "length"):
915 return self.member.length
916 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700917 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700918 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700919
920 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700921 def for_of_member(java_class, member):
922 if isinstance(member, OFPadMember):
923 return JavaMember(None, "", None, member)
924 else:
925 if member.name == 'len':
926 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700927 elif member.name == 'value_mask':
928 name = 'mask'
Andreas Wundsamacd57d52013-10-18 17:35:01 -0700929 elif member.name == 'group_id':
930 name = 'group'
Andreas Wundsam27303462013-07-16 12:52:35 -0700931 else:
932 name = java_type.name_c_to_camel(member.name)
933 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
934 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700935
936 @property
937 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700938 if not self.msg.c_name in of_g.unified:
939 print("%s not self.unified" % self.msg.c_name)
940 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700941 for version in of_g.unified[self.msg.c_name]:
942 if version == 'union' or version =='object_id':
943 continue
944 if 'use_version' in of_g.unified[self.msg.c_name][version]:
945 continue
946
Andreas Wundsam27303462013-07-16 12:52:35 -0700947 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 -0700948 return False
949 return True
950
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700951 @property
952 def is_virtual(self):
953 return False
954
Andreas Wundsam27303462013-07-16 12:52:35 -0700955 def __hash__(self):
956 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700957
Andreas Wundsam27303462013-07-16 12:52:35 -0700958 def __eq__(self, other):
959 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700960 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700961 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700962
Andreas Wundsamf1949682013-09-23 14:48:31 -0700963 @property
964 def is_nullable(self):
965 return self.name in model.nullable_map[self.msg.name]
966
967
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700968class JavaVirtualMember(JavaMember):
969 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
970 def __init__(self, msg, name, java_type, value=None):
971 JavaMember.__init__(self, msg, name, java_type, member=None)
972 self._value = value
973
974 @property
975 def is_fixed_value(self):
976 return True
977
978 @property
979 def value(self):
980 return self._value
981
982 @property
983 def priv_value(self):
984 return self._value
985
986
987 @property
988 def is_universal(self):
989 return True
990
991 @property
992 def is_virtual(self):
993 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700994
995#######################################################################
996### Unit Test
997#######################################################################
998
Yotam Harchol466b3212013-08-15 12:14:46 -0700999class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001000 def __init__(self, java_class):
1001 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -07001002 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001003 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -07001004 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
1005 name=java_class.c_name[3:]) + "{i}.data"
1006 test_class_name = self.java_class.name + "Test"
1007 self.test_units = []
1008 if test_data.exists(first_data_file_name):
1009 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
1010 i = 1
1011 while test_data.exists(data_file_template.format(i=i)):
1012 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
1013 i = i + 1
Andreas Wundsamf1949682013-09-23 14:48:31 -07001014
Yotam Harchol466b3212013-08-15 12:14:46 -07001015 @property
1016 def package(self):
1017 return self.java_class.package
1018
1019 @property
1020 def has_test_data(self):
1021 return len(self.test_units) > 0
1022
1023 @property
1024 def length(self):
1025 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -07001026
Yotam Harchol466b3212013-08-15 12:14:46 -07001027 def get_test_unit(self, i):
1028 return self.test_units[i]
1029
1030
1031class JavaUnitTest(object):
1032 def __init__(self, java_class, file_name=None, test_class_name=None):
1033 self.java_class = java_class
1034 if file_name is None:
1035 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
1036 name=java_class.c_name[3:])
1037 else:
1038 self.data_file_name = file_name
1039 if test_class_name is None:
1040 self.test_class_name = self.java_class.name + "Test"
1041 else:
1042 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001043
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001044 @property
1045 def package(self):
1046 return self.java_class.package
1047
1048 @property
1049 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001050 return self.test_class_name
Yotam Harchol595c6442013-09-27 16:29:08 -07001051
1052 @property
1053 def interface(self):
1054 return self.java_class.interface
1055
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001056 @property
1057 def has_test_data(self):
1058 return test_data.exists(self.data_file_name)
1059
1060 @property
1061 @memoize
1062 def test_data(self):
1063 return test_data.read(self.data_file_name)
1064
1065
Andreas Wundsam27303462013-07-16 12:52:35 -07001066#######################################################################
1067### Enums
1068#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001069
Andreas Wundsam27303462013-07-16 12:52:35 -07001070class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001071 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001072 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001073
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001074 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001075
Andreas Wundsam27303462013-07-16 12:52:35 -07001076 # Port_features has constants that start with digits
1077 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001078
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001079 self.version_enums = version_enum_map
1080
1081 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1082 for version, ir_enum in version_enum_map.items():
1083 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001084 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1085
Andreas Wundsam27303462013-07-16 12:52:35 -07001086 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001087 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001088
1089 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 -07001090 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001091
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001092 self.metadata = model.enum_metadata_map[self.name]
1093
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001094 def wire_type(self, version):
1095 ir_enum = self.version_enums[version]
1096 if "wire_type" in ir_enum.params:
1097 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1098 else:
1099 return java_type.u8
1100
1101 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001102 @memoize
1103 def is_bitmask(self):
1104 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1105
1106 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001107 def versions(self):
1108 return self.version_enums.keys()
1109
Andreas Wundsam27303462013-07-16 12:52:35 -07001110 @memoize
1111 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001112 res = find(lambda e: e.name == name, self.entries)
1113 if res:
1114 return res
1115 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001116 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1117
1118 @memoize
1119 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001120 res = find(lambda e: e.c_name == name, self.entries)
1121 if res:
1122 return res
1123 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001124 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1125
1126 @memoize
1127 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001128 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1129 if res:
1130 return res
1131 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001132 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1133
1134# values: Map JavaVersion->Value
1135class JavaEnumEntry(object):
1136 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001137 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001138 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1139 self.values = values
1140
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001141 @property
1142 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001143 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001144
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001145 def has_value(self, version):
1146 return version in self.values
1147
Andreas Wundsam27303462013-07-16 12:52:35 -07001148 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001149 return self.values[version]
1150
1151 def format_value(self, version):
1152 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001153 return res
1154
Andreas Wundsam27303462013-07-16 12:52:35 -07001155 def all_values(self, versions, not_present=None):
1156 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001157
1158 @property
1159 @memoize
1160 def masked_enum_group(self):
1161 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1162 return group
1163
1164 @property
1165 @memoize
1166 def is_mask(self):
1167 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])