/* * 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.util.ArrayList; import java.util.Iterator; import java.util.Random; import java.util.Map.Entry; import org.jboss.netty.buffer.ChannelBuffer; import org.openflow.util.HexString; /** * JSONAddPortMsg builds the JSON RPC message to request the addition * of a port * * @author Saurav Das * */ public class JSONAddPortMsg extends JSONMsg { private String localIPAddr; private String remoteIPAddr; private String name; private String completeString; private OVSDBImpl tsw; private int id; private String dbuuid = ""; private boolean capwap; /** * Constructor * @param name name of tunnel-port to add * @param remoteIPAddr IP addr of remote tunnel-endpoint * @param tsw the tunnel-switch on which to add port * @param messageId message-id for this RPC message * @param capwap true indicates creation of CAPWAP tunneling port */ public JSONAddPortMsg(String name, String localIPAddr, String remoteIPAddr, OVSDBImpl tsw, int messageId, boolean capwap) throws OVSDBBridgeUnknown { this.localIPAddr = localIPAddr; this.remoteIPAddr = remoteIPAddr; if (this.remoteIPAddr == null) this.remoteIPAddr = ""; this.name = name; this.tsw = tsw; this.id = messageId; this.capwap = capwap; buildAddPortMsg(); } private void buildAddPortMsg() throws OVSDBBridgeUnknown { //first build the header completeString = "{\"method\":\"transact\",\"id\":"+id+",\"params\":["+ " \"Open_vSwitch\", "; completeString += rowsUntil() + inserts() + mutations(); if (capwap) { completeString += comment(); } else { completeString += commentNonCapwap(); } } private String rowsUntil() { String rows = ""; //first the interfaces String start = "{\"rows\":[{\"interfaces\":[\"uuid\",\""; String mid = "\"]}],\"until\":\"==\",\"where\":[[\"_uuid\",\"==\"" + ",[\"uuid\",\""; String end = "\"]]],\"timeout\":0,\"op\":\"wait\",\"table\":\"Port\"" + ",\"columns\":[\"interfaces\"]},"; Iterator<Entry<String, OVSPort>> iter = tsw.port.entrySet().iterator(); while(iter.hasNext()) { Entry<String, OVSPort> e = iter.next(); String portuuid = e.getKey(); String intfuuid = e.getValue().getNew().getInterfaces().get(1); rows += start + intfuuid + mid + portuuid + end; } // then the bridges -- assumes there is a single db called Open_vSwitch int numbridges = getNumBridges(); if (numbridges > 1) { start = "{\"rows\":[{\"bridges\":[\"set\",[[\"uuid\",\""; String mid2 = "\"],[\"uuid\",\""; String mid3 = "\"]]]}],\"until\":\"==\",\"where\":[[\"_uuid\"," + "\"==\",[\"uuid\",\""; end = "\"]]],\"timeout\":0,\"op\":\"wait\",\"table\":\"Open_" + "vSwitch\"" + ",\"columns\":[\"bridges\"]},"; Iterator<Entry<String, OVSDatabase>> iter1 = tsw.open_vswitch.entrySet().iterator(); rows += start; Iterator<String> iter2 = tsw.bridge.keySet().iterator(); while (iter2.hasNext()) { String bridgeuuid = iter2.next(); rows += bridgeuuid; if (iter2.hasNext()) rows += mid2; else rows += mid3; } while (iter1.hasNext()) { Entry<String, OVSDatabase> e1 = iter1.next(); dbuuid = e1.getKey(); break; // only one database } rows += dbuuid + end; } else { start = "{\"rows\":[{\"bridges\":[\"uuid\",\""; end = "\"]]],\"timeout\":0,\"op\":\"wait\",\"table\":\"Open_" + "vSwitch\"" + ",\"columns\":[\"bridges\"]},"; Iterator<Entry<String, OVSDatabase>> iter1 = tsw.open_vswitch.entrySet().iterator(); while(iter1.hasNext()) { Entry<String, OVSDatabase> e1 = iter1.next(); dbuuid = e1.getKey(); String bridgeuuid = (String) e1.getValue().getNew() .getBridges().get(1); rows += start + bridgeuuid + mid + dbuuid + end; break; // just one database } } //finally the ports per bridge - a separate entry per bridge Iterator<Entry<String, OVSBridge>> iter5 = tsw.bridge.entrySet() .iterator(); while (iter5.hasNext()) { Entry<String, OVSBridge> e = iter5.next(); OVSBridge br = e.getValue(); String bridgeuuid = e.getKey(); start = "{\"rows\":[{\"ports\":[\"set\",["; rows += start; String porthdr = "[\"uuid\",\""; String porttlr = "\"]"; ArrayList<String> brportuuids = br.getNew().getPortUuids(); for (int i=0; i< brportuuids.size(); i++) { rows += porthdr + brportuuids.get(i) + porttlr; if (i+1 < brportuuids.size()) rows += ","; } end = "\"]]],\"timeout\":0,\"op\":\"wait\",\"table\":\"Bridge\"" + ",\"columns\":[\"ports\"]},"; rows += "]" + mid.substring(1) + bridgeuuid + end; } return rows; } private int getNumBridges() { // only a single database per ovs is expected for( OVSDatabase odb : tsw.open_vswitch.values()) { ArrayList<Object> brs = odb.getNew().getBridges(); return brs.size(); } return 0; } private String inserts() throws OVSDBBridgeUnknown { String start = "{\"uuid-name\":\""; Random rint = new Random(tsw.getDpid()); String fakeport = "row" + String.format("%8x", rint.nextInt()) + "_" + String.format("%4x", (short)rint.nextInt()) + "_" + String.format("%4x", (short)rint.nextInt()) + "_" + String.format("%4x", (short)rint.nextInt()) + "_" + String.format("%8x", rint.nextInt()) + String.format("%4x", (short)rint.nextInt()); String mid = "\",\"op\":\"insert\",\"table\":\"Port\",\"row\":" + "{\"interfaces\":[\"named-uuid\",\""; String fakeinterface = "row" + String.format("%8x", rint.nextInt()) + "_" + String.format("%4x", (short)rint.nextInt()) + "_" + String.format("%4x", (short)rint.nextInt()) + "_" + String.format("%4x", (short)rint.nextInt()) + "_" + String.format("%8x", rint.nextInt()) + String.format("%4x", (short)rint.nextInt()); String end = "\"],\"name\":\""+name+"\"}},"; fakeport = fakeport.replace(' ', 'd'); fakeinterface = fakeinterface.replace(' ', 'd'); String portinsert = start + fakeport + mid + fakeinterface + end; String bridgeuuid = getBridgeuuid(); String start1 = "{\"where\":[[\"_uuid\",\"==\",[\"uuid\",\"" + bridgeuuid + "\"]]],\"op\":\"update\",\"table\":\"Bridge\"," + "\"row\":{\"ports\":[\"set\",[[\"named-uuid\",\"" + fakeport + "\"],"; String ports = ""; String porthdr = "[\"uuid\",\""; String porttlr = "\"]"; OVSBridge br = tsw.bridge.get(bridgeuuid); if ( br == null ) { throw new RuntimeException("tsw.bridge.get("+ bridgeuuid + ")" + " returned Null"); } ArrayList<String> pl = br.getNew().getPortUuids(); //for this bridge for (int i=0; i< pl.size(); i++) { ports += porthdr + pl.get(i) + porttlr; if (i+1 < pl.size()) ports += ","; } String bridgeupdate = start1 + ports + "]]}},"; String intfinsert = "{\"uuid-name\":\"" + fakeinterface + "\",\"op\":" + "\"insert\",\"table\":\"Interface\",\"row\":{\"name\":\"" + name + "\",\"type\":\"gre\",\"options\":[\"map\"," + "[[\"remote_ip\",\"" + remoteIPAddr + "\"],[\"local_ip\",\"" + localIPAddr + "\"]]]}},"; String intfinsertNonCapwap = "{\"uuid-name\":\"" + fakeinterface + "\",\"op\":" + "\"insert\",\"table\":\"Interface\",\"row\":{\"name\":\"" + name + "\"}},"; if (capwap) { return portinsert + bridgeupdate + intfinsert; } else { return portinsert + bridgeupdate + intfinsertNonCapwap; } } private String getBridgeuuid() throws OVSDBBridgeUnknown { long dpid = tsw.getDpid(); Iterator<Entry<String, OVSBridge>> iter = tsw.bridge.entrySet(). iterator(); while (iter.hasNext()) { Entry<String, OVSBridge> e = iter.next(); String bruuid = e.getKey(); OVSBridge br = e.getValue(); if (br.getNew().getReportedDpid() == dpid) { return bruuid; } } throw new OVSDBBridgeUnknown(tsw.getDpid()); } private String mutations() { return "{\"mutations\":[[\"next_cfg\",\"+=\",1]]," + "\"where\":[[\"_uuid\",\"==\",[\"uuid\",\"" + dbuuid + "\"]]]," + "\"op\":\"mutate\",\"table\":\"Open_vSwitch\"}," + "{\"where\":[[\"_uuid\",\"==\",[\"uuid\",\"" + dbuuid + "\"]]]," + "\"op\":\"select\",\"table\":\"Open_vSwitch\"," + "\"columns\":[\"next_cfg\"]},"; } private String comment() { return "{\"comment\":\"ovs-vsctl: ./ovs-vsctl --db=tcp:" + tsw.getMgmtIPAddr() + ":6635 add-port tunnelswitch " + name +" -- set " + "interface "+ name + " type=capwap options:remote_ip=" + remoteIPAddr + "\",\"op\":\"comment\"}]}"; } private String commentNonCapwap() { return "{\"comment\":\"ovs-vsctl: ./ovs-vsctl --db=tcp:" + tsw.getMgmtIPAddr() + ":6635 add-port tunnelswitch " + name + "\",\"op\":\"comment\"}]}"; } @Override public void writeTo(ChannelBuffer buf) { if (log.isTraceEnabled()) { log.trace("sent add-port message to:" + name + " msg-id:"+ id + " @sw: {} ", HexString.toHexString(tsw.getDpid())); } buf.writeBytes(completeString.getBytes()); } @Override public int getLengthU() { return completeString.length(); } }