backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / app / sdnhub_apps / tap.py
1 # Copyright (C) 2014 SDN Hub
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #    http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12 # implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 import logging
17 import struct
18 import random
19 import ryu.utils
20
21 from ryu.base import app_manager
22 from ryu.topology import event as topo_event
23 from ryu.controller import mac_to_port
24 from ryu.controller import ofp_event
25 from ryu.controller.handler import HANDSHAKE_DISPATCHER
26 from ryu.controller.handler import CONFIG_DISPATCHER
27 from ryu.controller.handler import MAIN_DISPATCHER
28 from ryu.controller.handler import set_ev_cls
29 from ryu.ofproto import ofproto_v1_3
30 from ryu.lib import ofctl_v1_3
31 from ryu.lib.mac import haddr_to_bin
32 from ryu.lib.packet import packet
33 from ryu.lib.packet import ethernet
34 from ryu.lib.packet import ipv4
35
36 from ryu.ofproto import ether
37 from ryu.controller import dpset
38
39 #import networkx as nx
40
41 LOG = logging.getLogger('ryu.app.sdnhub_apps.tap')
42
43 class StarterTap(app_manager.RyuApp):
44     OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
45
46     def __init__(self, *args, **kwargs):
47         super(StarterTap, self).__init__(*args, **kwargs)
48
49         self.broadened_field = {'dl_host': ['dl_src', 'dl_dst'],
50                                 'nw_host': ['nw_src', 'nw_dst'],
51                                 'tp_port': ['tp_src', 'tp_dst']}
52
53
54     @set_ev_cls(ofp_event.EventOFPErrorMsg, [HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])
55     def error_msg_handler(self, ev):
56         msg = ev.msg
57       
58         LOG.info('OFPErrorMsg received: type=0x%02x code=0x%02x message=%s',
59                         msg.type, msg.code, ryu.utils.hex_array(msg.data))
60
61
62     @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
63     def switch_features_handler(self, ev):
64         datapath = ev.msg.datapath
65         ofproto = datapath.ofproto
66         ofproto_parser = datapath.ofproto_parser
67
68         # Delete all existing rules on the switch
69         mod = ofproto_parser.OFPFlowMod(datapath=datapath, command=ofproto.OFPFC_DELETE,
70                              out_port=ofproto.OFPP_ANY,out_group=ofproto.OFPG_ANY)
71         datapath.send_msg(mod)
72
73
74     def change_field(self, old_attrs, original, new):
75         new_attrs = {}
76         for key, val in old_attrs.items():
77             if (key == original):
78                 new_attrs[new] = val
79             else:
80                 new_attrs[key] = val
81         return new_attrs
82
83     def create_tap(self, filter_data):
84         LOG.debug("Creating tap with filter = %s", str(filter_data))
85
86         # If dl_host, nw_host or tp_port are used, the recursively call the individual filters.
87         # This causes the match to expand and more rules to be programmed.
88         result = True
89         filter_data.setdefault('fields', {})
90         filter_fields = filter_data['fields']
91
92         for key, val in self.broadened_field.iteritems():
93             if key in filter_fields:
94                 for new_val in val:
95                     filter_data['fields'] = self.change_field(filter_fields, key, new_val)
96                     result = result and self.create_tap(filter_data)
97
98                 return result
99
100         # If match fields are exact, then proceed programming switches
101
102         # Iterate over all the sources and sinks, and collect the individual
103         # hop information. It is possible that a switch is both a source,
104         # a sink and an intermediate hop.
105         for source in filter_data['sources']:
106             for sink in filter_data['sinks']:
107
108                 # Handle error case
109                 if source == sink:
110                     continue
111
112                 # In basic version, source and sink are same switch
113                 if source['dpid'] != sink['dpid']:
114                     LOG.debug("Mismatching source and sink switch")
115                     return False
116
117                 datapath = self.dpset.get(source['dpid'])
118
119                 # If dpid is invalid, return
120                 if datapath is None:
121                     LOG.debug("Unable to get datapath for id = %s", str(source['dpid']))
122                     return False
123
124                 ofproto = datapath.ofproto
125                 ofproto_parser = datapath.ofproto_parser
126
127                 in_port = source['port_no']
128                 out_port = sink['port_no']
129                 filter_fields = filter_data['fields'].copy()
130
131                 ######## Create action list
132                 actions = [ofproto_parser.OFPActionOutput(out_port)]
133
134                 ######## Create match
135                 if in_port != 'all':  # If not sniffing on all in_ports
136                     filter_fields['in_port'] = in_port
137                 match = ofctl_v1_3.to_match(datapath, filter_fields)
138
139                 ######## Cookie might come handy
140                 cookie = random.randint(0, 0xffffffffffffffff)
141
142                 inst = [ofproto_parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)]
143
144                 # install the flow in the switch
145                 mod = ofproto_parser.OFPFlowMod(
146                             datapath=datapath, match=match, 
147                             command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0,
148                             instructions=inst, cookie=cookie)
149
150                 datapath.send_msg(mod)
151
152                 LOG.debug("Flow inserted to switch %x: cookie=%s, out_port=%d, match=%s",
153                                   datapath.id, str(cookie), out_port, str(filter_fields))
154
155         LOG.info("Created tap with filter = %s", str(filter_data))
156         return True
157
158
159     def delete_tap(self, filter_data):
160         LOG.debug("Deleting tap with filter %s", str(filter_data))
161
162         # If dl_host, nw_host or tp_port are used, the recursively call the individual filters.
163         # This causes the match to expand and more rules to be programmed.
164         filter_data.setdefault('fields', {})
165         filter_fields = filter_data['fields']
166
167         for key, val in self.broadened_field.iteritems():
168             if key in filter_fields:
169
170                 for new_val in val:
171                     filter_data['fields'] = self.change_field(filter_fields, key, new_val)
172                     self.delete_tap(filter_data)
173
174                 return
175
176         # If match fields are exact, then proceed programming switches
177         for source in filter_data['sources']:
178             in_port = source['port_no']
179             filter_fields = filter_data['fields'].copy()
180             if in_port != 'all':  # If not sniffing on all in_ports
181                 filter_fields['in_port'] = in_port
182
183             datapath = self.dpset.get(source['dpid'])
184
185             # If dpid is invalid, return
186             if datapath is None:
187                 continue
188
189             ofproto = datapath.ofproto
190             ofproto_parser = datapath.ofproto_parser
191                     
192             match = ofctl_v1_3.to_match(datapath, filter_fields)
193
194             mod = ofproto_parser.OFPFlowMod(datapath=datapath, command=ofproto.OFPFC_DELETE,
195                           match = match, out_port=ofproto.OFPP_ANY,out_group=ofproto.OFPG_ANY)
196
197             datapath.send_msg(mod)
198