diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 65d5a0e49c3..808570de493 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -5306,8 +5306,10 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe try { Network nw = findOrCreateTunnelNetwork(conn, cmd.getBridgeName()); String bridgeName = nw.getBridge(conn); + long sequenceNo = cmd.getSequenceNumber(); String result = callHostPlugin(conn, "ovstunnel", "configure_ovs_bridge_for_network_topology", "bridge", - bridgeName, "config", cmd.getVpcConfigInJson(), "host-id", ((Long)cmd.getHostId()).toString()); + bridgeName, "config", cmd.getVpcConfigInJson(), "host-id", ((Long)cmd.getHostId()).toString(), + "seq-no", Long.toString(sequenceNo)); if (result.startsWith("SUCCESS")) { return new Answer(cmd, true, result); } else { @@ -5324,10 +5326,11 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe try { Network nw = findOrCreateTunnelNetwork(conn, cmd.getBridgeName()); String bridgeName = nw.getBridge(conn); + long sequenceNo = cmd.getSequenceNumber(); String result = callHostPlugin(conn, "ovstunnel", "configure_ovs_bridge_for_routing_policies", "bridge", bridgeName, "host-id", ((Long)cmd.getHostId()).toString(), "config", - cmd.getVpcConfigInJson()); + cmd.getVpcConfigInJson(), "seq-no", Long.toString(sequenceNo)); if (result.startsWith("SUCCESS")) { return new Answer(cmd, true, result); } else { diff --git a/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml b/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml index fa56d5d1e63..086ffd61348 100644 --- a/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml +++ b/plugins/network-elements/ovs/resources/META-INF/cloudstack/ovs/spring-ovs-context.xml @@ -39,4 +39,5 @@ - + + diff --git a/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsVpcPhysicalTopologyConfigCommand.java b/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsVpcPhysicalTopologyConfigCommand.java index 17299d3f842..403dff400ad 100644 --- a/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsVpcPhysicalTopologyConfigCommand.java +++ b/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsVpcPhysicalTopologyConfigCommand.java @@ -32,6 +32,9 @@ public class OvsVpcPhysicalTopologyConfigCommand extends Command { long hostId; String bridgeName; + long sequenceNumber; + String schemaVersion; + public static class Host { long hostId; String ipAddress; @@ -127,4 +130,13 @@ public class OvsVpcPhysicalTopologyConfigCommand extends Command { public void setBridgeName(String bridgeName) { this.bridgeName = bridgeName; } + + public long getSequenceNumber() { + return sequenceNumber; + } + + public void setSequenceNumber(long sequenceNumber) { + this.sequenceNumber = sequenceNumber; + } + } \ No newline at end of file diff --git a/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsVpcRoutingPolicyConfigCommand.java b/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsVpcRoutingPolicyConfigCommand.java index 50f1fdd98a3..d9514d5a9a1 100644 --- a/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsVpcRoutingPolicyConfigCommand.java +++ b/plugins/network-elements/ovs/src/com/cloud/agent/api/OvsVpcRoutingPolicyConfigCommand.java @@ -27,6 +27,8 @@ public class OvsVpcRoutingPolicyConfigCommand extends Command { VpcConfig vpcConfig =null; long hostId; String bridgeName; + long sequenceNumber; + String schemaVersion; public static class AclItem { int number; @@ -120,4 +122,12 @@ public class OvsVpcRoutingPolicyConfigCommand extends Command { public boolean executeInSequence() { return false; } + + public long getSequenceNumber() { + return sequenceNumber; + } + + public void setSequenceNumber(long sequenceNumber) { + this.sequenceNumber = sequenceNumber; + } } \ No newline at end of file diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java index a86106eb27b..c755d72d009 100644 --- a/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java +++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/OvsTunnelManagerImpl.java @@ -78,9 +78,14 @@ import com.cloud.network.ovs.dao.OvsTunnelInterfaceVO; import com.cloud.network.ovs.dao.OvsTunnelNetworkDao; import com.cloud.network.ovs.dao.OvsTunnelNetworkVO; import com.cloud.network.ovs.dao.OvsTunnel; +import com.cloud.network.ovs.dao.VpcDistributedRouterSeqNoDao; +import com.cloud.network.ovs.dao.VpcDistributedRouterSeqNoVO; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; +import com.cloud.utils.db.TransactionStatus; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; import com.cloud.utils.fsm.StateListener; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.dao.DomainRouterDao; @@ -128,6 +133,8 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage NetworkACLDao _networkACLDao; @Inject NetworkACLItemDao _networkACLItemDao; + @Inject + VpcDistributedRouterSeqNoDao _vpcDrSeqNoDao; @Override public boolean configure(String name, Map params) @@ -683,7 +690,7 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage return true; } - public void handleVmStateChange(VMInstanceVO vm) { + private void handleVmStateChange(VMInstanceVO vm) { // get the VPC's impacted with the VM start List vpcIds = _ovsNetworkToplogyGuru.getVpcIdsVmIsPartOf(vm.getId()); @@ -693,6 +700,7 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage for (Long vpcId: vpcIds) { VpcVO vpc = _vpcDao.findById(vpcId); + // nothing to do if the VPC is not setup for distributed routing if (vpc == null || !vpc.usesDistributedRouter()) { return; } @@ -702,6 +710,9 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage String bridgeName=generateBridgeNameForVpc(vpcId); OvsVpcPhysicalTopologyConfigCommand topologyConfigCommand = prepareVpcTopologyUpdate(vpcId); + topologyConfigCommand.setSequenceNumber(getNextSequenceNumber(vpcId)); + + // send topology change update to VPC spanned hosts for (Long id: vpcSpannedHostIds) { if (!sendVpcTopologyChangeUpdate(topologyConfigCommand, id, bridgeName)) { s_logger.debug("Failed to send VPC topology change update to host : " + id + ". Moving on " + @@ -809,6 +820,10 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage if (network.getVpcId() != null && isVpcEnabledForDistributedRouter(network.getVpcId())) { long vpcId = network.getVpcId(); OvsVpcRoutingPolicyConfigCommand cmd = prepareVpcRoutingPolicyUpdate(vpcId); + cmd.setSequenceNumber(getNextSequenceNumber(vpcId)); + + // get the list of hosts on which VPC spans (i.e hosts that need to be aware of VPC + // network ACL update) List vpcSpannedHostIds = _ovsNetworkToplogyGuru.getVpcSpannedHosts(vpcId); for (Long id: vpcSpannedHostIds) { if (!sendVpcRoutingPolicyChangeUpdate(cmd, id, bridgeName)) { @@ -867,7 +882,7 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage return cmd; } - public boolean sendVpcRoutingPolicyChangeUpdate(OvsVpcRoutingPolicyConfigCommand updateCmd, long hostId, String bridgeName) { + private boolean sendVpcRoutingPolicyChangeUpdate(OvsVpcRoutingPolicyConfigCommand updateCmd, long hostId, String bridgeName) { try { s_logger.debug("Sending VPC routing policies change update to the host " + hostId); updateCmd.setHostId(hostId); @@ -885,4 +900,26 @@ public class OvsTunnelManagerImpl extends ManagerBase implements OvsTunnelManage return false; } } + + private long getNextSequenceNumber(final long vpcId) { + + try { + return Transaction.execute(new TransactionCallback() { + @Override + public Long doInTransaction(TransactionStatus status) { + VpcDistributedRouterSeqNoVO seqVo = _vpcDrSeqNoDao.findByVpcId(vpcId); + if (seqVo == null) { + seqVo = new VpcDistributedRouterSeqNoVO(vpcId); + _vpcDrSeqNoDao.persist(seqVo); + } + _vpcDrSeqNoDao.lockRow(seqVo.getId(), true); + seqVo.incrSequenceNo(); + _vpcDrSeqNoDao.update(seqVo.getId(), seqVo); + return seqVo.getSequenceNo(); + } + }); + } finally { + + } + } } diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/VpcDistributedRouterSeqNoDao.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/VpcDistributedRouterSeqNoDao.java new file mode 100644 index 00000000000..9965510cc40 --- /dev/null +++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/VpcDistributedRouterSeqNoDao.java @@ -0,0 +1,23 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. +package com.cloud.network.ovs.dao; + +import com.cloud.utils.db.GenericDao; + +public interface VpcDistributedRouterSeqNoDao extends GenericDao { + VpcDistributedRouterSeqNoVO findByVpcId(long vpcId); +} diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/VpcDistributedRouterSeqNoDaoImpl.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/VpcDistributedRouterSeqNoDaoImpl.java new file mode 100644 index 00000000000..88fa9c1da4e --- /dev/null +++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/VpcDistributedRouterSeqNoDaoImpl.java @@ -0,0 +1,47 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. +package com.cloud.network.ovs.dao; + +import javax.ejb.Local; + +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +@Local(value = {VpcDistributedRouterSeqNoDao.class}) +public class VpcDistributedRouterSeqNoDaoImpl extends GenericDaoBase implements VpcDistributedRouterSeqNoDao { + protected static final Logger s_logger = Logger.getLogger(VpcDistributedRouterSeqNoDaoImpl.class); + private SearchBuilder VpcIdSearch; + + protected VpcDistributedRouterSeqNoDaoImpl() { + VpcIdSearch = createSearchBuilder(); + VpcIdSearch.and("vmId", VpcIdSearch.entity().getVpcId(), SearchCriteria.Op.EQ); + VpcIdSearch.done(); + } + + @Override + public VpcDistributedRouterSeqNoVO findByVpcId(long vpcId) { + SearchCriteria sc = VpcIdSearch.create(); + sc.setParameters("vmId", vpcId); + return findOneIncludingRemovedBy(sc); + } + +} diff --git a/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/VpcDistributedRouterSeqNoVO.java b/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/VpcDistributedRouterSeqNoVO.java new file mode 100644 index 00000000000..d87a2c4dc57 --- /dev/null +++ b/plugins/network-elements/ovs/src/com/cloud/network/ovs/dao/VpcDistributedRouterSeqNoVO.java @@ -0,0 +1,72 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. +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; + +import org.apache.cloudstack.api.InternalIdentity; + +@Entity +@Table(name = "op_vpc_distributed_router_sequence_no") +public class VpcDistributedRouterSeqNoVO implements InternalIdentity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "vpc_id", updatable = false, nullable = false) + private Long vpcId; + + @Column(name = "sequence_no") + long sequenceNo = 0; + + protected VpcDistributedRouterSeqNoVO() { + + } + + public VpcDistributedRouterSeqNoVO(Long vpcId) { + super(); + this.vpcId = vpcId; + } + + @Override + public long getId() { + return id; + } + + public Long getVpcId() { + return vpcId; + } + + public void setVpcId(Long vpcId) { + this.vpcId = vpcId; + } + + public long getSequenceNo() { + return sequenceNo; + } + + public void incrSequenceNo() { + sequenceNo++; + } +} diff --git a/scripts/vm/hypervisor/xenserver/cloudstack_pluginlib.py b/scripts/vm/hypervisor/xenserver/cloudstack_pluginlib.py index 85daa864c2f..cda36457808 100644 --- a/scripts/vm/hypervisor/xenserver/cloudstack_pluginlib.py +++ b/scripts/vm/hypervisor/xenserver/cloudstack_pluginlib.py @@ -314,7 +314,7 @@ class jsonLoader(object): return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for (k, v) in self.__dict__.iteritems())) -def configure_bridge_for_network_topology(bridge, this_host_id, json_config): +def configure_bridge_for_network_topology(bridge, this_host_id, json_config, sequence_no): vpconfig = jsonLoader(json.loads(json_config)).vpc if vpconfig is None: @@ -389,7 +389,7 @@ def get_acl(vpcconfig, required_acl_id): return acl return None -def configure_ovs_bridge_for_routing_policies(bridge, json_config): +def configure_ovs_bridge_for_routing_policies(bridge, json_config, sequence_no): vpconfig = jsonLoader(json.loads(json_config)).vpc if vpconfig is None: diff --git a/scripts/vm/hypervisor/xenserver/ovstunnel b/scripts/vm/hypervisor/xenserver/ovstunnel index f9673023a95..a97df9b66f4 100755 --- a/scripts/vm/hypervisor/xenserver/ovstunnel +++ b/scripts/vm/hypervisor/xenserver/ovstunnel @@ -400,15 +400,17 @@ def configure_ovs_bridge_for_network_topology(session, args): bridge = args.pop("bridge") json_config = args.pop("config") this_host_id = args.pop("host-id") + sequence_no = args.pop("seq-no") - return lib.configure_bridge_for_network_topology(bridge, this_host_id, json_config) + return lib.configure_bridge_for_network_topology(bridge, this_host_id, json_config, sequence_no) @echo def configure_ovs_bridge_for_routing_policies(session, args): bridge = args.pop("bridge") json_config = args.pop("config") + sequence_no = args.pop("seq-no") - return lib.configure_ovs_bridge_for_routing_policies(bridge, json_config) + return lib.configure_ovs_bridge_for_routing_policies(bridge, json_config, sequence_no) if __name__ == "__main__": XenAPIPlugin.dispatch({"create_tunnel": create_tunnel, diff --git a/setup/db/db/schema-430to440.sql b/setup/db/db/schema-430to440.sql index 12314dd0ac4..f0bdba4c053 100644 --- a/setup/db/db/schema-430to440.sql +++ b/setup/db/db/schema-430to440.sql @@ -770,6 +770,12 @@ ALTER TABLE `cloud`.`vpc_offerings` ADD COLUMN supports_region_level_vpc boolean ALTER TABLE `cloud`.`network_offerings` ADD COLUMN supports_streched_l2 boolean default false; ALTER TABLE `cloud`.`networks` ADD COLUMN streched_l2 boolean default false; ALTER TABLE `cloud`.`vpc` ADD COLUMN region_level_vpc boolean default false; - INSERT INTO `cloud`.`configuration`(category, instance, component, name, value, description, default_value) VALUES ('Advanced', 'DEFAULT', 'NetworkOrchestrationService', 'router.redundant.vrrp.interval', '1', 'seconds between VRRP broadcast. It would 3 times broadcast fail to trigger fail-over mechanism of redundant router', '1') ON DUPLICATE KEY UPDATE category='Advanced'; INSERT INTO `cloud`.`configuration`(category, instance, component, name, value, description, default_value) VALUES ('Advanced', 'DEFAULT', 'NetworkOrchestrationService', 'router.aggregation.command.each.timeout', '3', 'timeout in seconds for each Virtual Router command being aggregated. The final aggregation command timeout would be determined by this timeout * commands counts ', '3') ON DUPLICATE KEY UPDATE category='Advanced'; +CREATE TABLE `cloud`.`op_vpc_distributed_router_sequence_no` ( + `id` bigint unsigned UNIQUE NOT NULL AUTO_INCREMENT COMMENT 'id', + `vpc_id` bigint unsigned NOT NULL COMMENT 'vpc id.', + `sequence_no` bigint unsigned COMMENT 'seq number to be sent to agent, uniquely identifies topology or routing policy updates', + PRIMARY KEY (`id`), + UNIQUE `u_op_vpc_distributed_router_sequence_no_vpc_id`(`vpc_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8;