backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / lib / ofctl_string.py
1 # Copyright (C) 2017 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 re
17
18 import ryu.exception
19 from ryu.lib.ofctl_utils import str_to_int
20 from ryu.ofproto import nicira_ext
21
22
23 def ofp_instruction_from_str(ofproto, action_str):
24     """
25     Parse an ovs-ofctl style action string and return a list of
26     jsondict representations of OFPInstructionActions, which
27     can then be passed to ofproto_parser.ofp_instruction_from_jsondict.
28
29     Please note that this is for making transition from ovs-ofctl
30     easier. Please consider using OFPAction constructors when writing
31     new codes.
32
33     This function takes the following arguments.
34
35     =========== =================================================
36     Argument    Description
37     =========== =================================================
38     ofproto     An ofproto module.
39     action_str  An action string.
40     =========== =================================================
41     """
42     action_re = re.compile(r"([a-z_]+)(\([^)]*\)|[^a-z_,()][^,()]*)*")
43     result = []
44     while len(action_str):
45         m = action_re.match(action_str)
46         if not m:
47             raise ryu.exception.OFPInvalidActionString(action_str=action_str)
48         action_name = m.group(1)
49         this_action = m.group(0)
50         paren_level = this_action.count('(') - this_action.count(')')
51         assert paren_level >= 0
52         try:
53             # Parens can be nested. Look for as many ')'s as '('s.
54             if paren_level > 0:
55                 this_action, rest = _tokenize_paren_block(action_str, m.end(0))
56             else:
57                 rest = action_str[m.end(0):]
58             if len(rest):
59                 assert rest[0] == ','
60                 rest = rest[1:]
61         except Exception:
62             raise ryu.exception.OFPInvalidActionString(action_str=action_str)
63         if action_name == 'drop':
64             assert this_action == 'drop'
65             assert len(result) == 0 and rest == ''
66             return []
67         converter = getattr(OfctlActionConverter, action_name, None)
68         if converter is None or not callable(converter):
69             raise ryu.exception.OFPInvalidActionString(action_str=action_name)
70         result.append(converter(ofproto, this_action))
71         action_str = rest
72
73     return result
74
75
76 def _tokenize_paren_block(string, pos):
77     paren_re = re.compile("[()]")
78     paren_level = string[:pos].count('(') - string[:pos].count(')')
79     while paren_level > 0:
80         m = paren_re.search(string[pos:])
81         if m.group(0) == '(':
82             paren_level += 1
83         else:
84             paren_level -= 1
85         pos += m.end(0)
86     return string[:pos], string[pos:]
87
88
89 def tokenize_ofp_instruction_arg(arg):
90     """
91     Tokenize an argument portion of ovs-ofctl style action string.
92     """
93     arg_re = re.compile("[^,()]*")
94     try:
95         rest = arg
96         result = []
97         while len(rest):
98             m = arg_re.match(rest)
99             if m.end(0) == len(rest):
100                 result.append(rest)
101                 return result
102             if rest[m.end(0)] == '(':
103                 this_block, rest = _tokenize_paren_block(
104                     rest, m.end(0) + 1)
105                 result.append(this_block)
106             elif rest[m.end(0)] == ',':
107                 result.append(m.group(0))
108                 rest = rest[m.end(0):]
109             else:  # is ')'
110                 raise Exception
111             if len(rest):
112                 assert rest[0] == ','
113                 rest = rest[1:]
114         return result
115     except Exception:
116         raise ryu.exception.OFPInvalidActionString(action_str=arg)
117
118
119 _OXM_FIELD_OFCTL_ALIASES = {
120     'tun_id': 'tunnel_id',
121     'in_port': 'in_port_nxm',
122     'in_port_oxm': 'in_port',
123     'dl_src': 'eth_src',
124     'dl_type': 'eth_type',
125     'nw_src': 'ipv4_src',
126     'ip_src': 'ipv4_src',
127     'nw_proto': 'ip_proto',
128     'nw_ecn': 'ip_ecn',
129     'tp_src': 'tcp_src',
130     'icmp_type': 'icmpv4_type',
131     'icmp_code': 'icmpv4_code',
132     'nd_target': 'ipv6_nd_target',
133     'nd_sll': 'ipv6_nd_sll',
134     'nd_tll': 'ipv6_nd_tll',
135     # Nicira extension
136     'tun_src': 'tun_ipv4_src'
137 }
138
139
140 def ofp_ofctl_field_name_to_ryu(field):
141     """Convert an ovs-ofctl field name to ryu equivalent."""
142     mapped = _OXM_FIELD_OFCTL_ALIASES.get(field)
143     if mapped:
144         return mapped
145     if field.endswith("_dst"):
146         mapped = _OXM_FIELD_OFCTL_ALIASES.get(field[:-3] + "src")
147         if mapped:
148             return mapped[:-3] + "dst"
149     return field
150
151
152 _NXM_FIELD_MAP = dict([(key, key + '_nxm') for key in [
153     'arp_sha', 'arp_tha', 'ipv6_src', 'ipv6_dst',
154     'icmpv6_type', 'icmpv6_code', 'ip_ecn', 'tcp_flags']])
155 _NXM_FIELD_MAP.update({
156     'tun_id': 'tunnel_id_nxm', 'ip_ttl': 'nw_ttl'})
157
158 _NXM_OF_FIELD_MAP = dict([(key, key + '_nxm') for key in [
159     'in_port', 'eth_dst', 'eth_src', 'eth_type', 'ip_proto',
160     'tcp_src', 'tcp_dst', 'udp_src', 'udp_dst',
161     'arp_op', 'arp_spa', 'arp_tpa']])
162 _NXM_OF_FIELD_MAP.update({
163     'ip_src': 'ipv4_src_nxm', 'ip_dst': 'ipv4_dst_nxm',
164     'icmp_type': 'icmpv4_type_nxm', 'icmp_code': 'icmpv4_code_nxm'})
165
166
167 def nxm_field_name_to_ryu(field):
168     """
169     Convert an ovs-ofctl style NXM_/OXM_ field name to
170     a ryu match field name.
171     """
172     if field.endswith("_W"):
173         field = field[:-2]
174     prefix = field[:7]
175     field = field[7:].lower()
176     mapped_result = None
177
178     if prefix == 'NXM_NX_':
179         mapped_result = _NXM_FIELD_MAP.get(field)
180     elif prefix == "NXM_OF_":
181         mapped_result = _NXM_OF_FIELD_MAP.get(field)
182     elif prefix == "OXM_OF_":
183         # no mapping needed
184         pass
185     else:
186         raise ValueError
187     if mapped_result is not None:
188         return mapped_result
189     return field
190
191
192 class OfctlActionConverter(object):
193
194     @classmethod
195     def goto_table(cls, ofproto, action_str):
196         assert action_str.startswith('goto_table:')
197         table_id = str_to_int(action_str[len('goto_table:'):])
198         return dict(OFPInstructionGotoTable={'table_id': table_id})
199
200     @classmethod
201     def normal(cls, ofproto, action_str):
202         return cls.output(ofproto, action_str)
203
204     @classmethod
205     def output(cls, ofproto, action_str):
206         if action_str == 'normal':
207             port = ofproto.OFPP_NORMAL
208         else:
209             assert action_str.startswith('output:')
210             port = str_to_int(action_str[len('output:'):])
211         return dict(OFPActionOutput={'port': port})
212
213     @classmethod
214     def pop_vlan(cls, ofproto, action_str):
215         return dict(OFPActionPopVlan={})
216
217     @classmethod
218     def set_field(cls, ofproto, action_str):
219         try:
220             assert action_str.startswith("set_field:")
221             value, key = action_str[len("set_field:"):].split("->", 1)
222             fieldarg = dict(field=ofp_ofctl_field_name_to_ryu(key))
223             m = value.find('/')
224             if m >= 0:
225                 fieldarg['value'] = str_to_int(value[:m])
226                 fieldarg['mask'] = str_to_int(value[m + 1:])
227             else:
228                 fieldarg['value'] = str_to_int(value)
229         except Exception:
230             raise ryu.exception.OFPInvalidActionString(action_str=action_str)
231         return dict(OFPActionSetField={
232             'field': {'OXMTlv': fieldarg}})
233
234     # NX actions
235     @classmethod
236     def resubmit(cls, ofproto, action_str):
237         arg = action_str[len("resubmit"):]
238         kwargs = {}
239         try:
240             if arg[0] == ':':
241                 kwargs['in_port'] = str_to_int(arg[1:])
242             elif arg[0] == '(' and arg[-1] == ')':
243                 in_port, table_id = arg[1:-1].split(',')
244                 if in_port:
245                     kwargs['in_port'] = str_to_int(in_port)
246                 if table_id:
247                     kwargs['table_id'] = str_to_int(table_id)
248             else:
249                 raise Exception
250             return dict(NXActionResubmitTable=kwargs)
251         except Exception:
252             raise ryu.exception.OFPInvalidActionString(
253                 action_str=action_str)
254
255     @classmethod
256     def conjunction(cls, ofproto, action_str):
257         try:
258             assert action_str.startswith('conjunction(')
259             assert action_str[-1] == ')'
260             args = action_str[len('conjunction('):-1].split(',')
261             assert len(args) == 2
262             id_ = str_to_int(args[0])
263             clauses = list(map(str_to_int, args[1].split('/')))
264             assert len(clauses) == 2
265             return dict(NXActionConjunction={
266                 'clause': clauses[0] - 1,
267                 'n_clauses': clauses[1],
268                 'id': id_})
269         except Exception:
270             raise ryu.exception.OFPInvalidActionString(
271                 action_str=action_str)
272
273     @classmethod
274     def ct(cls, ofproto, action_str):
275         str_to_port = {'ftp': 21, 'tftp': 69}
276         flags = 0
277         zone_src = ""
278         zone_ofs_nbits = 0
279         recirc_table = nicira_ext.NX_CT_RECIRC_NONE
280         alg = 0
281         ct_actions = []
282
283         if len(action_str) > 2:
284             if (not action_str.startswith('ct(') or
285                     action_str[-1] != ')'):
286                 raise ryu.exception.OFPInvalidActionString(
287                     action_str=action_str)
288             rest = tokenize_ofp_instruction_arg(action_str[len('ct('):-1])
289         else:
290             rest = []
291         for arg in rest:
292             if arg == 'commit':
293                 flags |= nicira_ext.NX_CT_F_COMMIT
294                 rest = rest[len('commit'):]
295             elif arg == 'force':
296                 flags |= nicira_ext.NX_CT_F_FORCE
297             elif arg.startswith('exec('):
298                 ct_actions = ofp_instruction_from_str(
299                     ofproto, arg[len('exec('):-1])
300             else:
301                 try:
302                     k, v = arg.split('=', 1)
303                     if k == 'table':
304                         recirc_table = str_to_int(v)
305                     elif k == 'zone':
306                         m = re.search(r'\[(\d*)\.\.(\d*)\]', v)
307                         if m:
308                             zone_ofs_nbits = nicira_ext.ofs_nbits(
309                                 int(m.group(1)), int(m.group(2)))
310                             zone_src = nxm_field_name_to_ryu(
311                                 v[:m.start(0)])
312                         else:
313                             zone_ofs_nbits = str_to_int(v)
314                     elif k == 'alg':
315                         alg = str_to_port[arg[len('alg='):]]
316                 except Exception:
317                     raise ryu.exception.OFPInvalidActionString(
318                         action_str=action_str)
319         return dict(NXActionCT={'flags': flags,
320                                 'zone_src': zone_src,
321                                 'zone_ofs_nbits': zone_ofs_nbits,
322                                 'recirc_table': recirc_table,
323                                 'alg': alg,
324                                 'actions': ct_actions})
325
326     @classmethod
327     def ct_clear(cls, ofproto, action_str):
328         return dict(NXActionCTClear={})