backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / lib / ofctl_utils.py
1 # Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
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
12 # implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 import base64
17 import logging
18
19 import netaddr
20 import six
21
22 from ryu.lib import dpid
23 from ryu.lib import hub
24 from ryu.ofproto import ofproto_v1_2
25
26
27 LOG = logging.getLogger(__name__)
28 DEFAULT_TIMEOUT = 1.0
29
30 # NOTE(jkoelker) Constants for converting actions
31 OUTPUT = 'OUTPUT'
32 COPY_TTL_OUT = 'COPY_TTL_OUT'
33 COPY_TTL_IN = 'COPY_TTL_IN'
34 SET_MPLS_TTL = 'SET_MPLS_TTL'
35 DEC_MPLS_TTL = 'DEC_MPLS_TTL'
36 PUSH_VLAN = 'PUSH_VLAN'
37 POP_VLAN = 'POP_VLAN'
38 PUSH_MPLS = 'PUSH_MPLS'
39 POP_MPLS = 'POP_MPLS'
40 SET_QUEUE = 'SET_QUEUE'
41 GROUP = 'GROUP'
42 SET_NW_TTL = 'SET_NW_TTL'
43 DEC_NW_TTL = 'DEC_NW_TTL'
44 SET_FIELD = 'SET_FIELD'
45 PUSH_PBB = 'PUSH_PBB'      # OpenFlow 1.3 or later
46 POP_PBB = 'POP_PBB'        # OpenFlow 1.3 or later
47 COPY_FIELD = 'COPY_FIELD'  # OpenFlow 1.5 or later
48 METER = 'METER'            # OpenFlow 1.5 or later
49 EXPERIMENTER = 'EXPERIMENTER'
50
51
52 def get_logger(logger=None):
53     # NOTE(jkoelker) use the logger the calling code wants us to
54     if logger is not None:
55         return logger
56
57     return LOG
58
59
60 def match_vid_to_str(value, mask, ofpvid_present):
61     if mask is not None:
62         return '0x%04x/0x%04x' % (value, mask)
63
64     if value & ofpvid_present:
65         return str(value & ~ofpvid_present)
66
67     return '0x%04x' % value
68
69
70 def to_action(dic, ofp, parser, action_type, util):
71     actions = {COPY_TTL_OUT: parser.OFPActionCopyTtlOut,
72                COPY_TTL_IN: parser.OFPActionCopyTtlIn,
73                DEC_MPLS_TTL: parser.OFPActionDecMplsTtl,
74                POP_VLAN: parser.OFPActionPopVlan,
75                DEC_NW_TTL: parser.OFPActionDecNwTtl}
76     if ofp.OFP_VERSION > ofproto_v1_2.OFP_VERSION:
77         actions[POP_PBB] = parser.OFPActionPopPbb
78
79     need_ethertype = {PUSH_VLAN: parser.OFPActionPushVlan,
80                       PUSH_MPLS: parser.OFPActionPushMpls,
81                       POP_MPLS: parser.OFPActionPopMpls}
82     if ofp.OFP_VERSION > ofproto_v1_2.OFP_VERSION:
83         need_ethertype[PUSH_PBB] = parser.OFPActionPushPbb
84
85     if action_type in actions:
86         return actions[action_type]()
87
88     elif action_type in need_ethertype:
89         ethertype = str_to_int(dic.get('ethertype'))
90         return need_ethertype[action_type](ethertype)
91
92     elif action_type == OUTPUT:
93         out_port = util.ofp_port_from_user(dic.get('port', ofp.OFPP_ANY))
94         max_len = util.ofp_cml_from_user(dic.get('max_len', ofp.OFPCML_MAX))
95         return parser.OFPActionOutput(out_port, max_len)
96
97     elif action_type == SET_MPLS_TTL:
98         mpls_ttl = str_to_int(dic.get('mpls_ttl'))
99         return parser.OFPActionSetMplsTtl(mpls_ttl)
100
101     elif action_type == SET_QUEUE:
102         queue_id = util.ofp_queue_from_user(dic.get('queue_id'))
103         return parser.OFPActionSetQueue(queue_id)
104
105     elif action_type == GROUP:
106         group_id = util.ofp_group_from_user(dic.get('group_id'))
107         return parser.OFPActionGroup(group_id)
108
109     elif action_type == SET_NW_TTL:
110         nw_ttl = str_to_int(dic.get('nw_ttl'))
111         return parser.OFPActionSetNwTtl(nw_ttl)
112
113     elif action_type == SET_FIELD:
114         field = dic.get('field')
115         value = dic.get('value')
116         return parser.OFPActionSetField(**{field: value})
117
118     elif action_type == 'COPY_FIELD':
119         n_bits = str_to_int(dic.get('n_bits'))
120         src_offset = str_to_int(dic.get('src_offset'))
121         dst_offset = str_to_int(dic.get('dst_offset'))
122         oxm_ids = [parser.OFPOxmId(str(dic.get('src_oxm_id'))),
123                    parser.OFPOxmId(str(dic.get('dst_oxm_id')))]
124         return parser.OFPActionCopyField(
125             n_bits, src_offset, dst_offset, oxm_ids)
126
127     elif action_type == 'METER':
128         if hasattr(parser, 'OFPActionMeter'):
129             # OpenFlow 1.5 or later
130             meter_id = str_to_int(dic.get('meter_id'))
131             return parser.OFPActionMeter(meter_id)
132         else:
133             # OpenFlow 1.4 or earlier
134             return None
135
136     elif action_type == EXPERIMENTER:
137         experimenter = str_to_int(dic.get('experimenter'))
138         data_type = dic.get('data_type', 'ascii')
139
140         if data_type not in ('ascii', 'base64'):
141             LOG.error('Unknown data type: %s', data_type)
142             return None
143
144         data = dic.get('data', '')
145         if data_type == 'base64':
146             data = base64.b64decode(data)
147         return parser.OFPActionExperimenterUnknown(experimenter, data)
148
149     return None
150
151
152 def to_match_eth(value):
153     if '/' in value:
154         value = value.split('/')
155         return value[0], value[1]
156
157     return value
158
159
160 def to_match_ip(value):
161     if '/' in value:
162         (ip_addr, ip_mask) = value.split('/')
163
164         if ip_mask.isdigit():
165             ip = netaddr.ip.IPNetwork(value)
166             ip_addr = str(ip.ip)
167             ip_mask = str(ip.netmask)
168
169         return ip_addr, ip_mask
170
171     return value
172
173
174 def to_match_vid(value, ofpvid_present):
175     # NOTE: If "vlan_id" field is described as decimal int value
176     #       (and decimal string value), it is treated as values of
177     #       VLAN tag, and OFPVID_PRESENT(0x1000) bit is automatically
178     #       applied. OTOH, If it is described as hexadecimal string,
179     #       treated as values of oxm_value (including OFPVID_PRESENT
180     #       bit), and OFPVID_PRESENT bit is NOT automatically applied
181     if isinstance(value, six.integer_types):
182         # described as decimal int value
183         return value | ofpvid_present
184
185     else:
186         if '/' in value:
187             val = value.split('/')
188             return str_to_int(val[0]), str_to_int(val[1])
189
190         else:
191             if value.isdigit():
192                 # described as decimal string value
193                 return int(value, 10) | ofpvid_present
194
195             return str_to_int(value)
196
197
198 def to_match_masked_int(value):
199     if isinstance(value, str) and '/' in value:
200         value = value.split('/')
201         return str_to_int(value[0]), str_to_int(value[1])
202
203     return str_to_int(value)
204
205
206 def to_match_packet_type(value):
207     if isinstance(value, (list, tuple)):
208         return str_to_int(value[0]) << 16 | str_to_int(value[1])
209     else:
210         return str_to_int(value)
211
212
213 def send_experimenter(dp, exp, logger=None):
214     experimenter = exp.get('experimenter', 0)
215     exp_type = exp.get('exp_type', 0)
216     data_type = exp.get('data_type', 'ascii')
217
218     data = exp.get('data', '')
219     if data_type == 'base64':
220         data = base64.b64decode(data)
221     elif data_type == 'ascii':
222         data = data.encode('ascii')
223     else:
224         get_logger(logger).error('Unknown data type: %s', data_type)
225         return
226
227     expmsg = dp.ofproto_parser.OFPExperimenter(
228         dp, experimenter, exp_type, data)
229     send_msg(dp, expmsg, logger)
230
231
232 def send_msg(dp, msg, logger=None):
233     if msg.xid is None:
234         dp.set_xid(msg)
235
236     log = get_logger(logger)
237     # NOTE(jkoelker) Prevent unnecessary string formating by including the
238     #                format rules in the log_msg
239     log_msg = ('Sending message with xid(%x) to '
240                'datapath(' + dpid._DPID_FMT + '): %s')
241     log.debug(log_msg, msg.xid, dp.id, msg)
242     dp.send_msg(msg)
243
244
245 def send_stats_request(dp, stats, waiters, msgs, logger=None):
246     dp.set_xid(stats)
247     waiters_per_dp = waiters.setdefault(dp.id, {})
248     lock = hub.Event()
249     previous_msg_len = len(msgs)
250     waiters_per_dp[stats.xid] = (lock, msgs)
251     send_msg(dp, stats, logger)
252
253     lock.wait(timeout=DEFAULT_TIMEOUT)
254     current_msg_len = len(msgs)
255
256     while current_msg_len > previous_msg_len:
257         previous_msg_len = current_msg_len
258         lock.wait(timeout=DEFAULT_TIMEOUT)
259         current_msg_len = len(msgs)
260
261     if not lock.is_set():
262         del waiters_per_dp[stats.xid]
263
264
265 def str_to_int(str_num):
266     return int(str(str_num), 0)
267
268
269 def get_role(dp, waiters, to_user):
270     stats = dp.ofproto_parser.OFPRoleRequest(
271         dp, dp.ofproto.OFPCR_ROLE_NOCHANGE, generation_id=0)
272     msgs = []
273     send_stats_request(dp, stats, waiters, msgs, LOG)
274     descs = []
275
276     for msg in msgs:
277         d = msg.to_jsondict()[msg.__class__.__name__]
278         if to_user:
279             d['role'] = OFCtlUtil(dp.ofproto).ofp_role_to_user(d['role'])
280         descs.append(d)
281
282     return {str(dp.id): descs}
283
284
285 class OFCtlUtil(object):
286
287     def __init__(self, ofproto):
288         self.ofproto = ofproto
289         self.deprecated_value = [
290             'OFPTFPT_EXPERIMENTER_SLAVE',
291             'OFPTFPT_EXPERIMENTER_MASTER',
292             'OFPQCFC_EPERM']
293
294     def _reserved_num_from_user(self, num, prefix):
295         try:
296             return str_to_int(num)
297         except ValueError:
298             try:
299                 if num.startswith(prefix):
300                     return getattr(self.ofproto, num.upper())
301                 else:
302                     return getattr(self.ofproto, prefix + num.upper())
303             except AttributeError:
304                 LOG.warning(
305                     "Cannot convert argument to reserved number: %s", num)
306         return num
307
308     def _reserved_num_to_user(self, num, prefix):
309         for k, v in self.ofproto.__dict__.items():
310             if k not in self.deprecated_value and \
311                k.startswith(prefix) and v == num:
312                 return k.replace(prefix, '')
313         return num
314
315     def ofp_port_features_from_user(self, act):
316         return self._reserved_num_from_user(act, 'OFPPF_')
317
318     def ofp_port_features_to_user(self, act):
319         return self._reserved_num_to_user(act, 'OFPPF_')
320
321     def ofp_port_mod_prop_type_from_user(self, act):
322         return self._reserved_num_from_user(act, 'OFPPMPT_')
323
324     def ofp_port_mod_prop_type_to_user(self, act):
325         return self._reserved_num_to_user(act, 'OFPPMPT_')
326
327     def ofp_port_desc_prop_type_from_user(self, act):
328         return self._reserved_num_from_user(act, 'OFPPDPT_')
329
330     def ofp_port_desc_prop_type_to_user(self, act):
331         return self._reserved_num_to_user(act, 'OFPPDPT_')
332
333     def ofp_action_type_from_user(self, act):
334         return self._reserved_num_from_user(act, 'OFPAT_')
335
336     def ofp_action_type_to_user(self, act):
337         return self._reserved_num_to_user(act, 'OFPAT_')
338
339     def ofp_instruction_type_from_user(self, act):
340         return self._reserved_num_from_user(act, 'OFPIT_')
341
342     def ofp_instruction_type_to_user(self, act):
343         return self._reserved_num_to_user(act, 'OFPIT_')
344
345     def ofp_group_type_from_user(self, act):
346         return self._reserved_num_from_user(act, 'OFPGT_')
347
348     def ofp_group_type_to_user(self, act):
349         return self._reserved_num_to_user(act, 'OFPGT_')
350
351     def ofp_meter_band_type_from_user(self, act):
352         return self._reserved_num_from_user(act, 'OFPMBT_')
353
354     def ofp_meter_band_type_to_user(self, act):
355         return self._reserved_num_to_user(act, 'OFPMBT_')
356
357     def ofp_table_feature_prop_type_from_user(self, act):
358         return self._reserved_num_from_user(act, 'OFPTFPT_')
359
360     def ofp_table_feature_prop_type_to_user(self, act):
361         return self._reserved_num_to_user(act, 'OFPTFPT_')
362
363     def ofp_port_stats_prop_type_from_user(self, act):
364         return self._reserved_num_from_user(act, 'OFPPSPT_')
365
366     def ofp_port_stats_prop_type_to_user(self, act):
367         return self._reserved_num_to_user(act, 'OFPPSPT_')
368
369     def ofp_queue_desc_prop_type_from_user(self, act):
370         return self._reserved_num_from_user(act, 'OFPQDPT_')
371
372     def ofp_queue_desc_prop_type_to_user(self, act):
373         return self._reserved_num_to_user(act, 'OFPQDPT_')
374
375     def ofp_queue_stats_prop_type_from_user(self, act):
376         return self._reserved_num_from_user(act, 'OFPQSPT_')
377
378     def ofp_queue_stats_prop_type_to_user(self, act):
379         return self._reserved_num_to_user(act, 'OFPQSPT_')
380
381     def ofp_meter_flags_from_user(self, act):
382         return self._reserved_num_from_user(act, 'OFPMF_')
383
384     def ofp_meter_flags_to_user(self, act):
385         return self._reserved_num_to_user(act, 'OFPMF_')
386
387     def ofp_port_from_user(self, port):
388         return self._reserved_num_from_user(port, 'OFPP_')
389
390     def ofp_port_to_user(self, port):
391         return self._reserved_num_to_user(port, 'OFPP_')
392
393     def ofp_table_from_user(self, table):
394         return self._reserved_num_from_user(table, 'OFPTT_')
395
396     def ofp_table_to_user(self, table):
397         return self._reserved_num_to_user(table, 'OFPTT_')
398
399     def ofp_cml_from_user(self, max_len):
400         return self._reserved_num_from_user(max_len, 'OFPCML_')
401
402     def ofp_cml_to_user(self, max_len):
403         return self._reserved_num_to_user(max_len, 'OFPCML_')
404
405     def ofp_group_from_user(self, group):
406         return self._reserved_num_from_user(group, 'OFPG_')
407
408     def ofp_group_to_user(self, group):
409         return self._reserved_num_to_user(group, 'OFPG_')
410
411     def ofp_group_capabilities_from_user(self, group):
412         return self._reserved_num_from_user(group, 'OFPGFC_')
413
414     def ofp_group_capabilities_to_user(self, group):
415         return self._reserved_num_to_user(group, 'OFPGFC_')
416
417     def ofp_group_bucket_prop_type_from_user(self, group):
418         return self._reserved_num_from_user(group, 'OFPGBPT_')
419
420     def ofp_group_bucket_prop_type_to_user(self, group):
421         return self._reserved_num_to_user(group, 'OFPGBPT_')
422
423     def ofp_buffer_from_user(self, buffer):
424         if buffer in ['OFP_NO_BUFFER', 'NO_BUFFER']:
425             return self.ofproto.OFP_NO_BUFFER
426         else:
427             return buffer
428
429     def ofp_buffer_to_user(self, buffer):
430         if self.ofproto.OFP_NO_BUFFER == buffer:
431             return 'NO_BUFFER'
432         else:
433             return buffer
434
435     def ofp_meter_from_user(self, meter):
436         return self._reserved_num_from_user(meter, 'OFPM_')
437
438     def ofp_meter_to_user(self, meter):
439         return self._reserved_num_to_user(meter, 'OFPM_')
440
441     def ofp_queue_from_user(self, queue):
442         return self._reserved_num_from_user(queue, 'OFPQ_')
443
444     def ofp_queue_to_user(self, queue):
445         return self._reserved_num_to_user(queue, 'OFPQ_')
446
447     def ofp_role_from_user(self, role):
448         return self._reserved_num_from_user(role, 'OFPCR_ROLE_')
449
450     def ofp_role_to_user(self, role):
451         return self._reserved_num_to_user(role, 'OFPCR_ROLE_')