Skip to content

Commit

Permalink
add IGMP snooping application
Browse files Browse the repository at this point in the history
this application provides the simple example of IGMP snooping.

the module "igmplib" mainly offers 2 functions:
- listening on in the IGMP conversation between multicast routers and hosts
- emulating of the querier function of multicast servers
the former operates a switch as a snooping switch and controls transmission of an unnecessary multicasting packet.
the latter realizes the IGMP conversation in the environment without multicast routers.

the module "simple_switch_igmp" is a variation of "simple_switch".
the switch receives the "EventPacketIn" event instead of the "EventOFPPacketIn" event from the module "igmplib" in order to except IGMP.

Signed-off-by: Yuichi Ito <ito.yuichi0@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
  • Loading branch information
Yuichi Ito authored and fujita committed Jan 6, 2014
1 parent 5611b9e commit ffc1f82
Show file tree
Hide file tree
Showing 2 changed files with 914 additions and 0 deletions.
104 changes: 104 additions & 0 deletions ryu/app/simple_switch_igmp.py
@@ -0,0 +1,104 @@
# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import struct

from ryu.base import app_manager
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_0
from ryu.lib import addrconv
from ryu.lib import igmplib
from ryu.lib.dpid import str_to_dpid


class SimpleSwitchIgmp(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION]
_CONTEXTS = {'igmplib': igmplib.IgmpLib}

def __init__(self, *args, **kwargs):
super(SimpleSwitchIgmp, self).__init__(*args, **kwargs)
self.mac_to_port = {}
self._snoop = kwargs['igmplib']
# if you want a switch to operate as a querier,
# set up as follows:
self._snoop.set_querier_mode(
dpid=str_to_dpid('0000000000000001'), server_port=2)
# dpid the datapath id that will operate as a querier.
# server_port a port number which connect to the multicast
# server.
#
# NOTE: you can set up only the one querier.
# when you called this method several times,
# only the last one becomes effective.

def add_flow(self, datapath, in_port, dst, actions):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser

match = parser.OFPMatch(in_port=in_port,
dl_dst=addrconv.mac.text_to_bin(dst))
mod = parser.OFPFlowMod(
datapath=datapath, match=match, cookie=0,
command=ofproto.OFPFC_ADD, actions=actions)
datapath.send_msg(mod)

@set_ev_cls(igmplib.EventPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto

(dst_, src_, _eth_type) = struct.unpack_from(
'!6s6sH', buffer(msg.data), 0)
src = addrconv.mac.bin_to_text(src_)
dst = addrconv.mac.bin_to_text(dst_)

dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})

self.logger.info("packet in %s %s %s %s",
dpid, src, dst, msg.in_port)

# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src] = msg.in_port

if dst in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst]
else:
out_port = ofproto.OFPP_FLOOD

actions = [datapath.ofproto_parser.OFPActionOutput(out_port)]

# install a flow to avoid packet_in next time
if out_port != ofproto.OFPP_FLOOD:
self.add_flow(datapath, msg.in_port, dst, actions)

out = datapath.ofproto_parser.OFPPacketOut(
datapath=datapath, buffer_id=msg.buffer_id, in_port=msg.in_port,
actions=actions)
datapath.send_msg(out)

@set_ev_cls(igmplib.EventMulticastGroupStateChanged,
MAIN_DISPATCHER)
def _status_changed(self, ev):
msg = {
igmplib.MG_GROUP_ADDED: 'Multicast Group Added',
igmplib.MG_MEMBER_CHANGED: 'Multicast Group Member Changed',
igmplib.MG_GROUP_REMOVED: 'Multicast Group Removed',
}
self.logger.info("%s: [%s] querier:[%s] hosts:%s",
msg.get(ev.reason), ev.address, ev.src,
ev.dsts)

0 comments on commit ffc1f82

Please sign in to comment.