package org.opennaas.extensions.openflowswitch.driver.floodlight.protocol.client.serializers.json; /* * #%L * OpenNaaS :: OpenFlow Switch :: Floodlight driver v0.90 * %% * Copyright (C) 2007 - 2014 FundaciĆ³ Privada i2CAT, Internet i InnovaciĆ³ a Catalunya * %% * 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. * #L% */ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.JsonProcessingException; import org.codehaus.jackson.JsonToken; import org.codehaus.jackson.map.DeserializationContext; import org.codehaus.jackson.map.JsonDeserializer; import org.opennaas.extensions.openflowswitch.driver.floodlight.offorwarding.actionssets.FloodlightConstants; import org.opennaas.extensions.openflowswitch.driver.floodlight.protocol.client.wrappers.FloodlightOFFlowsWrapper; import org.opennaas.extensions.openflowswitch.model.FloodlightOFAction; import org.opennaas.extensions.openflowswitch.model.FloodlightOFFlow; import org.opennaas.extensions.openflowswitch.model.FloodlightOFMatch; public class FloodlightOFFlowsWrapperJSONDeserializer extends JsonDeserializer<FloodlightOFFlowsWrapper> { private Log log = LogFactory.getLog(FloodlightOFFlowsWrapperJSONDeserializer.class); @Override public FloodlightOFFlowsWrapper deserialize(JsonParser jp, DeserializationContext ctx) throws IOException, JsonProcessingException { // initialize object wrapper FloodlightOFFlowsWrapper wrapper = new FloodlightOFFlowsWrapper(); // switch IDs loop while ((jp.nextToken()) != JsonToken.END_OBJECT) { if ((jp.getCurrentToken()) != JsonToken.FIELD_NAME) { throw new IOException("Expected FIELD_NAME and it was " + jp.getCurrentToken()); } // get switch ID String switchId = jp.getCurrentName(); // expect switch start object JsonToken token = jp.nextToken(); if (token == JsonToken.VALUE_NULL) { // no object inside, stop deserializing break; } else if (token != JsonToken.START_OBJECT) { throw new IOException("Expected START_OBJECT and it was " + jp.getCurrentToken()); } // flow IDs loop while ((jp.nextToken()) != JsonToken.END_OBJECT) { if ((jp.getCurrentToken()) != JsonToken.FIELD_NAME) { throw new IOException("Expected FIELD_NAME and it was " + jp.getCurrentToken()); } // get flow name and go to next token String flowName = jp.getCurrentName(); jp.nextToken(); // initialize the new flow FloodlightOFFlow flow = new FloodlightOFFlow(); flow.setName(flowName); flow.setSwitchId(switchId); FloodlightOFMatch match = new FloodlightOFMatch(); List<FloodlightOFAction> actions = new ArrayList<FloodlightOFAction>(0); if (jp.getCurrentToken() != JsonToken.START_OBJECT) { throw new IOException("Expected START_OBJECT and it was " + jp.getCurrentToken()); } // flow fields loop while ((jp.nextToken()) != JsonToken.END_OBJECT) { if ((jp.getCurrentToken()) != JsonToken.FIELD_NAME) { throw new IOException("Expected FIELD_NAME and it was " + jp.getCurrentToken()); } // get token name and go to the next token String nodeName = jp.getCurrentName(); jp.nextToken(); if (jp.getText().equals("")) continue; if (nodeName == "actions") { actions = parseActions(jp); } else if (nodeName == "priority") flow.setPriority(jp.getText()); else if (nodeName == "match") { match = parseMatch(jp); } } // set flows and match flow.setMatch(match); flow.setActions(actions); // set active true, it is never sent by Floodlight, if the flow is returned it is active flow.setActive(true); convertFloodlightDefaultsToNull(flow); // add flow wrapper.add(flow); } } return wrapper; } private List<FloodlightOFAction> parseActions(JsonParser jp) throws JsonParseException, IOException { // initialize action list List<FloodlightOFAction> actions = new ArrayList<FloodlightOFAction>(); // expect start array if (jp.getCurrentToken() != JsonToken.START_ARRAY) { throw new IOException("Expected START_ARRAY and it was " + jp.getCurrentToken()); } // action array loop while (jp.nextToken() != JsonToken.END_ARRAY) { // expect action start object if (jp.getCurrentToken() != JsonToken.START_OBJECT) { throw new IOException("Expected START_OBJECT and it was " + jp.getCurrentToken()); } Map<String, String> actionMap = new HashMap<String, String>(); // action fields loop while (jp.nextToken() != JsonToken.END_OBJECT) { if (jp.getCurrentToken() != JsonToken.FIELD_NAME) { throw new IOException("Expected FIELD_NAME and it was " + jp.getCurrentToken()); } // get field name and go to next token String fieldName = jp.getCurrentName(); jp.nextToken(); actionMap.put(fieldName.toLowerCase(), jp.getText()); } // fill action list following some rules, by now only OUTPUT actions are parsed if (actionMap.get("type").equalsIgnoreCase(FloodlightOFAction.TYPE_OUTPUT.toLowerCase())) { // fill action FloodlightOFAction action = new FloodlightOFAction(); // set type and value action.setType(FloodlightOFAction.TYPE_OUTPUT.toLowerCase()); action.setValue(actionMap.get("port")); actions.add(action); } else { // no more types known log.info("Property type unknown: " + actionMap.get("type")); } } return actions; } private FloodlightOFMatch parseMatch(JsonParser jp) throws JsonParseException, IOException { // initialize match FloodlightOFMatch match = new FloodlightOFMatch(); // match fields loop while ((jp.nextToken()) != JsonToken.END_OBJECT) { if ((jp.getCurrentToken()) != JsonToken.FIELD_NAME) { throw new IOException("Expected FIELD_NAME and it was " + jp.getCurrentToken()); } // get field name and go to next token String fieldName = jp.getCurrentName(); jp.nextToken(); if (fieldName == "wildcards") match.setWildcards(jp.getText()); else if (fieldName == "inputPort") match.setIngressPort(jp.getText()); else if (fieldName == "dataLayerSource") match.setSrcMac(jp.getText()); else if (fieldName == "dataLayerDestination") match.setDstMac(jp.getText()); else if (fieldName == "dataLayerVirtualLan") match.setVlanId(jp.getText()); else if (fieldName == "dataLayerVirtualLanPriorityCodePoint") match.setVlanPriority(jp.getText()); else if (fieldName == "dataLayerType") match.setEtherType(jp.getText()); else if (fieldName == "networkTypeOfService") match.setTosBits(jp.getText()); else if (fieldName == "networkProtocol") match.setProtocol(jp.getText()); else if (fieldName == "networkSource") match.setSrcIp(jp.getText()); else if (fieldName == "networkDestination") match.setDstIp(jp.getText()); else if (fieldName == "transportSource") match.setSrcPort(jp.getText()); else if (fieldName == "transportDestination") match.setDstPort(jp.getText()); } return match; } private static void convertFloodlightDefaultsToNull(FloodlightOFFlow flow) { if (flow.getMatch() != null) { if (flow.getMatch().getWildcards() != null && flow.getMatch().getWildcards().equals(FloodlightConstants.DEFAULT_MATCH_WILDCARDS)) { flow.getMatch().setWildcards(null); } if (flow.getMatch().getIngressPort() != null && flow.getMatch().getIngressPort().equals(FloodlightConstants.DEFAULT_MATCH_INGRESS_PORT)) { flow.getMatch().setIngressPort(null); } if (flow.getMatch().getSrcMac() != null && flow.getMatch().getSrcMac().equals(FloodlightConstants.DEFAULT_MATCH_SRC_MAC)) { flow.getMatch().setSrcMac(null); } if (flow.getMatch().getDstMac() != null && flow.getMatch().getDstMac().equals(FloodlightConstants.DEFAULT_MATCH_DST_MAC)) { flow.getMatch().setDstMac(null); } if (flow.getMatch().getVlanId() != null && flow.getMatch().getVlanId().equals(FloodlightConstants.DEFAULT_MATCH_VLAN_ID)) { flow.getMatch().setVlanId(null); } if (flow.getMatch().getVlanPriority() != null && flow.getMatch().getVlanPriority() .equals(FloodlightConstants.DEFAULT_MATCH_VLAN_PRIORITY)) { flow.getMatch().setVlanPriority(null); } if (flow.getMatch().getEtherType() != null && flow.getMatch().getEtherType().equals(FloodlightConstants.DEFAULT_MATCH_ETHER_TYPE)) { flow.getMatch().setEtherType(null); } if (flow.getMatch().getTosBits() != null && flow.getMatch().getTosBits().equals(FloodlightConstants.DEFAULT_MATCH_TOS_BITS)) { flow.getMatch().setTosBits(null); } if (flow.getMatch().getProtocol() != null && flow.getMatch().getProtocol().equals(FloodlightConstants.DEFAULT_MATCH_PROTOCOL)) { flow.getMatch().setProtocol(null); } if (flow.getMatch().getSrcIp() != null && flow.getMatch().getSrcIp().equals(FloodlightConstants.DEFAULT_MATCH_SRC_IP)) { flow.getMatch().setSrcIp(null); } if (flow.getMatch().getDstIp() != null && flow.getMatch().getDstIp().equals(FloodlightConstants.DEFAULT_MATCH_DST_IP)) { flow.getMatch().setDstIp(null); } if (flow.getMatch().getSrcPort() != null && flow.getMatch().getSrcPort().equals(FloodlightConstants.DEFAULT_MATCH_SRC_PORT)) { flow.getMatch().setSrcPort(null); } if (flow.getMatch().getDstPort() != null && flow.getMatch().getDstPort().equals(FloodlightConstants.DEFAULT_MATCH_DST_PORT)) { flow.getMatch().setDstPort(null); } } } }