GENIRacksHome/OpenGENIRacks/RaspberryPIs: ryu_13_custom.py

File ryu_13_custom.py, 5.6 KB (added by rrhain@bbn.com, 8 years ago)

RYU controller python script - Li Lin

Line 
1# Copyright (C) 2011 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
16from ryu.base import app_manager
17from ryu.controller import ofp_event
18from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
19from ryu.controller.handler import set_ev_cls
20from ryu.ofproto import ofproto_v1_3
21from ryu.lib.packet import packet
22from ryu.lib.packet import ethernet
23from ryu.lib.packet import ether_types
24
25pi1_ip4_add = '10.10.1.4'
26pi2_ip4_add = '10.10.1.5'
27pi3_ip4_add = '10.10.1.6'
28
29pi1_eth_add = 'b8:27:eb:21:14:0d'
30pi2_eth_add = 'b8:27:eb:43:97:10'
31pi3_eth_add = 'b8:27:eb:23:c1:0c'
32
33insert_special_flow = True
34
35class SimpleSwitch13(app_manager.RyuApp):
36    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
37
38    def __init__(self, *args, **kwargs):
39        super(SimpleSwitch13, self).__init__(*args, **kwargs)
40        self.mac_to_port = {}
41
42    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
43    def switch_features_handler(self, ev):
44        datapath = ev.msg.datapath
45        ofproto = datapath.ofproto
46        parser = datapath.ofproto_parser
47
48        # install table-miss flow entry
49        #
50        # We specify NO BUFFER to max_len of the output action due to
51        # OVS bug. At this moment, if we specify a lesser number, e.g.,
52        # 128, OVS will send Packet-In with invalid buffer_id and
53        # truncated packet data. In that case, we cannot output packets
54        # correctly.  The bug has been fixed in OVS v2.1.0.
55        match = parser.OFPMatch()
56        actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
57                                          ofproto.OFPCML_NO_BUFFER)]
58        self.add_flow(datapath, 0, match, actions)
59
60    def add_flow(self, datapath, priority, match, actions, buffer_id=None):
61        ofproto = datapath.ofproto
62        parser = datapath.ofproto_parser
63
64        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
65                                             actions)]
66        if buffer_id:
67            mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,
68                                    priority=priority, match=match,
69                                    instructions=inst)
70        else:
71            mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
72                                    match=match, instructions=inst)
73        datapath.send_msg(mod)
74
75    def get_eth_add_from_port(self, dpid, port):
76        for each in self.mac_to_port[dpid]:
77            print(str(self.mac_to_port[dpid][each]) + "\n\n\n\n")
78            if self.mac_to_port[dpid][each] == port:
79                return each
80
81    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
82    def _packet_in_handler(self, ev):
83        # If you hit this you might want to increase
84        # the "miss_send_length" of your switch
85        if ev.msg.msg_len < ev.msg.total_len:
86            self.logger.debug("packet truncated: only %s of %s bytes",
87                              ev.msg.msg_len, ev.msg.total_len)
88        msg = ev.msg
89        datapath = msg.datapath
90        ofproto = datapath.ofproto
91        parser = datapath.ofproto_parser
92        in_port = msg.match['in_port']
93
94        pkt = packet.Packet(msg.data)
95        eth = pkt.get_protocols(ethernet.ethernet)[0]
96
97        if eth.ethertype == ether_types.ETH_TYPE_LLDP:
98            # ignore lldp packet
99            return
100        dst = eth.dst
101        src = eth.src
102
103        dpid = datapath.id
104        self.mac_to_port.setdefault(dpid, {})
105
106        # learn a mac address to avoid FLOOD next time.
107        self.mac_to_port[dpid][src] = in_port
108
109        if dst in self.mac_to_port[dpid]:
110            out_port = self.mac_to_port[dpid][dst]
111        else:
112            out_port = ofproto.OFPP_FLOOD
113 
114        actions = [parser.OFPActionOutput(out_port)]
115
116        self.logger.info("packet in %s %s %s %s->%s", dpid, src, dst, in_port, out_port)
117
118        # Duplicate a packet to go out on port 2 as well
119        if insert_special_flow:
120            if out_port == 3 and not in_port == 2:
121                actions = [parser.OFPActionOutput(out_port),
122                           parser.OFPActionSetField(eth_dst=pi3_eth_add),
123                           parser.OFPActionSetField(ipv4_dst=pi3_ip4_add),
124                           parser.OFPActionOutput(2)]
125
126        # install a flow to avoid packet_in next time
127        if out_port != ofproto.OFPP_FLOOD:
128            if insert_special_flow and out_port == 3 and not in_port == 2:
129                match = parser.OFPMatch(in_port=in_port, eth_type=0x0800)
130            else:
131                match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
132            # verify if we have a valid buffer_id, if yes avoid to send both
133            # flow_mod & packet_out
134            if msg.buffer_id != ofproto.OFP_NO_BUFFER:
135                self.add_flow(datapath, 1, match, actions, msg.buffer_id)
136                return
137            else:
138                self.add_flow(datapath, 1, match, actions)
139        data = None
140        if msg.buffer_id == ofproto.OFP_NO_BUFFER:
141            data = msg.data
142
143        out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
144                                  in_port=in_port, actions=actions, data=data)
145        datapath.send_msg(out)