Don't restart plugin if its already up TELSDN-564
[lispflowmapping.git] / mappingservice / southbound / src / main / java / org / opendaylight / lispflowmapping / southbound / LispSouthboundPlugin.java
1 /*
2  * Copyright (c) 2013 Contextream, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.lispflowmapping.southbound;
10
11 import java.io.IOException;
12 import java.net.DatagramPacket;
13 import java.net.DatagramSocket;
14 import java.net.InetAddress;
15 import java.net.InetSocketAddress;
16 import java.net.SocketException;
17 import java.net.SocketTimeoutException;
18 import java.nio.ByteBuffer;
19 import java.util.concurrent.Future;
20
21 import org.eclipse.osgi.framework.console.CommandProvider;
22 import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
23 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
24 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
25 import org.opendaylight.lispflowmapping.implementation.serializer.LispMessage;
26 import org.opendaylight.lispflowmapping.implementation.serializer.MapNotifySerializer;
27 import org.opendaylight.lispflowmapping.implementation.serializer.MapReplySerializer;
28 import org.opendaylight.lispflowmapping.southbound.lisp.LispSouthboundService;
29 import org.opendaylight.lispflowmapping.type.lisp.MapNotify;
30 import org.opendaylight.lispflowmapping.type.lisp.MapReply;
31 import org.opendaylight.lispflowmapping.type.sbplugin.ILispSouthboundPlugin;
32 import org.opendaylight.yangtools.yang.common.RpcResult;
33 import org.osgi.framework.BundleContext;
34 import org.osgi.framework.FrameworkUtil;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 public class LispSouthboundPlugin extends AbstractBindingAwareProvider implements ILispSouthboundPlugin, CommandProvider {
39     protected static final Logger logger = LoggerFactory.getLogger(LispSouthboundPlugin.class);
40
41     private LispIoThread thread;
42     private LispSouthboundService lispSouthboundService;
43     private volatile DatagramSocket socket = null;
44     private final String MAP_NOTIFY = "MapNotify";
45     private final String MAP_REPlY = "MapReply";
46
47     private void registerWithOSGIConsole() {
48         BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
49         bundleContext.registerService(CommandProvider.class.getName(), this, null);
50     }
51
52     protected void stopImpl(BundleContext context) {
53         unloadActions();
54     }
55
56     private void unloadActions() {
57         if (thread != null) {
58             thread.stopRunning();
59         }
60         lispSouthboundService = null;
61         thread = null;
62         logger.info("LISP (RFC6830) Mapping Service is down!");
63         try {
64             Thread.sleep(1100);
65         } catch (InterruptedException e) {
66         }
67     }
68
69     public void destroy() {
70         unloadActions();
71     }
72
73     private class LispIoThread extends Thread {
74         private volatile boolean running;
75
76         public LispIoThread() {
77             super("Lisp Thread");
78             running = true;
79         }
80
81         @Override
82         public void run() {
83             String lispBindAddress = "0.0.0.0";
84             String lispIp = System.getProperty("lispip");
85             if (lispIp != null) {
86                 lispBindAddress = lispIp;
87             }
88
89             int lispPortNumber = LispMessage.PORT_NUM;
90             int lispReceiveTimeout = 1000;
91
92             logger.info("LISP (RFC6830) Mapping Service is running and listening on " + lispBindAddress);
93             try {
94                 socket = new DatagramSocket(new InetSocketAddress(lispBindAddress, lispPortNumber));
95                 socket.setSoTimeout(lispReceiveTimeout);
96             } catch (SocketException e) {
97                 logger.warn("Cannot open socket on UDP port " + lispPortNumber, e);
98                 return;
99             }
100
101             while (running) {
102                 byte[] buffer = new byte[4096];
103                 DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
104                 try {
105                     socket.receive(packet);
106                     logger.debug("Received a packet!");
107                 } catch (SocketTimeoutException ste) {
108                     continue;
109                 } catch (IOException e) {
110                     logger.error("IO Exception while trying to recieve packet", e);
111                 }
112                 logger.debug("Handling packet from {}:{} (len={})", packet.getAddress().getHostAddress(), packet.getPort(), packet.getLength());
113
114                 try {
115                     lispSouthboundService.handlePacket(packet);
116                 } catch (Throwable t) {
117                     logger.error("Error while handling packet", t);
118                 }
119             }
120
121             socket.close();
122             logger.info("Socket closed");
123         }
124
125         public void stopRunning() {
126             running = false;
127         }
128     }
129
130     public static String intToIpv4(int address) {
131         return ((address >> 24) & 0xff) + "." + //
132                 ((address >> 16) & 0xff) + "." + //
133                 ((address >> 8) & 0xff) + "." + //
134                 ((address >> 0) & 0xff);
135     }
136
137     public String getHelp() {
138         StringBuffer help = new StringBuffer();
139         help.append("---LISP Southbound Plugin---\n");
140         return help.toString();
141     }
142
143     public void onSessionInitiated(ProviderContext session) {
144         if (thread == null) {
145             lispSouthboundService = new LispSouthboundService();
146             thread = new LispIoThread();
147             logger.info("LISP (RFC6830) Mapping Service is up!");
148             thread.start();
149
150             // OSGI console
151             registerWithOSGIConsole();
152
153             logger.debug("Provider Session initialized");
154
155             lispSouthboundService.setNotificationProvider(session.getSALService(NotificationProviderService.class));
156             session.addRpcImplementation(ILispSouthboundPlugin.class, this);
157         }
158     }
159
160     public Future<RpcResult<Void>> handleMapNotify(MapNotify mapNotify, InetAddress address) {
161         logger.trace("handleMapNotify called!!");
162         if (mapNotify != null) {
163             ByteBuffer outBuffer = MapNotifySerializer.getInstance().serialize(mapNotify);
164             handleSerializedLispBuffer(address, outBuffer, MAP_NOTIFY);
165         } else {
166             logger.debug("MapNotify was null");
167         }
168         return null;
169     }
170
171     private void handleSerializedLispBuffer(InetAddress address, ByteBuffer outBuffer, String packetType) {
172         DatagramPacket packet = new DatagramPacket(outBuffer.array(), outBuffer.limit());
173         packet.setPort(LispMessage.PORT_NUM);
174         packet.setAddress(address);
175         try {
176             if (logger.isDebugEnabled()) {
177                 logger.debug("Sending " + packetType + " on port " + LispMessage.PORT_NUM + " to address: " + address);
178             }
179             socket.send(packet);
180         } catch (IOException e) {
181             logger.error("Failed to send " + packetType, e);
182         }
183     }
184
185     public Future<RpcResult<Void>> handleMapReply(MapReply mapReply, InetAddress address) {
186         logger.trace("handleMapReply called!!");
187         if (mapReply != null) {
188             ByteBuffer outBuffer = MapReplySerializer.getInstance().serialize(mapReply);
189             handleSerializedLispBuffer(address, outBuffer, MAP_REPlY);
190         } else {
191             logger.debug("MapReply was null");
192         }
193         return null;
194     }
195 }