blob: 4d84e11d7649e07e33cca61277c51a438ca7d0ab [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 Wundsam43526532013-08-01 22:03:50 -070050 enum_blacklist = set(("OFDefinitions",))
51 enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
Andreas Wundsambe168f72013-08-03 22:49:35 -070052 # OFUint structs are there for god-knows what in loci. We certainly don't need them.
53 interface_blacklist = set( ("OFUint8", "OFUint32",))
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070054 read_blacklist = defaultdict(lambda: set(), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
55 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 Wundsam001b1822013-08-02 22:25:55 -070056 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070057
Andreas Wundsam2be7da52013-08-22 07:34:25 -070058 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
Yotam Harchole5d92972013-08-22 14:18:36 -070059 oxm_map = { "OFOxmInPort": OxmMapEntry("OFPort", "IN_PORT", False),
60 "OFOxmInPortMasked": OxmMapEntry("OFPort", "IN_PORT", True),
61 "OFOxmInPhyPort": OxmMapEntry("OFPort", "IN_PHY_PORT", False),
62 "OFOxmInPhyPortMasked": OxmMapEntry("OFPort", "IN_PHY_PORT", True),
63 "OFOxmMetadata": OxmMapEntry("OFMetadata", "METADATA", False),
64 "OFOxmMetadataMasked": OxmMapEntry("OFMetadata", "METADATA", True),
65 "OFOxmEthDst": OxmMapEntry("MacAddress", "ETH_DST", False),
66 "OFOxmEthDstMasked": OxmMapEntry("MacAddress", "ETH_DST", True),
67 "OFOxmEthSrc": OxmMapEntry("MacAddress", "ETH_SRC", False),
68 "OFOxmEthSrcMasked": OxmMapEntry("MacAddress", "ETH_SRC", True),
69 "OFOxmEthType": OxmMapEntry("EthType", "ETH_TYPE", False),
70 "OFOxmEthTypeMasked": OxmMapEntry("EthType", "ETH_TYPE", True),
71 "OFOxmVlanVid": OxmMapEntry("VlanVid", "VLAN_VID", False),
72 "OFOxmVlanVidMasked": OxmMapEntry("VlanVid", "VLAN_VID", True),
73 "OFOxmVlanPcp": OxmMapEntry("VlanPcp", "VLAN_PCP", False),
74 "OFOxmVlanPcpMasked": OxmMapEntry("VlanPcp", "VLAN_PCP", True),
75 "OFOxmIpDscp": OxmMapEntry("IpDscp", "IP_DSCP", False),
76 "OFOxmIpDscpMasked": OxmMapEntry("IpDscp", "IP_DSCP", True),
77 "OFOxmIpEcn": OxmMapEntry("IpEcn", "IP_ECN", False),
78 "OFOxmIpEcnMasked": OxmMapEntry("IpEcn", "IP_ECN", True),
79 "OFOxmIpProto": OxmMapEntry("IpProtocol", "IP_PROTO", False),
80 "OFOxmIpProtoMasked": OxmMapEntry("IpProtocol", "IP_PROTO", True),
Yotam Harchola289d552013-09-16 10:10:40 -070081 "OFOxmIpv4Src": OxmMapEntry("IPv4Address", "IPV4_SRC", False),
82 "OFOxmIpv4SrcMasked": OxmMapEntry("IPv4Address", "IPV4_SRC", True),
83 "OFOxmIpv4Dst": OxmMapEntry("IPv4Address", "IPV4_DST", False),
84 "OFOxmIpv4DstMasked": OxmMapEntry("IPv4Address", "IPV4_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -070085 "OFOxmTcpSrc": OxmMapEntry("TransportPort", "TCP_SRC", False),
86 "OFOxmTcpSrcMasked": OxmMapEntry("TransportPort", "TCP_SRC", True),
87 "OFOxmTcpDst": OxmMapEntry("TransportPort", "TCP_DST", False),
88 "OFOxmTcpDstMasked": OxmMapEntry("TransportPort", "TCP_DST", True),
89 "OFOxmUdpSrc": OxmMapEntry("TransportPort", "UDP_SRC", False),
90 "OFOxmUdpSrcMasked": OxmMapEntry("TransportPort", "UDP_SRC", True),
91 "OFOxmUdpDst": OxmMapEntry("TransportPort", "UDP_DST", False),
92 "OFOxmUdpDstMasked": OxmMapEntry("TransportPort", "UDP_DST", True),
93 "OFOxmSctpSrc": OxmMapEntry("TransportPort", "SCTP_SRC", False),
94 "OFOxmSctpSrcMasked": OxmMapEntry("TransportPort", "SCTP_SRC", True),
95 "OFOxmSctpDst": OxmMapEntry("TransportPort", "SCTP_DST", False),
96 "OFOxmSctpDstMasked": OxmMapEntry("TransportPort", "SCTP_DST", True),
97 "OFOxmIcmpv4Type": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", False),
98 "OFOxmIcmpv4TypeMasked": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", True),
99 "OFOxmIcmpv4Code": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", False),
100 "OFOxmIcmpv4CodeMasked": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", True),
101 "OFOxmArpOp": OxmMapEntry("ArpOpcode", "ARP_OP", False),
102 "OFOxmArpOpMasked": OxmMapEntry("ArpOpcode", "ARP_OP", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700103 "OFOxmArpSpa": OxmMapEntry("IPv4Address", "ARP_SPA", False),
104 "OFOxmArpSpaMasked": OxmMapEntry("IPv4Address", "ARP_SPA", True),
105 "OFOxmArpTpa": OxmMapEntry("IPv4Address", "ARP_TPA", False),
106 "OFOxmArpTpaMasked": OxmMapEntry("IPv4Address", "ARP_TPA", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700107 "OFOxmArpSha": OxmMapEntry("MacAddress", "ARP_SHA", False),
108 "OFOxmArpShaMasked": OxmMapEntry("MacAddress", "ARP_SHA", True),
109 "OFOxmArpTha": OxmMapEntry("MacAddress", "ARP_THA", False),
110 "OFOxmArpThaMasked": OxmMapEntry("MacAddress", "ARP_THA", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700111 "OFOxmIpv6Src": OxmMapEntry("IPv6Address", "IPV6_SRC", False),
112 "OFOxmIpv6SrcMasked": OxmMapEntry("IPv6Address", "IPV6_SRC", True),
113 "OFOxmIpv6Dst": OxmMapEntry("IPv6Address", "IPV6_DST", False),
114 "OFOxmIpv6DstMasked": OxmMapEntry("IPv6Address", "IPV6_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700115 "OFOxmIpv6Flabel": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", False),
Yotam Harchola86e4252013-09-06 15:36:28 -0700116 "OFOxmIpv6FlabelMasked": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True),
117 "OFOxmIcmpv6Type": OxmMapEntry("U8", "ICMPV6_TYPE", False),
118 "OFOxmIcmpv6TypeMasked": OxmMapEntry("U8", "ICMPV6_TYPE", True),
119 "OFOxmIcmpv6Code": OxmMapEntry("U8", "ICMPV6_CODE", False),
120 "OFOxmIcmpv6CodeMasked": OxmMapEntry("U8", "ICMPV6_CODE", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700121 "OFOxmIpv6NdTarget": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", False),
122 "OFOxmIpv6NdTargetMasked": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", True),
Yotam Harchola86e4252013-09-06 15:36:28 -0700123 "OFOxmIpv6NdSll": OxmMapEntry("MacAddress", "IPV6_ND_SLL", False),
124 "OFOxmIpv6NdSllMasked": OxmMapEntry("MacAddress", "IPV6_ND_SLL", True),
125 "OFOxmIpv6NdTll": OxmMapEntry("MacAddress", "IPV6_ND_TLL", False),
126 "OFOxmIpv6NdTllMasked": OxmMapEntry("MacAddress", "IPV6_ND_TLL", True),
127 "OFOxmMplsLabel": OxmMapEntry("U32", "MPLS_LABEL", False),
128 "OFOxmMplsLabelMasked": OxmMapEntry("U32", "MPLS_LABEL", True),
129 "OFOxmMplsTc": OxmMapEntry("U8", "MPLS_TC", False),
130 "OFOxmMplsTcMasked": OxmMapEntry("U8", "MPLS_TC", True)
131 }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700132
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700133 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700134 @property
135 def variable_name(self):
136 return self.name[0].lower() + self.name[1:]
137
138 @property
139 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700140 prefix = "is" if self.type == java_type.boolean else "get"
141 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700142
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700143 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
144
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700145 def gen_port_speed(enum_entry):
146 splits = enum_entry.name.split("_")
147 if len(splits)>=2:
148 m = re.match(r'\d+[MGTP]B', splits[1])
149 if m:
150 return "PortSpeed.SPEED_{}".format(splits[1])
151 return "PortSpeed.SPEED_NONE";
152
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700153
154 port_features_to_string_map = {
155 "PF_10MB_HD": "10mb-hd",
156 "PF_10MB_FD": "10mb-fd",
157 "PF_100MB_HD": "100mb-hd",
158 "PF_100MB_FD": "100mb-fd",
159 "PF_1GB_HD": "1gb-hd",
160 "PF_1GB_FD": "1gb-fd",
161 "PF_10GB_FD": "10gb-fd",
162 "PF_40GB_FD": "40gb-fd",
163 "PF_100GB_FD": "100gb-fd",
164 "PF_1TB_FD": "1tb-fd",
165 "PF_COPPER": "copper",
166 "PF_FIBER": "fiber",
167 "PF_AUTONEG": "autoneg",
168 "PF_PAUSE": "pause",
169 "PF_PAUSE_ASYM": "pause-asym",
170 "PF_OTHER": "other",
171 }
172
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700173 def gen_stp_state(enum_entry):
174 splits = enum_entry.name.split("_")
175 if len(splits)>=1:
176 if splits[0] == "STP":
177 return "true"
178 return "false"
179
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700180 port_state_to_string_map = {
181 "STP_LISTEN": "listen",
182 "LINK_DOWN": "link-down",
183 "STP_LEARN": "learn-no-relay",
184 "STP_FORWARD": "forward",
185 "STP_BLOCK": "block-broadcast",
186 "BLOCKED": "blocked",
187 "LIVE": "live"
188 }
189
190 port_config_to_string_map = {
191 "PORT_DOWN": "port-down",
192 "NO_STP": "no-stp",
193 "NO_RECV": "no-recv",
194 "NO_RECV_STP": "no-recv-stp",
195 "NO_FLOOD": "no-flood",
196 "NO_FWD": "no-fwd",
197 "NO_PACKET_IN": "no-pkt-in",
198 }
199
200 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
201 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), lambda e: JavaModel.port_features_to_string_map.get(e.name)),
202 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), lambda e: JavaModel.port_state_to_string_map.get(e.name)),
203 OFPortConfig = OFEnumMetadata((), lambda e: JavaModel.port_config_to_string_map.get(e.name))
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700204 )
205
Andreas Wundsam27303462013-07-16 12:52:35 -0700206 @property
207 @memoize
208 def versions(self):
209 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
210
211 @property
212 @memoize
213 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700214 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700215
216 for raw_version, of_protocol in of_g.ir.items():
217 jversion = JavaOFVersion(of_protocol.wire_version)
218
219 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700220 if not of_class.name in version_map_per_class:
221 version_map_per_class[of_class.name] = collections.OrderedDict()
222
Andreas Wundsam27303462013-07-16 12:52:35 -0700223 version_map_per_class[of_class.name][jversion] = of_class
224
225 interfaces = []
226 for class_name, version_map in version_map_per_class.items():
227 interfaces.append(JavaOFInterface(class_name, version_map))
228
Andreas Wundsambe168f72013-08-03 22:49:35 -0700229 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
230
Andreas Wundsam27303462013-07-16 12:52:35 -0700231 return interfaces
232
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700233 @memoize
234 def interface_by_name(self, name):
235 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
236
Andreas Wundsam27303462013-07-16 12:52:35 -0700237 @property
238 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700239 def all_classes(self):
240 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
241
242 @property
243 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700244 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700245 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700246
247 for version in self.versions:
248 of_protocol = of_g.ir[version.int_version]
249 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700250 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700251
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700252 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
253 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700254
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700255 # inelegant - need java name here
256 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700257 return enums
258
259 @memoize
260 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700261 res = find(lambda e: e.name == name, self.enums)
262 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700263 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700264 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700265
Andreas Wundsam5204de22013-07-30 11:34:45 -0700266 @property
267 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700268 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700269 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700270
271 factories = OrderedDict()
272
273 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
274 for base_class in sub_factory_classes:
275 package = base_class[2:].lower()
276 remove_prefix = base_class[2].lower() + base_class[3:]
277
278 # HACK need to have a better way to deal with parameterized base classes
279 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
280
281 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
282 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
283
284 factories[""] = OFFactory(
285 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700286 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700287 remove_prefix="",
288 members=[], base_class="OFMessage", sub_factories=OrderedDict(
289 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
290
291 for i in self.interfaces:
292 for n, factory in factories.items():
293 if n == "":
294 factory.members.append(i)
295 break
296 else:
297 super_class = self.interface_by_name(n)
298 if i.is_instance_of(super_class):
299 factory.members.append(i)
300 break
301 return factories.values()
Andreas Wundsam5204de22013-07-30 11:34:45 -0700302
303 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700304 """ return wether or not to generate implementation class clazz.
305 Now true for everything except OFTableModVer10.
306 @param clazz JavaOFClass instance
307 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700308 if clazz.interface.name.startswith("OFMatchV"):
309 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700310 elif clazz.name == "OFTableModVer10":
311 # tablemod ver 10 is a hack and has no oftype defined
312 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700313 if loxi_utils.class_is_message(clazz.interface.c_name):
314 return True
315 if loxi_utils.class_is_oxm(clazz.interface.c_name):
316 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700317 if loxi_utils.class_is_action(clazz.interface.c_name):
318 return True
319 if loxi_utils.class_is_instruction(clazz.interface.c_name):
320 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700321 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700322 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700323
324
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700325class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700326 @property
327 def factory_classes(self):
328 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700329 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700330 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700331 interface=self,
332 version=version
333 ) for version in model.versions ]
334
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700335 def method_name(self, member, builder=True):
336 n = member.variable_name
337 if n.startswith(self.remove_prefix):
338 n = n[len(self.remove_prefix):]
339 n = n[0].lower() + n[1:]
340 if builder:
341 return "build" + n[0].upper() + n[1:]
342 else:
343 return n
Andreas Wundsam5204de22013-07-30 11:34:45 -0700344
345OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700346class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
347 @property
348 def base_class(self):
349 return self.interface.base_class
350
351 @property
352 def versioned_base_class(self):
353 base_class_interface = model.interface_by_name(self.interface.base_class)
354 if base_class_interface and base_class_interface.has_version(self.version):
355 return base_class_interface.versioned_class(self.version)
356 else:
357 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700358
Andreas Wundsam27303462013-07-16 12:52:35 -0700359model = JavaModel()
360
361#######################################################################
362### OFVersion
363#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700364
365class JavaOFVersion(object):
366 """ Models a version of OpenFlow. contains methods to convert the internal
367 Loxi version to a java constant / a string """
368 def __init__(self, int_version):
369 self.int_version = int(int_version)
370
371 @property
372 def of_version(self):
373 return "1" + str(int(self.int_version) - 1)
374
375 @property
376 def constant_version(self):
377 return "OF_" + self.of_version
378
Andreas Wundsam27303462013-07-16 12:52:35 -0700379 def __repr__(self):
380 return "JavaOFVersion(%d)" % self.int_version
381
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700382 def __str__(self):
383 return of_g.param_version_names[self.int_version]
384
Andreas Wundsam27303462013-07-16 12:52:35 -0700385 def __hash__(self):
386 return hash(self.int_version)
387
388 def __eq__(self, other):
389 if other is None or type(self) != type(other):
390 return False
391 return (self.int_version,) == (other.int_version,)
392
393#######################################################################
394### Interface
395#######################################################################
396
397class JavaOFInterface(object):
398 """ Models an OpenFlow Message class for the purpose of the java class.
399 Version agnostic, in contrast to the loxi_ir python model.
400 """
401 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700402 """"
403 @param c_name: loxi style name (e.g., of_flow_add)
404 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
405 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700406 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700407 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700408 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700409 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 -0700410 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700411 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700412 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700413 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700414 self.constant_name = c_name.upper().replace("OF_", "")
415
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700416 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700417 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700418 if self.name != parent_interface:
419 self.parent_interface = parent_interface
420 else:
421 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700422
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700423 @property
424 @memoize
425 def all_parent_interfaces(self):
426 return [ "OFObject" ] + \
427 ([ self.parent_interface ] if self.parent_interface else [] )+ \
428 self.additional_parent_interfaces
429 @property
430 @memoize
431 def additional_parent_interfaces(self):
432 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
433 m = re.match(r'(.*)Request$', self.name)
434 if m:
435 reply_name = m.group(1) + "Reply"
436 if model.interface_by_name(reply_name):
437 return ["OFRequest<%s>" % reply_name ]
438 return []
439
440
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700441 def is_instance_of(self, other_class):
442 if self == other_class:
443 return True
444 parent = self.super_class
445 if parent is None:
446 return False
447 else:
448 return parent.is_instance_of(other_class)
449
450 @property
451 def super_class(self):
452 if not self.parent_interface:
453 return None
454 else:
455 return model.interface_by_name(self.parent_interface)
456
457
458 def inherited_declaration(self, type_spec="?"):
459 if self.type_annotation:
460 return "%s<%s>" % (self.name, type_spec)
461 else:
462 return "%s" % self.name
463
464 @property
465 def type_variable(self):
466 if self.type_annotation:
467 return "<T>"
468 else:
469 return "";
470
Andreas Wundsam27303462013-07-16 12:52:35 -0700471 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700472 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
473 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
474 # model (note, that the loxi model is on versioned classes). Should check/infer the
475 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700476 if re.match(r'OF.+StatsRequest$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700477 return ("", "OFStatsRequest", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700478 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700479 return ("", "OFStatsReply", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700480 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700481 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700482 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 -0700483 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700484 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 -0700485 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700486 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
487 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700488 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700489 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700490 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700491 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700492 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700493 if re.match(r'OFActionBsn.+', self.name):
494 return ("action", "OFActionBsn", None)
495 elif re.match(r'OFActionNicira.+', self.name):
496 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700497 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
498 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700499 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700500 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700501 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700502 return ("", "OFBsnVport", None)
503 elif self.name == "OFOxm":
504 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700505 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700506 if self.name in model.oxm_map:
507 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
508 else:
509 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700510 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700511 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700512 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700513 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700514 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700515 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700516 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700517 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700518 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700519 return ("", None, None)
520
521 @property
522 @memoize
523 def writeable_members(self):
524 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700525
526 @property
527 @memoize
528 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700529 return self.ir_model_members + self.virtual_members
530
531 @property
532 @memoize
533 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700534 """return a list of all members to be exposed by this interface. Corresponds to
535 the union of the members of the vesioned classes without length, fieldlength
536 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700537 all_versions = []
538 member_map = collections.OrderedDict()
539
540 for (version, of_class) in self.version_map.items():
541 for of_member in of_class.members:
542 if isinstance(of_member, OFLengthMember) or \
543 isinstance(of_member, OFFieldLengthMember) or \
544 isinstance(of_member, OFPadMember):
545 continue
546 if of_member.name not in member_map:
547 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
548
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700549 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 -0700550
551 @property
552 def virtual_members(self):
553 if self.name == "OFOxm":
554 return (
555 JavaVirtualMember(self, "value", java_type.generic_t),
556 JavaVirtualMember(self, "mask", java_type.generic_t),
557 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
558 JavaVirtualMember(self, "masked", java_type.boolean),
559 )
560 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
561 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
562 if self.name in model.oxm_map \
563 else java_type.make_match_field_jtype()
564
565 return (
566 JavaVirtualMember(self, "matchField", field_type),
567 JavaVirtualMember(self, "masked", java_type.boolean),
568 ) \
569 + \
570 (
571 ( JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type), ) if not find(lambda x: x.name == "mask", self.ir_model_members) else
572 ()
573 )
574 else:
575 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700576
577 @property
578 @memoize
579 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700580 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700581 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 -0700582
583 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700584 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700585 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700586 return len(self.all_versions) == len(model.versions)
587
588 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700589 @memoize
590 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700591 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700592 return self.version_map.keys()
593
Andreas Wundsam5204de22013-07-30 11:34:45 -0700594 def has_version(self, version):
595 return version in self.version_map
596
Andreas Wundsam27303462013-07-16 12:52:35 -0700597 def versioned_class(self, version):
598 return JavaOFClass(self, version, self.version_map[version])
599
600 @property
601 @memoize
602 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700603 return [ self.versioned_class(version) for version in self.all_versions ]
604
605#######################################################################
606### (Versioned) Classes
607#######################################################################
608
609class JavaOFClass(object):
610 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700611 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700612 """
613 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700614 """
615 @param interface JavaOFInterface instance of the parent interface
616 @param version JavaOFVersion
617 @param ir_class OFClass from loxi_ir
618 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700619 self.interface = interface
620 self.ir_class = ir_class
621 self.c_name = self.ir_class.name
622 self.version = version
623 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700624 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700625 self.generated = False
626
627 @property
628 @memoize
629 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700630 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700631
632 @property
633 def name(self):
634 return "%sVer%s" % (self.interface.name, self.version.of_version)
635
636 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700637 def variable_name(self):
638 return self.name[3:]
639
640 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700641 def length(self):
642 if self.is_fixed_length:
643 return self.min_length
644 else:
645 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
646
647 @property
648 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700649 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700650 id_tuple = (self.ir_class.name, self.version.int_version)
651 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
652
653 @property
654 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700655 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700656 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
657 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700658
659 def all_properties(self):
660 return self.interface.members
661
662 def get_member(self, name):
663 for m in self.members:
664 if m.name == name:
665 return m
666
667 @property
668 @memoize
669 def data_members(self):
670 return [ prop for prop in self.members if prop.is_data ]
671
672 @property
673 @memoize
674 def fixed_value_members(self):
675 return [ prop for prop in self.members if prop.is_fixed_value ]
676
677 @property
678 @memoize
679 def public_members(self):
680 return [ prop for prop in self.members if prop.is_public ]
681
682 @property
683 @memoize
684 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700685 return self.ir_model_members + self.virtual_members
686
687 @property
688 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700689 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700690 return tuple(members)
691
692 @property
693 def virtual_members(self):
694 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
695 if self.interface.name in model.oxm_map:
696 oxm_entry = model.oxm_map[self.interface.name]
697 return (
698 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
699 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
700 )
701 else:
702 return (
703 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
704 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
705 )
706 else:
707 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700708
709 def all_versions(self):
710 return [ JavaOFVersion(int_version)
711 for int_version in of_g.unified[self.c_name]
712 if int_version != 'union' and int_version != 'object_id' ]
713
714 def version_is_inherited(self, version):
715 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
716
717 def inherited_from(self, version):
718 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
719
720 @property
721 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700722 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
723
724 @property
725 def discriminator(self):
726 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700727
728 @property
729 def is_extension(self):
730 return type_maps.message_is_extension(self.c_name, -1)
731
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700732 @property
733 def align(self):
734 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
735
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700736 @property
737 @memoize
738 def superclass(self):
739 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
740
741 @property
742 @memoize
743 def subclasses(self):
744 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
745
Andreas Wundsam27303462013-07-16 12:52:35 -0700746#######################################################################
747### Member
748#######################################################################
749
750
751class JavaMember(object):
752 """ Models a property (member) of an openflow class. """
753 def __init__(self, msg, name, java_type, member):
754 self.msg = msg
755 self.name = name
756 self.java_type = java_type
757 self.member = member
758 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700759
760 @property
761 def title_name(self):
762 return self.name[0].upper() + self.name[1:]
763
764 @property
765 def constant_name(self):
766 return self.c_name.upper()
767
768 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700769 def getter_name(self):
770 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
771
772 @property
773 def setter_name(self):
774 return "set" + self.title_name
775
776 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700777 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700778 if self.is_fixed_value:
779 return self.constant_name
780 else:
781 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700782
783 @property
784 def default_value(self):
785 java_type = self.java_type.public_type;
786
Andreas Wundsam27303462013-07-16 12:52:35 -0700787 if self.is_fixed_value:
788 return self.enum_value
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700789 elif java_type == "OFOxmList":
790 return "OFOxmList.EMPTY"
Andreas Wundsam27303462013-07-16 12:52:35 -0700791 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700792 return "Collections.emptyList()"
793 elif java_type == "boolean":
794 return "false";
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700795 elif self.java_type.is_array:
796 return "new %s[0]" % java_type[:-2]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700797 elif java_type in ("byte", "char", "short", "int", "long"):
798 return "({0}) 0".format(java_type);
799 else:
800 return "null";
801
802 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700803 def enum_value(self):
804 if self.name == "version":
805 return "OFVersion.%s" % self.msg.version.constant_version
806
807 java_type = self.java_type.public_type;
808 try:
809 global model
810 enum = model.enum_by_name(java_type)
811 entry = enum.entry_by_version_value(self.msg.version, self.value)
812 return "%s.%s" % ( enum.name, entry.name)
813 except KeyError, e:
814 print e.message
815 return self.value
816
817 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700818 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700819 return isinstance(self.member, OFPadMember)
820
821 def is_type_value(self, version=None):
822 if(version==None):
823 return any(self.is_type_value(version) for version in self.msg.all_versions)
824 try:
825 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
826 except:
827 return False
828
829 @property
830 def is_field_length_value(self):
831 return isinstance(self.member, OFFieldLengthMember)
832
833 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700834 def is_discriminator(self):
835 return isinstance(self.member, OFDiscriminatorMember)
836
837 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700838 def is_length_value(self):
839 return isinstance(self.member, OFLengthMember)
840
841 @property
842 def is_public(self):
843 return not (self.is_pad or self.is_length_value)
844
845 @property
846 def is_data(self):
847 return isinstance(self.member, OFDataMember) and self.name != "version"
848
849 @property
850 def is_fixed_value(self):
851 return hasattr(self.member, "value") or self.name == "version" \
852 or ( self.name == "length" and self.msg.is_fixed_length) \
853 or ( self.name == "len" and self.msg.is_fixed_length)
854
855 @property
856 def value(self):
857 if self.name == "version":
858 return self.msg.version.int_version
859 elif self.name == "length" or self.name == "len":
860 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700861 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700862 return self.java_type.format_value(self.member.value)
863
864 @property
865 def priv_value(self):
866 if self.name == "version":
867 return self.msg.version.int_version
868 elif self.name == "length" or self.name == "len":
869 return self.msg.length
870 else:
871 return self.java_type.format_value(self.member.value, pub_type=False)
872
Andreas Wundsam27303462013-07-16 12:52:35 -0700873
874 @property
875 def is_writeable(self):
876 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
877
878 def get_type_value_info(self, version):
879 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700880
881 @property
882 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700883 if hasattr(self.member, "length"):
884 return self.member.length
885 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700886 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700887 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700888
889 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700890 def for_of_member(java_class, member):
891 if isinstance(member, OFPadMember):
892 return JavaMember(None, "", None, member)
893 else:
894 if member.name == 'len':
895 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700896 elif member.name == 'value_mask':
897 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700898 else:
899 name = java_type.name_c_to_camel(member.name)
900 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
901 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700902
903 @property
904 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700905 if not self.msg.c_name in of_g.unified:
906 print("%s not self.unified" % self.msg.c_name)
907 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700908 for version in of_g.unified[self.msg.c_name]:
909 if version == 'union' or version =='object_id':
910 continue
911 if 'use_version' in of_g.unified[self.msg.c_name][version]:
912 continue
913
Andreas Wundsam27303462013-07-16 12:52:35 -0700914 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 -0700915 return False
916 return True
917
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700918 @property
919 def is_virtual(self):
920 return False
921
Andreas Wundsam27303462013-07-16 12:52:35 -0700922 def __hash__(self):
923 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700924
Andreas Wundsam27303462013-07-16 12:52:35 -0700925 def __eq__(self, other):
926 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700927 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700928 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700929
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700930class JavaVirtualMember(JavaMember):
931 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
932 def __init__(self, msg, name, java_type, value=None):
933 JavaMember.__init__(self, msg, name, java_type, member=None)
934 self._value = value
935
936 @property
937 def is_fixed_value(self):
938 return True
939
940 @property
941 def value(self):
942 return self._value
943
944 @property
945 def priv_value(self):
946 return self._value
947
948
949 @property
950 def is_universal(self):
951 return True
952
953 @property
954 def is_virtual(self):
955 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700956
957#######################################################################
958### Unit Test
959#######################################################################
960
Yotam Harchol466b3212013-08-15 12:14:46 -0700961class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700962 def __init__(self, java_class):
963 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700964 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700965 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700966 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
967 name=java_class.c_name[3:]) + "{i}.data"
968 test_class_name = self.java_class.name + "Test"
969 self.test_units = []
970 if test_data.exists(first_data_file_name):
971 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
972 i = 1
973 while test_data.exists(data_file_template.format(i=i)):
974 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
975 i = i + 1
976
977 @property
978 def package(self):
979 return self.java_class.package
980
981 @property
982 def has_test_data(self):
983 return len(self.test_units) > 0
984
985 @property
986 def length(self):
987 return len(self.test_units)
988
989 def get_test_unit(self, i):
990 return self.test_units[i]
991
992
993class JavaUnitTest(object):
994 def __init__(self, java_class, file_name=None, test_class_name=None):
995 self.java_class = java_class
996 if file_name is None:
997 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
998 name=java_class.c_name[3:])
999 else:
1000 self.data_file_name = file_name
1001 if test_class_name is None:
1002 self.test_class_name = self.java_class.name + "Test"
1003 else:
1004 self.test_class_name = test_class_name
1005
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001006 @property
1007 def package(self):
1008 return self.java_class.package
1009
1010 @property
1011 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001012 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001013
1014 @property
1015 def has_test_data(self):
1016 return test_data.exists(self.data_file_name)
1017
1018 @property
1019 @memoize
1020 def test_data(self):
1021 return test_data.read(self.data_file_name)
1022
1023
Andreas Wundsam27303462013-07-16 12:52:35 -07001024#######################################################################
1025### Enums
1026#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001027
Andreas Wundsam27303462013-07-16 12:52:35 -07001028class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001029 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001030 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001031
1032 if c_name == "of_stats_types":
1033 self.name = "OFStatsType"
1034 else:
1035 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001036
Andreas Wundsam27303462013-07-16 12:52:35 -07001037 # Port_features has constants that start with digits
1038 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001039
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001040 self.version_enums = version_enum_map
1041
1042 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1043 for version, ir_enum in version_enum_map.items():
1044 for ir_entry in ir_enum.entries:
1045 if "virtual" in ir_entry.params:
1046 continue
1047 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1048
Andreas Wundsam27303462013-07-16 12:52:35 -07001049 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001050 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001051
1052 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 -07001053 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001054
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001055 self.metadata = model.enum_metadata_map[self.name]
1056
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001057 def wire_type(self, version):
1058 ir_enum = self.version_enums[version]
1059 if "wire_type" in ir_enum.params:
1060 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1061 else:
1062 return java_type.u8
1063
1064 @property
1065 def versions(self):
1066 return self.version_enums.keys()
1067
Andreas Wundsam27303462013-07-16 12:52:35 -07001068 @memoize
1069 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001070 res = find(lambda e: e.name == name, self.entries)
1071 if res:
1072 return res
1073 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001074 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1075
1076 @memoize
1077 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001078 res = find(lambda e: e.c_name == name, self.entries)
1079 if res:
1080 return res
1081 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001082 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1083
1084 @memoize
1085 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001086 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1087 if res:
1088 return res
1089 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001090 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1091
1092# values: Map JavaVersion->Value
1093class JavaEnumEntry(object):
1094 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001095 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001096 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1097 self.values = values
1098
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001099 @property
1100 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001101 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001102
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001103 def has_value(self, version):
1104 return version in self.values
1105
Andreas Wundsam27303462013-07-16 12:52:35 -07001106 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001107 return self.values[version]
1108
1109 def format_value(self, version):
1110 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001111 return res
1112
Andreas Wundsam27303462013-07-16 12:52:35 -07001113 def all_values(self, versions, not_present=None):
1114 return [ self.values[version] if version in self.values else not_present for version in versions ]