Something like this dhcp rest responder.

The api is:

Set dhcp in a switch PUT /dhcp/add/{dpid}  params
    'ipaddress': '192.168.1.1'
    'netmask': '255.255.255.0'
    'address': '0a:e4:1c:d1:3e:44'
    'dns': '8.8.8.8'
    'startip':'192.168.1.100'
    'endip': '192.168.1.200'
Set static ip in a host PUT /dhcp/host/{dpid} params
    'address': '00:00:00:d3:fc:57'
    'ipaddress':  '192.168.1.2'
    'hostname': 'huehuehue'
    'dns': '8.8.8.8' * optional

This file is not complete (needs delete functions) but you will get so util.

2016-12-15 22:34 GMT-06:00 Munther Numan <munpro...@gmail.com>:

> Greeting ,
>
> Dear all,
>
>
>
> I just would like to ask you if I need to add dhcp server in my
> experiment, is any example code for it or there is already  code for dhcp
> server with Ryu controller?
>
> Best Regards
>
> Munther Numan
> Master Student
> Faculty of Engineering
> University Putra Malaysia
>
>
>
>
> ------------------------------------------------------------
> ------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, SlashDot.org! http://sdm.link/slashdot
> _______________________________________________
> Ryu-devel mailing list
> Ryu-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/ryu-devel
>
>


-- 
"La utopía sirve para caminar" Fernando Birri
# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
# Copyright (C) 2013 YAMAMOTO Takashi <yamamoto at valinux co jp>
#
# 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.

# a simple ICMP Echo Responder


import json

from ryu.app.wsgi import ControllerBase, WSGIApplication, route
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.lib import addrconv, dpid as dpid_lib
from ryu.lib.packet import dhcp
from ryu.lib.packet import ethernet
from ryu.lib.packet import ipv4
from ryu.lib.packet import packet
from ryu.lib.packet import udp
from ryu.ofproto import ofproto_v1_3
from webob import Response


class DHCPResponder(app_manager.RyuApp):
    """
    use example
        self.switches = {
            '81474781969487': {
                'ipaddress': '192.168.1.1',
                'netmask': '255.255.255.0',
                'address': '0a:e4:1c:d1:3e:44',
                'dns': '8.8.8.8',
                'hosts': {
                    '00:00:00:d3:fc:57': {
                        'hostname': 'huehuehue',
                        'dns': '8.8.8.8',
                        'ipaddress':  '192.168.1.2',
                    }
                },
                'available_address': [
                    '192.168.1.10',
                    '192.168.1.20'
                ]

            }}
    """

    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
    _CONTEXTS = {'wsgi': WSGIApplication}

    def __init__(self, *args, **kwargs):
        super(DHCPResponder, self).__init__(*args, **kwargs)
        self.acks = {}
        self.switches = {}
        wsgi = kwargs['wsgi']
        wsgi.register(DHCPController,
                      {'dhcp_server': self})

    def get_server_info(self, datapath):
        if datapath in self.switches:
            ipaddress = addrconv.ipv4.text_to_bin(
                self.switches[datapath]['ipaddress'])
            netmask = addrconv.ipv4.text_to_bin(
                self.switches[datapath]['netmask'])
            address = str(self.switches[datapath]['address'])
            return ipaddress, netmask, address, str(self.switches[datapath]['ipaddress'])
        return None, None, None, None

    def get_host_info(self, datapath, hostaddress):
        ipaddress = hostname = dns = None
        if datapath in self.switches:
            if hostaddress in self.acks:
                info = self.acks[hostaddress]
                return str(info['ipaddress']), str(info['hostname']), info['dns']

            if hostaddress in self.switches[datapath]['hosts']:
                confhost = self.switches[datapath]['hosts'][hostaddress]
                ipaddress = str(confhost['ipaddress'])
                hostname = str(confhost['hostname'])
                dns = addrconv.ipv4.text_to_bin(confhost['dns'])
            if not ipaddress and self.switches[datapath]['available_address']:
                ipaddress = str(
                    self.switches[datapath]['available_address'].pop())
                num = ipaddress.split('.')[-1]
                hostname = str("machine" + num)
                dns = addrconv.ipv4.text_to_bin(self.switches[datapath]['dns'])
                self.acks[hostaddress] = {
                    'ipaddress': str(ipaddress),
                    'hostname': str(hostname),
                    'dns': dns
                }
        return ipaddress, hostname, dns

    @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
    def _switch_features_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        actions = [parser.OFPActionOutput(port=ofproto.OFPP_CONTROLLER,
                                          max_len=ofproto.OFPCML_NO_BUFFER
                                          )]
        inst = [parser.OFPInstructionActions(type_=ofproto.OFPIT_APPLY_ACTIONS,
                                             actions=actions)]
        mod67 = parser.OFPFlowMod(datapath=datapath,
                                  priority=0,
                                  match=parser.OFPMatch(
                                      eth_type=0x0800, ip_proto=17, udp_dst=67),
                                  instructions=inst)
        mod68 = parser.OFPFlowMod(datapath=datapath,
                                  priority=0,
                                  match=parser.OFPMatch(
                                      eth_type=0x0800, ip_proto=17, udp_dst=68),
                                  instructions=inst)

        req = parser.OFPSetConfig(datapath, ofproto.OFPC_FRAG_NORMAL, 1500)
        datapath.send_msg(req)
        datapath.send_msg(mod67)
        datapath.send_msg(mod68)

    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def _packet_in_handler(self, ev):
        print("PACKET IN")
        msg = ev.msg
        datapath = msg.datapath
        port = msg.match['in_port']
        pkt = packet.Packet(data=msg.data)
        pkt_dhcp = pkt.get_protocols(dhcp.dhcp)
        if pkt_dhcp:
            self._handle_dhcp(datapath, port, pkt)

    def assemble_ack(self, pkt, datapath):
        print("assemble_ack")
        req_eth = pkt.get_protocol(ethernet.ethernet)
        req_ipv4 = pkt.get_protocol(ipv4.ipv4)
        req = pkt.get_protocol(dhcp.dhcp)

        ipaddress, netmask, address, dhcpip = self.get_server_info(datapath)
        hostipaddress, hostname, dns = self.get_host_info(datapath,
                                                          req_eth.src)

        print(ipaddress, datapath)
        if ipaddress:
            req.options.option_list.remove(
                next(opt for opt in req.options.option_list if opt.tag == 53))
            req.options.option_list.insert(
                0, dhcp.option(tag=51, value='8640'))
            req.options.option_list.insert(
                0, dhcp.option(tag=53, value='05'.decode('hex')))

            ack_pkt = packet.Packet()
            ack_pkt.add_protocol(ethernet.ethernet(
                ethertype=req_eth.ethertype, dst=req_eth.src, src=address))
            ack_pkt.add_protocol(
                ipv4.ipv4(dst=req_ipv4.dst, src=dhcpip, proto=req_ipv4.proto))
            ack_pkt.add_protocol(udp.udp(src_port=67, dst_port=68))
            ack_pkt.add_protocol(dhcp.dhcp(op=2, chaddr=req_eth.src,
                                           siaddr=dhcpip,
                                           boot_file=req.boot_file,
                                           yiaddr=hostipaddress,
                                           xid=req.xid,
                                           options=req.options))
            self.logger.info("ASSEMBLED ACK: %s -> %s" %
                             (req_eth.src, hostipaddress))
        return ack_pkt

    def assemble_offer(self, pkt, datapath):
        print("assemble_offer")
        disc_eth = pkt.get_protocol(ethernet.ethernet)
        disc_ipv4 = pkt.get_protocol(ipv4.ipv4)
        disc = pkt.get_protocol(dhcp.dhcp)
        offer_pkt = None
        ipaddress, netmask, address, dhcpip = self.get_server_info(datapath)
        hostipaddress, hostname, dns = self.get_host_info(
            datapath, disc_eth.src)
        print "offer"
        for x, y in zip([ipaddress, netmask, address, dhcpip,
                         hostipaddress, hostname, dns], ["ipaddress",
                                                         "netmask", "address", "dhcpip",
                                                         "hostipaddress", "hostname", "dns"]):
            print y, type(x), x
        if ipaddress:
            disc.options.option_list.remove(
                next(opt for opt in disc.options.option_list if opt.tag == 55))
            disc.options.option_list.remove(
                next(opt for opt in disc.options.option_list if opt.tag == 53))
            disc.options.option_list.remove(
                next(opt for opt in disc.options.option_list if opt.tag == 12))
            disc.options.option_list.insert(
                0, dhcp.option(tag=1, value=netmask))
            disc.options.option_list.insert(
                0, dhcp.option(tag=3, value=ipaddress))
            disc.options.option_list.insert(
                0, dhcp.option(tag=6, value=dns))
            disc.options.option_list.insert(
                0, dhcp.option(tag=12, value=hostname))
            disc.options.option_list.insert(
                0, dhcp.option(tag=53, value='02'.decode('hex')))
            disc.options.option_list.insert(
                0, dhcp.option(tag=54, value=ipaddress))
            offer_pkt = packet.Packet()
            offer_pkt.add_protocol(ethernet.ethernet(
                ethertype=disc_eth.ethertype, dst=disc_eth.src, src=address))
            offer_pkt.add_protocol(
                ipv4.ipv4(dst=disc_ipv4.dst, src=dhcpip, proto=disc_ipv4.proto))
            offer_pkt.add_protocol(udp.udp(src_port=67, dst_port=68))
            offer_pkt.add_protocol(dhcp.dhcp(op=2, chaddr=disc_eth.src,
                                             siaddr=dhcpip,
                                             boot_file=disc.boot_file,
                                             yiaddr=hostipaddress,
                                             xid=disc.xid,
                                             options=disc.options))
            # print(offer_pkt)
            self.logger.info("ASSEMBLED OFFER: %s --> %s" %
                             (disc_eth.src, hostipaddress))
        return offer_pkt

    def get_state(self, pkt_dhcp):
        dhcp_state = ord(
            [opt for opt in pkt_dhcp.options.option_list if opt.tag == 53][0].value)
        if dhcp_state == 1:
            state = 'DHCPDISCOVER'
        elif dhcp_state == 2:
            state = 'DHCPOFFER'
        elif dhcp_state == 3:
            state = 'DHCPREQUEST'
        elif dhcp_state == 5:
            state = 'DHCPACK'
        return state

    def _handle_dhcp(self, datapath, port, pkt):

        pkt_dhcp = pkt.get_protocols(dhcp.dhcp)[0]
        dhcp_state = self.get_state(pkt_dhcp)
        self.logger.info("NEW DHCP %s PACKET RECEIVED: %s" %
                         (dhcp_state, pkt_dhcp.chaddr))

        if dhcp_state == 'DHCPDISCOVER':
            discover = self.assemble_offer(pkt, datapath.id)
            if discover:
                self._send_packet(datapath, port, discover)
        elif dhcp_state == 'DHCPREQUEST':
            ack = self.assemble_ack(pkt, datapath.id)
            if ack:
                self._send_packet(datapath, port, ack)

    def _send_packet(self, datapath, port, pkt):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser
        pkt.serialize()
        #self.logger.info("packet-out %s" % (pkt,))
        data = pkt.data
        actions = [parser.OFPActionOutput(port=port)]
        out = parser.OFPPacketOut(datapath=datapath,
                                  buffer_id=ofproto.OFP_NO_BUFFER,
                                  in_port=ofproto.OFPP_CONTROLLER,
                                  actions=actions,
                                  data=data)
        datapath.send_msg(out)


class DHCPController(ControllerBase):

    def __init__(self, req, link, data, **config):
        super(DHCPController, self).__init__(req, link, data, **config)
        self.dhcp_server = data['dhcp_server']

    @route('dhcp', '/dhcp/all', methods=['GET'])
    def get_dhcp_info(self, req, **kwargs):
        body = json.dumps(self.dhcp_server.switches)
        return Response(content_type='application/json', body=body)

    @route('dhcp', '/dhcp/{dpid}', methods=['GET'],
           requirements={'dpid': dpid_lib.DPID_PATTERN})
    def get_dhcp_switch_info(self, req, **kwargs):
        dpid = dpid_lib.str_to_dpid(kwargs['dpid'])
        if dpid not in self.dhcp_server.switches:
            return Response(status=404)

        body = json.dumps(self.dhcp_server.switches[dpid])
        return Response(content_type='application/json', body=body)

    @route('dhcp', '/dhcp/add/{dpid}', methods=['PUT'],
           requirements={'dpid': dpid_lib.DPID_PATTERN})
    def insert_dhcp_netinformation(self, req, **kwargs):
        dpid = long(kwargs['dpid'])
        try:
            new_entry = req.json if req.body else {}
        except ValueError:
            return Response(status=400)
        if new_entry:
            dns = '8.8.8.8'
            for field in ["ipaddress", "netmask", "address"]:
                if field not in new_entry:
                    return Response(status=400)

            if 'dns' in new_entry:
                dns = new_entry['dns']

            available_address = []
            if 'startip' in new_entry and 'endip' in new_entry:
                startip = int(new_entry['startip'].split('.')[-1])
                endip = int(new_entry['endip'].split('.')[-1])
                base = ".".join(new_entry['startip'].split('.')[:-1])
                if startip >= endip:
                    return Response(status=400)
                for i in range(startip, endip + 1):
                    available_address.append(base + "." + "%02.0f" % (i))

            if dpid not in self.dhcp_server.switches:
                self.dhcp_server.switches[dpid] = {
                    "available_address": available_address,
                    "hosts": {}
                }

            self.dhcp_server.switches[dpid][
                'ipaddress'] = new_entry['ipaddress']
            self.dhcp_server.switches[dpid]['netmask'] = new_entry['netmask']
            self.dhcp_server.switches[dpid]['address'] = new_entry['address']
            self.dhcp_server.switches[dpid]['dns'] = dns
            body = json.dumps(self.dhcp_server.switches[dpid])
            return Response(content_type='application/json', body=body)
        return Response(status=404)

    @route('dhcp', '/dhcp/host/{dpid}', methods=['PUT'],
           requirements={'dpid': dpid_lib.DPID_PATTERN})
    def insert_dhcp_hostinformation(self, req, **kwargs):
        #dpid = dpid_lib.str_to_dpid(kwargs['dpid'])
        dpid = long(kwargs['dpid'])
        if dpid in self.dhcp_server.switches:
            try:
                new_entry = req.json if req.body else {}
            except ValueError:
                return Response(status=400)
            if new_entry:
                dns = self.dhcp_server.switches[dpid]['dns']
                for field in ["ipaddress", 'hostname', "address"]:
                    if field not in new_entry:
                        return Response(status=400)

                if 'dns' in new_entry:
                    dns = new_entry['dns']

                if new_entry["address"] not in self.dhcp_server.switches[dpid]['hosts']:
                    self.dhcp_server.switches[dpid][
                        'hosts'][new_entry["address"]] = {'dns': dns}

                self.dhcp_server.switches[dpid]['hosts'][
                    "ipaddress"] = new_entry['ipaddress']

                self.dhcp_server.switches[dpid][
                    'hosts']['hostname'] = new_entry['hostname']

                body = json.dumps(self.dhcp_server.switches[dpid])
                return Response(content_type='application/json', body=body)
        return Response(status=404)
------------------------------------------------------------------------------
Developer Access Program for Intel Xeon Phi Processors
Access to Intel Xeon Phi processor-based developer platforms.
With one year of Intel Parallel Studio XE.
Training and support from Colfax.
Order your platform today. http://sdm.link/xeonphi
_______________________________________________
Ryu-devel mailing list
Ryu-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to