blob: 185fb59b5801072451c9f020fa22e459a3c8a6ce [file] [log] [blame]
Stephane Barbarie6e1bd502018-11-05 22:44:45 -05001#
2# Copyright 2017 the original author or authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17"""
18Convert loxi objects to openflow_13 messages and back.
19"""
20from copy import copy
21
22from google.protobuf.descriptor import FieldDescriptor
23
24import loxi.of13 as of13
25from protobuf_to_dict import protobuf_to_dict, TYPE_CALLABLE_MAP
William Kurkianfc0dcda2019-04-08 16:54:36 -040026from voltha_protos import openflow_13_pb2 as pb2
Stephane Barbarie6e1bd502018-11-05 22:44:45 -050027
28
29type_callable_map = copy(TYPE_CALLABLE_MAP)
30type_callable_map.update({
31 FieldDescriptor.TYPE_STRING: str
32})
33
34def pb2dict(pb):
35 """
36 Convert protobuf to a dict of values good for instantiating
37 loxi objects (or any other objects). We specialize the protobuf_to_dict
38 library call with our modified decoders.
39 :param pb: protobuf as loaded into Python
40 :return: dict of values
41 """
42 return protobuf_to_dict(pb, type_callable_map)
43
44def to_loxi(grpc_object):
45 cls = grpc_object.__class__
46 converter = to_loxi_converters[cls.__name__]
47 return converter(grpc_object)
48
49def to_grpc(loxi_object):
50 cls = loxi_object.__class__
51 converter = to_grpc_converters[cls]
52 return converter(loxi_object)
53
54def ofp_port_to_loxi_port_desc(pb):
55 kw = pb2dict(pb)
56 return of13.common.port_desc(**kw)
57
58def ofp_port_status_to_loxi_port_status(pb):
59 return of13.message.port_status(
60 reason=pb.reason,
61 desc=ofp_port_to_loxi_port_desc(pb.desc)
62 )
63
64def ofp_port_stats_to_loxi_port_stats(pb):
65 kw = pb2dict(pb)
66 return of13.port_stats_entry(**kw)
67
68def make_loxi_field(oxm_field):
69 assert oxm_field['oxm_class'] == pb2.OFPXMC_OPENFLOW_BASIC
70 ofb_field = oxm_field['ofb_field']
71 field_type = ofb_field.get('type', 0)
72
73 if field_type == pb2.OFPXMT_OFB_ETH_TYPE:
74 return (
75 of13.oxm.eth_type(value=ofb_field['eth_type']))
76
77 elif field_type == pb2.OFPXMT_OFB_IN_PORT:
78 return (
79 of13.oxm.in_port(value=ofb_field['port']))
80
81 elif field_type == pb2.OFPXMT_OFB_IP_PROTO:
82 return (
83 of13.oxm.ip_proto(value=ofb_field['ip_proto']))
84
85 elif field_type == pb2.OFPXMT_OFB_VLAN_VID:
86 return (
87 of13.oxm.vlan_vid(value=ofb_field['vlan_vid']))
88
89 elif field_type == pb2.OFPXMT_OFB_VLAN_PCP:
90 return (
91 of13.oxm.vlan_pcp(value=ofb_field['vlan_pcp']))
92
93 elif field_type == pb2.OFPXMT_OFB_IPV4_SRC:
94 return (
95 of13.oxm.ipv4_src(value=ofb_field['ipv4_src']))
96
97 elif field_type == pb2.OFPXMT_OFB_IPV4_DST:
98 return (
99 of13.oxm.ipv4_dst(value=ofb_field['ipv4_dst']))
100
101 elif field_type == pb2.OFPXMT_OFB_UDP_SRC:
102 return (
103 of13.oxm.udp_src(value=ofb_field['udp_src']))
104
105 elif field_type == pb2.OFPXMT_OFB_UDP_DST:
106 return (
107 of13.oxm.udp_dst(value=ofb_field['udp_dst']))
108
109 elif field_type == pb2.OFPXMT_OFB_METADATA:
110 return (
111 of13.oxm.metadata(value=ofb_field['table_metadata']))
112
113 else:
114 raise NotImplementedError(
115 'OXM match field for type %s' % field_type)
116
117def make_loxi_match(match):
118 assert match.get('type', pb2.OFPMT_STANDARD) == pb2.OFPMT_OXM
119 loxi_match_fields = []
120 for oxm_field in match.get('oxm_fields', []):
121 loxi_match_fields.append(make_loxi_field(oxm_field))
122 return of13.match_v3(oxm_list=loxi_match_fields)
123
124
125def make_loxi_action(a):
126 if type(a) is not dict:
127 a = pb2dict(a)
128
129 typ = a.get('type', 0)
130
131 if typ == pb2.OFPAT_OUTPUT:
132 output_kws = a['output']
133 return of13.action.output(**output_kws)
134
135 elif typ == pb2.OFPAT_POP_VLAN:
136 return of13.action.pop_vlan()
137
138 elif typ == pb2.OFPAT_PUSH_VLAN:
139 push_vlan_kws = a['push']
140 return of13.action.push_vlan(**push_vlan_kws)
141
142 elif typ == pb2.OFPAT_SET_FIELD:
143 loxi_field = make_loxi_field(a['set_field']['field'])
144 return of13.action.set_field(loxi_field)
145
146 elif typ == pb2.OFPAT_GROUP:
147 group_kws = a['group']
148 return of13.action.group(**group_kws)
149
150 else:
151 raise NotImplementedError(
152 'Action decoder for action OFPAT_* %d' % typ)
153
154
155def ofp_flow_stats_to_loxi_flow_stats(pb):
156 kw = pb2dict(pb)
157
158 def make_loxi_instruction(inst):
159 type = inst['type']
160 if type == pb2.OFPIT_APPLY_ACTIONS:
161 return of13.instruction.apply_actions(
162 actions=[make_loxi_action(a)
163 for a in inst['actions']['actions']])
164 elif type == pb2.OFPIT_CLEAR_ACTIONS:
165 return of13.instruction.clear_actions()
166 elif type == pb2.OFPIT_GOTO_TABLE:
167 return of13.instruction.goto_table(
168 table_id=inst['goto_table']['table_id'])
Daniele Rossi9ab99b72019-07-12 08:51:55 +0000169 elif type == pb2.OFPIT_WRITE_ACTIONS:
170 return of13.instruction.write_actions(
171 actions=[make_loxi_action(a)
172 for a in inst['actions']['actions']])
173 elif type == pb2.OFPIT_WRITE_METADATA:
174 if 'metadata' in inst['write_metadata']:
175 return of13.instruction.write_metadata(
176 metadata=inst['write_metadata']['metadata'])
177 else:
178 return of13.instruction.write_metadata(0)
179 elif type == pb2.OFPIT_METER:
180 return of13.instruction.meter(
181 meter_id=inst['meter']['meter_id'])
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500182 else:
183 raise NotImplementedError('Instruction type %d' % type)
184
185 kw['match'] = make_loxi_match(kw['match'])
Daniele Rossi9ab99b72019-07-12 08:51:55 +0000186 # if the flow action is drop, then the instruction is not found in the dict
187 if 'instructions' in kw:
188 kw['instructions'] = [make_loxi_instruction(i) for i in kw['instructions']]
Stephane Barbarie6e1bd502018-11-05 22:44:45 -0500189 del kw['id']
190 return of13.flow_stats_entry(**kw)
191
192
193def ofp_packet_in_to_loxi_packet_in(pb):
194 packet_in = of13.message.packet_in(
195 buffer_id=pb.buffer_id,
196 reason=pb.reason,
197 table_id=pb.table_id,
198 cookie=pb.cookie,
199 match=make_loxi_match(pb2dict(pb.match)),
200 data=pb.data
201 )
202 return packet_in
203
204def ofp_group_desc_to_loxi_group_desc(pb):
205 return of13.group_desc_stats_entry(
206 group_type=pb.type,
207 group_id=pb.group_id,
208 buckets=[to_loxi(bucket) for bucket in pb.buckets])
209
210
211def ofp_group_stats_to_loxi_group_stats(pb):
212 return of13.group_stats_entry(
213 group_id=pb.group_id,
214 ref_count=pb.ref_count,
215 packet_count=pb.packet_count,
216 byte_count=pb.byte_count,
217 duration_sec=pb.duration_sec,
218 duration_nsec=pb.duration_nsec,
219 bucket_stats=[to_loxi(bstat) for bstat in pb.bucket_stats])
220
221
222def ofp_bucket_counter_to_loxy_bucket_counter(pb):
223 return of13.bucket_counter(
224 packet_count=pb.packet_count,
225 byte_count=pb.byte_count)
226
227
228def ofp_bucket_to_loxi_bucket(pb):
229 return of13.bucket(
230 weight=pb.weight,
231 watch_port=pb.watch_port,
232 watch_group=pb.watch_group,
233 actions=[to_loxi(action) for action in pb.actions]
234 )
235
236
237to_loxi_converters = {
238 'ofp_port': ofp_port_to_loxi_port_desc,
239 'ofp_port_status': ofp_port_status_to_loxi_port_status,
240 'ofp_flow_stats': ofp_flow_stats_to_loxi_flow_stats,
241 'ofp_packet_in': ofp_packet_in_to_loxi_packet_in,
242 'ofp_group_stats': ofp_group_stats_to_loxi_group_stats,
243 'ofp_group_desc': ofp_group_desc_to_loxi_group_desc,
244 'ofp_bucket_counter': ofp_bucket_counter_to_loxy_bucket_counter,
245 'ofp_bucket': ofp_bucket_to_loxi_bucket,
246 'ofp_action': make_loxi_action,
247 'ofp_port_stats': ofp_port_stats_to_loxi_port_stats
248}
249
250
251def loxi_flow_mod_to_ofp_flow_mod(lo):
252 return pb2.ofp_flow_mod(
253 cookie=lo.cookie,
254 cookie_mask=lo.cookie_mask,
255 table_id=lo.table_id,
256 command=lo._command,
257 idle_timeout=lo.idle_timeout,
258 hard_timeout=lo.hard_timeout,
259 priority=lo.priority,
260 buffer_id=lo.buffer_id,
261 out_port=lo.out_port,
262 out_group=lo.out_group,
263 flags=lo.flags,
264 match=to_grpc(lo.match),
265 instructions=[to_grpc(i) for i in lo.instructions])
266
267
268def loxi_group_mod_to_ofp_group_mod(lo):
269 return pb2.ofp_group_mod(
270 command=lo.command,
271 type=lo.group_type,
272 group_id=lo.group_id,
273 buckets=[to_grpc(b) for b in lo.buckets])
274
275
276def loxi_packet_out_to_ofp_packet_out(lo):
277 return pb2.ofp_packet_out(
278 buffer_id=lo.buffer_id,
279 in_port=lo.in_port,
280 actions=[to_grpc(a) for a in lo.actions],
281 data=lo.data)
282
283
284def loxi_match_v3_to_ofp_match(lo):
285 return pb2.ofp_match(
286 type=pb2.OFPMT_OXM,
287 oxm_fields=[to_grpc(f) for f in lo.oxm_list])
288
289
290def loxi_bucket_to_ofp_bucket(lo):
291 return pb2.ofp_bucket(
292 weight=lo.weight,
293 watch_port=lo.watch_port,
294 watch_group=lo.watch_group,
295 actions=[to_grpc(a) for a in lo.actions])
296
297
298def loxi_oxm_eth_type_to_ofp_oxm(lo):
299 return pb2.ofp_oxm_field(
300 oxm_class=pb2.OFPXMC_OPENFLOW_BASIC,
301 ofb_field=pb2.ofp_oxm_ofb_field(
302 type=pb2.OFPXMT_OFB_ETH_TYPE,
303 eth_type=lo.value))
304
305
306def loxi_oxm_in_port_to_ofp_oxm(lo):
307 return pb2.ofp_oxm_field(
308 oxm_class=pb2.OFPXMC_OPENFLOW_BASIC,
309 ofb_field=pb2.ofp_oxm_ofb_field(
310 type=pb2.OFPXMT_OFB_IN_PORT,
311 port=lo.value))
312
313
314def loxi_oxm_ip_proto_to_ofp_oxm(lo):
315 return pb2.ofp_oxm_field(
316 oxm_class=pb2.OFPXMC_OPENFLOW_BASIC,
317 ofb_field=pb2.ofp_oxm_ofb_field(
318 type=pb2.OFPXMT_OFB_IP_PROTO,
319 ip_proto=lo.value))
320
321
322def loxi_oxm_vlan_vid_to_ofp_oxm(lo):
323 return pb2.ofp_oxm_field(
324 oxm_class=pb2.OFPXMC_OPENFLOW_BASIC,
325 ofb_field=pb2.ofp_oxm_ofb_field(
326 type=pb2.OFPXMT_OFB_VLAN_VID,
327 vlan_vid=lo.value))
328
329
330def loxi_oxm_vlan_pcp_to_ofp_oxm(lo):
331 return pb2.ofp_oxm_field(
332 oxm_class=pb2.OFPXMC_OPENFLOW_BASIC,
333 ofb_field=pb2.ofp_oxm_ofb_field(
334 type=pb2.OFPXMT_OFB_VLAN_PCP,
335 vlan_pcp=lo.value))
336
337
338def loxi_oxm_ipv4_dst_to_ofp_oxm(lo):
339 return pb2.ofp_oxm_field(
340 oxm_class=pb2.OFPXMC_OPENFLOW_BASIC,
341 ofb_field=pb2.ofp_oxm_ofb_field(
342 type=pb2.OFPXMT_OFB_IPV4_DST,
343 ipv4_dst=lo.value))
344
345
346def loxi_oxm_udp_dst_to_ofp_oxm(lo):
347 return pb2.ofp_oxm_field(
348 oxm_class=pb2.OFPXMC_OPENFLOW_BASIC,
349 ofb_field=pb2.ofp_oxm_ofb_field(
350 type=pb2.OFPXMT_OFB_UDP_DST,
351 udp_dst=lo.value))
352
353
354def loxi_oxm_udp_src_to_ofp_oxm(lo):
355 return pb2.ofp_oxm_field(
356 oxm_class=pb2.OFPXMC_OPENFLOW_BASIC,
357 ofb_field=pb2.ofp_oxm_ofb_field(
358 type=pb2.OFPXMT_OFB_UDP_SRC,
359 udp_src=lo.value))
360
361
362def loxi_oxm_metadata_to_ofp_oxm(lo):
363 return pb2.ofp_oxm_field(
364 oxm_class=pb2.OFPXMC_OPENFLOW_BASIC,
365 ofb_field=pb2.ofp_oxm_ofb_field(
366 type=pb2.OFPXMT_OFB_METADATA,
367 table_metadata=lo.value))
368
369
370def loxi_apply_actions_to_ofp_instruction(lo):
371 return pb2.ofp_instruction(
372 type=pb2.OFPIT_APPLY_ACTIONS,
373 actions=pb2.ofp_instruction_actions(
374 actions=[to_grpc(a) for a in lo.actions]))
375
376def loxi_clear_actions_to_ofp_instruction(lo):
377 return pb2.ofp_instruction(
378 type=pb2.OFPIT_CLEAR_ACTIONS)
379
380
381def loxi_goto_table_to_ofp_instruction(lo):
382 return pb2.ofp_instruction(
383 type=pb2.OFPIT_GOTO_TABLE,
384 goto_table=pb2.ofp_instruction_goto_table(table_id=lo.table_id))
385
386
387def loxi_output_action_to_ofp_action(lo):
388 return pb2.ofp_action(
389 type=pb2.OFPAT_OUTPUT,
390 output=pb2.ofp_action_output(port=lo.port, max_len=lo.max_len))
391
392
393def loxi_group_action_to_ofp_action(lo):
394 return pb2.ofp_action(
395 type=pb2.OFPAT_GROUP,
396 group=pb2.ofp_action_group(group_id=lo.group_id))
397
398
399def loxi_set_field_action_to_ofp_action(lo):
400 return pb2.ofp_action(
401 type=pb2.OFPAT_SET_FIELD,
402 set_field=pb2.ofp_action_set_field(field=to_grpc(lo.field)))
403
404
405def loxi_pop_vlan_action_to_ofp_action(lo):
406 return pb2.ofp_action(type=pb2.OFPAT_POP_VLAN)
407
408
409def loxi_push_vlan_action_to_ofp_action(lo):
410 return pb2.ofp_action(
411 type=pb2.OFPAT_PUSH_VLAN,
412 push=pb2.ofp_action_push(ethertype=lo.ethertype))
413
414
415to_grpc_converters = {
416
417 of13.message.flow_add: loxi_flow_mod_to_ofp_flow_mod,
418 of13.message.flow_delete: loxi_flow_mod_to_ofp_flow_mod,
419 of13.message.flow_delete_strict: loxi_flow_mod_to_ofp_flow_mod,
420 of13.message.flow_modify: loxi_flow_mod_to_ofp_flow_mod,
421 of13.message.flow_modify_strict: loxi_flow_mod_to_ofp_flow_mod,
422
423 of13.message.group_add: loxi_group_mod_to_ofp_group_mod,
424 of13.message.group_delete: loxi_group_mod_to_ofp_group_mod,
425 of13.message.group_modify: loxi_group_mod_to_ofp_group_mod,
426 of13.message.packet_out: loxi_packet_out_to_ofp_packet_out,
427
428 of13.common.match_v3: loxi_match_v3_to_ofp_match,
429 of13.common.bucket: loxi_bucket_to_ofp_bucket,
430
431 of13.oxm.eth_type: loxi_oxm_eth_type_to_ofp_oxm,
432 of13.oxm.in_port: loxi_oxm_in_port_to_ofp_oxm,
433 of13.oxm.ip_proto: loxi_oxm_ip_proto_to_ofp_oxm,
434 of13.oxm.vlan_vid: loxi_oxm_vlan_vid_to_ofp_oxm,
435 of13.oxm.vlan_pcp: loxi_oxm_vlan_pcp_to_ofp_oxm,
436 of13.oxm.ipv4_dst: loxi_oxm_ipv4_dst_to_ofp_oxm,
437 of13.oxm.udp_src: loxi_oxm_udp_src_to_ofp_oxm,
438 of13.oxm.udp_dst: loxi_oxm_udp_dst_to_ofp_oxm,
439 of13.oxm.metadata: loxi_oxm_metadata_to_ofp_oxm,
440
441 of13.instruction.apply_actions: loxi_apply_actions_to_ofp_instruction,
442 of13.instruction.clear_actions: loxi_clear_actions_to_ofp_instruction,
443 of13.instruction.goto_table: loxi_goto_table_to_ofp_instruction,
444
445 of13.action.output: loxi_output_action_to_ofp_action,
446 of13.action.group: loxi_group_action_to_ofp_action,
447 of13.action.set_field: loxi_set_field_action_to_ofp_action,
448 of13.action.pop_vlan: loxi_pop_vlan_action_to_ofp_action,
449 of13.action.push_vlan: loxi_push_vlan_action_to_ofp_action,
450}