/*
 * Copyright 2017-present Open Networking Foundation
 *
 * 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.
 */

package org.onosproject.ra;

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.EthType;
import org.onlab.packet.Ethernet;
import org.onlab.packet.ICMP6;
import org.onlab.packet.IPv6;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.ndp.NeighborDiscoveryOptions;
import org.onlab.packet.ndp.RouterAdvertisement;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.MastershipRole;
import org.onosproject.net.config.ConfigFactory;
import org.onosproject.net.config.NetworkConfigEvent;
import org.onosproject.net.config.NetworkConfigListener;
import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.config.basics.InterfaceConfig;
import org.onosproject.net.config.basics.SubjectFactories;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.intf.Interface;
import org.onosproject.net.intf.InterfaceEvent;
import org.onosproject.net.intf.InterfaceListener;
import org.onosproject.net.intf.InterfaceService;
import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.InboundPacket;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketContext;
import org.onosproject.net.packet.PacketProcessor;
import org.onosproject.net.packet.PacketService;
import org.onosproject.ra.config.RouterAdvertisementDeviceConfig;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.concurrent.GuardedBy;
import java.nio.ByteBuffer;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.IntStream;

import static com.google.common.base.Strings.isNullOrEmpty;
import static org.onlab.util.Tools.get;
import static org.onlab.util.Tools.groupedThreads;
import com.google.common.collect.ImmutableMap;

/**
 * Manages IPv6 Router Advertisements.
 */
@Service
@Component(immediate = true)
public class RouterAdvertisementManager implements RoutingAdvertisementService {

    private final Logger log = LoggerFactory.getLogger(getClass());
    private static final String PROP_RA_THREADS_POOL = "raPoolSize";
    private static final int DEFAULT_RA_THREADS_POOL_SIZE = 10;
    private static final String PROP_RA_THREADS_DELAY = "raThreadDelay";
    private static final int DEFAULT_RA_THREADS_DELAY = 5;
    private static final String PROP_RA_FLAG_MBIT_STATUS = "raFlagMbitStatus";
    private static final boolean DEFAULT_RA_FLAG_MBIT_STATUS = false;
    private static final String PROP_RA_FLAG_OBIT_STATUS = "raFlagObitStatus";
    private static final boolean DEFAULT_RA_FLAG_OBIT_STATUS = false;
    private static final String PROP_RA_OPTION_PREFIX_STATUS = "raOptionPrefixStatus";
    private static final boolean DEFAULT_RA_OPTION_PREFIX_STATUS = false;
    private static final String PROP_RA_GLOBAL_PREFIX_CONF_STATUS = "raGlobalPrefixConfStatus";
    private static final boolean DEFAULT_RA_GLOBAL_PREFIX_CONF_STATUS = true;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected CoreService coreService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    PacketService packetService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected ComponentConfigService componentConfigService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    public InterfaceService interfaceService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    public MastershipService mastershipService;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected NetworkConfigRegistry networkConfigRegistry;

    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
    protected DeviceService deviceService;

    @Property(name = PROP_RA_THREADS_POOL, intValue = DEFAULT_RA_THREADS_POOL_SIZE,
            label = "Thread pool capacity")
    protected int raPoolSize = DEFAULT_RA_THREADS_POOL_SIZE;

    @Property(name = PROP_RA_THREADS_DELAY, intValue = DEFAULT_RA_THREADS_DELAY,
            label = "Thread delay in seconds")
    protected int raThreadDelay = DEFAULT_RA_THREADS_DELAY;

    @Property(name = PROP_RA_FLAG_MBIT_STATUS, boolValue = DEFAULT_RA_FLAG_MBIT_STATUS,
            label = "Turn M-bit flag on/off")
    protected boolean raFlagMbitStatus = DEFAULT_RA_FLAG_MBIT_STATUS;

    @Property(name = PROP_RA_FLAG_OBIT_STATUS, boolValue = DEFAULT_RA_FLAG_OBIT_STATUS,
            label = "Turn O-bit flag on/off")
    protected boolean raFlagObitStatus = DEFAULT_RA_FLAG_OBIT_STATUS;

    @Property(name = PROP_RA_OPTION_PREFIX_STATUS, boolValue = DEFAULT_RA_OPTION_PREFIX_STATUS,
            label = "Prefix option support needed or not")
    protected boolean raOptionPrefixStatus = DEFAULT_RA_OPTION_PREFIX_STATUS;

    @Property(name = PROP_RA_GLOBAL_PREFIX_CONF_STATUS, boolValue = DEFAULT_RA_GLOBAL_PREFIX_CONF_STATUS,
            label = "Global prefix configuration support on/off")
    protected boolean raGlobalConfigStatus = DEFAULT_RA_GLOBAL_PREFIX_CONF_STATUS;

    @GuardedBy(value = "this")
    private final Map<ConnectPoint, Map.Entry<ScheduledFuture<?>, List<InterfaceIpAddress>>> transmitters =
            new LinkedHashMap<>();

    @GuardedBy(value = "this")
    private final Map<DeviceId, List<InterfaceIpAddress>> globalPrefixes = new LinkedHashMap<>();

    @Override
    public ImmutableMap<DeviceId, List<InterfaceIpAddress>> getGlobalPrefixes() {
        return ImmutableMap.copyOf(globalPrefixes);
    }

    private Function<Interface, Map.Entry<ConnectPoint, List<InterfaceIpAddress>>> prefixGenerator =
            i -> {
                Map.Entry<ConnectPoint, List<InterfaceIpAddress>> prefixEntry;
                if (raGlobalConfigStatus && globalPrefixes.containsKey(i.connectPoint().deviceId())) {
                    prefixEntry = new AbstractMap.SimpleEntry<>(i.connectPoint(),
                            globalPrefixes.get(i.connectPoint().deviceId()));
                } else {
                    prefixEntry = new AbstractMap.SimpleEntry<>(i.connectPoint(), i.ipAddressesList());
                }
                return prefixEntry;
            };

    private ScheduledExecutorService executors = null;

    private static final String APP_NAME = "org.onosproject.routeradvertisement";
    private ApplicationId appId;

    private final ConfigFactory<DeviceId, RouterAdvertisementDeviceConfig> deviceConfigFactory =
            new ConfigFactory<DeviceId, RouterAdvertisementDeviceConfig>(
                    SubjectFactories.DEVICE_SUBJECT_FACTORY,
                    RouterAdvertisementDeviceConfig.class, "routeradvertisement") {
                @Override
                public RouterAdvertisementDeviceConfig createConfig() {

                    return new RouterAdvertisementDeviceConfig();
                }
            };

    // Listener for handling dynamic interface modifications.
    private class InternalInterfaceListener implements InterfaceListener {
        @Override
        public void event(InterfaceEvent event) {
            switch (event.type()) {
                case INTERFACE_ADDED:
                case INTERFACE_UPDATED:
                    clearTxWorkers();
                    loadGlobalPrefixConfig();
                    setupTxWorkers();
                    log.info("Configuration updated for {}", event.subject());
                    break;
                case INTERFACE_REMOVED:
                    Interface i = event.subject();
                    if (mastershipService.getLocalRole(i.connectPoint().deviceId())
                            == MastershipRole.MASTER) {
                        deactivateRouterAdvertisement(i.connectPoint());
                    }
                    break;
                default:
            }
        }
    }

    private final InterfaceListener interfaceListener = new InternalInterfaceListener();

    // Enables RA threads on 'connectPoint' with configured IPv6s
    private synchronized void activateRouterAdvertisement(ConnectPoint connectPoint,
                                                          List<InterfaceIpAddress> addresses) {
        RAWorkerThread worker = new RAWorkerThread(connectPoint, addresses, raThreadDelay, null, null);
        ScheduledFuture<?> handler = executors.scheduleAtFixedRate(worker, raThreadDelay,
                raThreadDelay, TimeUnit.SECONDS);
        transmitters.put(connectPoint, new AbstractMap.SimpleEntry<>(handler, addresses));
    }

    // Disables already activated RA threads on 'connectPoint'
    private synchronized List<InterfaceIpAddress> deactivateRouterAdvertisement(ConnectPoint connectPoint) {
        if (connectPoint != null) {
            Map.Entry<ScheduledFuture<?>, List<InterfaceIpAddress>> details = transmitters.get(connectPoint);
            details.getKey().cancel(false);
            transmitters.remove(connectPoint);
            return details.getValue();
        }
        return null;
    }

    private synchronized void setupThreadPool() {
        executors = Executors.newScheduledThreadPool(raPoolSize,
                groupedThreads("RouterAdvertisement", "event-%d", log));
    }

    private synchronized void clearThreadPool() {
        executors.shutdown();
    }

    // Start Tx threads for all configured interfaces.
    private synchronized void setupTxWorkers() {
        interfaceService.getInterfaces()
                .stream()
                .filter(i -> mastershipService.getLocalRole(i.connectPoint().deviceId())
                        == MastershipRole.MASTER)
                .map(prefixGenerator::apply)
                .filter(i -> i.getValue()
                        .stream()
                        .anyMatch(ia -> ia.ipAddress().version().equals(IpAddress.Version.INET6)))
                .forEach(j ->
                        activateRouterAdvertisement(j.getKey(), j.getValue())
                );
    }

    // Clear out Tx threads.
    private synchronized void clearTxWorkers() {
        transmitters.entrySet().stream().forEach(i -> i.getValue().getKey().cancel(false));
        transmitters.clear();
    }

    private synchronized void setupPoolAndTxWorkers() {
        setupThreadPool();
        setupTxWorkers();
    }

    private synchronized void clearPoolAndTxWorkers() {
        clearTxWorkers();
        clearThreadPool();
    }

    // Loading global prefixes for devices from network configuration
    private synchronized void loadGlobalPrefixConfig() {
        globalPrefixes.clear();
        Set<DeviceId> deviceSubjects =
                networkConfigRegistry.getSubjects(DeviceId.class, RouterAdvertisementDeviceConfig.class);
        deviceSubjects.forEach(subject -> {
            RouterAdvertisementDeviceConfig config =
                    networkConfigRegistry.getConfig(subject, RouterAdvertisementDeviceConfig.class);
            if (config != null) {
                List<InterfaceIpAddress> ips = config.prefixes();
                globalPrefixes.put(subject, ips);
            }
        });
    }

    // Handler for network configuration updates
    private class InternalNetworkConfigListener implements NetworkConfigListener {
        @Override
        public void event(NetworkConfigEvent event) {
            if (event.configClass().equals(RouterAdvertisementDeviceConfig.class)
                    || event.configClass().equals(InterfaceConfig.class)) {
                switch (event.type()) {
                    case CONFIG_ADDED:
                    case CONFIG_UPDATED:
                        clearTxWorkers();
                        loadGlobalPrefixConfig();
                        setupTxWorkers();
                        log.info("Configuration updated for {}", event.subject());
                        break;
                    default:
                }
            }
        }
    }

    private final InternalNetworkConfigListener networkConfigListener
            = new InternalNetworkConfigListener();

    // Handler for device updates
    private class InternalDeviceListener implements DeviceListener {

        @Override
        public void event(DeviceEvent event) {
            switch (event.type()) {
                case DEVICE_ADDED:
                case PORT_UPDATED:
                case PORT_ADDED:
                case DEVICE_UPDATED:
                case DEVICE_AVAILABILITY_CHANGED:
                    clearTxWorkers();
                    setupTxWorkers();
                    log.trace("Processed device event {} on {}", event.type(), event.subject());
                    break;
                default:
            }
        }
    }

    private final InternalDeviceListener internalDeviceListener =
            new InternalDeviceListener();

    // Processor for Solicited RA packets
    private class InternalPacketProcessor implements PacketProcessor {

        @Override
        public void process(PacketContext context) {
            if (context.isHandled()) {
                return;
            }

            // Ensure packet is IPv6 Solicited RA
            InboundPacket pkt = context.inPacket();
            Ethernet ethernet = pkt.parsed();
            if ((ethernet == null) || (ethernet.getEtherType() != Ethernet.TYPE_IPV6)) {
                return;
            }
            IPv6 ipv6Packet = (IPv6) ethernet.getPayload();
            if (ipv6Packet.getNextHeader() != IPv6.PROTOCOL_ICMP6) {
                return;
            }
            ICMP6 icmp6Packet = (ICMP6) ipv6Packet.getPayload();
            if (icmp6Packet.getIcmpType() != ICMP6.ROUTER_SOLICITATION) {
                return;
            }

            // Start solicited-RA handling thread
            SolicitedRAWorkerThread sraWorkerThread = new SolicitedRAWorkerThread(pkt);
            executors.schedule(sraWorkerThread, 0, TimeUnit.SECONDS);
        }
    }

    InternalPacketProcessor processor = null;

    @Activate
    protected void activate(ComponentContext context) {
        // Basic application registrations.
        appId = coreService.registerApplication(APP_NAME);
        componentConfigService.registerProperties(getClass());

        // Packet processor for handling Router Solicitations
        processor = new InternalPacketProcessor();
        packetService.addProcessor(processor, PacketProcessor.director(3));

        // Setup global prefix loading components
        networkConfigRegistry.addListener(networkConfigListener);
        networkConfigRegistry.registerConfigFactory(deviceConfigFactory);
        loadGlobalPrefixConfig();

        // Dynamic device updates handling
        deviceService.addListener(internalDeviceListener);

        // Setup pool and worker threads for existing interfaces
        setupPoolAndTxWorkers();
    }


    @Modified
    protected void modified(ComponentContext context) {
        int newRaPoolSize, newRaThreadDelay;

        // Loading configured properties.
        if (context != null) {
            Dictionary<?, ?> properties = context.getProperties();
            try {
                // Handle change in pool size
                String s = get(properties, PROP_RA_THREADS_POOL);
                newRaPoolSize = isNullOrEmpty(s) ?
                        DEFAULT_RA_THREADS_POOL_SIZE : Integer.parseInt(s.trim());
                if (newRaPoolSize != raPoolSize) {
                    raPoolSize = newRaPoolSize;
                    clearPoolAndTxWorkers();
                    setupPoolAndTxWorkers();
                    log.info("Thread pool size updated to {}", raPoolSize);
                }

                // Handle change in thread delay
                s = get(properties, PROP_RA_THREADS_DELAY);
                newRaThreadDelay = isNullOrEmpty(s) ?
                        DEFAULT_RA_THREADS_DELAY : Integer.parseInt(s.trim());
                if (newRaThreadDelay != raThreadDelay) {
                    raThreadDelay = newRaThreadDelay;
                    clearTxWorkers();
                    setupTxWorkers();
                    log.info("Thread delay updated to {}", raThreadDelay);
                }

                // Handle M-flag changes
                s = get(properties, PROP_RA_FLAG_MBIT_STATUS);
                if (!isNullOrEmpty(s)) {
                    raFlagMbitStatus = Boolean.parseBoolean(s.trim());
                    log.info("RA M-flag set {}", s);
                }

                // Handle O-flag changes
                s = get(properties, PROP_RA_FLAG_OBIT_STATUS);
                if (!isNullOrEmpty(s)) {
                    raFlagObitStatus = Boolean.parseBoolean(s.trim());
                    log.info("RA O-flag set {}", s);
                }

                // Handle prefix option configuration
                s = get(properties, PROP_RA_OPTION_PREFIX_STATUS);
                if (!isNullOrEmpty(s)) {
                    raOptionPrefixStatus = Boolean.parseBoolean(s.trim());
                    String status = raOptionPrefixStatus ? "enabled" : "disabled";
                    log.info("RA prefix option {}", status);
                }

                s = get(properties, PROP_RA_GLOBAL_PREFIX_CONF_STATUS);
                if (!isNullOrEmpty(s)) {
                    raGlobalConfigStatus = Boolean.parseBoolean(s.trim());
                    clearTxWorkers();
                    setupTxWorkers();
                    String status = raOptionPrefixStatus ? "enabled" : "disabled";
                    log.info("RA global configuration file loading {}", status);
                }

            } catch (NumberFormatException e) {
                log.warn("Component configuration had invalid value, aborting changes loading.", e);
            }
        }
    }

    @Deactivate
    protected void deactivate() {
        // Unregister resources.
        componentConfigService.unregisterProperties(getClass(), false);
        interfaceService.removeListener(interfaceListener);
        networkConfigRegistry.removeListener(networkConfigListener);
        networkConfigRegistry.unregisterConfigFactory(deviceConfigFactory);
        packetService.removeProcessor(processor);
        deviceService.removeListener(internalDeviceListener);

        // Clear pool & threads
        clearPoolAndTxWorkers();
    }

    // Worker thread for actually sending ICMPv6 RA packets.
    private class RAWorkerThread implements Runnable {

        ConnectPoint connectPoint;
        List<InterfaceIpAddress> ipAddresses;
        int retransmitPeriod;
        MacAddress solicitHostMac;
        byte[] solicitHostAddress;

        // Various fixed values in RA packet
        public static final byte RA_HOP_LIMIT = (byte) 0xff;
        public static final short RA_ROUTER_LIFETIME = (short) 1800;
        public static final int RA_OPTIONS_BUFFER_SIZE = 500;
        public static final int RA_OPTION_MTU_VALUE = 1500;
        public static final int RA_OPTION_PREFIX_VALID_LIFETIME = 600;
        public static final int RA_OPTION_PREFIX_PREFERRED_LIFETIME = 600;
        public static final int RA_RETRANSMIT_CALIBRATION_PERIOD = 1;


        RAWorkerThread(ConnectPoint connectPoint, List<InterfaceIpAddress> ipAddresses, int period,
                       MacAddress macAddress, byte[] ipv6Address) {
            this.connectPoint = connectPoint;
            this.ipAddresses = ipAddresses;
            retransmitPeriod = period;
            solicitHostMac = macAddress;
            solicitHostAddress = ipv6Address;
        }

        public void run() {
            // Router Advertisement header filling. Please refer RFC-2461.
            RouterAdvertisement ra = new RouterAdvertisement();
            ra.setCurrentHopLimit(RA_HOP_LIMIT);
            ra.setMFlag((byte) (raFlagMbitStatus ? 0x01 : 0x00));
            ra.setOFlag((byte) (raFlagObitStatus ? 0x01 : 0x00));
            ra.setRouterLifetime(RA_ROUTER_LIFETIME);
            ra.setReachableTime(0);
            ra.setRetransmitTimer(retransmitPeriod + RA_RETRANSMIT_CALIBRATION_PERIOD);

            // Option : Source link-layer address.
            byte[] optionBuffer = new byte[RA_OPTIONS_BUFFER_SIZE];
            ByteBuffer option = ByteBuffer.wrap(optionBuffer);
            Optional<MacAddress> macAddress = interfaceService.getInterfacesByPort(connectPoint).stream()
                    .map(Interface::mac).findFirst();
            if (!macAddress.isPresent()) {
                log.warn("Unable to retrieve interface {} MAC address. Terminating RA transmission.", connectPoint);
                return;
            }
            option.put(macAddress.get().toBytes());
            ra.addOption(NeighborDiscoveryOptions.TYPE_SOURCE_LL_ADDRESS,
                    Arrays.copyOfRange(option.array(), 0, option.position()));

            // Option : MTU.
            option.rewind();
            option.putShort((short) 0);
            option.putInt(RA_OPTION_MTU_VALUE);
            ra.addOption(NeighborDiscoveryOptions.TYPE_MTU,
                    Arrays.copyOfRange(option.array(), 0, option.position()));

            // Option : Prefix information.
            if (raOptionPrefixStatus) {
                ipAddresses.stream()
                        .filter(i -> i.ipAddress().version().equals(IpAddress.Version.INET6))
                        .forEach(i -> {
                            option.rewind();
                            option.put((byte) i.subnetAddress().prefixLength());
                            // Enable "onlink" option only.
                            option.put((byte) 0x80);
                            option.putInt(RA_OPTION_PREFIX_VALID_LIFETIME);
                            option.putInt(RA_OPTION_PREFIX_PREFERRED_LIFETIME);
                            // Clear reserved fields
                            option.putInt(0x00000000);
                            option.put(IpAddress.makeMaskedAddress(i.ipAddress(),
                                    i.subnetAddress().prefixLength()).toOctets());
                            ra.addOption(NeighborDiscoveryOptions.TYPE_PREFIX_INFORMATION,
                                    Arrays.copyOfRange(option.array(), 0, option.position()));

                        });
            }

            // ICMPv6 header filling.
            ICMP6 icmpv6 = new ICMP6();
            icmpv6.setIcmpType(ICMP6.ROUTER_ADVERTISEMENT);
            icmpv6.setIcmpCode((byte) 0);
            icmpv6.setPayload(ra);

            // IPv6 header filling.
            byte[] ip6AllNodesAddress = Ip6Address.valueOf("ff02::1").toOctets();
            IPv6 ipv6 = new IPv6();
            ipv6.setDestinationAddress((solicitHostAddress == null) ? ip6AllNodesAddress : solicitHostAddress);
            /* RA packet L2 source address created from port MAC address.
             * Note : As per RFC-4861 RAs should be sent from link-local address.
             */
            ipv6.setSourceAddress(IPv6.getLinkLocalAddress(macAddress.get().toBytes()));
            ipv6.setNextHeader(IPv6.PROTOCOL_ICMP6);
            ipv6.setHopLimit(RA_HOP_LIMIT);
            ipv6.setTrafficClass((byte) 0xe0);
            ipv6.setPayload(icmpv6);

            // Ethernet header filling.
            Ethernet ethernet = new Ethernet();

            /* Ethernet IPv6 multicast address creation.
             * Refer : RFC 2624 section 7.
             */
            byte[] l2Ipv6MulticastAddress = MacAddress.IPV6_MULTICAST.toBytes();
            IntStream.range(1, 4).forEach(i -> l2Ipv6MulticastAddress[l2Ipv6MulticastAddress.length - i] =
                    ip6AllNodesAddress[ip6AllNodesAddress.length - i]);
            // Provide unicast address for Solicit RA replays
            ethernet.setDestinationMACAddress((solicitHostMac == null) ?
                    MacAddress.valueOf(l2Ipv6MulticastAddress) : solicitHostMac);
            ethernet.setSourceMACAddress(macAddress.get().toBytes());
            ethernet.setEtherType(EthType.EtherType.IPV6.ethType().toShort());
            ethernet.setVlanID(Ethernet.VLAN_UNTAGGED);
            ethernet.setPayload(ipv6);
            ethernet.setPad(false);

            // Flush out PACKET_OUT.
            ByteBuffer stream = ByteBuffer.wrap(ethernet.serialize());
            TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
            OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
                    treatment, stream);
            packetService.emit(packet);
            log.trace("Transmitted Unsolicited Router Advertisement on {}", connectPoint);
        }
    }

    // Worker thread for processing IPv6 Solicited RA packets.
    public class SolicitedRAWorkerThread implements Runnable {

        private InboundPacket packet;

        SolicitedRAWorkerThread(InboundPacket packet) {
            this.packet = packet;
        }

        @Override
        public void run() {

            // TODO : Validate Router Solicitation

            // Pause already running unsolicited RA threads in received connect point
            ConnectPoint connectPoint = packet.receivedFrom();
            List<InterfaceIpAddress> addresses = deactivateRouterAdvertisement(connectPoint);

            /* Multicast RA(ie. Unsolicited RA) TX time is not preciously tracked so to make sure that
             * Unicast RA(ie. Router Solicitation Response) is TXed before Mulicast RA
             * logic adapted here is disable Mulicast RA, TX Unicast RA and then restore Multicast RA.
             */
            log.trace("Processing Router Solicitations from {}", connectPoint);
            try {
                Ethernet ethernet = packet.parsed();
                IPv6 ipv6 = (IPv6) ethernet.getPayload();
                RAWorkerThread worker = new RAWorkerThread(connectPoint,
                        addresses, raThreadDelay, ethernet.getSourceMAC(), ipv6.getSourceAddress());
                // TODO : Estimate TX time as in RFC 4861, Section 6.2.6 and schedule TX based on it
                CompletableFuture<Void> sraHandlerFuture = CompletableFuture.runAsync(worker, executors);
                sraHandlerFuture.get();
            } catch (Exception e) {
                log.error("Failed to respond to router solicitation. {}", e);
            } finally {
                activateRouterAdvertisement(connectPoint, addresses);
                log.trace("Restored Unsolicited Router Advertisements on {}", connectPoint);
            }
        }
    }

}
