Initial implementation of security group for kubevirt tenant network
Change-Id: If49d03021408a134be01267cc4eee9e0091e3c3d
diff --git a/apps/kubevirt-networking/api/BUILD b/apps/kubevirt-networking/api/BUILD
index 968dd56..e4264cc 100644
--- a/apps/kubevirt-networking/api/BUILD
+++ b/apps/kubevirt-networking/api/BUILD
@@ -1,4 +1,5 @@
COMPILE_DEPS = CORE_DEPS + [
+ "//apps/kubevirt-node/api:onos-apps-kubevirt-node-api",
"@k8s_client//jar",
"@k8s_model//jar",
"@k8s_model_common//jar",
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/Constants.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/Constants.java
index a2099e1..79e8351 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/Constants.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/Constants.java
@@ -34,7 +34,7 @@
public static final String TENANT_TO_TUNNEL_PREFIX = "i-to-t-";
public static final String TUNNEL_TO_TENANT_PREFIX = "t-to-i-";
- // flow table index
+ // provider and VLAN integration bridge flow table index
public static final int STAT_INBOUND_TABLE = 0;
public static final int VTAP_INBOUND_TABLE = 1;
public static final int STAT_FLAT_OUTBOUND_TABLE = 10;
@@ -44,9 +44,9 @@
public static final int FLAT_TABLE = 32;
public static final int ARP_TABLE = 35;
public static final int ACL_EGRESS_TABLE = 40;
- public static final int ACL_INGRESS_TABLE = 44;
- public static final int CT_TABLE = 45;
public static final int ACL_RECIRC_TABLE = 43;
+ public static final int ACL_INGRESS_TABLE = 44;
+ public static final int ACL_CT_TABLE = 45;
public static final int JUMP_TABLE = 50;
public static final int ROUTING_TABLE = 60;
public static final int STAT_OUTBOUND_TABLE = 70;
@@ -54,11 +54,15 @@
public static final int FORWARDING_TABLE = 80;
public static final int ERROR_TABLE = 100;
- // tenant integration bridge flow table index
+ // tenant (VXLAN/GRE/GENEVE) integration bridge flow table index
public static final int TENANT_INBOUND_TABLE = 0;
public static final int TENANT_DHCP_TABLE = 5;
public static final int TENANT_ARP_TABLE = 30;
public static final int TENANT_ICMP_TABLE = 35;
+ public static final int TENANT_ACL_EGRESS_TABLE = 40;
+ public static final int TENANT_ACL_RECIRC_TABLE = 43;
+ public static final int TENANT_ACL_INGRESS_TABLE = 44;
+ public static final int TENANT_ACL_CT_TABLE = 45;
public static final int TENANT_FORWARDING_TABLE = 80;
// tunnel bridge flow table index
@@ -69,8 +73,17 @@
public static final int PRIORITY_FORWARDING_RULE = 30000;
public static final int PRIORITY_DHCP_RULE = 42000;
public static final int PRIORITY_ARP_GATEWAY_RULE = 41000;
+ public static final int PRIORITY_ARP_DEFAULT_RULE = 40000;
public static final int PRIORITY_TUNNEL_RULE = 31000;
+ public static final int PRIORITY_IP_INGRESS_RULE = 19000;
+ public static final int PRIORITY_IP_EGRESS_RULE = 18000;
+ public static final int PRIORITY_ACL_RULE = 31000;
+ public static final int PRIORITY_ACL_INGRESS_RULE = 30000;
+ public static final int PRIORITY_CT_HOOK_RULE = 30500;
+ public static final int PRIORITY_CT_RULE = 32000;
+ public static final int PRIORITY_CT_DROP_RULE = 32500;
+
// CLI item length
public static final int CLI_ID_LENGTH = 30;
public static final int CLI_NAME_LENGTH = 30;
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtNetwork.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtNetwork.java
index 35d367f..73c96f0 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtNetwork.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtNetwork.java
@@ -30,6 +30,7 @@
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
+import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_TO_TUNNEL_PREFIX;
import static org.onosproject.kubevirtnetworking.api.Constants.TUNNEL_TO_TENANT_PREFIX;
import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.FLAT;
import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GENEVE;
@@ -157,9 +158,7 @@
public DeviceId tenantDeviceId(String hostname) {
if (type == VXLAN || type == GRE || type == GENEVE) {
String dpid = genDpidFromName(tenantBridgeName() + "-" + hostname);
- if (dpid != null) {
- return DeviceId.deviceId(dpid);
- }
+ return DeviceId.deviceId(dpid);
}
return null;
}
@@ -176,6 +175,17 @@
}
@Override
+ public PortNumber tenantToTunnelPort(DeviceId deviceId) {
+ String portName = TENANT_TO_TUNNEL_PREFIX + segmentIdHex(segmentId);
+ Port port = port(deviceId, portName);
+ if (port == null) {
+ return null;
+ } else {
+ return port.number();
+ }
+ }
+
+ @Override
public boolean equals(Object o) {
if (this == o) {
return true;
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtPort.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtPort.java
index 992eb90..2a7385f 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtPort.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtPort.java
@@ -16,12 +16,17 @@
package org.onosproject.kubevirtnetworking.api;
import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableSet;
+import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
+import org.onosproject.kubevirtnode.api.KubevirtNode;
+import org.onosproject.kubevirtnode.api.KubevirtNodeService;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import java.util.Objects;
+import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
@@ -37,6 +42,7 @@
private final IpAddress ipAddress;
private final DeviceId deviceId;
private final PortNumber portNumber;
+ private final Set<String> securityGroups;
/**
* Default constructor.
@@ -46,14 +52,16 @@
* @param ipAddress IP address
* @param deviceId device identifier
* @param portNumber port number
+ * @param securityGroups security groups
*/
public DefaultKubevirtPort(String networkId, MacAddress macAddress, IpAddress ipAddress,
- DeviceId deviceId, PortNumber portNumber) {
+ DeviceId deviceId, PortNumber portNumber, Set<String> securityGroups) {
this.networkId = networkId;
this.macAddress = macAddress;
this.ipAddress = ipAddress;
this.deviceId = deviceId;
this.portNumber = portNumber;
+ this.securityGroups = securityGroups;
}
@Override
@@ -77,6 +85,27 @@
}
@Override
+ public DeviceId tenantDeviceId() {
+ KubevirtNetworkService networkService =
+ DefaultServiceDirectory.getService(KubevirtNetworkService.class);
+ KubevirtNodeService nodeService =
+ DefaultServiceDirectory.getService(KubevirtNodeService.class);
+ KubevirtNetwork network = networkService.network(networkId);
+ KubevirtNode node = nodeService.node(deviceId);
+ return network.tenantDeviceId(node.hostname());
+ }
+
+ @Override
+ public boolean isTenant() {
+ KubevirtNetworkService networkService =
+ DefaultServiceDirectory.getService(KubevirtNetworkService.class);
+ KubevirtNetwork network = networkService.network(networkId);
+ return network.type() == KubevirtNetwork.Type.VXLAN ||
+ network.type() == KubevirtNetwork.Type.GRE ||
+ network.type() == KubevirtNetwork.Type.GENEVE;
+ }
+
+ @Override
public PortNumber portNumber() {
return portNumber;
}
@@ -89,6 +118,7 @@
.ipAddress(updateIpAddress)
.deviceId(deviceId)
.portNumber(portNumber)
+ .securityGroups(securityGroups)
.build();
}
@@ -100,6 +130,7 @@
.ipAddress(ipAddress)
.deviceId(deviceId)
.portNumber(updatedPortNumber)
+ .securityGroups(securityGroups)
.build();
}
@@ -111,6 +142,28 @@
.ipAddress(ipAddress)
.deviceId(updatedDeviceId)
.portNumber(portNumber)
+ .securityGroups(securityGroups)
+ .build();
+ }
+
+ @Override
+ public Set<String> securityGroups() {
+ if (securityGroups != null) {
+ return ImmutableSet.copyOf(securityGroups);
+ } else {
+ return ImmutableSet.of();
+ }
+ }
+
+ @Override
+ public KubevirtPort updateSecurityGroups(Set<String> sgs) {
+ return new Builder()
+ .networkId(networkId)
+ .macAddress(macAddress)
+ .ipAddress(ipAddress)
+ .deviceId(deviceId)
+ .portNumber(portNumber)
+ .securityGroups(sgs)
.build();
}
@@ -125,12 +178,12 @@
DefaultKubevirtPort that = (DefaultKubevirtPort) o;
return networkId.equals(that.networkId) && macAddress.equals(that.macAddress) &&
ipAddress.equals(that.ipAddress) && deviceId.equals(that.deviceId) &&
- portNumber.equals(that.portNumber);
+ portNumber.equals(that.portNumber) && securityGroups.equals(that.securityGroups);
}
@Override
public int hashCode() {
- return Objects.hash(networkId, macAddress, ipAddress, deviceId, portNumber);
+ return Objects.hash(networkId, macAddress, ipAddress, deviceId, portNumber, securityGroups);
}
@Override
@@ -141,6 +194,7 @@
.add("ipAddress", ipAddress)
.add("deviceId", deviceId)
.add("portNumber", portNumber)
+ .add("securityGroups", securityGroups)
.toString();
}
@@ -163,6 +217,7 @@
private IpAddress ipAddress;
private DeviceId deviceId;
private PortNumber portNumber;
+ private Set<String> securityGroups;
// private constructor not intended to use from external
private Builder() {
@@ -174,7 +229,7 @@
checkArgument(macAddress != null, NOT_NULL_MSG, "macAddress");
return new DefaultKubevirtPort(networkId, macAddress, ipAddress,
- deviceId, portNumber);
+ deviceId, portNumber, securityGroups);
}
@Override
@@ -206,5 +261,11 @@
this.portNumber = portNumber;
return this;
}
+
+ @Override
+ public Builder securityGroups(Set<String> securityGroups) {
+ this.securityGroups = securityGroups;
+ return this;
+ }
}
}
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtSecurityGroupRule.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtSecurityGroupRule.java
index 556d0bc..63d5f18 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtSecurityGroupRule.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtSecurityGroupRule.java
@@ -114,6 +114,21 @@
}
@Override
+ public KubevirtSecurityGroupRule updateDirection(String updated) {
+ return DefaultKubevirtSecurityGroupRule.builder()
+ .remoteGroupId(remoteGroupId)
+ .etherType(etherType)
+ .protocol(protocol)
+ .portRangeMin(portRangeMin)
+ .portRangeMax(portRangeMax)
+ .securityGroupId(securityGroupId)
+ .remoteIpPrefix(remoteIpPrefix)
+ .id(id)
+ .direction(updated)
+ .build();
+ }
+
+ @Override
public boolean equals(Object o) {
if (this == o) {
return true;
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtNetwork.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtNetwork.java
index b1bf336..94ed1de 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtNetwork.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtNetwork.java
@@ -144,7 +144,7 @@
DeviceId tenantDeviceId(String hostname);
/**
- * Returns the tunnel to tenant port number.
+ * Returns the tunnel bridge to tenant bridge port number.
*
* @param deviceId device identifier
* @return port number
@@ -152,6 +152,14 @@
PortNumber tunnelToTenantPort(DeviceId deviceId);
/**
+ * Returns the tenant bridge to tunnel bridge patch port number.
+ *
+ * @param deviceId device identifier
+ * @return port number
+ */
+ PortNumber tenantToTunnelPort(DeviceId deviceId);
+
+ /**
* Builder of new network.
*/
interface Builder {
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtNetworkService.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtNetworkService.java
index 574f365..e89a635 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtNetworkService.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtNetworkService.java
@@ -48,4 +48,11 @@
* @return set of kubevirt networks
*/
Set<KubevirtNetwork> networks(Type type);
+
+ /**
+ * Returns all kubevirt tenant networks.
+ *
+ * @return set of kubevirt tenant networks
+ */
+ Set<KubevirtNetwork> tenantNetworks();
}
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtPort.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtPort.java
index 850ac6f..3f19640 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtPort.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtPort.java
@@ -20,6 +20,8 @@
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
+import java.util.Set;
+
/**
* Representation of virtual port.
*/
@@ -54,6 +56,20 @@
DeviceId deviceId();
/**
+ * Returns the tenant device ID of the port.
+ *
+ * @return device ID
+ */
+ DeviceId tenantDeviceId();
+
+ /**
+ * Returns the result whether the port is associated with the tenant network.
+ *
+ * @return true if the port is associated with tenant network, false otherwise
+ */
+ boolean isTenant();
+
+ /**
* Returns the port number of the port.
*
* @return port number
@@ -85,6 +101,21 @@
KubevirtPort updateDeviceId(DeviceId updatedDeviceId);
/**
+ * Returns the security group IDs.
+ *
+ * @return security group identifiers.
+ */
+ Set<String> securityGroups();
+
+ /**
+ * Returns new port instance with the given security groups.
+ *
+ * @param sgs security groups
+ * @return updated port
+ */
+ KubevirtPort updateSecurityGroups(Set<String> sgs);
+
+ /**
* Builder of new port.
*/
interface Builder {
@@ -135,5 +166,13 @@
* @return port builder
*/
Builder portNumber(PortNumber portNumber);
+
+ /**
+ * Returns port builder with supplied security group identifiers.
+ *
+ * @param securityGroups security group identifiers
+ * @return port builder
+ */
+ Builder securityGroups(Set<String> securityGroups);
}
}
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtPortEvent.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtPortEvent.java
index efc67d5..2c2012a 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtPortEvent.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtPortEvent.java
@@ -15,13 +15,20 @@
*/
package org.onosproject.kubevirtnetworking.api;
+import org.onlab.util.Tools;
import org.onosproject.event.AbstractEvent;
+import org.onosproject.net.DeviceId;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
/**
* Kubevirt port event class.
*/
public class KubevirtPortEvent extends AbstractEvent<KubevirtPortEvent.Type, KubevirtPort> {
+ private final String securityGroupId;
+ private final DeviceId deviceId;
+
/**
* Creates an event of a given type for the specified port.
*
@@ -30,6 +37,34 @@
*/
public KubevirtPortEvent(Type type, KubevirtPort subject) {
super(type, subject);
+ securityGroupId = null;
+ deviceId = null;
+ }
+
+ /**
+ * Creates an event of a given type for the specified port.
+ *
+ * @param type kubevirt port event type
+ * @param subject kubevirt port subject
+ * @param securityGroupId kubevirt security group ID
+ */
+ public KubevirtPortEvent(Type type, KubevirtPort subject, String securityGroupId) {
+ super(type, subject);
+ this.securityGroupId = securityGroupId;
+ this.deviceId = null;
+ }
+
+ /**
+ * Creates an event of a given type for the specified port.
+ *
+ * @param type kubevirt port event type
+ * @param subject kubevirt port subject
+ * @param deviceId kubevirt device ID
+ */
+ public KubevirtPortEvent(Type type, KubevirtPort subject, DeviceId deviceId) {
+ super(type, subject);
+ this.deviceId = deviceId;
+ this.securityGroupId = null;
}
/**
@@ -51,5 +86,39 @@
* Signifies that the kubevirt port is removed.
*/
KUBEVIRT_PORT_REMOVED,
+
+ /**
+ * Signifies that the kubevirt device is added.
+ */
+ KUBEVIRT_PORT_DEVICE_ADDED,
+
+ /**
+ * Signifies that the kubevirt security group rule is added to a specific port.
+ */
+ KUBEVIRT_PORT_SECURITY_GROUP_ADDED,
+
+ /**
+ * Signifies that the kubevirt security group rule is removed from a specific port.
+ */
+ KUBEVIRT_PORT_SECURITY_GROUP_REMOVED,
+ }
+
+ /**
+ * Returns the security group rule IDs updated.
+ *
+ * @return edgestack security group
+ */
+ public String securityGroupId() {
+ return securityGroupId;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("time", Tools.defaultOffsetDataTime(time()))
+ .add("type", type())
+ .add("port", subject())
+ .add("security group", securityGroupId())
+ .toString();
}
}
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtSecurityGroupRule.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtSecurityGroupRule.java
index 8010d97..5c99306 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtSecurityGroupRule.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtSecurityGroupRule.java
@@ -86,6 +86,14 @@
String remoteGroupId();
/**
+ * Returns the security group rule with updated direction.
+ *
+ * @param direction direction
+ * @return updated security group
+ */
+ KubevirtSecurityGroupRule updateDirection(String direction);
+
+ /**
* A default builder interface.
*/
interface Builder {
diff --git a/apps/kubevirt-networking/api/src/test/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtPortTest.java b/apps/kubevirt-networking/api/src/test/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtPortTest.java
index f91ad2e..69b53ed 100644
--- a/apps/kubevirt-networking/api/src/test/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtPortTest.java
+++ b/apps/kubevirt-networking/api/src/test/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtPortTest.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.kubevirtnetworking.api;
+import com.google.common.collect.ImmutableSet;
import com.google.common.testing.EqualsTester;
import org.junit.Before;
import org.junit.Test;
@@ -23,6 +24,8 @@
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
+import java.util.Set;
+
import static junit.framework.TestCase.assertEquals;
import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
@@ -40,6 +43,8 @@
private static final DeviceId DEVICE_ID_2 = DeviceId.deviceId("of:000000000000002");
private static final PortNumber PORT_NUMBER_1 = PortNumber.portNumber(1);
private static final PortNumber PORT_NUMBER_2 = PortNumber.portNumber(2);
+ private static final Set<String> SGS_1 = ImmutableSet.of("1");
+ private static final Set<String> SGS_2 = ImmutableSet.of("2");
private KubevirtPort port1;
private KubevirtPort sameAsPort1;
@@ -64,6 +69,7 @@
.ipAddress(IP_ADDRESS_1)
.deviceId(DEVICE_ID_1)
.portNumber(PORT_NUMBER_1)
+ .securityGroups(SGS_1)
.build();
sameAsPort1 = DefaultKubevirtPort.builder()
@@ -72,6 +78,7 @@
.ipAddress(IP_ADDRESS_1)
.deviceId(DEVICE_ID_1)
.portNumber(PORT_NUMBER_1)
+ .securityGroups(SGS_1)
.build();
port2 = DefaultKubevirtPort.builder()
@@ -80,6 +87,7 @@
.ipAddress(IP_ADDRESS_2)
.deviceId(DEVICE_ID_2)
.portNumber(PORT_NUMBER_2)
+ .securityGroups(SGS_2)
.build();
}
@@ -105,5 +113,6 @@
assertEquals(IP_ADDRESS_1, port.ipAddress());
assertEquals(DEVICE_ID_1, port.deviceId());
assertEquals(PORT_NUMBER_1, port.portNumber());
+ assertEquals(SGS_1, port.securityGroups());
}
}
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtPortCodec.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtPortCodec.java
index dbbf9c8..a388227 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtPortCodec.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtPortCodec.java
@@ -16,6 +16,7 @@
package org.onosproject.kubevirtnetworking.codec;
import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
@@ -40,6 +41,7 @@
private static final String IP_ADDRESS = "ipAddress";
private static final String DEVICE_ID = "deviceId";
private static final String PORT_NUMBER = "portNumber";
+ private static final String SECURITY_GROUPS = "securityGroups";
private static final String MISSING_MESSAGE = " is required in KubevirtPort";
@@ -63,6 +65,14 @@
result.put(PORT_NUMBER, port.portNumber().toString());
}
+ if (port.securityGroups() != null) {
+ ArrayNode sgIds = context.mapper().createArrayNode();
+ for (String sgId : port.securityGroups()) {
+ sgIds.add(sgId);
+ }
+ result.set(SECURITY_GROUPS, sgIds);
+ }
+
return result;
}
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/DistributedKubevirtPortStore.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/DistributedKubevirtPortStore.java
index 5104bc8..15461df 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/DistributedKubevirtPortStore.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/DistributedKubevirtPortStore.java
@@ -25,6 +25,7 @@
import org.onosproject.kubevirtnetworking.api.KubevirtPortEvent;
import org.onosproject.kubevirtnetworking.api.KubevirtPortStore;
import org.onosproject.kubevirtnetworking.api.KubevirtPortStoreDelegate;
+import org.onosproject.net.DeviceId;
import org.onosproject.store.AbstractStore;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.ConsistentMap;
@@ -41,6 +42,7 @@
import org.slf4j.Logger;
import java.util.Collection;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -48,7 +50,10 @@
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.kubevirtnetworking.api.KubevirtPortEvent.Type.KUBEVIRT_PORT_CREATED;
+import static org.onosproject.kubevirtnetworking.api.KubevirtPortEvent.Type.KUBEVIRT_PORT_DEVICE_ADDED;
import static org.onosproject.kubevirtnetworking.api.KubevirtPortEvent.Type.KUBEVIRT_PORT_REMOVED;
+import static org.onosproject.kubevirtnetworking.api.KubevirtPortEvent.Type.KUBEVIRT_PORT_SECURITY_GROUP_ADDED;
+import static org.onosproject.kubevirtnetworking.api.KubevirtPortEvent.Type.KUBEVIRT_PORT_SECURITY_GROUP_REMOVED;
import static org.onosproject.kubevirtnetworking.api.KubevirtPortEvent.Type.KUBEVIRT_PORT_UPDATED;
import static org.slf4j.LoggerFactory.getLogger;
@@ -166,6 +171,8 @@
eventExecutor.execute(() ->
notifyDelegate(new KubevirtPortEvent(
KUBEVIRT_PORT_UPDATED, event.newValue().value())));
+ processSecurityGroupEvent(event.oldValue().value(), event.newValue().value());
+ processDeviceEvent(event.oldValue().value(), event.newValue().value());
break;
case REMOVE:
log.debug("Kubevirt port removed");
@@ -182,5 +189,36 @@
break;
}
}
+
+ private void processSecurityGroupEvent(KubevirtPort oldPort, KubevirtPort newPort) {
+ Set<String> oldSecurityGroups = oldPort.securityGroups() == null ?
+ ImmutableSet.of() : oldPort.securityGroups();
+ Set<String> newSecurityGroups = newPort.securityGroups() == null ?
+ ImmutableSet.of() : newPort.securityGroups();
+
+ oldSecurityGroups.stream()
+ .filter(sgId -> !Objects.requireNonNull(
+ newPort.securityGroups()).contains(sgId))
+ .forEach(sgId -> notifyDelegate(new KubevirtPortEvent(
+ KUBEVIRT_PORT_SECURITY_GROUP_REMOVED, newPort, sgId
+ )));
+
+ newSecurityGroups.stream()
+ .filter(sgId -> !oldPort.securityGroups().contains(sgId))
+ .forEach(sgId -> notifyDelegate(new KubevirtPortEvent(
+ KUBEVIRT_PORT_SECURITY_GROUP_ADDED, newPort, sgId
+ )));
+ }
+
+ private void processDeviceEvent(KubevirtPort oldPort, KubevirtPort newPort) {
+ DeviceId oldDeviceId = oldPort.deviceId();
+ DeviceId newDeviceId = newPort.deviceId();
+
+ if (oldDeviceId == null && newDeviceId != null) {
+ notifyDelegate(new KubevirtPortEvent(
+ KUBEVIRT_PORT_DEVICE_ADDED, newPort, newDeviceId
+ ));
+ }
+ }
}
}
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFloatingIpHandler.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFloatingIpHandler.java
index f1a5fe0..b77fb04 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFloatingIpHandler.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFloatingIpHandler.java
@@ -37,8 +37,6 @@
import org.onosproject.kubevirtnetworking.api.KubevirtRouterService;
import org.onosproject.kubevirtnetworking.util.RulePopulatorUtil;
import org.onosproject.kubevirtnode.api.KubevirtNode;
-import org.onosproject.kubevirtnode.api.KubevirtNodeEvent;
-import org.onosproject.kubevirtnode.api.KubevirtNodeListener;
import org.onosproject.kubevirtnode.api.KubevirtNodeService;
import org.onosproject.net.Device;
import org.onosproject.net.PortNumber;
@@ -130,16 +128,12 @@
private final InternalRouterEventListener kubevirtRouterListener =
new InternalRouterEventListener();
- private final InternalNodeEventListener kubevirtNodeListener =
- new InternalNodeEventListener();
-
@Activate
protected void activate() {
appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
localNodeId = clusterService.getLocalNode().id();
leadershipService.runForLeadership(appId.name());
kubevirtRouterService.addListener(kubevirtRouterListener);
- kubevirtNodeService.addListener(kubevirtNodeListener);
log.info("Started");
}
@@ -148,7 +142,6 @@
protected void deactivate() {
leadershipService.withdraw(appId.name());
kubevirtRouterService.removeListener(kubevirtRouterListener);
- kubevirtNodeService.removeListener(kubevirtNodeListener);
eventExecutor.shutdown();
@@ -162,8 +155,6 @@
KubevirtPort kubevirtPort = getKubevirtPort(floatingIp);
if (kubevirtPort == null) {
- log.warn("Failed to install floating Ip rules for floating ip {} " +
- "because there's no kubevirt port associated to it", floatingIp.floatingIp());
return;
}
@@ -386,6 +377,14 @@
eventExecutor.execute(() -> processRouterGatewayNodeChanged(event.subject(),
event.gateway()));
break;
+ case KUBEVIRT_GATEWAY_NODE_ATTACHED:
+ eventExecutor.execute(() -> processGatewayNodeAttachment(event.subject(),
+ event.gateway()));
+ break;
+ case KUBEVIRT_GATEWAY_NODE_DETACHED:
+ eventExecutor.execute(() -> processGatewayNodeDetachment(event.subject(),
+ event.gateway()));
+ break;
default:
//do nothing
break;
@@ -415,6 +414,28 @@
});
}
+ private void processGatewayNodeAttachment(KubevirtRouter router, String gatewayName) {
+ kubevirtRouterService.floatingIps().forEach(fip -> {
+ if (fip.routerName().equals(router.name())) {
+ KubevirtNode gw = kubevirtNodeService.node(gatewayName);
+ if (gw != null) {
+ setFloatingIpRulesForFip(router, fip, gw, true);
+ }
+ }
+ });
+ }
+
+ private void processGatewayNodeDetachment(KubevirtRouter router, String gatewayName) {
+ kubevirtRouterService.floatingIps().forEach(fip -> {
+ if (fip.routerName().equals(router.name())) {
+ KubevirtNode gw = kubevirtNodeService.node(gatewayName);
+ if (gw != null) {
+ setFloatingIpRulesForFip(router, fip, gw, false);
+ }
+ }
+ });
+ }
+
private void processFloatingIpAssociation(KubevirtRouter router, KubevirtFloatingIp floatingIp) {
if (!isRelevantHelper() || router.electedGateway() == null) {
return;
@@ -443,45 +464,4 @@
setFloatingIpRulesForFip(router, floatingIp, electedGw, false);
}
}
-
- private class InternalNodeEventListener implements KubevirtNodeListener {
-
- private boolean isRelevantHelper() {
- return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
- }
-
- @Override
- public void event(KubevirtNodeEvent event) {
- switch (event.type()) {
- case KUBEVIRT_NODE_COMPLETE:
- eventExecutor.execute(() -> processNodeCompletion(event.subject()));
- break;
- case KUBEVIRT_NODE_REMOVED:
- case KUBEVIRT_NODE_INCOMPLETE:
- default:
- break;
- }
- }
-
- private void processNodeCompletion(KubevirtNode node) {
- if (!isRelevantHelper() || !node.type().equals(KubevirtNode.Type.GATEWAY)) {
- return;
- }
-
- kubevirtRouterService.floatingIps().forEach(fip -> {
- KubevirtRouter router = kubevirtRouterService.router(fip.routerName());
-
- if (router != null && router.electedGateway() != null) {
- KubevirtNode electedGw = kubevirtNodeService.node(router.electedGateway());
- if (electedGw == null) {
- return;
- }
-
- if (electedGw.hostname().equals(node.hostname())) {
- setFloatingIpRulesForFip(router, fip, electedGw, true);
- }
- }
- });
- }
- }
}
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkHandler.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkHandler.java
index 603a293..f3edd55 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkHandler.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkHandler.java
@@ -88,12 +88,17 @@
import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
import static org.onosproject.kubevirtnetworking.api.Constants.PRE_FLAT_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_DEFAULT_RULE;
import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_DHCP_RULE;
import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_FORWARDING_RULE;
import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ICMP_RULE;
import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
+import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_IP_EGRESS_RULE;
+import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_IP_INGRESS_RULE;
import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_TUNNEL_RULE;
+import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_EGRESS_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_INGRESS_TABLE;
import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ARP_TABLE;
import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_DHCP_TABLE;
import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_FORWARDING_TABLE;
@@ -219,9 +224,9 @@
private void createBridge(KubevirtNode node, KubevirtNetwork network) {
- Device tunBridge = deviceService.getDevice(network.tenantDeviceId(node.hostname()));
- if (tunBridge != null) {
- log.warn("The tunnel bridge {} already exists at node {}",
+ Device tenantBridge = deviceService.getDevice(network.tenantDeviceId(node.hostname()));
+ if (tenantBridge != null) {
+ log.warn("The tenant bridge {} already exists at node {}",
network.tenantBridgeName(), node.hostname());
setDefaultRulesForTenantNetwork(node, network);
return;
@@ -321,7 +326,8 @@
ifaceConfig.removePatchMode(tunToIntIntf);
}
- private void setArpRulesForTenantNetwork(KubevirtNode node, KubevirtNetwork network) {
+ private void setGatewayArpRulesForTenantNetwork(KubevirtNode node,
+ KubevirtNetwork network) {
KubevirtRouter router = getRouterForKubevirtNetwork(kubevirtRouterService, network);
if (router == null) {
@@ -333,11 +339,12 @@
return;
}
- setGatewayArpRuleForTenantInternalNetwork(router, network, TENANT_ARP_TABLE, electedGw.intgBridge(),
- network.tenantDeviceId(node.hostname()), true);
+ setGatewayArpRuleForTenantInternalNetwork(router, network, TENANT_ARP_TABLE,
+ electedGw.intgBridge(), network.tenantDeviceId(node.hostname()), true);
}
- private void setIcmpRulesForTenantNetwork(KubevirtNode node, KubevirtNetwork network) {
+ private void setGatewayIcmpRulesForTenantNetwork(KubevirtNode node,
+ KubevirtNetwork network) {
KubevirtRouter router = getRouterForKubevirtNetwork(kubevirtRouterService, network);
if (router == null) {
return;
@@ -348,11 +355,12 @@
return;
}
- setGatewayIcmpRuleForTenantInternalNetwork(router, network, TENANT_ICMP_TABLE, electedGw.intgBridge(),
- network.tenantDeviceId(node.hostname()), true);
+ setGatewayIcmpRuleForTenantInternalNetwork(router, network, TENANT_ICMP_TABLE,
+ electedGw.intgBridge(), network.tenantDeviceId(node.hostname()), true);
}
- private void setDefaultGatewayRuleToWorkerNodeWhenNodeCreated(KubevirtNode node, KubevirtNetwork network) {
+ private void setGatewayRuleToWorkerNodeWhenNodeCreated(KubevirtNode node,
+ KubevirtNetwork network) {
KubevirtRouter router = getRouterForKubevirtNetwork(kubevirtRouterService, network);
if (router == null) {
return;
@@ -363,10 +371,12 @@
return;
}
- setDefaultGatewayRuleToWorkerNodeTunBridge(router, network, electedGw.intgBridge(), node, true);
+ setDefaultGatewayRuleToWorkerNodeTunBridge(router, network,
+ electedGw.intgBridge(), node, true);
}
- private void setDefaultRulesForTenantNetwork(KubevirtNode node, KubevirtNetwork network) {
+ private void setDefaultRulesForTenantNetwork(KubevirtNode node,
+ KubevirtNetwork network) {
DeviceId deviceId = network.tenantDeviceId(node.hostname());
while (!deviceService.isAvailable(deviceId)) {
@@ -384,9 +394,14 @@
flowService.connectTables(deviceId, TENANT_ARP_TABLE, TENANT_ICMP_TABLE);
flowService.connectTables(deviceId, TENANT_ICMP_TABLE, TENANT_FORWARDING_TABLE);
+ setArpRuleForTenantNetwork(deviceId, true);
setDhcpRuleForTenantNetwork(deviceId, true);
setForwardingRule(deviceId, true);
+ // security group related rules
+ setTenantIngressTransitionRule(network, network.tenantDeviceId(node.hostname()), true);
+ setEgressTransitionRule(network.tenantDeviceId(node.hostname()), true);
+
log.info("Install default flow rules for tenant bridge {}", network.tenantBridgeName());
}
@@ -436,13 +451,14 @@
case VXLAN:
case GRE:
case GENEVE:
- setDefaultEgressRuleToGatewayNode(router, network, electedGateway.intgBridge(), install);
+ setDefaultEgressRuleToGatewayNode(router, network,
+ electedGateway.intgBridge(), install);
kubevirtNodeService.completeNodes(WORKER).forEach(node -> {
- setGatewayArpRuleForTenantInternalNetwork(router, network, TENANT_ARP_TABLE,
- electedGateway.intgBridge(),
+ setGatewayArpRuleForTenantInternalNetwork(router, network,
+ TENANT_ARP_TABLE, electedGateway.intgBridge(),
network.tenantDeviceId(node.hostname()), install);
- setGatewayIcmpRuleForTenantInternalNetwork(router, network, TENANT_ICMP_TABLE,
- electedGateway.intgBridge(),
+ setGatewayIcmpRuleForTenantInternalNetwork(router, network,
+ TENANT_ICMP_TABLE, electedGateway.intgBridge(),
network.tenantDeviceId(node.hostname()), install);
setDefaultGatewayRuleToWorkerNodeTunBridge(router, network,
electedGateway.intgBridge(), node, install);
@@ -451,11 +467,12 @@
break;
case FLAT:
case VLAN:
- setGatewayArpRuleForProviderInternalNetwork(router, network, PRE_FLAT_TABLE,
- electedGateway.intgBridge(), install);
- setGatewayIcmpRuleForProviderInternalNetwork(router, network, PRE_FLAT_TABLE,
- electedGateway.intgBridge(), install);
- setGatewayProviderInterNetworkRoutingWithinSameRouter(network, router, electedGateway, install);
+ setGatewayArpRuleForProviderInternalNetwork(router, network,
+ PRE_FLAT_TABLE, electedGateway.intgBridge(), install);
+ setGatewayIcmpRuleForProviderInternalNetwork(router, network,
+ PRE_FLAT_TABLE, electedGateway.intgBridge(), install);
+ setGatewayProviderInterNetworkRoutingWithinSameRouter(network,
+ router, electedGateway, install);
break;
default:
// do nothing
@@ -519,6 +536,42 @@
install);
}
+ private void setTenantIngressTransitionRule(KubevirtNetwork network,
+ DeviceId deviceId, boolean install) {
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ sBuilder.matchEthType(EthType.EtherType.IPV4.ethType().toShort())
+ .matchInPort(network.tenantToTunnelPort(deviceId));
+
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ tBuilder.transition(TENANT_ACL_INGRESS_TABLE);
+
+ flowService.setRule(appId,
+ deviceId,
+ sBuilder.build(),
+ tBuilder.build(),
+ PRIORITY_IP_INGRESS_RULE,
+ TENANT_ICMP_TABLE,
+ install
+ );
+ }
+
+ private void setEgressTransitionRule(DeviceId deviceId, boolean install) {
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ sBuilder.matchEthType(EthType.EtherType.IPV4.ethType().toShort());
+
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ tBuilder.transition(TENANT_ACL_EGRESS_TABLE);
+
+ flowService.setRule(appId,
+ deviceId,
+ sBuilder.build(),
+ tBuilder.build(),
+ PRIORITY_IP_EGRESS_RULE,
+ TENANT_ICMP_TABLE,
+ install
+ );
+ }
+
private void setDefaultEgressRuleToGatewayNode(KubevirtRouter router,
KubevirtNetwork network,
DeviceId gwDeviceId,
@@ -610,6 +663,25 @@
install);
}
+ private void setArpRuleForTenantNetwork(DeviceId tenantDeviceId,
+ boolean install) {
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
+ .matchEthType(EthType.EtherType.ARP.ethType().toShort());
+
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
+ .transition(TENANT_FORWARDING_TABLE);
+
+ flowService.setRule(
+ appId,
+ tenantDeviceId,
+ sBuilder.build(),
+ tBuilder.build(),
+ PRIORITY_ARP_DEFAULT_RULE,
+ TENANT_ARP_TABLE,
+ install
+ );
+ }
+
private void setGatewayArpRuleForTenantInternalNetwork(KubevirtRouter router,
KubevirtNetwork network,
int tableNum,
@@ -1000,7 +1072,8 @@
});
}
- private void removeDetachedInternalNetworkRules(KubevirtNetwork removedNetwork, KubevirtRouter router,
+ private void removeDetachedInternalNetworkRules(KubevirtNetwork removedNetwork,
+ KubevirtRouter router,
KubevirtNode electedGw) {
router.internal().stream().filter(networkId -> kubevirtNetworkService.network(networkId) != null)
.forEach(networkId -> {
@@ -1213,9 +1286,9 @@
createBridge(node, network);
createPatchTenantInterface(node, network);
setDefaultRulesForTenantNetwork(node, network);
- setArpRulesForTenantNetwork(node, network);
- setIcmpRulesForTenantNetwork(node, network);
- setDefaultGatewayRuleToWorkerNodeWhenNodeCreated(node, network);
+ setGatewayArpRulesForTenantNetwork(node, network);
+ setGatewayIcmpRulesForTenantNetwork(node, network);
+ setGatewayRuleToWorkerNodeWhenNodeCreated(node, network);
break;
case FLAT:
reserveVrouterIp(network);
@@ -1322,7 +1395,8 @@
|| kubevirtNetworkService.network(srcNetwork) == null) {
return;
}
- setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
+ setGatewayInterNetworkRoutingFromNetworkToPort(router,
+ kubevirtNetworkService.network(srcNetwork),
kubevirtPort, gwNode, true);
});
}
@@ -1347,7 +1421,8 @@
|| kubevirtNetworkService.network(srcNetwork) == null) {
return;
}
- setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
+ setGatewayInterNetworkRoutingFromNetworkToPort(router,
+ kubevirtNetworkService.network(srcNetwork),
kubevirtPort, gwNode, true);
});
}
@@ -1372,7 +1447,8 @@
|| kubevirtNetworkService.network(srcNetwork) == null) {
return;
}
- setGatewayInterNetworkRoutingFromNetworkToPort(router, kubevirtNetworkService.network(srcNetwork),
+ setGatewayInterNetworkRoutingFromNetworkToPort(router,
+ kubevirtNetworkService.network(srcNetwork),
kubevirtPort, gwNode, false);
});
}
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkManager.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkManager.java
index 7b40b01..74d317d 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkManager.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkManager.java
@@ -46,6 +46,9 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
+import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GENEVE;
+import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GRE;
+import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VXLAN;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -216,6 +219,15 @@
.filter(n -> n.type() == type).collect(Collectors.toSet()));
}
+ @Override
+ public Set<KubevirtNetwork> tenantNetworks() {
+ return ImmutableSet.copyOf(networkStore.networks().stream()
+ .filter(n -> n.type() == VXLAN ||
+ n.type() == GRE ||
+ n.type() == GENEVE)
+ .collect(Collectors.toSet()));
+ }
+
private class InternalNetworkStorageDelegate implements KubevirtNetworkStoreDelegate {
@Override
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtRoutingSnatHandler.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtRoutingSnatHandler.java
index a2667f9..9acf35e 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtRoutingSnatHandler.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtRoutingSnatHandler.java
@@ -42,8 +42,6 @@
import org.onosproject.kubevirtnetworking.api.KubevirtRouterService;
import org.onosproject.kubevirtnetworking.util.RulePopulatorUtil;
import org.onosproject.kubevirtnode.api.KubevirtNode;
-import org.onosproject.kubevirtnode.api.KubevirtNodeEvent;
-import org.onosproject.kubevirtnode.api.KubevirtNodeListener;
import org.onosproject.kubevirtnode.api.KubevirtNodeService;
import org.onosproject.net.Device;
import org.onosproject.net.PortNumber;
@@ -148,9 +146,6 @@
private final InternalRouterEventListener kubevirtRouterlistener =
new InternalRouterEventListener();
- private final InternalNodeEventListener kubevirtNodeListener =
- new InternalNodeEventListener();
-
private ApplicationId appId;
private NodeId localNodeId;
@@ -162,7 +157,6 @@
kubevirtPortService.addListener(kubevirtPortListener);
kubevirtRouterService.addListener(kubevirtRouterlistener);
- kubevirtNodeService.addListener(kubevirtNodeListener);
log.info("Started");
}
@@ -170,7 +164,6 @@
@Deactivate
protected void deactivate() {
leadershipService.withdraw(appId.name());
- kubevirtNodeService.removeListener(kubevirtNodeListener);
kubevirtPortService.removeListener(kubevirtPortListener);
kubevirtRouterService.removeListener(kubevirtRouterlistener);
@@ -818,12 +811,4 @@
}
}
}
-
- private class InternalNodeEventListener implements KubevirtNodeListener {
-
- @Override
- public void event(KubevirtNodeEvent event) {
-
- }
- }
}
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtSecurityGroupHandler.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtSecurityGroupHandler.java
new file mode 100644
index 0000000..77b60d9
--- /dev/null
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtSecurityGroupHandler.java
@@ -0,0 +1,1072 @@
+/*
+ * Copyright 2020-present Open Networking Foundation
+ *
+ * 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.kubevirtnetworking.impl;
+
+import com.google.common.collect.Sets;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.TpPort;
+import org.onlab.packet.VlanId;
+import org.onlab.util.Tools;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.cfg.ConfigProperty;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.LeadershipService;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.kubevirtnetworking.api.KubevirtFlowRuleService;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetworkEvent;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetworkListener;
+import org.onosproject.kubevirtnetworking.api.KubevirtNetworkService;
+import org.onosproject.kubevirtnetworking.api.KubevirtPort;
+import org.onosproject.kubevirtnetworking.api.KubevirtPortEvent;
+import org.onosproject.kubevirtnetworking.api.KubevirtPortListener;
+import org.onosproject.kubevirtnetworking.api.KubevirtPortService;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroup;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupEvent;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupListener;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupRule;
+import org.onosproject.kubevirtnetworking.api.KubevirtSecurityGroupService;
+import org.onosproject.kubevirtnetworking.util.RulePopulatorUtil;
+import org.onosproject.kubevirtnode.api.KubevirtNode;
+import org.onosproject.kubevirtnode.api.KubevirtNodeEvent;
+import org.onosproject.kubevirtnode.api.KubevirtNodeListener;
+import org.onosproject.kubevirtnode.api.KubevirtNodeService;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.driver.DriverService;
+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.flow.criteria.ExtensionSelector;
+import org.onosproject.net.flow.instructions.ExtensionTreatment;
+import org.onosproject.store.service.StorageService;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Modified;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.slf4j.Logger;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
+
+import static java.lang.Thread.sleep;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.kubevirtnetworking.api.Constants.ERROR_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
+import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ACL_INGRESS_RULE;
+import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ACL_RULE;
+import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_CT_DROP_RULE;
+import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_CT_HOOK_RULE;
+import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_CT_RULE;
+import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_CT_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_EGRESS_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_INGRESS_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_RECIRC_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_FORWARDING_TABLE;
+import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GENEVE;
+import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GRE;
+import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VLAN;
+import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VXLAN;
+import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP;
+import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP_DEFAULT;
+import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getPropertyValueAsBoolean;
+import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.buildPortRangeMatches;
+import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.computeCtMaskFlag;
+import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.computeCtStateFlag;
+import static org.onosproject.kubevirtnetworking.util.RulePopulatorUtil.niciraConnTrackTreatmentBuilder;
+import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Populates flow rules to handle EdgeStack SecurityGroups.
+ */
+@Component(
+ immediate = true,
+ property = {
+ USE_SECURITY_GROUP + ":Boolean=" + USE_SECURITY_GROUP_DEFAULT
+ }
+)
+public class KubevirtSecurityGroupHandler {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final int VM_IP_PREFIX = 32;
+
+ private static final String STR_NULL = "null";
+ private static final String PROTO_ICMP = "ICMP";
+ private static final String PROTO_ICMP_NUM = "1";
+ private static final String PROTO_TCP = "TCP";
+ private static final String PROTO_TCP_NUM = "6";
+ private static final String PROTO_UDP = "UDP";
+ private static final String PROTO_UDP_NUM = "17";
+ private static final String PROTO_SCTP = "SCTP";
+ private static final String PROTO_SCTP_NUM = "132";
+ private static final byte PROTOCOL_SCTP = (byte) 0x84;
+ private static final String PROTO_ANY = "ANY";
+ private static final String PROTO_ANY_NUM = "0";
+ private static final String ETHTYPE_IPV4 = "IPV4";
+ private static final String EGRESS = "EGRESS";
+ private static final String INGRESS = "INGRESS";
+ private static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
+
+ private static final int ICMP_CODE_MIN = 0;
+ private static final int ICMP_CODE_MAX = 255;
+ private static final int ICMP_TYPE_MIN = 0;
+ private static final int ICMP_TYPE_MAX = 255;
+
+ private static final int CT_COMMIT = 0;
+ private static final int CT_NO_COMMIT = 1;
+ private static final short CT_NO_RECIRC = -1;
+
+ private static final int ACTION_NONE = 0;
+ private static final int ACTION_DROP = -1;
+
+ private static final long SLEEP_MS = 5000;
+
+ /** Apply EdgeStack security group rule for VM traffic. */
+ private boolean useSecurityGroup = USE_SECURITY_GROUP_DEFAULT;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected MastershipService mastershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected DriverService driverService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected LeadershipService leadershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected ClusterService clusterService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected StorageService storageService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected ComponentConfigService configService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected KubevirtNodeService nodeService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected KubevirtNetworkService networkService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected KubevirtPortService portService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected KubevirtFlowRuleService flowRuleService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected KubevirtSecurityGroupService securityGroupService;
+
+ private final KubevirtPortListener portListener =
+ new InternalKubevirtPortListener();
+ private final KubevirtSecurityGroupListener securityGroupListener =
+ new InternalSecurityGroupListener();
+ private final KubevirtNodeListener nodeListener =
+ new InternalNodeListener();
+ private final KubevirtNetworkListener networkListener =
+ new InternalNetworkListener();
+
+ private final ExecutorService eventExecutor = newSingleThreadExecutor(
+ groupedThreads(this.getClass().getSimpleName(), "event-handler"));
+
+ private ApplicationId appId;
+ private NodeId localNodeId;
+
+ @Activate
+ protected void activate() {
+ appId = coreService.registerApplication(KUBEVIRT_NETWORKING_APP_ID);
+ localNodeId = clusterService.getLocalNode().id();
+ securityGroupService.addListener(securityGroupListener);
+ portService.addListener(portListener);
+ networkService.addListener(networkListener);
+ configService.registerProperties(getClass());
+ nodeService.addListener(nodeListener);
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ securityGroupService.removeListener(securityGroupListener);
+ portService.removeListener(portListener);
+ configService.unregisterProperties(getClass(), false);
+ nodeService.removeListener(nodeListener);
+ networkService.removeListener(networkListener);
+ eventExecutor.shutdown();
+
+ log.info("Stopped");
+ }
+
+ @Modified
+ protected void modified(ComponentContext context) {
+ Dictionary<?, ?> properties = context.getProperties();
+ Boolean flag;
+
+ flag = Tools.isPropertyEnabled(properties, USE_SECURITY_GROUP);
+ if (flag == null) {
+ log.info("useSecurityGroup is not configured, " +
+ "using current value of {}", useSecurityGroup);
+ } else {
+ useSecurityGroup = flag;
+ log.info("Configured. useSecurityGroup is {}",
+ useSecurityGroup ? "enabled" : "disabled");
+ }
+
+ securityGroupService.setSecurityGroupEnabled(useSecurityGroup);
+ resetSecurityGroupRules();
+ }
+
+ private boolean getUseSecurityGroupFlag() {
+ Set<ConfigProperty> properties =
+ configService.getProperties(getClass().getName());
+ return getPropertyValueAsBoolean(properties, USE_SECURITY_GROUP);
+ }
+
+ private void initializeConnTrackTable(DeviceId deviceId, boolean install) {
+
+ // table={ACL_INGRESS_TABLE(44)},ip,ct_state=-trk, actions=ct(table:{ACL_CT_TABLE(45)})
+ long ctState = computeCtStateFlag(false, false, false);
+ long ctMask = computeCtMaskFlag(true, false, false);
+ setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, (short) TENANT_ACL_CT_TABLE,
+ ACTION_NONE, PRIORITY_CT_HOOK_RULE, install);
+
+ //table={ACL_CT_TABLE(45)},ip,nw_dst=10.10.0.2,ct_state=+trk+est,action=goto_table:{NORMAL_TABLE(80)}
+ ctState = computeCtStateFlag(true, false, true);
+ ctMask = computeCtMaskFlag(true, false, true);
+ setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
+ TENANT_FORWARDING_TABLE, PRIORITY_CT_RULE, install);
+
+ //table={ACL_CT_TABLE(45)},ip,nw_dst=10.10.0.2,ct_state=+trk+new,action=drop
+ ctState = computeCtStateFlag(true, true, false);
+ ctMask = computeCtMaskFlag(true, true, false);
+ setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
+ ACTION_DROP, PRIORITY_CT_DROP_RULE, install);
+ }
+
+ private void initializeAclTable(DeviceId deviceId, boolean install) {
+
+ ExtensionTreatment ctTreatment =
+ niciraConnTrackTreatmentBuilder(driverService, deviceId)
+ .commit(true)
+ .build();
+
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ sBuilder.matchEthType(Ethernet.TYPE_IPV4);
+
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ tBuilder.extension(ctTreatment, deviceId)
+ .transition(TENANT_FORWARDING_TABLE);
+
+ flowRuleService.setRule(appId,
+ deviceId,
+ sBuilder.build(),
+ tBuilder.build(),
+ PRIORITY_ACL_INGRESS_RULE,
+ TENANT_ACL_RECIRC_TABLE,
+ install);
+ }
+
+ private void initializeEgressTable(DeviceId deviceId, boolean install) {
+ if (install) {
+ flowRuleService.setUpTableMissEntry(deviceId, TENANT_ACL_EGRESS_TABLE);
+ } else {
+ flowRuleService.connectTables(deviceId, TENANT_ACL_EGRESS_TABLE, TENANT_FORWARDING_TABLE);
+ }
+ }
+
+ private void initializeIngressTable(DeviceId deviceId, boolean install) {
+ if (install) {
+ flowRuleService.setUpTableMissEntry(deviceId, TENANT_ACL_INGRESS_TABLE);
+ } else {
+ flowRuleService.connectTables(deviceId, TENANT_ACL_INGRESS_TABLE, TENANT_FORWARDING_TABLE);
+ }
+ }
+
+ private void updateSecurityGroupRule(KubevirtPort port,
+ KubevirtSecurityGroupRule sgRule, boolean install) {
+
+ if (port == null || sgRule == null) {
+ return;
+ }
+
+ if (sgRule.remoteGroupId() != null && !sgRule.remoteGroupId().isEmpty()) {
+ getRemotePorts(port, sgRule.remoteGroupId())
+ .forEach(rPort -> {
+ populateSecurityGroupRule(sgRule, port,
+ rPort.ipAddress().toIpPrefix(), install);
+ populateSecurityGroupRule(sgRule, rPort,
+ port.ipAddress().toIpPrefix(), install);
+
+ KubevirtSecurityGroupRule rSgRule = sgRule.updateDirection(
+ sgRule.direction().equalsIgnoreCase(EGRESS) ? INGRESS : EGRESS);
+ populateSecurityGroupRule(rSgRule, port,
+ rPort.ipAddress().toIpPrefix(), install);
+ populateSecurityGroupRule(rSgRule, rPort,
+ port.ipAddress().toIpPrefix(), install);
+ });
+ } else {
+ populateSecurityGroupRule(sgRule, port,
+ sgRule.remoteIpPrefix() == null ? IP_PREFIX_ANY :
+ sgRule.remoteIpPrefix(), install);
+ }
+ }
+
+ private boolean checkProtocol(String protocol) {
+ if (protocol == null) {
+ log.debug("No protocol was specified, use default IP(v4/v6) protocol.");
+ return true;
+ } else {
+ String protocolUpper = protocol.toUpperCase();
+ if (protocolUpper.equals(PROTO_TCP) ||
+ protocolUpper.equals(PROTO_UDP) ||
+ protocolUpper.equals(PROTO_ICMP) ||
+ protocolUpper.equals(PROTO_SCTP) ||
+ protocolUpper.equals(PROTO_ANY) ||
+ protocol.equals(PROTO_TCP_NUM) ||
+ protocol.equals(PROTO_UDP_NUM) ||
+ protocol.equals(PROTO_ICMP_NUM) ||
+ protocol.equals(PROTO_SCTP_NUM) ||
+ protocol.equals(PROTO_ANY_NUM)) {
+ return true;
+ } else {
+ log.error("Unsupported protocol {}, we only support " +
+ "TCP/UDP/ICMP/SCTP protocols.", protocol);
+ return false;
+ }
+ }
+ }
+
+ private void populateSecurityGroupRule(KubevirtSecurityGroupRule sgRule,
+ KubevirtPort port,
+ IpPrefix remoteIp,
+ boolean install) {
+ if (!checkProtocol(sgRule.protocol())) {
+ return;
+ }
+
+ DeviceId deviceId = port.isTenant() ? port.tenantDeviceId() : port.deviceId();
+
+ Set<TrafficSelector> selectors = buildSelectors(sgRule,
+ Ip4Address.valueOf(port.ipAddress().toInetAddress()),
+ remoteIp, port.networkId());
+ if (selectors == null || selectors.isEmpty()) {
+ return;
+ }
+
+ // if the device is not available we do not perform any action
+ if (deviceId == null || !deviceService.isAvailable(deviceId)) {
+ return;
+ }
+
+ // XXX All egress traffic needs to go through connection tracking module,
+ // which might hurt its performance.
+ ExtensionTreatment ctTreatment =
+ niciraConnTrackTreatmentBuilder(driverService, deviceId)
+ .commit(true)
+ .build();
+
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+ int aclTable;
+ if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
+ aclTable = TENANT_ACL_EGRESS_TABLE;
+ tBuilder.transition(TENANT_ACL_RECIRC_TABLE);
+ } else {
+ aclTable = TENANT_ACL_INGRESS_TABLE;
+ tBuilder.extension(ctTreatment, deviceId)
+ .transition(TENANT_FORWARDING_TABLE);
+ }
+
+ int finalAclTable = aclTable;
+ selectors.forEach(selector -> {
+ flowRuleService.setRule(appId,
+ deviceId,
+ selector, tBuilder.build(),
+ PRIORITY_ACL_RULE,
+ finalAclTable,
+ install);
+ });
+ }
+
+ /**
+ * Sets connection tracking rule using OVS extension commands.
+ * It is not so graceful, but I don't want to make it more general because
+ * it is going to be used only here.
+ * The following is the usage of the function.
+ *
+ * @param deviceId Device ID
+ * @param ctState ctState: please use RulePopulatorUtil.computeCtStateFlag()
+ * to build the value
+ * @param ctMask crMask: please use RulePopulatorUtil.computeCtMaskFlag()
+ * to build the value
+ * @param commit CT_COMMIT for commit action, CT_NO_COMMIT otherwise
+ * @param recircTable table number for recirculation after CT actions.
+ * CT_NO_RECIRC with no recirculation
+ * @param action Additional actions. ACTION_DROP, ACTION_NONE,
+ * GOTO_XXX_TABLE are supported.
+ * @param priority priority value for the rule
+ * @param install true for insertion, false for removal
+ */
+ private void setConnTrackRule(DeviceId deviceId, long ctState, long ctMask,
+ int commit, short recircTable,
+ int action, int priority, boolean install) {
+
+ ExtensionSelector esCtSate = RulePopulatorUtil
+ .buildCtExtensionSelector(driverService, deviceId, ctState, ctMask);
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .extension(esCtSate, deviceId)
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .build();
+
+ TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
+
+ if (commit == CT_COMMIT || recircTable > 0) {
+ RulePopulatorUtil.NiciraConnTrackTreatmentBuilder natTreatmentBuilder =
+ niciraConnTrackTreatmentBuilder(driverService, deviceId);
+ natTreatmentBuilder.natAction(false);
+ natTreatmentBuilder.commit(commit == CT_COMMIT);
+ if (recircTable > 0) {
+ natTreatmentBuilder.table(recircTable);
+ }
+ tb.extension(natTreatmentBuilder.build(), deviceId);
+ } else if (action == ACTION_DROP) {
+ tb.drop();
+ }
+
+ if (action != ACTION_NONE && action != ACTION_DROP) {
+ tb.transition(action);
+ }
+
+ int tableType = ERROR_TABLE;
+ if (priority == PRIORITY_CT_RULE || priority == PRIORITY_CT_DROP_RULE) {
+ tableType = TENANT_ACL_CT_TABLE;
+ } else if (priority == PRIORITY_CT_HOOK_RULE) {
+ tableType = TENANT_ACL_INGRESS_TABLE;
+ } else {
+ log.error("Cannot an appropriate table for the conn track rule.");
+ }
+
+ flowRuleService.setRule(
+ appId,
+ deviceId,
+ selector,
+ tb.build(),
+ priority,
+ tableType,
+ install);
+ }
+
+ /**
+ * Returns a set of host IP addresses engaged with supplied security group ID.
+ * It only searches a VM in the same tenant boundary.
+ *
+ * @param srcPort edgestack port
+ * @param sgId security group id
+ * @return set of ip addresses
+ */
+ private Set<KubevirtPort> getRemotePorts(KubevirtPort srcPort, String sgId) {
+ return portService.ports().stream()
+ .filter(port -> !port.macAddress().equals(srcPort.macAddress()))
+ .filter(port -> port.securityGroups().contains(sgId))
+ .filter(port -> port.ipAddress() != null)
+ .collect(Collectors.toSet());
+ }
+
+ private Set<TrafficSelector> buildSelectors(KubevirtSecurityGroupRule sgRule,
+ Ip4Address vmIp,
+ IpPrefix remoteIp,
+ String netId) {
+ if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, VM_IP_PREFIX))) {
+ // do nothing if the remote IP is my IP
+ return null;
+ }
+
+ Set<TrafficSelector> selectorSet = Sets.newHashSet();
+
+ if (sgRule.portRangeMax() != null && sgRule.portRangeMin() != null &&
+ sgRule.portRangeMin() < sgRule.portRangeMax()) {
+ Map<TpPort, TpPort> portRangeMatchMap =
+ buildPortRangeMatches(sgRule.portRangeMin(),
+ sgRule.portRangeMax());
+ portRangeMatchMap.forEach((key, value) -> {
+
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ buildMatches(sBuilder, sgRule, vmIp, remoteIp, netId);
+
+ if (sgRule.protocol().equalsIgnoreCase(PROTO_TCP) ||
+ sgRule.protocol().equals(PROTO_TCP_NUM)) {
+ if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
+ if (value.toInt() == TpPort.MAX_PORT) {
+ sBuilder.matchTcpSrc(key);
+ } else {
+ sBuilder.matchTcpSrcMasked(key, value);
+ }
+ } else {
+ if (value.toInt() == TpPort.MAX_PORT) {
+ sBuilder.matchTcpDst(key);
+ } else {
+ sBuilder.matchTcpDstMasked(key, value);
+ }
+ }
+ } else if (sgRule.protocol().equalsIgnoreCase(PROTO_UDP) ||
+ sgRule.protocol().equals(PROTO_UDP_NUM)) {
+ if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
+ if (value.toInt() == TpPort.MAX_PORT) {
+ sBuilder.matchUdpSrc(key);
+ } else {
+ sBuilder.matchUdpSrcMasked(key, value);
+ }
+ } else {
+ if (value.toInt() == TpPort.MAX_PORT) {
+ sBuilder.matchUdpDst(key);
+ } else {
+ sBuilder.matchUdpDstMasked(key, value);
+ }
+ }
+ } else if (sgRule.protocol().equalsIgnoreCase(PROTO_SCTP) ||
+ sgRule.protocol().equals(PROTO_SCTP_NUM)) {
+ if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
+ if (value.toInt() == TpPort.MAX_PORT) {
+ sBuilder.matchSctpSrc(key);
+ } else {
+ sBuilder.matchSctpSrcMasked(key, value);
+ }
+ } else {
+ if (value.toInt() == TpPort.MAX_PORT) {
+ sBuilder.matchSctpDst(key);
+ } else {
+ sBuilder.matchSctpDstMasked(key, value);
+ }
+ }
+ }
+
+ selectorSet.add(sBuilder.build());
+ });
+ } else {
+
+ TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+ buildMatches(sBuilder, sgRule, vmIp, remoteIp, netId);
+
+ selectorSet.add(sBuilder.build());
+ }
+
+ return selectorSet;
+ }
+
+ private void buildMatches(TrafficSelector.Builder sBuilder,
+ KubevirtSecurityGroupRule sgRule, Ip4Address vmIp,
+ IpPrefix remoteIp, String netId) {
+ buildTunnelId(sBuilder, netId);
+ buildMatchEthType(sBuilder, sgRule.etherType());
+ buildMatchDirection(sBuilder, sgRule.direction(), vmIp);
+ buildMatchProto(sBuilder, sgRule.protocol());
+ buildMatchPort(sBuilder, sgRule.protocol(), sgRule.direction(),
+ sgRule.portRangeMin() == null ? 0 : sgRule.portRangeMin(),
+ sgRule.portRangeMax() == null ? 0 : sgRule.portRangeMax());
+ buildMatchIcmp(sBuilder, sgRule.protocol(),
+ sgRule.portRangeMin(), sgRule.portRangeMax());
+ buildMatchRemoteIp(sBuilder, remoteIp, sgRule.direction());
+ }
+
+ private void buildTunnelId(TrafficSelector.Builder sBuilder, String netId) {
+ KubevirtNetwork network = networkService.network(netId);
+
+ if (network == null) {
+ log.warn("Network {} not found!", netId);
+ return;
+ }
+
+ String segId = network.segmentId();
+ Type netType = network.type();
+
+ if (netType == VLAN) {
+ sBuilder.matchVlanId(VlanId.vlanId(segId));
+ } else if (netType == VXLAN || netType == GRE || netType == GENEVE) {
+ // sBuilder.matchTunnelId(Long.parseLong(segId));
+ log.trace("{} typed match rules are installed for security group", netType);
+ } else {
+ log.debug("Cannot tag the VID as it is unsupported vnet type {}", netType);
+ }
+
+
+ }
+
+ private void buildMatchDirection(TrafficSelector.Builder sBuilder,
+ String direction,
+ Ip4Address vmIp) {
+ if (direction.equalsIgnoreCase(EGRESS)) {
+ sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
+ } else {
+ sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
+ }
+ }
+
+ 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 && !Objects.equals(etherType, STR_NULL) &&
+ !etherType.equalsIgnoreCase(ETHTYPE_IPV4)) {
+ log.debug("EthType {} is not supported yet in Security Group", etherType);
+ }
+ }
+
+ private void buildMatchRemoteIp(TrafficSelector.Builder sBuilder,
+ IpPrefix remoteIpPrefix, String direction) {
+ if (remoteIpPrefix != null &&
+ !remoteIpPrefix.getIp4Prefix().equals(IP_PREFIX_ANY)) {
+ if (direction.equalsIgnoreCase(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:
+ case PROTO_ICMP_NUM:
+ sBuilder.matchIPProtocol(IPv4.PROTOCOL_ICMP);
+ break;
+ case PROTO_TCP:
+ case PROTO_TCP_NUM:
+ sBuilder.matchIPProtocol(IPv4.PROTOCOL_TCP);
+ break;
+ case PROTO_UDP:
+ case PROTO_UDP_NUM:
+ sBuilder.matchIPProtocol(IPv4.PROTOCOL_UDP);
+ break;
+ case PROTO_SCTP:
+ case PROTO_SCTP_NUM:
+ sBuilder.matchIPProtocol(PROTOCOL_SCTP);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private void buildMatchPort(TrafficSelector.Builder sBuilder,
+ String protocol, String direction,
+ int portMin, int portMax) {
+ if (portMax > 0 && portMin == portMax) {
+ if (protocol.equalsIgnoreCase(PROTO_TCP) ||
+ protocol.equals(PROTO_TCP_NUM)) {
+ if (direction.equalsIgnoreCase(EGRESS)) {
+ sBuilder.matchTcpSrc(TpPort.tpPort(portMax));
+ } else {
+ sBuilder.matchTcpDst(TpPort.tpPort(portMax));
+ }
+ } else if (protocol.equalsIgnoreCase(PROTO_UDP) ||
+ protocol.equals(PROTO_UDP_NUM)) {
+ if (direction.equalsIgnoreCase(EGRESS)) {
+ sBuilder.matchUdpSrc(TpPort.tpPort(portMax));
+ } else {
+ sBuilder.matchUdpDst(TpPort.tpPort(portMax));
+ }
+ } else if (protocol.equalsIgnoreCase(PROTO_SCTP) ||
+ protocol.equals(PROTO_SCTP_NUM)) {
+ if (direction.equalsIgnoreCase(EGRESS)) {
+ sBuilder.matchSctpSrc(TpPort.tpPort(portMax));
+ } else {
+ sBuilder.matchSctpDst(TpPort.tpPort(portMax));
+ }
+ }
+ }
+ }
+
+ private void buildMatchIcmp(TrafficSelector.Builder sBuilder,
+ String protocol, Integer icmpCode, Integer icmpType) {
+ if (protocol != null) {
+ if (protocol.equalsIgnoreCase(PROTO_ICMP) ||
+ protocol.equals(PROTO_ICMP_NUM)) {
+ if (icmpCode != null && icmpCode >= ICMP_CODE_MIN &&
+ icmpCode <= ICMP_CODE_MAX) {
+ sBuilder.matchIcmpCode(icmpCode.byteValue());
+ }
+ if (icmpType != null && icmpType >= ICMP_TYPE_MIN &&
+ icmpType <= ICMP_TYPE_MAX) {
+ sBuilder.matchIcmpType(icmpType.byteValue());
+ }
+ }
+ }
+ }
+
+ private void resetSecurityGroupRules() {
+
+ if (getUseSecurityGroupFlag()) {
+ nodeService.completeNodes(WORKER).forEach(node -> {
+ initializeEgressTable(node.intgBridge(), true);
+ initializeConnTrackTable(node.intgBridge(), true);
+ initializeAclTable(node.intgBridge(), true);
+ initializeIngressTable(node.intgBridge(), true);
+
+ for (KubevirtNetwork network : networkService.tenantNetworks()) {
+ initializeEgressTable(network.tenantDeviceId(node.hostname()), true);
+ initializeIngressTable(network.tenantDeviceId(node.hostname()), true);
+ initializeConnTrackTable(network.tenantDeviceId(node.hostname()), true);
+ initializeAclTable(network.tenantDeviceId(node.hostname()), true);
+ }
+ });
+
+ securityGroupService.securityGroups().forEach(securityGroup ->
+ securityGroup.rules().forEach(this::securityGroupRuleAdded));
+ } else {
+ nodeService.completeNodes(WORKER).forEach(node -> {
+ initializeEgressTable(node.intgBridge(), false);
+ initializeConnTrackTable(node.intgBridge(), false);
+ initializeAclTable(node.intgBridge(), false);
+ initializeIngressTable(node.intgBridge(), false);
+
+ for (KubevirtNetwork network : networkService.tenantNetworks()) {
+ initializeEgressTable(network.tenantDeviceId(node.hostname()), false);
+ initializeIngressTable(network.tenantDeviceId(node.hostname()), false);
+ initializeConnTrackTable(network.tenantDeviceId(node.hostname()), false);
+ initializeAclTable(network.tenantDeviceId(node.hostname()), false);
+ }
+ });
+
+ securityGroupService.securityGroups().forEach(securityGroup ->
+ securityGroup.rules().forEach(this::securityGroupRuleRemoved));
+ }
+
+ log.info("Reset security group info " +
+ (getUseSecurityGroupFlag() ? "with" : "without") + " Security Group");
+ }
+
+ private void securityGroupRuleAdded(KubevirtSecurityGroupRule sgRule) {
+ portService.ports().stream()
+ .filter(port -> port.securityGroups().contains(sgRule.securityGroupId()))
+ .forEach(port -> {
+ updateSecurityGroupRule(port, sgRule, true);
+ log.info("Applied security group rule {} to port {}",
+ sgRule.id(), port.macAddress());
+ });
+ }
+
+ private void securityGroupRuleRemoved(KubevirtSecurityGroupRule sgRule) {
+ portService.ports().stream()
+ .filter(port -> port.securityGroups().contains(sgRule.securityGroupId()))
+ .forEach(port -> {
+ updateSecurityGroupRule(port, sgRule, false);
+ log.info("Removed security group rule {} from port {}",
+ sgRule.id(), port.macAddress());
+ });
+ }
+
+ private class InternalKubevirtPortListener implements KubevirtPortListener {
+
+ @Override
+ public boolean isRelevant(KubevirtPortEvent event) {
+ return getUseSecurityGroupFlag();
+ }
+
+ private boolean isRelevantHelper(KubevirtPortEvent event) {
+ DeviceId deviceId = event.subject().deviceId();
+
+ if (deviceId == null) {
+ return false;
+ }
+
+ return mastershipService.isLocalMaster(deviceId);
+ }
+
+ @Override
+ public void event(KubevirtPortEvent event) {
+ log.debug("security group event received {}", event);
+
+ switch (event.type()) {
+ case KUBEVIRT_PORT_SECURITY_GROUP_ADDED:
+ eventExecutor.execute(() -> processPortSgAdd(event));
+ break;
+ case KUBEVIRT_PORT_SECURITY_GROUP_REMOVED:
+ eventExecutor.execute(() -> processPortSgRemove(event));
+ break;
+ case KUBEVIRT_PORT_REMOVED:
+ eventExecutor.execute(() -> processPortRemove(event));
+ break;
+ case KUBEVIRT_PORT_DEVICE_ADDED:
+ eventExecutor.execute(() -> processPortDeviceAdded(event));
+ break;
+ default:
+ // do nothing for the other events
+ break;
+ }
+ }
+
+ private void processPortSgAdd(KubevirtPortEvent event) {
+ if (!isRelevantHelper(event)) {
+ return;
+ }
+
+ if (event.securityGroupId() == null ||
+ securityGroupService.securityGroup(event.securityGroupId()) == null) {
+ return;
+ }
+
+ KubevirtPort port = event.subject();
+ KubevirtSecurityGroup sg = securityGroupService.securityGroup(event.securityGroupId());
+
+ sg.rules().forEach(sgRule -> {
+ updateSecurityGroupRule(port, sgRule, true);
+ });
+ log.info("Added security group {} to port {}",
+ event.securityGroupId(), event.subject().macAddress());
+ }
+
+ private void processPortSgRemove(KubevirtPortEvent event) {
+ if (!isRelevantHelper(event)) {
+ return;
+ }
+
+ if (event.securityGroupId() == null ||
+ securityGroupService.securityGroup(event.securityGroupId()) == null) {
+ return;
+ }
+
+ KubevirtPort port = event.subject();
+ KubevirtSecurityGroup sg = securityGroupService.securityGroup(event.securityGroupId());
+
+ sg.rules().forEach(sgRule -> {
+ updateSecurityGroupRule(port, sgRule, false);
+ });
+ log.info("Removed security group {} from port {}",
+ event.securityGroupId(), event.subject().macAddress());
+ }
+
+ private void processPortRemove(KubevirtPortEvent event) {
+ if (!isRelevantHelper(event)) {
+ return;
+ }
+
+ KubevirtPort port = event.subject();
+ for (String sgStr : port.securityGroups()) {
+ KubevirtSecurityGroup sg = securityGroupService.securityGroup(sgStr);
+ sg.rules().forEach(sgRule -> {
+ updateSecurityGroupRule(port, sgRule, false);
+ });
+ log.info("Removed security group {} from port {}",
+ sgStr, event.subject().macAddress());
+ }
+ }
+
+ private void processPortDeviceAdded(KubevirtPortEvent event) {
+ if (!isRelevantHelper(event)) {
+ return;
+ }
+
+ for (String sgId : event.subject().securityGroups()) {
+ KubevirtSecurityGroup sg = securityGroupService.securityGroup(sgId);
+
+ sg.rules().forEach(sgRule -> {
+ updateSecurityGroupRule(event.subject(), sgRule, true);
+ });
+ log.info("Added security group {} to port {}",
+ event.securityGroupId(), event.subject().macAddress());
+ }
+ }
+ }
+
+ private class InternalNetworkListener implements KubevirtNetworkListener {
+
+ private boolean isRelevantHelper() {
+ return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
+ }
+
+ @Override
+ public void event(KubevirtNetworkEvent event) {
+ switch (event.type()) {
+ case KUBEVIRT_NETWORK_CREATED:
+ eventExecutor.execute(() -> processNetworkCreation(event.subject()));
+ break;
+ case KUBEVIRT_NETWORK_REMOVED:
+ case KUBEVIRT_NETWORK_UPDATED:
+ default:
+ // do thing
+ break;
+ }
+ }
+
+ private void processNetworkCreation(KubevirtNetwork network) {
+ if (!isRelevantHelper()) {
+ return;
+ }
+
+ Set<KubevirtNode> nodes = nodeService.completeNodes(WORKER);
+
+ if (nodes.size() > 0) {
+ // now we wait 5s for all tenant bridges are created,
+ // FIXME: we need to fina a better way to wait all tenant bridges
+ // are created before installing default security group rules
+ try {
+ sleep(SLEEP_MS);
+ } catch (InterruptedException e) {
+ log.error("Failed to install security group default rules.");
+ }
+
+ for (KubevirtNode node : nodes) {
+ initializeEgressTable(network.tenantDeviceId(node.hostname()), true);
+ initializeIngressTable(network.tenantDeviceId(node.hostname()), true);
+ initializeConnTrackTable(network.tenantDeviceId(node.hostname()), true);
+ initializeAclTable(network.tenantDeviceId(node.hostname()), true);
+ }
+ }
+ }
+ }
+
+ private class InternalSecurityGroupListener implements KubevirtSecurityGroupListener {
+
+ @Override
+ public boolean isRelevant(KubevirtSecurityGroupEvent event) {
+ return getUseSecurityGroupFlag();
+ }
+
+ private boolean isRelevantHelper() {
+ return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
+ }
+
+ @Override
+ public void event(KubevirtSecurityGroupEvent event) {
+ switch (event.type()) {
+ case KUBEVIRT_SECURITY_GROUP_RULE_CREATED:
+ eventExecutor.execute(() -> processSgRuleCreate(event));
+ break;
+ case KUBEVIRT_SECURITY_GROUP_RULE_REMOVED:
+ eventExecutor.execute(() -> processSgRuleRemove(event));
+ break;
+ default:
+ // do nothing
+ break;
+ }
+ }
+
+ private void processSgRuleCreate(KubevirtSecurityGroupEvent event) {
+ if (!isRelevantHelper()) {
+ return;
+ }
+
+ KubevirtSecurityGroupRule sgRuleToAdd = event.rule();
+ securityGroupRuleAdded(sgRuleToAdd);
+ log.info("Applied new security group rule {} to ports", sgRuleToAdd.id());
+ }
+
+ private void processSgRuleRemove(KubevirtSecurityGroupEvent event) {
+ if (!isRelevantHelper()) {
+ return;
+ }
+
+ KubevirtSecurityGroupRule sgRuleToRemove = event.rule();
+ securityGroupRuleRemoved(sgRuleToRemove);
+ log.info("Removed security group rule {} from ports", sgRuleToRemove.id());
+ }
+ }
+
+ private class InternalNodeListener implements KubevirtNodeListener {
+
+ @Override
+ public boolean isRelevant(KubevirtNodeEvent event) {
+ return event.subject().type() == WORKER;
+ }
+
+ private boolean isRelevantHelper() {
+ return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
+ }
+
+ @Override
+ public void event(KubevirtNodeEvent event) {
+ switch (event.type()) {
+ case KUBEVIRT_NODE_COMPLETE:
+ eventExecutor.execute(() -> processNodeComplete(event.subject()));
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void processNodeComplete(KubevirtNode node) {
+ if (!isRelevantHelper()) {
+ return;
+ }
+
+ resetSecurityGroupRulesByNode(node);
+ }
+
+ private void resetSecurityGroupRulesByNode(KubevirtNode node) {
+ if (getUseSecurityGroupFlag()) {
+ initializeEgressTable(node.intgBridge(), true);
+ initializeConnTrackTable(node.intgBridge(), true);
+ initializeAclTable(node.intgBridge(), true);
+ initializeIngressTable(node.intgBridge(), true);
+
+ for (KubevirtNetwork network : networkService.tenantNetworks()) {
+ initializeEgressTable(network.tenantDeviceId(node.hostname()), true);
+ initializeIngressTable(network.tenantDeviceId(node.hostname()), true);
+ initializeConnTrackTable(network.tenantDeviceId(node.hostname()), true);
+ initializeAclTable(network.tenantDeviceId(node.hostname()), true);
+ }
+
+ securityGroupService.securityGroups().forEach(securityGroup ->
+ securityGroup.rules().forEach(
+ KubevirtSecurityGroupHandler.this::securityGroupRuleAdded));
+ } else {
+ initializeEgressTable(node.intgBridge(), false);
+ initializeConnTrackTable(node.intgBridge(), false);
+ initializeAclTable(node.intgBridge(), false);
+ initializeIngressTable(node.intgBridge(), false);
+
+ for (KubevirtNetwork network : networkService.tenantNetworks()) {
+ initializeEgressTable(network.tenantDeviceId(node.hostname()), false);
+ initializeIngressTable(network.tenantDeviceId(node.hostname()), false);
+ initializeConnTrackTable(network.tenantDeviceId(node.hostname()), false);
+ initializeAclTable(network.tenantDeviceId(node.hostname()), false);
+ }
+
+ securityGroupService.securityGroups().forEach(securityGroup ->
+ securityGroup.rules().forEach(
+ KubevirtSecurityGroupHandler.this::securityGroupRuleRemoved));
+ }
+
+ log.info("Reset security group info " +
+ (getUseSecurityGroupFlag() ? "with" : "without") + " Security Group");
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtVmWatcher.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtVmWatcher.java
index 61b9be0..308707e 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtVmWatcher.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtVmWatcher.java
@@ -87,6 +87,8 @@
private static final String DOMAIN = "domain";
private static final String DEVICES = "devices";
private static final String INTERFACES = "interfaces";
+ private static final String NETWORK_POLICIES = "networkPolicies";
+ private static final String SECURITY_GROUPS = "securityGroups";
private static final String NAME = "name";
private static final String NETWORK = "network";
private static final String MAC = "macAddress";
@@ -211,6 +213,9 @@
case DELETED:
eventExecutor.execute(() -> processDeletion(resource));
break;
+ case MODIFIED:
+ eventExecutor.execute(() -> processModification(resource));
+ break;
case ERROR:
log.warn("Failures processing VM manipulation.");
break;
@@ -238,6 +243,9 @@
String name = parseResourceName(resource);
+ Set<String> sgs = parseSecurityGroups(resource);
+ port = port.updateSecurityGroups(sgs);
+
Map<String, IpAddress> ips = parseIpAddresses(resource);
IpAddress ip;
IpAddress existingIp = ips.get(port.networkId());
@@ -303,6 +311,28 @@
});
}
+ private void processModification(String resource) {
+ if (!isMaster()) {
+ return;
+ }
+
+ parseMacAddresses(resource).forEach((mac, net) -> {
+ KubevirtPort port = DefaultKubevirtPort.builder()
+ .macAddress(mac)
+ .networkId(net)
+ .build();
+
+ KubevirtPort existing = portAdminService.port(port.macAddress());
+
+ if (existing == null) {
+ return;
+ }
+
+ Set<String> sgs = parseSecurityGroups(resource);
+ portAdminService.updatePort(existing.updateSecurityGroups(sgs));
+ });
+ }
+
private void processDeletion(String resource) {
if (!isMaster()) {
return;
@@ -410,6 +440,37 @@
return null;
}
+ private Set<String> parseSecurityGroups(String resource) {
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode json = mapper.readTree(resource);
+ JsonNode metadata = json.get(SPEC).get(TEMPLATE).get(METADATA);
+
+ JsonNode annots = metadata.get(ANNOTATIONS);
+ if (annots == null) {
+ return new HashSet<>();
+ }
+
+ JsonNode sgsJson = annots.get(SECURITY_GROUPS);
+ if (sgsJson == null) {
+ return new HashSet<>();
+ }
+
+ Set<String> result = new HashSet<>();
+ ArrayNode sgs = (ArrayNode) mapper.readTree(sgsJson.asText());
+ for (JsonNode sg : sgs) {
+ result.add(sg.asText());
+ }
+
+ return result;
+
+ } catch (IOException e) {
+ log.error("Failed to parse kubevirt security group IDs.");
+ }
+
+ return new HashSet<>();
+ }
+
private Map<MacAddress, String> parseMacAddresses(String resource) {
try {
ObjectMapper mapper = new ObjectMapper();
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/OsgiPropertyConstants.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/OsgiPropertyConstants.java
index 68b15ea..5d5742b 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/OsgiPropertyConstants.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/OsgiPropertyConstants.java
@@ -28,4 +28,7 @@
static final String DHCP_SERVER_MAC = "dhcpServerMac";
static final String DHCP_SERVER_MAC_DEFAULT = "fe:00:00:00:00:02";
+
+ static final String USE_SECURITY_GROUP = "useSecurityGroup";
+ static final boolean USE_SECURITY_GROUP_DEFAULT = true;
}
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/util/RulePopulatorUtil.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/util/RulePopulatorUtil.java
index 610066f..304e9b6 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/util/RulePopulatorUtil.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/util/RulePopulatorUtil.java
@@ -15,15 +15,19 @@
*/
package org.onosproject.kubevirtnetworking.util;
+import com.google.common.collect.Maps;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.TpPort;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ExtensionSelectorResolver;
import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.driver.DriverHandler;
import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.flow.criteria.ExtensionSelector;
+import org.onosproject.net.flow.criteria.ExtensionSelectorType;
import org.onosproject.net.flow.instructions.ExtensionPropertyException;
import org.onosproject.net.flow.instructions.ExtensionTreatment;
import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
@@ -31,6 +35,8 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.Objects;
import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_LOAD;
import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_MOV_ARP_SHA_TO_THA;
@@ -257,6 +263,185 @@
}
}
+
+ /**
+ * Builds OVS ConnTrack matches.
+ *
+ * @param driverService driver service
+ * @param deviceId device ID
+ * @param ctState connection tracking sate masking value
+ * @param ctSateMask connection tracking sate masking value
+ * @return OVS ConnTrack extension match
+ */
+ public static ExtensionSelector buildCtExtensionSelector(DriverService driverService,
+ DeviceId deviceId,
+ long ctState,
+ long ctSateMask) {
+ DriverHandler handler = driverService.createHandler(deviceId);
+ ExtensionSelectorResolver esr = handler.behaviour(ExtensionSelectorResolver.class);
+
+ ExtensionSelector extensionSelector = esr.getExtensionSelector(
+ ExtensionSelectorType.ExtensionSelectorTypes.NICIRA_MATCH_CONNTRACK_STATE.type());
+ try {
+ extensionSelector.setPropertyValue(CT_STATE, ctState);
+ extensionSelector.setPropertyValue(CT_STATE_MASK, ctSateMask);
+ } catch (Exception e) {
+ log.error("Failed to set nicira match CT state because of {}", e);
+ return null;
+ }
+
+ return extensionSelector;
+ }
+
+ /**
+ * Computes ConnTack State flag values.
+ *
+ * @param isTracking true for +trk, false for -trk
+ * @param isNew true for +new, false for nothing
+ * @param isEstablished true for +est, false for nothing
+ * @return ConnTrack State flags
+ */
+ public static long computeCtStateFlag(boolean isTracking,
+ boolean isNew,
+ boolean isEstablished) {
+ long ctMaskFlag = 0x00;
+
+ if (isTracking) {
+ ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
+ }
+
+ if (isNew) {
+ ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
+ ctMaskFlag = ctMaskFlag | CT_STATE_NEW;
+ }
+
+ if (isEstablished) {
+ ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
+ ctMaskFlag = ctMaskFlag | CT_STATE_EST;
+ }
+
+ return ctMaskFlag;
+ }
+
+ /**
+ * Computes ConnTrack State mask values.
+ *
+ * @param isTracking true for setting +trk/-trk value, false for otherwise
+ * @param isNew true for setting +new value, false for otherwise
+ * @param isEstablished true for setting +est value, false for otherwise
+ * @return ConnTrack State Mask value
+ */
+ public static long computeCtMaskFlag(boolean isTracking,
+ boolean isNew,
+ boolean isEstablished) {
+ long ctMaskFlag = 0x00;
+
+ if (isTracking) {
+ ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
+ }
+
+ if (isNew) {
+ ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
+ ctMaskFlag = ctMaskFlag | CT_STATE_NEW;
+ }
+
+ if (isEstablished) {
+ ctMaskFlag = ctMaskFlag | CT_STATE_TRK;
+ ctMaskFlag = ctMaskFlag | CT_STATE_EST;
+ }
+
+ return ctMaskFlag;
+ }
+
+ /**
+ * Computes port and port mask value from port min/max values.
+ *
+ * @param portMin port min value
+ * @param portMax port max value
+ * @return Port Mask value
+ */
+ public static Map<TpPort, TpPort> buildPortRangeMatches(int portMin, int portMax) {
+
+ boolean processing = true;
+ int start = portMin;
+ Map<TpPort, TpPort> portMaskMap = Maps.newHashMap();
+ while (processing) {
+ String minStr = Integer.toBinaryString(start);
+ String binStrMinPadded = STR_PADDING.substring(minStr.length()) + minStr;
+
+ int mask = testMasks(binStrMinPadded, start, portMax);
+ int maskStart = binLower(binStrMinPadded, mask);
+ int maskEnd = binHigher(binStrMinPadded, mask);
+
+ log.debug("start : {} port/mask = {} / {} ", start, getMask(mask), maskStart);
+ portMaskMap.put(TpPort.tpPort(maskStart), TpPort.tpPort(
+ Integer.parseInt(Objects.requireNonNull(getMask(mask)), PORT_RADIX)));
+
+ start = maskEnd + 1;
+ if (start > portMax) {
+ processing = false;
+ }
+ }
+
+ return portMaskMap;
+ }
+
+ private static int binLower(String binStr, int bits) {
+ StringBuilder outBin = new StringBuilder(
+ binStr.substring(MASK_BEGIN_IDX, MASK_MAX_IDX - bits));
+ for (int i = 0; i < bits; i++) {
+ outBin.append(STR_ZERO);
+ }
+
+ return Integer.parseInt(outBin.toString(), MASK_RADIX);
+ }
+
+ private static int binHigher(String binStr, int bits) {
+ StringBuilder outBin = new StringBuilder(
+ binStr.substring(MASK_BEGIN_IDX, MASK_MAX_IDX - bits));
+ for (int i = 0; i < bits; i++) {
+ outBin.append(STR_ONE);
+ }
+
+ return Integer.parseInt(outBin.toString(), MASK_RADIX);
+ }
+
+ private static int testMasks(String binStr, int start, int end) {
+ int mask = MASK_BEGIN_IDX;
+ for (; mask <= MASK_MAX_IDX; mask++) {
+ int maskStart = binLower(binStr, mask);
+ int maskEnd = binHigher(binStr, mask);
+ if (maskStart < start || maskEnd > end) {
+ return mask - 1;
+ }
+ }
+
+ return mask;
+ }
+
+ private static String getMask(int bits) {
+ switch (bits) {
+ case 0: return "ffff";
+ case 1: return "fffe";
+ case 2: return "fffc";
+ case 3: return "fff8";
+ case 4: return "fff0";
+ case 5: return "ffe0";
+ case 6: return "ffc0";
+ case 7: return "ff80";
+ case 8: return "ff00";
+ case 9: return "fe00";
+ case 10: return "fc00";
+ case 11: return "f800";
+ case 12: return "f000";
+ case 13: return "e000";
+ case 14: return "c000";
+ case 15: return "8000";
+ case 16: return "0000";
+ default: return null;
+ }
+ }
+
public static NiciraConnTrackTreatmentBuilder niciraConnTrackTreatmentBuilder(DriverService ds, DeviceId id) {
return new NiciraConnTrackTreatmentBuilder(ds, id);
}