切换负载平衡动态主机拓扑

Switch load balancing dynamic host topology

下面是在mininet中搭建网络的代码,每台主机运行一个客户端程序(即通过hx.cmd('python pyexample.py')),每台服务器运行一个服务器程序哪些客户端将连接到。

首先,我把所有的主机都连接到了交换机上,有的是服务器,有的是主机。当 hosts/clients/servers 的数量不固定时,如何让此开关充当 负载平衡器

其次,在多个客户端向单个服务器发送请求的情况下,如何让客户端和服务器相互连接并将结果return发送给单个客户端?

#!/usr/bin/python

from mininet.topo import Topo
from mininet.net import Mininet
from mininet.util import dumpNodeConnections
from mininet.log import setLogLevel

import math

# num_hosts = number of servers + clients
# network with n hosts connected to one switch
class NetworkTopology(Topo, num_hosts, num_servers):
    clients = []
    servers = []

    def build(self, n=num_hosts):
        # Switch controlled to act as load balancer
        # TODO: Write controller
        switch = self.addSwitch('s1')

        # Generate 0..n-1 hosts - n = num_hosts
        for h in range(n):
            s = 0
            while s < num_servers:
                # Add server to the topology
                server = self.addHost('server%s' % (s+1))
                self.addLink(server, switch)
                servers.append(server)
            else:
                # Add client to the topology
                client = self.addHost('client%s' % ((h-s)+1))
                self.addLink(host, switch)
                clients.append(client)


def runTest(num_hosts, num_servers, num_levels, num_base_reports):
    topo = NetworkTopology(num_hosts, num_servers)


# Main function
if __name__ == '__main__':
    setLogLevel('info')

    num_base_reports = 100
    num_levels = math.log(num_base_reports, 10) # log to base 10
    num_hosts = round(4**(math.log(num_base_reports-1, 10)))
    num_servers = round(2**(math.log(num_base_reports-1, 10)))

    runTest(num_hosts, num_servers num_levels, num_base_reports)

编辑

下面是我用于客户端和服务器 Java 程序之间的套接字的代码,它们将在拓扑中的相应客户端和服务器主机上 运行。

服务器:

public class Server
{
    // Server socket
    protected ServerSocket serverSocket;
    // Server port
    public static final int PORT = 3000;

    public Server() throws IOException {
        this.serverSocket = new ServerSocket(PORT);
    }

    public ServerSocket getSocket() {
        return serverSocket;
    }

    public static void main(String[] args) {
        try {
            Server server = new Server();

            while(true) {
                // Get client socket
                Socket socket = server.getSocket().accept();
                new ClientThread(socket, server).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ClientThread:

public class ClientThread extends Thread
{

    private Socket socket;
    private static PDP server;

    public ClientThread(Socket sock, PDP server) {
        this.socket = sock;
        this.server = server;
    }

    public void run() {
        InputStream is = null;
        BufferedReader br = null;
        DataOutputStream dos = null;

        try {
            is = socket.getInputStream();
            br = new BufferedReader(new InputStreamReader(is));
            dos = new DataOutputStream(socket.getOutputStream());

            String request;
            while(true) {
                if((request = br.readLine()) != null) {
                    // Read request

                    // -- snip --

                    String response = "Done!";
                    // Send back response
                    dos.writeBytes(response + "\n\r");
                    dos.flush();
                } else {
                    socket.close();
                    System.out.println("Client Disconnected\n\r");
                    return;
                }
            }
        } catch (IOException e) {
            return;
        }
    }
}

客户:

public class Client
{
    protected static final int PORT = 3000;

    public Client() {
    }

    public static void main(String[] args) {
        try {
            Socket sock = new Socket("127.0.0.1", PORT);

            // Output Stream (sending to server)
            OutputStream os = sock.getOutputStream();
            PrintWriter pw = new PrintWriter(os, true);

            // Input Stream (receiving from server)
            InputStream is = sock.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));

            String request, response;
            while(true) {
                request = "MyRequest!";
                pw.println(request);
                if((response = br.readLine()) != null) {
                    System.out.println(response);
                    break;
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

如您所知,在 SDN 中发生了一些新的事情;是的!数据平面和控制平面分离!所以你必须使用控制器在你的网络中构建负载平衡功能。 SDN 控制器和交换机使用 OpenFlow 或另一个南向 API 来相互连接。防火墙、NATing、负载平衡等网络功能将在控制器软件上实现。

控制器有多种选择,如ONOS、OpenDaylight、Floodlight、RYU等。如果你在python中编写代码很容易,也许你最好选择RYU controller,因为其他提到的控制器都是基于java的。

您可以找到在 RYU 控制器顶部实现简单循环负载平衡应用程序的示例代码:

https://github.com/omi-uulm/openflow-loadbalancer/blob/master/load_balancer.py

您应该在第 131 行和此块中添加您的代码:

您必须在第 131 行之后和以下 elif 块中添加您的代码:

elif ip.proto == 0x06: # Resolve TCP

例如这样的事情:

elif ip.proto == 0x06: # Resolve TCP

                if pkt_tcp.src_port == 3000: # Ignore packets from server when creating rule
                    return

                ip_src = ip.src

                # if ip of client has been learned (flow installed), no need to process
                # helps with burst of traffic that creates duplicate flows
                if ip_src in self.ip_to_mac:
                    return

                out_port = self.net.servers[self.rr_counter].port
                mac_dest = self.net.servers[self.rr_counter].mac


                ip.dst = self.net.lb_ip

                # Forward Received TCP Packet to the selected Server
                p = packet.Packet()
                p.add_protocol(ethernet.ethernet(dst=mac_dest, src=src, ethertype=ether_types.ETH_TYPE_IP))
                p.add_protocol(ip)
                p.add_protocol(pkt_tcp)

                self.send_packet(p, msg, datapath, out_port)

                # Add Flow Entry
                match = datapath.ofproto_parser.OFPMatch(in_port=msg.in_port, dl_type=0x0800,
                                                         nw_proto=0x06, nw_src=ip_src, nw_dst=self.net.lb_ip)
                actions = [parser.OFPActionSetDlDst(mac_dest), parser.OFPActionOutput(out_port)]
                self.add_flow(match, actions)

                # Insert reverse flow
                match = datapath.ofproto_parser.OFPMatch(in_port=out_port, dl_type=0x0800,
                                                         nw_proto=0x06, nw_src=self.net.lb_ip, nw_dst=ip_src)
                actions = [parser.OFPActionSetDlSrc(self.net.lb_mac), parser.OFPActionOutput(msg.in_port)]
                self.add_flow(match, actions)

                # Update ARP table
                self.ip_to_mac.update({ip_src: src})

                # Update RR counter
                self.rr_counter = (self.rr_counter + 1) % self.net.servers_num

不要忘记在 network_setup.py class.

中添加您的 lb 和服务器 Mac 以及 IP

可能以这种方式帮助您的其他资源:

OpenFlow Switch Specification. Version 1.3.3

RYU Controller Guide