diff --git a/api/src/com/cloud/network/ovs/OvsDestroyBridgeCommand.java b/api/src/com/cloud/network/ovs/OvsDestroyBridgeCommand.java
new file mode 100644
index 00000000000..11f762bafa8
--- /dev/null
+++ b/api/src/com/cloud/network/ovs/OvsDestroyBridgeCommand.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) 2012 Cloud.com, Inc. All rights reserved.
+ *
+ * This software is licensed under the GNU General Public License v3 or later.
+ *
+ * It is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+package com.cloud.network.ovs;
+
+import com.cloud.agent.api.Command;
+
+public class OvsDestroyBridgeCommand extends Command {
+
+ long networkId;
+
+ public OvsDestroyBridgeCommand(long networkId) {
+ this.networkId = networkId;
+ }
+
+ public long getNetworkId() {
+ return networkId;
+ }
+
+ @Override
+ public boolean executeInSequence() {
+ return true;
+ }
+
+}
diff --git a/scripts/vm/hypervisor/xenserver/cloudstack_pluginlib.py b/scripts/vm/hypervisor/xenserver/cloudstack_pluginlib.py
new file mode 100644
index 00000000000..552e522c98a
--- /dev/null
+++ b/scripts/vm/hypervisor/xenserver/cloudstack_pluginlib.py
@@ -0,0 +1,198 @@
+# Common function for Cloudstack's XenAPI plugins
+#
+# Copyright (C) 2012 Citrix Systems
+
+import ConfigParser
+import logging
+import os
+import subprocess
+
+from time import localtime, asctime
+
+DEFAULT_LOG_FORMAT = "%(asctime)s %(levelname)8s [%(name)s] %(message)s"
+DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
+DEFAULT_LOG_FILE = "/var/log/cloudstack_plugins.log"
+
+PLUGIN_CONFIG_PATH='/etc/xensource/cloudstack_plugins.conf'
+OVSDB_PID_PATH = "/var/run/openvswitch/ovsdb-server.pid"
+OVSDB_DAEMON_PATH = "ovsdb-server"
+OVS_PID_PATH = "/var/run/openvswitch/ovs-vswitchd.pid"
+OVS_DAEMON_PATH = "ovs-vswitchd"
+VSCTL_PATH='/usr/bin/ovs-vsctl'
+OFCTL_PATH='/usr/bin/ovs-ofctl'
+XE_PATH= "/opt/xensource/bin/xe"
+
+class PluginError(Exception):
+ """Base Exception class for all plugin errors."""
+ def __init__(self, *args):
+ Exception.__init__(self, *args)
+
+def setup_logging(log_file=None):
+ debug = False
+ verbose = False
+ log_format = DEFAULT_LOG_FORMAT
+ log_date_format = DEFAULT_LOG_DATE_FORMAT
+ # try to read plugin configuration file
+ if os.path.exists(PLUGIN_CONFIG_PATH):
+ config = ConfigParser.ConfigParser()
+ config.read(PLUGIN_CONFIG_PATH)
+ try:
+ options = config.options('LOGGING')
+ if 'debug' in options:
+ debug = config.getboolean('LOGGING','debug')
+ if 'verbose' in options:
+ verbose = config.getboolean('LOGGING','verbose')
+ if 'format' in options:
+ log_format = config.get('LOGGING','format')
+ if 'date_format' in options:
+ log_date_format = config.get('LOGGING','date_format')
+ if 'file' in options:
+ log_file_2 = config.get('LOGGING','file')
+ except ValueError:
+ # configuration file contained invalid attributes
+ # ignore them
+ pass
+ except ConfigParser.NoSectionError:
+ # Missing 'Logging' section in configuration file
+ pass
+
+ root_logger = logging.root
+ if debug:
+ root_logger.setLevel(logging.DEBUG)
+ elif verbose:
+ root_logger.setLevel(logging.INFO)
+ else:
+ root_logger.setLevel(logging.WARNING)
+ formatter = logging.Formatter(log_format, log_date_format)
+
+ log_filename = log_file or log_file_2 or DEFAULT_LOG_FILE
+
+ logfile_handler = logging.FileHandler(log_filename)
+ logfile_handler.setFormatter(formatter)
+ root_logger.addHandler(logfile_handler)
+
+
+def do_cmd(cmd):
+ """Abstracts out the basics of issuing system commands. If the command
+ returns anything in stderr, a PluginError is raised with that information.
+ Otherwise, the output from stdout is returned.
+ """
+
+ pipe = subprocess.PIPE
+ logging.debug("Executing:%s", cmd)
+ proc = subprocess.Popen(cmd, shell=False, stdin=pipe, stdout=pipe,
+ stderr=pipe, close_fds=True)
+ ret_code = proc.wait()
+ err = proc.stderr.read()
+ if ret_code:
+ logging.debug("The command exited with the error code: " +
+ "%s (stderr output:%s)" % (ret_code, err))
+ raise PluginError(err)
+ output = proc.stdout.read()
+ if output.endswith('\n'):
+ output = output[:-1]
+ return output
+
+
+def _is_process_run (pidFile, name):
+ try:
+ fpid = open (pidFile, "r")
+ pid = fpid.readline ()
+ fpid.close ()
+ except IOError, e:
+ return -1
+
+ pid = pid[:-1]
+ ps = os.popen ("ps -ae")
+ for l in ps:
+ if pid in l and name in l:
+ ps.close ()
+ return 0
+
+ ps.close ()
+ return -2
+
+def _is_tool_exist (name):
+ if os.path.exists(name):
+ return 0
+ return -1
+
+
+def check_switch ():
+ global result
+
+ ret = _is_process_run (OVSDB_PID_PATH, OVSDB_DAEMON_PATH)
+ if ret < 0:
+ if ret == -1: return "NO_DB_PID_FILE"
+ if ret == -2: return "DB_NOT_RUN"
+
+ ret = _is_process_run (OVS_PID_PATH, OVS_DAEMON_PATH)
+ if ret < 0:
+ if ret == -1: return "NO_SWITCH_PID_FILE"
+ if ret == -2: return "SWITCH_NOT_RUN"
+
+ if _is_tool_exist (VSCTL_PATH) < 0:
+ return "NO_VSCTL"
+
+ if _is_tool_exist (OFCTL_PATH) < 0:
+ return "NO_OFCTL"
+
+ return "SUCCESS"
+
+
+def _build_flow_expr(**kwargs):
+ is_delete_expr = kwargs.get('delete', False)
+ flow = ""
+ if not is_delete_expr:
+ flow = "hard_timeout=%s,idle_timeout=%s,priority=%s"\
+ % (kwargs.get('hard_timeout','0'),
+ kwargs.get('idle_timeout','0'),
+ kwargs.get('priority','1'))
+ in_port = 'in_port' in kwargs and ",in_port=%s" % kwargs['in_port'] or ''
+ dl_type = 'dl_type' in kwargs and ",dl_type=%s" % kwargs['dl_type'] or ''
+ dl_src = 'dl_src' in kwargs and ",dl_src=%s" % kwargs['dl_src'] or ''
+ dl_dst = 'dl_dst' in kwargs and ",dl_dst=%s" % kwargs['dl_dst'] or ''
+ nw_src = 'nw_src' in kwargs and ",nw_src=%s" % kwargs['nw_src'] or ''
+ nw_dst = 'nw_dst' in kwargs and ",nw_dst=%s" % kwargs['nw_dst'] or ''
+ proto = 'proto' in kwargs and ",%s" % kwargs['proto'] or ''
+ ip = ('nw_src' in kwargs or 'nw_dst' in kwargs) and ',ip' or ''
+ flow = (flow + in_port + dl_type + dl_src + dl_dst +
+ (ip or proto) + nw_src + nw_dst)
+ return flow
+
+
+def add_flow(bridge, **kwargs):
+ """
+ Builds a flow expression for **kwargs and adds the flow entry
+ to an Open vSwitch instance
+ """
+ flow = _build_flow_expr(**kwargs)
+ actions = 'actions' in kwargs and ",actions=%s" % kwargs['actions'] or ''
+ flow = flow + actions
+ addflow = [OFCTL_PATH, "add-flow", bridge, flow]
+ do_cmd(addflow)
+
+
+def del_flows(bridge, **kwargs):
+ """
+ Removes flows according to criteria passed as keyword.
+ """
+ flow = _build_flow_expr(delete=True, **kwargs)
+ # out_port condition does not exist for all flow commands
+ out_port = 'out_port' in kwargs and ",out_port=%s" % kwargs['out_port'] or ''
+ flow = flow + out_port
+ delFlow = [OFCTL_PATH, 'del-flows', bridge, flow]
+ do_cmd(delFlow)
+
+
+def del_all_flows(bridge):
+ delFlow = [OFCTL_PATH, "del-flows", bridge]
+ do_cmd(delFlow)
+
+ normalFlow = "priority=0 idle_timeout=0 hard_timeout=0 actions=normal"
+ add_flow(bridge, normalFlow)
+
+
+def del_port(bridge, port):
+ delPort = [VSCTL_PATH, "del-port", bridge, port]
+ do_cmd(delPort)
diff --git a/scripts/vm/hypervisor/xenserver/cloudstack_plugins.conf b/scripts/vm/hypervisor/xenserver/cloudstack_plugins.conf
new file mode 100644
index 00000000000..fb078dd188b
--- /dev/null
+++ b/scripts/vm/hypervisor/xenserver/cloudstack_plugins.conf
@@ -0,0 +1,4 @@
+[LOGGING]
+# Logging options for Cloudstack plugins
+debug = True
+verbose = True
diff --git a/scripts/vm/hypervisor/xenserver/xen-ovs-vif-flows.rules b/scripts/vm/hypervisor/xenserver/xen-ovs-vif-flows.rules
new file mode 100644
index 00000000000..85c930f18a2
--- /dev/null
+++ b/scripts/vm/hypervisor/xenserver/xen-ovs-vif-flows.rules
@@ -0,0 +1,2 @@
+# Adds or removes per-VIF flows
+SUBSYSTEM=="xen-backend", KERNEL=="vif*", RUN+="/usr/bin/python /etc/xapi.d/plugins/ovs-vif-flows.py $env{ACTION} %k"
\ No newline at end of file
diff --git a/scripts/vm/hypervisor/xenserver/xenserver56fp1/ovs-vif-flows.py b/scripts/vm/hypervisor/xenserver/xenserver56fp1/ovs-vif-flows.py
new file mode 100644
index 00000000000..937c892224c
--- /dev/null
+++ b/scripts/vm/hypervisor/xenserver/xenserver56fp1/ovs-vif-flows.py
@@ -0,0 +1,98 @@
+# A simple script for enabling and disabling per-vif rules for explicitly
+# allowing broadcast/multicast traffic on the port where the VIF is attached
+#
+# Copyright (C) 2012 Citrix Systems
+
+import os
+import sys
+
+import cloudstack_pluginlib as pluginlib
+
+
+def clear_flows(bridge, this_vif_ofport, vif_ofports):
+ # Remove flow entries originating from given ofport
+ pluginlib.del_flows(bridge, in_port=this_vif_ofport)
+ # The following will remove the port being delete from actions
+ pluginlib.add_flow(bridge, priority=1100,
+ dl_dst='ff:ff:ff:ff:ff:ff', actions=action)
+ pluginlib.add_flow(bridge, priority=1100,
+ nw_dst='224.0.0.0/24', actions=action)
+
+
+def apply_flows(bridge, this_vif_ofport, vif_ofports):
+ action = "".join("output:%s," %ofport
+ for ofport in vif_ofports)[:-1]
+ # Ensure {b|m}casts sent from VIF ports are always allowed
+ pluginlib.add_flow(bridge, priority=1200,
+ in_port=this_vif_ofport,
+ dl_dst='ff:ff:ff:ff:ff:ff',
+ actions='NORMAL')
+ pluginlib.add_flow(bridge, priority=1200,
+ in_port=this_vif_ofport,
+ nw_dst='224.0.0.0/24',
+ actions='NORMAL')
+ # Ensure {b|m}casts are always propagated to VIF ports
+ pluginlib.add_flow(bridge, priority=1100,
+ dl_dst='ff:ff:ff:ff:ff:ff', actions=action)
+ pluginlib.add_flow(bridge, priority=1100,
+ nw_dst='224.0.0.0/24', actions=action)
+
+
+def main(command, vif_raw):
+ if command not in ('online', 'offline'):
+ return
+ # TODO (very important)
+ # Quit immediately if networking is NOT being managed by the OVS tunnel manager
+ vif_name, dom_id, vif_index = vif_raw.split('-')
+ # validate vif and dom-id
+ this_vif = "%s%s.%s" % (vif_name, dom_id, vif_index)
+
+ bridge = pluginlib.do_cmd([pluginlib.VSCTL_PATH, 'iface-to-br', this_vif])
+
+ # find xs network for this bridge, verify is used for ovs tunnel network
+ xs_nw_uuid = pluginlib.do_cmd([pluginlib.XE_PATH, "network-list",
+ "bridge=%s" % bridge, "--minimal"])
+ result = pluginlib.do_cmd([pluginlib.XE_PATH,"network-param-get",
+ "uuid=%s" % xs_nw_uuid,
+ "param-name=other-config",
+ "param-key=is-ovs-tun-network", "--minimal"])
+
+ if result != 'True':
+ return
+
+ vlan = pluginlib.do_cmd([pluginlib.VSCTL_PATH, 'br-to-vlan', bridge])
+ if vlan != '0':
+ # We need the REAL bridge name
+ bridge = pluginlib.do_cmd([pluginlib.VSCTL_PATH,
+ 'br-to-parent', bridge])
+ # For the OVS version shipped with XS56FP1 we need to retrieve
+ # the ofport number for all interfaces
+ vsctl_output = pluginlib.do_cmd([pluginlib.VSCTL_PATH,
+ 'list-ports', bridge])
+ vifs = vsctl_output.split('\n')
+ vif_ofports = []
+ for vif in vifs:
+ vif_ofport = pluginlib.do_cmd([pluginlib.VSCTL_PATH, 'get',
+ 'Interface', vif, 'ofport'])
+ if this_vif == vif:
+ this_vif_ofport = vif_ofport
+ vif_ofports.append(vif_ofport)
+ # So regardless of whether the VIF is brought online or offline we
+ # will always execute the same action
+ if command == 'offline':
+ clear_flows(bridge, this_vif_ofport, vif_ofports)
+
+ if command == 'online':
+ apply_flows(bridge, this_vif_ofport, vif_ofports)
+
+
+
+
+if __name__ == "__main__":
+ if len(sys.argv) != 3:
+ print "usage: %s [online|offline] vif-domid-idx" % \
+ os.path.basename(sys.argv[0])
+ sys.exit(1)
+ else:
+ command, vif_raw = sys.argv[1:3]
+ main(command, vif_raw)
\ No newline at end of file
diff --git a/scripts/vm/hypervisor/xenserver/xenserver60/ovs-vif-flows.py b/scripts/vm/hypervisor/xenserver/xenserver60/ovs-vif-flows.py
new file mode 100644
index 00000000000..1e2ab230f17
--- /dev/null
+++ b/scripts/vm/hypervisor/xenserver/xenserver60/ovs-vif-flows.py
@@ -0,0 +1,79 @@
+# A simple script for enabling and disabling per-vif rules for explicitly
+# allowing broadcast/multicast traffic on the port where the VIF is attached
+#
+# Copyright (C) 2012 Citrix Systems
+
+import os
+import sys
+
+import cloudstack_pluginlib as pluginlib
+
+
+def clear_flows(bridge, vif_ofport):
+ # Remove flow entries originating from given ofport
+ pluginlib.del_flows(bridge, in_port=vif_ofport)
+ # Leverage out_port option for removing flows based on actions
+ pluginlib.del_flows(bridge, out_port=vif_ofport)
+
+
+def apply_flows(bridge, vif_ofport):
+ action = "output:%s," % vif_ofport
+ # Ensure {b|m}casts sent from VIF ports are always allowed
+ pluginlib.add_flow(bridge, priority=1200,
+ in_port=vif_ofport,
+ dl_dst='ff:ff:ff:ff:ff:ff',
+ actions='NORMAL')
+ pluginlib.add_flow(bridge, priority=1200,
+ in_port=vif_ofport,
+ nw_dst='224.0.0.0/24',
+ actions='NORMAL')
+ # Ensure {b|m}casts are always propagated to VIF ports
+ pluginlib.add_flow(bridge, priority=1100,
+ dl_dst='ff:ff:ff:ff:ff:ff', actions=action)
+ pluginlib.add_flow(bridge, priority=1100,
+ nw_dst='224.0.0.0/24', actions=action)
+
+
+def main(command, vif_raw):
+ if command not in ('online', 'offline'):
+ return
+ # TODO (very important)
+ # Quit immediately if networking is NOT being managed by the OVS tunnel manager
+ vif_name, dom_id, vif_index = vif_raw.split('-')
+ # validate vif and dom-id
+ vif = "%s%s.%s" % (vif_name, dom_id, vif_index)
+
+ bridge = pluginlib.do_cmd([pluginlib.VSCTL_PATH, 'iface-to-br', vif])
+ # find xs network for this bridge, verify is used for ovs tunnel network
+ xs_nw_uuid = pluginlib.do_cmd([pluginlib.XE_PATH, "network-list",
+ "bridge=%s" % bridge, "--minimal"])
+ result = pluginlib.do_cmd([pluginlib.XE_PATH,"network-param-get",
+ "uuid=%s" % xs_nw_uuid,
+ "param-name=other-config",
+ "param-key=is-ovs-tun-network", "--minimal"])
+
+ if result != 'True':
+ return
+
+ vlan = pluginlib.do_cmd([pluginlib.VSCTL_PATH, 'br-to-vlan', bridge])
+ if vlan != '0':
+ # We need the REAL bridge name
+ bridge = pluginlib.do_cmd([pluginlib.VSCTL_PATH, 'br-to-parent', bridge])
+ vif_ofport = pluginlib.do_cmd([pluginlib.VSCTL_PATH, 'get', 'Interface',
+ vif, 'ofport'])
+
+ if command == 'offline':
+ clear_flows(bridge, vif_ofport)
+
+ if command == 'online':
+ apply_flows(bridge, vif_ofport)
+
+
+if __name__ == "__main__":
+ if len(sys.argv) != 3:
+ print "usage: %s [online|offline] vif-domid-idx" % \
+ os.path.basename(sys.argv[0])
+ sys.exit(1)
+ else:
+ command, vif_raw = sys.argv[1:3]
+ main(command, vif_raw)
\ No newline at end of file
diff --git a/server/src/com/cloud/network/ovs/dao/OvsTunnelNetworkDao.java b/server/src/com/cloud/network/ovs/dao/OvsTunnelNetworkDao.java
new file mode 100644
index 00000000000..4b0b61c865d
--- /dev/null
+++ b/server/src/com/cloud/network/ovs/dao/OvsTunnelNetworkDao.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
+ *
+ * This software is licensed under the GNU General Public License v3 or later.
+ *
+ * It is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package com.cloud.network.ovs.dao;
+
+import java.util.List;
+
+import com.cloud.utils.db.GenericDao;
+
+public interface OvsTunnelNetworkDao extends
+ GenericDao {
+ OvsTunnelNetworkVO getByFromToNetwork(long from, long to, long networkId);
+ void removeByFromNetwork(long from, long networkId);
+ void removeByFromToNetwork(long from, long to, long networkId);
+ List listByToNetwork(long to, long networkId);
+}
diff --git a/server/src/com/cloud/network/ovs/dao/OvsTunnelNetworkDaoImpl.java b/server/src/com/cloud/network/ovs/dao/OvsTunnelNetworkDaoImpl.java
new file mode 100644
index 00000000000..3b979de1919
--- /dev/null
+++ b/server/src/com/cloud/network/ovs/dao/OvsTunnelNetworkDaoImpl.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
+ *
+ * This software is licensed under the GNU General Public License v3 or later.
+ *
+ * It is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package com.cloud.network.ovs.dao;
+
+import java.util.List;
+
+import javax.ejb.Local;
+
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.SearchCriteria.Op;
+
+@Local(value = { OvsTunnelNetworkDao.class })
+public class OvsTunnelNetworkDaoImpl extends
+ GenericDaoBase implements OvsTunnelNetworkDao {
+
+ protected final SearchBuilder fromToNetworkSearch;
+ protected final SearchBuilder fromNetworkSearch;
+ protected final SearchBuilder toNetworkSearch;
+
+ public OvsTunnelNetworkDaoImpl() {
+ fromToNetworkSearch = createSearchBuilder();
+ fromToNetworkSearch.and("from", fromToNetworkSearch.entity().getFrom(), Op.EQ);
+ fromToNetworkSearch.and("to", fromToNetworkSearch.entity().getTo(), Op.EQ);
+ fromToNetworkSearch.and("network_id", fromToNetworkSearch.entity().getNetworkId(), Op.EQ);
+ fromToNetworkSearch.done();
+
+ fromNetworkSearch = createSearchBuilder();
+ fromNetworkSearch.and("from", fromNetworkSearch.entity().getFrom(), Op.EQ);
+ fromNetworkSearch.and("network_id", fromNetworkSearch.entity().getNetworkId(), Op.EQ);
+ fromNetworkSearch.done();
+
+ toNetworkSearch = createSearchBuilder();
+ toNetworkSearch.and("to", toNetworkSearch.entity().getTo(), Op.EQ);
+ toNetworkSearch.and("network_id", toNetworkSearch.entity().getNetworkId(), Op.EQ);
+ toNetworkSearch.done();
+ }
+
+ @Override
+ public OvsTunnelNetworkVO getByFromToNetwork(long from, long to,
+ long networkId) {
+ SearchCriteria sc = fromToNetworkSearch.create();
+ sc.setParameters("from", from);
+ sc.setParameters("to", to);
+ sc.setParameters("network_id", networkId);
+ return findOneBy(sc);
+ }
+
+ @Override
+ public void removeByFromNetwork(long from, long networkId) {
+ SearchCriteria sc = fromNetworkSearch.create();
+ sc.setParameters("from", from);
+ sc.setParameters("network_id", networkId);
+ remove(sc);
+ }
+
+ @Override
+ public List listByToNetwork(long to, long networkId) {
+ SearchCriteria sc = toNetworkSearch.create();
+ sc.setParameters("to", to);
+ sc.setParameters("network_id", networkId);
+ return listBy(sc);
+ }
+
+ @Override
+ public void removeByFromToNetwork(long from, long to, long networkId) {
+ SearchCriteria sc = fromToNetworkSearch.create();
+ sc.setParameters("from", from);
+ sc.setParameters("to", to);
+ sc.setParameters("network_id", networkId);
+ remove(sc);
+ }
+
+}
diff --git a/server/src/com/cloud/network/ovs/dao/OvsTunnelNetworkVO.java b/server/src/com/cloud/network/ovs/dao/OvsTunnelNetworkVO.java
new file mode 100644
index 00000000000..ad793c8ec42
--- /dev/null
+++ b/server/src/com/cloud/network/ovs/dao/OvsTunnelNetworkVO.java
@@ -0,0 +1,106 @@
+/**
+ * Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
+ *
+ * This software is licensed under the GNU General Public License v3 or later.
+ *
+ * It is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package com.cloud.network.ovs.dao;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name=("ovs_tunnel_network"))
+public class OvsTunnelNetworkVO {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private long id;
+
+ @Column(name = "from")
+ private long from;
+
+ @Column(name = "to")
+ private long to;
+
+ @Column(name = "key")
+ private int key;
+
+ @Column(name = "network_id")
+ private long networkId;
+
+ @Column(name = "port_name")
+ private String portName;
+
+ @Column(name = "state")
+ private String state;
+
+ public OvsTunnelNetworkVO() {
+
+ }
+
+ public OvsTunnelNetworkVO(long from, long to, int key, long networkId) {
+ this.from = from;
+ this.to = to;
+ this.key = key;
+ this.networkId = networkId;
+ this.portName = "[]";
+ this.state = "FAILED";
+ }
+
+ public void setKey(int key) {
+ this.key = key;
+ }
+
+ public long getFrom() {
+ return from;
+ }
+
+ public long getTo() {
+ return to;
+ }
+
+ public int getKey() {
+ return key;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public long getNetworkId() {
+ return networkId;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public void setState(String state) {
+ this.state = state;
+ }
+
+ public void setPortName(String name) {
+ this.portName = name;
+ }
+
+ public String getPortName() {
+ return portName;
+ }
+}