1 # Copyright (C) 2012 Nippon Telegraph and Telephone Corporation.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
20 from ryu.ofproto import ofproto_v1_0
21 from ryu.lib import ofctl_utils
22 from ryu.lib.mac import haddr_to_bin, haddr_to_str
25 LOG = logging.getLogger('ryu.lib.ofctl_v1_0')
27 DEFAULT_TIMEOUT = 1.0 # TODO:XXX
29 UTIL = ofctl_utils.OFCtlUtil(ofproto_v1_0)
30 str_to_int = ofctl_utils.str_to_int
33 def to_actions(dp, acts):
36 action_type = a.get('type')
37 if action_type == 'OUTPUT':
38 port = UTIL.ofp_port_from_user(
39 a.get('port', ofproto_v1_0.OFPP_NONE))
40 # NOTE: The reason of this magic number (0xffe5)
41 # is because there is no good constant in of1.0.
42 # The same value as OFPCML_MAX of of1.2 and of1.3 is used.
43 max_len = str_to_int(a.get('max_len', 0xffe5))
44 actions.append(dp.ofproto_parser.OFPActionOutput(port, max_len))
45 elif action_type == 'SET_VLAN_VID':
46 vlan_vid = str_to_int(a.get('vlan_vid', 0xffff))
47 actions.append(dp.ofproto_parser.OFPActionVlanVid(vlan_vid))
48 elif action_type == 'SET_VLAN_PCP':
49 vlan_pcp = str_to_int(a.get('vlan_pcp', 0))
50 actions.append(dp.ofproto_parser.OFPActionVlanPcp(vlan_pcp))
51 elif action_type == 'STRIP_VLAN':
52 actions.append(dp.ofproto_parser.OFPActionStripVlan())
53 elif action_type == 'SET_DL_SRC':
54 dl_src = haddr_to_bin(a.get('dl_src'))
55 actions.append(dp.ofproto_parser.OFPActionSetDlSrc(dl_src))
56 elif action_type == 'SET_DL_DST':
57 dl_dst = haddr_to_bin(a.get('dl_dst'))
58 actions.append(dp.ofproto_parser.OFPActionSetDlDst(dl_dst))
59 elif action_type == 'SET_NW_SRC':
60 nw_src = ipv4_to_int(a.get('nw_src'))
61 actions.append(dp.ofproto_parser.OFPActionSetNwSrc(nw_src))
62 elif action_type == 'SET_NW_DST':
63 nw_dst = ipv4_to_int(a.get('nw_dst'))
64 actions.append(dp.ofproto_parser.OFPActionSetNwDst(nw_dst))
65 elif action_type == 'SET_NW_TOS':
66 nw_tos = str_to_int(a.get('nw_tos', 0))
67 actions.append(dp.ofproto_parser.OFPActionSetNwTos(nw_tos))
68 elif action_type == 'SET_TP_SRC':
69 tp_src = str_to_int(a.get('tp_src', 0))
70 actions.append(dp.ofproto_parser.OFPActionSetTpSrc(tp_src))
71 elif action_type == 'SET_TP_DST':
72 tp_dst = str_to_int(a.get('tp_dst', 0))
73 actions.append(dp.ofproto_parser.OFPActionSetTpDst(tp_dst))
74 elif action_type == 'ENQUEUE':
75 port = UTIL.ofp_port_from_user(
76 a.get('port', ofproto_v1_0.OFPP_NONE))
77 queue_id = UTIL.ofp_queue_from_user(a.get('queue_id', 0))
78 actions.append(dp.ofproto_parser.OFPActionEnqueue(port, queue_id))
80 LOG.error('Unknown action type')
85 def actions_to_str(acts):
88 action_type = a.cls_action_type
90 if action_type == ofproto_v1_0.OFPAT_OUTPUT:
91 port = UTIL.ofp_port_to_user(a.port)
92 buf = 'OUTPUT:' + str(port)
93 elif action_type == ofproto_v1_0.OFPAT_SET_VLAN_VID:
94 buf = 'SET_VLAN_VID:' + str(a.vlan_vid)
95 elif action_type == ofproto_v1_0.OFPAT_SET_VLAN_PCP:
96 buf = 'SET_VLAN_PCP:' + str(a.vlan_pcp)
97 elif action_type == ofproto_v1_0.OFPAT_STRIP_VLAN:
99 elif action_type == ofproto_v1_0.OFPAT_SET_DL_SRC:
100 buf = 'SET_DL_SRC:' + haddr_to_str(a.dl_addr)
101 elif action_type == ofproto_v1_0.OFPAT_SET_DL_DST:
102 buf = 'SET_DL_DST:' + haddr_to_str(a.dl_addr)
103 elif action_type == ofproto_v1_0.OFPAT_SET_NW_SRC:
104 buf = 'SET_NW_SRC:' + \
105 socket.inet_ntoa(struct.pack('!I', a.nw_addr))
106 elif action_type == ofproto_v1_0.OFPAT_SET_NW_DST:
107 buf = 'SET_NW_DST:' + \
108 socket.inet_ntoa(struct.pack('!I', a.nw_addr))
109 elif action_type == ofproto_v1_0.OFPAT_SET_NW_TOS:
110 buf = 'SET_NW_TOS:' + str(a.tos)
111 elif action_type == ofproto_v1_0.OFPAT_SET_TP_SRC:
112 buf = 'SET_TP_SRC:' + str(a.tp)
113 elif action_type == ofproto_v1_0.OFPAT_SET_TP_DST:
114 buf = 'SET_TP_DST:' + str(a.tp)
115 elif action_type == ofproto_v1_0.OFPAT_ENQUEUE:
116 port = UTIL.ofp_port_to_user(a.port)
117 queue = UTIL.ofp_queue_to_user(a.queue_id)
118 buf = 'ENQUEUE:' + str(port) + ":" + str(queue)
119 elif action_type == ofproto_v1_0.OFPAT_VENDOR:
128 def ipv4_to_int(addr):
138 def to_match(dp, attrs):
141 wildcards = ofp.OFPFW_ALL
155 for key, value in attrs.items():
157 in_port = UTIL.ofp_port_from_user(value)
158 wildcards &= ~ofp.OFPFW_IN_PORT
159 elif key == 'dl_src':
160 dl_src = haddr_to_bin(value)
161 wildcards &= ~ofp.OFPFW_DL_SRC
162 elif key == 'dl_dst':
163 dl_dst = haddr_to_bin(value)
164 wildcards &= ~ofp.OFPFW_DL_DST
165 elif key == 'dl_vlan':
166 dl_vlan = str_to_int(value)
167 wildcards &= ~ofp.OFPFW_DL_VLAN
168 elif key == 'dl_vlan_pcp':
169 dl_vlan_pcp = str_to_int(value)
170 wildcards &= ~ofp.OFPFW_DL_VLAN_PCP
171 elif key == 'dl_type':
172 dl_type = str_to_int(value)
173 wildcards &= ~ofp.OFPFW_DL_TYPE
174 elif key == 'nw_tos':
175 nw_tos = str_to_int(value)
176 wildcards &= ~ofp.OFPFW_NW_TOS
177 elif key == 'nw_proto':
178 nw_proto = str_to_int(value)
179 wildcards &= ~ofp.OFPFW_NW_PROTO
180 elif key == 'nw_src':
181 ip = value.split('/')
182 nw_src = struct.unpack('!I', socket.inet_aton(ip[0]))[0]
186 assert 0 < mask <= 32
187 v = (32 - mask) << ofp.OFPFW_NW_SRC_SHIFT | \
188 ~ofp.OFPFW_NW_SRC_MASK
190 elif key == 'nw_dst':
191 ip = value.split('/')
192 nw_dst = struct.unpack('!I', socket.inet_aton(ip[0]))[0]
196 assert 0 < mask <= 32
197 v = (32 - mask) << ofp.OFPFW_NW_DST_SHIFT | \
198 ~ofp.OFPFW_NW_DST_MASK
200 elif key == 'tp_src':
201 tp_src = str_to_int(value)
202 wildcards &= ~ofp.OFPFW_TP_SRC
203 elif key == 'tp_dst':
204 tp_dst = str_to_int(value)
205 wildcards &= ~ofp.OFPFW_TP_DST
207 LOG.error("unknown match name %s, %s, %d", key, value, len(key))
209 match = dp.ofproto_parser.OFPMatch(
210 wildcards, in_port, dl_src, dl_dst, dl_vlan, dl_vlan_pcp,
211 dl_type, nw_tos, nw_proto, nw_src, nw_dst, tp_src, tp_dst)
220 if ~m.wildcards & ofproto_v1_0.OFPFW_IN_PORT:
221 match['in_port'] = UTIL.ofp_port_to_user(m.in_port)
223 if ~m.wildcards & ofproto_v1_0.OFPFW_DL_SRC:
224 match['dl_src'] = haddr_to_str(m.dl_src)
226 if ~m.wildcards & ofproto_v1_0.OFPFW_DL_DST:
227 match['dl_dst'] = haddr_to_str(m.dl_dst)
229 if ~m.wildcards & ofproto_v1_0.OFPFW_DL_VLAN:
230 match['dl_vlan'] = m.dl_vlan
232 if ~m.wildcards & ofproto_v1_0.OFPFW_DL_VLAN_PCP:
233 match['dl_vlan_pcp'] = m.dl_vlan_pcp
235 if ~m.wildcards & ofproto_v1_0.OFPFW_DL_TYPE:
236 match['dl_type'] = m.dl_type
238 if ~m.wildcards & ofproto_v1_0.OFPFW_NW_TOS:
239 match['nw_tos'] = m.nw_tos
241 if ~m.wildcards & ofproto_v1_0.OFPFW_NW_PROTO:
242 match['nw_proto'] = m.nw_proto
244 if ~m.wildcards & ofproto_v1_0.OFPFW_NW_SRC_ALL:
245 match['nw_src'] = nw_src_to_str(m.wildcards, m.nw_src)
247 if ~m.wildcards & ofproto_v1_0.OFPFW_NW_DST_ALL:
248 match['nw_dst'] = nw_dst_to_str(m.wildcards, m.nw_dst)
250 if ~m.wildcards & ofproto_v1_0.OFPFW_TP_SRC:
251 match['tp_src'] = m.tp_src
253 if ~m.wildcards & ofproto_v1_0.OFPFW_TP_DST:
254 match['tp_dst'] = m.tp_dst
259 def nw_src_to_str(wildcards, addr):
260 ip = socket.inet_ntoa(struct.pack('!I', addr))
261 mask = 32 - ((wildcards & ofproto_v1_0.OFPFW_NW_SRC_MASK) >>
262 ofproto_v1_0.OFPFW_NW_SRC_SHIFT)
270 def nw_dst_to_str(wildcards, addr):
271 ip = socket.inet_ntoa(struct.pack('!I', addr))
272 mask = 32 - ((wildcards & ofproto_v1_0.OFPFW_NW_DST_MASK) >>
273 ofproto_v1_0.OFPFW_NW_DST_SHIFT)
281 def get_desc_stats(dp, waiters):
282 stats = dp.ofproto_parser.OFPDescStatsRequest(dp, 0)
284 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
289 s = stats.to_jsondict()[stats.__class__.__name__]
291 return {str(dp.id): s}
294 def get_queue_stats(dp, waiters, port=None, queue_id=None):
296 port = dp.ofproto.OFPP_ALL
298 port = str_to_int(port)
301 queue_id = dp.ofproto.OFPQ_ALL
303 queue_id = str_to_int(queue_id)
305 stats = dp.ofproto_parser.OFPQueueStatsRequest(dp, 0, port,
308 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
314 s.append({'port_no': stat.port_no,
315 'queue_id': stat.queue_id,
316 'tx_bytes': stat.tx_bytes,
317 'tx_errors': stat.tx_errors,
318 'tx_packets': stat.tx_packets})
320 return {str(dp.id): s}
323 def get_flow_stats(dp, waiters, flow=None):
324 flow = flow if flow else {}
325 match = to_match(dp, flow.get('match', {}))
326 table_id = UTIL.ofp_table_from_user(
327 flow.get('table_id', 0xff))
328 out_port = UTIL.ofp_port_from_user(
329 flow.get('out_port', dp.ofproto.OFPP_NONE))
330 # Note: OpenFlow does not allow to filter flow entries by priority,
331 # but for efficiency, ofctl provides the way to do it.
332 priority = str_to_int(flow.get('priority', -1))
334 stats = dp.ofproto_parser.OFPFlowStatsRequest(
335 dp, 0, match, table_id, out_port)
338 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
342 for stats in msg.body:
343 if 0 <= priority != stats.priority:
346 actions = actions_to_str(stats.actions)
347 match = match_to_str(stats.match)
349 s = {'priority': stats.priority,
350 'cookie': stats.cookie,
351 'idle_timeout': stats.idle_timeout,
352 'hard_timeout': stats.hard_timeout,
355 'byte_count': stats.byte_count,
356 'duration_sec': stats.duration_sec,
357 'duration_nsec': stats.duration_nsec,
358 'packet_count': stats.packet_count,
359 'table_id': UTIL.ofp_table_to_user(stats.table_id)}
362 return {str(dp.id): flows}
365 def get_aggregate_flow_stats(dp, waiters, flow=None):
366 flow = flow if flow else {}
367 match = to_match(dp, flow.get('match', {}))
368 table_id = UTIL.ofp_table_from_user(
369 flow.get('table_id', 0xff))
370 out_port = UTIL.ofp_port_from_user(
371 flow.get('out_port', dp.ofproto.OFPP_NONE))
373 stats = dp.ofproto_parser.OFPAggregateStatsRequest(
374 dp, 0, match, table_id, out_port)
377 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
383 s = {'packet_count': st.packet_count,
384 'byte_count': st.byte_count,
385 'flow_count': st.flow_count}
388 return {str(dp.id): flows}
391 def get_table_stats(dp, waiters):
392 stats = dp.ofproto_parser.OFPTableStatsRequest(dp, 0)
395 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
397 match_convert = {ofp.OFPFW_IN_PORT: 'IN_PORT',
398 ofp.OFPFW_DL_VLAN: 'DL_VLAN',
399 ofp.OFPFW_DL_SRC: 'DL_SRC',
400 ofp.OFPFW_DL_DST: 'DL_DST',
401 ofp.OFPFW_DL_TYPE: 'DL_TYPE',
402 ofp.OFPFW_NW_PROTO: 'NW_PROTO',
403 ofp.OFPFW_TP_SRC: 'TP_SRC',
404 ofp.OFPFW_TP_DST: 'TP_DST',
405 ofp.OFPFW_NW_SRC_SHIFT: 'NW_SRC_SHIFT',
406 ofp.OFPFW_NW_SRC_BITS: 'NW_SRC_BITS',
407 ofp.OFPFW_NW_SRC_MASK: 'NW_SRC_MASK',
408 ofp.OFPFW_NW_SRC: 'NW_SRC',
409 ofp.OFPFW_NW_SRC_ALL: 'NW_SRC_ALL',
410 ofp.OFPFW_NW_DST_SHIFT: 'NW_DST_SHIFT',
411 ofp.OFPFW_NW_DST_BITS: 'NW_DST_BITS',
412 ofp.OFPFW_NW_DST_MASK: 'NW_DST_MASK',
413 ofp.OFPFW_NW_DST: 'NW_DST',
414 ofp.OFPFW_NW_DST_ALL: 'NW_DST_ALL',
415 ofp.OFPFW_DL_VLAN_PCP: 'DL_VLAN_PCP',
416 ofp.OFPFW_NW_TOS: 'NW_TOS',
417 ofp.OFPFW_ALL: 'ALL',
418 ofp.OFPFW_ICMP_TYPE: 'ICMP_TYPE',
419 ofp.OFPFW_ICMP_CODE: 'ICMP_CODE'}
426 for k, v in match_convert.items():
427 if (1 << k) & stat.wildcards:
429 s = {'table_id': UTIL.ofp_table_to_user(stat.table_id),
430 'name': stat.name.decode('utf-8'),
431 'wildcards': wildcards,
432 'max_entries': stat.max_entries,
433 'active_count': stat.active_count,
434 'lookup_count': stat.lookup_count,
435 'matched_count': stat.matched_count}
438 return {str(dp.id): tables}
441 def get_port_stats(dp, waiters, port=None):
443 port = dp.ofproto.OFPP_NONE
445 port = str_to_int(port)
447 stats = dp.ofproto_parser.OFPPortStatsRequest(
450 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
454 for stats in msg.body:
455 s = {'port_no': UTIL.ofp_port_to_user(stats.port_no),
456 'rx_packets': stats.rx_packets,
457 'tx_packets': stats.tx_packets,
458 'rx_bytes': stats.rx_bytes,
459 'tx_bytes': stats.tx_bytes,
460 'rx_dropped': stats.rx_dropped,
461 'tx_dropped': stats.tx_dropped,
462 'rx_errors': stats.rx_errors,
463 'tx_errors': stats.tx_errors,
464 'rx_frame_err': stats.rx_frame_err,
465 'rx_over_err': stats.rx_over_err,
466 'rx_crc_err': stats.rx_crc_err,
467 'collisions': stats.collisions}
470 return {str(dp.id): ports}
473 def get_port_desc(dp, waiters):
475 stats = dp.ofproto_parser.OFPFeaturesRequest(dp)
477 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
482 for stat in stats.values():
483 d = {'port_no': UTIL.ofp_port_to_user(stat.port_no),
484 'hw_addr': stat.hw_addr,
485 'name': stat.name.decode('utf-8'),
486 'config': stat.config,
489 'advertised': stat.advertised,
490 'supported': stat.supported,
494 return {str(dp.id): descs}
497 def mod_flow_entry(dp, flow, cmd):
498 cookie = str_to_int(flow.get('cookie', 0))
499 priority = str_to_int(
500 flow.get('priority', dp.ofproto.OFP_DEFAULT_PRIORITY))
501 buffer_id = UTIL.ofp_buffer_from_user(
502 flow.get('buffer_id', dp.ofproto.OFP_NO_BUFFER))
503 out_port = UTIL.ofp_port_from_user(
504 flow.get('out_port', dp.ofproto.OFPP_NONE))
505 flags = str_to_int(flow.get('flags', 0))
506 idle_timeout = str_to_int(flow.get('idle_timeout', 0))
507 hard_timeout = str_to_int(flow.get('hard_timeout', 0))
508 actions = to_actions(dp, flow.get('actions', []))
509 match = to_match(dp, flow.get('match', {}))
511 flow_mod = dp.ofproto_parser.OFPFlowMod(
512 datapath=dp, match=match, cookie=cookie,
513 command=cmd, idle_timeout=idle_timeout,
514 hard_timeout=hard_timeout, priority=priority,
515 buffer_id=buffer_id, out_port=out_port,
519 ofctl_utils.send_msg(dp, flow_mod, LOG)
522 def delete_flow_entry(dp):
523 match = dp.ofproto_parser.OFPMatch(
524 dp.ofproto.OFPFW_ALL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
526 flow_mod = dp.ofproto_parser.OFPFlowMod(
527 datapath=dp, match=match, cookie=0,
528 command=dp.ofproto.OFPFC_DELETE)
530 ofctl_utils.send_msg(dp, flow_mod, LOG)
533 def mod_port_behavior(dp, port_config):
534 port_no = UTIL.ofp_port_from_user(port_config.get('port_no', 0))
535 hw_addr = str(port_config.get('hw_addr'))
536 config = str_to_int(port_config.get('config', 0))
537 mask = str_to_int(port_config.get('mask', 0))
538 advertise = str_to_int(port_config.get('advertise'))
540 port_mod = dp.ofproto_parser.OFPPortMod(
541 dp, port_no, hw_addr, config, mask, advertise)
543 ofctl_utils.send_msg(dp, port_mod, LOG)