Example #1
0
    def __init__(self, *args, **kwargs):
        super(Ryu, self).__init__(*args, **kwargs)
        #--- register for configuration options
        SciPass_opts = [
            cfg.StrOpt('SciPassConfig',
                       default='/etc/SciPass/SciPass.xml',
                       help='where to find the SciPass config file'),
            cfg.BoolOpt('readState',
                        default=False,
                        help='Read previous state or not')
        ]
        self.CONF.register_opts(SciPass_opts, group='SciPass')
        self.logger.error("Starting SciPass")
        self.datapaths = {}
        self.isactive = 1
        self.statsInterval = 5
        self.balanceInterval = 15
        self.bal = None
        self.stats = {}
        self.stats_thread = hub.spawn(self._stats_loop)
        self.balance_thread = hub.spawn(self._balance_loop)

        self.ports = defaultdict(dict)
        self.prefix_bytes = defaultdict(lambda: defaultdict(dict))
        self.lastStatsTime = {}
        self.flowmods = {}

        api = SciPass(logger=self.logger,
                      config=self.CONF.SciPass.SciPassConfig,
                      readState=self.CONF.SciPass.readState)

        api.registerForwardingStateChangeHandler(
            self.changeSwitchForwardingState)

        self.api = api

        wsgi = kwargs['wsgi']
        wsgi.register(SciPassRest, {'api': self.api})
from ryu.lib.packet import lldp, ether_types
from ryu.ofproto.ether import ETH_TYPE_LLDP
from ryu.ofproto.ether import ETH_TYPE_CFM
from ryu.ofproto import nx_match
from ryu.ofproto import ofproto_v1_0
from ryu.ofproto import ofproto_v1_2
from ryu.ofproto import ofproto_v1_3
from ryu.ofproto import ofproto_v1_4

LOG = logging.getLogger(__name__)

CONF = cfg.CONF

CONF.register_cli_opts([
    cfg.BoolOpt('observe-links',
                default=False,
                help='observe link discovery events.'),
    cfg.BoolOpt('install-lldp-flow',
                default=True,
                help='link discovery: explicitly install flow entry '
                'to send lldp packet to controller'),
    cfg.BoolOpt('explicit-drop',
                default=True,
                help='link discovery: explicitly drop lldp packet in')
])


class Port(object):
    # This is data class passed by EventPortXXX
    def __init__(self, dpid, ofproto, ofpport):
        super(Port, self).__init__()
Example #3
0
LOG = logging.getLogger('dragon_knight')
CONF = cfg.CONF

CONF.set_override('observe_links', True)

CONF.register_cli_opts([
    cfg.ListOpt('app-lists', default=[],
                help='application module name to run'),
    cfg.MultiStrOpt('app',
                    positional=True,
                    default=[],
                    help='application module name to run'),
    cfg.StrOpt('pid-file', default=None, help='pid file name'),
    cfg.BoolOpt('enable-debugger',
                default=False,
                help='don\'t overwrite Python standard threading library'
                '(use only for debugging)')
])


def main(args=None, prog=None):
    try:
        CONF(args=args,
             prog=prog,
             project='ryu',
             version='ryu-manager {}'.format(version),
             default_config_files=['/usr/local/etc/ryu/ryu.conf'])
    except cfg.ConfigFilesNotFoundError:
        CONF(args=args,
             prog=prog,
             project='ryu',
Example #4
0
class ForwardingModule(app_manager.RyuApp):
    """
    Generic forwarding module. Wont listen to Packet in messages but other modules
    will trigger when they need forwarding

    Table 2 -> Used by Forwarding module
        Table 2 entries:
            SRC_MAC:DST_MAC:IN_PORT -> OUT_PORT (n vice versa x times) to enable basic forwarding
            Proto ARP: Controller
            NO_MATCH: Discard -> TODO: communication error on Controller reboot
    """
    _CONTEXTS = {
        'switches': switches.Switches,
        'dpset': dpset.DPSet,
        'db': DatabaseModule
    }

    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
    opts = [
        cfg.IntOpt('table', default=2, help='Table to use for forwarding'),
        cfg.IntOpt('cookie_arp',
                   default=101,
                   help='FLow mod cookie to use for Controller event on arp'),
        cfg.IntOpt('priority',
                   default=1,
                   help='Priority to use to add the forwarding rules'),
        cfg.BoolOpt(
            'caching',
            default='true',
            help='Disables or enables caching of shortest paths and of paths')
    ]

    def __init__(self, *args, **kwargs):
        super(ForwardingModule, self).__init__(*args, **kwargs)

        CONF.register_opts(self.opts, group='forwarding')
        self.switches = kwargs['switches']
        self.dpset = kwargs['dpset']
        self.ofHelper = ofprotoHelper.ofProtoHelperGeneric()
        self.installed_paths = []
        self.shortestPathCache = []
        if CONF.forwarding.caching:
            self.logger.info('Caching enabled')

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        """
        Loads ARP action to send arp packets to controller
        :param ev:
        :return:
        """
        datapath = ev.msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        match = parser.OFPMatch()
        actions = [
            parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
                                   ofproto.OFPCML_NO_BUFFER)
        ]
        self.ofHelper.add_flow(datapath, 0, match, actions,
                               CONF.forwarding.table,
                               CONF.forwarding.cookie_arp)

    def _add_forwarding_rule(self, datapath, src_ip, dst_ip, out_port):
        parser = datapath.ofproto_parser

        match = parser.OFPMatch(eth_type=ether_types.ETH_TYPE_IP,
                                ipv4_src=src_ip,
                                ipv4_dst=dst_ip)
        actions = [parser.OFPActionOutput(out_port)]
        self.ofHelper.add_flow(datapath, CONF.forwarding.priority, match,
                               actions, CONF.forwarding.table)

    def _apply_forwarding_path(self, path):
        """
        :param path: Path to apply
        :type path: Path
        :return:
        """
        if CONF.forwarding.caching:
            if (path.src_ip, path.dst_ip) not in self.installed_paths:
                for rule in path.fw:
                    if isinstance(rule['src'], int):
                        self._add_forwarding_rule(
                            self.switches.dps[rule['src']], path.src_ip,
                            path.dst_ip, rule['port'])
                self.installed_paths.append((path.src_ip, path.dst_ip))
        else:
            for rule in path.fw:
                if isinstance(rule['src'], int):
                    self._add_forwarding_rule(self.switches.dps[rule['src']],
                                              path.src_ip, path.dst_ip,
                                              rule['port'])

        if CONF.forwarding.caching:
            if (path.dst_ip, path.src_ip) not in self.installed_paths:
                for rule in path.bw:
                    if isinstance(rule['src'], int):
                        self._add_forwarding_rule(
                            self.switches.dps[rule['src']], path.dst_ip,
                            path.src_ip, rule['port'])
                self.installed_paths.append((path.dst_ip, path.src_ip))
        else:
            for rule in path.bw:
                if isinstance(rule['src'], int):
                    self._add_forwarding_rule(self.switches.dps[rule['src']],
                                              path.dst_ip, path.src_ip,
                                              rule['port'])

    def _get_topology(self):
        """
        Returns a networkx DiGraph Object
        :return:
        """
        switches = [dp for dp in self.switches.dps]
        links = [(link.src.dpid, link.dst.dpid, {
            'port': link.src.port_no
        }) for link in self.switches.links]

        g = nx.DiGraph()
        g.add_nodes_from(switches)
        g.add_edges_from(links)

        for mac, host in self.switches.hosts.iteritems():
            g.add_node(host.ipv4[0])
            g.add_edge(host.ipv4[0], host.port.dpid)
            g.add_edge(host.port.dpid, host.ipv4[0], port=host.port.port_no)

        return g

    def _get_shortest_path(self, src_ip, dst_ip):
        if CONF.forwarding.caching:
            pathcache = dict(self.shortestPathCache)
            if src_ip + '_' + dst_ip in pathcache:
                return pathcache[src_ip + '_' + dst_ip]

        g = self._get_topology()

        try:
            nxPath = nx.shortest_path(g, src_ip, dst_ip)
        except nx.NodeNotFound:
            return None

        path = Path(src_ip, dst_ip)

        for i in range(0, len(nxPath) - 1):
            edged = g.get_edge_data(nxPath[i], nxPath[i + 1])
            path.fw.append({
                'src': nxPath[i],
                'dst': nxPath[i + 1],
                'port': edged['port'] if 'port' in edged else ''
            })
            edged = g.get_edge_data(nxPath[i + 1], nxPath[i])
            path.bw.append({
                'src': nxPath[i + 1],
                'dst': nxPath[i],
                'port': edged['port'] if 'port' in edged else ''
            })

        if CONF.forwarding.caching:
            self.shortestPathCache.append((src_ip + '_' + dst_ip, path))

        return path

    def _get_hop_out_port(self, dst_ip, datapath, path):
        """

        :param dst_ip:
        :param datapath:
        :type datapath: Datapath
        :param path:
        :type path: Path
        :return:
        """
        if dst_ip == path.dst_ip:
            for hop in path.fw:
                if hop['src'] == datapath.id:
                    for port in self.switches.ports:  # type: Port
                        if port.dpid == datapath.id and port.port_no == hop[
                                'port']:
                            return port

        if dst_ip == path.src_ip:
            for hop in path.bw:
                if hop['src'] == datapath.id:
                    for port in self.switches.ports:  # type: Port
                        if port.dpid == datapath.id and port.port_no == hop[
                                'port']:
                            return port

        return None

    @set_ev_cls(EventTopologyRequest, None)
    def getTopology(self, ev):
        topology = self._get_topology()
        reply = EventTopologyReply(topology, ev.src)
        self.reply_to_request(ev, reply)

    @set_ev_cls(EventShortestPathRequest, None)
    def requestShortestPath(self, ev):
        path = self._get_shortest_path(ev.src_ip, ev.dst_ip)
        if path:
            self._apply_forwarding_path(path)
            reply = EventShortestPathReply(path=path, dst=ev.src)
        else:
            reply = EventShortestPathReply(path=None, dst=ev.src)
        self.reply_to_request(ev, reply)

    @set_ev_cls(EventForwardingPipeline, None)
    def forwardingRequest(self, ev):
        """

        :param ev:
        :type ev: EventForwardingPipeline
        :return:
        """
        datapath = ev.datapath
        match = ev.match

        pkt = packet.Packet(ev.data)
        eth = pkt.get_protocols(
            ethernet.ethernet)[0]  # type: ethernet.ethernet

        self.logger.debug('EventForwarding requested on ' + str(eth))

        if eth.ethertype == ether_types.ETH_TYPE_ARP:
            # This part is responsible for handling ARP's,
            # ARP are only received and sent on access port to eliminate forwarding loops
            arpp = pkt.get_protocols(arp.arp)[0]
            if arpp.opcode in [arp.ARP_REQUEST, arp.ARP_REPLY]:
                self.logger.debug('we are looking for %s:%s from %s:%s',
                                  arpp.dst_ip, arpp.dst_mac, arpp.src_ip,
                                  arpp.src_mac)
                host = [
                    x for key, x in self.switches.hosts.iteritems()
                    if x.ipv4[0] == arpp.dst_ip
                ]
                if host:
                    host = host[0]
                    self.ofHelper.do_packet_out(
                        ev.data, self.switches.dps[host.port.dpid], host.port)
                else:
                    nonAccessPorts = []
                    for link, ts in self.switches.links.iteritems():
                        nonAccessPorts.extend((link.src, link.dst))
                    accessPorts = [
                        port
                        for port, portdata in self.switches.ports.iteritems()
                        if port not in nonAccessPorts
                    ]

                    # Send packet out to all access ports instead of flood to prevent broadcast loops
                    for port in accessPorts:
                        self.ofHelper.do_packet_out(
                            ev.data, self.switches.dps[port.dpid], port)
        elif eth.ethertype == ether_types.ETH_TYPE_IP:
            # gets the shortest path between two nodes and installs.
            ip = pkt.get_protocols(ipv4.ipv4)[0]  # type: ipv4.ipv4

            self.logger.debug('Eventforwarding on IP packet ' + str(ip))

            path = self._get_shortest_path(ip.src, ip.dst)
            if path:
                self._apply_forwarding_path(path)
                if ev.doPktOut:
                    out_port = self._get_hop_out_port(ip.dst, ev.datapath,
                                                      path)
                    if out_port:
                        self.logger.debug(
                            'Doing a Packet out on forwarding request')
                        self.ofHelper.do_packet_out(ev.data, ev.datapath,
                                                    out_port)
                    else:
                        self.logger.error('Failed to retrieve next hop port')
Example #5
0
PRIORITY_DEFAULT_ROUTING = 1
PRIORITY_ADDRESSED_DEFAULT_ROUTING = 2
PRIORITY_MAC_LEARNING = 3
PRIORITY_STATIC_ROUTING = 3
PRIORITY_ADDRESSED_STATIC_ROUTING = 4
PRIORITY_IMPLICIT_ROUTING = 5
PRIORITY_L2_SWITCHING = 6
PRIORITY_IP_HANDLING = 7
PRIORITY_PENALTYBOX = 8

PRIORITY_TYPE_ROUTE = 'priority_route'

CONF = cfg.CONF
plexus_configuration_group = 'plexus'
plexus_backdoor_opt = cfg.BoolOpt('backdoor_enable',
                                  default = True,
                                  help = 'Enable backdoor REPL for inspecting state of python runtime')
plexus_backdoor_port_opt = cfg.IntOpt('backdoor_listen_port',
                                      default = 3000,
                                      help='Port on which the backdoor REPL should listen, on the local interface')
CONF.register_opt(plexus_backdoor_opt, group = plexus_configuration_group)
CONF.register_opt(plexus_backdoor_port_opt, group = plexus_configuration_group)

switchboard_configuration_group = 'switchboard'
switchboard_stateurl_opt = cfg.StrOpt('state_url',
                                      default = 'https://switchboard.oit.duke.edu/sdn_callback/restore_state',
                                      help = 'URL for accessing SwitchBoard knowledge base')
switchboard_username_opt = cfg.StrOpt('username',
                                      default = 'username',
                                      help='Username for accessing SwitchBoard knowledge base')
switchboard_password_opt = cfg.StrOpt('password',
Example #6
0
from __future__ import print_function
from ryu import cfg
import inspect
import platform
import logging
import logging.config
import logging.handlers
import os
import sys
import ConfigParser

CONF = cfg.CONF

CONF.register_cli_opts([
    cfg.IntOpt('default-log-level', default=None, help='default log level'),
    cfg.BoolOpt('verbose', default=False, help='show debug output'),
    cfg.BoolOpt('use-stderr', default=True, help='log to standard error'),
    cfg.BoolOpt('use-syslog', default=False, help='output to syslog'),
    cfg.StrOpt('log-dir', default=None, help='log file directory'),
    cfg.StrOpt('log-file', default=None, help='log file name'),
    cfg.StrOpt('log-file-mode',
               default='0644',
               help='default log file permission'),
    cfg.StrOpt('log-config-file',
               default=None,
               help='Path to a logging config file to use')
])

_EARLY_LOG_HANDLER = None

Example #7
0
import ryu.lib.packet.ipv4
import ryu.lib.packet.udp
import sys  # For getting command line arguments and passing to Ryu
import eventlet
from eventlet import backdoor  # For telnet python access
from ryu.ofproto import ofproto_v1_0  # This code is OpenFlow 1.0 specific

# Will use this to track the VLAN info associated with each switch
SwitchVLAN = namedtuple("SwitchVLAN", ['vid2local', 'port2vid', 'taggedPorts'])

if __name__ == "__main__":  # Stuff to set additional command line options
    from ryu import cfg
    CONF = cfg.CONF
    CONF.register_cli_opts([
        cfg.StrOpt('netfile', default=None, help='network json file'),
        cfg.BoolOpt('notelnet', default=False, help='Telnet based debugger.')
    ])


class MultipleSwitchVLANlrn(app_manager.RyuApp):
    """ Outline of a Ryu application that performs a number of tasks and
        responds to various events.
    """
    OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION]

    def __init__(self, *args, **kwargs):
        """ Define member variables here.  I do this here so that we can look at
            them via the telnet python command line.  I use the standard Python
            deque data structure with a finite length so that I only keep the
            latest few events of a given type.
        """
Example #8
0
import os
import collections

from docker import client
from docker import tls
from ryu import cfg

docker_opts = [
    cfg.BoolOpt('api_insecure',
                default=False,
                help='If set, ignore any SSL validation issues'),
    cfg.StrOpt('ca_file',
               help='Location of CA certificates file for '
                    'securing docker api requests (tlscacert).'),
    cfg.StrOpt('cert_file',
               help='Location of TLS certificate file for '
                    'securing docker api requests (tlscert).'),
    cfg.StrOpt('key_file',
               help='Location of TLS private key file for '
                    'securing docker api requests (tlskey).'),
]

CONF = cfg.CONF
CONF.register_opts(docker_opts, 'docker')

DOCKER_PLUGIN = 'daolinet'
DEFAULT_TIMEOUT_SECONDS = 120
DEFAULT_DOCKER_API_VERSION = '1.19'


class DockerHTTPClient(client.Client):
Example #9
0
                   default=3,
                   help='tester sw receiving port 2 '
                   '(default: 3)'),
        cfg.StrOpt('dir',
                   default='ryu/tests/switch/of13',
                   help='test files directory'),
        cfg.StrOpt('target-version',
                   default='openflow13',
                   help='target sw OFP version [openflow13|openflow14] '
                   '(default: openflow13)'),
        cfg.StrOpt('tester-version',
                   default='openflow13',
                   help='tester sw OFP version [openflow13|openflow14] '
                   '(default: openflow13)')
    ],
    group='test-switch')

CONF.register_cli_opts(
    [
        # refmon
        cfg.StrOpt('config', default=None, help='path of config file'),
        cfg.StrOpt('flowmodlog', default=None,
                   help='path of flowmod log file'),
        cfg.StrOpt('input', default=None, help='path of input file'),
        cfg.StrOpt('log', default=None, help='path of log file'),
        cfg.BoolOpt('always_ready',
                    default=False,
                    help='assume all switches are up and registered with Ryu'),
    ],
    group='refmon')
Example #10
0
from ryu.topology import switches

#"ryu.app.simple_switch_13_rest"
#"ryu.app.domain_controller"
CONF = cfg.CONF
CONF.register_cli_opts([
    cfg.ListOpt('app-lists',
                default=["ryu.app.domain_controller"],
                help='application module name to run'),
    cfg.MultiStrOpt('app',
                    positional=True,
                    default=[],
                    help='application module name to run'),
    cfg.StrOpt('pid-file', default=None, help='pid file name'),
    cfg.BoolOpt('enable-debugger',
                default=False,
                help='don\'t overwrite Python standard threading library'
                '(use only for debugging)'),
    cfg.IntOpt("domain_id", default=1, help="id of domain controller"),
    cfg.StrOpt("domain_wsgi_ip",
               default="10.108.90.202",
               help="port no of domain\'s wsgi"),
    cfg.IntOpt("domain_port",
               default=8080,
               help="domain_port of super controller"),
    cfg.StrOpt("super_wsgi_ip",
               default="10.108.90.200",
               help="port no of super\'s wsgi"),
    cfg.IntOpt("super_wsgi_port",
               default=8080,
               help="super_port of super controller"),
    cfg.BoolOpt('super_exist',
import ShortestPathBridgeNet_NP as spbN_NP
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import set_ev_cls
from ryu.cmd import manager # For directly starting Ryu
import sys  # For getting command line arguments and passing to Ryu
import eventlet
from eventlet import backdoor  # For telnet python access
from ryu.ofproto import ofproto_v1_0 # This code is OpenFlow 1.0 specific

if __name__ == "__main__": # Stuff to set additional command line options
    from ryu import cfg
    CONF = cfg.CONF
    CONF.register_cli_opts([
        cfg.StrOpt('netfile', default=None, help='network json file'),
        cfg.BoolOpt('widest_paths', default=False,
                    help='Use widest path.'),
        cfg.BoolOpt('notelnet', default=False,
                    help='Telnet based debugger.')
    ])

class L2DestForwardStatic(app_manager.RyuApp):
    """
    Waits for OpenFlow switches to connect and then fills their forwarding
    tables based on the network topology json file from the command line.
    """
    OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION]

    def __init__(self, *args, **kwargs):
        """
        Compute the forwarding tables based on the network description file,
        and whether shortest or widest paths should be used.