blob: 9f2bdc943dd4d42cf57409a517f6c5d087587651 [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
Andreas Wundsam5da68512013-10-22 22:18:00 -0700776 def length_includes_align(self):
777 return self.ir_class.params['length_includes_align'] == "True" if 'length_includes_align' in self.ir_class.params else False
778
779 @property
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700780 @memoize
781 def superclass(self):
782 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
783
784 @property
785 @memoize
786 def subclasses(self):
787 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
788
Andreas Wundsam27303462013-07-16 12:52:35 -0700789#######################################################################
790### Member
791#######################################################################
792
793
794class JavaMember(object):
795 """ Models a property (member) of an openflow class. """
796 def __init__(self, msg, name, java_type, member):
797 self.msg = msg
798 self.name = name
799 self.java_type = java_type
800 self.member = member
801 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700802
803 @property
804 def title_name(self):
805 return self.name[0].upper() + self.name[1:]
806
807 @property
808 def constant_name(self):
809 return self.c_name.upper()
810
811 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700812 def getter_name(self):
813 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
814
815 @property
816 def setter_name(self):
817 return "set" + self.title_name
818
819 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700820 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700821 if self.is_fixed_value:
822 return self.constant_name
823 else:
824 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700825
826 @property
827 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700828 if self.is_fixed_value:
829 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700830 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700831 default = self.java_type.default_op(self.msg.version)
832 if default == "null" and not self.is_nullable:
833 return None
834 else:
835 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700836
837 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700838 def enum_value(self):
839 if self.name == "version":
840 return "OFVersion.%s" % self.msg.version.constant_version
841
842 java_type = self.java_type.public_type;
843 try:
844 global model
845 enum = model.enum_by_name(java_type)
846 entry = enum.entry_by_version_value(self.msg.version, self.value)
847 return "%s.%s" % ( enum.name, entry.name)
848 except KeyError, e:
849 print e.message
850 return self.value
851
852 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700853 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700854 return isinstance(self.member, OFPadMember)
855
856 def is_type_value(self, version=None):
857 if(version==None):
858 return any(self.is_type_value(version) for version in self.msg.all_versions)
859 try:
860 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
861 except:
862 return False
863
864 @property
865 def is_field_length_value(self):
866 return isinstance(self.member, OFFieldLengthMember)
867
868 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700869 def is_discriminator(self):
870 return isinstance(self.member, OFDiscriminatorMember)
871
872 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700873 def is_length_value(self):
874 return isinstance(self.member, OFLengthMember)
875
876 @property
877 def is_public(self):
878 return not (self.is_pad or self.is_length_value)
879
880 @property
881 def is_data(self):
882 return isinstance(self.member, OFDataMember) and self.name != "version"
883
884 @property
885 def is_fixed_value(self):
886 return hasattr(self.member, "value") or self.name == "version" \
887 or ( self.name == "length" and self.msg.is_fixed_length) \
888 or ( self.name == "len" and self.msg.is_fixed_length)
889
890 @property
891 def value(self):
892 if self.name == "version":
893 return self.msg.version.int_version
894 elif self.name == "length" or self.name == "len":
895 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700896 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700897 return self.java_type.format_value(self.member.value)
898
899 @property
900 def priv_value(self):
901 if self.name == "version":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700902 return self.java_type.format_value(self.msg.version.int_version, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700903 elif self.name == "length" or self.name == "len":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700904 return self.java_type.format_value(self.msg.length, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700905 else:
906 return self.java_type.format_value(self.member.value, pub_type=False)
907
Andreas Wundsam27303462013-07-16 12:52:35 -0700908
909 @property
910 def is_writeable(self):
911 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
912
913 def get_type_value_info(self, version):
914 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700915
916 @property
917 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700918 if hasattr(self.member, "length"):
919 return self.member.length
920 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700921 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700922 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700923
924 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700925 def for_of_member(java_class, member):
926 if isinstance(member, OFPadMember):
927 return JavaMember(None, "", None, member)
928 else:
929 if member.name == 'len':
930 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700931 elif member.name == 'value_mask':
932 name = 'mask'
Andreas Wundsamacd57d52013-10-18 17:35:01 -0700933 elif member.name == 'group_id':
934 name = 'group'
Andreas Wundsam27303462013-07-16 12:52:35 -0700935 else:
936 name = java_type.name_c_to_camel(member.name)
937 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
938 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700939
940 @property
941 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700942 if not self.msg.c_name in of_g.unified:
943 print("%s not self.unified" % self.msg.c_name)
944 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700945 for version in of_g.unified[self.msg.c_name]:
946 if version == 'union' or version =='object_id':
947 continue
948 if 'use_version' in of_g.unified[self.msg.c_name][version]:
949 continue
950
Andreas Wundsam27303462013-07-16 12:52:35 -0700951 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 -0700952 return False
953 return True
954
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700955 @property
956 def is_virtual(self):
957 return False
958
Andreas Wundsam27303462013-07-16 12:52:35 -0700959 def __hash__(self):
960 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700961
Andreas Wundsam27303462013-07-16 12:52:35 -0700962 def __eq__(self, other):
963 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700964 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700965 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700966
Andreas Wundsamf1949682013-09-23 14:48:31 -0700967 @property
968 def is_nullable(self):
969 return self.name in model.nullable_map[self.msg.name]
970
971
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700972class JavaVirtualMember(JavaMember):
973 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
974 def __init__(self, msg, name, java_type, value=None):
975 JavaMember.__init__(self, msg, name, java_type, member=None)
976 self._value = value
977
978 @property
979 def is_fixed_value(self):
980 return True
981
982 @property
983 def value(self):
984 return self._value
985
986 @property
987 def priv_value(self):
988 return self._value
989
990
991 @property
992 def is_universal(self):
993 return True
994
995 @property
996 def is_virtual(self):
997 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700998
999#######################################################################
1000### Unit Test
1001#######################################################################
1002
Yotam Harchol466b3212013-08-15 12:14:46 -07001003class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001004 def __init__(self, java_class):
1005 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -07001006 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001007 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -07001008 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
1009 name=java_class.c_name[3:]) + "{i}.data"
1010 test_class_name = self.java_class.name + "Test"
1011 self.test_units = []
1012 if test_data.exists(first_data_file_name):
1013 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
1014 i = 1
1015 while test_data.exists(data_file_template.format(i=i)):
1016 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
1017 i = i + 1
Andreas Wundsamf1949682013-09-23 14:48:31 -07001018
Yotam Harchol466b3212013-08-15 12:14:46 -07001019 @property
1020 def package(self):
1021 return self.java_class.package
1022
1023 @property
1024 def has_test_data(self):
1025 return len(self.test_units) > 0
1026
1027 @property
1028 def length(self):
1029 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -07001030
Yotam Harchol466b3212013-08-15 12:14:46 -07001031 def get_test_unit(self, i):
1032 return self.test_units[i]
1033
1034
1035class JavaUnitTest(object):
1036 def __init__(self, java_class, file_name=None, test_class_name=None):
1037 self.java_class = java_class
1038 if file_name is None:
1039 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
1040 name=java_class.c_name[3:])
1041 else:
1042 self.data_file_name = file_name
1043 if test_class_name is None:
1044 self.test_class_name = self.java_class.name + "Test"
1045 else:
1046 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001047
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001048 @property
1049 def package(self):
1050 return self.java_class.package
1051
1052 @property
1053 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001054 return self.test_class_name
Yotam Harchol595c6442013-09-27 16:29:08 -07001055
1056 @property
1057 def interface(self):
1058 return self.java_class.interface
1059
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001060 @property
1061 def has_test_data(self):
1062 return test_data.exists(self.data_file_name)
1063
1064 @property
1065 @memoize
1066 def test_data(self):
1067 return test_data.read(self.data_file_name)
1068
1069
Andreas Wundsam27303462013-07-16 12:52:35 -07001070#######################################################################
1071### Enums
1072#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001073
Andreas Wundsam27303462013-07-16 12:52:35 -07001074class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001075 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001076 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001077
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001078 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001079
Andreas Wundsam27303462013-07-16 12:52:35 -07001080 # Port_features has constants that start with digits
1081 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001082
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001083 self.version_enums = version_enum_map
1084
1085 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1086 for version, ir_enum in version_enum_map.items():
1087 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001088 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1089
Andreas Wundsam27303462013-07-16 12:52:35 -07001090 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001091 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001092
1093 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 -07001094 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001095
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001096 self.metadata = model.enum_metadata_map[self.name]
1097
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001098 def wire_type(self, version):
1099 ir_enum = self.version_enums[version]
1100 if "wire_type" in ir_enum.params:
1101 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1102 else:
1103 return java_type.u8
1104
1105 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001106 @memoize
1107 def is_bitmask(self):
1108 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1109
1110 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001111 def versions(self):
1112 return self.version_enums.keys()
1113
Andreas Wundsam27303462013-07-16 12:52:35 -07001114 @memoize
1115 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001116 res = find(lambda e: e.name == name, self.entries)
1117 if res:
1118 return res
1119 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001120 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1121
1122 @memoize
1123 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001124 res = find(lambda e: e.c_name == name, self.entries)
1125 if res:
1126 return res
1127 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001128 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1129
1130 @memoize
1131 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001132 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1133 if res:
1134 return res
1135 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001136 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1137
1138# values: Map JavaVersion->Value
1139class JavaEnumEntry(object):
1140 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001141 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001142 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1143 self.values = values
1144
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001145 @property
1146 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001147 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001148
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001149 def has_value(self, version):
1150 return version in self.values
1151
Andreas Wundsam27303462013-07-16 12:52:35 -07001152 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001153 return self.values[version]
1154
1155 def format_value(self, version):
1156 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001157 return res
1158
Andreas Wundsam27303462013-07-16 12:52:35 -07001159 def all_values(self, versions, not_present=None):
1160 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001161
1162 @property
1163 @memoize
1164 def masked_enum_group(self):
1165 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1166 return group
1167
1168 @property
1169 @memoize
1170 def is_mask(self):
1171 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])