/* * Copyright (c) 2013 Big Switch Networks, Inc. * * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html * * 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.sdnplatform.ovsdb.internal; import java.io.IOException; import java.net.ConnectException; import java.nio.channels.ClosedChannelException; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.exc.UnrecognizedPropertyException; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.openflow.util.HexString; import org.sdnplatform.ovsdb.IOVSDB; import org.sdnplatform.ovsdb.internal.JSONShowReplyMsg.ShowResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class JSONMsgHandler extends SimpleChannelUpstreamHandler { protected static Logger logger = LoggerFactory.getLogger(JSONMsgHandler.class); private IOVSDB tsw; private Object statusObject; private static final int SHOW_REPLY = 0; private static final int ADD_PORT_REPLY = 1; private static final int DEL_PORT_REPLY = 2; private static final int SET_DPID_REPLY = 3; private static final int SET_CIP_REPLY = 4; private static int MSG = -1; public JSONMsgHandler(IOVSDB tsw, Object statusObject) { this.tsw = tsw; this.statusObject = statusObject; } @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { JsonNode jn = (JsonNode)e.getMessage(); if (logger.isTraceEnabled()) logger.trace("receveid message: {}", e.toString()); if (jn.get("id") == null) return; if (jn.get("id").isNumber()) { if(logger.isDebugEnabled()) { logger.debug("got result for id: {}", jn.get("id").getValueAsInt()); } MSG = tsw.getExpectedMessage(jn.get("id").getValueAsInt()); switch (MSG) { case SHOW_REPLY: handleShowReply(jn); synchronized(statusObject) { statusObject.notify(); } break; case ADD_PORT_REPLY: handleAddPortReply(jn); synchronized(statusObject) { statusObject.notify(); } break; case DEL_PORT_REPLY: handleDelPortReply(jn); synchronized(statusObject) { statusObject.notify(); } break; case SET_DPID_REPLY: //noop break; case SET_CIP_REPLY: //noop break; //FIXME check for errors default : //noop logger.error("Unexpected Message Reply id {}", jn.get("id").getValueAsInt()); } } else { if (jn.get("method") == null) return; // handle JSON RPC notifications if (jn.get("id").getValueAsText().equals("null") && jn.get("method").getValueAsText().equals("update")) { // got an update message if (logger.isDebugEnabled()) logger.debug("GOT an UPDATE"); handleUpdateNotification(jn); synchronized(statusObject) { statusObject.notify(); } } else if (jn.get("id").getValueAsText().equals("echo") && jn.get("method").getValueAsText().equals("echo")) { // no op } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (e.getCause() instanceof IllegalStateException) { // hiding exception logging - expected because of the way we do // JSON message decoding // logger.debug("Illegal State exception ", // e.getCause().toString()); } else if (e.getCause() instanceof UnrecognizedPropertyException) { logger.error("Jackson unrecognized property error {}", e.getCause()); } else if (e.getCause() instanceof JsonMappingException) { logger.error("Jackson mapping error {}", e.getCause()); } else if (e.getCause() instanceof JsonParseException) { logger.error("Jackson parsing error {}", e.getCause()); } else if (e.getCause() instanceof ClosedChannelException) { logger.error("Netty closed channel error", e.getCause()); } else if (e.getCause() instanceof ConnectException) { logger.error("Connection refused", e.getCause()); } else if (e.getCause() instanceof IOException) { logger.error("IO problem", e.getCause()); } else { super.exceptionCaught(ctx, e); } } private void handleAddPortReply(JsonNode jn) throws Exception { ObjectMapper mapper = new ObjectMapper(); JSONAddPortReplyMsg rep = mapper.treeToValue(jn, JSONAddPortReplyMsg.class); //just check for errors String returned = rep.getResult().toString(); if (returned.contains("error")) { logger.error("ovsdb-server at sw {} returned error {}", HexString.toHexString(tsw.getDpid()), returned.substring(returned.indexOf("error"))); } } private void handleDelPortReply(JsonNode jn) throws Exception { ObjectMapper mapper = new ObjectMapper(); JSONDelPortReplyMsg rep = mapper.treeToValue(jn, JSONDelPortReplyMsg.class); //just check for errors String returned = rep.getResult().toString(); if (returned.contains("error")) { logger.error("ovsdb-server at sw {} returned error {}", HexString.toHexString(tsw.getDpid()), returned.substring(returned.indexOf("error"))); } } private void handleUpdateNotification(JsonNode jn) throws Exception { ObjectMapper mapper = new ObjectMapper(); JSONUpdateMsg rep = mapper.treeToValue(jn, JSONUpdateMsg.class); ShowResult res = rep.getParams().get(1); tsw.updateTunnelSwitchFromUpdate(res); //debugUpdateOrShow(res); } private void handleShowReply(JsonNode jn) throws Exception { ObjectMapper mapper = new ObjectMapper(); JSONShowReplyMsg rep = mapper.treeToValue(jn, JSONShowReplyMsg.class); tsw.updateTunnelSwitchFromShow(rep); //debugUpdateOrShow(rep.getResult()); } public void debugUpdateOrShow(ShowResult sr) { if (logger.isDebugEnabled()) { if (sr.getOpen_vSwitch() != null) { logger.debug("DB UPDATE: " + sr.getOpen_vSwitch().toString()); } if (sr.getController() != null) { logger.debug("CNTL UPDATE: " + sr.getController().toString()); } if (sr.getInterface() != null) { logger.debug("INTF UPDATE: " + sr.getInterface().toString()); } if (sr.getPort() != null) { logger.debug("PORT UPDATE: " + sr.getPort().toString()); } if (sr.getBridge() != null) { logger.debug("BRIDGE UPDATE: " + sr.getBridge().toString()); } } } }