package org.opennaas.extensions.openflowswitch.driver.ryu.protocol.client.serializers.json;
/*
* #%L
* OpenNaaS :: OpenFlow Switch :: Ryu driver v3.14
* %%
* 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.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.ryu.offorwarding.actionssets.RyuConstants;
import org.opennaas.extensions.openflowswitch.driver.ryu.protocol.client.model.RyuOFFlow;
import org.opennaas.extensions.openflowswitch.driver.ryu.protocol.client.wrappers.RyuOFFlowListWrapper;
import org.opennaas.extensions.openflowswitch.model.FloodlightOFAction;
import org.opennaas.extensions.openflowswitch.model.FloodlightOFMatch;
/**
* {@link RyuOFFlowListWrapper} {@link JSONDeserializer}
*
* @author Julio Carlos Barrera
*
*/
public class RyuOFFlowListWrapperJSONDeserializer extends JsonDeserializer<RyuOFFlowListWrapper> {
@Override
public RyuOFFlowListWrapper deserialize(JsonParser jp, DeserializationContext ctx) throws IOException, JsonProcessingException {
// initialize object wrapper
RyuOFFlowListWrapper wrapper = new RyuOFFlowListWrapper();
// dpids 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 dpid = jp.getCurrentName();
// expect switch start object
if (jp.nextToken() == JsonToken.VALUE_NULL) {
// no object inside, stop deserializing
break;
}
else if (jp.getCurrentToken() != JsonToken.START_ARRAY) {
throw new IOException("Expected START_ARRAY and it was " + jp.getCurrentToken());
}
// array loop
while ((jp.nextToken()) != JsonToken.END_ARRAY) {
if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
throw new IOException("Expected START_OBJECT and it was " + jp.getCurrentToken());
}
RyuOFFlow flow = new RyuOFFlow();
FloodlightOFMatch match = new FloodlightOFMatch();
List<FloodlightOFAction> actions = new ArrayList<FloodlightOFAction>(0);
flow.setDpid(dpid);
// flow loop
while (jp.nextToken() != JsonToken.END_OBJECT) {
if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
throw new IOException("Expected FIELD_NAME");
}
String n = jp.getCurrentName();
jp.nextToken();
if (jp.getText().equals("")) {
continue;
}
else if (n.equals("actions"))
actions = parseActions(jp);
else if (n.equals("priority"))
flow.setPriority(jp.getText());
else if (n.equals("buffer_id"))
flow.setBufferId(jp.getText());
else if (n.equals("cookie"))
flow.setCookie(jp.getText());
else if (n.equals("cookie_mask"))
flow.setCookieMask(jp.getText());
else if (n.equals("flags"))
flow.setFlags(jp.getText());
else if (n.equals("hard_timeout"))
flow.setHardTimeout(jp.getText());
else if (n.equals("idle_timeout"))
flow.setIdleTimeout(jp.getText());
else if (n.equals("table_id"))
flow.setTableId(jp.getText());
else if (n.equals("match")) {
match = parseMatch(jp);
}
}
flow.setMatch(match);
flow.setActions(actions);
convertRyuDefaultsToNull(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
Map<String, String> actionMap = new HashMap<String, String>();
while (jp.nextToken() != JsonToken.END_ARRAY) {
String actionstr = jp.getText();
if (actionstr != null) {
actionstr = actionstr.toLowerCase();
for (String subaction : actionstr.split(",")) {
String[] split = subaction.split("[=:]");
String type = split[0];
String value;
if (split.length > 1) {
value = split[1];
} else {
value = null;
}
actionMap.put(type.toLowerCase(), value);
}
}
}
// fill action list following some rules, by now only OUTPUT actions are parsed
if (actionMap.containsKey(FloodlightOFAction.TYPE_OUTPUT.toLowerCase())) {
// fill action
FloodlightOFAction action = new FloodlightOFAction();
// set type and value
action.setType(FloodlightOFAction.TYPE_OUTPUT.toLowerCase());
action.setValue(actionMap.get(FloodlightOFAction.TYPE_OUTPUT.toLowerCase()));
actions.add(action);
} else {
// no more known types
}
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.equals("wildcards"))
match.setWildcards(jp.getText());
else if (fieldName.equals("in_port"))
match.setIngressPort(jp.getText());
else if (fieldName.equals("dl_src"))
match.setSrcMac(jp.getText());
else if (fieldName.equals("dl_dst"))
match.setDstMac(jp.getText());
else if (fieldName.equals("dl_vlan"))
match.setVlanId(jp.getText());
else if (fieldName.equals("dl_vlan_pcp"))
match.setVlanPriority(jp.getText());
else if (fieldName.equals("dl_type"))
match.setEtherType(jp.getText());
else if (fieldName.equals("ip_dscp"))
match.setTosBits(jp.getText());
else if (fieldName.equals("nw_proto"))
match.setProtocol(jp.getText());
else if (fieldName.equals("nw_src"))
match.setSrcIp(jp.getText());
else if (fieldName.equals("nw_dst"))
match.setDstIp(jp.getText());
else if (fieldName.equals("tp_src"))
match.setSrcPort(jp.getText());
else if (fieldName.equals("tp_dst"))
match.setDstPort(jp.getText());
}
return match;
}
private static void convertRyuDefaultsToNull(RyuOFFlow flow) {
// fields
if (flow.getCookie() != null && flow.getCookie().equals(RyuConstants.DEFAULT_COOKIE)) {
flow.setCookie(null);
}
if (flow.getIdleTimeout() != null && flow.getIdleTimeout().equals(RyuConstants.DEFAULT_IDLE_TIMEOUT)) {
flow.setIdleTimeout(null);
}
if (flow.getHardTimeout() != null && flow.getHardTimeout().equals(RyuConstants.DEFAULT_HARD_TIMEOUT)) {
flow.setHardTimeout(null);
}
if (flow.getTableId() != null && flow.getTableId().equals(RyuConstants.DEFAULT_TABLE_ID)) {
flow.setTableId(null);
}
// match fields
if (flow.getMatch() != null) {
if (flow.getMatch().getWildcards() != null && flow.getMatch().getWildcards().equals(RyuConstants.DEFAULT_MATCH_WILDCARDS)) {
flow.getMatch().setWildcards(null);
}
if (flow.getMatch().getIngressPort() != null && flow.getMatch().getIngressPort().equals(RyuConstants.DEFAULT_MATCH_INGRESS_PORT)) {
flow.getMatch().setIngressPort(null);
}
if (flow.getMatch().getSrcMac() != null && flow.getMatch().getSrcMac().equals(RyuConstants.DEFAULT_MATCH_SRC_MAC)) {
flow.getMatch().setSrcMac(null);
}
if (flow.getMatch().getDstMac() != null && flow.getMatch().getDstMac().equals(RyuConstants.DEFAULT_MATCH_DST_MAC)) {
flow.getMatch().setDstMac(null);
}
if (flow.getMatch().getVlanId() != null && flow.getMatch().getVlanId().equals(RyuConstants.DEFAULT_MATCH_VLAN_ID)) {
flow.getMatch().setVlanId(null);
}
if (flow.getMatch().getVlanPriority() != null && flow.getMatch().getVlanPriority().equals(RyuConstants.DEFAULT_MATCH_VLAN_PRIORITY)) {
flow.getMatch().setVlanPriority(null);
}
if (flow.getMatch().getEtherType() != null && flow.getMatch().getEtherType().equals(RyuConstants.DEFAULT_MATCH_ETHER_TYPE)) {
flow.getMatch().setEtherType(null);
}
if (flow.getMatch().getProtocol() != null && flow.getMatch().getProtocol().equals(RyuConstants.DEFAULT_MATCH_PROTOCOL)) {
flow.getMatch().setProtocol(null);
}
if (flow.getMatch().getSrcIp() != null && flow.getMatch().getSrcIp().equals(RyuConstants.DEFAULT_MATCH_SRC_IP)) {
flow.getMatch().setSrcIp(null);
}
if (flow.getMatch().getDstIp() != null && flow.getMatch().getDstIp().equals(RyuConstants.DEFAULT_MATCH_DST_IP)) {
flow.getMatch().setDstIp(null);
}
if (flow.getMatch().getSrcPort() != null && flow.getMatch().getSrcPort().equals(RyuConstants.DEFAULT_MATCH_SRC_PORT)) {
flow.getMatch().setSrcPort(null);
}
if (flow.getMatch().getDstPort() != null && flow.getMatch().getDstPort().equals(RyuConstants.DEFAULT_MATCH_DST_PORT)) {
flow.getMatch().setDstPort(null);
}
}
}
}