blob: 19ac5bc07e0485972818d8c8955fb4a011de44f1 [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 Wundsam55b71ce2013-10-01 19:26:46 -070052 enum_blacklist = set(("OFDefinitions", "OFPortNo", "OFVlanId"))
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)
Andreas Wundsam27303462013-07-16 12:52:35 -0700545 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700546 return ("", None, None)
547
548 @property
549 @memoize
550 def writeable_members(self):
551 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700552
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700553 @memoize
554 def member_by_name(self, name):
555 return find(lambda m: m.name == name, self.members)
556
Andreas Wundsam27303462013-07-16 12:52:35 -0700557 @property
558 @memoize
559 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700560 return self.ir_model_members + self.virtual_members
561
562 @property
563 @memoize
564 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700565 """return a list of all members to be exposed by this interface. Corresponds to
566 the union of the members of the vesioned classes without length, fieldlength
567 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700568 all_versions = []
569 member_map = collections.OrderedDict()
570
571 for (version, of_class) in self.version_map.items():
572 for of_member in of_class.members:
573 if isinstance(of_member, OFLengthMember) or \
574 isinstance(of_member, OFFieldLengthMember) or \
575 isinstance(of_member, OFPadMember):
576 continue
577 if of_member.name not in member_map:
578 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
579
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700580 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 -0700581
582 @property
583 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700584 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700585 if self.name == "OFOxm":
Andreas Wundsama0981022013-10-02 18:15:06 -0700586 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700587 JavaVirtualMember(self, "value", java_type.generic_t),
588 JavaVirtualMember(self, "mask", java_type.generic_t),
589 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
590 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsama0981022013-10-02 18:15:06 -0700591 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700592 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
593 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
594 if self.name in model.oxm_map \
595 else java_type.make_match_field_jtype()
596
Andreas Wundsama0981022013-10-02 18:15:06 -0700597 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700598 JavaVirtualMember(self, "matchField", field_type),
599 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsama0981022013-10-02 18:15:06 -0700600 ]
601 if not find(lambda x: x.name == "mask", self.ir_model_members):
602 virtual_members.append(JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type))
603
604 if not find(lambda m: m.name == "version", self.ir_model_members):
605 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version))
606
607 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700608
609 @property
610 @memoize
611 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700612 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700613 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 -0700614
615 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700616 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700617 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700618 return len(self.all_versions) == len(model.versions)
619
620 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700621 @memoize
622 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700623 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700624 return self.version_map.keys()
625
Andreas Wundsam5204de22013-07-30 11:34:45 -0700626 def has_version(self, version):
627 return version in self.version_map
628
Andreas Wundsam27303462013-07-16 12:52:35 -0700629 def versioned_class(self, version):
630 return JavaOFClass(self, version, self.version_map[version])
631
632 @property
633 @memoize
634 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700635 return [ self.versioned_class(version) for version in self.all_versions ]
636
637#######################################################################
638### (Versioned) Classes
639#######################################################################
640
641class JavaOFClass(object):
642 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700643 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700644 """
645 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700646 """
647 @param interface JavaOFInterface instance of the parent interface
648 @param version JavaOFVersion
649 @param ir_class OFClass from loxi_ir
650 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700651 self.interface = interface
652 self.ir_class = ir_class
653 self.c_name = self.ir_class.name
654 self.version = version
655 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700656 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700657 self.generated = False
658
659 @property
660 @memoize
661 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700662 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700663
664 @property
665 def name(self):
666 return "%sVer%s" % (self.interface.name, self.version.of_version)
667
668 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700669 def variable_name(self):
670 return self.name[3:]
671
672 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700673 def length(self):
674 if self.is_fixed_length:
675 return self.min_length
676 else:
677 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
678
679 @property
680 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700681 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700682 id_tuple = (self.ir_class.name, self.version.int_version)
683 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
684
685 @property
686 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700687 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700688 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
689 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700690
691 def all_properties(self):
692 return self.interface.members
693
694 def get_member(self, name):
695 for m in self.members:
696 if m.name == name:
697 return m
698
699 @property
700 @memoize
701 def data_members(self):
702 return [ prop for prop in self.members if prop.is_data ]
703
704 @property
705 @memoize
706 def fixed_value_members(self):
707 return [ prop for prop in self.members if prop.is_fixed_value ]
708
709 @property
710 @memoize
711 def public_members(self):
712 return [ prop for prop in self.members if prop.is_public ]
713
714 @property
715 @memoize
716 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700717 return self.ir_model_members + self.virtual_members
718
719 @property
Andreas Wundsama0981022013-10-02 18:15:06 -0700720 @memoize
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700721 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700722 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700723 return tuple(members)
724
725 @property
726 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700727 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700728 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
729 if self.interface.name in model.oxm_map:
730 oxm_entry = model.oxm_map[self.interface.name]
Andreas Wundsama0981022013-10-02 18:15:06 -0700731 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700732 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
733 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
Andreas Wundsama0981022013-10-02 18:15:06 -0700734 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700735 else:
Andreas Wundsama0981022013-10-02 18:15:06 -0700736 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700737 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
738 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
Andreas Wundsama0981022013-10-02 18:15:06 -0700739 ]
740
741 if not find(lambda m: m.name == "version", self.ir_model_members):
742 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version, "OFVersion.%s" % self.version.constant_version))
743
744 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700745
746 def all_versions(self):
747 return [ JavaOFVersion(int_version)
748 for int_version in of_g.unified[self.c_name]
749 if int_version != 'union' and int_version != 'object_id' ]
750
751 def version_is_inherited(self, version):
752 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
753
754 def inherited_from(self, version):
755 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
756
757 @property
758 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700759 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
760
761 @property
762 def discriminator(self):
763 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700764
765 @property
766 def is_extension(self):
767 return type_maps.message_is_extension(self.c_name, -1)
768
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700769 @property
770 def align(self):
771 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
772
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700773 @property
774 @memoize
775 def superclass(self):
776 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
777
778 @property
779 @memoize
780 def subclasses(self):
781 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
782
Andreas Wundsam27303462013-07-16 12:52:35 -0700783#######################################################################
784### Member
785#######################################################################
786
787
788class JavaMember(object):
789 """ Models a property (member) of an openflow class. """
790 def __init__(self, msg, name, java_type, member):
791 self.msg = msg
792 self.name = name
793 self.java_type = java_type
794 self.member = member
795 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700796
797 @property
798 def title_name(self):
799 return self.name[0].upper() + self.name[1:]
800
801 @property
802 def constant_name(self):
803 return self.c_name.upper()
804
805 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700806 def getter_name(self):
807 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
808
809 @property
810 def setter_name(self):
811 return "set" + self.title_name
812
813 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700814 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700815 if self.is_fixed_value:
816 return self.constant_name
817 else:
818 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700819
820 @property
821 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700822 if self.is_fixed_value:
823 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700824 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700825 default = self.java_type.default_op(self.msg.version)
826 if default == "null" and not self.is_nullable:
827 return None
828 else:
829 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700830
831 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700832 def enum_value(self):
833 if self.name == "version":
834 return "OFVersion.%s" % self.msg.version.constant_version
835
836 java_type = self.java_type.public_type;
837 try:
838 global model
839 enum = model.enum_by_name(java_type)
840 entry = enum.entry_by_version_value(self.msg.version, self.value)
841 return "%s.%s" % ( enum.name, entry.name)
842 except KeyError, e:
843 print e.message
844 return self.value
845
846 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700847 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700848 return isinstance(self.member, OFPadMember)
849
850 def is_type_value(self, version=None):
851 if(version==None):
852 return any(self.is_type_value(version) for version in self.msg.all_versions)
853 try:
854 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
855 except:
856 return False
857
858 @property
859 def is_field_length_value(self):
860 return isinstance(self.member, OFFieldLengthMember)
861
862 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700863 def is_discriminator(self):
864 return isinstance(self.member, OFDiscriminatorMember)
865
866 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700867 def is_length_value(self):
868 return isinstance(self.member, OFLengthMember)
869
870 @property
871 def is_public(self):
872 return not (self.is_pad or self.is_length_value)
873
874 @property
875 def is_data(self):
876 return isinstance(self.member, OFDataMember) and self.name != "version"
877
878 @property
879 def is_fixed_value(self):
880 return hasattr(self.member, "value") or self.name == "version" \
881 or ( self.name == "length" and self.msg.is_fixed_length) \
882 or ( self.name == "len" and self.msg.is_fixed_length)
883
884 @property
885 def value(self):
886 if self.name == "version":
887 return self.msg.version.int_version
888 elif self.name == "length" or self.name == "len":
889 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700890 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700891 return self.java_type.format_value(self.member.value)
892
893 @property
894 def priv_value(self):
895 if self.name == "version":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700896 return self.java_type.format_value(self.msg.version.int_version, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700897 elif self.name == "length" or self.name == "len":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700898 return self.java_type.format_value(self.msg.length, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700899 else:
900 return self.java_type.format_value(self.member.value, pub_type=False)
901
Andreas Wundsam27303462013-07-16 12:52:35 -0700902
903 @property
904 def is_writeable(self):
905 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
906
907 def get_type_value_info(self, version):
908 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700909
910 @property
911 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700912 if hasattr(self.member, "length"):
913 return self.member.length
914 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700915 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700916 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700917
918 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700919 def for_of_member(java_class, member):
920 if isinstance(member, OFPadMember):
921 return JavaMember(None, "", None, member)
922 else:
923 if member.name == 'len':
924 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700925 elif member.name == 'value_mask':
926 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700927 else:
928 name = java_type.name_c_to_camel(member.name)
929 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
930 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700931
932 @property
933 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700934 if not self.msg.c_name in of_g.unified:
935 print("%s not self.unified" % self.msg.c_name)
936 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700937 for version in of_g.unified[self.msg.c_name]:
938 if version == 'union' or version =='object_id':
939 continue
940 if 'use_version' in of_g.unified[self.msg.c_name][version]:
941 continue
942
Andreas Wundsam27303462013-07-16 12:52:35 -0700943 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 -0700944 return False
945 return True
946
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700947 @property
948 def is_virtual(self):
949 return False
950
Andreas Wundsam27303462013-07-16 12:52:35 -0700951 def __hash__(self):
952 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700953
Andreas Wundsam27303462013-07-16 12:52:35 -0700954 def __eq__(self, other):
955 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700956 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700957 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700958
Andreas Wundsamf1949682013-09-23 14:48:31 -0700959 @property
960 def is_nullable(self):
961 return self.name in model.nullable_map[self.msg.name]
962
963
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700964class JavaVirtualMember(JavaMember):
965 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
966 def __init__(self, msg, name, java_type, value=None):
967 JavaMember.__init__(self, msg, name, java_type, member=None)
968 self._value = value
969
970 @property
971 def is_fixed_value(self):
972 return True
973
974 @property
975 def value(self):
976 return self._value
977
978 @property
979 def priv_value(self):
980 return self._value
981
982
983 @property
984 def is_universal(self):
985 return True
986
987 @property
988 def is_virtual(self):
989 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700990
991#######################################################################
992### Unit Test
993#######################################################################
994
Yotam Harchol466b3212013-08-15 12:14:46 -0700995class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700996 def __init__(self, java_class):
997 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700998 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700999 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -07001000 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
1001 name=java_class.c_name[3:]) + "{i}.data"
1002 test_class_name = self.java_class.name + "Test"
1003 self.test_units = []
1004 if test_data.exists(first_data_file_name):
1005 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
1006 i = 1
1007 while test_data.exists(data_file_template.format(i=i)):
1008 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
1009 i = i + 1
Andreas Wundsamf1949682013-09-23 14:48:31 -07001010
Yotam Harchol466b3212013-08-15 12:14:46 -07001011 @property
1012 def package(self):
1013 return self.java_class.package
1014
1015 @property
1016 def has_test_data(self):
1017 return len(self.test_units) > 0
1018
1019 @property
1020 def length(self):
1021 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -07001022
Yotam Harchol466b3212013-08-15 12:14:46 -07001023 def get_test_unit(self, i):
1024 return self.test_units[i]
1025
1026
1027class JavaUnitTest(object):
1028 def __init__(self, java_class, file_name=None, test_class_name=None):
1029 self.java_class = java_class
1030 if file_name is None:
1031 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
1032 name=java_class.c_name[3:])
1033 else:
1034 self.data_file_name = file_name
1035 if test_class_name is None:
1036 self.test_class_name = self.java_class.name + "Test"
1037 else:
1038 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001039
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001040 @property
1041 def package(self):
1042 return self.java_class.package
1043
1044 @property
1045 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001046 return self.test_class_name
Yotam Harchol595c6442013-09-27 16:29:08 -07001047
1048 @property
1049 def interface(self):
1050 return self.java_class.interface
1051
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001052 @property
1053 def has_test_data(self):
1054 return test_data.exists(self.data_file_name)
1055
1056 @property
1057 @memoize
1058 def test_data(self):
1059 return test_data.read(self.data_file_name)
1060
1061
Andreas Wundsam27303462013-07-16 12:52:35 -07001062#######################################################################
1063### Enums
1064#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001065
Andreas Wundsam27303462013-07-16 12:52:35 -07001066class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001067 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001068 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001069
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001070 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001071
Andreas Wundsam27303462013-07-16 12:52:35 -07001072 # Port_features has constants that start with digits
1073 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001074
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001075 self.version_enums = version_enum_map
1076
1077 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1078 for version, ir_enum in version_enum_map.items():
1079 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001080 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1081
Andreas Wundsam27303462013-07-16 12:52:35 -07001082 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001083 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001084
1085 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 -07001086 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001087
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001088 self.metadata = model.enum_metadata_map[self.name]
1089
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001090 def wire_type(self, version):
1091 ir_enum = self.version_enums[version]
1092 if "wire_type" in ir_enum.params:
1093 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1094 else:
1095 return java_type.u8
1096
1097 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001098 @memoize
1099 def is_bitmask(self):
1100 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1101
1102 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001103 def versions(self):
1104 return self.version_enums.keys()
1105
Andreas Wundsam27303462013-07-16 12:52:35 -07001106 @memoize
1107 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001108 res = find(lambda e: e.name == name, self.entries)
1109 if res:
1110 return res
1111 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001112 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1113
1114 @memoize
1115 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001116 res = find(lambda e: e.c_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 c_name %s" % (self.name, name))
1121
1122 @memoize
1123 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001124 res = find(lambda e: e.values[version] == value if version in e.values else False, 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 version %s, value %s" % (self.name, version, value))
1129
1130# values: Map JavaVersion->Value
1131class JavaEnumEntry(object):
1132 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001133 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001134 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1135 self.values = values
1136
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001137 @property
1138 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001139 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001140
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001141 def has_value(self, version):
1142 return version in self.values
1143
Andreas Wundsam27303462013-07-16 12:52:35 -07001144 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001145 return self.values[version]
1146
1147 def format_value(self, version):
1148 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001149 return res
1150
Andreas Wundsam27303462013-07-16 12:52:35 -07001151 def all_values(self, versions, not_present=None):
1152 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001153
1154 @property
1155 @memoize
1156 def masked_enum_group(self):
1157 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1158 return group
1159
1160 @property
1161 @memoize
1162 def is_mask(self):
1163 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])