shwstppr commented on a change in pull request #5786:
URL: https://github.com/apache/cloudstack/pull/5786#discussion_r821465950
##########
File path:
server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
##########
@@ -2583,6 +2598,21 @@ private void createDefaultEgressFirewallRule(final
List<FirewallRule> rules, fin
}
}
+ private void createDefaultEgressIpv6FirewallRule(final List<FirewallRule>
rules, final long networkId) {
+ final NetworkVO network = _networkDao.findById(networkId);
+
if(!_networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId())) {
+ return;
+ }
+ // Since not all networks will IPv6 supported, add a system rule for
IPv6 networks
+ final List<String> sourceCidr = new ArrayList<String>();
+ final List<String> destCidr = new ArrayList<String>();
+ sourceCidr.add(network.getIp6Cidr());
+ destCidr.add(NetUtils.ALL_IP6_CIDRS);
+ final FirewallRule rule = new FirewallRuleVO(null, null, null, null,
"all", networkId, network.getAccountId(), network.getDomainId(),
Purpose.Ipv6Firewall, sourceCidr,
Review comment:
All egress rules are not allowed by default. It would depend on
network's egress policy.
A rule for `all` protocols is added here to make python script in router
understand that it needs to configure IPv6 firewall for the network, allow or
deny logic based on policy is present in
`systemvm/debian/opt/cloud/bin/configure.py`
##########
File path: server/src/main/java/com/cloud/network/Ipv6ServiceImpl.java
##########
@@ -0,0 +1,517 @@
+// 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;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import org.apache.cloudstack.api.command.user.ipv6.CreateIpv6FirewallRuleCmd;
+import org.apache.cloudstack.api.command.user.ipv6.DeleteIpv6FirewallRuleCmd;
+import org.apache.cloudstack.api.command.user.ipv6.ListIpv6FirewallRulesCmd;
+import org.apache.cloudstack.api.command.user.ipv6.UpdateIpv6FirewallRuleCmd;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.managed.context.ManagedContextRunnable;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Logger;
+
+import com.cloud.configuration.Resource;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenterGuestIpv6Prefix;
+import com.cloud.dc.DataCenterGuestIpv6PrefixVO;
+import com.cloud.dc.Vlan;
+import com.cloud.dc.VlanVO;
+import com.cloud.dc.dao.DataCenterGuestIpv6PrefixDao;
+import com.cloud.dc.dao.VlanDao;
+import com.cloud.event.ActionEvent;
+import com.cloud.event.ActionEventUtils;
+import com.cloud.event.EventTypes;
+import com.cloud.event.EventVO;
+import com.cloud.event.UsageEventUtils;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.network.dao.FirewallRulesDao;
+import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao;
+import com.cloud.network.dao.NetworkDetailsDao;
+import com.cloud.network.firewall.FirewallService;
+import com.cloud.network.guru.PublicNetworkGuru;
+import com.cloud.network.rules.FirewallManager;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.FirewallRuleVO;
+import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.utils.Pair;
+import com.cloud.utils.component.ComponentLifecycleBase;
+import com.cloud.utils.concurrency.NamedThreadFactory;
+import com.cloud.utils.db.GlobalLock;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallbackWithException;
+import com.cloud.utils.db.TransactionStatus;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.vm.DomainRouterVO;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.NicVO;
+import com.cloud.vm.dao.DomainRouterDao;
+import com.cloud.vm.dao.NicDao;
+import com.googlecode.ipv6.IPv6Address;
+import com.googlecode.ipv6.IPv6Network;
+import com.googlecode.ipv6.IPv6NetworkMask;
+
+public class Ipv6ServiceImpl extends ComponentLifecycleBase implements
Ipv6Service {
+
+ public static final Logger s_logger =
Logger.getLogger(Ipv6ServiceImpl.class.getName());
+
+ ScheduledExecutorService _ipv6GuestPrefixSubnetNetworkMapStateScanner;
+
+ @Inject
+ NetworkOfferingDao networkOfferingDao;
+ @Inject
+ VlanDao vlanDao;
+ @Inject
+ DataCenterGuestIpv6PrefixDao dataCenterGuestIpv6PrefixDao;
+ @Inject
+ Ipv6GuestPrefixSubnetNetworkMapDao ipv6GuestPrefixSubnetNetworkMapDao;
+ @Inject
+ FirewallRulesDao firewallDao;
+ @Inject
+ FirewallService firewallService;
+ @Inject
+ NetworkDetailsDao networkDetailsDao;
+ @Inject
+ NicDao nicDao;
+ @Inject
+ DomainRouterDao domainRouterDao;
+ @Inject
+ AccountManager accountManager;
+ @Inject
+ NetworkModel networkModel;
+ @Inject
+ FirewallManager firewallManager;
+
+ protected void releaseIpv6Subnet(long subnetId) {
+ Ipv6GuestPrefixSubnetNetworkMapVO ipv6GuestPrefixSubnetNetworkMapVO =
ipv6GuestPrefixSubnetNetworkMapDao.createForUpdate(subnetId);
+
ipv6GuestPrefixSubnetNetworkMapVO.setState(Ipv6GuestPrefixSubnetNetworkMap.State.Free);
+ ipv6GuestPrefixSubnetNetworkMapVO.setNetworkId(null);
+ ipv6GuestPrefixSubnetNetworkMapVO.setUpdated(new Date());
+
ipv6GuestPrefixSubnetNetworkMapDao.update(ipv6GuestPrefixSubnetNetworkMapVO.getId(),
ipv6GuestPrefixSubnetNetworkMapVO);
+ }
+
+ @Override
+ public boolean start() {
+
_ipv6GuestPrefixSubnetNetworkMapStateScanner.scheduleWithFixedDelay(new
Ipv6GuestPrefixSubnetNetworkMapStateScanner(), 300, 30*60, TimeUnit.SECONDS);
+ return true;
+ }
+
+ @Override
+ public boolean configure(String name, Map<String, Object> params) throws
ConfigurationException {
+ _name = name;
+ _configParams = params;
+ _ipv6GuestPrefixSubnetNetworkMapStateScanner =
Executors.newScheduledThreadPool(1, new
NamedThreadFactory("Ipv6GuestPrefixSubnet-State-Scanner"));
+
+ return true;
+ }
+
+ @Override
+ public List<Class<?>> getCommands() {
+ final List<Class<?>> cmdList = new ArrayList<Class<?>>();
+ cmdList.add(CreateIpv6FirewallRuleCmd.class);
+ cmdList.add(ListIpv6FirewallRulesCmd.class);
+ cmdList.add(UpdateIpv6FirewallRuleCmd.class);
+ cmdList.add(DeleteIpv6FirewallRuleCmd.class);
+ return cmdList;
+ }
+
+ @Override
+ public String getConfigComponentName() {
+ return Ipv6Service.class.getSimpleName();
+ }
+
+ @Override
+ public ConfigKey<?>[] getConfigKeys() {
+ return new ConfigKey<?>[] {
+ Ipv6NetworkOfferingCreationEnabled
+ };
+ }
+
+ @Override
+ public Pair<Integer, Integer>
getUsedTotalIpv6SubnetForPrefix(DataCenterGuestIpv6Prefix prefix) {
+ List<Ipv6GuestPrefixSubnetNetworkMapVO> usedSubnets =
ipv6GuestPrefixSubnetNetworkMapDao.listUsedByPrefix(prefix.getId());
+ final IPv6Network ip6Prefix =
IPv6Network.fromString(prefix.getPrefix());
+ Iterator<IPv6Network> splits =
ip6Prefix.split(IPv6NetworkMask.fromPrefixLength(IPV6_SLAAC_CIDR_NETMASK));
+ int total = 0;
+ while(splits.hasNext()) {
+ total++;
+ splits.next();
+ }
+ return new Pair<>(usedSubnets.size(), total);
+ }
+
+ @Override
+ public Pair<Integer, Integer> getUsedTotalIpv6SubnetForZone(long zoneId) {
+ int used = 0;
+ int total = 0;
+ List<DataCenterGuestIpv6PrefixVO> prefixes =
dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId);
+ for (DataCenterGuestIpv6PrefixVO prefix : prefixes) {
+ Pair<Integer, Integer> usedTotal =
getUsedTotalIpv6SubnetForPrefix(prefix);
+ used += usedTotal.first();
+ total += usedTotal.second();
+ }
+ return new Pair<>(used, total);
+ }
+
+ public Pair<String, String> preAllocateIpv6SubnetForNetwork(long zoneId)
throws ResourceAllocationException {
+ List<DataCenterGuestIpv6PrefixVO> prefixes =
dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId);
+ if (CollectionUtils.isEmpty(prefixes)) {
+ s_logger.error(String.format("IPv6 prefixes not found for the zone
ID: %d", zoneId));
+ throw new ResourceAllocationException("Unable to allocate IPv6
network", Resource.ResourceType.network);
+ }
+ Ipv6GuestPrefixSubnetNetworkMapVO ip6Subnet = null;
+ for (DataCenterGuestIpv6PrefixVO prefix : prefixes) {
+ ip6Subnet =
ipv6GuestPrefixSubnetNetworkMapDao.findFirstAvailable(prefix.getId());
+ if (ip6Subnet == null) {
+ Ipv6GuestPrefixSubnetNetworkMapVO last =
ipv6GuestPrefixSubnetNetworkMapDao.findLast(prefix.getId());
+ String lastUsedSubnet = last != null ? last.getSubnet() : null;
+ final IPv6Network ip6Prefix =
IPv6Network.fromString(prefix.getPrefix());
+ Iterator<IPv6Network> splits =
ip6Prefix.split(IPv6NetworkMask.fromPrefixLength(IPV6_SLAAC_CIDR_NETMASK));
+ while (splits.hasNext()) {
+ IPv6Network i = splits.next();
+ if (lastUsedSubnet == null) {
+ ip6Subnet = new
Ipv6GuestPrefixSubnetNetworkMapVO(prefix.getId(), i.toString(), null,
Ipv6GuestPrefixSubnetNetworkMap.State.Allocating);
+ break;
+ }
+ if (i.toString().equals(lastUsedSubnet)) {
+ lastUsedSubnet = null;
+ }
+ }
+ }
+ if (ip6Subnet != null) {
+ break;
+ }
+ }
+ if (ip6Subnet == null) {
+ throw new ResourceAllocationException("Unable to allocate IPv6
guest subnet for the network", Resource.ResourceType.network);
+ }
+ ip6Subnet.setUpdated(new Date());
+ if
(Ipv6GuestPrefixSubnetNetworkMap.State.Free.equals(ip6Subnet.getState())) {
+
ip6Subnet.setState(Ipv6GuestPrefixSubnetNetworkMap.State.Allocating);
+ ipv6GuestPrefixSubnetNetworkMapDao.update(ip6Subnet.getId(),
ip6Subnet);
+ } else {
+ ipv6GuestPrefixSubnetNetworkMapDao.persist(ip6Subnet);
+ }
+ IPv6Network network = IPv6Network.fromString(ip6Subnet.getSubnet());
+ return new Pair<>(network.getFirst().toString(), network.toString());
+ }
+
+ @Override
+ public void assignIpv6SubnetToNetwork(String subnet, long networkId) {
+ Ipv6GuestPrefixSubnetNetworkMapVO ipv6GuestPrefixSubnetNetworkMapVO =
ipv6GuestPrefixSubnetNetworkMapDao.findBySubnet(subnet);
+ if (ipv6GuestPrefixSubnetNetworkMapVO != null) {
+ ipv6GuestPrefixSubnetNetworkMapVO =
ipv6GuestPrefixSubnetNetworkMapDao.createForUpdate(ipv6GuestPrefixSubnetNetworkMapVO.getId());
+
ipv6GuestPrefixSubnetNetworkMapVO.setState(Ipv6GuestPrefixSubnetNetworkMap.State.Allocated);
+ ipv6GuestPrefixSubnetNetworkMapVO.setNetworkId(networkId);
+ ipv6GuestPrefixSubnetNetworkMapVO.setUpdated(new Date());
+
ipv6GuestPrefixSubnetNetworkMapDao.update(ipv6GuestPrefixSubnetNetworkMapVO.getId(),
ipv6GuestPrefixSubnetNetworkMapVO);
+ }
+ }
+
+ @Override
+ public void releaseIpv6SubnetForNetwork(long networkId) {
+ Ipv6GuestPrefixSubnetNetworkMapVO ipv6GuestPrefixSubnetNetworkMapVO =
ipv6GuestPrefixSubnetNetworkMapDao.findByNetworkId(networkId);
+ if (ipv6GuestPrefixSubnetNetworkMapVO != null) {
+ releaseIpv6Subnet(ipv6GuestPrefixSubnetNetworkMapVO.getId());
+ }
+ }
+
+ public Pair<String, ? extends Vlan> assignPublicIpv6ToNetwork(Network
network, String nicMacAddress) {
+ final List<VlanVO> ranges =
vlanDao.listVlansWithIpV6RangeByPhysicalNetworkId(network.getPhysicalNetworkId());
+ if (CollectionUtils.isEmpty(ranges)) {
+ s_logger.error(String.format("Unable to find IPv6 range for the
zone ID: %d", network.getDataCenterId()));
+ throw new CloudRuntimeException(String.format("Cannot find IPv6
address for network %s", network.getName()));
+ }
+ Collections.shuffle(ranges);
+ VlanVO selectedVlan = ranges.get(0);
+ IPv6Network iPv6Network =
IPv6Network.fromString(selectedVlan.getIp6Cidr());
+ if (iPv6Network.getNetmask().asPrefixLength() <
IPV6_SLAAC_CIDR_NETMASK) {
+ Iterator<IPv6Network> splits =
iPv6Network.split(IPv6NetworkMask.fromPrefixLength(IPV6_SLAAC_CIDR_NETMASK));
+ if (splits.hasNext()) {
+ splits.next();
+ }
+ if (splits.hasNext()) {
+ iPv6Network = splits.next();
+ }
+ }
+ IPv6Address ipv6Addr = NetUtils.EUI64Address(iPv6Network,
nicMacAddress);
+ String event = EventTypes.EVENT_NET_IP6_ASSIGN;
+ String description = String.format("Assigned public IPv6 address: %s
for network ID: %s", ipv6Addr, network.getUuid());
+
ActionEventUtils.onCompletedActionEvent(CallContext.current().getCallingUserId(),
network.getAccountId(), EventVO.LEVEL_INFO, event, description, 0);
+ final boolean usageHidden =
networkDetailsDao.isNetworkUsageHidden(network.getId());
+ final String guestType = selectedVlan.getVlanType().toString();
+ UsageEventUtils.publishUsageEvent(event, network.getAccountId(),
network.getDataCenterId(), 0L,
+ ipv6Addr.toString(), false, guestType, false, usageHidden,
+ IPv6Network.class.getName(), null);
+ return new Pair<>(ipv6Addr.toString(), selectedVlan);
+ }
+
+ @Override
+ public void updateNicIpv6(NicProfile nic, DataCenter dc, Network network) {
+ boolean isIpv6Supported =
networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId());
+ if (nic.getIPv6Address() == null && isIpv6Supported) {
+ Pair<String, ? extends Vlan> publicIpv6AddressVlanPair =
assignPublicIpv6ToNetwork(network, nic.getMacAddress());
+ final Vlan vlan = publicIpv6AddressVlanPair.second();
+ final String routerIpv6 = publicIpv6AddressVlanPair.first();
+ final String routerIpv6Gateway = vlan.getIp6Gateway();
+ final String routerIpv6Cidr = vlan.getIp6Cidr();
+ nic.setIPv6Address(routerIpv6);
+ nic.setIPv6Gateway(routerIpv6Gateway);
+ nic.setIPv6Cidr(routerIpv6Cidr);
+ if (nic.getIPv4Address() != null) {
+ nic.setFormat(Networks.AddressFormat.DualStack);
+ } else {
+ nic.setFormat(Networks.AddressFormat.Ip6);
+ }
+ nic.setIPv6Dns1(dc.getIp6Dns1());
+ nic.setIPv6Dns2(dc.getIp6Dns2());
+ }
+ }
+
+ @Override
+ public void releasePublicIpv6ForNic(Network network, String
nicIpv6Address) {
+ String event = EventTypes.EVENT_NET_IP6_RELEASE;
+ String description = String.format("Releasing public IPv6 address: %s
from network ID: %s", nicIpv6Address, network.getUuid());
+
ActionEventUtils.onCompletedActionEvent(CallContext.current().getCallingUserId(),
network.getAccountId(), EventVO.LEVEL_INFO, event, description, 0);
+ final boolean usageHidden =
networkDetailsDao.isNetworkUsageHidden(network.getId());
+ UsageEventUtils.publishUsageEvent(event, network.getAccountId(),
network.getDataCenterId(), 0L,
+ nicIpv6Address, false,
Vlan.VlanType.VirtualNetwork.toString(), false, usageHidden,
+ IPv6Address.class.getName(), null);
+ }
+
+ @Override
+ public List<String> getPublicIpv6AddressesForNetwork(Network network) {
+ List<String> addresses = new ArrayList<>();
+ List<DomainRouterVO> routers =
domainRouterDao.findByNetwork(network.getId());
+ for (DomainRouterVO router : routers) {
+ List<NicVO> nics = nicDao.listByVmId(router.getId());
+ for (NicVO nic : nics) {
+ String address = nic.getIPv6Address();
+ if
(!PublicNetworkGuru.class.getSimpleName().equals(nic.getReserver()) ||
StringUtils.isEmpty(address)) {
+ continue;
+ }
+ addresses.add(address);
+ }
+ }
+ return addresses;
+ }
+
+ @Override
+ public Pair<List<? extends FirewallRule>, Integer>
listIpv6FirewallRules(ListIpv6FirewallRulesCmd listIpv6FirewallRulesCmd) {
+ return firewallService.listFirewallRules(listIpv6FirewallRulesCmd);
+ }
+
+ @Override
+ @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_OPEN, eventDescription
= "creating IPv6 firewall rule", create = true)
+ public FirewallRule createIpv6FirewallRule(CreateIpv6FirewallRuleCmd cmd)
throws NetworkRuleConflictException {
+ final Account caller = CallContext.current().getCallingAccount();
+ final long networkId = cmd.getNetworkId();
+ final Integer portStart = cmd.getSourcePortStart();
+ final Integer portEnd = cmd.getSourcePortEnd();
+ final FirewallRule.TrafficType trafficType = cmd.getTrafficType();
+ final String protocol = cmd.getProtocol();
+ final Integer icmpCode = cmd.getIcmpCode();
+ final Integer icmpType = cmd.getIcmpType();
+ final boolean forDisplay = cmd.isDisplay();
+ final FirewallRule.FirewallRuleType type =
FirewallRule.FirewallRuleType.User;
+ final List<String> sourceCidrList = cmd.getSourceCidrList();
+ final List<String> destinationCidrList = cmd.getDestinationCidrList();
+
+ if (portStart != null && !NetUtils.isValidPort(portStart)) {
+ throw new InvalidParameterValueException("publicPort is an invalid
value: " + portStart);
+ }
+ if (portEnd != null && !NetUtils.isValidPort(portEnd)) {
+ throw new InvalidParameterValueException("Public port range is an
invalid value: " + portEnd);
+ }
+
+ // start port can't be bigger than end port
+ if (portStart != null && portEnd != null && portStart > portEnd) {
+ throw new InvalidParameterValueException("Start port can't be
bigger than end port");
+ }
+
+ Network network = networkModel.getNetwork(networkId);
+ assert network != null : "Can't create rule as network is null?";
+
+ final long accountId = network.getAccountId();
+ final long domainId = network.getDomainId();
+
+ if (FirewallRule.TrafficType.Egress.equals(trafficType)) {
+ accountManager.checkAccess(caller, null, true, network);
+ }
+
+ // Verify that the network guru supports the protocol specified
+ Map<Network.Capability, String> caps =
networkModel.getNetworkServiceCapabilities(network.getId(),
Network.Service.Firewall);
+
+ if (caps != null) {
+ String supportedProtocols;
+ String supportedTrafficTypes = null;
+ supportedTrafficTypes =
caps.get(Network.Capability.SupportedTrafficDirection).toLowerCase();
+
+ if (trafficType == FirewallRule.TrafficType.Egress) {
+ supportedProtocols =
caps.get(Network.Capability.SupportedEgressProtocols).toLowerCase();
+ } else {
+ supportedProtocols =
caps.get(Network.Capability.SupportedProtocols).toLowerCase();
+ }
+
+ if (!supportedProtocols.contains(protocol.toLowerCase())) {
+ throw new
InvalidParameterValueException(String.format("Protocol %s is not supported in
zone", protocol));
+ } else if
(!supportedTrafficTypes.contains(trafficType.toString().toLowerCase())) {
+ throw new InvalidParameterValueException("Traffic Type " +
trafficType + " is currently supported by Firewall in network " + networkId);
+ }
+ }
+
+ // icmp code and icmp type can't be passed in for any other protocol
rather than icmp
+ if (!protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (icmpCode !=
null || icmpType != null)) {
+ throw new InvalidParameterValueException("Can specify icmpCode and
icmpType for ICMP protocol only");
+ }
+
+ if (protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (portStart !=
null || portEnd != null)) {
+ throw new InvalidParameterValueException("Can't specify start/end
port when protocol is ICMP");
+ }
+
+ return Transaction.execute(new
TransactionCallbackWithException<FirewallRuleVO,
NetworkRuleConflictException>() {
+ @Override
+ public FirewallRuleVO doInTransaction(TransactionStatus status)
throws NetworkRuleConflictException {
+ FirewallRuleVO newRule =
+ new FirewallRuleVO(null, null, portStart, portEnd,
protocol.toLowerCase(), networkId, accountId, domainId,
FirewallRule.Purpose.Ipv6Firewall,
+ sourceCidrList, destinationCidrList, icmpCode,
icmpType, null, trafficType);
+ newRule.setType(type);
+ newRule.setDisplay(forDisplay);
+ newRule = firewallDao.persist(newRule);
+
+ if (FirewallRule.FirewallRuleType.User.equals(type)) {
+ firewallManager.detectRulesConflict(newRule);
+ }
+
+ if (!firewallDao.setStateToAdd(newRule)) {
+ throw new CloudRuntimeException("Unable to update the
state to add for " + newRule);
+ }
+ CallContext.current().setEventDetails("Rule Id: " +
newRule.getId());
+
+ return newRule;
+ }
+ });
+ }
+
+ @Override
+ @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_CLOSE, eventDescription
= "revoking IPv6 firewall rule", async = true)
+ public boolean revokeIpv6FirewallRule(Long id) {
+ FirewallRuleVO rule = firewallDao.findById(id);
+ if (rule == null) {
+ throw new InvalidParameterValueException(String.format("Unable to
find IPv6 firewall rule with id %d", id));
+ }
+ if (FirewallRule.TrafficType.Ingress.equals(rule.getTrafficType())) {
+ return firewallManager.revokeIngressFirewallRule(rule.getId(),
true);
+ }
+ return firewallManager.revokeEgressFirewallRule(rule.getId(), true);
+ }
+
+ @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_UPDATE,
eventDescription = "updating IPv6 firewall rule", async = true)
+ public FirewallRule updateIpv6FirewallRule(UpdateIpv6FirewallRuleCmd cmd) {
+ final long id = cmd.getId();
+ final boolean forDisplay = cmd.isDisplay();
+ FirewallRuleVO rule = firewallDao.findById(id);
+ if (rule == null) {
+ throw new InvalidParameterValueException(String.format("Unable to
find IPv6 firewall rule with id %d", id));
+ }
+ if (FirewallRule.TrafficType.Ingress.equals(rule.getTrafficType())) {
+ return firewallManager.updateIngressFirewallRule(rule.getId(),
null, forDisplay);
+ }
+ return firewallManager.updateEgressFirewallRule(rule.getId(), null,
forDisplay);
+ }
+
+ @Override
+ public FirewallRule getIpv6FirewallRule(Long entityId) {
+ return firewallDao.findById(entityId);
+ }
+
+ @Override
+ public boolean applyIpv6FirewallRule(long id) {
+ FirewallRuleVO rule = firewallDao.findById(id);
+ if (rule == null) {
+ s_logger.error(String.format("Unable to find IPv6 firewall rule
with ID: %d", id));
+ return false;
+ }
+ if (!FirewallRule.Purpose.Ipv6Firewall.equals(rule.getPurpose())) {
+ s_logger.error(String.format("Cannot apply IPv6 firewall rule with
ID: %d as purpose %s is not %s", id, rule.getPurpose(),
FirewallRule.Purpose.Ipv6Firewall));
+ }
+ s_logger.debug(String.format("Applying IPv6 firewall rules for rule
with ID: %s", rule.getUuid()));
+ List<FirewallRuleVO> rules =
firewallDao.listByNetworkPurposeTrafficType(rule.getNetworkId(),
rule.getPurpose(), FirewallRule.TrafficType.Egress);
+
rules.addAll(firewallDao.listByNetworkPurposeTrafficType(rule.getNetworkId(),
FirewallRule.Purpose.Ipv6Firewall, FirewallRule.TrafficType.Ingress));
+ return firewallManager.applyFirewallRules(rules, false,
CallContext.current().getCallingAccount());
+ }
+
+ public class Ipv6GuestPrefixSubnetNetworkMapStateScanner extends
ManagedContextRunnable {
+ @Override
+ protected void runInContext() {
+ GlobalLock gcLock =
GlobalLock.getInternLock("Ipv6GuestPrefixSubnetNetworkMap.State.Scanner.Lock");
+ try {
+ if (gcLock.lock(3)) {
+ try {
+ reallyRun();
+ } finally {
+ gcLock.unlock();
+ }
+ }
+ } finally {
+ gcLock.releaseRef();
+ }
+ }
+
+ public void reallyRun() {
+ try {
+ List<Ipv6GuestPrefixSubnetNetworkMapVO> subnets =
ipv6GuestPrefixSubnetNetworkMapDao.findPrefixesInStates(Ipv6GuestPrefixSubnetNetworkMap.State.Allocating);
+ for (Ipv6GuestPrefixSubnetNetworkMapVO subnet : subnets) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info(String.format("Running state scanned on
Ipv6GuestPrefixSubnetNetworkMap : %s", subnet.getSubnet()));
+ }
+ try {
+ if ((new Date()).getTime() -
subnet.getUpdated().getTime() < 30*60*1000) {
Review comment:
done
##########
File path:
api/src/main/java/org/apache/cloudstack/api/command/user/ipv6/CreateIpv6FirewallRuleCmd.java
##########
@@ -0,0 +1,245 @@
+// 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 org.apache.cloudstack.api.command.user.ipv6;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCreateCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.FirewallResponse;
+import org.apache.cloudstack.api.response.FirewallRuleResponse;
+import org.apache.cloudstack.api.response.NetworkResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Logger;
+
+import com.cloud.event.EventTypes;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.Ipv6Service;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.user.Account;
+import com.cloud.utils.net.NetUtils;
+
+@APICommand(name = CreateIpv6FirewallRuleCmd.APINAME, description = "Creates
an Ipv6 firewall rule in the given network (the network has to belong to VPC)",
responseObject = FirewallRuleResponse.class, requestHasSensitiveInfo = false,
responseHasSensitiveInfo = false)
+public class CreateIpv6FirewallRuleCmd extends BaseAsyncCreateCmd {
+ public static final Logger s_logger =
Logger.getLogger(CreateIpv6FirewallRuleCmd.class.getName());
+
+ public static final String APINAME = "createIpv6FirewallRule";
+
+ @Inject
+ Ipv6Service ipv6Service;
+ // ///////////////////////////////////////////////////
+ // ////////////// API parameters /////////////////////
+ // ///////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.PROTOCOL, type = CommandType.STRING,
required = true, description = "the protocol for the Ipv6 firewall rule. Valid
values are TCP/UDP/ICMP/ALL or valid protocol number")
+ private String protocol;
+
+ @Parameter(name = ApiConstants.START_PORT, type = CommandType.INTEGER,
description = "the starting port of Ipv6 firewall rule")
+ private Integer publicStartPort;
+
+ @Parameter(name = ApiConstants.END_PORT, type = CommandType.INTEGER,
description = "the ending port of Ipv6 firewall rule")
+ private Integer publicEndPort;
+
+ @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST,
collectionType = CommandType.STRING, description = "the source CIDR list to
allow traffic from. Multiple entries must be separated by a single comma
character (,).")
+ private List<String> sourceCidrList;
+
+ @Parameter(name = ApiConstants.DEST_CIDR_LIST, type = CommandType.LIST,
collectionType = CommandType.STRING, description = "the destination CIDR list
to allow traffic to. Multiple entries must be separated by a single comma
character (,).")
+ private List<String> destinationCidrlist;
+
+ @Parameter(name = ApiConstants.ICMP_TYPE, type = CommandType.INTEGER,
description = "type of the ICMP message being sent")
+ private Integer icmpType;
+
+ @Parameter(name = ApiConstants.ICMP_CODE, type = CommandType.INTEGER,
description = "error code for this ICMP message")
+ private Integer icmpCode;
+
+ @Parameter(name = ApiConstants.NETWORK_ID, type = CommandType.UUID,
entityType = NetworkResponse.class, description = "The network of the VM the
Ipv6 firewall rule will be created for", required = true)
+ private Long networkId;
+
+ @Parameter(name = ApiConstants.TRAFFIC_TYPE, type = CommandType.STRING,
description = "the traffic type for the Ipv6 firewall rule, can be ingress or
egress, defaulted to ingress if not specified")
+ private String trafficType;
+
+ @Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN,
description = "an optional field, whether to the display the rule to the end
user or not", authorized = {RoleType.Admin})
+ private Boolean display;
+
+ // ///////////////////////////////////////////////////
+ // ///////////////// Accessors ///////////////////////
+ // ///////////////////////////////////////////////////
+
+ @Override
+ public boolean isDisplay() {
+ if (display != null) {
+ return display;
+ } else {
+ return true;
+ }
+ }
+
+ public String getProtocol() {
+ String p = protocol.trim();
+ // Deal with ICMP(protocol number 1) specially because it need to be
paired with icmp type and code
+ if (StringUtils.isNumeric(p)) {
+ int protoNumber = Integer.parseInt(p);
+ if (protoNumber == 1) {
+ p = "icmp";
+ }
+ }
+ return p;
+ }
+
+ public List<String> getSourceCidrList() {
+ if (sourceCidrList != null) {
+ return sourceCidrList;
+ } else {
+ List<String> oneCidrList = new ArrayList<String>();
+ oneCidrList.add(NetUtils.ALL_IP6_CIDRS);
+ return oneCidrList;
+ }
+ }
+
+ public List<String> getDestinationCidrList() {
+ if (destinationCidrlist != null) {
+ return destinationCidrlist;
+ } else {
+ List<String> oneCidrList = new ArrayList<String>();
+ oneCidrList.add(NetUtils.ALL_IP6_CIDRS);
+ return oneCidrList;
+ }
+ }
+
+ public FirewallRule.TrafficType getTrafficType() {
+ if (trafficType == null) {
+ return FirewallRule.TrafficType.Ingress;
+ }
+ for (FirewallRule.TrafficType type :
FirewallRule.TrafficType.values()) {
+ if (type.toString().equalsIgnoreCase(trafficType)) {
+ return type;
+ }
+ }
+ throw new InvalidParameterValueException("Invalid traffic type " +
trafficType);
+ }
+
+ // ///////////////////////////////////////////////////
+ // ///////////// API Implementation///////////////////
+ // ///////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return APINAME.toLowerCase() + RESPONSE_SUFFIX;
+ }
+
+ public Integer getSourcePortStart() {
+ return publicStartPort;
+ }
+
+ public Integer getSourcePortEnd() {
+ if (publicEndPort == null) {
+ if (publicStartPort != null) {
+ return publicStartPort;
+ }
+ } else {
+ return publicEndPort;
+ }
+
+ return null;
+ }
+
+ public Long getNetworkId() {
+ return networkId;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ Account caller = CallContext.current().getCallingAccount();
Review comment:
refactored
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]