Commit bbc9efc3 authored by Anurag Kumar's avatar Anurag Kumar

Upload New File

parent 45c2e504
# encoding: utf-8
from netaddr import IPNetwork
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_0, ofproto_v1_3
from ryu.lib import hub
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib.packet import ipv4
from ryu.lib.packet import tcp
from ryu.lib.packet import ether_types
from ryu.topology import api as topology
from ryu.services.protocols.bgp.bgpspeaker import BGPSpeaker
from ryu.lib.ofp_pktinfilter import packet_in_filter, RequiredTypeFilter
from conf_mgr import BGPSpeakerManager
from fwd_util import RoutingClass
from hop_db import HopDB
"""
SDN-IP main class, responsible for the following functions:
1. Start a BGPSpeaker as an iBGP Speaker on Ryu, and connect with other BGPSpeakers in the SDN domain to obtain route information (SDN-IP BGPSpeaker<---->Internal BGPSpeaker);
Corresponding method: __init__()
2. Establish a connection between BGPSpeaker in the SDN domain and BGPSpeaker outside the domain (Internal BGPSpeaker<--->External BGPSpeaker);
Corresponding method:  bgp_packet_in_handler()
3. Establish a data path to access external hosts (Traffic--->External Hosts)
Corresponding method: best_path_change_handler()
5. Establish a path for external hosts to access the local host (External Host---> Local Host)
Corresponding method: internet_to_host_route_handler()
4. Establish a data path for access between internal hosts (Local Host <--->Local Host)
Corresponding method: internal_host_route_handler()
"""
class SDNIP(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
_CONTEXTS = {
'fwd': RoutingClass,
'hop_db': HopDB
}
"""
Initialization method
"""
def __init__(self, *args, **kwargs):
super(SDNIP, self).__init__(*args, **kwargs)
self.fwd_util = kwargs['fwd']
self.hop_db = kwargs['hop_db']
self.cfg_mgr = BGPSpeakerManager() #Obtain SDN-IP configuration information
# Run an iBGPSpeaker on Ryu
self.bgp_speaker =\
BGPSpeaker(self.cfg_mgr.as_id, #AS number
str(self.cfg_mgr.speaker_Router_IP), #iBGP router id
bgp_server_port=self.cfg_mgr.in_port, #Port number for listening BGP protocol
best_path_change_handler=self.best_path_change_handler, #This method is called when the routing information changes
peer_down_handler=self.peer_down_handler, #BGP peer goes offline
peer_up_handler=self.peer_up_handler) #BGP peer goes online
speaker_ids = self.cfg_mgr.get_speakers_id()
# Establish a connection between iBGPSpeaker and BGPSpeaker in the SDN domain
for speaker_id in speaker_ids:
self.bgp_speaker.neighbor_add(speaker_id,
self.cfg_mgr.as_id,
is_next_hop_self=True)
# Start a thread to repair the data path to the external host
#hub.spawn(self.prefix_check_loop)
"""
When the routing information changes, call this method to establish a data path to the external host.
parameter:
ev: route update time, containing the next hop address information of the destination network.
The established paths are:
1. The path through the local traffic to the external host (Transit Traffic ---> Internet)
2. The path for the local host to access the external host (Local Host ---> Internet)
"""
def best_path_change_handler(self, ev):
self.logger.info('path changed:')
self.logger.info('remote_as: %d', ev.remote_as)
self.logger.info('route_dist: %s', ev.route_dist)
self.logger.info('prefix: %s', ev.prefix)
self.logger.info('nexthop: %s', ev.nexthop)
self.logger.info('')
# self.logger.info('path changed:')
# self.logger.info('remote_as: %d', ev.remote_as)
# self.logger.info('route_dist: %s', ev.route_dist)
# self.logger.info('prefix: %s', ev.prefix)
# self.logger.info('nexthop: %s', ev.nexthop)
# self.logger.info('label: %s', ev.label)
# self.logger.info('is_withdraw: %s', ev.is_withdraw)
# self.logger.info('')
# Get network prefix
prefix_nw = IPNetwork(ev.prefix)
# Do not process local network updates
# for internal_network in self.cfg_mgr.get_internal_networks():
# int_nw = IPNetwork(internal_network)
# if int_nw == prefix_nw:
# self.logger.info('Internal network, ignored.')
# return
if ev.is_withdraw:
self.hop_db.remove_hop(ev.prefix)
else:
# Record the next hop address information of the access destination network
self.hop_db.add_hop(ev.prefix, ev.nexthop)
"""
Establish a connection between BGPSpeakers.
"""
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def bgp_packet_in_handler(self, ev):
msg = ev.msg
dp = msg.datapath
dpid = dp.id
ofproto = dp.ofproto
pkt = packet.Packet(msg.data)
tcp_header = pkt.get_protocol(tcp.tcp)
#Only process BGP packets, tcp port is 179
if tcp_header is None or (tcp_header.src_port is not 179 and
tcp_header.dst_port is not 179):
return
ipv4_header = pkt.get_protocol(ipv4.ipv4)
src_ip = ipv4_header.src
dst_ip = ipv4_header.dst
self.logger.info("BGP from %s to %s", src_ip, dst_ip)
# Obtain source and destination host information
hosts = topology.get_all_host(self)
src_host = None
dst_host = None
for host in hosts:
if src_ip in host.ipv4:
src_host = host
elif dst_ip in host.ipv4:
dst_host = host
if src_host is None or dst_host is None:
return
# Establish a data path between BGPSpeakers
src_port = src_host.port
dst_port = dst_host.port
dst_mac = dst_host.mac
to_dst_match = dp.ofproto_parser.OFPMatch(eth_dst=dst_mac,
ipv4_dst=dst_ip,
eth_type=2048)
pre_actions = [
dp.ofproto_parser.OFPActionSetField(eth_dst=dst_mac)
]
port_no = self.fwd_util.set_best_path(src_port.dpid,
dst_port.dpid,
dst_port.port_no,
to_dst_match,pre_actions )
# Submit the first data packet directly to the destination host to prevent the loss of the first packet
if port_no is None:
return
self.fwd_util.packet_out(dp, msg, port_no)
"""
Process packet-in requests and establish a one-way data path to external hosts
"""
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
@packet_in_filter(RequiredTypeFilter, {'types': [ipv4.ipv4]})
def internal_host_route_handler(self, ev):
msg = ev.msg
dp = msg.datapath
dpid = dp.id
ofproto = dp.ofproto
pkt = packet.Packet(msg.data)
ipv4_header = pkt.get_protocol(ipv4.ipv4)
src_ip = ipv4_header.src
dst_ip = ipv4_header.dst
#Only process visits whose purpose is not local
# if self.cfg_mgr.is_internal_host(dst_ip):
# return
# Get the next hop information, if the next information does not exist, do not process
nexthop_info = self.hop_db.get_nexthop_by_ip(dst_ip)
if not nexthop_info:
return
nexthop_prefix = nexthop_info[0]
nexthop = nexthop_info[1]
nexthop_host = self.fwd_util.get_host(nexthop)
if nexthop_host is None:
return
# Establish a data path between hosts
host_match = \
dp.ofproto_parser.OFPMatch(ipv4_dst=(str(nexthop_prefix.ip), str(nexthop_prefix.netmask)), eth_type=2048)
pre_actions = [
dp.ofproto_parser.OFPActionSetField(eth_dst=nexthop_host.mac)
]
# self.logger.info("daowaiwaiwai")
self.logger.info("path found: ")
self.fwd_util.set_best_path(dpid,
nexthop_host.port.dpid,
nexthop_host.port.port_no,
host_match,
pre_actions)
# Submit the first data packet directly to the destination host to prevent the loss of the first packet
switch = topology.get_switch(self, nexthop_host.port.dpid)[0]
self.fwd_util.packet_out(switch.dp,msg,nexthop_host.port.port_no)
"""
Process packet-in requests and establish a one-way data path with the destination host being the local host.
"""
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
@packet_in_filter(RequiredTypeFilter, {'types': [ipv4.ipv4]})
def internet_to_host_route_handler(self, ev):
msg = ev.msg
dp = msg.datapath
dpid = dp.id
ofproto = dp.ofproto
pkt = packet.Packet(msg.data)
ipv4_header = pkt.get_protocol(ipv4.ipv4)
src_ip = ipv4_header.src
dst_ip = ipv4_header.dst
# If the destination host is not the local host, do not process
# if not self.cfg_mgr.is_internal_host(dst_ip):
# return
#Get the destination host information, if the destination host does not exist, do not process
dst_host = self.fwd_util.get_host(dst_ip)
if dst_host is None:
return
#Data path to local host
host_match = \
dp.ofproto_parser.OFPMatch(ipv4_dst=dst_ip, eth_type=2048)
pre_actions = [
dp.ofproto_parser.OFPActionSetField(eth_dst=dst_host.mac)
]
# self.logger.info("daoneineinei")
self.fwd_util.set_best_path(dpid,
dst_host.port.dpid,
dst_host.port.port_no,
host_match,
pre_actions)
# Submit the first data packet directly to the destination host to prevent the loss of the first packet
switch = topology.get_switch(self, dst_host.port.dpid)[0]
self.fwd_util.packet_out(switch.dp, msg, dst_host.port.port_no)
def peer_down_handler(self, remote_ip, remote_as):
self.logger.info('peer down:')
self.logger.info('remote_as: %d', remote_as)
self.logger.info('remote ip: %s', remote_ip)
self.logger.info('')
def peer_up_handler(self, remote_ip, remote_as):
self.logger.info('peer up:')
self.logger.info('remote_as: %d', remote_as)
self.logger.info('remote ip: %s', remote_ip)
self.logger.info('')
"""
Fix the data path to the external host
"""
def prefix_check_loop(self):
while True:
prefixs_to_install = self.hop_db.get_uninstalled_prefix_list()
self.logger.debug("prefix to install: %s", str(prefixs_to_install))
for prefix in prefixs_to_install:
prefix_nw = IPNetwork(prefix)
# for internal_network in self.cfg_mgr.get_internal_networks():
# int_nw = IPNetwork(internal_network)
# if int_nw == prefix_nw:
# self.logger.info('Internal network, ignored.')
# continue
nexthop = self.hop_db.get_nexthop(prefix)
self.install_best_path(prefix, nexthop)
hub.sleep(3)
"""
Establish a path to the destination network based on the next hop address [Traffic(dst_ip in prefix) ---> nexthot host]
"""
def install_best_path(self, prefix, nexthop):
# Get next hop router information
nexthop_host = self.fwd_util.get_host(nexthop)
self.logger.debug("nexthop host: %s", str(nexthop_host))
if nexthop_host is None:
return
nexthop_port = nexthop_host.port
nexthop_mac = nexthop_host.mac
nexthop_dpid = nexthop_port.dpid
nexthop_port_no = nexthop_port.port_no
prefix_ip = str(IPNetwork(prefix).ip)
prefix_mask = str(IPNetwork(prefix).netmask)
'''
Up and down the flow table on each switch on the path to the next hop host:
match:
The packet type is IPV4
The destination ipv4 network is prefix
deal with:
Modify the destination Mac as the next hop router Mac
Forward the packet to the next hop direction
'''
for dp in self.fwd_util.get_all_datapaths():
from_dpid = dp.id
nexthop_match = \
dp.ofproto_parser.OFPMatch(ipv4_dst=(prefix_ip, prefix_mask),
eth_type=2048)
pre_actions = [
dp.ofproto_parser.OFPActionSetField(eth_dst=nexthop_mac)
]
self.fwd_util.set_best_path(from_dpid,
nexthop_dpid,
nexthop_port_no,
nexthop_match,
pre_actions)
self.hop_db.install_prefix(prefix)
#app_manager.require_app('ryu.app.gui_topology.gui_topology')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment