From a49261c3b1f2d52d637f481e0bcff4b0d58d7b56 Mon Sep 17 00:00:00 2001 From: Jayapal Uradi Date: Wed, 6 Mar 2013 18:11:10 +0530 Subject: [PATCH] CLOUDSTACK-24: mipn feature for basiczone Signed-off-by: Abhinandan Prateek --- .../agent/api/SecurityGroupRulesCmd.java | 37 ++++ api/src/com/cloud/agent/api/to/NicTO.java | 11 + .../security/SecurityGroupService.java | 4 +- .../api/command/user/vm/AddIpToVmNicCmd.java | 29 ++- .../command/user/vm/RemoveIpFromVmNicCmd.java | 48 ++++- .../api/NetworkRulesVmSecondaryIpCommand.java | 71 +++++++ .../xen/resource/CitrixResourceBase.java | 32 ++- scripts/vm/hypervisor/xenserver/vmops | 199 +++++++++++++++++- .../cloud/hypervisor/HypervisorGuruBase.java | 12 +- .../src/com/cloud/network/NetworkManager.java | 5 +- .../com/cloud/network/NetworkManagerImpl.java | 29 ++- .../com/cloud/network/NetworkModelImpl.java | 2 +- .../com/cloud/network/NetworkServiceImpl.java | 94 +++++++-- .../com/cloud/network/dao/IPAddressDao.java | 2 + .../cloud/network/dao/IPAddressDaoImpl.java | 8 + .../cloud/network/guru/DirectNetworkGuru.java | 18 +- .../security/SecurityGroupManagerImpl.java | 93 +++++++- .../security/SecurityGroupManagerImpl2.java | 13 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 7 - server/src/com/cloud/vm/dao/NicDao.java | 2 + server/src/com/cloud/vm/dao/NicDaoImpl.java | 9 + .../cloud/network/MockNetworkManagerImpl.java | 20 +- .../com/cloud/vpc/MockNetworkManagerImpl.java | 33 ++- 23 files changed, 704 insertions(+), 74 deletions(-) create mode 100644 core/src/com/cloud/agent/api/NetworkRulesVmSecondaryIpCommand.java diff --git a/api/src/com/cloud/agent/api/SecurityGroupRulesCmd.java b/api/src/com/cloud/agent/api/SecurityGroupRulesCmd.java index affad1f9b9d..4336b4c32b4 100644 --- a/api/src/com/cloud/agent/api/SecurityGroupRulesCmd.java +++ b/api/src/com/cloud/agent/api/SecurityGroupRulesCmd.java @@ -18,6 +18,7 @@ package com.cloud.agent.api; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.List; import java.util.zip.DeflaterOutputStream; import org.apache.commons.codec.binary.Base64; @@ -80,6 +81,7 @@ public class SecurityGroupRulesCmd extends Command { Long msId; IpPortAndProto [] ingressRuleSet; IpPortAndProto [] egressRuleSet; + private List secIps; public SecurityGroupRulesCmd() { super(); @@ -103,6 +105,23 @@ public class SecurityGroupRulesCmd extends Command { } + public SecurityGroupRulesCmd(String guestIp, String guestMac, String vmName, Long vmId, String signature, Long seqNum, IpPortAndProto[] ingressRuleSet, IpPortAndProto[] egressRuleSet, List secIps) { + super(); + this.guestIp = guestIp; + this.vmName = vmName; + this.ingressRuleSet = ingressRuleSet; + this.egressRuleSet = egressRuleSet; + this.guestMac = guestMac; + this.signature = signature; + this.seqNum = seqNum; + this.vmId = vmId; + if (signature == null) { + String stringified = stringifyRules(); + this.signature = DigestUtils.md5Hex(stringified); + } + this.secIps = secIps; + } + @Override public boolean executeInSequence() { return true; @@ -131,6 +150,10 @@ public class SecurityGroupRulesCmd extends Command { return guestIp; } + public List getSecIps() { + return secIps; + } + public String getVmName() { return vmName; @@ -165,6 +188,20 @@ public class SecurityGroupRulesCmd extends Command { } + public String getSecIpsString() { + StringBuilder sb = new StringBuilder(); + List ips = getSecIps(); + if (ips == null) { + return "0:"; + } else { + for (String ip : ips) { + sb.append(ip).append(":"); + } + } + return sb.toString(); + } + + public String stringifyCompressedRules() { StringBuilder ruleBuilder = new StringBuilder(); for (SecurityGroupRulesCmd.IpPortAndProto ipPandP : getIngressRuleSet()) { diff --git a/api/src/com/cloud/agent/api/to/NicTO.java b/api/src/com/cloud/agent/api/to/NicTO.java index aa2aa19cc19..ccebe115f97 100644 --- a/api/src/com/cloud/agent/api/to/NicTO.java +++ b/api/src/com/cloud/agent/api/to/NicTO.java @@ -16,12 +16,15 @@ // under the License. package com.cloud.agent.api.to; +import java.util.List; + public class NicTO extends NetworkTO { int deviceId; Integer networkRateMbps; Integer networkRateMulticastMbps; boolean defaultNic; String uuid; + List nicSecIps; public NicTO() { super(); @@ -69,4 +72,12 @@ public class NicTO extends NetworkTO { public String toString() { return new StringBuilder("[Nic:").append(type).append("-").append(ip).append("-").append(broadcastUri).append("]").toString(); } + + public void setNicSecIps(List secIps) { + this.nicSecIps = secIps; + } + + public List getNicSecIps() { + return nicSecIps; + } } diff --git a/api/src/com/cloud/network/security/SecurityGroupService.java b/api/src/com/cloud/network/security/SecurityGroupService.java index c6480323780..397de1ccb46 100644 --- a/api/src/com/cloud/network/security/SecurityGroupService.java +++ b/api/src/com/cloud/network/security/SecurityGroupService.java @@ -24,6 +24,7 @@ import org.apache.cloudstack.api.command.user.securitygroup.CreateSecurityGroupC import org.apache.cloudstack.api.command.user.securitygroup.DeleteSecurityGroupCmd; import org.apache.cloudstack.api.command.user.securitygroup.RevokeSecurityGroupEgressCmd; import org.apache.cloudstack.api.command.user.securitygroup.RevokeSecurityGroupIngressCmd; +import org.apache.cloudstack.api.command.user.vm.AddIpToVmNicCmd; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; @@ -45,5 +46,6 @@ public interface SecurityGroupService { public List authorizeSecurityGroupIngress(AuthorizeSecurityGroupIngressCmd cmd); public List authorizeSecurityGroupEgress(AuthorizeSecurityGroupEgressCmd cmd); - + public boolean securityGroupRulesForVmSecIp(Long nicId, Long networkId, + String secondaryIp, boolean ruleAction); } diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java index 0f992743f6d..cc34b7b2b44 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/AddIpToVmNicCmd.java @@ -28,6 +28,8 @@ import org.apache.cloudstack.api.response.NicResponse; import org.apache.cloudstack.api.response.NicSecondaryIpResponse; import com.cloud.async.AsyncJob; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenter.NetworkType; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientAddressCapacityException; @@ -83,6 +85,9 @@ public class AddIpToVmNicCmd extends BaseAsyncCmd { public Long getNetworkId() { Nic nic = _entityMgr.findById(Nic.class, nicId); + if (nic == null) { + throw new InvalidParameterValueException("Can't find network id for specified nic"); + } Long networkId = nic.getNetworkId(); return networkId; } @@ -98,6 +103,13 @@ public class AddIpToVmNicCmd extends BaseAsyncCmd { return null; } } + + public NetworkType getNetworkType() { + Network ntwk = _entityMgr.findById(Network.class, getNetworkId()); + DataCenter dc = _entityMgr.findById(DataCenter.class, ntwk.getDataCenterId()); + return dc.getNetworkType(); + } + @Override public long getEntityOwnerId() { Account caller = UserContext.current().getCaller(); @@ -134,7 +146,7 @@ public class AddIpToVmNicCmd extends BaseAsyncCmd { UserContext.current().setEventDetails("Nic Id: " + getNicId() ); String ip; - String SecondaryIp = null; + String secondaryIp = null; if ((ip = getIpaddress()) != null) { if (!NetUtils.isValidIp(ip)) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Invalid ip address " + ip); @@ -142,13 +154,22 @@ public class AddIpToVmNicCmd extends BaseAsyncCmd { } try { - SecondaryIp = _networkService.allocateSecondaryGuestIP(_accountService.getAccount(getEntityOwnerId()), getZoneId(), getNicId(), getNetworkId(), getIpaddress()); + secondaryIp = _networkService.allocateSecondaryGuestIP(_accountService.getAccount(getEntityOwnerId()), getZoneId(), getNicId(), getNetworkId(), getIpaddress()); } catch (InsufficientAddressCapacityException e) { throw new InvalidParameterValueException("Allocating guest ip for nic failed"); } - if (SecondaryIp != null) { - s_logger.info("Associated ip address to NIC : " + SecondaryIp); + if (secondaryIp != null) { + if (getNetworkType() == NetworkType.Basic) { + // add security group rules for the secondary ip addresses + boolean success = false; + success = _securityGroupService.securityGroupRulesForVmSecIp(getNicId(), getNetworkId(), secondaryIp, (boolean) true); + if (success == false) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to set security group rules for the secondary ip"); + } + } + + s_logger.info("Associated ip address to NIC : " + secondaryIp); NicSecondaryIpResponse response = new NicSecondaryIpResponse(); response = _responseGenerator.createSecondaryIPToNicResponse(ip, getNicId(), getNetworkId()); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java b/api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java index cb5e0855f64..d9ab7e03080 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vm/RemoveIpFromVmNicCmd.java @@ -27,10 +27,15 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.NicSecondaryIpResponse; import org.apache.cloudstack.api.response.SuccessResponse; import com.cloud.async.AsyncJob; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenter.NetworkType; import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.Network; import com.cloud.user.Account; import com.cloud.user.UserContext; +import com.cloud.vm.Nic; +import com.cloud.vm.NicSecondaryIp; @APICommand(name = "removeIpFromNic", description="Assigns secondary IP to NIC.", responseObject=SuccessResponse.class) public class RemoveIpFromVmNicCmd extends BaseAsyncCmd { @@ -43,7 +48,7 @@ public class RemoveIpFromVmNicCmd extends BaseAsyncCmd { @Parameter(name=ApiConstants.ID, type=CommandType.UUID, required = true, entityType = NicSecondaryIpResponse.class, description="the ID of the secondary ip address to nic") - private long id; + private Long id; // unexposed parameter needed for events logging @Parameter(name=ApiConstants.ACCOUNT_ID, type=CommandType.UUID, expose=false) @@ -57,7 +62,7 @@ public class RemoveIpFromVmNicCmd extends BaseAsyncCmd { return "nic_secondary_ips"; } - public long getIpAddressId() { + public Long getIpAddressId() { return id; } @@ -80,6 +85,11 @@ public class RemoveIpFromVmNicCmd extends BaseAsyncCmd { return EventTypes.EVENT_NET_IP_ASSIGN; } + public NicSecondaryIp getIpEntry() { + NicSecondaryIp nicSecIp = _entityMgr.findById(NicSecondaryIp.class, getIpAddressId()); + return nicSecIp; + } + @Override public String getEventDescription() { return ("Disassociating ip address with id=" + id); @@ -98,9 +108,43 @@ public class RemoveIpFromVmNicCmd extends BaseAsyncCmd { return "addressinfo"; } + public Long getNetworkId() { + NicSecondaryIp nicSecIp = _entityMgr.findById(NicSecondaryIp.class, getIpAddressId()); + if (nicSecIp != null) { + Long networkId = nicSecIp.getNetworkId(); + return networkId; + } else { + return null; + } + } + + public NetworkType getNetworkType() { + Network ntwk = _entityMgr.findById(Network.class, getNetworkId()); + if (ntwk != null) { + DataCenter dc = _entityMgr.findById(DataCenter.class, ntwk.getDataCenterId()); + return dc.getNetworkType(); + } + return null; + } + @Override public void execute() throws InvalidParameterValueException { UserContext.current().setEventDetails("Ip Id: " + getIpAddressId()); + NicSecondaryIp nicSecIp = getIpEntry(); + + if (nicSecIp == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Invalid IP id is passed"); + } + + if (getNetworkType() == NetworkType.Basic) { + //remove the security group rules for this secondary ip + boolean success = false; + success = _securityGroupService.securityGroupRulesForVmSecIp(nicSecIp.getNicId(), nicSecIp.getNetworkId(),nicSecIp.getIp4Address(), false); + if (success == false) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to set security group rules for the secondary ip"); + } + } + boolean result = _networkService.releaseSecondaryIpFromNic(getIpAddressId()); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); diff --git a/core/src/com/cloud/agent/api/NetworkRulesVmSecondaryIpCommand.java b/core/src/com/cloud/agent/api/NetworkRulesVmSecondaryIpCommand.java new file mode 100644 index 00000000000..ce4080878a1 --- /dev/null +++ b/core/src/com/cloud/agent/api/NetworkRulesVmSecondaryIpCommand.java @@ -0,0 +1,71 @@ +// 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.agent.api; + +import com.cloud.vm.VirtualMachine; + +public class NetworkRulesVmSecondaryIpCommand extends Command { + + private String vmName; + private VirtualMachine.Type type; + private String vmSecIp; + private String vmMac; + private String action; + + public NetworkRulesVmSecondaryIpCommand(String vmName, VirtualMachine.Type type) { + this.vmName = vmName; + this.type = type; + } + + + public NetworkRulesVmSecondaryIpCommand(String vmName, String vmMac, + String secondaryIp, boolean action) { + this.vmName = vmName; + this.vmMac = vmMac; + this.vmSecIp = secondaryIp; + if (action) { + this.action = "-A"; + } else { + this.action = "-D"; + } + } + + public String getVmName() { + return vmName; + } + + public VirtualMachine.Type getType() { + return type; + } + + public String getVmSecIp() { + return vmSecIp; + } + + public String getVmMac() { + return vmMac; + } + + public String getAction() { + return action; + } + + @Override + public boolean executeInSequence() { + return false; + } +} 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 886fc6f04fa..f0cf2f05bf0 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 @@ -118,6 +118,7 @@ import com.cloud.agent.api.ModifySshKeysCommand; import com.cloud.agent.api.ModifyStoragePoolAnswer; import com.cloud.agent.api.ModifyStoragePoolCommand; import com.cloud.agent.api.NetworkRulesSystemVmCommand; +import com.cloud.agent.api.NetworkRulesVmSecondaryIpCommand; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.PingRoutingCommand; import com.cloud.agent.api.PingRoutingWithNwGroupsCommand; @@ -597,6 +598,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return execute((DeleteVMSnapshotCommand)cmd); } else if (clazz == RevertToVMSnapshotCommand.class) { return execute((RevertToVMSnapshotCommand)cmd); + } else if (clazz == NetworkRulesVmSecondaryIpCommand.class) { + return execute((NetworkRulesVmSecondaryIpCommand)cmd); } else { return Answer.createUnsupportedCommandAnswer(cmd); } @@ -1468,7 +1471,18 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe for (NicTO nic : nics) { if ( nic.isSecurityGroupEnabled() || nic.getIsolationUri() != null && nic.getIsolationUri().getScheme().equalsIgnoreCase(IsolationType.Ec2.toString())) { - result = callHostPlugin(conn, "vmops", "default_network_rules", "vmName", vmName, "vmIP", nic.getIp(), "vmMAC", nic.getMac(), "vmID", Long.toString(vmSpec.getId())); + List nicSecIps = nic.getNicSecIps(); + String secIpsStr; + StringBuilder sb = new StringBuilder(); + if (nicSecIps != null) { + for (String ip : nicSecIps) { + sb.append(ip).append(":"); + } + secIpsStr = sb.toString(); + } else { + secIpsStr = "0:"; + } + result = callHostPlugin(conn, "vmops", "default_network_rules", "vmName", vmName, "vmIP", nic.getIp(), "vmMAC", nic.getMac(), "vmID", Long.toString(vmSpec.getId()), "secIps", secIpsStr); if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { s_logger.warn("Failed to program default network rules for " + vmName+" on nic with ip:"+nic.getIp()+" mac:"+nic.getMac()); @@ -5454,7 +5468,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe "signature", cmd.getSignature(), "seqno", Long.toString(cmd.getSeqNum()), "deflated", "true", - "rules", cmd.compressStringifiedRules()); + "rules", cmd.compressStringifiedRules(), + "secIps", cmd.getSecIpsString()); if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { s_logger.warn("Failed to program network rules for vm " + cmd.getVmName()); @@ -7506,6 +7521,19 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return new Answer(cmd, success, ""); } + private Answer execute(NetworkRulesVmSecondaryIpCommand cmd) { + boolean success = true; + Connection conn = getConnection(); + + String result = callHostPlugin(conn, "vmops", "network_rules_vmSecondaryIp", "vmName", cmd.getVmName(), "vmMac", cmd.getVmMac(), "vmSecIp", cmd.getVmSecIp(), "action", + cmd.getAction()); + if (result == null || result.isEmpty() || !Boolean.parseBoolean(result)) { + success = false; + } + + return new Answer(cmd, success, ""); + } + protected SetFirewallRulesAnswer execute(SetFirewallRulesCommand cmd) { String[] results = new String[cmd.getRules().length]; String callResult; diff --git a/scripts/vm/hypervisor/xenserver/vmops b/scripts/vm/hypervisor/xenserver/vmops index db6f6d63ac9..31c9a59663e 100755 --- a/scripts/vm/hypervisor/xenserver/vmops +++ b/scripts/vm/hypervisor/xenserver/vmops @@ -610,6 +610,7 @@ def destroy_network_rules_for_vm(session, args): util.SMlog("Ignoring failure to delete egress chain " + vmchain_egress) remove_rule_log_for_vm(vm_name) + remove_secip_log_for_vm(vm_name) if 1 in [ vm_name.startswith(c) for c in ['r-', 's-', 'v-', 'l-'] ]: return 'true' @@ -749,6 +750,43 @@ def default_arp_antispoof(vm_chain, vifs, vm_ip, vm_mac): return 'true' + +@echo +def network_rules_vmSecondaryIp(session, args): + vm_name = args.pop('vmName') + vm_mac = args.pop('vmMac') + ip_secondary = args.pop('vmSecIp') + action = args.pop('action') + util.SMlog("vmMac = "+ vm_mac) + util.SMlog("vmName = "+ vm_name) + #action = "-A" + util.SMlog("action = "+ action) + try: + vm = session.xenapi.VM.get_by_name_label(vm_name) + if len(vm) != 1: + return 'false' + vm_rec = session.xenapi.VM.get_record(vm[0]) + vm_vifs = vm_rec.get('VIFs') + vifnums = [session.xenapi.VIF.get_record(vif).get('device') for vif in vm_vifs] + domid = vm_rec.get('domid') + except: + util.SMlog("### Failed to get domid or vif list for vm ##" + vm_name) + return 'false' + + if domid == '-1': + util.SMlog("### Failed to get domid for vm (-1): " + vm_name) + return 'false' + + vifs = ["vif" + domid + "." + v for v in vifnums] + #vm_name = '-'.join(vm_name.split('-')[:-1]) + vmchain = chain_name(vm_name) + add_to_ipset(vmchain, [ip_secondary], action) + + #add arptables rules for the secondary ip + arp_rules_vmip(vmchain, vifs, [ip_secondary], vm_mac, action) + + return 'true' + @echo def default_network_rules_systemvm(session, args): vm_name = args.pop('vmName') @@ -798,6 +836,55 @@ def default_network_rules_systemvm(session, args): util.SMlog("Failed to log default network rules for systemvm, ignoring") return 'true' +@echo +def create_ipset_forvm (ipsetname): + result = True + try: + util.SMlog("Creating ipset chain .... " + ipsetname) + util.pread2(['ipset', '-F', ipsetname]) + util.pread2(['ipset', '-X', ipsetname]) + util.pread2(['ipset', '-N', ipsetname, 'iphash']) + except: + util.SMlog("ipset chain not exists creating.... " + ipsetname) + util.pread2(['ipset', '-N', ipsetname, 'iphash']) + + return result + +@echo +def add_to_ipset(ipsetname, ips, action): + result = True + for ip in ips: + try: + util.SMlog("vm ip " + ip) + util.pread2(['ipset', action, ipsetname, ip]) + except: + util.SMlog("vm ip alreday in ip set" + ip) + continue + + return result + +@echo +def arp_rules_vmip (vm_chain, vifs, ips, vm_mac, action): + try: + if action == "-A": + action = "-I" + for vif in vifs: + for vm_ip in ips: + #accept any arp requests to this vm as long as the request is for this vm's ip + util.pread2(['arptables', action, vm_chain, '-o', vif, '--opcode', 'Request', '--destination-ip', vm_ip, '-j', 'ACCEPT']) + #accept any arp replies to this vm as long as the mac and ip matches + util.pread2(['arptables', action, vm_chain, '-o', vif, '--opcode', 'Reply', '--destination-mac', vm_mac, '--destination-ip', vm_ip, '-j', 'ACCEPT']) + #accept arp replies into the bridge as long as the source mac and ips match the vm + util.pread2(['arptables', action, vm_chain, '-i', vif, '--opcode', 'Reply', '--source-mac', vm_mac, '--source-ip', vm_ip, '-j', 'ACCEPT']) + #accept any arp requests from this vm. In the future this can be restricted to deny attacks on hosts + #also important to restrict source ip and src mac in these requests as they can be used to update arp tables on destination + util.pread2(['arptables', action, vm_chain, '-i', vif, '--opcode', 'Request', '--source-mac', vm_mac, '--source-ip', vm_ip, '-j', 'RETURN']) + except: + util.SMlog("Failed to program arptables rules for ip") + return 'false' + + return 'true' + @echo def default_network_rules(session, args): @@ -805,6 +892,8 @@ def default_network_rules(session, args): vm_ip = args.pop('vmIP') vm_id = args.pop('vmID') vm_mac = args.pop('vmMAC') + sec_ips = args.pop("secIps") + action = "-A" try: vm = session.xenapi.VM.get_by_name_label(vm_name) @@ -854,6 +943,32 @@ def default_network_rules(session, args): except: util.pread2(['iptables', '-F', vmchain_default]) + vmipset = vm_name + #create ipset and add vm ips to that ip set + if create_ipset_forvm(vmipset) == False: + util.SMlog(" failed to create ipset for rule " + str(tokens)) + return 'false' + + #add primary nic ip to ipset + if add_to_ipset(vmipset, [vm_ip], action ) == False: + util.SMlog(" failed to add vm " + vm_ip + " ip to set ") + return 'false' + + #add secodnary nic ips to ipset + secIpSet = "1" + ips = sec_ips.split(':') + ips.pop() + if ips[0] == "0": + secIpSet = "0"; + + if secIpSet == "1": + util.SMlog("Adding ipset for secondary ips") + add_to_ipset(vmipset, ips, action) + if write_secip_log_for_vm(vm_name, sec_ips, vm_id) == False: + util.SMlog("Failed to log default network rules, ignoring") + + keyword = '--' + get_ipset_keyword() + try: for v in vifs: util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', v, '-j', vmchain_default]) @@ -861,16 +976,22 @@ def default_network_rules(session, args): #don't let vm spoof its ip address for v in vifs: - util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '--source', vm_ip,'-p', 'udp', '--dport', '53', '-j', 'RETURN']) - util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '--source', '!', vm_ip, '-j', 'DROP']) - util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', v, '--destination', '!', vm_ip, '-j', 'DROP']) - util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '--source', vm_ip, '-j', vmchain_egress]) + #util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '--source', vm_ip,'-p', 'udp', '--dport', '53', '-j', 'RETURN']) + util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '-m', 'set', keyword, vmipset, 'src', '-p', 'udp', '--dport', '53', '-j', 'RETURN']) + util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '-m', 'set', '!', keyword, vmipset, 'src', '-j', 'DROP']) + util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', v, '-m', 'set', '!', keyword, vmipset, 'dst', '-j', 'DROP']) + util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '-m', 'set', keyword, vmipset, 'src', '-j', vmchain_egress]) util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', v, '-j', vmchain]) except: util.SMlog("Failed to program default rules for vm " + vm_name) return 'false' default_arp_antispoof(vmchain, vifs, vm_ip, vm_mac) + #add default arp rules for secondary ips; + if secIpSet == "1": + util.SMlog("Adding arp rules for sec ip") + arp_rules_vmip(vmchain, vifs, ips, vm_mac, action) + default_ebtables_antispoof_rules(vmchain, vifs, vm_ip, vm_mac) if write_rule_log_for_vm(vm_name, vm_id, vm_ip, domid, '_initial_', '-1', vm_mac) == False: @@ -994,10 +1115,45 @@ def network_rules_for_rebooted_vm(session, vmName): destroy_arptables_rules(vmchain) [vm_ip, vm_mac] = get_vm_mac_ip_from_log(vmchain) default_arp_antispoof(vmchain, vifs, vm_ip, vm_mac) + + #check wether the vm has secondary ips + if is_secondary_ips_set(vm_name) == True: + vmips = get_vm_sec_ips(vm_name) + #add arp rules for the secondaryp ip + for ip in vmips: + arp_rules_vmip(vmchain, vifs, [ip], vm_mac, "-A") + + default_ebtables_antispoof_rules(vmchain, vifs, vm_ip, vm_mac) rewrite_rule_log_for_vm(vm_name, curr_domid) return True + + +@echo +def get_vm_sec_ips(vm_name): + logfilename = "/var/run/cloud/" + vm_name +".ip" + + lines = (line.rstrip() for line in open(logfilename)) + for line in lines: + try: + [_vmName,_vmIP,_vmID] = line.split(',') + break + except ValueError,v: + [_vmName,_vmIP,_vmID] = line.split(',') + + _vmIPS = _vmIP.split(":")[:-1] + return _vmIPS + +@echo +def is_secondary_ips_set(vm_name): + logfilename = "/var/run/cloud/" + vm_name +".ip" + if not os.path.exists(logfilename): + return False + + return True + +@echo def rewrite_rule_log_for_vm(vm_name, new_domid): logfilename = "/var/run/cloud/" + vm_name +".log" if not os.path.exists(logfilename): @@ -1194,6 +1350,39 @@ def check_rule_log_for_vm(vmName, vmID, vmIP, domID, signature, seqno): return [reprogramDefault, reprogramChain, rewriteLog] +@echo +def write_secip_log_for_vm (vmName, secIps, vmId): + vm_name = vmName + logfilename = "/var/run/cloud/"+vm_name+".ip" + util.SMlog("Writing log to " + logfilename) + logf = open(logfilename, 'w') + output = ','.join([vmName, secIps, vmId]) + result = True + + try: + logf.write(output) + logf.write('\n') + except: + util.SMlog("Failed to write to rule log file " + logfilename) + result = False + + logf.close() + + return result + +@echo +def remove_secip_log_for_vm(vmName): + vm_name = vmName + logfilename = "/var/run/cloud/"+vm_name+".ip" + + result = True + try: + os.remove(logfilename) + except: + util.SMlog("Failed to delete rule log file " + logfilename) + result = False + + return result @echo def write_rule_log_for_vm(vmName, vmID, vmIP, domID, signature, seqno, vmMac='ff:ff:ff:ff:ff:ff'): @@ -1289,6 +1478,7 @@ def network_rules(session, args): vm_mac = args.get('vmMAC') signature = args.pop('signature') seqno = args.pop('seqno') + sec_ips = args.pop("secIps") deflated = 'false' if 'deflated' in args: deflated = args.pop('deflated') @@ -1469,6 +1659,7 @@ if __name__ == "__main__": "can_bridge_firewall":can_bridge_firewall, "default_network_rules":default_network_rules, "destroy_network_rules_for_vm":destroy_network_rules_for_vm, "default_network_rules_systemvm":default_network_rules_systemvm, + "network_rules_vmSecondaryIp":network_rules_vmSecondaryIp, "get_rule_logs_for_vms":get_rule_logs_for_vms, "setLinkLocalIP":setLinkLocalIP, "cleanup_rules":cleanup_rules, diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java index efe93966fe9..d77796da300 100644 --- a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java +++ b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java @@ -34,6 +34,7 @@ import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.VMInstanceDao; public abstract class HypervisorGuruBase extends AdapterBase implements HypervisorGuru { @@ -41,7 +42,8 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis @Inject VMTemplateDetailsDao _templateDetailsDao; @Inject NicDao _nicDao; @Inject VMInstanceDao _virtualMachineDao; - + @Inject NicSecondaryIpDao _nicSecIpDao; + protected HypervisorGuruBase() { super(); } @@ -68,6 +70,14 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis // Workaround to make sure the TO has the UUID we need for Niciri integration NicVO nicVO = _nicDao.findById(profile.getId()); to.setUuid(nicVO.getUuid()); + //check whether the this nic has secondary ip addresses set + //set nic secondary ip address in NicTO which are used for security group + // configuration. Use full when vm stop/start + List secIps = null; + if (nicVO.getSecondaryIp()) { + secIps = _nicSecIpDao.getSecondaryIpAddressesForNic(nicVO.getId()); + } + to.setNicSecIps(secIps); return to; } diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 8b6bf9a7402..48e017edabd 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -21,6 +21,8 @@ import java.util.Map; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.Pod; import com.cloud.dc.Vlan.VlanType; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; @@ -339,8 +341,9 @@ public interface NetworkManager { public String allocateGuestIP(Account ipOwner, boolean isSystem, long zoneId, Long networkId, String requestedIp) throws InsufficientAddressCapacityException; - boolean removeVmSecondaryIps(long vmId); List listVmNics(Long vmId, Long nicId); + String allocatePublicIpForGuestNic(Long networkId, DataCenter dc, Pod pod, Account caller, String requestedIp) throws InsufficientAddressCapacityException; + boolean removeVmSecondaryIpsOfNic(long nicId); } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index ba5ab5d378b..3220c9174eb 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -1765,12 +1765,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L _nicDao.remove(nic.getId()); s_logger.debug("Removed nic id=" + nic.getId()); //remove the secondary ip addresses corresponding to to this nic - List secondaryIps = _nicSecondaryIpDao.listByNicId(nic.getId()); - if (secondaryIps != null) { - for (NicSecondaryIpVO ip : secondaryIps) { - _nicSecondaryIpDao.remove(ip.getId()); - } - s_logger.debug("Removed nic " + nic.getId() + " secondary ip addreses"); + if (!removeVmSecondaryIpsOfNic(nic.getId())) { + s_logger.debug("Removing nic " + nic.getId() + " secondary ip addreses failed"); } } @@ -2835,7 +2831,6 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L _accountMgr.checkAccess(caller, null, false, network); - //return acquireGuestIpAddress(network, requestedIp); ipaddr = acquireGuestIpAddress(network, requestedIp); return ipaddr; } @@ -3654,11 +3649,11 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L return nic.getSecondaryIp(); } - @Override - public boolean removeVmSecondaryIps(long vmId) { + @Override + public boolean removeVmSecondaryIpsOfNic(long nicId) { Transaction txn = Transaction.currentTxn(); txn.start(); - List ipList = _nicSecondaryIpDao.listByVmId(vmId); + List ipList = _nicSecondaryIpDao.listByNicId(nicId); if (ipList != null) { for (NicSecondaryIpVO ip: ipList) { _nicSecondaryIpDao.remove(ip.getId()); @@ -3669,4 +3664,16 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L return true; } -} + @Override + public String allocatePublicIpForGuestNic(Long networkId, DataCenter dc, Pod pod,Account owner, + String requestedIp) throws InsufficientAddressCapacityException { + PublicIp ip = assignPublicIpAddress(dc.getId(), null, owner, VlanType.DirectAttached, networkId, requestedIp, false); + if (ip == null) { + s_logger.debug("There is no free public ip address"); + return null; + } + Ip ipAddr = ip.getAddress(); + return ipAddr.addr(); + } + + } diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index e83c0d28ad4..46790b3ebdc 100644 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -742,7 +742,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { @Override public Nic getNicInNetwork(long vmId, long networkId) { - return _nicDao.findByInstanceIdAndNetworkId(networkId, vmId); + return _nicDao.findByInstanceIdAndNetworkIdIncludingRemoved(networkId, vmId); } @Override diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 821aa6db26f..ba55ff853b9 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -517,8 +517,45 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } catch (InsufficientAddressCapacityException e) { throw new InvalidParameterValueException("Allocating guest ip for nic failed"); } + } else if (dc.getNetworkType() == NetworkType.Basic) { + Account caller = UserContext.current().getCaller(); + long callerUserId = UserContext.current().getCallerUserId(); + _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, network); + //handle the basic networks here + VirtualMachine vm = _userVmDao.findById(nicVO.getInstanceId()); + if (vm == null) { + throw new InvalidParameterValueException("There is no vm with the nic"); + } + VMInstanceVO vmi = (VMInstanceVO)vm; + Long podId = vmi.getPodIdToDeployIn(); + if (podId == null) { + throw new InvalidParameterValueException("vm pod id is null"); + } + Pod pod = _hostPodDao.findById(podId); + if (pod == null) { + throw new InvalidParameterValueException("vm pod is null"); + } + + try { + ipaddr = _networkMgr.allocatePublicIpForGuestNic(networkId, dc, pod, caller, requestedIp); + if (ipaddr == null) { + throw new InvalidParameterValueException("Allocating ip to guest nic " + nicId + " failed"); + } + } catch (InsufficientAddressCapacityException e) { + s_logger.error("Allocating ip to guest nic " + nicId + " failed"); + return null; + } + } else if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) && zone.getNetworkType() == NetworkType.Advanced) { + // if shared network in the advanced zone, then check the caller against the network for 'AccessType.UseNetwork' + Account caller = UserContext.current().getCaller(); + long callerUserId = UserContext.current().getCallerUserId(); + _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, network); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Associate IP address called by the user " + callerUserId + " account " + ipOwner.getId()); + } } else { - throw new InvalidParameterValueException("AddIpToVMNic is not supported in this network..."); + s_logger.error("AddIpToVMNic is not supported in this network..."); + return null; } if (ipaddr != null) { @@ -549,18 +586,18 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { boolean success = false; // Verify input parameters - NicSecondaryIpVO ipVO= _nicSecondaryIpDao.findById(ipAddressId); - if (ipVO == null) { + NicSecondaryIpVO secIpVO= _nicSecondaryIpDao.findById(ipAddressId); + if (secIpVO == null) { throw new InvalidParameterValueException("Unable to find ip address by id"); } - Network network = _networksDao.findById(ipVO.getNetworkId()); + Network network = _networksDao.findById(secIpVO.getNetworkId()); // verify permissions _accountMgr.checkAccess(caller, null, true, network); - Long nicId = ipVO.getNicId(); - s_logger.debug("ip id and nic id" + ipAddressId + "..." + nicId); + Long nicId = secIpVO.getNicId(); + s_logger.debug("ip id and nic id " + ipAddressId + "..." + nicId); //check is this the last secondary ip for NIC List ipList = _nicSecondaryIpDao.listByNicId(nicId); boolean lastIp = false; @@ -568,20 +605,41 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { // this is the last secondary ip to nic lastIp = true; } - //check PF or static NAT is configured on this ip address - String secondaryIp = ipVO.getIp4Address(); - List pfRuleList = _portForwardingDao.listByDestIpAddr(secondaryIp); - if (pfRuleList.size() != 0) { - s_logger.debug("VM nic IP " + secondaryIp + " is associated with the port forwarding rule"); - throw new InvalidParameterValueException("Can't remove the secondary ip " + secondaryIp + " is associate with the port forwarding rule"); + + DataCenter dc = _dcDao.findById(network.getDataCenterId()); + if (dc == null) { + throw new InvalidParameterValueException("Invalid zone Id is given"); } - //check if the secondary ip associated with any static nat rule - IPAddressVO publicIpVO = _ipAddressDao.findByVmIp(secondaryIp); - if (publicIpVO != null) { - s_logger.debug("VM nic IP " + secondaryIp + " is associated with the static NAT rule public IP address id " + publicIpVO.getId()); - throw new InvalidParameterValueException("Can' remove the ip " + secondaryIp + "is associate with static NAT rule public IP address id " + publicIpVO.getId()); + + s_logger.debug("Calling the ip allocation ..."); + if (dc.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Isolated) { + //check PF or static NAT is configured on this ip address + String secondaryIp = secIpVO.getIp4Address(); + List pfRuleList = _portForwardingDao.listByDestIpAddr(secondaryIp); + if (pfRuleList.size() != 0) { + s_logger.debug("VM nic IP " + secondaryIp + " is associated with the port forwarding rule"); + throw new InvalidParameterValueException("Can't remove the secondary ip " + secondaryIp + " is associate with the port forwarding rule"); + } + //check if the secondary ip associated with any static nat rule + IPAddressVO publicIpVO = _ipAddressDao.findByVmIp(secondaryIp); + if (publicIpVO != null) { + s_logger.debug("VM nic IP " + secondaryIp + " is associated with the static NAT rule public IP address id " + publicIpVO.getId()); + throw new InvalidParameterValueException("Can' remove the ip " + secondaryIp + "is associate with static NAT rule public IP address id " + publicIpVO.getId()); + } + } else if (dc.getNetworkType() == NetworkType.Basic) { + IPAddressVO ip = _ipAddressDao.findByIpAndNetworkId(secIpVO.getNetworkId(), secIpVO.getIp4Address()); + if (ip != null) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + _networkMgr.markIpAsUnavailable(ip.getId()); + _ipAddressDao.unassignIpAddress(ip.getId()); + txn.commit(); + } + } else if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) && dc.getNetworkType() == NetworkType.Advanced) { + throw new InvalidParameterValueException("Not supported for this network now"); } - success = removeNicSecondaryIP(ipVO, lastIp); + + success = removeNicSecondaryIP(secIpVO, lastIp); return success; } diff --git a/server/src/com/cloud/network/dao/IPAddressDao.java b/server/src/com/cloud/network/dao/IPAddressDao.java index 1052639ebf2..3d588fa9307 100755 --- a/server/src/com/cloud/network/dao/IPAddressDao.java +++ b/server/src/com/cloud/network/dao/IPAddressDao.java @@ -66,4 +66,6 @@ public interface IPAddressDao extends GenericDao { IPAddressVO findByVmIp(String vmIp); IPAddressVO findByAssociatedVmIdAndVmIp(long vmId, String vmIp); + + IPAddressVO findByIpAndNetworkId(long networkId, String ipAddress); } diff --git a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java index b0eef4f3043..73f310fd628 100755 --- a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java +++ b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java @@ -184,6 +184,14 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen return findOneBy(sc); } + @Override + public IPAddressVO findByIpAndNetworkId(long networkId, String ipAddress) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("network", networkId); + sc.setParameters("ipAddress", ipAddress); + return findOneBy(sc); + } + @Override public IPAddressVO findByIpAndDcId(long dcId, String ipAddress) { SearchCriteria sc = AllFieldsSearch.create(); diff --git a/server/src/com/cloud/network/guru/DirectNetworkGuru.java b/server/src/com/cloud/network/guru/DirectNetworkGuru.java index 46a525e214a..8707cfd418c 100755 --- a/server/src/com/cloud/network/guru/DirectNetworkGuru.java +++ b/server/src/com/cloud/network/guru/DirectNetworkGuru.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.network.guru; +import java.util.List; + import javax.ejb.Local; import javax.inject.Inject; @@ -54,7 +56,9 @@ import com.cloud.utils.component.AdapterBase; import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; import com.cloud.vm.Nic.ReservationStrategy; +import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.NicProfile; +import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; @@ -79,7 +83,9 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { UserIpv6AddressDao _ipv6Dao; @Inject Ipv6AddressManager _ipv6Mgr; - + @Inject + NicSecondaryIpDao _nicSecondaryIpDao; + private static final TrafficType[] _trafficTypes = {TrafficType.Guest}; @Override @@ -230,6 +236,16 @@ public class DirectNetworkGuru extends AdapterBase implements NetworkGuru { txn.start(); _networkMgr.markIpAsUnavailable(ip.getId()); _ipAddressDao.unassignIpAddress(ip.getId()); + //unassign nic secondary ip address + s_logger.debug("remove nic " + nic.getId() + " secondary ip "); + List nicSecIps = null; + nicSecIps = _nicSecondaryIpDao.getSecondaryIpAddressesForNic(nic.getId()); + for (String secIp: nicSecIps) { + IPAddressVO pubIp = _ipAddressDao.findByIpAndSourceNetworkId(nic.getNetworkId(), secIp); + _networkMgr.markIpAsUnavailable(pubIp.getId()); + _ipAddressDao.unassignIpAddress(pubIp.getId()); + } + txn.commit(); } } diff --git a/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java b/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java index eafe88e36a4..1c189c44688 100755 --- a/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java +++ b/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java @@ -46,8 +46,10 @@ import org.apache.cloudstack.api.command.user.securitygroup.RevokeSecurityGroupI import org.apache.commons.codec.digest.DigestUtils; import org.apache.log4j.Logger; +import com.amazonaws.services.identitymanagement.model.User; import com.cloud.agent.AgentManager; import com.cloud.agent.api.NetworkRulesSystemVmCommand; +import com.cloud.agent.api.NetworkRulesVmSecondaryIpCommand; import com.cloud.agent.api.SecurityGroupRulesCmd; import com.cloud.agent.api.SecurityGroupRulesCmd.IpPortAndProto; import com.cloud.agent.manager.Commands; @@ -67,12 +69,6 @@ import com.cloud.network.NetworkManager; import com.cloud.network.NetworkModel; import com.cloud.network.security.SecurityGroupWork.Step; import com.cloud.network.security.SecurityRule.SecurityRuleType; -import com.cloud.network.security.dao.SecurityGroupDao; -import com.cloud.network.security.dao.SecurityGroupRuleDao; -import com.cloud.network.security.dao.SecurityGroupRulesDao; -import com.cloud.network.security.dao.SecurityGroupVMMapDao; -import com.cloud.network.security.dao.SecurityGroupWorkDao; -import com.cloud.network.security.dao.VmRulesetLogDao; import com.cloud.network.security.dao.*; import com.cloud.projects.ProjectManager; import com.cloud.tags.dao.ResourceTagDao; @@ -97,6 +93,8 @@ import com.cloud.utils.net.NetUtils; import com.cloud.vm.*; import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; import edu.emory.mathcs.backport.java.util.Collections; @@ -149,6 +147,10 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro ProjectManager _projectMgr; @Inject ResourceTagDao _resourceTagDao; + @Inject + NicDao _nicDao; + @Inject + NicSecondaryIpDao _nicSecIpDao; ScheduledExecutorService _executorPool; ScheduledExecutorService _cleanupExecutor; @@ -489,7 +491,7 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro return affectedVms; } - protected SecurityGroupRulesCmd generateRulesetCmd(String vmName, String guestIp, String guestMac, Long vmId, String signature, long seqnum, Map> ingressRules, Map> egressRules) { + protected SecurityGroupRulesCmd generateRulesetCmd(String vmName, String guestIp, String guestMac, Long vmId, String signature, long seqnum, Map> ingressRules, Map> egressRules, List secIps) { List ingressResult = new ArrayList(); List egressResult = new ArrayList(); for (PortAndProto pAp : ingressRules.keySet()) { @@ -506,7 +508,7 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro egressResult.add(ipPortAndProto); } } - return new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqnum, ingressResult.toArray(new IpPortAndProto[ingressResult.size()]), egressResult.toArray(new IpPortAndProto[egressResult.size()])); + return new SecurityGroupRulesCmd(guestIp, guestMac, vmName, vmId, signature, seqnum, ingressResult.toArray(new IpPortAndProto[ingressResult.size()]), egressResult.toArray(new IpPortAndProto[egressResult.size()]), secIps); } protected void handleVmStopped(VMInstanceVO vm) { @@ -947,8 +949,19 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro Map> egressRules = generateRulesForVM(userVmId, SecurityRuleType.EgressRule); agentId = vm.getHostId(); if (agentId != null) { + // get nic secondary ip address + String privateIp = vm.getPrivateIpAddress(); + NicVO nic = _nicDao.findByIp4AddressAndVmId(privateIp, vm.getId()); + List nicSecIps = null; + if (nic != null) { + if (nic.getSecondaryIp()) { + //get secondary ips of the vm + long networkId = nic.getNetworkId(); + nicSecIps = _nicSecIpDao.getSecondaryIpAddressesForNic(nic.getId()); + } + } SecurityGroupRulesCmd cmd = generateRulesetCmd( vm.getInstanceName(), vm.getPrivateIpAddress(), vm.getPrivateMacAddress(), vm.getId(), generateRulesetSignature(ingressRules, egressRules), seqnum, - ingressRules, egressRules); + ingressRules, egressRules, nicSecIps); Commands cmds = new Commands(cmd); try { _agentMgr.send(agentId, cmds, _answerListener); @@ -1272,4 +1285,66 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro return true; } } + + @Override + public boolean securityGroupRulesForVmSecIp(Long nicId, Long networkId, + String secondaryIp, boolean ruleAction) { + + String vmMac = null; + String vmName = null; + + if (secondaryIp == null || nicId == null || networkId == null) { + throw new InvalidParameterValueException("Vm nicId or networkId or secondaryIp can't be null"); + } + + NicVO nic = _nicDao.findById(nicId); + Long vmId = nic.getInstanceId(); + + // Validate parameters + List vmSgGrps = getSecurityGroupsForVm(vmId); + if (vmSgGrps == null) { + s_logger.debug("Vm is not in any Security group "); + return true; + } + + Account caller = UserContext.current().getCaller(); + + for (SecurityGroupVO securityGroup: vmSgGrps) { + Account owner = _accountMgr.getAccount(securityGroup.getAccountId()); + if (owner == null) { + throw new InvalidParameterValueException("Unable to find security group owner by id=" + securityGroup.getAccountId()); + } + // Verify permissions + _accountMgr.checkAccess(caller, null, true, securityGroup); + } + + UserVm vm = _userVMDao.findById(vmId); + if (vm.getType() != VirtualMachine.Type.User) { + throw new InvalidParameterValueException("Can't configure the SG ipset, arprules rules for the non user vm"); + } + + if (vm != null) { + vmMac = vm.getPrivateMacAddress(); + vmName = vm.getInstanceName(); + if (vmMac == null || vmName == null) { + throw new InvalidParameterValueException("vm name or vm mac can't be null"); + } + } + + //create command for the to add ip in ipset and arptables rules + NetworkRulesVmSecondaryIpCommand cmd = new NetworkRulesVmSecondaryIpCommand(vmName, vmMac, secondaryIp, ruleAction); + s_logger.debug("Asking agent to configure rules for vm secondary ip"); + Commands cmds = null; + + cmds = new Commands(cmd); + try { + _agentMgr.send(vm.getHostId(), cmds); + } catch (AgentUnavailableException e) { + s_logger.debug(e.toString()); + } catch (OperationTimedoutException e) { + s_logger.debug(e.toString()); + } + + return true; + } } diff --git a/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java b/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java index a3a0fc300f9..a42881ec905 100644 --- a/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java +++ b/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java @@ -40,6 +40,7 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.Profiler; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.mgmt.JmxUtil; +import com.cloud.vm.NicVO; import com.cloud.vm.VirtualMachine.State; import com.cloud.network.security.SecurityRule.SecurityRuleType; @@ -169,9 +170,19 @@ public class SecurityGroupManagerImpl2 extends SecurityGroupManagerImpl{ Map> egressRules = generateRulesForVM(userVmId, SecurityRuleType.EgressRule); Long agentId = vm.getHostId(); if (agentId != null) { + String privateIp = vm.getPrivateIpAddress(); + NicVO nic = _nicDao.findByIp4AddressAndVmId(privateIp, vm.getId()); + List nicSecIps = null; + if (nic != null) { + if (nic.getSecondaryIp()) { + //get secondary ips of the vm + long networkId = nic.getNetworkId(); + nicSecIps = _nicSecIpDao.getSecondaryIpAddressesForNic(nic.getId()); + } + } SecurityGroupRulesCmd cmd = generateRulesetCmd(vm.getInstanceName(), vm.getPrivateIpAddress(), vm.getPrivateMacAddress(), vm.getId(), null, - work.getLogsequenceNumber(), ingressRules, egressRules); + work.getLogsequenceNumber(), ingressRules, egressRules, nicSecIps); cmd.setMsId(_serverId); if (s_logger.isDebugEnabled()) { s_logger.debug("SecurityGroupManager v2: sending ruleset update for vm " + vm.getInstanceName() + diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 6b2f762a74d..88086ced461 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -1360,13 +1360,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use + " as a part of vm id=" + vmId + " expunge because resource is unavailable", e); } - //remove vm secondary ip addresses - if (_networkMgr.removeVmSecondaryIps(vmId)) { - s_logger.debug("Removed vm " + vmId + " secondary ip address of the VM Nics as a part of expunge process"); - } else { - success = false; - s_logger.warn("Fail to remove secondary ip address of vm " + vmId + " Nics as a part of expunge process"); - } return success; } diff --git a/server/src/com/cloud/vm/dao/NicDao.java b/server/src/com/cloud/vm/dao/NicDao.java index 794bacc6e8b..35d719131bb 100644 --- a/server/src/com/cloud/vm/dao/NicDao.java +++ b/server/src/com/cloud/vm/dao/NicDao.java @@ -60,4 +60,6 @@ public interface NicDao extends GenericDao { NicVO findByIp4AddressAndNetworkIdAndInstanceId(long networkId, long instanceId, String ip4Address); List listByVmIdAndNicId(Long vmId, Long nicId); + + NicVO findByIp4AddressAndVmId(String ip4Address, long instance); } diff --git a/server/src/com/cloud/vm/dao/NicDaoImpl.java b/server/src/com/cloud/vm/dao/NicDaoImpl.java index 44911740e96..b9ec72ee7c9 100644 --- a/server/src/com/cloud/vm/dao/NicDaoImpl.java +++ b/server/src/com/cloud/vm/dao/NicDaoImpl.java @@ -212,4 +212,13 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { sc.setParameters("nicid", nicId); return listBy(sc); } + + @Override + public NicVO findByIp4AddressAndVmId(String ip4Address, long instance) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("address", ip4Address); + sc.setParameters("instance", instance); + return findOneBy(sc); + } + } diff --git a/server/test/com/cloud/network/MockNetworkManagerImpl.java b/server/test/com/cloud/network/MockNetworkManagerImpl.java index 80043102648..eb43cce0b9e 100755 --- a/server/test/com/cloud/network/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/network/MockNetworkManagerImpl.java @@ -32,6 +32,7 @@ import org.springframework.stereotype.Component; import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; import com.cloud.dc.DataCenter; +import com.cloud.dc.Pod; import com.cloud.dc.Vlan.VlanType; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; @@ -854,11 +855,6 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage return null; } - @Override - public boolean removeVmSecondaryIps(long vmId) { - // TODO Auto-generated method stub - return false; - } @Override public List listVmNics(Long vmId, Long nicId) { @@ -871,4 +867,18 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage // TODO Auto-generated method stub return null; } + + @Override + public String allocatePublicIpForGuestNic(Long networkId, DataCenter dc, + Pod pod, Account caller, String requestedIp) + throws InsufficientAddressCapacityException { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean removeVmSecondaryIpsOfNic(long nicId) { + // TODO Auto-generated method stub + return false; + } } diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index 63ef8744be8..c798cdf7810 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -34,6 +34,7 @@ import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.dc.DataCenter; +import com.cloud.dc.Pod; import com.cloud.dc.Vlan.VlanType; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; @@ -1365,12 +1366,6 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage - @Override - public boolean removeVmSecondaryIps(long vmId) { - // TODO Auto-generated method stub - return false; - } - @@ -1390,4 +1385,30 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkManage // TODO Auto-generated method stub return null; } + + + + + + @Override + public String allocatePublicIpForGuestNic(Long networkId, DataCenter dc, + Pod pod, Account caller, String requestedIp) + throws InsufficientAddressCapacityException { + // TODO Auto-generated method stub + return null; + } + + + + + + + + + + @Override + public boolean removeVmSecondaryIpsOfNic(long nicId) { + // TODO Auto-generated method stub + return false; + } }