backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / app / rest_router.py
1 # Copyright (C) 2013 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
17 import logging
18 import numbers
19 import socket
20 import struct
21
22 import json
23
24 from ryu.app.wsgi import ControllerBase
25 from ryu.app.wsgi import Response
26 from ryu.app.wsgi import WSGIApplication
27 from ryu.base import app_manager
28 from ryu.controller import dpset
29 from ryu.controller import ofp_event
30 from ryu.controller.handler import set_ev_cls
31 from ryu.controller.handler import MAIN_DISPATCHER
32 from ryu.exception import OFPUnknownVersion
33 from ryu.exception import RyuException
34 from ryu.lib import dpid as dpid_lib
35 from ryu.lib import hub
36 from ryu.lib import mac as mac_lib
37 from ryu.lib import addrconv
38 from ryu.lib.packet import arp
39 from ryu.lib.packet import ethernet
40 from ryu.lib.packet import icmp
41 from ryu.lib.packet import ipv4
42 from ryu.lib.packet import packet
43 from ryu.lib.packet import packet_base
44 from ryu.lib.packet import tcp
45 from ryu.lib.packet import udp
46 from ryu.lib.packet import vlan
47 from ryu.ofproto import ether
48 from ryu.ofproto import inet
49 from ryu.ofproto import ofproto_v1_0
50 from ryu.ofproto import ofproto_v1_2
51 from ryu.ofproto import ofproto_v1_3
52
53
54 # =============================
55 #          REST API
56 # =============================
57 #
58 #  Note: specify switch and vlan group, as follows.
59 #   {switch_id} : 'all' or switchID
60 #   {vlan_id}   : 'all' or vlanID
61 #
62
63 # 1. get address data and routing data.
64 #
65 # * get data of no vlan
66 # GET /router/{switch_id}
67 #
68 # * get data of specific vlan group
69 # GET /router/{switch_id}/{vlan_id}
70 #
71
72 # 2. set address data or routing data.
73 #
74 # * set data of no vlan
75 # POST /router/{switch_id}
76 #
77 # * set data of specific vlan group
78 # POST /router/{switch_id}/{vlan_id}
79 #
80 #  case1: set address data.
81 #    parameter = {"address": "A.B.C.D/M"}
82 #  case2-1: set static route.
83 #    parameter = {"destination": "A.B.C.D/M", "gateway": "E.F.G.H"}
84 #  case2-2: set default route.
85 #    parameter = {"gateway": "E.F.G.H"}
86 #
87
88 # 3. delete address data or routing data.
89 #
90 # * delete data of no vlan
91 # DELETE /router/{switch_id}
92 #
93 # * delete data of specific vlan group
94 # DELETE /router/{switch_id}/{vlan_id}
95 #
96 #  case1: delete address data.
97 #    parameter = {"address_id": "<int>"} or {"address_id": "all"}
98 #  case2: delete routing data.
99 #    parameter = {"route_id": "<int>"} or {"route_id": "all"}
100 #
101 #
102
103
104 UINT16_MAX = 0xffff
105 UINT32_MAX = 0xffffffff
106 UINT64_MAX = 0xffffffffffffffff
107
108 ETHERNET = ethernet.ethernet.__name__
109 VLAN = vlan.vlan.__name__
110 IPV4 = ipv4.ipv4.__name__
111 ARP = arp.arp.__name__
112 ICMP = icmp.icmp.__name__
113 TCP = tcp.tcp.__name__
114 UDP = udp.udp.__name__
115
116 MAX_SUSPENDPACKETS = 50  # Threshold of the packet suspends thread count.
117
118 ARP_REPLY_TIMER = 2  # sec
119 OFP_REPLY_TIMER = 1.0  # sec
120 CHK_ROUTING_TBL_INTERVAL = 1800  # sec
121
122 SWITCHID_PATTERN = dpid_lib.DPID_PATTERN + r'|all'
123 VLANID_PATTERN = r'[0-9]{1,4}|all'
124
125 VLANID_NONE = 0
126 VLANID_MIN = 2
127 VLANID_MAX = 4094
128
129 COOKIE_DEFAULT_ID = 0
130 COOKIE_SHIFT_VLANID = 32
131 COOKIE_SHIFT_ROUTEID = 16
132
133 DEFAULT_ROUTE = '0.0.0.0/0'
134 IDLE_TIMEOUT = 1800  # sec
135 DEFAULT_TTL = 64
136
137 REST_COMMAND_RESULT = 'command_result'
138 REST_RESULT = 'result'
139 REST_DETAILS = 'details'
140 REST_OK = 'success'
141 REST_NG = 'failure'
142 REST_ALL = 'all'
143 REST_SWITCHID = 'switch_id'
144 REST_VLANID = 'vlan_id'
145 REST_NW = 'internal_network'
146 REST_ADDRESSID = 'address_id'
147 REST_ADDRESS = 'address'
148 REST_ROUTEID = 'route_id'
149 REST_ROUTE = 'route'
150 REST_DESTINATION = 'destination'
151 REST_GATEWAY = 'gateway'
152
153 PRIORITY_VLAN_SHIFT = 1000
154 PRIORITY_NETMASK_SHIFT = 32
155
156 PRIORITY_NORMAL = 0
157 PRIORITY_ARP_HANDLING = 1
158 PRIORITY_DEFAULT_ROUTING = 1
159 PRIORITY_MAC_LEARNING = 2
160 PRIORITY_STATIC_ROUTING = 2
161 PRIORITY_IMPLICIT_ROUTING = 3
162 PRIORITY_L2_SWITCHING = 4
163 PRIORITY_IP_HANDLING = 5
164
165 PRIORITY_TYPE_ROUTE = 'priority_route'
166
167
168 def get_priority(priority_type, vid=0, route=None):
169     log_msg = None
170     priority = priority_type
171
172     if priority_type == PRIORITY_TYPE_ROUTE:
173         assert route is not None
174         if route.dst_ip:
175             priority_type = PRIORITY_STATIC_ROUTING
176             priority = priority_type + route.netmask
177             log_msg = 'static routing'
178         else:
179             priority_type = PRIORITY_DEFAULT_ROUTING
180             priority = priority_type
181             log_msg = 'default routing'
182
183     if vid or priority_type == PRIORITY_IP_HANDLING:
184         priority += PRIORITY_VLAN_SHIFT
185
186     if priority_type > PRIORITY_STATIC_ROUTING:
187         priority += PRIORITY_NETMASK_SHIFT
188
189     if log_msg is None:
190         return priority
191     else:
192         return priority, log_msg
193
194
195 def get_priority_type(priority, vid):
196     if vid:
197         priority -= PRIORITY_VLAN_SHIFT
198     return priority
199
200
201 class NotFoundError(RyuException):
202     message = 'Router SW is not connected. : switch_id=%(switch_id)s'
203
204
205 class CommandFailure(RyuException):
206     pass
207
208
209 class RestRouterAPI(app_manager.RyuApp):
210
211     OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION,
212                     ofproto_v1_2.OFP_VERSION,
213                     ofproto_v1_3.OFP_VERSION]
214
215     _CONTEXTS = {'dpset': dpset.DPSet,
216                  'wsgi': WSGIApplication}
217
218     def __init__(self, *args, **kwargs):
219         super(RestRouterAPI, self).__init__(*args, **kwargs)
220
221         # logger configure
222         RouterController.set_logger(self.logger)
223
224         wsgi = kwargs['wsgi']
225         self.waiters = {}
226         self.data = {'waiters': self.waiters}
227
228         mapper = wsgi.mapper
229         wsgi.registory['RouterController'] = self.data
230         requirements = {'switch_id': SWITCHID_PATTERN,
231                         'vlan_id': VLANID_PATTERN}
232
233         # For no vlan data
234         path = '/router/{switch_id}'
235         mapper.connect('router', path, controller=RouterController,
236                        requirements=requirements,
237                        action='get_data',
238                        conditions=dict(method=['GET']))
239         mapper.connect('router', path, controller=RouterController,
240                        requirements=requirements,
241                        action='set_data',
242                        conditions=dict(method=['POST']))
243         mapper.connect('router', path, controller=RouterController,
244                        requirements=requirements,
245                        action='delete_data',
246                        conditions=dict(method=['DELETE']))
247         # For vlan data
248         path = '/router/{switch_id}/{vlan_id}'
249         mapper.connect('router', path, controller=RouterController,
250                        requirements=requirements,
251                        action='get_vlan_data',
252                        conditions=dict(method=['GET']))
253         mapper.connect('router', path, controller=RouterController,
254                        requirements=requirements,
255                        action='set_vlan_data',
256                        conditions=dict(method=['POST']))
257         mapper.connect('router', path, controller=RouterController,
258                        requirements=requirements,
259                        action='delete_vlan_data',
260                        conditions=dict(method=['DELETE']))
261
262     @set_ev_cls(dpset.EventDP, dpset.DPSET_EV_DISPATCHER)
263     def datapath_handler(self, ev):
264         if ev.enter:
265             RouterController.register_router(ev.dp)
266         else:
267             RouterController.unregister_router(ev.dp)
268
269     @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
270     def packet_in_handler(self, ev):
271         RouterController.packet_in_handler(ev.msg)
272
273     def _stats_reply_handler(self, ev):
274         msg = ev.msg
275         dp = msg.datapath
276
277         if (dp.id not in self.waiters
278                 or msg.xid not in self.waiters[dp.id]):
279             return
280         event, msgs = self.waiters[dp.id][msg.xid]
281         msgs.append(msg)
282
283         if ofproto_v1_3.OFP_VERSION == dp.ofproto.OFP_VERSION:
284             more = dp.ofproto.OFPMPF_REPLY_MORE
285         else:
286             more = dp.ofproto.OFPSF_REPLY_MORE
287         if msg.flags & more:
288             return
289         del self.waiters[dp.id][msg.xid]
290         event.set()
291
292     # for OpenFlow version1.0
293     @set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
294     def stats_reply_handler_v1_0(self, ev):
295         self._stats_reply_handler(ev)
296
297     # for OpenFlow version1.2/1.3
298     @set_ev_cls(ofp_event.EventOFPStatsReply, MAIN_DISPATCHER)
299     def stats_reply_handler_v1_2(self, ev):
300         self._stats_reply_handler(ev)
301
302     # TODO: Update routing table when port status is changed.
303
304
305 # REST command template
306 def rest_command(func):
307     def _rest_command(*args, **kwargs):
308         try:
309             msg = func(*args, **kwargs)
310             return Response(content_type='application/json',
311                             body=json.dumps(msg))
312
313         except SyntaxError as e:
314             status = 400
315             details = e.msg
316         except (ValueError, NameError) as e:
317             status = 400
318             details = e.message
319
320         except NotFoundError as msg:
321             status = 404
322             details = str(msg)
323
324         msg = {REST_RESULT: REST_NG,
325                REST_DETAILS: details}
326         return Response(status=status, body=json.dumps(msg))
327
328     return _rest_command
329
330
331 class RouterController(ControllerBase):
332
333     _ROUTER_LIST = {}
334     _LOGGER = None
335
336     def __init__(self, req, link, data, **config):
337         super(RouterController, self).__init__(req, link, data, **config)
338         self.waiters = data['waiters']
339
340     @classmethod
341     def set_logger(cls, logger):
342         cls._LOGGER = logger
343         cls._LOGGER.propagate = False
344         hdlr = logging.StreamHandler()
345         fmt_str = '[RT][%(levelname)s] switch_id=%(sw_id)s: %(message)s'
346         hdlr.setFormatter(logging.Formatter(fmt_str))
347         cls._LOGGER.addHandler(hdlr)
348
349     @classmethod
350     def register_router(cls, dp):
351         dpid = {'sw_id': dpid_lib.dpid_to_str(dp.id)}
352         try:
353             router = Router(dp, cls._LOGGER)
354         except OFPUnknownVersion as message:
355             cls._LOGGER.error(str(message), extra=dpid)
356             return
357         cls._ROUTER_LIST.setdefault(dp.id, router)
358         cls._LOGGER.info('Join as router.', extra=dpid)
359
360     @classmethod
361     def unregister_router(cls, dp):
362         if dp.id in cls._ROUTER_LIST:
363             cls._ROUTER_LIST[dp.id].delete()
364             del cls._ROUTER_LIST[dp.id]
365
366             dpid = {'sw_id': dpid_lib.dpid_to_str(dp.id)}
367             cls._LOGGER.info('Leave router.', extra=dpid)
368
369     @classmethod
370     def packet_in_handler(cls, msg):
371         dp_id = msg.datapath.id
372         if dp_id in cls._ROUTER_LIST:
373             router = cls._ROUTER_LIST[dp_id]
374             router.packet_in_handler(msg)
375
376     # GET /router/{switch_id}
377     @rest_command
378     def get_data(self, req, switch_id, **_kwargs):
379         return self._access_router(switch_id, VLANID_NONE,
380                                    'get_data', req)
381
382     # GET /router/{switch_id}/{vlan_id}
383     @rest_command
384     def get_vlan_data(self, req, switch_id, vlan_id, **_kwargs):
385         return self._access_router(switch_id, vlan_id,
386                                    'get_data', req)
387
388     # POST /router/{switch_id}
389     @rest_command
390     def set_data(self, req, switch_id, **_kwargs):
391         return self._access_router(switch_id, VLANID_NONE,
392                                    'set_data', req)
393
394     # POST /router/{switch_id}/{vlan_id}
395     @rest_command
396     def set_vlan_data(self, req, switch_id, vlan_id, **_kwargs):
397         return self._access_router(switch_id, vlan_id,
398                                    'set_data', req)
399
400     # DELETE /router/{switch_id}
401     @rest_command
402     def delete_data(self, req, switch_id, **_kwargs):
403         return self._access_router(switch_id, VLANID_NONE,
404                                    'delete_data', req)
405
406     # DELETE /router/{switch_id}/{vlan_id}
407     @rest_command
408     def delete_vlan_data(self, req, switch_id, vlan_id, **_kwargs):
409         return self._access_router(switch_id, vlan_id,
410                                    'delete_data', req)
411
412     def _access_router(self, switch_id, vlan_id, func, req):
413         rest_message = []
414         routers = self._get_router(switch_id)
415         try:
416             param = req.json if req.body else {}
417         except ValueError:
418             raise SyntaxError('invalid syntax %s', req.body)
419         for router in routers.values():
420             function = getattr(router, func)
421             data = function(vlan_id, param, self.waiters)
422             rest_message.append(data)
423
424         return rest_message
425
426     def _get_router(self, switch_id):
427         routers = {}
428
429         if switch_id == REST_ALL:
430             routers = self._ROUTER_LIST
431         else:
432             sw_id = dpid_lib.str_to_dpid(switch_id)
433             if sw_id in self._ROUTER_LIST:
434                 routers = {sw_id: self._ROUTER_LIST[sw_id]}
435
436         if routers:
437             return routers
438         else:
439             raise NotFoundError(switch_id=switch_id)
440
441
442 class Router(dict):
443     def __init__(self, dp, logger):
444         super(Router, self).__init__()
445         self.dp = dp
446         self.dpid_str = dpid_lib.dpid_to_str(dp.id)
447         self.sw_id = {'sw_id': self.dpid_str}
448         self.logger = logger
449
450         self.port_data = PortData(dp.ports)
451
452         ofctl = OfCtl.factory(dp, logger)
453         cookie = COOKIE_DEFAULT_ID
454
455         # Set SW config: TTL error packet in (for OFPv1.2/1.3)
456         ofctl.set_sw_config_for_ttl()
457
458         # Set flow: ARP handling (packet in)
459         priority = get_priority(PRIORITY_ARP_HANDLING)
460         ofctl.set_packetin_flow(cookie, priority, dl_type=ether.ETH_TYPE_ARP)
461         self.logger.info('Set ARP handling (packet in) flow [cookie=0x%x]',
462                          cookie, extra=self.sw_id)
463
464         # Set flow: L2 switching (normal)
465         priority = get_priority(PRIORITY_NORMAL)
466         ofctl.set_normal_flow(cookie, priority)
467         self.logger.info('Set L2 switching (normal) flow [cookie=0x%x]',
468                          cookie, extra=self.sw_id)
469
470         # Set VlanRouter for vid=None.
471         vlan_router = VlanRouter(VLANID_NONE, dp, self.port_data, logger)
472         self[VLANID_NONE] = vlan_router
473
474         # Start cyclic routing table check.
475         self.thread = hub.spawn(self._cyclic_update_routing_tbl)
476         self.logger.info('Start cyclic routing table update.',
477                          extra=self.sw_id)
478
479     def delete(self):
480         hub.kill(self.thread)
481         self.thread.wait()
482         self.logger.info('Stop cyclic routing table update.',
483                          extra=self.sw_id)
484
485     def _get_vlan_router(self, vlan_id):
486         vlan_routers = []
487
488         if vlan_id == REST_ALL:
489             vlan_routers = list(self.values())
490         else:
491             vlan_id = int(vlan_id)
492             if (vlan_id != VLANID_NONE and
493                     (vlan_id < VLANID_MIN or VLANID_MAX < vlan_id)):
494                 msg = 'Invalid {vlan_id} value. Set [%d-%d]'
495                 raise ValueError(msg % (VLANID_MIN, VLANID_MAX))
496             elif vlan_id in self:
497                 vlan_routers = [self[vlan_id]]
498
499         return vlan_routers
500
501     def _add_vlan_router(self, vlan_id):
502         vlan_id = int(vlan_id)
503         if vlan_id not in self:
504             vlan_router = VlanRouter(vlan_id, self.dp, self.port_data,
505                                      self.logger)
506             self[vlan_id] = vlan_router
507         return self[vlan_id]
508
509     def _del_vlan_router(self, vlan_id, waiters):
510         #  Remove unnecessary VlanRouter.
511         if vlan_id == VLANID_NONE:
512             return
513
514         vlan_router = self[vlan_id]
515         if (len(vlan_router.address_data) == 0
516                 and len(vlan_router.routing_tbl) == 0):
517             vlan_router.delete(waiters)
518             del self[vlan_id]
519
520     def get_data(self, vlan_id, dummy1, dummy2):
521         vlan_routers = self._get_vlan_router(vlan_id)
522         if vlan_routers:
523             msgs = [vlan_router.get_data() for vlan_router in vlan_routers]
524         else:
525             msgs = [{REST_VLANID: vlan_id}]
526
527         return {REST_SWITCHID: self.dpid_str,
528                 REST_NW: msgs}
529
530     def set_data(self, vlan_id, param, waiters):
531         vlan_routers = self._get_vlan_router(vlan_id)
532         if not vlan_routers:
533             vlan_routers = [self._add_vlan_router(vlan_id)]
534
535         msgs = []
536         for vlan_router in vlan_routers:
537             try:
538                 msg = vlan_router.set_data(param)
539                 msgs.append(msg)
540                 if msg[REST_RESULT] == REST_NG:
541                     # Data setting is failure.
542                     self._del_vlan_router(vlan_router.vlan_id, waiters)
543             except ValueError as err_msg:
544                 # Data setting is failure.
545                 self._del_vlan_router(vlan_router.vlan_id, waiters)
546                 raise err_msg
547
548         return {REST_SWITCHID: self.dpid_str,
549                 REST_COMMAND_RESULT: msgs}
550
551     def delete_data(self, vlan_id, param, waiters):
552         msgs = []
553         vlan_routers = self._get_vlan_router(vlan_id)
554         if vlan_routers:
555             for vlan_router in vlan_routers:
556                 msg = vlan_router.delete_data(param, waiters)
557                 if msg:
558                     msgs.append(msg)
559                 # Check unnecessary VlanRouter.
560                 self._del_vlan_router(vlan_router.vlan_id, waiters)
561         if not msgs:
562             msgs = [{REST_RESULT: REST_NG,
563                      REST_DETAILS: 'Data is nothing.'}]
564
565         return {REST_SWITCHID: self.dpid_str,
566                 REST_COMMAND_RESULT: msgs}
567
568     def packet_in_handler(self, msg):
569         pkt = packet.Packet(msg.data)
570         # TODO: Packet library convert to string
571         # self.logger.debug('Packet in = %s', str(pkt), self.sw_id)
572         header_list = dict((p.protocol_name, p)
573                            for p in pkt.protocols
574                            if isinstance(p, packet_base.PacketBase))
575         if header_list:
576             # Check vlan-tag
577             vlan_id = VLANID_NONE
578             if VLAN in header_list:
579                 vlan_id = header_list[VLAN].vid
580
581             # Event dispatch
582             if vlan_id in self:
583                 self[vlan_id].packet_in_handler(msg, header_list)
584             else:
585                 self.logger.debug('Drop unknown vlan packet. [vlan_id=%d]',
586                                   vlan_id, extra=self.sw_id)
587
588     def _cyclic_update_routing_tbl(self):
589         while True:
590             # send ARP to all gateways.
591             for vlan_router in self.values():
592                 vlan_router.send_arp_all_gw()
593                 hub.sleep(1)
594
595             hub.sleep(CHK_ROUTING_TBL_INTERVAL)
596
597
598 class VlanRouter(object):
599     def __init__(self, vlan_id, dp, port_data, logger):
600         super(VlanRouter, self).__init__()
601         self.vlan_id = vlan_id
602         self.dp = dp
603         self.sw_id = {'sw_id': dpid_lib.dpid_to_str(dp.id)}
604         self.logger = logger
605
606         self.port_data = port_data
607         self.address_data = AddressData()
608         self.routing_tbl = RoutingTable()
609         self.packet_buffer = SuspendPacketList(self.send_icmp_unreach_error)
610         self.ofctl = OfCtl.factory(dp, logger)
611
612         # Set flow: default route (drop)
613         self._set_defaultroute_drop()
614
615     def delete(self, waiters):
616         # Delete flow.
617         msgs = self.ofctl.get_all_flow(waiters)
618         for msg in msgs:
619             for stats in msg.body:
620                 vlan_id = VlanRouter._cookie_to_id(REST_VLANID, stats.cookie)
621                 if vlan_id == self.vlan_id:
622                     self.ofctl.delete_flow(stats)
623
624         assert len(self.packet_buffer) == 0
625
626     @staticmethod
627     def _cookie_to_id(id_type, cookie):
628         if id_type == REST_VLANID:
629             rest_id = cookie >> COOKIE_SHIFT_VLANID
630         elif id_type == REST_ADDRESSID:
631             rest_id = cookie & UINT32_MAX
632         else:
633             assert id_type == REST_ROUTEID
634             rest_id = (cookie & UINT32_MAX) >> COOKIE_SHIFT_ROUTEID
635
636         return rest_id
637
638     def _id_to_cookie(self, id_type, rest_id):
639         vid = self.vlan_id << COOKIE_SHIFT_VLANID
640
641         if id_type == REST_VLANID:
642             cookie = rest_id << COOKIE_SHIFT_VLANID
643         elif id_type == REST_ADDRESSID:
644             cookie = vid + rest_id
645         else:
646             assert id_type == REST_ROUTEID
647             cookie = vid + (rest_id << COOKIE_SHIFT_ROUTEID)
648
649         return cookie
650
651     def _get_priority(self, priority_type, route=None):
652         return get_priority(priority_type, vid=self.vlan_id, route=route)
653
654     def _response(self, msg):
655         if msg and self.vlan_id:
656             msg.setdefault(REST_VLANID, self.vlan_id)
657         return msg
658
659     def get_data(self):
660         address_data = self._get_address_data()
661         routing_data = self._get_routing_data()
662
663         data = {}
664         if address_data[REST_ADDRESS]:
665             data.update(address_data)
666         if routing_data[REST_ROUTE]:
667             data.update(routing_data)
668
669         return self._response(data)
670
671     def _get_address_data(self):
672         address_data = []
673         for value in self.address_data.values():
674             default_gw = ip_addr_ntoa(value.default_gw)
675             address = '%s/%d' % (default_gw, value.netmask)
676             data = {REST_ADDRESSID: value.address_id,
677                     REST_ADDRESS: address}
678             address_data.append(data)
679         return {REST_ADDRESS: address_data}
680
681     def _get_routing_data(self):
682         routing_data = []
683         for key, value in self.routing_tbl.items():
684             if value.gateway_mac is not None:
685                 gateway = ip_addr_ntoa(value.gateway_ip)
686                 data = {REST_ROUTEID: value.route_id,
687                         REST_DESTINATION: key,
688                         REST_GATEWAY: gateway}
689                 routing_data.append(data)
690         return {REST_ROUTE: routing_data}
691
692     def set_data(self, data):
693         details = None
694
695         try:
696             # Set address data
697             if REST_ADDRESS in data:
698                 address = data[REST_ADDRESS]
699                 address_id = self._set_address_data(address)
700                 details = 'Add address [address_id=%d]' % address_id
701             # Set routing data
702             elif REST_GATEWAY in data:
703                 gateway = data[REST_GATEWAY]
704                 if REST_DESTINATION in data:
705                     destination = data[REST_DESTINATION]
706                 else:
707                     destination = DEFAULT_ROUTE
708                 route_id = self._set_routing_data(destination, gateway)
709                 details = 'Add route [route_id=%d]' % route_id
710
711         except CommandFailure as err_msg:
712             msg = {REST_RESULT: REST_NG, REST_DETAILS: str(err_msg)}
713             return self._response(msg)
714
715         if details is not None:
716             msg = {REST_RESULT: REST_OK, REST_DETAILS: details}
717             return self._response(msg)
718         else:
719             raise ValueError('Invalid parameter.')
720
721     def _set_address_data(self, address):
722         address = self.address_data.add(address)
723
724         cookie = self._id_to_cookie(REST_ADDRESSID, address.address_id)
725
726         # Set flow: host MAC learning (packet in)
727         priority = self._get_priority(PRIORITY_MAC_LEARNING)
728         self.ofctl.set_packetin_flow(cookie, priority,
729                                      dl_type=ether.ETH_TYPE_IP,
730                                      dl_vlan=self.vlan_id,
731                                      dst_ip=address.nw_addr,
732                                      dst_mask=address.netmask)
733         log_msg = 'Set host MAC learning (packet in) flow [cookie=0x%x]'
734         self.logger.info(log_msg, cookie, extra=self.sw_id)
735
736         # set Flow: IP handling(PacketIn)
737         priority = self._get_priority(PRIORITY_IP_HANDLING)
738         self.ofctl.set_packetin_flow(cookie, priority,
739                                      dl_type=ether.ETH_TYPE_IP,
740                                      dl_vlan=self.vlan_id,
741                                      dst_ip=address.default_gw)
742         self.logger.info('Set IP handling (packet in) flow [cookie=0x%x]',
743                          cookie, extra=self.sw_id)
744
745         # Set flow: L2 switching (normal)
746         outport = self.ofctl.dp.ofproto.OFPP_NORMAL
747         priority = self._get_priority(PRIORITY_L2_SWITCHING)
748         self.ofctl.set_routing_flow(
749             cookie, priority, outport, dl_vlan=self.vlan_id,
750             nw_src=address.nw_addr, src_mask=address.netmask,
751             nw_dst=address.nw_addr, dst_mask=address.netmask)
752         self.logger.info('Set L2 switching (normal) flow [cookie=0x%x]',
753                          cookie, extra=self.sw_id)
754
755         # Send GARP
756         self.send_arp_request(address.default_gw, address.default_gw)
757
758         return address.address_id
759
760     def _set_routing_data(self, destination, gateway):
761         err_msg = 'Invalid [%s] value.' % REST_GATEWAY
762         dst_ip = ip_addr_aton(gateway, err_msg=err_msg)
763         address = self.address_data.get_data(ip=dst_ip)
764         if address is None:
765             msg = 'Gateway=%s\'s address is not registered.' % gateway
766             raise CommandFailure(msg=msg)
767         elif dst_ip == address.default_gw:
768             msg = 'Gateway=%s is used as default gateway of address_id=%d'\
769                 % (gateway, address.address_id)
770             raise CommandFailure(msg=msg)
771         else:
772             src_ip = address.default_gw
773             route = self.routing_tbl.add(destination, gateway)
774             self._set_route_packetin(route)
775             self.send_arp_request(src_ip, dst_ip)
776             return route.route_id
777
778     def _set_defaultroute_drop(self):
779         cookie = self._id_to_cookie(REST_VLANID, self.vlan_id)
780         priority = self._get_priority(PRIORITY_DEFAULT_ROUTING)
781         outport = None  # for drop
782         self.ofctl.set_routing_flow(cookie, priority, outport,
783                                     dl_vlan=self.vlan_id)
784         self.logger.info('Set default route (drop) flow [cookie=0x%x]',
785                          cookie, extra=self.sw_id)
786
787     def _set_route_packetin(self, route):
788         cookie = self._id_to_cookie(REST_ROUTEID, route.route_id)
789         priority, log_msg = self._get_priority(PRIORITY_TYPE_ROUTE,
790                                                route=route)
791         self.ofctl.set_packetin_flow(cookie, priority,
792                                      dl_type=ether.ETH_TYPE_IP,
793                                      dl_vlan=self.vlan_id,
794                                      dst_ip=route.dst_ip,
795                                      dst_mask=route.netmask)
796         self.logger.info('Set %s (packet in) flow [cookie=0x%x]', log_msg,
797                          cookie, extra=self.sw_id)
798
799     def delete_data(self, data, waiters):
800         if REST_ROUTEID in data:
801             route_id = data[REST_ROUTEID]
802             msg = self._delete_routing_data(route_id, waiters)
803         elif REST_ADDRESSID in data:
804             address_id = data[REST_ADDRESSID]
805             msg = self._delete_address_data(address_id, waiters)
806         else:
807             raise ValueError('Invalid parameter.')
808
809         return self._response(msg)
810
811     def _delete_address_data(self, address_id, waiters):
812         if address_id != REST_ALL:
813             try:
814                 address_id = int(address_id)
815             except ValueError as e:
816                 err_msg = 'Invalid [%s] value. %s'
817                 raise ValueError(err_msg % (REST_ADDRESSID, e.message))
818
819         skip_ids = self._chk_addr_relation_route(address_id)
820
821         # Get all flow.
822         delete_list = []
823         msgs = self.ofctl.get_all_flow(waiters)
824         max_id = UINT16_MAX
825         for msg in msgs:
826             for stats in msg.body:
827                 vlan_id = VlanRouter._cookie_to_id(REST_VLANID, stats.cookie)
828                 if vlan_id != self.vlan_id:
829                     continue
830                 addr_id = VlanRouter._cookie_to_id(REST_ADDRESSID,
831                                                    stats.cookie)
832                 if addr_id in skip_ids:
833                     continue
834                 elif address_id == REST_ALL:
835                     if addr_id <= COOKIE_DEFAULT_ID or max_id < addr_id:
836                         continue
837                 elif address_id != addr_id:
838                     continue
839                 delete_list.append(stats)
840
841         delete_ids = []
842         for flow_stats in delete_list:
843             # Delete flow
844             self.ofctl.delete_flow(flow_stats)
845             address_id = VlanRouter._cookie_to_id(REST_ADDRESSID,
846                                                   flow_stats.cookie)
847
848             del_address = self.address_data.get_data(addr_id=address_id)
849             if del_address is not None:
850                 # Clean up suspend packet threads.
851                 self.packet_buffer.delete(del_addr=del_address)
852
853                 # Delete data.
854                 self.address_data.delete(address_id)
855                 if address_id not in delete_ids:
856                     delete_ids.append(address_id)
857
858         msg = {}
859         if delete_ids:
860             delete_ids = ','.join(str(addr_id) for addr_id in delete_ids)
861             details = 'Delete address [address_id=%s]' % delete_ids
862             msg = {REST_RESULT: REST_OK, REST_DETAILS: details}
863
864         if skip_ids:
865             skip_ids = ','.join(str(addr_id) for addr_id in skip_ids)
866             details = 'Skip delete (related route exist) [address_id=%s]'\
867                 % skip_ids
868             if msg:
869                 msg[REST_DETAILS] += ', %s' % details
870             else:
871                 msg = {REST_RESULT: REST_NG, REST_DETAILS: details}
872
873         return msg
874
875     def _delete_routing_data(self, route_id, waiters):
876         if route_id != REST_ALL:
877             try:
878                 route_id = int(route_id)
879             except ValueError as e:
880                 err_msg = 'Invalid [%s] value. %s'
881                 raise ValueError(err_msg % (REST_ROUTEID, e.message))
882
883         # Get all flow.
884         msgs = self.ofctl.get_all_flow(waiters)
885
886         delete_list = []
887         for msg in msgs:
888             for stats in msg.body:
889                 vlan_id = VlanRouter._cookie_to_id(REST_VLANID, stats.cookie)
890                 if vlan_id != self.vlan_id:
891                     continue
892                 rt_id = VlanRouter._cookie_to_id(REST_ROUTEID, stats.cookie)
893                 if route_id == REST_ALL:
894                     if rt_id == COOKIE_DEFAULT_ID:
895                         continue
896                 elif route_id != rt_id:
897                     continue
898                 delete_list.append(stats)
899
900         # Delete flow.
901         delete_ids = []
902         for flow_stats in delete_list:
903             self.ofctl.delete_flow(flow_stats)
904             route_id = VlanRouter._cookie_to_id(REST_ROUTEID,
905                                                 flow_stats.cookie)
906             self.routing_tbl.delete(route_id)
907             if route_id not in delete_ids:
908                 delete_ids.append(route_id)
909
910             # case: Default route deleted. -> set flow (drop)
911             route_type = get_priority_type(flow_stats.priority,
912                                            vid=self.vlan_id)
913             if route_type == PRIORITY_DEFAULT_ROUTING:
914                 self._set_defaultroute_drop()
915
916         msg = {}
917         if delete_ids:
918             delete_ids = ','.join(str(route_id) for route_id in delete_ids)
919             details = 'Delete route [route_id=%s]' % delete_ids
920             msg = {REST_RESULT: REST_OK, REST_DETAILS: details}
921
922         return msg
923
924     def _chk_addr_relation_route(self, address_id):
925         # Check exist of related routing data.
926         relate_list = []
927         gateways = self.routing_tbl.get_gateways()
928         for gateway in gateways:
929             address = self.address_data.get_data(ip=gateway)
930             if address is not None:
931                 if (address_id == REST_ALL
932                         and address.address_id not in relate_list):
933                     relate_list.append(address.address_id)
934                 elif address.address_id == address_id:
935                     relate_list = [address_id]
936                     break
937         return relate_list
938
939     def packet_in_handler(self, msg, header_list):
940         # Check invalid TTL (for OpenFlow V1.2/1.3)
941         ofproto = self.dp.ofproto
942         if ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION or \
943                 ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
944             if msg.reason == ofproto.OFPR_INVALID_TTL:
945                 self._packetin_invalid_ttl(msg, header_list)
946                 return
947
948         # Analyze event type.
949         if ARP in header_list:
950             self._packetin_arp(msg, header_list)
951             return
952
953         if IPV4 in header_list:
954             rt_ports = self.address_data.get_default_gw()
955             if header_list[IPV4].dst in rt_ports:
956                 # Packet to router's port.
957                 if ICMP in header_list:
958                     if header_list[ICMP].type == icmp.ICMP_ECHO_REQUEST:
959                         self._packetin_icmp_req(msg, header_list)
960                         return
961                 elif TCP in header_list or UDP in header_list:
962                     self._packetin_tcp_udp(msg, header_list)
963                     return
964             else:
965                 # Packet to internal host or gateway router.
966                 self._packetin_to_node(msg, header_list)
967                 return
968
969     def _packetin_arp(self, msg, header_list):
970         src_addr = self.address_data.get_data(ip=header_list[ARP].src_ip)
971         if src_addr is None:
972             return
973
974         # case: Receive ARP from the gateway
975         #  Update routing table.
976         # case: Receive ARP from an internal host
977         #  Learning host MAC.
978         gw_flg = self._update_routing_tbl(msg, header_list)
979         if gw_flg is False:
980             self._learning_host_mac(msg, header_list)
981
982         # ARP packet handling.
983         in_port = self.ofctl.get_packetin_inport(msg)
984         src_ip = header_list[ARP].src_ip
985         dst_ip = header_list[ARP].dst_ip
986         srcip = ip_addr_ntoa(src_ip)
987         dstip = ip_addr_ntoa(dst_ip)
988         rt_ports = self.address_data.get_default_gw()
989
990         if src_ip == dst_ip:
991             # GARP -> packet forward (normal)
992             output = self.ofctl.dp.ofproto.OFPP_NORMAL
993             self.ofctl.send_packet_out(in_port, output, msg.data)
994
995             self.logger.info('Receive GARP from [%s].', srcip,
996                              extra=self.sw_id)
997             self.logger.info('Send GARP (normal).', extra=self.sw_id)
998
999         elif dst_ip not in rt_ports:
1000             dst_addr = self.address_data.get_data(ip=dst_ip)
1001             if (dst_addr is not None and
1002                     src_addr.address_id == dst_addr.address_id):
1003                 # ARP from internal host -> packet forward (normal)
1004                 output = self.ofctl.dp.ofproto.OFPP_NORMAL
1005                 self.ofctl.send_packet_out(in_port, output, msg.data)
1006
1007                 self.logger.info('Receive ARP from an internal host [%s].',
1008                                  srcip, extra=self.sw_id)
1009                 self.logger.info('Send ARP (normal)', extra=self.sw_id)
1010         else:
1011             if header_list[ARP].opcode == arp.ARP_REQUEST:
1012                 # ARP request to router port -> send ARP reply
1013                 src_mac = self.port_data[in_port].mac
1014                 dst_mac = header_list[ARP].src_mac
1015                 arp_target_mac = dst_mac
1016                 output = in_port
1017                 in_port = self.ofctl.dp.ofproto.OFPP_CONTROLLER
1018
1019                 self.ofctl.send_arp(arp.ARP_REPLY, self.vlan_id,
1020                                     src_mac, dst_mac, dst_ip, src_ip,
1021                                     arp_target_mac, in_port, output)
1022
1023                 log_msg = 'Receive ARP request from [%s] to router port [%s].'
1024                 self.logger.info(log_msg, srcip, dstip, extra=self.sw_id)
1025                 self.logger.info('Send ARP reply to [%s]', srcip,
1026                                  extra=self.sw_id)
1027
1028             elif header_list[ARP].opcode == arp.ARP_REPLY:
1029                 #  ARP reply to router port -> suspend packets forward
1030                 log_msg = 'Receive ARP reply from [%s] to router port [%s].'
1031                 self.logger.info(log_msg, srcip, dstip, extra=self.sw_id)
1032
1033                 packet_list = self.packet_buffer.get_data(src_ip)
1034                 if packet_list:
1035                     # stop ARP reply wait thread.
1036                     for suspend_packet in packet_list:
1037                         self.packet_buffer.delete(pkt=suspend_packet)
1038
1039                     # send suspend packet.
1040                     output = self.ofctl.dp.ofproto.OFPP_TABLE
1041                     for suspend_packet in packet_list:
1042                         self.ofctl.send_packet_out(suspend_packet.in_port,
1043                                                    output,
1044                                                    suspend_packet.data)
1045                         self.logger.info('Send suspend packet to [%s].',
1046                                          srcip, extra=self.sw_id)
1047
1048     def _packetin_icmp_req(self, msg, header_list):
1049         # Send ICMP echo reply.
1050         in_port = self.ofctl.get_packetin_inport(msg)
1051         self.ofctl.send_icmp(in_port, header_list, self.vlan_id,
1052                              icmp.ICMP_ECHO_REPLY,
1053                              icmp.ICMP_ECHO_REPLY_CODE,
1054                              icmp_data=header_list[ICMP].data)
1055
1056         srcip = ip_addr_ntoa(header_list[IPV4].src)
1057         dstip = ip_addr_ntoa(header_list[IPV4].dst)
1058         log_msg = 'Receive ICMP echo request from [%s] to router port [%s].'
1059         self.logger.info(log_msg, srcip, dstip, extra=self.sw_id)
1060         self.logger.info('Send ICMP echo reply to [%s].', srcip,
1061                          extra=self.sw_id)
1062
1063     def _packetin_tcp_udp(self, msg, header_list):
1064         # Send ICMP port unreach error.
1065         in_port = self.ofctl.get_packetin_inport(msg)
1066         self.ofctl.send_icmp(in_port, header_list, self.vlan_id,
1067                              icmp.ICMP_DEST_UNREACH,
1068                              icmp.ICMP_PORT_UNREACH_CODE,
1069                              msg_data=msg.data)
1070
1071         srcip = ip_addr_ntoa(header_list[IPV4].src)
1072         dstip = ip_addr_ntoa(header_list[IPV4].dst)
1073         self.logger.info('Receive TCP/UDP from [%s] to router port [%s].',
1074                          srcip, dstip, extra=self.sw_id)
1075         self.logger.info('Send ICMP destination unreachable to [%s].', srcip,
1076                          extra=self.sw_id)
1077
1078     def _packetin_to_node(self, msg, header_list):
1079         if len(self.packet_buffer) >= MAX_SUSPENDPACKETS:
1080             self.logger.info('Packet is dropped, MAX_SUSPENDPACKETS exceeded.',
1081                              extra=self.sw_id)
1082             return
1083
1084         # Send ARP request to get node MAC address.
1085         in_port = self.ofctl.get_packetin_inport(msg)
1086         src_ip = None
1087         dst_ip = header_list[IPV4].dst
1088         srcip = ip_addr_ntoa(header_list[IPV4].src)
1089         dstip = ip_addr_ntoa(dst_ip)
1090
1091         address = self.address_data.get_data(ip=dst_ip)
1092         if address is not None:
1093             log_msg = 'Receive IP packet from [%s] to an internal host [%s].'
1094             self.logger.info(log_msg, srcip, dstip, extra=self.sw_id)
1095             src_ip = address.default_gw
1096         else:
1097             route = self.routing_tbl.get_data(dst_ip=dst_ip)
1098             if route is not None:
1099                 log_msg = 'Receive IP packet from [%s] to [%s].'
1100                 self.logger.info(log_msg, srcip, dstip, extra=self.sw_id)
1101                 gw_address = self.address_data.get_data(ip=route.gateway_ip)
1102                 if gw_address is not None:
1103                     src_ip = gw_address.default_gw
1104                     dst_ip = route.gateway_ip
1105
1106         if src_ip is not None:
1107             self.packet_buffer.add(in_port, header_list, msg.data)
1108             self.send_arp_request(src_ip, dst_ip, in_port=in_port)
1109             self.logger.info('Send ARP request (flood)', extra=self.sw_id)
1110
1111     def _packetin_invalid_ttl(self, msg, header_list):
1112         # Send ICMP TTL error.
1113         srcip = ip_addr_ntoa(header_list[IPV4].src)
1114         self.logger.info('Receive invalid ttl packet from [%s].', srcip,
1115                          extra=self.sw_id)
1116
1117         in_port = self.ofctl.get_packetin_inport(msg)
1118         src_ip = self._get_send_port_ip(header_list)
1119         if src_ip is not None:
1120             self.ofctl.send_icmp(in_port, header_list, self.vlan_id,
1121                                  icmp.ICMP_TIME_EXCEEDED,
1122                                  icmp.ICMP_TTL_EXPIRED_CODE,
1123                                  msg_data=msg.data, src_ip=src_ip)
1124             self.logger.info('Send ICMP time exceeded to [%s].', srcip,
1125                              extra=self.sw_id)
1126
1127     def send_arp_all_gw(self):
1128         gateways = self.routing_tbl.get_gateways()
1129         for gateway in gateways:
1130             address = self.address_data.get_data(ip=gateway)
1131             self.send_arp_request(address.default_gw, gateway)
1132
1133     def send_arp_request(self, src_ip, dst_ip, in_port=None):
1134         # Send ARP request from all ports.
1135         for send_port in self.port_data.values():
1136             if in_port is None or in_port != send_port.port_no:
1137                 src_mac = send_port.mac
1138                 dst_mac = mac_lib.BROADCAST_STR
1139                 arp_target_mac = mac_lib.DONTCARE_STR
1140                 inport = self.ofctl.dp.ofproto.OFPP_CONTROLLER
1141                 output = send_port.port_no
1142                 self.ofctl.send_arp(arp.ARP_REQUEST, self.vlan_id,
1143                                     src_mac, dst_mac, src_ip, dst_ip,
1144                                     arp_target_mac, inport, output)
1145
1146     def send_icmp_unreach_error(self, packet_buffer):
1147         # Send ICMP host unreach error.
1148         self.logger.info('ARP reply wait timer was timed out.',
1149                          extra=self.sw_id)
1150         src_ip = self._get_send_port_ip(packet_buffer.header_list)
1151         if src_ip is not None:
1152             self.ofctl.send_icmp(packet_buffer.in_port,
1153                                  packet_buffer.header_list,
1154                                  self.vlan_id,
1155                                  icmp.ICMP_DEST_UNREACH,
1156                                  icmp.ICMP_HOST_UNREACH_CODE,
1157                                  msg_data=packet_buffer.data,
1158                                  src_ip=src_ip)
1159
1160             dstip = ip_addr_ntoa(packet_buffer.dst_ip)
1161             self.logger.info('Send ICMP destination unreachable to [%s].',
1162                              dstip, extra=self.sw_id)
1163
1164     def _update_routing_tbl(self, msg, header_list):
1165         # Set flow: routing to gateway.
1166         out_port = self.ofctl.get_packetin_inport(msg)
1167         src_mac = header_list[ARP].src_mac
1168         dst_mac = self.port_data[out_port].mac
1169         src_ip = header_list[ARP].src_ip
1170
1171         gateway_flg = False
1172         for key, value in self.routing_tbl.items():
1173             if value.gateway_ip == src_ip:
1174                 gateway_flg = True
1175                 if value.gateway_mac == src_mac:
1176                     continue
1177                 self.routing_tbl[key].gateway_mac = src_mac
1178
1179                 cookie = self._id_to_cookie(REST_ROUTEID, value.route_id)
1180                 priority, log_msg = self._get_priority(PRIORITY_TYPE_ROUTE,
1181                                                        route=value)
1182                 self.ofctl.set_routing_flow(cookie, priority, out_port,
1183                                             dl_vlan=self.vlan_id,
1184                                             src_mac=dst_mac,
1185                                             dst_mac=src_mac,
1186                                             nw_dst=value.dst_ip,
1187                                             dst_mask=value.netmask,
1188                                             dec_ttl=True)
1189                 self.logger.info('Set %s flow [cookie=0x%x]', log_msg, cookie,
1190                                  extra=self.sw_id)
1191         return gateway_flg
1192
1193     def _learning_host_mac(self, msg, header_list):
1194         # Set flow: routing to internal Host.
1195         out_port = self.ofctl.get_packetin_inport(msg)
1196         src_mac = header_list[ARP].src_mac
1197         dst_mac = self.port_data[out_port].mac
1198         src_ip = header_list[ARP].src_ip
1199
1200         gateways = self.routing_tbl.get_gateways()
1201         if src_ip not in gateways:
1202             address = self.address_data.get_data(ip=src_ip)
1203             if address is not None:
1204                 cookie = self._id_to_cookie(REST_ADDRESSID, address.address_id)
1205                 priority = self._get_priority(PRIORITY_IMPLICIT_ROUTING)
1206                 self.ofctl.set_routing_flow(cookie, priority,
1207                                             out_port, dl_vlan=self.vlan_id,
1208                                             src_mac=dst_mac, dst_mac=src_mac,
1209                                             nw_dst=src_ip,
1210                                             idle_timeout=IDLE_TIMEOUT,
1211                                             dec_ttl=True)
1212                 self.logger.info('Set implicit routing flow [cookie=0x%x]',
1213                                  cookie, extra=self.sw_id)
1214
1215     def _get_send_port_ip(self, header_list):
1216         try:
1217             src_mac = header_list[ETHERNET].src
1218             if IPV4 in header_list:
1219                 src_ip = header_list[IPV4].src
1220             else:
1221                 src_ip = header_list[ARP].src_ip
1222         except KeyError:
1223             self.logger.debug('Receive unsupported packet.', extra=self.sw_id)
1224             return None
1225
1226         address = self.address_data.get_data(ip=src_ip)
1227         if address is not None:
1228             return address.default_gw
1229         else:
1230             route = self.routing_tbl.get_data(gw_mac=src_mac)
1231             if route is not None:
1232                 address = self.address_data.get_data(ip=route.gateway_ip)
1233                 if address is not None:
1234                     return address.default_gw
1235
1236         self.logger.debug('Receive packet from unknown IP[%s].',
1237                           ip_addr_ntoa(src_ip), extra=self.sw_id)
1238         return None
1239
1240
1241 class PortData(dict):
1242     def __init__(self, ports):
1243         super(PortData, self).__init__()
1244         for port in ports.values():
1245             data = Port(port.port_no, port.hw_addr)
1246             self[port.port_no] = data
1247
1248
1249 class Port(object):
1250     def __init__(self, port_no, hw_addr):
1251         super(Port, self).__init__()
1252         self.port_no = port_no
1253         self.mac = hw_addr
1254
1255
1256 class AddressData(dict):
1257     def __init__(self):
1258         super(AddressData, self).__init__()
1259         self.address_id = 1
1260
1261     def add(self, address):
1262         err_msg = 'Invalid [%s] value.' % REST_ADDRESS
1263         nw_addr, mask, default_gw = nw_addr_aton(address, err_msg=err_msg)
1264
1265         # Check overlaps
1266         for other in self.values():
1267             other_mask = mask_ntob(other.netmask)
1268             add_mask = mask_ntob(mask, err_msg=err_msg)
1269             if (other.nw_addr == ipv4_apply_mask(default_gw, other.netmask) or
1270                     nw_addr == ipv4_apply_mask(other.default_gw, mask,
1271                                                err_msg)):
1272                 msg = 'Address overlaps [address_id=%d]' % other.address_id
1273                 raise CommandFailure(msg=msg)
1274
1275         address = Address(self.address_id, nw_addr, mask, default_gw)
1276         ip_str = ip_addr_ntoa(nw_addr)
1277         key = '%s/%d' % (ip_str, mask)
1278         self[key] = address
1279
1280         self.address_id += 1
1281         self.address_id &= UINT32_MAX
1282         if self.address_id == COOKIE_DEFAULT_ID:
1283             self.address_id = 1
1284
1285         return address
1286
1287     def delete(self, address_id):
1288         for key, value in self.items():
1289             if value.address_id == address_id:
1290                 del self[key]
1291                 return
1292
1293     def get_default_gw(self):
1294         return [address.default_gw for address in self.values()]
1295
1296     def get_data(self, addr_id=None, ip=None):
1297         for address in self.values():
1298             if addr_id is not None:
1299                 if addr_id == address.address_id:
1300                     return address
1301             else:
1302                 assert ip is not None
1303                 if ipv4_apply_mask(ip, address.netmask) == address.nw_addr:
1304                     return address
1305         return None
1306
1307
1308 class Address(object):
1309     def __init__(self, address_id, nw_addr, netmask, default_gw):
1310         super(Address, self).__init__()
1311         self.address_id = address_id
1312         self.nw_addr = nw_addr
1313         self.netmask = netmask
1314         self.default_gw = default_gw
1315
1316     def __contains__(self, ip):
1317         return bool(ipv4_apply_mask(ip, self.netmask) == self.nw_addr)
1318
1319
1320 class RoutingTable(dict):
1321     def __init__(self):
1322         super(RoutingTable, self).__init__()
1323         self.route_id = 1
1324
1325     def add(self, dst_nw_addr, gateway_ip):
1326         err_msg = 'Invalid [%s] value.'
1327
1328         if dst_nw_addr == DEFAULT_ROUTE:
1329             dst_ip = 0
1330             netmask = 0
1331         else:
1332             dst_ip, netmask, dummy = nw_addr_aton(
1333                 dst_nw_addr, err_msg=err_msg % REST_DESTINATION)
1334
1335         gateway_ip = ip_addr_aton(gateway_ip, err_msg=err_msg % REST_GATEWAY)
1336
1337         # Check overlaps
1338         overlap_route = None
1339         if dst_nw_addr == DEFAULT_ROUTE:
1340             if DEFAULT_ROUTE in self:
1341                 overlap_route = self[DEFAULT_ROUTE].route_id
1342         elif dst_nw_addr in self:
1343             overlap_route = self[dst_nw_addr].route_id
1344
1345         if overlap_route is not None:
1346             msg = 'Destination overlaps [route_id=%d]' % overlap_route
1347             raise CommandFailure(msg=msg)
1348
1349         routing_data = Route(self.route_id, dst_ip, netmask, gateway_ip)
1350         ip_str = ip_addr_ntoa(dst_ip)
1351         key = '%s/%d' % (ip_str, netmask)
1352         self[key] = routing_data
1353
1354         self.route_id += 1
1355         self.route_id &= UINT32_MAX
1356         if self.route_id == COOKIE_DEFAULT_ID:
1357             self.route_id = 1
1358
1359         return routing_data
1360
1361     def delete(self, route_id):
1362         for key, value in self.items():
1363             if value.route_id == route_id:
1364                 del self[key]
1365                 return
1366
1367     def get_gateways(self):
1368         return [routing_data.gateway_ip for routing_data in self.values()]
1369
1370     def get_data(self, gw_mac=None, dst_ip=None):
1371         if gw_mac is not None:
1372             for route in self.values():
1373                 if gw_mac == route.gateway_mac:
1374                     return route
1375             return None
1376
1377         elif dst_ip is not None:
1378             get_route = None
1379             mask = 0
1380             for route in self.values():
1381                 if ipv4_apply_mask(dst_ip, route.netmask) == route.dst_ip:
1382                     # For longest match
1383                     if mask < route.netmask:
1384                         get_route = route
1385                         mask = route.netmask
1386
1387             if get_route is None:
1388                 get_route = self.get(DEFAULT_ROUTE, None)
1389             return get_route
1390         else:
1391             return None
1392
1393
1394 class Route(object):
1395     def __init__(self, route_id, dst_ip, netmask, gateway_ip):
1396         super(Route, self).__init__()
1397         self.route_id = route_id
1398         self.dst_ip = dst_ip
1399         self.netmask = netmask
1400         self.gateway_ip = gateway_ip
1401         self.gateway_mac = None
1402
1403
1404 class SuspendPacketList(list):
1405     def __init__(self, timeout_function):
1406         super(SuspendPacketList, self).__init__()
1407         self.timeout_function = timeout_function
1408
1409     def add(self, in_port, header_list, data):
1410         suspend_pkt = SuspendPacket(in_port, header_list, data,
1411                                     self.wait_arp_reply_timer)
1412         self.append(suspend_pkt)
1413
1414     def delete(self, pkt=None, del_addr=None):
1415         if pkt is not None:
1416             del_list = [pkt]
1417         else:
1418             assert del_addr is not None
1419             del_list = [pkt for pkt in self if pkt.dst_ip in del_addr]
1420
1421         for pkt in del_list:
1422             self.remove(pkt)
1423             hub.kill(pkt.wait_thread)
1424             pkt.wait_thread.wait()
1425
1426     def get_data(self, dst_ip):
1427         return [pkt for pkt in self if pkt.dst_ip == dst_ip]
1428
1429     def wait_arp_reply_timer(self, suspend_pkt):
1430         hub.sleep(ARP_REPLY_TIMER)
1431         if suspend_pkt in self:
1432             self.timeout_function(suspend_pkt)
1433             self.delete(pkt=suspend_pkt)
1434
1435
1436 class SuspendPacket(object):
1437     def __init__(self, in_port, header_list, data, timer):
1438         super(SuspendPacket, self).__init__()
1439         self.in_port = in_port
1440         self.dst_ip = header_list[IPV4].dst
1441         self.header_list = header_list
1442         self.data = data
1443         # Start ARP reply wait timer.
1444         self.wait_thread = hub.spawn(timer, self)
1445
1446
1447 class OfCtl(object):
1448     _OF_VERSIONS = {}
1449
1450     @staticmethod
1451     def register_of_version(version):
1452         def _register_of_version(cls):
1453             OfCtl._OF_VERSIONS.setdefault(version, cls)
1454             return cls
1455         return _register_of_version
1456
1457     @staticmethod
1458     def factory(dp, logger):
1459         of_version = dp.ofproto.OFP_VERSION
1460         if of_version in OfCtl._OF_VERSIONS:
1461             ofctl = OfCtl._OF_VERSIONS[of_version](dp, logger)
1462         else:
1463             raise OFPUnknownVersion(version=of_version)
1464
1465         return ofctl
1466
1467     def __init__(self, dp, logger):
1468         super(OfCtl, self).__init__()
1469         self.dp = dp
1470         self.sw_id = {'sw_id': dpid_lib.dpid_to_str(dp.id)}
1471         self.logger = logger
1472
1473     def set_sw_config_for_ttl(self):
1474         # OpenFlow v1_2/1_3.
1475         pass
1476
1477     def set_flow(self, cookie, priority, dl_type=0, dl_dst=0, dl_vlan=0,
1478                  nw_src=0, src_mask=32, nw_dst=0, dst_mask=32,
1479                  nw_proto=0, idle_timeout=0, actions=None):
1480         # Abstract method
1481         raise NotImplementedError()
1482
1483     def send_arp(self, arp_opcode, vlan_id, src_mac, dst_mac,
1484                  src_ip, dst_ip, arp_target_mac, in_port, output):
1485         # Generate ARP packet
1486         if vlan_id != VLANID_NONE:
1487             ether_proto = ether.ETH_TYPE_8021Q
1488             pcp = 0
1489             cfi = 0
1490             vlan_ether = ether.ETH_TYPE_ARP
1491             v = vlan.vlan(pcp, cfi, vlan_id, vlan_ether)
1492         else:
1493             ether_proto = ether.ETH_TYPE_ARP
1494         hwtype = 1
1495         arp_proto = ether.ETH_TYPE_IP
1496         hlen = 6
1497         plen = 4
1498
1499         pkt = packet.Packet()
1500         e = ethernet.ethernet(dst_mac, src_mac, ether_proto)
1501         a = arp.arp(hwtype, arp_proto, hlen, plen, arp_opcode,
1502                     src_mac, src_ip, arp_target_mac, dst_ip)
1503         pkt.add_protocol(e)
1504         if vlan_id != VLANID_NONE:
1505             pkt.add_protocol(v)
1506         pkt.add_protocol(a)
1507         pkt.serialize()
1508
1509         # Send packet out
1510         self.send_packet_out(in_port, output, pkt.data, data_str=str(pkt))
1511
1512     def send_icmp(self, in_port, protocol_list, vlan_id, icmp_type,
1513                   icmp_code, icmp_data=None, msg_data=None, src_ip=None):
1514         # Generate ICMP reply packet
1515         csum = 0
1516         offset = ethernet.ethernet._MIN_LEN
1517
1518         if vlan_id != VLANID_NONE:
1519             ether_proto = ether.ETH_TYPE_8021Q
1520             pcp = 0
1521             cfi = 0
1522             vlan_ether = ether.ETH_TYPE_IP
1523             v = vlan.vlan(pcp, cfi, vlan_id, vlan_ether)
1524             offset += vlan.vlan._MIN_LEN
1525         else:
1526             ether_proto = ether.ETH_TYPE_IP
1527
1528         eth = protocol_list[ETHERNET]
1529         e = ethernet.ethernet(eth.src, eth.dst, ether_proto)
1530
1531         ip = protocol_list[IPV4]
1532
1533         if icmp_data is None and msg_data is not None:
1534             # RFC 4884 says that we should send "at least 128 octets"
1535             # if we are using the ICMP Extension Structure.
1536             # We're not using the extension structure, but let's send
1537             # up to 128 bytes of the original msg_data.
1538             #
1539             # RFC 4884 also states that the length field is interpreted in
1540             # 32 bit units, so the length calculated in bytes needs to first
1541             # be divided by 4, then increased by 1 if the modulus is non-zero.
1542             #
1543             # Finally, RFC 4884 says, if we're specifying the length, we MUST
1544             # zero pad to the next 32 bit boundary.
1545             end_of_data = offset + len(ip) + 128
1546             ip_datagram = bytearray()
1547             ip_datagram += msg_data[offset:end_of_data]
1548             data_len = int(len(ip_datagram) / 4)
1549             length_modulus = int(len(ip_datagram) % 4)
1550             if length_modulus:
1551                 data_len += 1
1552                 ip_datagram += bytearray([0] * (4 - length_modulus))
1553             if icmp_type == icmp.ICMP_DEST_UNREACH:
1554                 icmp_data = icmp.dest_unreach(data_len=data_len,
1555                                               data=ip_datagram)
1556             elif icmp_type == icmp.ICMP_TIME_EXCEEDED:
1557                 icmp_data = icmp.TimeExceeded(data_len=data_len,
1558                                               data=ip_datagram)
1559
1560         ic = icmp.icmp(icmp_type, icmp_code, csum, data=icmp_data)
1561
1562         if src_ip is None:
1563             src_ip = ip.dst
1564         ip_total_length = ip.header_length * 4 + ic._MIN_LEN
1565         if ic.data is not None:
1566             ip_total_length += ic.data._MIN_LEN
1567             if ic.data.data is not None:
1568                 ip_total_length += + len(ic.data.data)
1569         i = ipv4.ipv4(ip.version, ip.header_length, ip.tos,
1570                       ip_total_length, ip.identification, ip.flags,
1571                       ip.offset, DEFAULT_TTL, inet.IPPROTO_ICMP, csum,
1572                       src_ip, ip.src)
1573
1574         pkt = packet.Packet()
1575         pkt.add_protocol(e)
1576         if vlan_id != VLANID_NONE:
1577             pkt.add_protocol(v)
1578         pkt.add_protocol(i)
1579         pkt.add_protocol(ic)
1580         pkt.serialize()
1581
1582         # Send packet out
1583         self.send_packet_out(in_port, self.dp.ofproto.OFPP_IN_PORT,
1584                              pkt.data, data_str=str(pkt))
1585
1586     def send_packet_out(self, in_port, output, data, data_str=None):
1587         actions = [self.dp.ofproto_parser.OFPActionOutput(output, 0)]
1588         self.dp.send_packet_out(buffer_id=UINT32_MAX, in_port=in_port,
1589                                 actions=actions, data=data)
1590         # TODO: Packet library convert to string
1591         # if data_str is None:
1592         #     data_str = str(packet.Packet(data))
1593         # self.logger.debug('Packet out = %s', data_str, extra=self.sw_id)
1594
1595     def set_normal_flow(self, cookie, priority):
1596         out_port = self.dp.ofproto.OFPP_NORMAL
1597         actions = [self.dp.ofproto_parser.OFPActionOutput(out_port, 0)]
1598         self.set_flow(cookie, priority, actions=actions)
1599
1600     def set_packetin_flow(self, cookie, priority, dl_type=0, dl_dst=0,
1601                           dl_vlan=0, dst_ip=0, dst_mask=32, nw_proto=0):
1602         miss_send_len = UINT16_MAX
1603         actions = [self.dp.ofproto_parser.OFPActionOutput(
1604             self.dp.ofproto.OFPP_CONTROLLER, miss_send_len)]
1605         self.set_flow(cookie, priority, dl_type=dl_type, dl_dst=dl_dst,
1606                       dl_vlan=dl_vlan, nw_dst=dst_ip, dst_mask=dst_mask,
1607                       nw_proto=nw_proto, actions=actions)
1608
1609     def send_stats_request(self, stats, waiters):
1610         self.dp.set_xid(stats)
1611         waiters_per_dp = waiters.setdefault(self.dp.id, {})
1612         event = hub.Event()
1613         msgs = []
1614         waiters_per_dp[stats.xid] = (event, msgs)
1615         self.dp.send_msg(stats)
1616
1617         try:
1618             event.wait(timeout=OFP_REPLY_TIMER)
1619         except hub.Timeout:
1620             del waiters_per_dp[stats.xid]
1621
1622         return msgs
1623
1624
1625 @OfCtl.register_of_version(ofproto_v1_0.OFP_VERSION)
1626 class OfCtl_v1_0(OfCtl):
1627
1628     def __init__(self, dp, logger):
1629         super(OfCtl_v1_0, self).__init__(dp, logger)
1630
1631     def get_packetin_inport(self, msg):
1632         return msg.in_port
1633
1634     def get_all_flow(self, waiters):
1635         ofp = self.dp.ofproto
1636         ofp_parser = self.dp.ofproto_parser
1637
1638         match = ofp_parser.OFPMatch(ofp.OFPFW_ALL, 0, 0, 0,
1639                                     0, 0, 0, 0, 0, 0, 0, 0, 0)
1640         stats = ofp_parser.OFPFlowStatsRequest(self.dp, 0, match,
1641                                                0xff, ofp.OFPP_NONE)
1642         return self.send_stats_request(stats, waiters)
1643
1644     def set_flow(self, cookie, priority, dl_type=0, dl_dst=0, dl_vlan=0,
1645                  nw_src=0, src_mask=32, nw_dst=0, dst_mask=32,
1646                  nw_proto=0, idle_timeout=0, actions=None):
1647         ofp = self.dp.ofproto
1648         ofp_parser = self.dp.ofproto_parser
1649         cmd = ofp.OFPFC_ADD
1650
1651         # Match
1652         wildcards = ofp.OFPFW_ALL
1653         if dl_type:
1654             wildcards &= ~ofp.OFPFW_DL_TYPE
1655         if dl_dst:
1656             wildcards &= ~ofp.OFPFW_DL_DST
1657         if dl_vlan:
1658             wildcards &= ~ofp.OFPFW_DL_VLAN
1659         if nw_src:
1660             v = (32 - src_mask) << ofp.OFPFW_NW_SRC_SHIFT | \
1661                 ~ofp.OFPFW_NW_SRC_MASK
1662             wildcards &= v
1663             nw_src = ipv4_text_to_int(nw_src)
1664         if nw_dst:
1665             v = (32 - dst_mask) << ofp.OFPFW_NW_DST_SHIFT | \
1666                 ~ofp.OFPFW_NW_DST_MASK
1667             wildcards &= v
1668             nw_dst = ipv4_text_to_int(nw_dst)
1669         if nw_proto:
1670             wildcards &= ~ofp.OFPFW_NW_PROTO
1671
1672         match = ofp_parser.OFPMatch(wildcards, 0, 0, dl_dst, dl_vlan, 0,
1673                                     dl_type, 0, nw_proto,
1674                                     nw_src, nw_dst, 0, 0)
1675         actions = actions or []
1676
1677         m = ofp_parser.OFPFlowMod(self.dp, match, cookie, cmd,
1678                                   idle_timeout=idle_timeout,
1679                                   priority=priority, actions=actions)
1680         self.dp.send_msg(m)
1681
1682     def set_routing_flow(self, cookie, priority, outport, dl_vlan=0,
1683                          nw_src=0, src_mask=32, nw_dst=0, dst_mask=32,
1684                          src_mac=0, dst_mac=0, idle_timeout=0, **dummy):
1685         ofp_parser = self.dp.ofproto_parser
1686
1687         dl_type = ether.ETH_TYPE_IP
1688
1689         # Decrement TTL value is not supported at OpenFlow V1.0
1690         actions = []
1691         if src_mac:
1692             actions.append(ofp_parser.OFPActionSetDlSrc(
1693                            mac_lib.haddr_to_bin(src_mac)))
1694         if dst_mac:
1695             actions.append(ofp_parser.OFPActionSetDlDst(
1696                            mac_lib.haddr_to_bin(dst_mac)))
1697         if outport is not None:
1698             actions.append(ofp_parser.OFPActionOutput(outport))
1699
1700         self.set_flow(cookie, priority, dl_type=dl_type, dl_vlan=dl_vlan,
1701                       nw_src=nw_src, src_mask=src_mask,
1702                       nw_dst=nw_dst, dst_mask=dst_mask,
1703                       idle_timeout=idle_timeout, actions=actions)
1704
1705     def delete_flow(self, flow_stats):
1706         match = flow_stats.match
1707         cookie = flow_stats.cookie
1708         cmd = self.dp.ofproto.OFPFC_DELETE_STRICT
1709         priority = flow_stats.priority
1710         actions = []
1711
1712         flow_mod = self.dp.ofproto_parser.OFPFlowMod(
1713             self.dp, match, cookie, cmd, priority=priority, actions=actions)
1714         self.dp.send_msg(flow_mod)
1715         self.logger.info('Delete flow [cookie=0x%x]', cookie, extra=self.sw_id)
1716
1717
1718 class OfCtl_after_v1_2(OfCtl):
1719
1720     def __init__(self, dp, logger):
1721         super(OfCtl_after_v1_2, self).__init__(dp, logger)
1722
1723     def set_sw_config_for_ttl(self):
1724         pass
1725
1726     def get_packetin_inport(self, msg):
1727         in_port = self.dp.ofproto.OFPP_ANY
1728         for match_field in msg.match.fields:
1729             if match_field.header == self.dp.ofproto.OXM_OF_IN_PORT:
1730                 in_port = match_field.value
1731                 break
1732         return in_port
1733
1734     def get_all_flow(self, waiters):
1735         pass
1736
1737     def set_flow(self, cookie, priority, dl_type=0, dl_dst=0, dl_vlan=0,
1738                  nw_src=0, src_mask=32, nw_dst=0, dst_mask=32,
1739                  nw_proto=0, idle_timeout=0, actions=None):
1740         ofp = self.dp.ofproto
1741         ofp_parser = self.dp.ofproto_parser
1742         cmd = ofp.OFPFC_ADD
1743
1744         # Match
1745         match = ofp_parser.OFPMatch()
1746         if dl_type:
1747             match.set_dl_type(dl_type)
1748         if dl_dst:
1749             match.set_dl_dst(dl_dst)
1750         if dl_vlan:
1751             match.set_vlan_vid(dl_vlan)
1752         if nw_src:
1753             match.set_ipv4_src_masked(ipv4_text_to_int(nw_src),
1754                                       mask_ntob(src_mask))
1755         if nw_dst:
1756             match.set_ipv4_dst_masked(ipv4_text_to_int(nw_dst),
1757                                       mask_ntob(dst_mask))
1758         if nw_proto:
1759             if dl_type == ether.ETH_TYPE_IP:
1760                 match.set_ip_proto(nw_proto)
1761             elif dl_type == ether.ETH_TYPE_ARP:
1762                 match.set_arp_opcode(nw_proto)
1763
1764         # Instructions
1765         actions = actions or []
1766         inst = [ofp_parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
1767                                                  actions)]
1768
1769         m = ofp_parser.OFPFlowMod(self.dp, cookie, 0, 0, cmd, idle_timeout,
1770                                   0, priority, UINT32_MAX, ofp.OFPP_ANY,
1771                                   ofp.OFPG_ANY, 0, match, inst)
1772         self.dp.send_msg(m)
1773
1774     def set_routing_flow(self, cookie, priority, outport, dl_vlan=0,
1775                          nw_src=0, src_mask=32, nw_dst=0, dst_mask=32,
1776                          src_mac=0, dst_mac=0, idle_timeout=0, dec_ttl=False):
1777         ofp = self.dp.ofproto
1778         ofp_parser = self.dp.ofproto_parser
1779
1780         dl_type = ether.ETH_TYPE_IP
1781
1782         actions = []
1783         if dec_ttl:
1784             actions.append(ofp_parser.OFPActionDecNwTtl())
1785         if src_mac:
1786             actions.append(ofp_parser.OFPActionSetField(eth_src=src_mac))
1787         if dst_mac:
1788             actions.append(ofp_parser.OFPActionSetField(eth_dst=dst_mac))
1789         if outport is not None:
1790             actions.append(ofp_parser.OFPActionOutput(outport, 0))
1791
1792         self.set_flow(cookie, priority, dl_type=dl_type, dl_vlan=dl_vlan,
1793                       nw_src=nw_src, src_mask=src_mask,
1794                       nw_dst=nw_dst, dst_mask=dst_mask,
1795                       idle_timeout=idle_timeout, actions=actions)
1796
1797     def delete_flow(self, flow_stats):
1798         ofp = self.dp.ofproto
1799         ofp_parser = self.dp.ofproto_parser
1800
1801         cmd = ofp.OFPFC_DELETE
1802         cookie = flow_stats.cookie
1803         cookie_mask = UINT64_MAX
1804         match = ofp_parser.OFPMatch()
1805         inst = []
1806
1807         flow_mod = ofp_parser.OFPFlowMod(self.dp, cookie, cookie_mask, 0, cmd,
1808                                          0, 0, 0, UINT32_MAX, ofp.OFPP_ANY,
1809                                          ofp.OFPG_ANY, 0, match, inst)
1810         self.dp.send_msg(flow_mod)
1811         self.logger.info('Delete flow [cookie=0x%x]', cookie, extra=self.sw_id)
1812
1813
1814 @OfCtl.register_of_version(ofproto_v1_2.OFP_VERSION)
1815 class OfCtl_v1_2(OfCtl_after_v1_2):
1816
1817     def __init__(self, dp, logger):
1818         super(OfCtl_v1_2, self).__init__(dp, logger)
1819
1820     def set_sw_config_for_ttl(self):
1821         flags = self.dp.ofproto.OFPC_INVALID_TTL_TO_CONTROLLER
1822         miss_send_len = UINT16_MAX
1823         m = self.dp.ofproto_parser.OFPSetConfig(self.dp, flags,
1824                                                 miss_send_len)
1825         self.dp.send_msg(m)
1826         self.logger.info('Set SW config for TTL error packet in.',
1827                          extra=self.sw_id)
1828
1829     def get_all_flow(self, waiters):
1830         ofp = self.dp.ofproto
1831         ofp_parser = self.dp.ofproto_parser
1832
1833         match = ofp_parser.OFPMatch()
1834         stats = ofp_parser.OFPFlowStatsRequest(self.dp, 0, ofp.OFPP_ANY,
1835                                                ofp.OFPG_ANY, 0, 0, match)
1836         return self.send_stats_request(stats, waiters)
1837
1838
1839 @OfCtl.register_of_version(ofproto_v1_3.OFP_VERSION)
1840 class OfCtl_v1_3(OfCtl_after_v1_2):
1841
1842     def __init__(self, dp, logger):
1843         super(OfCtl_v1_3, self).__init__(dp, logger)
1844
1845     def set_sw_config_for_ttl(self):
1846         packet_in_mask = (1 << self.dp.ofproto.OFPR_ACTION |
1847                           1 << self.dp.ofproto.OFPR_INVALID_TTL)
1848         port_status_mask = (1 << self.dp.ofproto.OFPPR_ADD |
1849                             1 << self.dp.ofproto.OFPPR_DELETE |
1850                             1 << self.dp.ofproto.OFPPR_MODIFY)
1851         flow_removed_mask = (1 << self.dp.ofproto.OFPRR_IDLE_TIMEOUT |
1852                              1 << self.dp.ofproto.OFPRR_HARD_TIMEOUT |
1853                              1 << self.dp.ofproto.OFPRR_DELETE)
1854         m = self.dp.ofproto_parser.OFPSetAsync(
1855             self.dp, [packet_in_mask, 0], [port_status_mask, 0],
1856             [flow_removed_mask, 0])
1857         self.dp.send_msg(m)
1858         self.logger.info('Set SW config for TTL error packet in.',
1859                          extra=self.sw_id)
1860
1861     def get_all_flow(self, waiters):
1862         ofp = self.dp.ofproto
1863         ofp_parser = self.dp.ofproto_parser
1864
1865         match = ofp_parser.OFPMatch()
1866         stats = ofp_parser.OFPFlowStatsRequest(self.dp, 0, 0, ofp.OFPP_ANY,
1867                                                ofp.OFPG_ANY, 0, 0, match)
1868         return self.send_stats_request(stats, waiters)
1869
1870
1871 def ip_addr_aton(ip_str, err_msg=None):
1872     try:
1873         return addrconv.ipv4.bin_to_text(socket.inet_aton(ip_str))
1874     except (struct.error, socket.error) as e:
1875         if err_msg is not None:
1876             e.message = '%s %s' % (err_msg, e.message)
1877         raise ValueError(e.message)
1878
1879
1880 def ip_addr_ntoa(ip):
1881     return socket.inet_ntoa(addrconv.ipv4.text_to_bin(ip))
1882
1883
1884 def mask_ntob(mask, err_msg=None):
1885     try:
1886         return (UINT32_MAX << (32 - mask)) & UINT32_MAX
1887     except ValueError:
1888         msg = 'illegal netmask'
1889         if err_msg is not None:
1890             msg = '%s %s' % (err_msg, msg)
1891         raise ValueError(msg)
1892
1893
1894 def ipv4_apply_mask(address, prefix_len, err_msg=None):
1895     import itertools
1896
1897     assert isinstance(address, str)
1898     address_int = ipv4_text_to_int(address)
1899     return ipv4_int_to_text(address_int & mask_ntob(prefix_len, err_msg))
1900
1901
1902 def ipv4_int_to_text(ip_int):
1903     assert isinstance(ip_int, numbers.Integral)
1904     return addrconv.ipv4.bin_to_text(struct.pack('!I', ip_int))
1905
1906
1907 def ipv4_text_to_int(ip_text):
1908     if ip_text == 0:
1909         return ip_text
1910     assert isinstance(ip_text, str)
1911     return struct.unpack('!I', addrconv.ipv4.text_to_bin(ip_text))[0]
1912
1913
1914 def nw_addr_aton(nw_addr, err_msg=None):
1915     ip_mask = nw_addr.split('/')
1916     default_route = ip_addr_aton(ip_mask[0], err_msg=err_msg)
1917     netmask = 32
1918     if len(ip_mask) == 2:
1919         try:
1920             netmask = int(ip_mask[1])
1921         except ValueError as e:
1922             if err_msg is not None:
1923                 e.message = '%s %s' % (err_msg, e.message)
1924             raise ValueError(e.message)
1925     if netmask < 0:
1926         msg = 'illegal netmask'
1927         if err_msg is not None:
1928             msg = '%s %s' % (err_msg, msg)
1929         raise ValueError(msg)
1930     nw_addr = ipv4_apply_mask(default_route, netmask, err_msg)
1931     return nw_addr, netmask, default_route