/**
* Copyright 2011, Big Switch Networks, Inc.
* Originally created by David Erickson, Stanford University
*
* 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.util;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/***
* A static utility class to register flow cookiue AppIds and generating
* flow cookies for a particular App`
*
* An "app" is a module or piece of code that can install flows in a switch.
* E.g., Forwarding and StaticFlowPusher are apps. An App is identified by a
* 12 bit integer, the id. Furthermore, an App has a name. The id value must
* be unique but the same name can be registered for multiple numeric ids.
* TODO: should we enforce unique names
*
* This class is thread-safe.
*
* The 64 bit OpenFlow cookie field used in the following way
* <li> Bit 63 -- 52 (12 bit): the AppId
* <li> Bit 51 -- 32 (20 bit): currently unused. Set to 0.
* <li> Bit 31 -- 0 (32 bit): user data
*
* FIXME: The class should be a singleton. The registration method should
* return an instance of class. This instance should then be used to generate
* flow cookies. Ideally, we would also represent a flow cookie as a class
* instance.
*
*
* @author capveg
*
*/
public class AppCookie {
static final int APP_ID_BITS = 12;
static final long APP_ID_MASK = (1L << APP_ID_BITS) - 1;
static final int APP_ID_SHIFT = (64 - APP_ID_BITS);
static final long USER_MASK = 0x00000000FFFFFFFFL;
/**the following bit will be set accordingly if the field is rewritten by application. e.g. VRS or floating IP
* FIXME: these should not be in AppCookie and they shoul not use
* the reserved bit range*/
static final int SRC_MAC_REWRITE_BIT=33;
static final int DEST_MAC_REWRITE_BIT=34;
static final int SRC_IP_REWRITE_BIT=35;
static final int DEST_IP_REWRITE_BIT=36;
static final long REWRITE_MASK= 0x000f00000000L;
private static ConcurrentMap<Integer, String> appIdMap =
new ConcurrentHashMap<Integer, String>();
/**
* Encapsulate an application ID and a user block of stuff into a cookie
*
* @param application An ID to identify the application
* @param user Some application specific data
* @return a cookie for use in OFFlowMod.setCookie()
* @throws IllegalStateException if the application has not been registered
*/
static public long makeCookie(int application, int user) {
if (!appIdMap.containsKey(application)) {
throw new AppIDNotRegisteredException(application);
}
long longApp = application;
long longUser = user & USER_MASK; // mask to prevent sign extend
return (longApp << APP_ID_SHIFT) | longUser;
}
/**
* Extract the application id from a flow cookie. Does <em>not</em> check
* whether the application id is registered
* @param cookie
* @return
*/
static public int extractApp(long cookie) {
return (int)((cookie >>> APP_ID_SHIFT) & APP_ID_MASK);
}
static public int extractUser(long cookie) {
return (int)(cookie & USER_MASK);
}
static public boolean isRewriteFlagSet(long cookie) {
if ((cookie & REWRITE_MASK) !=0L)
return true;
return false;
}
static public boolean isSrcMacRewriteFlagSet(long cookie) {
if ((cookie & (1L << (SRC_MAC_REWRITE_BIT-1))) !=0L)
return true;
return false;
}
static public boolean isDestMacRewriteFlagSet(long cookie) {
if ((cookie & (1L << (DEST_MAC_REWRITE_BIT-1))) !=0L)
return true;
return false;
}
static public boolean isSrcIpRewriteFlagSet(long cookie) {
if ((cookie & (1L << (SRC_IP_REWRITE_BIT-1))) !=0L)
return true;
return false;
}
static public boolean isDestIpRewriteFlagSet(long cookie) {
if ((cookie & (1L << (DEST_IP_REWRITE_BIT-1))) !=0L)
return true;
return false;
}
static public long setSrcMacRewriteFlag(long cookie) {
return cookie | (1L << (SRC_MAC_REWRITE_BIT-1));
}
static public long setDestMacRewriteFlag(long cookie) {
return cookie | (1L << (DEST_MAC_REWRITE_BIT-1));
}
static public long setSrcIpRewriteFlag(long cookie) {
return cookie | (1L << (SRC_IP_REWRITE_BIT-1));
}
static public long setDestIpRewriteFlag(long cookie) {
return cookie | (1L << (DEST_IP_REWRITE_BIT-1));
}
/**
* A lame attempt to prevent duplicate application ID.
* TODO: Once bigdb is merged, we should expose appID->appName map
* via REST API so CLI doesn't need a separate copy of the map.
*
* @param application
* @param appName
* @throws AppIDInUseException
*/
public static void registerApp(int application, String appName)
throws AppIDException
{
if ((application & APP_ID_MASK) != application) {
throw new InvalidAppIDValueException(application);
}
String oldApp = appIdMap.putIfAbsent(application, appName);
if (oldApp != null && !oldApp.equals(appName)) {
throw new AppIDInUseException(application, oldApp, appName);
}
}
/**
* Retrieves the application name registered for the given application id
* or null if the application has not been registered
* @param application
* @return
*/
public static String getAppName(int application) {
return appIdMap.get(application);
}
}