net.floodlightcontroller.core.web.SwitchRoleResource.java Source code

Java tutorial

Introduction

Here is the source code for net.floodlightcontroller.core.web.SwitchRoleResource.java

Source

/**
 *    Copyright 2013, Big Switch Networks, Inc.
 *
 *    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 net.floodlightcontroller.core.web;

import java.io.IOException;
import java.lang.Thread.State;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.projectfloodlight.openflow.protocol.OFControllerRole;
import org.projectfloodlight.openflow.protocol.OFFactories;
import org.projectfloodlight.openflow.protocol.OFNiciraControllerRole;
import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleReply;
import org.projectfloodlight.openflow.protocol.OFRoleReply;
import org.projectfloodlight.openflow.protocol.OFVersion;
import org.projectfloodlight.openflow.types.DatapathId;
import org.projectfloodlight.openflow.types.U64;
import org.restlet.resource.Post;
import org.restlet.resource.ServerResource;

import net.floodlightcontroller.core.IOFSwitch;
import net.floodlightcontroller.core.internal.IOFSwitchService;

import org.restlet.resource.Get;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.MappingJsonFactory;
import com.google.common.util.concurrent.ListenableFuture;

public class SwitchRoleResource extends ServerResource {

    protected static Logger log = LoggerFactory.getLogger(SwitchRoleResource.class);

    private static final String STR_ROLE_PREFIX = "ROLE_"; /* enum OFControllerRole is ROLE_XXX, so trim the ROLE_ when printing */
    private static final String STR_ROLE_MASTER = "MASTER"; /* these are all assumed uppercase within this class */
    private static final String STR_ROLE_SLAVE = "SLAVE";
    private static final String STR_ROLE_EQUAL = "EQUAL";
    private static final String STR_ROLE_OTHER = "OTHER";

    @Get("json")
    public Map<String, String> getRole() {
        IOFSwitchService switchService = (IOFSwitchService) getContext().getAttributes()
                .get(IOFSwitchService.class.getCanonicalName());

        String switchId = (String) getRequestAttributes().get(CoreWebRoutable.STR_SWITCH_ID);
        HashMap<String, String> model = new HashMap<String, String>();

        if (switchId.equalsIgnoreCase(CoreWebRoutable.STR_ALL)) {
            for (IOFSwitch sw : switchService.getAllSwitchMap().values()) {
                switchId = sw.getId().toString();
                model.put(switchId, sw.getControllerRole().toString().replaceFirst(STR_ROLE_PREFIX, ""));
            }
            return model;
        } else {
            try {
                DatapathId dpid = DatapathId.of(switchId);
                IOFSwitch sw = switchService.getSwitch(dpid);
                if (sw == null) {
                    model.put("ERROR", "Switch Manager could not locate switch DPID " + dpid.toString());
                    return model;
                } else {
                    model.put(dpid.toString(), sw.getControllerRole().toString().replaceFirst(STR_ROLE_PREFIX, ""));
                    return model;
                }
            } catch (Exception e) {
                model.put("ERROR", "Could not parse switch DPID " + switchId);
                return model;
            }
        }
    }

    /* for some reason @Post("json") isn't working here... */
    @Post
    public Map<String, String> setRole(String json) {
        IOFSwitchService switchService = (IOFSwitchService) getContext().getAttributes()
                .get(IOFSwitchService.class.getCanonicalName());
        Map<String, String> retValue = new HashMap<String, String>();

        String switchId = (String) getRequestAttributes().get(CoreWebRoutable.STR_SWITCH_ID);

        MappingJsonFactory f = new MappingJsonFactory();
        JsonParser jp = null;
        String role = null;

        try {
            try {
                jp = f.createParser(json);
            } catch (IOException e) {
                e.printStackTrace();
            }

            jp.nextToken();
            if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
                throw new IOException("Expected START_OBJECT");
            }

            while (jp.nextToken() != JsonToken.END_OBJECT) {
                if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
                    throw new IOException("Expected FIELD_NAME");
                }

                String n = jp.getCurrentName().toLowerCase();
                jp.nextToken();

                switch (n) {
                case CoreWebRoutable.STR_ROLE:
                    role = jp.getText();

                    if (switchId.equalsIgnoreCase(CoreWebRoutable.STR_ALL)) {
                        for (IOFSwitch sw : switchService.getAllSwitchMap().values()) {
                            List<SetConcurrentRoleThread> activeThreads = new ArrayList<SetConcurrentRoleThread>(
                                    switchService.getAllSwitchMap().size());
                            List<SetConcurrentRoleThread> pendingRemovalThreads = new ArrayList<SetConcurrentRoleThread>();
                            SetConcurrentRoleThread t;
                            t = new SetConcurrentRoleThread(sw, parseRole(role));
                            activeThreads.add(t);
                            t.start();

                            // Join all the threads after the timeout. Set a hard timeout
                            // of 12 seconds for the threads to finish. If the thread has not
                            // finished the switch has not replied yet and therefore we won't
                            // add the switch's stats to the reply.
                            for (int iSleepCycles = 0; iSleepCycles < 12; iSleepCycles++) {
                                for (SetConcurrentRoleThread curThread : activeThreads) {
                                    if (curThread.getState() == State.TERMINATED) {
                                        retValue.put(curThread.getSwitch().getId().toString(),
                                                (curThread.getRoleReply() == null
                                                        ? "Error communicating with switch. Role not changed."
                                                        : curThread.getRoleReply().getRole().toString()
                                                                .replaceFirst(STR_ROLE_PREFIX, "")));
                                        pendingRemovalThreads.add(curThread);
                                    }
                                }

                                // remove the threads that have completed the queries to the switches
                                for (SetConcurrentRoleThread curThread : pendingRemovalThreads) {
                                    activeThreads.remove(curThread);
                                }
                                // clear the list so we don't try to double remove them
                                pendingRemovalThreads.clear();

                                // if we are done finish early so we don't always get the worst case
                                if (activeThreads.isEmpty()) {
                                    break;
                                }

                                // sleep for 1 s here
                                try {
                                    Thread.sleep(1000);
                                } catch (InterruptedException e) {
                                    log.error("Interrupted while waiting for role replies", e);
                                    retValue.put("ERROR",
                                            "Thread sleep interrupted while waiting for role replies.");
                                }

                            }
                        }
                    } else {
                        /* Must be a specific switch DPID then. */
                        try {
                            DatapathId dpid = DatapathId.of(switchId);
                            IOFSwitch sw = switchService.getSwitch(dpid);
                            if (sw == null) {
                                retValue.put("ERROR",
                                        "Switch Manager could not locate switch DPID " + dpid.toString());
                            } else {
                                OFRoleReply reply = setSwitchRole(sw, parseRole(role));
                                retValue.put(sw.getId().toString(),
                                        (reply == null ? "Error communicating with switch. Role not changed."
                                                : reply.getRole().toString().replaceFirst(STR_ROLE_PREFIX, "")));
                            }
                        } catch (Exception e) {
                            retValue.put("ERROR", "Could not parse switch DPID " + switchId);
                        }
                    }
                    break;
                default:
                    retValue.put("ERROR", "Unrecognized JSON key.");
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            retValue.put("ERROR", "Caught IOException while parsing JSON POST request in role request.");
        }
        return retValue;
    }

    protected class SetConcurrentRoleThread extends Thread {
        private OFRoleReply switchReply;
        private OFControllerRole role;
        private IOFSwitch sw;

        public SetConcurrentRoleThread(IOFSwitch sw, OFControllerRole role) {
            this.sw = sw;
            this.switchReply = null;
            this.role = role;
        }

        public OFRoleReply getRoleReply() {
            return switchReply;
        }

        public IOFSwitch getSwitch() {
            return sw;
        }

        public OFControllerRole getRole() {
            return role;
        }

        @Override
        public void run() {
            switchReply = setSwitchRole(sw, role);
        }
    }

    private static OFRoleReply setSwitchRole(IOFSwitch sw, OFControllerRole role) {
        try {
            if (sw.getOFFactory().getVersion().compareTo(OFVersion.OF_12) < 0) {
                OFNiciraControllerRole nrole;
                switch (role) {
                case ROLE_EQUAL:
                    nrole = OFNiciraControllerRole.ROLE_OTHER;
                    log.warn("Assuming EQUAL as OTHER for Nicira role request.");
                    break;
                case ROLE_MASTER:
                    nrole = OFNiciraControllerRole.ROLE_MASTER;
                    break;
                case ROLE_SLAVE:
                    nrole = OFNiciraControllerRole.ROLE_SLAVE;
                    break;
                case ROLE_NOCHANGE:
                    log.error("Nicira extension does not support NOCHANGE role. Thus, we won't change the role.");
                    return OFFactories.getFactory(OFVersion.OF_13).buildRoleReply().setRole(sw.getControllerRole())
                            .setGenerationId(U64.ZERO).build();
                default:
                    log.error("Impossible to have anything other than MASTER, OTHER, or SLAVE for Nicira role.");
                    return OFFactories.getFactory(OFVersion.OF_13).buildRoleReply().setRole(sw.getControllerRole())
                            .setGenerationId(U64.ZERO).build();
                }

                ListenableFuture<OFNiciraControllerRoleReply> future = sw
                        .writeRequest(sw.getOFFactory().buildNiciraControllerRoleRequest().setRole(nrole).build());
                OFNiciraControllerRoleReply nreply = future.get(10, TimeUnit.SECONDS);
                if (nreply != null) {
                    /* Turn the OFControllerRoleReply into a OFNiciraControllerRoleReply */
                    switch (nreply.getRole()) {
                    case ROLE_MASTER:
                        return OFFactories.getFactory(OFVersion.OF_13).buildRoleReply()
                                .setRole(OFControllerRole.ROLE_MASTER).setGenerationId(U64.ZERO).build();
                    case ROLE_OTHER:
                        return OFFactories.getFactory(OFVersion.OF_13).buildRoleReply()
                                .setRole(OFControllerRole.ROLE_EQUAL).setGenerationId(U64.ZERO).build();
                    case ROLE_SLAVE:
                        return OFFactories.getFactory(OFVersion.OF_13).buildRoleReply()
                                .setRole(OFControllerRole.ROLE_SLAVE).setGenerationId(U64.ZERO).build();
                    default:
                        log.error(
                                "Impossible to have anything other than MASTER, OTHER, or SLAVE for Nicira role: {}.",
                                nreply.getRole().toString());
                        break;
                    }
                } else {
                    log.error("Did not receive Nicira role reply for switch {}.", sw.getId().toString());
                }
            } else {
                ListenableFuture<OFRoleReply> future = sw.writeRequest(
                        sw.getOFFactory().buildRoleRequest().setGenerationId(U64.ZERO).setRole(role).build());
                return future.get(10, TimeUnit.SECONDS);
            }
        } catch (Exception e) {
            log.error("Failure setting switch {} role to {}.", sw.toString(), role.toString());
            log.error(e.getMessage());
        }
        return null;
    }

    private static OFControllerRole parseRole(String role) {
        if (role == null || role.isEmpty()) {
            return OFControllerRole.ROLE_NOCHANGE;
        }

        role = role.toUpperCase();

        if (role.contains(STR_ROLE_MASTER)) {
            return OFControllerRole.ROLE_MASTER;
        } else if (role.contains(STR_ROLE_SLAVE)) {
            return OFControllerRole.ROLE_SLAVE;
        } else if (role.contains(STR_ROLE_EQUAL) || role.contains(STR_ROLE_OTHER)) {
            return OFControllerRole.ROLE_EQUAL;
        } else {
            return OFControllerRole.ROLE_NOCHANGE;
        }
    }
}