blob: c61bf55f1206155d1d8f8711d9d2661af09b6812 [file] [log] [blame]
Matteo Scandolod2044a42017-08-07 16:08:28 -07001# Copyright 2017-present Open Networking Foundation
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
Zack Williams9a42f872019-02-15 17:56:04 -070015from __future__ import absolute_import, print_function
Matteo Scandolod2044a42017-08-07 16:08:28 -070016
Zack Williams9a42f872019-02-15 17:56:04 -070017import copy
18import sys
19
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020020import plyxproto.model as m
Sapan Bhatiadb183c22017-06-23 02:47:42 -070021from plyxproto.helpers import Visitor
Zack Williams9a42f872019-02-15 17:56:04 -070022from six.moves import map, range
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070023
Zack Williams045b63d2019-01-22 16:30:57 -070024
Sapan Bhatiad3fcb662017-07-25 21:13:48 -040025class MissingPolicyException(Exception):
26 pass
27
Zack Williams045b63d2019-01-22 16:30:57 -070028
Sapan Bhatiad3fcb662017-07-25 21:13:48 -040029def find_missing_policy_calls(name, policies, policy):
30 if isinstance(policy, dict):
31 (k, lst), = policy.items()
Zack Williams045b63d2019-01-22 16:30:57 -070032 if k == "policy":
Sapan Bhatiad3fcb662017-07-25 21:13:48 -040033 policy_name = lst[0]
Zack Williams045b63d2019-01-22 16:30:57 -070034 if policy_name not in policies:
35 raise MissingPolicyException(
36 "Policy %s invoked missing policy %s" % (name, policy_name)
37 )
Sapan Bhatiad3fcb662017-07-25 21:13:48 -040038 else:
39 for p in lst:
40 find_missing_policy_calls(name, policies, p)
41 elif isinstance(policy, list):
42 for p in lst:
43 find_missing_policy_calls(name, policies, p)
Matteo Scandolo67654fa2017-06-09 09:33:17 -070044
Zack Williams045b63d2019-01-22 16:30:57 -070045
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020046def dotname_to_fqn(dotname):
47 b_names = [part.pval for part in dotname]
Zack Williams045b63d2019-01-22 16:30:57 -070048 package = ".".join(b_names[:-1])
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020049 name = b_names[-1]
50 if package:
Zack Williams045b63d2019-01-22 16:30:57 -070051 fqn = package + "." + name
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020052 else:
53 fqn = name
Zack Williams045b63d2019-01-22 16:30:57 -070054 return {"name": name, "fqn": fqn, "package": package}
Matteo Scandolo67654fa2017-06-09 09:33:17 -070055
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020056
57def dotname_to_name(dotname):
58 b_names = [part.pval for part in dotname]
Zack Williams045b63d2019-01-22 16:30:57 -070059 return ".".join(b_names)
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020060
61
Sapan Bhatia504cc972017-04-27 01:56:28 +020062def count_messages(body):
63 count = 0
64 for e in body:
Zack Williams045b63d2019-01-22 16:30:57 -070065 if isinstance(e, m.MessageDefinition):
Matteo Scandolo67654fa2017-06-09 09:33:17 -070066 count += 1
Sapan Bhatia504cc972017-04-27 01:56:28 +020067 return count
68
Matteo Scandolo67654fa2017-06-09 09:33:17 -070069
Sapan Bhatia504cc972017-04-27 01:56:28 +020070def count_fields(body):
71 count = 0
72 for e in body:
Zack Williams045b63d2019-01-22 16:30:57 -070073 if type(e) in [m.LinkDefinition, m.FieldDefinition, m.LinkSpec]:
Matteo Scandolo67654fa2017-06-09 09:33:17 -070074 count += 1
Sapan Bhatia504cc972017-04-27 01:56:28 +020075 return count
76
Matteo Scandolo67654fa2017-06-09 09:33:17 -070077
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020078def name_to_value(obj):
79 try:
80 value = obj.value.value.pval
81 except AttributeError:
82 try:
83 value = obj.value.value
84 except AttributeError:
85 value = obj.value.pval
86
87 return value
88
Matteo Scandolo67654fa2017-06-09 09:33:17 -070089
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070090class Stack(list):
Matteo Scandolo67654fa2017-06-09 09:33:17 -070091 def push(self, x):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070092 self.append(x)
93
Matteo Scandolo67654fa2017-06-09 09:33:17 -070094
Zack Williams045b63d2019-01-22 16:30:57 -070095""" XOS2Jinja overrides the underlying visitor pattern to transform the tree
96 in addition to traversing it """
97
Matteo Scandolo67654fa2017-06-09 09:33:17 -070098
Sapan Bhatiadb183c22017-06-23 02:47:42 -070099class XOS2Jinja(Visitor):
Scott Bakerc237f882018-09-28 14:12:47 -0700100 def __init__(self, args):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700101 super(XOS2Jinja, self).__init__()
102
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700103 self.stack = Stack()
104 self.models = {}
105 self.options = {}
106 self.package = None
107 self.message_options = {}
108 self.count_stack = Stack()
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700109 self.policies = {}
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700110 self.content = ""
111 self.offset = 0
112 self.current_message_name = None
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700113 self.verbose = 0
114 self.first_field = True
115 self.first_method = True
Scott Bakerc237f882018-09-28 14:12:47 -0700116 self.args = args
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700117
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700118 def visit_PolicyDefinition(self, obj):
119 if self.package:
Zack Williams045b63d2019-01-22 16:30:57 -0700120 pname = ".".join([self.package, obj.name.value.pval])
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700121 else:
122 pname = obj.name.value.pval
123
124 self.policies[pname] = obj.body
Sapan Bhatiad3fcb662017-07-25 21:13:48 -0400125 find_missing_policy_calls(pname, self.policies, obj.body)
Sapan Bhatia3e3c1cd2017-07-15 01:35:44 -0400126
127 return True
128
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700129 def visit_PackageStatement(self, obj):
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200130 dotlist = obj.name.value
131 dotlist2 = [f.pval for f in dotlist]
Zack Williams045b63d2019-01-22 16:30:57 -0700132 dotstr = ".".join(dotlist2)
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200133 self.package = dotstr
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700134 return True
135
136 def visit_ImportStatement(self, obj):
Zack Williams045b63d2019-01-22 16:30:57 -0700137 """Ignore"""
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700138 return True
139
140 def visit_OptionStatement(self, obj):
Zack Williams045b63d2019-01-22 16:30:57 -0700141 if not hasattr(obj, "mark_for_deletion"):
142 if self.current_message_name:
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200143 self.message_options[obj.name.value.pval] = obj.value.value.pval
144 else:
145 self.options[obj.name.value.pval] = obj.value.value.pval
Sapan Bhatia504cc972017-04-27 01:56:28 +0200146
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700147 return True
148
149 def visit_LU(self, obj):
150 return True
151
152 def visit_default(self, obj):
153 return True
154
155 def visit_FieldDirective(self, obj):
156 return True
157
158 def visit_FieldDirective_post(self, obj):
159
160 try:
161 name = obj.name.value.pval
162 except AttributeError:
163 name = obj.name.value
164
Zack Williams045b63d2019-01-22 16:30:57 -0700165 if isinstance(obj.value, list):
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200166 value = dotname_to_name(obj.value)
167 else:
168 value = name_to_value(obj)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700169
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700170 self.stack.push([name, value])
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700171 return True
172
173 def visit_FieldType(self, obj):
Zack Williams9a42f872019-02-15 17:56:04 -0700174 """
175 Field type, if type is name, then it may need refactoring consistent
176 with refactoring rules according to the table
177 """
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700178 return True
179
180 def visit_LinkDefinition(self, obj):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700181 s = {}
Sapan Bhatia8a57c662017-04-11 10:39:47 -0700182
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200183 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700184 s["link_type"] = obj.link_type.pval
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200185 except AttributeError:
Zack Williams045b63d2019-01-22 16:30:57 -0700186 s["link_type"] = obj.link_type
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200187
Zack Williams045b63d2019-01-22 16:30:57 -0700188 s["src_port"] = obj.src_port.value.pval
189 s["name"] = obj.src_port.value.pval
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700190 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700191 s["policy"] = obj.policy.pval
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700192 except AttributeError:
Zack Williams045b63d2019-01-22 16:30:57 -0700193 s["policy"] = None
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200194
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700195 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700196 s["dst_port"] = obj.dst_port.value.pval
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700197 except AttributeError:
Zack Williams045b63d2019-01-22 16:30:57 -0700198 s["dst_port"] = obj.dst_port
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200199
Zack Williams045b63d2019-01-22 16:30:57 -0700200 if isinstance(obj.through, list):
201 s["through"] = dotname_to_fqn(obj.through)
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200202 else:
203 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700204 s["through"] = obj.through.pval
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200205 except AttributeError:
Zack Williams045b63d2019-01-22 16:30:57 -0700206 s["through"] = obj.through
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200207
Zack Williams045b63d2019-01-22 16:30:57 -0700208 if isinstance(obj.name, list):
209 s["peer"] = dotname_to_fqn(obj.name)
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200210 else:
211 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700212 s["peer"] = obj.name.pval
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200213 except AttributeError:
Zack Williams045b63d2019-01-22 16:30:57 -0700214 s["peer"] = obj.name
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200215
Scott Bakerc237f882018-09-28 14:12:47 -0700216 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700217 s["reverse_id"] = obj.reverse_id.pval
Scott Bakerc237f882018-09-28 14:12:47 -0700218 except AttributeError:
Zack Williams045b63d2019-01-22 16:30:57 -0700219 s["reverse_id"] = obj.reverse_id
Scott Bakerc237f882018-09-28 14:12:47 -0700220
Zack Williams045b63d2019-01-22 16:30:57 -0700221 s["_type"] = "link"
222 s["options"] = {"modifier": "optional"}
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700223
224 self.stack.push(s)
225 return True
226
227 def visit_FieldDefinition(self, obj):
228 self.count_stack.push(len(obj.fieldDirective))
229 return True
230
231 def visit_FieldDefinition_post(self, obj):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700232 s = {}
233
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700234 if isinstance(obj.ftype, m.Name):
Zack Williams045b63d2019-01-22 16:30:57 -0700235 s["type"] = obj.ftype.value
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700236 else:
Zack Williams045b63d2019-01-22 16:30:57 -0700237 s["type"] = obj.ftype.name.pval
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200238
Zack Williams045b63d2019-01-22 16:30:57 -0700239 s["name"] = obj.name.value.pval
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700240
241 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700242 s["policy"] = obj.policy.pval
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700243 except AttributeError:
Zack Williams045b63d2019-01-22 16:30:57 -0700244 s["policy"] = None
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700245
Zack Williams045b63d2019-01-22 16:30:57 -0700246 s["modifier"] = obj.field_modifier.pval
247 s["id"] = obj.fieldId.pval
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700248
Zack Williams045b63d2019-01-22 16:30:57 -0700249 opts = {"modifier": s["modifier"]}
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700250 n = self.count_stack.pop()
251 for i in range(0, n):
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700252 k, v = self.stack.pop()
Sapan Bhatia5769d932017-05-17 11:10:54 +0200253
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700254 # The two lines below may be added to eliminate "" around an option.
Sapan Bhatia5769d932017-05-17 11:10:54 +0200255 # Right now, this is handled in targets. FIXME
256 #
257 # if (v.startswith('"') and v.endswith('"')):
258 # v = v[1:-1]
259
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700260 opts[k] = v
261
Zack Williams045b63d2019-01-22 16:30:57 -0700262 s["options"] = opts
Sapan Bhatia8a57c662017-04-11 10:39:47 -0700263 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700264 last_link = self.stack[-1]["_type"]
265 if last_link == "link":
266 s["link"] = True
267 except BaseException:
Sapan Bhatia8a57c662017-04-11 10:39:47 -0700268 pass
Zack Williams045b63d2019-01-22 16:30:57 -0700269 s["_type"] = "field"
Scott Baker7ae3a8f2019-03-05 16:24:14 -0800270 s["_linespan"] = obj.linespan
Sapan Bhatia8a57c662017-04-11 10:39:47 -0700271
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700272 self.stack.push(s)
273 return True
274
275 def visit_EnumFieldDefinition(self, obj):
276 if self.verbose > 4:
Zack Williams045b63d2019-01-22 16:30:57 -0700277 print("\tEnumField: name=%s, %s" % (obj.name, obj))
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700278
279 return True
280
281 def visit_EnumDefinition(self, obj):
Zack Williams045b63d2019-01-22 16:30:57 -0700282 """New enum definition, refactor name"""
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700283 if self.verbose > 3:
Zack Williams045b63d2019-01-22 16:30:57 -0700284 print("Enum, [%s] body=%s\n\n" % (obj.name, obj.body))
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700285
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700286 return True
287
288 def visit_MessageDefinition(self, obj):
Sapan Bhatia504cc972017-04-27 01:56:28 +0200289 self.current_message_name = obj.name.value.pval
290 self.message_options = {}
291 self.count_stack.push(count_fields(obj.body))
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700292 return True
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700293
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700294 def visit_MessageDefinition_post(self, obj):
295 stack_num = self.count_stack.pop()
296 fields = []
297 links = []
Zack Williams9a42f872019-02-15 17:56:04 -0700298 last_field = {}
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200299 try:
Zack Williams9a42f872019-02-15 17:56:04 -0700300 obj.bases = list(map(dotname_to_fqn, obj.bases))
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200301 except AttributeError:
302 pass
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700303
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700304 for i in range(0, stack_num):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700305 f = self.stack.pop()
Zack Williams045b63d2019-01-22 16:30:57 -0700306 if f["_type"] == "link":
307 f["options"] = {
308 i: d[i] for d in [f["options"], last_field["options"]] for i in d
309 }
310 assert last_field == fields[0]
311 fields[0].setdefault("options", {})["link_type"] = f["link_type"]
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700312 links.insert(0, f)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700313 else:
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700314 fields.insert(0, f)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700315 last_field = f
316
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200317 if self.package:
Zack Williams045b63d2019-01-22 16:30:57 -0700318 model_name = ".".join([self.package, obj.name.value.pval])
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200319 else:
320 model_name = obj.name.value.pval
321
Zack Williams045b63d2019-01-22 16:30:57 -0700322 model_def = {
323 "name": obj.name.value.pval,
324 "fields": fields,
325 "links": links,
326 "bases": obj.bases,
327 "options": self.message_options,
328 "package": self.package,
329 "fqn": model_name,
330 "rlinks": [],
Scott Baker7ae3a8f2019-03-05 16:24:14 -0800331 "_linespan": obj.linespan, # first and last line number
Zack Williams045b63d2019-01-22 16:30:57 -0700332 }
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700333 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700334 model_def["policy"] = obj.policy.pval
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700335 except AttributeError:
Zack Williams045b63d2019-01-22 16:30:57 -0700336 model_def["policy"] = None
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700337
Sapan Bhatia943dad52017-05-19 18:41:01 +0200338 self.stack.push(model_def)
Zack Williams045b63d2019-01-22 16:30:57 -0700339
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200340 self.models[model_name] = model_def
341
342 # Set message options
Zack Williams9a42f872019-02-15 17:56:04 -0700343 for k, v in sorted(self.options.items(), key=lambda t: t[0]): # sorted by key
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200344 try:
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200345 if k not in self.message_options:
346 self.message_options[k] = v
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200347 except KeyError:
348 pass
349
Sapan Bhatia504cc972017-04-27 01:56:28 +0200350 self.current_message_name = None
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700351 return True
352
353 def visit_MessageExtension(self, obj):
354 return True
355
356 def visit_MethodDefinition(self, obj):
357 return True
358
359 def visit_ServiceDefinition(self, obj):
360 return True
361
362 def visit_ExtensionsDirective(self, obj):
363 return True
364
365 def visit_Literal(self, obj):
366 return True
367
368 def visit_Name(self, obj):
369 return True
370
371 def visit_DotName(self, obj):
372 return True
373
374 def visit_Proto(self, obj):
Sapan Bhatia504cc972017-04-27 01:56:28 +0200375 self.count_stack.push(count_messages(obj.body))
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700376 return True
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700377
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700378 def visit_Proto_post(self, obj):
379 count = self.count_stack.pop()
380 messages = []
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700381 for i in range(0, count):
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200382 try:
383 m = self.stack.pop()
384 except IndexError:
Sapan Bhatia504cc972017-04-27 01:56:28 +0200385 pass
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200386
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700387 messages.insert(0, m)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700388
Scott Bakerc237f882018-09-28 14:12:47 -0700389 self.compute_rlinks(messages, self.models)
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200390
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700391 self.messages = messages
392 return True
393
394 def visit_LinkSpec(self, obj):
395 count = self.count_stack.pop()
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700396 self.count_stack.push(count + 1)
Sapan Bhatiadb183c22017-06-23 02:47:42 -0700397 return True
Scott Bakerc237f882018-09-28 14:12:47 -0700398
399 def compute_rlinks(self, messages, message_dict):
400 rev_links = {}
401
402 link_opposite = {
Zack Williams045b63d2019-01-22 16:30:57 -0700403 "manytomany": "manytomany",
404 "manytoone": "onetomany",
405 "onetoone": "onetoone",
406 "onetomany": "manytoone",
Scott Bakerc237f882018-09-28 14:12:47 -0700407 }
408
Zack Williams9a42f872019-02-15 17:56:04 -0700409 for msg in messages:
410 for lnk in msg["links"]:
411 rlink = copy.deepcopy(lnk)
Scott Bakerc237f882018-09-28 14:12:47 -0700412
Zack Williams045b63d2019-01-22 16:30:57 -0700413 rlink["_type"] = "rlink" # An implicit link, not declared in the model
Zack Williams9a42f872019-02-15 17:56:04 -0700414 rlink["src_port"] = lnk["dst_port"]
415 rlink["dst_port"] = lnk["src_port"]
Zack Williams045b63d2019-01-22 16:30:57 -0700416 rlink["peer"] = {
Zack Williams9a42f872019-02-15 17:56:04 -0700417 "name": msg["name"],
418 "package": msg["package"],
419 "fqn": msg["fqn"],
Zack Williams045b63d2019-01-22 16:30:57 -0700420 }
Zack Williams9a42f872019-02-15 17:56:04 -0700421 rlink["link_type"] = link_opposite[lnk["link_type"]]
422 rlink["reverse_id"] = lnk["reverse_id"]
Scott Bakerc237f882018-09-28 14:12:47 -0700423
Zack Williams9a42f872019-02-15 17:56:04 -0700424 if (not lnk["reverse_id"]) and (self.args.verbosity >= 1):
Zack Williams045b63d2019-01-22 16:30:57 -0700425 print(
426 "WARNING: Field %s in model %s has no reverse_id"
Zack Williams9a42f872019-02-15 17:56:04 -0700427 % (lnk["src_port"], msg["name"]),
Zack Williams045b63d2019-01-22 16:30:57 -0700428 file=sys.stderr,
429 )
Scott Bakerc237f882018-09-28 14:12:47 -0700430
Zack Williams9a42f872019-02-15 17:56:04 -0700431 if lnk["reverse_id"] and (
432 (int(lnk["reverse_id"]) < 1000) or (int(lnk["reverse_id"]) >= 1900)
Zack Williams045b63d2019-01-22 16:30:57 -0700433 ):
434 raise Exception(
435 "reverse id for field %s in model %s should be between 1000 and 1899"
Zack Williams9a42f872019-02-15 17:56:04 -0700436 % (lnk["src_port"], msg["name"])
Zack Williams045b63d2019-01-22 16:30:57 -0700437 )
Scott Bakerc237f882018-09-28 14:12:47 -0700438
439 try:
440 try:
Zack Williams9a42f872019-02-15 17:56:04 -0700441 rev_links[lnk["peer"]["fqn"]].append(rlink)
Scott Bakerc237f882018-09-28 14:12:47 -0700442 except TypeError:
443 pass
444 except KeyError:
Zack Williams9a42f872019-02-15 17:56:04 -0700445 rev_links[lnk["peer"]["fqn"]] = [rlink]
Scott Bakerc237f882018-09-28 14:12:47 -0700446
Zack Williams9a42f872019-02-15 17:56:04 -0700447 for msg in messages:
Scott Bakerc237f882018-09-28 14:12:47 -0700448 try:
Zack Williams9a42f872019-02-15 17:56:04 -0700449 msg["rlinks"] = rev_links[msg["name"]]
450 message_dict[msg["name"]]["rlinks"] = msg["rlinks"]
Scott Bakerc237f882018-09-28 14:12:47 -0700451 except KeyError:
452 pass