blob: ac52de43ef57bc2513e3e6d185e58423c7c49902 [file] [log] [blame]
Andreas Wundsam27303462013-07-16 12:52:35 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
Andreas Wundsam40e14f72013-05-06 14:49:08 -070028# Prototype of an Intermediate Object model for the java code generator
29# A lot of this stuff could/should probably be merged with the python utilities
30
Andreas Wundsam27303462013-07-16 12:52:35 -070031import collections
Andreas Wundsam5204de22013-07-30 11:34:45 -070032from collections import namedtuple, defaultdict, OrderedDict
Andreas Wundsam27303462013-07-16 12:52:35 -070033import logging
Andreas Wundsam40e14f72013-05-06 14:49:08 -070034import os
35import pdb
36import re
37
Andreas Wundsam5204de22013-07-30 11:34:45 -070038from generic_utils import find, memoize, OrderedSet, OrderedDefaultDict
Andreas Wundsam27303462013-07-16 12:52:35 -070039import of_g
40from loxi_ir import *
Andreas Wundsam40e14f72013-05-06 14:49:08 -070041import loxi_front_end.type_maps as type_maps
Andreas Wundsam5204de22013-07-30 11:34:45 -070042import loxi_utils.loxi_utils as loxi_utils
Andreas Wundsam40e14f72013-05-06 14:49:08 -070043import py_gen.util as py_utils
Andreas Wundsam5204de22013-07-30 11:34:45 -070044import test_data
Andreas Wundsam40e14f72013-05-06 14:49:08 -070045
Andreas Wundsam27303462013-07-16 12:52:35 -070046import java_gen.java_type as java_type
Andreas Wundsame0d52be2013-08-22 07:52:13 -070047from java_gen.java_type import erase_type_annotation
Andreas Wundsam40e14f72013-05-06 14:49:08 -070048
Andreas Wundsam27303462013-07-16 12:52:35 -070049class JavaModel(object):
Andreas Wundsamf1949682013-09-23 14:48:31 -070050 # registry for enums that should not be generated
51 # set(${java_enum_name})
Andreas Wundsamacd57d52013-10-18 17:35:01 -070052 enum_blacklist = set(("OFDefinitions", "OFPortNo", "OFVlanId", "OFGroup"))
Andreas Wundsamf1949682013-09-23 14:48:31 -070053 # registry for enum *entry* that should not be generated
54 # map: ${java_enum_name} -> set(${java_entry_entry_name})
Andreas Wundsam43526532013-08-01 22:03:50 -070055 enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
Andreas Wundsamf1949682013-09-23 14:48:31 -070056
57 # registry of interfaces that should not be generated
58 # set(java_names)
Andreas Wundsambe168f72013-08-03 22:49:35 -070059 # OFUint structs are there for god-knows what in loci. We certainly don't need them.
60 interface_blacklist = set( ("OFUint8", "OFUint32",))
Andreas Wundsamf1949682013-09-23 14:48:31 -070061 # registry of interface properties that should not be generated
62 # map: $java_type -> set(java_name_property)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070063 read_blacklist = defaultdict(lambda: set(), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070064 # map: $java_type -> set(java_name_property)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070065 write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070066 # interfaces that are virtual
Andreas Wundsam001b1822013-08-02 22:25:55 -070067 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070068
Andreas Wundsam2be7da52013-08-22 07:34:25 -070069 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
Yotam Harchole5d92972013-08-22 14:18:36 -070070 oxm_map = { "OFOxmInPort": OxmMapEntry("OFPort", "IN_PORT", False),
71 "OFOxmInPortMasked": OxmMapEntry("OFPort", "IN_PORT", True),
72 "OFOxmInPhyPort": OxmMapEntry("OFPort", "IN_PHY_PORT", False),
73 "OFOxmInPhyPortMasked": OxmMapEntry("OFPort", "IN_PHY_PORT", True),
74 "OFOxmMetadata": OxmMapEntry("OFMetadata", "METADATA", False),
75 "OFOxmMetadataMasked": OxmMapEntry("OFMetadata", "METADATA", True),
76 "OFOxmEthDst": OxmMapEntry("MacAddress", "ETH_DST", False),
77 "OFOxmEthDstMasked": OxmMapEntry("MacAddress", "ETH_DST", True),
78 "OFOxmEthSrc": OxmMapEntry("MacAddress", "ETH_SRC", False),
79 "OFOxmEthSrcMasked": OxmMapEntry("MacAddress", "ETH_SRC", True),
80 "OFOxmEthType": OxmMapEntry("EthType", "ETH_TYPE", False),
81 "OFOxmEthTypeMasked": OxmMapEntry("EthType", "ETH_TYPE", True),
82 "OFOxmVlanVid": OxmMapEntry("VlanVid", "VLAN_VID", False),
83 "OFOxmVlanVidMasked": OxmMapEntry("VlanVid", "VLAN_VID", True),
84 "OFOxmVlanPcp": OxmMapEntry("VlanPcp", "VLAN_PCP", False),
85 "OFOxmVlanPcpMasked": OxmMapEntry("VlanPcp", "VLAN_PCP", True),
86 "OFOxmIpDscp": OxmMapEntry("IpDscp", "IP_DSCP", False),
87 "OFOxmIpDscpMasked": OxmMapEntry("IpDscp", "IP_DSCP", True),
88 "OFOxmIpEcn": OxmMapEntry("IpEcn", "IP_ECN", False),
89 "OFOxmIpEcnMasked": OxmMapEntry("IpEcn", "IP_ECN", True),
90 "OFOxmIpProto": OxmMapEntry("IpProtocol", "IP_PROTO", False),
91 "OFOxmIpProtoMasked": OxmMapEntry("IpProtocol", "IP_PROTO", True),
Yotam Harchola289d552013-09-16 10:10:40 -070092 "OFOxmIpv4Src": OxmMapEntry("IPv4Address", "IPV4_SRC", False),
93 "OFOxmIpv4SrcMasked": OxmMapEntry("IPv4Address", "IPV4_SRC", True),
94 "OFOxmIpv4Dst": OxmMapEntry("IPv4Address", "IPV4_DST", False),
95 "OFOxmIpv4DstMasked": OxmMapEntry("IPv4Address", "IPV4_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -070096 "OFOxmTcpSrc": OxmMapEntry("TransportPort", "TCP_SRC", False),
97 "OFOxmTcpSrcMasked": OxmMapEntry("TransportPort", "TCP_SRC", True),
98 "OFOxmTcpDst": OxmMapEntry("TransportPort", "TCP_DST", False),
99 "OFOxmTcpDstMasked": OxmMapEntry("TransportPort", "TCP_DST", True),
100 "OFOxmUdpSrc": OxmMapEntry("TransportPort", "UDP_SRC", False),
101 "OFOxmUdpSrcMasked": OxmMapEntry("TransportPort", "UDP_SRC", True),
102 "OFOxmUdpDst": OxmMapEntry("TransportPort", "UDP_DST", False),
103 "OFOxmUdpDstMasked": OxmMapEntry("TransportPort", "UDP_DST", True),
104 "OFOxmSctpSrc": OxmMapEntry("TransportPort", "SCTP_SRC", False),
105 "OFOxmSctpSrcMasked": OxmMapEntry("TransportPort", "SCTP_SRC", True),
106 "OFOxmSctpDst": OxmMapEntry("TransportPort", "SCTP_DST", False),
107 "OFOxmSctpDstMasked": OxmMapEntry("TransportPort", "SCTP_DST", True),
108 "OFOxmIcmpv4Type": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", False),
109 "OFOxmIcmpv4TypeMasked": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", True),
110 "OFOxmIcmpv4Code": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", False),
111 "OFOxmIcmpv4CodeMasked": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", True),
112 "OFOxmArpOp": OxmMapEntry("ArpOpcode", "ARP_OP", False),
113 "OFOxmArpOpMasked": OxmMapEntry("ArpOpcode", "ARP_OP", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700114 "OFOxmArpSpa": OxmMapEntry("IPv4Address", "ARP_SPA", False),
115 "OFOxmArpSpaMasked": OxmMapEntry("IPv4Address", "ARP_SPA", True),
116 "OFOxmArpTpa": OxmMapEntry("IPv4Address", "ARP_TPA", False),
117 "OFOxmArpTpaMasked": OxmMapEntry("IPv4Address", "ARP_TPA", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700118 "OFOxmArpSha": OxmMapEntry("MacAddress", "ARP_SHA", False),
119 "OFOxmArpShaMasked": OxmMapEntry("MacAddress", "ARP_SHA", True),
120 "OFOxmArpTha": OxmMapEntry("MacAddress", "ARP_THA", False),
121 "OFOxmArpThaMasked": OxmMapEntry("MacAddress", "ARP_THA", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700122 "OFOxmIpv6Src": OxmMapEntry("IPv6Address", "IPV6_SRC", False),
123 "OFOxmIpv6SrcMasked": OxmMapEntry("IPv6Address", "IPV6_SRC", True),
124 "OFOxmIpv6Dst": OxmMapEntry("IPv6Address", "IPV6_DST", False),
125 "OFOxmIpv6DstMasked": OxmMapEntry("IPv6Address", "IPV6_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700126 "OFOxmIpv6Flabel": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", False),
Yotam Harchola86e4252013-09-06 15:36:28 -0700127 "OFOxmIpv6FlabelMasked": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True),
128 "OFOxmIcmpv6Type": OxmMapEntry("U8", "ICMPV6_TYPE", False),
129 "OFOxmIcmpv6TypeMasked": OxmMapEntry("U8", "ICMPV6_TYPE", True),
130 "OFOxmIcmpv6Code": OxmMapEntry("U8", "ICMPV6_CODE", False),
131 "OFOxmIcmpv6CodeMasked": OxmMapEntry("U8", "ICMPV6_CODE", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700132 "OFOxmIpv6NdTarget": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", False),
133 "OFOxmIpv6NdTargetMasked": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", True),
Yotam Harchola86e4252013-09-06 15:36:28 -0700134 "OFOxmIpv6NdSll": OxmMapEntry("MacAddress", "IPV6_ND_SLL", False),
135 "OFOxmIpv6NdSllMasked": OxmMapEntry("MacAddress", "IPV6_ND_SLL", True),
136 "OFOxmIpv6NdTll": OxmMapEntry("MacAddress", "IPV6_ND_TLL", False),
137 "OFOxmIpv6NdTllMasked": OxmMapEntry("MacAddress", "IPV6_ND_TLL", True),
138 "OFOxmMplsLabel": OxmMapEntry("U32", "MPLS_LABEL", False),
139 "OFOxmMplsLabelMasked": OxmMapEntry("U32", "MPLS_LABEL", True),
140 "OFOxmMplsTc": OxmMapEntry("U8", "MPLS_TC", False),
Yotam Harchola11f38b2013-09-26 15:38:17 -0700141 "OFOxmMplsTcMasked": OxmMapEntry("U8", "MPLS_TC", True),
Yotam Harchol2c535582013-10-01 15:50:20 -0700142 "OFOxmBsnInPorts128": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", False),
Rich Lane1424d0b2013-10-24 17:16:24 -0700143 "OFOxmBsnInPorts128Masked": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", True),
Rich Lane376cafe2013-10-27 21:49:14 -0700144 "OFOxmBsnLagId": OxmMapEntry("LagId", "BSN_LAG_ID", False),
145 "OFOxmBsnLagIdMasked": OxmMapEntry("LagId", "BSN_LAG_ID", True),
Yotam Harchola86e4252013-09-06 15:36:28 -0700146 }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700147
Andreas Wundsamf1949682013-09-23 14:48:31 -0700148 # Registry of nullable properties:
149 # ${java_class_name} -> set(${java_property_name})
150 nullable_map = defaultdict(lambda: set(),
151 )
152
153 # represents a subgroup of a bitmask enum that is actualy a normal enumerable within a masked part of the enum
154 # e.g., the flags STP.* in OF1.0 port state are bit mask entries, but instead enumerables according to the mask "STP_MASK"
155 # name: a name for the group
156 # mask: java name of the enum entry that defines the mask
157 # members: set of names of the members of the group
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700158 MaskedEnumGroup = namedtuple("MaskedEnumGroup", ("name", "mask", "members"))
159
Andreas Wundsamf1949682013-09-23 14:48:31 -0700160 # registry of MaskedEnumGroups (see above).
161 # map: ${java_enum_name}: tuple(MaskedEnumGroup)
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700162 masked_enum_groups = defaultdict(lambda: (),
Andreas Wundsamaebe5182013-09-24 13:01:07 -0700163 OFPortState = (MaskedEnumGroup("stp_flags", mask="STP_MASK", members=set(("STP_LISTEN", "STP_LEARN", "STP_FORWARD", "STP_BLOCK"))), ),
164 OFConfigFlags = (
165 MaskedEnumGroup("frag_flags", mask="FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
Andreas Wundsam376cef52013-09-24 13:52:18 -0700166 ),
167 OFTableConfig = (
168 MaskedEnumGroup("table_miss_flags", mask="TABLE_MISS_MASK", members=set(("TABLE_MISS_CONTROLLER", "TABLE_MISS_CONTINUE", "TABLE_MISS_DROP"))),
169 ),
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700170 )
171
Andreas Wundsamf1949682013-09-23 14:48:31 -0700172 # represents a metadata property associated with an EnumClass
173 # name:
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700174 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700175 """
176 represents a metadata property associated with an Enum Class
177 @param name name of metadata property
178 @param type java_type instance describing the type
179 @value: Generator function f(entry) that generates the value
180 """
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700181 @property
182 def variable_name(self):
183 return self.name[0].lower() + self.name[1:]
184
185 @property
186 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700187 prefix = "is" if self.type == java_type.boolean else "get"
188 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700189
Andreas Wundsamf1949682013-09-23 14:48:31 -0700190 """ Metadata container. """
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700191 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
192
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700193 def gen_port_speed(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700194 """ Generator function for OFortFeatures.PortSpeed"""
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700195 splits = enum_entry.name.split("_")
196 if len(splits)>=2:
197 m = re.match(r'\d+[MGTP]B', splits[1])
198 if m:
199 return "PortSpeed.SPEED_{}".format(splits[1])
200 return "PortSpeed.SPEED_NONE";
201
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700202 def gen_stp_state(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700203 """ Generator function for OFPortState.StpState"""
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700204 splits = enum_entry.name.split("_")
205 if len(splits)>=1:
206 if splits[0] == "STP":
207 return "true"
208 return "false"
209
Andreas Wundsamf1949682013-09-23 14:48:31 -0700210 # registry for metadata properties for enums
211 # map: ${java_enum_name}: OFEnumMetadata
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700212 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700213 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
214 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700215 )
216
Andreas Wundsam27303462013-07-16 12:52:35 -0700217 @property
218 @memoize
219 def versions(self):
220 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
221
222 @property
223 @memoize
224 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700225 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700226
227 for raw_version, of_protocol in of_g.ir.items():
228 jversion = JavaOFVersion(of_protocol.wire_version)
229
230 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700231 if not of_class.name in version_map_per_class:
232 version_map_per_class[of_class.name] = collections.OrderedDict()
233
Andreas Wundsam27303462013-07-16 12:52:35 -0700234 version_map_per_class[of_class.name][jversion] = of_class
235
236 interfaces = []
237 for class_name, version_map in version_map_per_class.items():
238 interfaces.append(JavaOFInterface(class_name, version_map))
239
Andreas Wundsambe168f72013-08-03 22:49:35 -0700240 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
241
Andreas Wundsam27303462013-07-16 12:52:35 -0700242 return interfaces
243
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700244 @memoize
245 def interface_by_name(self, name):
246 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
247
Andreas Wundsam27303462013-07-16 12:52:35 -0700248 @property
249 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700250 def all_classes(self):
251 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
252
253 @property
254 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700255 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700256 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700257
258 for version in self.versions:
259 of_protocol = of_g.ir[version.int_version]
260 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700261 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700262
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700263 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
264 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700265
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700266 # inelegant - need java name here
267 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700268 return enums
269
270 @memoize
271 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700272 res = find(lambda e: e.name == name, self.enums)
273 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700274 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700275 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700276
Andreas Wundsam5204de22013-07-30 11:34:45 -0700277 @property
278 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700279 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700280 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700281
282 factories = OrderedDict()
283
284 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
285 for base_class in sub_factory_classes:
286 package = base_class[2:].lower()
287 remove_prefix = base_class[2].lower() + base_class[3:]
288
289 # HACK need to have a better way to deal with parameterized base classes
290 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
291
292 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700293 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 -0700294
295 factories[""] = OFFactory(
296 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700297 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700298 remove_prefix="",
299 members=[], base_class="OFMessage", sub_factories=OrderedDict(
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700300 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ),
301 xid_generator=True)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700302
303 for i in self.interfaces:
304 for n, factory in factories.items():
305 if n == "":
306 factory.members.append(i)
307 break
308 else:
309 super_class = self.interface_by_name(n)
310 if i.is_instance_of(super_class):
311 factory.members.append(i)
312 break
313 return factories.values()
Yotam Harchol595c6442013-09-27 16:29:08 -0700314
315 @memoize
316 def factory_of(self, interface):
317 for factory in self.of_factories:
318 if interface in factory.members:
319 return factory
320 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700321
322 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700323 """ return wether or not to generate implementation class clazz.
324 Now true for everything except OFTableModVer10.
325 @param clazz JavaOFClass instance
326 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700327 if clazz.interface.name.startswith("OFMatchV"):
328 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700329 elif clazz.name == "OFTableModVer10":
330 # tablemod ver 10 is a hack and has no oftype defined
331 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700332 if loxi_utils.class_is_message(clazz.interface.c_name):
333 return True
334 if loxi_utils.class_is_oxm(clazz.interface.c_name):
335 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700336 if loxi_utils.class_is_action(clazz.interface.c_name):
337 return True
338 if loxi_utils.class_is_instruction(clazz.interface.c_name):
339 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700340 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700341 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700342
343
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700344class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories", "xid_generator"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700345 @property
346 def factory_classes(self):
347 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700348 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700349 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700350 interface=self,
351 version=version
352 ) for version in model.versions ]
353
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700354 def method_name(self, member, builder=True):
355 n = member.variable_name
356 if n.startswith(self.remove_prefix):
357 n = n[len(self.remove_prefix):]
358 n = n[0].lower() + n[1:]
359 if builder:
360 return "build" + n[0].upper() + n[1:]
361 else:
362 return n
Yotam Harchol595c6442013-09-27 16:29:08 -0700363
364 def of_version(self, version):
365 for fc in self.factory_classes:
366 if fc.version == version:
367 return fc
368 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700369
370OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700371class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
372 @property
373 def base_class(self):
374 return self.interface.base_class
375
376 @property
377 def versioned_base_class(self):
378 base_class_interface = model.interface_by_name(self.interface.base_class)
379 if base_class_interface and base_class_interface.has_version(self.version):
380 return base_class_interface.versioned_class(self.version)
381 else:
382 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700383
Andreas Wundsam27303462013-07-16 12:52:35 -0700384model = JavaModel()
385
386#######################################################################
387### OFVersion
388#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700389
390class JavaOFVersion(object):
391 """ Models a version of OpenFlow. contains methods to convert the internal
392 Loxi version to a java constant / a string """
393 def __init__(self, int_version):
394 self.int_version = int(int_version)
395
396 @property
397 def of_version(self):
398 return "1" + str(int(self.int_version) - 1)
399
400 @property
401 def constant_version(self):
402 return "OF_" + self.of_version
403
Andreas Wundsam27303462013-07-16 12:52:35 -0700404 def __repr__(self):
405 return "JavaOFVersion(%d)" % self.int_version
406
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700407 def __str__(self):
408 return of_g.param_version_names[self.int_version]
409
Andreas Wundsam27303462013-07-16 12:52:35 -0700410 def __hash__(self):
411 return hash(self.int_version)
412
413 def __eq__(self, other):
414 if other is None or type(self) != type(other):
415 return False
416 return (self.int_version,) == (other.int_version,)
417
418#######################################################################
419### Interface
420#######################################################################
421
422class JavaOFInterface(object):
423 """ Models an OpenFlow Message class for the purpose of the java class.
424 Version agnostic, in contrast to the loxi_ir python model.
425 """
426 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700427 """"
428 @param c_name: loxi style name (e.g., of_flow_add)
429 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
430 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700431 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700432 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700433 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700434 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 -0700435 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700436 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700437 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700438 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700439 self.constant_name = c_name.upper().replace("OF_", "")
440
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700441 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700442 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700443 if self.name != parent_interface:
444 self.parent_interface = parent_interface
445 else:
446 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700447
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700448 @property
449 @memoize
450 def all_parent_interfaces(self):
451 return [ "OFObject" ] + \
452 ([ self.parent_interface ] if self.parent_interface else [] )+ \
453 self.additional_parent_interfaces
454 @property
455 @memoize
456 def additional_parent_interfaces(self):
457 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
458 m = re.match(r'(.*)Request$', self.name)
459 if m:
460 reply_name = m.group(1) + "Reply"
461 if model.interface_by_name(reply_name):
462 return ["OFRequest<%s>" % reply_name ]
463 return []
464
465
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700466 def is_instance_of(self, other_class):
467 if self == other_class:
468 return True
469 parent = self.super_class
470 if parent is None:
471 return False
472 else:
473 return parent.is_instance_of(other_class)
474
475 @property
476 def super_class(self):
477 if not self.parent_interface:
478 return None
479 else:
480 return model.interface_by_name(self.parent_interface)
481
482
483 def inherited_declaration(self, type_spec="?"):
484 if self.type_annotation:
485 return "%s<%s>" % (self.name, type_spec)
486 else:
487 return "%s" % self.name
488
489 @property
490 def type_variable(self):
491 if self.type_annotation:
492 return "<T>"
493 else:
494 return "";
495
Andreas Wundsam27303462013-07-16 12:52:35 -0700496 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700497 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
498 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
499 # model (note, that the loxi model is on versioned classes). Should check/infer the
500 # inheritance information from the versioned lox_ir classes.
Andreas Wundsamd6b0cb02013-09-28 18:55:56 -0700501 if re.match(r'OFStatsRequest$', self.name):
502 return ("", "OFMessage", "T extends OFStatsReply")
503 elif re.match(r'OF.+StatsRequest$', self.name):
504 return ("", "OFStatsRequest<{}>".format(re.sub(r'Request$', 'Reply', self.name)), None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700505 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700506 return ("", "OFStatsReply", None)
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700507 elif re.match(r'OF.+ErrorMsg$', self.name):
508 return ("", "OFErrorMsg", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700509 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700510 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700511 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 -0700512 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700513 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 -0700514 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700515 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
516 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700517 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700518 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700519 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700520 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700521 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700522 if re.match(r'OFActionBsn.+', self.name):
523 return ("action", "OFActionBsn", None)
524 elif re.match(r'OFActionNicira.+', self.name):
525 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700526 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
527 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700528 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700529 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700530 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700531 return ("", "OFBsnVport", None)
532 elif self.name == "OFOxm":
533 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700534 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700535 if self.name in model.oxm_map:
536 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
537 else:
538 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700539 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700540 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700541 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700542 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700543 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700544 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700545 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700546 return ("", "OFHelloElem", None)
Rich Lane26847562013-10-08 13:44:47 -0700547 elif loxi_utils.class_is_table_feature_prop(self.c_name):
548 return ("", "OFTableFeatureProp", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700549 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700550 return ("", None, None)
551
552 @property
553 @memoize
554 def writeable_members(self):
555 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700556
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700557 @memoize
558 def member_by_name(self, name):
559 return find(lambda m: m.name == name, self.members)
560
Andreas Wundsam27303462013-07-16 12:52:35 -0700561 @property
562 @memoize
563 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700564 return self.ir_model_members + self.virtual_members
565
566 @property
567 @memoize
568 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700569 """return a list of all members to be exposed by this interface. Corresponds to
570 the union of the members of the vesioned classes without length, fieldlength
571 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700572 all_versions = []
573 member_map = collections.OrderedDict()
574
575 for (version, of_class) in self.version_map.items():
576 for of_member in of_class.members:
577 if isinstance(of_member, OFLengthMember) or \
578 isinstance(of_member, OFFieldLengthMember) or \
579 isinstance(of_member, OFPadMember):
580 continue
581 if of_member.name not in member_map:
582 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
583
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700584 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 -0700585
586 @property
587 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700588 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700589 if self.name == "OFOxm":
Andreas Wundsama0981022013-10-02 18:15:06 -0700590 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700591 JavaVirtualMember(self, "value", java_type.generic_t),
592 JavaVirtualMember(self, "mask", java_type.generic_t),
593 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
594 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsama0981022013-10-02 18:15:06 -0700595 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700596 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
597 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
598 if self.name in model.oxm_map \
599 else java_type.make_match_field_jtype()
600
Andreas Wundsama0981022013-10-02 18:15:06 -0700601 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700602 JavaVirtualMember(self, "matchField", field_type),
603 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsama0981022013-10-02 18:15:06 -0700604 ]
605 if not find(lambda x: x.name == "mask", self.ir_model_members):
606 virtual_members.append(JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type))
607
608 if not find(lambda m: m.name == "version", self.ir_model_members):
609 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version))
610
611 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700612
613 @property
614 @memoize
615 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700616 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700617 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 -0700618
619 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700620 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700621 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700622 return len(self.all_versions) == len(model.versions)
623
624 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700625 @memoize
626 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700627 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700628 return self.version_map.keys()
629
Andreas Wundsam5204de22013-07-30 11:34:45 -0700630 def has_version(self, version):
631 return version in self.version_map
632
Andreas Wundsam27303462013-07-16 12:52:35 -0700633 def versioned_class(self, version):
634 return JavaOFClass(self, version, self.version_map[version])
635
636 @property
637 @memoize
638 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700639 return [ self.versioned_class(version) for version in self.all_versions ]
640
641#######################################################################
642### (Versioned) Classes
643#######################################################################
644
645class JavaOFClass(object):
646 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700647 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700648 """
649 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700650 """
651 @param interface JavaOFInterface instance of the parent interface
652 @param version JavaOFVersion
653 @param ir_class OFClass from loxi_ir
654 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700655 self.interface = interface
656 self.ir_class = ir_class
657 self.c_name = self.ir_class.name
658 self.version = version
659 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700660 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700661 self.generated = False
662
663 @property
664 @memoize
665 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700666 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700667
668 @property
669 def name(self):
670 return "%sVer%s" % (self.interface.name, self.version.of_version)
671
672 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700673 def variable_name(self):
674 return self.name[3:]
675
676 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700677 def length(self):
678 if self.is_fixed_length:
679 return self.min_length
680 else:
681 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
682
683 @property
684 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700685 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700686 id_tuple = (self.ir_class.name, self.version.int_version)
687 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
688
689 @property
690 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700691 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700692 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
693 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700694
695 def all_properties(self):
696 return self.interface.members
697
698 def get_member(self, name):
699 for m in self.members:
700 if m.name == name:
701 return m
702
703 @property
704 @memoize
705 def data_members(self):
706 return [ prop for prop in self.members if prop.is_data ]
707
708 @property
709 @memoize
710 def fixed_value_members(self):
711 return [ prop for prop in self.members if prop.is_fixed_value ]
712
713 @property
714 @memoize
715 def public_members(self):
716 return [ prop for prop in self.members if prop.is_public ]
717
718 @property
719 @memoize
720 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700721 return self.ir_model_members + self.virtual_members
722
723 @property
Andreas Wundsama0981022013-10-02 18:15:06 -0700724 @memoize
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700725 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700726 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700727 return tuple(members)
728
729 @property
730 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700731 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700732 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
733 if self.interface.name in model.oxm_map:
734 oxm_entry = model.oxm_map[self.interface.name]
Andreas Wundsama0981022013-10-02 18:15:06 -0700735 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700736 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
737 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
Andreas Wundsama0981022013-10-02 18:15:06 -0700738 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700739 else:
Andreas Wundsama0981022013-10-02 18:15:06 -0700740 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700741 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
742 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
Andreas Wundsama0981022013-10-02 18:15:06 -0700743 ]
744
745 if not find(lambda m: m.name == "version", self.ir_model_members):
746 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version, "OFVersion.%s" % self.version.constant_version))
747
748 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700749
750 def all_versions(self):
751 return [ JavaOFVersion(int_version)
752 for int_version in of_g.unified[self.c_name]
753 if int_version != 'union' and int_version != 'object_id' ]
754
755 def version_is_inherited(self, version):
756 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
757
758 def inherited_from(self, version):
759 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
760
761 @property
762 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700763 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
764
765 @property
766 def discriminator(self):
767 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700768
769 @property
770 def is_extension(self):
771 return type_maps.message_is_extension(self.c_name, -1)
772
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700773 @property
774 def align(self):
775 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
776
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700777 @property
Andreas Wundsam5da68512013-10-22 22:18:00 -0700778 def length_includes_align(self):
779 return self.ir_class.params['length_includes_align'] == "True" if 'length_includes_align' in self.ir_class.params else False
780
781 @property
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700782 @memoize
783 def superclass(self):
784 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
785
786 @property
787 @memoize
788 def subclasses(self):
789 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
790
Andreas Wundsam27303462013-07-16 12:52:35 -0700791#######################################################################
792### Member
793#######################################################################
794
795
796class JavaMember(object):
797 """ Models a property (member) of an openflow class. """
798 def __init__(self, msg, name, java_type, member):
799 self.msg = msg
800 self.name = name
801 self.java_type = java_type
802 self.member = member
803 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700804
805 @property
806 def title_name(self):
807 return self.name[0].upper() + self.name[1:]
808
809 @property
810 def constant_name(self):
811 return self.c_name.upper()
812
813 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700814 def getter_name(self):
815 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
816
817 @property
818 def setter_name(self):
819 return "set" + self.title_name
820
821 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700822 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700823 if self.is_fixed_value:
824 return self.constant_name
825 else:
826 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700827
828 @property
829 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700830 if self.is_fixed_value:
831 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700832 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700833 default = self.java_type.default_op(self.msg.version)
834 if default == "null" and not self.is_nullable:
835 return None
836 else:
837 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700838
839 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700840 def enum_value(self):
841 if self.name == "version":
842 return "OFVersion.%s" % self.msg.version.constant_version
843
844 java_type = self.java_type.public_type;
845 try:
846 global model
847 enum = model.enum_by_name(java_type)
848 entry = enum.entry_by_version_value(self.msg.version, self.value)
849 return "%s.%s" % ( enum.name, entry.name)
850 except KeyError, e:
851 print e.message
852 return self.value
853
854 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700855 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700856 return isinstance(self.member, OFPadMember)
857
858 def is_type_value(self, version=None):
859 if(version==None):
860 return any(self.is_type_value(version) for version in self.msg.all_versions)
861 try:
862 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
863 except:
864 return False
865
866 @property
867 def is_field_length_value(self):
868 return isinstance(self.member, OFFieldLengthMember)
869
870 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700871 def is_discriminator(self):
872 return isinstance(self.member, OFDiscriminatorMember)
873
874 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700875 def is_length_value(self):
876 return isinstance(self.member, OFLengthMember)
877
878 @property
879 def is_public(self):
880 return not (self.is_pad or self.is_length_value)
881
882 @property
883 def is_data(self):
884 return isinstance(self.member, OFDataMember) and self.name != "version"
885
886 @property
887 def is_fixed_value(self):
888 return hasattr(self.member, "value") or self.name == "version" \
889 or ( self.name == "length" and self.msg.is_fixed_length) \
890 or ( self.name == "len" and self.msg.is_fixed_length)
891
892 @property
893 def value(self):
894 if self.name == "version":
895 return self.msg.version.int_version
896 elif self.name == "length" or self.name == "len":
897 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700898 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700899 return self.java_type.format_value(self.member.value)
900
901 @property
902 def priv_value(self):
903 if self.name == "version":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700904 return self.java_type.format_value(self.msg.version.int_version, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700905 elif self.name == "length" or self.name == "len":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700906 return self.java_type.format_value(self.msg.length, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700907 else:
908 return self.java_type.format_value(self.member.value, pub_type=False)
909
Andreas Wundsam27303462013-07-16 12:52:35 -0700910
911 @property
912 def is_writeable(self):
913 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
914
915 def get_type_value_info(self, version):
916 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700917
918 @property
919 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700920 if hasattr(self.member, "length"):
921 return self.member.length
922 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700923 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700924 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700925
926 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700927 def for_of_member(java_class, member):
928 if isinstance(member, OFPadMember):
929 return JavaMember(None, "", None, member)
930 else:
931 if member.name == 'len':
932 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700933 elif member.name == 'value_mask':
934 name = 'mask'
Andreas Wundsamacd57d52013-10-18 17:35:01 -0700935 elif member.name == 'group_id':
936 name = 'group'
Andreas Wundsam27303462013-07-16 12:52:35 -0700937 else:
938 name = java_type.name_c_to_camel(member.name)
939 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
940 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700941
942 @property
943 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700944 if not self.msg.c_name in of_g.unified:
945 print("%s not self.unified" % self.msg.c_name)
946 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700947 for version in of_g.unified[self.msg.c_name]:
948 if version == 'union' or version =='object_id':
949 continue
950 if 'use_version' in of_g.unified[self.msg.c_name][version]:
951 continue
952
Andreas Wundsam27303462013-07-16 12:52:35 -0700953 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 -0700954 return False
955 return True
956
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700957 @property
958 def is_virtual(self):
959 return False
960
Andreas Wundsam27303462013-07-16 12:52:35 -0700961 def __hash__(self):
962 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700963
Andreas Wundsam27303462013-07-16 12:52:35 -0700964 def __eq__(self, other):
965 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700966 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700967 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700968
Andreas Wundsamf1949682013-09-23 14:48:31 -0700969 @property
970 def is_nullable(self):
971 return self.name in model.nullable_map[self.msg.name]
972
973
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700974class JavaVirtualMember(JavaMember):
975 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
976 def __init__(self, msg, name, java_type, value=None):
977 JavaMember.__init__(self, msg, name, java_type, member=None)
978 self._value = value
979
980 @property
981 def is_fixed_value(self):
982 return True
983
984 @property
985 def value(self):
986 return self._value
987
988 @property
989 def priv_value(self):
990 return self._value
991
992
993 @property
994 def is_universal(self):
995 return True
996
997 @property
998 def is_virtual(self):
999 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001000
1001#######################################################################
1002### Unit Test
1003#######################################################################
1004
Yotam Harchol466b3212013-08-15 12:14:46 -07001005class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001006 def __init__(self, java_class):
1007 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -07001008 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001009 name=java_class.c_name[3:])
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001010 glob_file_name = "of{version}/{name}__*.data".format(version=java_class.version.of_version,
1011 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -07001012 test_class_name = self.java_class.name + "Test"
1013 self.test_units = []
1014 if test_data.exists(first_data_file_name):
1015 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001016
Yotam Harchol466b3212013-08-15 12:14:46 -07001017 i = 1
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001018 for f in test_data.glob(glob_file_name):
1019 m = re.match(".*__(.*).data", f)
1020 if m:
1021 suffix = java_type.name_c_to_caps_camel(m.group(1))
1022 else:
1023 suffix = str(i)
1024 i += 1
1025 test_class_name = self.java_class.name + suffix + "Test"
1026 self.test_units.append(JavaUnitTest(java_class, f, test_class_name))
Andreas Wundsamf1949682013-09-23 14:48:31 -07001027
Yotam Harchol466b3212013-08-15 12:14:46 -07001028 @property
1029 def package(self):
1030 return self.java_class.package
1031
1032 @property
1033 def has_test_data(self):
1034 return len(self.test_units) > 0
1035
1036 @property
1037 def length(self):
1038 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -07001039
Yotam Harchol466b3212013-08-15 12:14:46 -07001040 def get_test_unit(self, i):
1041 return self.test_units[i]
1042
1043
1044class JavaUnitTest(object):
1045 def __init__(self, java_class, file_name=None, test_class_name=None):
1046 self.java_class = java_class
1047 if file_name is None:
1048 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
1049 name=java_class.c_name[3:])
1050 else:
1051 self.data_file_name = file_name
1052 if test_class_name is None:
1053 self.test_class_name = self.java_class.name + "Test"
1054 else:
1055 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001056
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001057 @property
1058 def package(self):
1059 return self.java_class.package
1060
1061 @property
1062 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001063 return self.test_class_name
Yotam Harchol595c6442013-09-27 16:29:08 -07001064
1065 @property
1066 def interface(self):
1067 return self.java_class.interface
1068
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001069 @property
1070 def has_test_data(self):
1071 return test_data.exists(self.data_file_name)
1072
1073 @property
1074 @memoize
1075 def test_data(self):
1076 return test_data.read(self.data_file_name)
1077
1078
Andreas Wundsam27303462013-07-16 12:52:35 -07001079#######################################################################
1080### Enums
1081#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001082
Andreas Wundsam27303462013-07-16 12:52:35 -07001083class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001084 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001085 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001086
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001087 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001088
Andreas Wundsam27303462013-07-16 12:52:35 -07001089 # Port_features has constants that start with digits
1090 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001091
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001092 self.version_enums = version_enum_map
1093
1094 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1095 for version, ir_enum in version_enum_map.items():
1096 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001097 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1098
Andreas Wundsam27303462013-07-16 12:52:35 -07001099 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001100 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001101
1102 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 -07001103 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001104
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001105 self.metadata = model.enum_metadata_map[self.name]
1106
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001107 def wire_type(self, version):
1108 ir_enum = self.version_enums[version]
1109 if "wire_type" in ir_enum.params:
1110 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1111 else:
1112 return java_type.u8
1113
1114 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001115 @memoize
1116 def is_bitmask(self):
1117 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1118
1119 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001120 def versions(self):
1121 return self.version_enums.keys()
1122
Andreas Wundsam27303462013-07-16 12:52:35 -07001123 @memoize
1124 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001125 res = find(lambda e: e.name == name, self.entries)
1126 if res:
1127 return res
1128 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001129 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1130
1131 @memoize
1132 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001133 res = find(lambda e: e.c_name == name, self.entries)
1134 if res:
1135 return res
1136 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001137 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1138
1139 @memoize
1140 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001141 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1142 if res:
1143 return res
1144 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001145 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1146
1147# values: Map JavaVersion->Value
1148class JavaEnumEntry(object):
1149 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001150 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001151 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1152 self.values = values
1153
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001154 @property
1155 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001156 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001157
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001158 def has_value(self, version):
1159 return version in self.values
1160
Andreas Wundsam27303462013-07-16 12:52:35 -07001161 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001162 return self.values[version]
1163
1164 def format_value(self, version):
1165 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001166 return res
1167
Andreas Wundsam27303462013-07-16 12:52:35 -07001168 def all_values(self, versions, not_present=None):
1169 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001170
1171 @property
1172 @memoize
1173 def masked_enum_group(self):
1174 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1175 return group
1176
1177 @property
1178 @memoize
1179 def is_mask(self):
1180 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])