blob: e7bf32880f7ea9c727a812afbf7a8ea7e17b2ed8 [file] [log] [blame]
Hyunsun Moon90163ba2016-10-12 13:35:14 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Hyunsun Moon90163ba2016-10-12 13:35:14 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.ofagent.impl;
17
Daniel Parkbe6b6732016-11-11 15:52:19 +090018import io.netty.bootstrap.Bootstrap;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070019import io.netty.channel.ChannelFuture;
20import io.netty.channel.ChannelFutureListener;
Daniel Parkbe6b6732016-11-11 15:52:19 +090021import io.netty.channel.ChannelOption;
Hyunsun Moon53381e82017-03-28 19:58:28 +090022import io.netty.channel.EventLoop;
Daniel Parkbe6b6732016-11-11 15:52:19 +090023import io.netty.channel.EventLoopGroup;
24import io.netty.channel.socket.nio.NioSocketChannel;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070025import org.onosproject.ofagent.api.OFController;
26import org.onosproject.ofagent.api.OFSwitch;
27import org.slf4j.Logger;
28import org.slf4j.LoggerFactory;
29
Daniel Parkbe6b6732016-11-11 15:52:19 +090030import java.net.InetSocketAddress;
31import java.net.SocketAddress;
Hyunsun Moon53381e82017-03-28 19:58:28 +090032import java.util.concurrent.TimeUnit;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070033import java.util.concurrent.atomic.AtomicInteger;
34
35/**
36 * Implementation of OpenFlow connection handler.
37 * It retries a connection for a certain amount of time and then give up.
38 */
39public final class OFConnectionHandler implements ChannelFutureListener {
40
41 private final Logger log = LoggerFactory.getLogger(getClass());
42
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090043 private static final String MSG_STATE = "Device %s %s to controller %s:%s";
44 private static final String MSG_CONNECTING = "connecting";
45 private static final String MSG_CONNECTED = "connected";
46 private static final String MSG_FAILED = "failed to connect";
47
Daniel Parkbe6b6732016-11-11 15:52:19 +090048 private final AtomicInteger retryCount;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070049 private final OFSwitch ofSwitch;
50 private final OFController controller;
Daniel Parkbe6b6732016-11-11 15:52:19 +090051 private final EventLoopGroup workGroup;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090052
53 // TODO make this value configurable
Daniel Parkbe6b6732016-11-11 15:52:19 +090054 private static final int MAX_RETRY = 3;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070055
56 /**
57 * Default constructor.
58 *
59 * @param ofSwitch openflow switch that initiates this connection
60 * @param controller controller to connect
61 * @param workGroup work group for connection
62 */
63 public OFConnectionHandler(OFSwitch ofSwitch, OFController controller,
Daniel Parkbe6b6732016-11-11 15:52:19 +090064 EventLoopGroup workGroup) {
Hyunsun Moon90163ba2016-10-12 13:35:14 -070065 this.ofSwitch = ofSwitch;
66 this.controller = controller;
67 this.workGroup = workGroup;
Daniel Parkbe6b6732016-11-11 15:52:19 +090068 this.retryCount = new AtomicInteger();
Hyunsun Moon90163ba2016-10-12 13:35:14 -070069 }
70
71 /**
72 * Creates a connection to the supplied controller.
73 */
74 public void connect() {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090075 SocketAddress remoteAddr = new InetSocketAddress(
76 controller.ip().toInetAddress(), controller.port().toInt());
Daniel Parkbe6b6732016-11-11 15:52:19 +090077 Bootstrap bootstrap = new Bootstrap();
78 bootstrap.group(workGroup)
79 .channel(NioSocketChannel.class)
80 .option(ChannelOption.SO_KEEPALIVE, true)
81 .handler(new OFChannelInitializer(ofSwitch));
82
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090083 log.debug(String.format(MSG_STATE,
84 ofSwitch.dpid(),
85 MSG_CONNECTING,
86 controller.ip(),
87 controller.port()));
Daniel Parkbe6b6732016-11-11 15:52:19 +090088 bootstrap.connect(remoteAddr).addListener(this);
Hyunsun Moon90163ba2016-10-12 13:35:14 -070089 }
90
91 @Override
92 public void operationComplete(ChannelFuture future) throws Exception {
Hyunsun Moon90163ba2016-10-12 13:35:14 -070093 if (future.isSuccess()) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090094 log.info(String.format(MSG_STATE,
95 ofSwitch.dpid(),
96 MSG_CONNECTED,
97 controller.ip(),
98 controller.port()));
Hyunsun Moon53381e82017-03-28 19:58:28 +090099 // FIXME add close future listener to handle connection lost
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700100 } else {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900101 if (retryCount.getAndIncrement() > MAX_RETRY) {
102 log.warn(String.format(MSG_STATE,
103 ofSwitch.dpid(),
104 MSG_FAILED,
105 controller.ip(),
106 controller.port()));
107 } else {
Hyunsun Moon53381e82017-03-28 19:58:28 +0900108 final EventLoop loop = future.channel().eventLoop();
109 loop.schedule(this::connect, 1L, TimeUnit.SECONDS);
Daniel Parkbe6b6732016-11-11 15:52:19 +0900110 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700111 }
112 }
113}