从controller1向controller2发送消息

时间:2018-09-12 20:22:16

标签: java mininet

我在mininet中有一个拓扑,该拓扑由2个泛光灯控制器(c1和c2),一个连接到c1的交换机(s1)和连接到此交换机的2个主机(h1和h2)组成。我正在编写一个程序,当c1从s1接收到ICMP数据包时,它将向c2发送一个Hello消息。

我为此使用tutorial,它表示:

  

可以使用send将消息从一个控制器发送到另一个控制器   功能,并且消息必须用“ m”“ m”标记。您将把此消息发送给特定的控制器,以便   TO地址由IP:port两部分组成。 IP就是机器   另一个控制器的IP地址(HAServer正在所有ip上监听),   该端口是该端口上HAServer的相应侦听端口   机器。

     

默认情况下,控制器1上的HAServer正在监听4242,   控制器2在4243上,在控制器3在4244上……等等。

     

recv()函数类似于send函数,您将得到   FROM地址,以从特定控制器中获得回音。来自   地址还包括IP:端口两部分。 IP是机器IP   另一个控制器的地址(HAServer正在所有ip上监听),   该端口是该端口上HAServer的相应侦听端口   机器。

     

理想情况下,在调用相应的send()之后调用此函数   功能,否则可能未建立连接,并且   它只会返回错误。

这是我模块的完整代码:

package net.floodlightcontroller.mactracker;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;

import net.floodlightcontroller.core.FloodlightContext;
import net.floodlightcontroller.core.IFloodlightProviderService;
import net.floodlightcontroller.core.IOFMessageListener;
import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.hasupport.IHAControllerService;
import net.floodlightcontroller.hasupport.NetworkNode;
import net.floodlightcontroller.packet.Ethernet;
import net.floodlightcontroller.packet.ICMP;
import net.floodlightcontroller.packet.IPv4;

import org.projectfloodlight.openflow.protocol.OFMessage;
import org.projectfloodlight.openflow.protocol.OFType;
import org.projectfloodlight.openflow.types.EthType;
import org.projectfloodlight.openflow.types.IpProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Mactracker implements IFloodlightModule, IOFMessageListener {

    protected static IHAControllerService hacontroller;
    protected static Logger logger = LoggerFactory.getLogger(Mactracker.class);
    protected IFloodlightProviderService floodlightProvider;
    protected Set<Long> macAddresses;
    private static NetworkNode network;

    @Override
    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
        // TODO Auto-generated method stubs
        return null;
    }

    @Override
    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
        // TODO Auto-generated method stub
        Collection<Class<? extends IFloodlightService>> l =
                new ArrayList<Class<? extends IFloodlightService>>();
            l.add(IFloodlightProviderService.class);
            l.add(IHAControllerService.class);
        return l;
    }

    @Override
    public void init(FloodlightModuleContext context) throws FloodlightModuleException {
        // TODO Auto-generated method stub
        hacontroller = context.getServiceImpl(IHAControllerService.class);
        floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
        macAddresses = new ConcurrentSkipListSet<Long>();
    }

    @Override
    public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
        // TODO Auto-generated method stub
        floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
        // After more than 51% of configured controllers are started, this function will return,
        // or when a timeout of 60s is reached, whichever is earlier.
        hacontroller.pollForLeader();       
    }

    @Override
    public String getName() {
        // TODO Auto-generated method stub
        return Mactracker.class.getSimpleName();
    }

    @Override
    public boolean isCallbackOrderingPrereq(OFType type, String name) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isCallbackOrderingPostreq(OFType type, String name) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public net.floodlightcontroller.core.IListener.Command receive(IOFSwitch sw, OFMessage msg,
            FloodlightContext cntx) {
        // TODO Auto-generated method stub
        Ethernet eth =
                IFloodlightProviderService.bcStore.get(cntx,
                                            IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
        if (eth.getEtherType() == EthType.IPv4) {
            IPv4 ipv4 = (IPv4) eth.getPayload();

            if ( ipv4.getProtocol().equals(IpProtocol.ICMP)){
                logger.warn ("ICMP Packet Received!:-)");
                ICMP icmp = (ICMP) ipv4.getPayload();
                logger.warn ("icmp.getIcmpType: "+icmp.getIcmpType());

                hacontroller.send("127.0.0.1:4243", "mHelloWorld");
                hacontroller.recv("127.0.0.1:4242");
            }
        }

        Long sourceMACHash = eth.getSourceMACAddress().getLong();
        if (!macAddresses.contains(sourceMACHash)) {
            macAddresses.add(sourceMACHash);
            logger.info("MAC Address: {} seen on switch: {}",
                    eth.getSourceMACAddress().toString(),
                    sw.getId().toString());
        }
        return Command.CONTINUE;
    }
}

但是运行这段代码后,当c1收到ICMP数据包时,我遇到了多个错误:

2018-09-13 00:39:56.716 WARN  [n.f.m.Mactracker] ICMP Packet Received!:-)
2018-09-13 00:39:56.716 WARN  [n.f.m.Mactracker] icmp.getIcmpType: 0
2018-09-13 00:39:56.716 INFO  [n.f.h.NetworkNode] [NetworkNode] Sending: mHelloWorld sent through port: 127.0.0.1:4243
2018-09-13 00:39:56.720 WARN  [i.n.c.DefaultChannelPipeline] An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
java.lang.NullPointerException: null
    at net.floodlightcontroller.hasupport.NetworkNode.recv(NetworkNode.java:535) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.hasupport.HAController.recv(HAController.java:190) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.mactracker.Mactracker.receive(Mactracker.java:121) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.Controller.handleMessage(Controller.java:411) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFSwitchManager.handleMessage(OFSwitchManager.java:487) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.dispatchMessage(OFSwitchHandshakeHandler.java:1752) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.access$24(OFSwitchHandshakeHandler.java:1751) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler$MasterState.processOFPacketIn(OFSwitchHandshakeHandler.java:1488) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler$OFSwitchHandshakeState.processOFMessage(OFSwitchHandshakeHandler.java:839) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.processOFMessage(OFSwitchHandshakeHandler.java:1790) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFSwitchHandshakeHandler.messageReceived(OFSwitchHandshakeHandler.java:1964) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFConnection.messageReceived(OFConnection.java:414) ~[floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFChannelHandler.sendMessageToConnection(OFChannelHandler.java:579) [floodlight.jar:1.2-SNAPSHOT]
    at net.floodlightcontroller.core.internal.OFChannelHandler.access$9(OFChannelHandler.java:578) [floodlight.jar:1.2-SNAPSHOT]

出什么问题了? recv()函数似乎出了点问题。这是内置send()和receive函数的代码。

发送():

/**
 * Sends a message to a specified client IP:port, if possible.
 *
 * @return boolean value that indicates success or failure.
 */

@Override
public Boolean send(String clientPort, String message) {
    if (message.equals(null)) {
        return Boolean.FALSE;
    }

    clientSock = socketDict.get(clientPort);
    try {
        logger.info("[NetworkNode] Sending: "+message+" sent through port: "+clientPort.toString());
        clientSock.send(message);
        return Boolean.TRUE;

    } catch (Exception e) {
        if (clientSock.getSocketChannel() != null) {
            clientSock.deleteConnection();
        }
        logger.debug("[NetworkNode] Send Failed: " + message + " not sent through port: " + clientPort.toString());
        return Boolean.FALSE;
    }
}

recv():

/**
 * Receives a message from the specified IP:port, if possible.
 *
 * @return String containing the received message.
 */

@Override
public String recv(String receivingPort) {
    clientSock = socketDict.get(receivingPort);
    try {
        response = clientSock.recv();
        response.trim();
        logger.info("[NetworkNode] Recv on port:"+receivingPort.toString()+response);
        return response;
    } catch (Exception e) {
        if (clientSock.getSocketChannel() != null) {
            clientSock.deleteConnection();
        }
        logger.debug("[NetworkNode] Recv Failed on port: " + receivingPort.toString());
        return "";
    }

}

send()和recv()函数所在的NetworkNode模块的完整代码为here,而高可用性支持的完整程序包为here(如果需要)

4 个答案:

答案 0 :(得分:0)

从您发布的日志和可用的Github存储库来看,clientSock似乎是null。第NullPointerException行第529行被抛出:

response = clientSock.recv();

并被抓住。

但是在catch块中,clientSock仍然是null,所以当您这样做时:

if (clientSock.getSocketChannel() != null) {

抛出第二个NullPointerException(我们在日志中看到的那个),隐藏之前抛出的那个。

您可以调试代码以验证socketDict是否包含receivingPort吗?如果没有,请确保正确初始化它。

此外,捕获Exception通常也不是一个好主意,因为它太大。如果可以的话,我建议您捕获一个更精确的异常。如果这样做,您将更容易看到此错误的来源。

答案 1 :(得分:0)

NetworkNode.recv()中引发的第一个空指针异常是因为clientSock从未初始化。无法检查第535行的空比较,因为clientSock不存在,因此无法调用方法getSocketChannel()

多个类缺少初始化所有变量的构造方法。这似乎是大多数问题的根源。确保也调用了所有init()preStart()方法。看起来大多数变量初始化都是在这些方法中进行的。

答案 2 :(得分:0)

NetworkNode.recv()方法存在多个问题:

  • 在取消引用对象之前,应检查null。
  • 您不应在String对象上调用toString。这是多余的。
  • 在捕获和忽略异常时应该小心。在这种情况下,您不需要捕获Exception,因为NioClient.recv()不会抛出任何异常。该方法应在哪里抑制异常,这是另一个问题。
  • 避免使用成员变量而不是局部变量。每个方法都需要声明局部变量。这是代码中许多地方的常见问题。

receive方法可以重写如下:

NioClient receivingSock = socketDict.get(receivingPort);
if (receivingSock == null) {
    logger.debug("[NetworkNode] No receivingSock on receivingport: " + receivingPort);
    return "";
}
else {
    response = receivingSock.recv();
    if (response != null) {
        response.trim();
    }
    return response;
}

答案 3 :(得分:0)

此代码的问题在于,当交换机向控制器发送新数据包时,调用receive()方法或(例如)处于活动状态。

当第一个控制器接收到ICMP数据包时,它通过以下这段代码向第二个控制器发送问候消息:

 hacontroller.send("127.0.0.1:4243", "mHelloWorld");

但是,由于第二个控制器尚未收到来自交换机的任何消息,因此它目前未实现这段代码(receive()),并且看不到:

hacontroller.recv("127.0.0.1:4242");

据我所知,这就是clientSock从未初始化的原因,所以我收到此错误。