sangho
Committed by Gerrit Code Review

[ONOS-3953] Implements Security Group of Openstack

Change-Id: I30766097a2894a26e46a7a399176d99e95af6abf
......@@ -15,6 +15,8 @@
*/
package org.onosproject.openstackinterface;
import org.onlab.packet.IpPrefix;
import java.util.Objects;
import static com.google.common.base.Preconditions.checkNotNull;
......@@ -24,25 +26,34 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public final class OpenstackSecurityGroupRule {
private final String direction;
private final Direction direction;
private final String ethertype;
private final String id;
private final String portRangeMax;
private final String portRangeMin;
private final int portRangeMax;
private final int portRangeMin;
private final String protocol;
private final String remoteGroupId;
private final String remoteIpPrefix;
private final IpPrefix remoteIpPrefix;
private final String secuityGroupId;
private final String tenantId;
private OpenstackSecurityGroupRule(String direction,
/**
* Direction of the Security Group.
*
*/
public enum Direction {
INGRESS,
EGRESS
}
private OpenstackSecurityGroupRule(Direction direction,
String ethertype,
String id,
String portRangeMax,
String portRangeMin,
int portRangeMax,
int portRangeMin,
String protocol,
String remoteGroupId,
String remoteIpPrefix,
IpPrefix remoteIpPrefix,
String securityGroupId,
String tenantId) {
this.direction = direction;
......@@ -57,6 +68,105 @@ public final class OpenstackSecurityGroupRule {
this.tenantId = tenantId;
}
/**
* Returns the builder object for the OpenstackSecurityGroupRule.
*
* @return OpenstackSecurityGroupRule builder object
*/
public static OpenstackSecurityGroupRule.Builder builder() {
return new Builder();
}
/**
* Returns the direction.
*
* @return direction
*/
public Direction direction() {
return direction;
}
/**
* Returns the Ethernet type.
*
* @return Ethernet type
*/
public String ethertype() {
return ethertype;
}
/**
* Returns the Security Group ID.
*
* @return Security Group ID
*/
public String id() {
return id;
}
/**
* Returns the max of the port range.
*
* @return max of the port range
*/
public int portRangeMax() {
return portRangeMax;
}
/**
* Returns the min of the port range.
*
* @return min of the port range
*/
public int portRangeMin() {
return portRangeMin;
}
/**
* Returns the IP protocol.
*
* @return IP protocol
*/
public String protocol() {
return protocol;
}
/**
* Returns the remote group ID.
*
* @return remote group ID
*/
public String remoteGroupId() {
return remoteGroupId;
}
/**
* Returns the remote IP address.
*
* @return remote IP address
*/
public IpPrefix remoteIpPrefix() {
return this.remoteIpPrefix;
}
/**
* Returns the Security Group ID.
*
* @return security group ID
*/
public String secuityGroupId() {
return secuityGroupId;
}
/**
* Returns the tenant ID.
*
* @return tenant ID
*/
public String tenantId() {
return tenantId;
}
@Override
public String toString() {
return new StringBuilder(" [")
......@@ -84,8 +194,8 @@ public final class OpenstackSecurityGroupRule {
return this.direction.equals(that.direction) &&
this.ethertype.equals(that.direction) &&
this.id.equals(that.id) &&
this.portRangeMax.equals(that.portRangeMax) &&
this.portRangeMin.equals(that.portRangeMin) &&
this.portRangeMax == that.portRangeMax &&
this.portRangeMin == that.portRangeMin &&
this.protocol.equals(that.protocol) &&
this.remoteGroupId.equals(that.remoteGroupId) &&
this.secuityGroupId.equals(that.secuityGroupId) &&
......@@ -235,8 +345,16 @@ public final class OpenstackSecurityGroupRule {
* @return OpenstackSecurityGroupRule object
*/
public OpenstackSecurityGroupRule build() {
return new OpenstackSecurityGroupRule(direction, etherType, id, portRangeMax,
portRangeMin, protocol, remoteGroupId, remoteIpPrefix, secuityGroupId, tenantId);
int portRangeMinInt = (portRangeMin == null || portRangeMin.equals("null")) ?
-1 : Integer.parseInt(portRangeMax);
int portRangeMaxInt = (portRangeMax == null || portRangeMax.equals("null")) ?
-1 : Integer.parseInt(portRangeMax);
IpPrefix ipPrefix = (remoteIpPrefix == null || remoteIpPrefix.equals("null")) ?
null : IpPrefix.valueOf(remoteIpPrefix);
return new OpenstackSecurityGroupRule(Direction.valueOf(direction.toUpperCase()), etherType, id,
portRangeMaxInt, portRangeMinInt, protocol, remoteGroupId, ipPrefix, secuityGroupId, tenantId);
}
}
}
......
......@@ -48,7 +48,7 @@ public class OpenstackSecurityGroupCodec extends JsonCodec<OpenstackSecurityGrou
private static final String REMOTE_GROUP_ID = "remote_group_id";
private static final String REMOTE_IP_PREFIX = "remote_ip_prefix";
private static final String SECURITY_GROUP_ID = "security_group_id";
private static final String TENAN_ID = "tenant_id";
private static final String TENANT_ID = "tenant_id";
@Override
public OpenstackSecurityGroup decode(ObjectNode json, CodecContext context) {
......@@ -75,12 +75,12 @@ public class OpenstackSecurityGroupCodec extends JsonCodec<OpenstackSecurityGrou
.remoteGroupId(ruleInfo.path(REMOTE_GROUP_ID).asText())
.remoteIpPrefix(ruleInfo.path(REMOTE_IP_PREFIX).asText())
.securityGroupId(ruleInfo.path(SECURITY_GROUP_ID).asText())
.tenantId(ruleInfo.path(TENAN_ID).asText())
.tenantId(ruleInfo.path(TENANT_ID).asText())
.build();
rules.add(openstackSecurityGroupRule);
}
String tenantId = securityGroupNode.path(TENAN_ID).asText();
String tenantId = securityGroupNode.path(TENANT_ID).asText();
OpenstackSecurityGroup openstackSecurityGroup = OpenstackSecurityGroup.builder()
.description(description)
......
......@@ -18,6 +18,10 @@ package org.onosproject.openstacknetworking;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onosproject.net.DeviceId;
import java.util.Collection;
import java.util.Collections;
import static com.google.common.base.Preconditions.checkNotNull;
/**
......@@ -29,70 +33,174 @@ public class OpenstackPortInfo {
private final DeviceId deviceId;
private final long vni;
private final Ip4Address gatewayIP;
public OpenstackPortInfo(Ip4Address hostIp, MacAddress hostMac, DeviceId deviceId, long vni, Ip4Address gatewayIP) {
private final Collection<String> securityGroups;
/**
* Returns OpenstackPortInfo reference.
*
* @param hostIp host IP address
* @param hostMac host MAC address
* @param deviceId device ID
* @param vni tunnel ID
* @param gatewayIP gateway IP address
* @param securityGroups security group list
*/
public OpenstackPortInfo(Ip4Address hostIp, MacAddress hostMac, DeviceId deviceId, long vni,
Ip4Address gatewayIP, Collection<String> securityGroups) {
this.hostIp = hostIp;
this.hostMac = hostMac;
this.deviceId = deviceId;
this.vni = vni;
this.gatewayIP = gatewayIP;
this.securityGroups = securityGroups;
}
/**
* Returns IP address of the port.
*
* @return IP address
*/
public Ip4Address ip() {
return hostIp;
}
/**
* Returns MAC address of the port.
*
* @return MAC address
*/
public MacAddress mac() {
return hostMac;
}
/**
* Returns device ID.
*
* @return device ID
*/
public DeviceId deviceId() {
return deviceId;
}
/**
* Returns tunnel ID.
*
* @return tunnel ID
*/
public long vni() {
return vni;
}
/**
* Returns gateway IP address.
*
* @return gateway IP address
*/
public Ip4Address gatewayIP() {
return gatewayIP;
}
/**
* Returns Security Group ID list.
*
* @return list of Security Group ID
*/
public Collection<String> securityGroups() {
return Collections.unmodifiableCollection(securityGroups);
}
/**
* Returns the builder of the OpenstackPortInfo.
*
* @return OpenstackPortInfo builder reference
*/
public static OpenstackPortInfo.Builder builder() {
return new Builder();
}
/**
* Represents the OpenstackPortInfo Builder.
*
*/
public static final class Builder {
private Ip4Address hostIp;
private MacAddress hostMac;
private DeviceId deviceId;
private long vni;
private Ip4Address gatewayIP;
private Collection<String> securityGroups;
/**
* Sets the IP address of the port.
*
* @param gatewayIP
* @return Builder reference
*/
public Builder setGatewayIP(Ip4Address gatewayIP) {
this.gatewayIP = checkNotNull(gatewayIP, "gatewayIP cannot be null");
return this;
}
/**
* Sets the host IP address of the port.
*
* @param hostIp host IP address
* @return Builder reference
*/
public Builder setHostIp(Ip4Address hostIp) {
this.hostIp = checkNotNull(hostIp, "hostIp cannot be null");
return this;
}
/**
* Sets the host MAC address of the port.
*
* @param hostMac host MAC address
* @return Builder reference
*/
public Builder setHostMac(MacAddress hostMac) {
this.hostMac = checkNotNull(hostMac, "hostMac cannot be bull");
return this;
}
/**
* Sets the device ID.
*
* @param deviceId device ID
* @return Builder reference
*/
public Builder setDeviceId(DeviceId deviceId) {
this.deviceId = checkNotNull(deviceId, "deviceId cannot be null");
return this;
}
/**
* Sets the tunnel ID.
*
* @param vni tunnel ID
* @return Builder reference
*/
public Builder setVni(long vni) {
this.vni = checkNotNull(vni, "vni cannot be null");
return this;
}
/**
* Sets the security group ID list.
*
* @param securityGroups security group ID list
* @return Builder reference
*/
public Builder setSecurityGroups(Collection<String> securityGroups) {
this.securityGroups = securityGroups;
return this;
}
/**
* Builds the OpenstackPortInfo reference.
*
* @return OpenstackPortInfo reference
*/
public OpenstackPortInfo build() {
return new OpenstackPortInfo(this);
}
......@@ -104,5 +212,6 @@ public class OpenstackPortInfo {
deviceId = builder.deviceId;
vni = builder.vni;
gatewayIP = builder.gatewayIP;
securityGroups = builder.securityGroups;
}
}
......
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed 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.onosproject.openstacknetworking.switching;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.TpPort;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.openstackinterface.OpenstackInterfaceService;
import org.onosproject.openstackinterface.OpenstackSecurityGroup;
import org.onosproject.openstackinterface.OpenstackSecurityGroupRule;
import org.onosproject.openstacknetworking.OpenstackPortInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
/**
* Populates flows rules for Security Groups of VMs.
*
*/
public class OpenstackSecurityGroupRulePopulator {
private static Logger log = LoggerFactory
.getLogger(OpenstackSecurityGroupRulePopulator.class);
private OpenstackInterfaceService openstackService;
private FlowObjectiveService flowObjectiveService;
private ApplicationId appId;
private static final String PROTO_ICMP = "ICMP";
private static final String PROTO_TCP = "TCP";
private static final String PROTO_UDP = "UDP";
private static final String ETHTYPE_IPV4 = "IPV4";
private static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
private static final int ACL_RULE_PRIORITY = 30000;
/**
* Constructor.
*
* @param appId
* @param openstackService
* @param flowObjectiveService
*/
public OpenstackSecurityGroupRulePopulator(ApplicationId appId, OpenstackInterfaceService openstackService,
FlowObjectiveService flowObjectiveService) {
this.appId = appId;
this.openstackService = openstackService;
this.flowObjectiveService = flowObjectiveService;
}
/**
* Populates flow rules for security groups.
*
* @param id Device ID
* @param sgId Security Group ID
* @param vmIp VM IP address
* @param portInfoMap Port Info map
*/
public void populateSecurityGroupRules(DeviceId id, String sgId, Ip4Address vmIp,
Map<String, OpenstackPortInfo> portInfoMap) {
OpenstackSecurityGroup securityGroup = openstackService.getSecurityGroup(sgId);
if (securityGroup != null) {
securityGroup.rules().stream().forEach(sgRule -> {
if (sgRule.remoteGroupId() != null && !sgRule.remoteGroupId().equals("null")) {
openstackService.ports().stream()
.filter(port -> port.securityGroups().contains(sgRule.remoteGroupId()))
.flatMap(port -> port.fixedIps().values().stream())
.forEach(remoteIp -> setSecurityGroupRule(id, sgRule,
vmIp, IpPrefix.valueOf((IpAddress) remoteIp, 32)));
} else {
setSecurityGroupRule(id, sgRule, vmIp, sgRule.remoteIpPrefix());
}
});
openstackService.ports().stream().forEach(osPort ->
osPort.securityGroups().stream().forEach(remoteVmSgId -> {
OpenstackSecurityGroup remoteVmSg = openstackService.getSecurityGroup(remoteVmSgId);
remoteVmSg.rules().stream()
.filter(remoteVmSgRule -> remoteVmSgRule.remoteGroupId().equals(sgId))
.forEach(remoteVmSgRule -> {
Ip4Address remoteVmIp =
(Ip4Address) osPort.fixedIps().values().stream().findAny().orElse(null);
OpenstackPortInfo osPortInfo = portInfoMap.get(OpenstackSwitchingManager.PORTNAME_PREFIX_VM
+ osPort.id().substring(0, 11));
if (osPortInfo != null && remoteVmIp != null) {
setSecurityGroupRule(osPortInfo.deviceId(), remoteVmSgRule, remoteVmIp,
IpPrefix.valueOf(vmIp, 32));
}
});
}));
}
}
/**
* Removes flow rules for security groups.
*
* @param id Device ID
* @param sgId Security Group ID to remove
* @param vmIp VM IP address
* @param portInfoMap port info map
* @param securityGroupMap security group info map
*/
public void removeSecurityGroupRules(DeviceId id, String sgId, Ip4Address vmIp,
Map<String, OpenstackPortInfo> portInfoMap,
Map<String, OpenstackSecurityGroup> securityGroupMap) {
OpenstackSecurityGroup securityGroup = securityGroupMap.get(sgId);
if (securityGroup != null) {
securityGroup.rules().stream().forEach(sgRule -> {
if (sgRule.remoteGroupId() != null && !sgRule.remoteGroupId().equals("null")) {
portInfoMap.values().stream()
.filter(portInfo -> portInfo.securityGroups().contains(sgRule.remoteGroupId()))
.map(OpenstackPortInfo::ip)
.forEach(remoteIp -> {
removeSecurityGroupRule(id, sgRule, vmIp, IpPrefix.valueOf(remoteIp, 32));
});
} else {
removeSecurityGroupRule(id, sgRule, vmIp, sgRule.remoteIpPrefix());
}
});
portInfoMap.values().stream()
.forEach(portInfo -> portInfo.securityGroups()
.forEach(remoteVmSgId -> {
OpenstackSecurityGroup remoteVmSg = securityGroupMap.get(remoteVmSgId);
remoteVmSg.rules().stream()
.filter(remoteVmSgRule -> remoteVmSgRule.remoteGroupId().equals(sgId))
.forEach(remoteVmSgRule -> removeSecurityGroupRule(portInfo.deviceId(),
remoteVmSgRule, portInfo.ip(), IpPrefix.valueOf(vmIp, 32)));
}));
}
}
private void setSecurityGroupRule(DeviceId id, OpenstackSecurityGroupRule sgRule,
Ip4Address vmIp, IpPrefix remoteIp) {
ForwardingObjective.Builder foBuilder = buildFlowObjective(id, sgRule, vmIp, remoteIp);
if (foBuilder != null) {
flowObjectiveService.forward(id, foBuilder.add());
}
}
private void removeSecurityGroupRule(DeviceId id, OpenstackSecurityGroupRule sgRule,
Ip4Address vmIp, IpPrefix remoteIp) {
ForwardingObjective.Builder foBuilder = buildFlowObjective(id, sgRule, vmIp, remoteIp);
if (foBuilder != null) {
flowObjectiveService.forward(id, foBuilder.remove());
}
}
ForwardingObjective.Builder buildFlowObjective(DeviceId id, OpenstackSecurityGroupRule sgRule,
Ip4Address vmIp, IpPrefix remoteIp) {
if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, 32))) {
return null;
}
TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
buildMatchs(sBuilder, sgRule, vmIp, remoteIp);
ForwardingObjective.Builder foBuilder = DefaultForwardingObjective.builder()
.withSelector(sBuilder.build())
.withTreatment(tBuilder.build())
.withPriority(ACL_RULE_PRIORITY)
.withFlag(ForwardingObjective.Flag.SPECIFIC)
.fromApp(appId);
return foBuilder;
}
private void buildMatchs(TrafficSelector.Builder sBuilder, OpenstackSecurityGroupRule sgRule,
Ip4Address vmIp, IpPrefix remoteIp) {
buildMatchEthType(sBuilder, sgRule.ethertype());
buildMatchDirection(sBuilder, sgRule.direction(), vmIp);
buildMatchProto(sBuilder, sgRule.protocol());
buildMatchPort(sBuilder, sgRule.protocol(), sgRule.direction(), sgRule.portRangeMax(), sgRule.portRangeMin());
buildMatchRemoteIp(sBuilder, remoteIp, sgRule.direction());
}
private void buildMatchDirection(TrafficSelector.Builder sBuilder,
OpenstackSecurityGroupRule.Direction direction, Ip4Address vmIp) {
if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, 32));
} else {
sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, 32));
}
}
private void buildMatchEthType(TrafficSelector.Builder sBuilder, String ethertype) {
// Either IpSrc or IpDst (or both) is set by default, and we need to set EthType as IPv4.
sBuilder.matchEthType(Ethernet.TYPE_IPV4);
if (ethertype != null && ethertype != "null" &&
!ethertype.toUpperCase().equals(ETHTYPE_IPV4)) {
log.error("EthType {} is not supported yet in Security Group", ethertype);
}
}
private void buildMatchRemoteIp(TrafficSelector.Builder sBuilder, IpPrefix remoteIpPrefix,
OpenstackSecurityGroupRule.Direction direction) {
if (remoteIpPrefix != null && !remoteIpPrefix.getIp4Prefix().equals(IP_PREFIX_ANY)) {
if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
sBuilder.matchIPDst(remoteIpPrefix);
} else {
sBuilder.matchIPSrc(remoteIpPrefix);
}
}
}
private void buildMatchProto(TrafficSelector.Builder sBuilder, String protocol) {
if (protocol != null) {
switch (protocol.toUpperCase()) {
case PROTO_ICMP:
sBuilder.matchIPProtocol(IPv4.PROTOCOL_ICMP);
break;
case PROTO_TCP:
sBuilder.matchIPProtocol(IPv4.PROTOCOL_TCP);
break;
case PROTO_UDP:
sBuilder.matchIPProtocol(IPv4.PROTOCOL_UDP);
break;
default:
}
}
}
private void buildMatchPort(TrafficSelector.Builder sBuilder, String protocol,
OpenstackSecurityGroupRule.Direction direction,
int portMin, int portMax) {
if (portMin > 0 && portMax > 0 && portMin == portMax) {
if (protocol.toUpperCase().equals(PROTO_TCP)) {
if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
sBuilder.matchTcpDst(TpPort.tpPort(portMax));
} else {
sBuilder.matchTcpSrc(TpPort.tpPort(portMax));
}
} else if (protocol.toUpperCase().equals(PROTO_UDP)) {
if (direction.equals(OpenstackSecurityGroupRule.Direction.EGRESS)) {
sBuilder.matchUdpDst(TpPort.tpPort(portMax));
} else {
sBuilder.matchUdpSrc(TpPort.tpPort(portMax));
}
}
}
}
}
......@@ -104,7 +104,9 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
public static final String DEVICE_OWNER_GATEWAY = "network:router_gateway";
private ApplicationId appId;
private OpenstackArpHandler arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
private OpenstackArpHandler arpHandler;
private OpenstackSecurityGroupRulePopulator sgRulePopulator;
private ExecutorService deviceEventExcutorService =
Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "device-event"));
......@@ -114,6 +116,7 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
private InternalHostListener internalHostListener = new InternalHostListener();
private Map<String, OpenstackPortInfo> openstackPortInfoMap = Maps.newHashMap();
private Map<String, OpenstackSecurityGroup> securityGroupMap = Maps.newConcurrentMap();
@Activate
protected void activate() {
......@@ -124,6 +127,9 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
deviceService.addListener(internalDeviceListener);
hostService.addListener(internalHostListener);
arpHandler = new OpenstackArpHandler(openstackService, packetService, hostService);
sgRulePopulator = new OpenstackSecurityGroupRulePopulator(appId, openstackService, flowObjectiveService);
initializeFlowRules();
log.info("Started");
......@@ -148,13 +154,6 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
registerDhcpInfo(openstackPort);
}
}
if (!openstackPort.securityGroups().isEmpty()) {
openstackPort.securityGroups().forEach(sgId -> {
OpenstackSecurityGroup sg = openstackService.getSecurityGroup(sgId);
log.debug("SecurityGroup : {}", sg.toString());
});
}
}
@Override
......@@ -185,6 +184,22 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
@Override
public void updatePort(OpenstackPort openstackPort) {
if (openstackPort.status().equals(OpenstackPort.PortStatus.ACTIVE)) {
String portName = PORTNAME_PREFIX_VM + openstackPort.id().substring(0, 11);
OpenstackPortInfo osPortInfo = openstackPortInfoMap.get(portName);
if (osPortInfo != null) {
// Remove all security group rules based on the ones stored in security group map.
osPortInfo.securityGroups().stream().forEach(
sgId -> sgRulePopulator.removeSecurityGroupRules(osPortInfo.deviceId(), sgId,
osPortInfo.ip(), openstackPortInfoMap, securityGroupMap));
// Add all security group rules based on the updated security group.
openstackPort.securityGroups().stream().forEach(
sgId -> sgRulePopulator.populateSecurityGroupRules(osPortInfo.deviceId(), sgId,
osPortInfo.ip(), openstackPortInfoMap));
updatePortMap(osPortInfo.deviceId(), portName, openstackService.networks(),
openstackService.subnets(), openstackPort);
}
}
}
@Override
......@@ -205,26 +220,37 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
}
private void processPortUpdated(Device device, Port port) {
if (!port.annotations().value(PORTNAME).equals(PORTNAME_PREFIX_TUNNEL)) {
if (port.isEnabled() || port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER)) {
OpenstackSwitchingRulePopulator rulePopulator =
new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
deviceService, openstackService, driverService);
rulePopulator.populateSwitchingRules(device, port);
updatePortMap(device.id(), port, openstackService.networks(), openstackService.subnets(),
rulePopulator.openstackPort(port));
//In case portupdate event is driven by vm shutoff from openstack
} else if (!port.isEnabled() && openstackPortInfoMap.containsKey(port.annotations().value(PORTNAME))) {
log.debug("Flowrules according to the port {} were removed", port.number().toString());
OpenstackSwitchingRulePopulator rulePopulator =
new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
deviceService, openstackService, driverService);
rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
dhcpService.removeStaticMapping(openstackPortInfoMap.get(port.annotations().value(PORTNAME)).mac());
openstackPortInfoMap.remove(port.annotations().value(PORTNAME));
String portName = port.annotations().value(PORTNAME);
synchronized (openstackPortInfoMap) {
if (portName.startsWith(PORTNAME_PREFIX_VM)) {
if (port.isEnabled()) {
OpenstackSwitchingRulePopulator rulePopulator =
new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
deviceService, openstackService, driverService);
rulePopulator.populateSwitchingRules(device, port);
OpenstackPort openstackPort = rulePopulator.openstackPort(port);
Ip4Address vmIp = (Ip4Address) openstackPort.fixedIps().values().stream()
.findAny().orElseGet(null);
openstackPort.securityGroups().stream().forEach(
sgId -> sgRulePopulator.populateSecurityGroupRules(device.id(), sgId, vmIp,
openstackPortInfoMap));
updatePortMap(device.id(), port.annotations().value(PORTNAME),
openstackService.networks(), openstackService.subnets(), openstackPort);
//In case portupdate event is driven by vm shutoff from openstack
} else if (!port.isEnabled() && openstackPortInfoMap.containsKey(portName)) {
log.debug("Flowrules according to the port {} were removed", port.number().toString());
OpenstackSwitchingRulePopulator rulePopulator =
new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
deviceService, openstackService, driverService);
rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
openstackPortInfoMap.get(portName).securityGroups().stream().forEach(
sgId -> sgRulePopulator.removeSecurityGroupRules(device.id(), sgId,
openstackPortInfoMap.get(portName).ip(), openstackPortInfoMap, securityGroupMap));
dhcpService.removeStaticMapping(openstackPortInfoMap.get(port.annotations().value(PORTNAME)).mac());
openstackPortInfoMap.remove(port.annotations().value(PORTNAME));
}
}
}
}
......@@ -242,27 +268,33 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
Collection<OpenstackSubnet> subnets = openstackService.subnets();
deviceService.getDevices().forEach(device -> {
log.debug("device {} num of ports {} ", device.id(),
deviceService.getPorts(device.id()).size());
deviceService.getPorts(device.id()).stream()
.filter(port -> port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_VM) ||
port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER))
.forEach(vmPort -> {
OpenstackPort osPort = rulePopulator.openstackPort(vmPort);
if (osPort != null && !osPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
rulePopulator.populateSwitchingRules(device, vmPort);
updatePortMap(device.id(), vmPort, networks, subnets, osPort);
registerDhcpInfo(osPort);
} else {
log.warn("No openstackPort information for port {}", vmPort);
}
}
);
log.debug("device {} num of ports {} ", device.id(),
deviceService.getPorts(device.id()).size());
deviceService.getPorts(device.id()).stream()
.filter(port -> port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_VM) ||
port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER))
.forEach(vmPort -> {
OpenstackPort osPort = rulePopulator.openstackPort(vmPort);
if (osPort != null && !osPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
rulePopulator.populateSwitchingRules(device, vmPort);
Ip4Address vmIp = (Ip4Address) osPort.fixedIps().values().stream()
.findAny().orElseGet(null);
osPort.securityGroups().stream().forEach(
sgId -> sgRulePopulator.populateSecurityGroupRules(device.id(),
sgId, vmIp, openstackPortInfoMap));
updatePortMap(device.id(), vmPort.annotations().value(PORTNAME), networks,
subnets, osPort);
registerDhcpInfo(osPort);
} else {
log.warn("No openstackPort information for port {}", vmPort);
}
}
);
}
);
}
private void updatePortMap(DeviceId deviceId, Port port, Collection<OpenstackNetwork> networks,
private void updatePortMap(DeviceId deviceId, String portName, Collection<OpenstackNetwork> networks,
Collection<OpenstackSubnet> subnets, OpenstackPort openstackPort) {
long vni = Long.parseLong(networks.stream()
.filter(n -> n.id().equals(openstackPort.networkId()))
......@@ -279,10 +311,17 @@ public class OpenstackSwitchingManager implements OpenstackSwitchingService {
.setHostIp((Ip4Address) openstackPort.fixedIps().values().stream().findFirst().orElse(null))
.setHostMac(openstackPort.macAddress())
.setVni(vni)
.setGatewayIP(gatewayIPAddress);
.setGatewayIP(gatewayIPAddress)
.setSecurityGroups(openstackPort.securityGroups());
openstackPortInfoMap.put(portName, portBuilder.build());
openstackPort.securityGroups().stream().forEach(sgId -> {
if (!securityGroupMap.containsKey(sgId)) {
securityGroupMap.put(sgId, openstackService.getSecurityGroup(sgId));
}
});
openstackPortInfoMap.putIfAbsent(port.annotations().value(PORTNAME),
portBuilder.build());
}
private void processHostRemoved(Host host) {
......
......@@ -58,7 +58,6 @@ public class OpenstackSwitchingRulePopulator {
private static Logger log = LoggerFactory
.getLogger(OpenstackSwitchingRulePopulator.class);
private static final int SWITCHING_RULE_PRIORITY = 30000;
private static final int EAST_WEST_ROUTING_RULE_PRIORITY = 29000;
private static final int TUNNELTAG_RULE_PRIORITY = 30000;
private FlowObjectiveService flowObjectiveService;
......@@ -490,4 +489,5 @@ public class OpenstackSwitchingRulePopulator {
}
return port.number();
}
}
......
......@@ -84,6 +84,23 @@ public class OpenstackPortWebResource extends AbstractWebResource {
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response updatePorts(InputStream input) {
return Response.status(Response.Status.OK).build();
try {
ObjectMapper mapper = new ObjectMapper();
ObjectNode portNode = (ObjectNode) mapper.readTree(input);
OpenstackPort openstackPort = PORT_CODEC.decode(portNode, this);
OpenstackSwitchingService switchingService =
getService(OpenstackSwitchingService.class);
switchingService.updatePort(openstackPort);
log.debug("REST API update port is called with {}", portNode.toString());
return Response.status(Response.Status.OK).build();
} catch (Exception e) {
log.error("Update Port failed because of exception {}",
e.toString());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
.build();
}
}
}
......
......@@ -64,6 +64,7 @@ public class OpenstackPipeline extends DefaultSingleTablePipeline
protected static final int VNI_TABLE = 0;
protected static final int FORWARDING_TABLE = 1;
protected static final int ACL_TABLE = 2;
private static final int DROP_PRIORITY = 0;
private static final int TIME_OUT = 0;
......@@ -136,6 +137,7 @@ public class OpenstackPipeline extends DefaultSingleTablePipeline
private void initializePipeline() {
processVniTable(true);
processForwardingTable(true);
processAclTable(true);
}
private void processVniTable(boolean install) {
......@@ -176,6 +178,26 @@ public class OpenstackPipeline extends DefaultSingleTablePipeline
applyRules(install, flowRule);
}
private void processAclTable(boolean install) {
TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
treatment.wipeDeferred();
treatment.drop();
FlowRule flowRule = DefaultFlowRule.builder()
.forDevice(deviceId)
.withSelector(selector.build())
.withTreatment(treatment.build())
.withPriority(DROP_PRIORITY)
.fromApp(appId)
.makePermanent()
.forTable(ACL_TABLE)
.build();
applyRules(install, flowRule);
}
private void applyRules(boolean install, FlowRule flowRule) {
FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
......@@ -264,8 +286,15 @@ public class OpenstackPipeline extends DefaultSingleTablePipeline
tBuilder.transition(FORWARDING_TABLE);
ruleBuilder.withTreatment(tBuilder.build());
ruleBuilder.forTable(VNI_TABLE);
} else {
} else if (forwardingObjective.selector().getCriterion(Criterion.Type.TUNNEL_ID) != null) {
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
tBuilder.deferred();
forwardingObjective.treatment().allInstructions().forEach(tBuilder::add);
tBuilder.transition(ACL_TABLE);
ruleBuilder.withTreatment(tBuilder.build());
ruleBuilder.forTable(FORWARDING_TABLE);
} else {
ruleBuilder.forTable(ACL_TABLE);
}
return Collections.singletonList(ruleBuilder.build());
......