[AETHER-1295][AETHER-1294] First stab to the TOST APIs framework
and to the DROP policies.
Patch includes also some CLI commands. REST APIs will be implemented
in a separate review. Other review will follow to implement the logic
of the REDIRECT policies
Change-Id: I34aa3da700c5a16682196e4dd8db9c4757d609c4
diff --git a/api/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java b/api/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java
index 2d0bbd2..bb86aac 100644
--- a/api/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java
+++ b/api/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java
@@ -101,6 +101,13 @@
boolean isEdgeDevice(DeviceId deviceId) throws DeviceConfigNotFoundException;
/**
+ * Returns a list of edge devices.
+ *
+ * @return list of the edge device ids
+ */
+ List<DeviceId> getEdgeDeviceIds();
+
+ /**
* Returns all segment IDs to be considered in building auto
*
* created groups.
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java b/impl/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
index 3251e7a..04d63a2 100644
--- a/impl/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
+++ b/impl/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
@@ -394,6 +394,14 @@
}
@Override
+ public List<DeviceId> getEdgeDeviceIds() {
+ return deviceConfigMap.values().stream()
+ .filter(deviceInfo -> deviceInfo.isEdge)
+ .map(deviceInfo -> deviceInfo.deviceId)
+ .collect(Collectors.toList());
+ }
+
+ @Override
public List<Integer> getAllDeviceSegmentIds() {
return allSegmentIds;
}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/impl/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 9e98218..f65d4ea 100644
--- a/impl/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/impl/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -1199,6 +1199,11 @@
.collect(Collectors.toSet());
}
+ @Override
+ public List<DeviceId> getEdgeDeviceIds() {
+ return deviceConfiguration.getEdgeDeviceIds();
+ }
+
/**
* Returns locations of given resolved route.
*
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java b/impl/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
index 3bfd88b..95b5be5 100644
--- a/impl/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
+++ b/impl/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
@@ -436,4 +436,11 @@
default Set<PortNumber> getEdgePorts(DeviceId deviceId) {
throw new NotImplementedException("getEdgePorts not implemented");
}
+
+ /**
+ * Returns a list of edge devices.
+ *
+ * @return list of the edge device ids
+ */
+ List<DeviceId> getEdgeDeviceIds();
}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/cli/DropPolicyAddCommand.java b/impl/src/main/java/org/onosproject/segmentrouting/cli/DropPolicyAddCommand.java
new file mode 100644
index 0000000..9c3cb51
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/cli/DropPolicyAddCommand.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015-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.segmentrouting.cli;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.segmentrouting.policy.api.DropPolicy;
+import org.onosproject.segmentrouting.policy.api.PolicyId;
+import org.onosproject.segmentrouting.policy.api.PolicyService;
+
+/**
+ * Command to add a new drop policy.
+ */
+@Service
+@Command(scope = "onos", name = "sr-drop-policy-add",
+ description = "Create a new drop policy")
+public class DropPolicyAddCommand extends AbstractShellCommand {
+
+ @Override
+ protected void doExecute() {
+ PolicyService policyService = AbstractShellCommand.get(PolicyService.class);
+ PolicyId policyId = policyService.addOrUpdatePolicy(new DropPolicy());
+ print("Policy %s has been submitted", policyId);
+ }
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/cli/PolicyAddCommand.java b/impl/src/main/java/org/onosproject/segmentrouting/cli/PolicyAddCommand.java
deleted file mode 100644
index 1f75317..0000000
--- a/impl/src/main/java/org/onosproject/segmentrouting/cli/PolicyAddCommand.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2015-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.segmentrouting.cli;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.Policy;
-import org.onosproject.segmentrouting.PolicyHandler;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.TunnelPolicy;
-
-/**
- * Command to add a new policy.
- */
-@Service
-@Command(scope = "onos", name = "sr-policy-add",
- description = "Create a new policy")
-public class PolicyAddCommand extends AbstractShellCommand {
-
- // TODO: Need to support skipping some parameters
-
- @Argument(index = 0, name = "ID",
- description = "policy ID",
- required = true, multiValued = false)
- String policyId;
-
- @Argument(index = 1, name = "priority",
- description = "priority",
- required = true, multiValued = false)
- int priority;
-
- @Argument(index = 2, name = "src_IP",
- description = "src IP",
- required = false, multiValued = false)
- String srcIp;
-
- @Argument(index = 3, name = "src_port",
- description = "src port",
- required = false, multiValued = false)
- short srcPort;
-
- @Argument(index = 4, name = "dst_IP",
- description = "dst IP",
- required = false, multiValued = false)
- String dstIp;
-
- @Argument(index = 5, name = "dst_port",
- description = "dst port",
- required = false, multiValued = false)
- short dstPort;
-
- @Argument(index = 6, name = "proto",
- description = "IP protocol",
- required = false, multiValued = false)
- String proto;
-
- @Argument(index = 7, name = "policy_type",
- description = "policy type",
- required = true, multiValued = false)
- String policyType;
-
- @Argument(index = 8, name = "tunnel_ID",
- description = "tunnel ID",
- required = false, multiValued = false)
- String tunnelId;
-
- @Override
- protected void doExecute() {
-
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- TunnelPolicy.Builder tpb = TunnelPolicy.builder().setPolicyId(policyId);
- tpb.setPriority(priority);
- tpb.setType(Policy.Type.valueOf(policyType));
-
- if (srcIp != null) {
- tpb.setSrcIp(srcIp);
- }
- if (dstIp != null) {
- tpb.setDstIp(dstIp);
- }
- if (srcPort != 0) {
- tpb.setSrcPort(srcPort);
- }
- if (dstPort != 0) {
- tpb.setDstPort(dstPort);
- }
- if (!"ip".equals(proto)) {
- tpb.setIpProto(proto);
- }
- if (Policy.Type.valueOf(policyType) == Policy.Type.TUNNEL_FLOW) {
- if (tunnelId == null) {
- error("tunnel ID must be specified for TUNNEL_FLOW policy");
- return;
- }
- tpb.setTunnelId(tunnelId);
- }
- PolicyHandler.Result result = srService.createPolicy(tpb.build());
-
- switch (result) {
- case POLICY_EXISTS:
- error("the same policy exists");
- break;
- case ID_EXISTS:
- error("the same policy ID exists");
- break;
- case TUNNEL_NOT_FOUND:
- error("the tunnel is not found");
- break;
- case UNSUPPORTED_TYPE:
- error("the policy type specified is not supported");
- break;
- default:
- break;
- }
-
- }
-}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/cli/PolicyListCommand.java b/impl/src/main/java/org/onosproject/segmentrouting/cli/PolicyListCommand.java
index 3520fba..1c61912 100644
--- a/impl/src/main/java/org/onosproject/segmentrouting/cli/PolicyListCommand.java
+++ b/impl/src/main/java/org/onosproject/segmentrouting/cli/PolicyListCommand.java
@@ -16,11 +16,16 @@
package org.onosproject.segmentrouting.cli;
import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.glassfish.jersey.internal.guava.Sets;
+
import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.Policy;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.TunnelPolicy;
+import org.onosproject.segmentrouting.policy.api.Policy;
+import org.onosproject.segmentrouting.policy.api.PolicyData;
+import org.onosproject.segmentrouting.policy.api.PolicyService;
+
+import java.util.Set;
/**
* Command to show the list of policies.
@@ -30,24 +35,37 @@
description = "Lists all policies")
public class PolicyListCommand extends AbstractShellCommand {
- private static final String FORMAT_MAPPING_TUNNEL =
- " id=%s, type=%s, prio=%d, src=%s, port=%d, dst=%s, port=%d, proto=%s, tunnel=%s";
+ private static final String FORMAT_MAPPING_POLICY =
+ " id=%s, state=%s, type=%s";
+ private static final String FORMAT_MAPPING_OPERATION =
+ " op=%s";
+
+ @Option(name = "-filt", aliases = "--filter",
+ description = "Filter based on policy type",
+ valueToShowInHelp = "DROP",
+ multiValued = true)
+ String[] filters = null;
@Override
protected void doExecute() {
-
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- srService.getPolicies().forEach(policy -> printPolicy(policy));
+ PolicyService policyService =
+ AbstractShellCommand.get(PolicyService.class);
+ policyService.policies(policyTypes()).forEach(this::printPolicy);
}
- private void printPolicy(Policy policy) {
- if (policy.type() == Policy.Type.TUNNEL_FLOW) {
- print(FORMAT_MAPPING_TUNNEL, policy.id(), policy.type(), policy.priority(),
- policy.srcIp(), policy.srcPort(), policy.dstIp(), policy.dstPort(),
- (policy.ipProto() == null) ? "" : policy.ipProto(),
- ((TunnelPolicy) policy).tunnelId());
+ private Set<Policy.PolicyType> policyTypes() {
+ Set<Policy.PolicyType> policyTypes = Sets.newHashSet();
+ if (filters != null) {
+ for (String filter : filters) {
+ policyTypes.add(Policy.PolicyType.valueOf(filter));
+ }
}
+ return policyTypes;
+ }
+
+ private void printPolicy(PolicyData policyData) {
+ print(FORMAT_MAPPING_POLICY, policyData.policy().policyId(), policyData.policyState(),
+ policyData.policy().policyType());
+ policyData.operations().forEach(operation -> print(FORMAT_MAPPING_OPERATION, operation));
}
}
\ No newline at end of file
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/cli/PolicyRemoveCommand.java b/impl/src/main/java/org/onosproject/segmentrouting/cli/PolicyRemoveCommand.java
index 575d35f..ff35423 100644
--- a/impl/src/main/java/org/onosproject/segmentrouting/cli/PolicyRemoveCommand.java
+++ b/impl/src/main/java/org/onosproject/segmentrouting/cli/PolicyRemoveCommand.java
@@ -15,14 +15,13 @@
*/
package org.onosproject.segmentrouting.cli;
-
import org.apache.karaf.shell.api.action.Argument;
import org.apache.karaf.shell.api.action.Command;
import org.apache.karaf.shell.api.action.lifecycle.Service;
+
import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.PolicyHandler;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.TunnelPolicy;
+import org.onosproject.segmentrouting.policy.api.PolicyId;
+import org.onosproject.segmentrouting.policy.api.PolicyService;
/**
* Command to remove a policy.
@@ -32,21 +31,18 @@
description = "Remove a policy")
public class PolicyRemoveCommand extends AbstractShellCommand {
- @Argument(index = 0, name = "policy ID",
- description = "policy ID",
+ @Argument(index = 0, name = "policyId",
+ description = "policy id",
required = true, multiValued = false)
String policyId;
@Override
protected void doExecute() {
-
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- TunnelPolicy.Builder tpb = TunnelPolicy.builder().setPolicyId(policyId);
- PolicyHandler.Result result = srService.removePolicy(tpb.build());
- if (result == PolicyHandler.Result.POLICY_NOT_FOUND) {
- print("ERROR: the policy is not found");
+ PolicyService policyService = AbstractShellCommand.get(PolicyService.class);
+ if (policyService.removePolicy(PolicyId.of(policyId))) {
+ print("Removing policy %s", policyId);
+ } else {
+ print("Unable to remove policy %s", policyId);
}
}
}
\ No newline at end of file
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchAddCommand.java b/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchAddCommand.java
new file mode 100644
index 0000000..d8b7a0a
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchAddCommand.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2015-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.segmentrouting.cli;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+import org.onlab.packet.IPv4;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.TpPort;
+import org.onlab.packet.VlanId;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.cli.net.IpProtocol;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.segmentrouting.policy.api.PolicyId;
+import org.onosproject.segmentrouting.policy.api.PolicyService;
+import org.onosproject.segmentrouting.policy.api.TrafficMatch;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchId;
+
+/**
+ * Command to add a traffic match.
+ */
+@Service
+@Command(scope = "onos", name = "sr-tmatch-add",
+ description = "Create a new traffic match")
+public class TrafficMatchAddCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "policyId",
+ description = "policy id",
+ required = true, multiValued = false)
+ String policyId;
+
+ @Argument(index = 1, name = "srcIp",
+ description = "src IP",
+ required = false, multiValued = false)
+ String srcIp;
+
+ @Argument(index = 2, name = "srcPort",
+ description = "src port",
+ required = false, multiValued = false)
+ short srcPort;
+
+ @Argument(index = 3, name = "dstIp",
+ description = "dst IP",
+ required = false, multiValued = false)
+ String dstIp;
+
+ @Argument(index = 4, name = "dstPort",
+ description = "dst port",
+ required = false, multiValued = false)
+ short dstPort;
+
+ @Argument(index = 5, name = "proto",
+ description = "IP protocol",
+ required = false, multiValued = false)
+ String proto;
+
+ @Argument(index = 6, name = "srcMac",
+ description = "src MAC",
+ required = false, multiValued = false)
+ String srcMac;
+
+ @Argument(index = 7, name = "dstMac",
+ description = "dst MAC",
+ required = false, multiValued = false)
+ String dstMac;
+
+ @Argument(index = 8, name = "vlanId",
+ description = "VLAN id",
+ required = false, multiValued = false)
+ short vlanId = -1;
+
+ @Override
+ protected void doExecute() {
+ TrafficSelector trafficSelector = parseArguments();
+ if (trafficSelector.equals(DefaultTrafficSelector.emptySelector())) {
+ print("Empty traffic selector is not allowed");
+ return;
+ }
+
+ PolicyService policyService = AbstractShellCommand.get(PolicyService.class);
+ TrafficMatchId trafficMatchId = policyService.addOrUpdateTrafficMatch(
+ new TrafficMatch(trafficSelector, PolicyId.of(policyId)));
+ print("Traffic match %s has been submitted", trafficMatchId);
+ }
+
+ private TrafficSelector parseArguments() {
+ TrafficSelector.Builder trafficSelectorBuilder = DefaultTrafficSelector.builder();
+ if (srcIp != null) {
+ trafficSelectorBuilder.matchIPSrc(IpPrefix.valueOf(srcIp));
+ }
+ if (dstIp != null) {
+ trafficSelectorBuilder.matchIPDst(IpPrefix.valueOf(dstIp));
+ }
+ byte ipProtocol = 0;
+ if (proto != null) {
+ ipProtocol = (byte) (0xFF & IpProtocol.parseFromString(proto));
+ trafficSelectorBuilder.matchIPProtocol(ipProtocol);
+ }
+ if (srcPort != 0) {
+ if (ipProtocol == IPv4.PROTOCOL_TCP) {
+ trafficSelectorBuilder.matchTcpSrc(TpPort.tpPort(srcPort));
+ } else if (ipProtocol == IPv4.PROTOCOL_UDP) {
+ trafficSelectorBuilder.matchUdpSrc(TpPort.tpPort(srcPort));
+ }
+ }
+ if (dstPort != 0) {
+ if (ipProtocol == IPv4.PROTOCOL_TCP) {
+ trafficSelectorBuilder.matchTcpDst(TpPort.tpPort(dstPort));
+ } else if (ipProtocol == IPv4.PROTOCOL_UDP) {
+ trafficSelectorBuilder.matchUdpDst(TpPort.tpPort(dstPort));
+ }
+ }
+ if (srcMac != null) {
+ trafficSelectorBuilder.matchEthSrc(MacAddress.valueOf(srcMac));
+ }
+ if (dstMac != null) {
+ trafficSelectorBuilder.matchEthDst(MacAddress.valueOf(dstMac));
+ }
+ if (vlanId != -1) {
+ trafficSelectorBuilder.matchVlanId(VlanId.vlanId(vlanId));
+ }
+ return trafficSelectorBuilder.build();
+ }
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchListCommand.java b/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchListCommand.java
new file mode 100644
index 0000000..c00d1fa
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchListCommand.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015-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.segmentrouting.cli;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.segmentrouting.policy.api.PolicyService;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchData;
+
+/**
+ * Command to show the list of traffic matches.
+ */
+@Service
+@Command(scope = "onos", name = "sr-tmatch-list",
+ description = "Lists all traffic matches")
+public class TrafficMatchListCommand extends AbstractShellCommand {
+
+ private static final String FORMAT_MAPPING_TRAFFIC_MATCH =
+ " id=%s, state=%s";
+ private static final String FORMAT_MAPPING_OPERATION =
+ " op=%s";
+
+ @Override
+ protected void doExecute() {
+ PolicyService policyService = AbstractShellCommand.get(PolicyService.class);
+ policyService.trafficMatches().forEach(this::printTrafficMatch);
+ }
+
+ private void printTrafficMatch(TrafficMatchData trafficMatchData) {
+ print(FORMAT_MAPPING_TRAFFIC_MATCH, trafficMatchData.trafficMatch().trafficMatchId(),
+ trafficMatchData.trafficMatchState());
+ trafficMatchData.operations().forEach(operation -> print(FORMAT_MAPPING_OPERATION, operation));
+ }
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchRemoveCommand.java b/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchRemoveCommand.java
new file mode 100644
index 0000000..763e9c8
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchRemoveCommand.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2015-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.segmentrouting.cli;
+
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.segmentrouting.policy.api.PolicyService;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchId;
+
+/**
+ * Command to remove a traffic match.
+ */
+@Service
+@Command(scope = "onos", name = "sr-tmatch-remove",
+ description = "Remove a traffic match")
+public class TrafficMatchRemoveCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "trafficMatchId",
+ description = "traffic match id",
+ required = true, multiValued = false)
+ String trafficMatchId;
+
+ @Override
+ protected void doExecute() {
+ PolicyService policyService = AbstractShellCommand.get(PolicyService.class);
+ trafficMatchId = trafficMatchId.replace("\\", "");
+ if (policyService.removeTrafficMatch(TrafficMatchId.of(trafficMatchId))) {
+ print("Removing traffic match %s", trafficMatchId);
+ } else {
+ print("Unable to remove traffic match %s", trafficMatchId);
+ }
+ }
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/cli/TunnelAddCommand.java b/impl/src/main/java/org/onosproject/segmentrouting/cli/TunnelAddCommand.java
deleted file mode 100644
index 0e487d0..0000000
--- a/impl/src/main/java/org/onosproject/segmentrouting/cli/TunnelAddCommand.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2015-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.segmentrouting.cli;
-
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.DefaultTunnel;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.Tunnel;
-import org.onosproject.segmentrouting.TunnelHandler;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.StringTokenizer;
-
-/**
- * Command to add a new tunnel.
- */
-@Service
-@Command(scope = "onos", name = "sr-tunnel-add",
- description = "Create a new tunnel")
-public class TunnelAddCommand extends AbstractShellCommand {
-
- @Argument(index = 0, name = "tunnel ID",
- description = "tunnel ID",
- required = true, multiValued = false)
- String tunnelId;
-
- @Argument(index = 1, name = "label path",
- description = "label path",
- required = true, multiValued = false)
- String labels;
-
-
- @Override
- protected void doExecute() {
-
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- List<Integer> labelIds = new ArrayList<>();
- StringTokenizer strToken = new StringTokenizer(labels, ",");
- while (strToken.hasMoreTokens()) {
- labelIds.add(Integer.valueOf(strToken.nextToken()));
- }
- Tunnel tunnel = new DefaultTunnel(tunnelId, labelIds);
-
- TunnelHandler.Result result = srService.createTunnel(tunnel);
- switch (result) {
- case ID_EXISTS:
- print("ERROR: the same tunnel ID exists");
- break;
- case TUNNEL_EXISTS:
- print("ERROR: the same tunnel exists");
- break;
- case INTERNAL_ERROR:
- print("ERROR: internal tunnel creation error");
- break;
- case WRONG_PATH:
- print("ERROR: the tunnel path is wrong");
- break;
- default:
- break;
- }
- }
-}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/cli/TunnelListCommand.java b/impl/src/main/java/org/onosproject/segmentrouting/cli/TunnelListCommand.java
deleted file mode 100644
index 6c5f33d..0000000
--- a/impl/src/main/java/org/onosproject/segmentrouting/cli/TunnelListCommand.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2015-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.segmentrouting.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.Tunnel;
-
-/**
- * Command to show the list of tunnels.
- */
-@Service
-@Command(scope = "onos", name = "sr-tunnel-list",
- description = "Lists all tunnels")
-public class TunnelListCommand extends AbstractShellCommand {
-
- private static final String FORMAT_MAPPING =
- " id=%s, path=%s";
-
- @Override
- protected void doExecute() {
-
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- srService.getTunnels().forEach(tunnel -> printTunnel(tunnel));
- }
-
- private void printTunnel(Tunnel tunnel) {
- print(FORMAT_MAPPING, tunnel.id(), tunnel.labelIds());
- }
-}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/cli/TunnelRemoveCommand.java b/impl/src/main/java/org/onosproject/segmentrouting/cli/TunnelRemoveCommand.java
deleted file mode 100644
index f5f0299..0000000
--- a/impl/src/main/java/org/onosproject/segmentrouting/cli/TunnelRemoveCommand.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2015-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.segmentrouting.cli;
-
-
-import com.google.common.collect.Lists;
-import org.apache.karaf.shell.api.action.Argument;
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.segmentrouting.DefaultTunnel;
-import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.Tunnel;
-import org.onosproject.segmentrouting.TunnelHandler;
-
-/**
- * Command to remove a tunnel.
- */
-@Service
-@Command(scope = "onos", name = "sr-tunnel-remove",
- description = "Remove a tunnel")
-public class TunnelRemoveCommand extends AbstractShellCommand {
-
- @Argument(index = 0, name = "tunnel ID",
- description = "tunnel ID",
- required = true, multiValued = false)
- String tunnelId;
-
- @Override
- protected void doExecute() {
- SegmentRoutingService srService =
- AbstractShellCommand.get(SegmentRoutingService.class);
-
- Tunnel tunnel = new DefaultTunnel(tunnelId, Lists.newArrayList());
- TunnelHandler.Result result = srService.removeTunnel(tunnel);
- switch (result) {
- case TUNNEL_IN_USE:
- print("ERROR: the tunnel is still in use");
- break;
- case TUNNEL_NOT_FOUND:
- print("ERROR: the tunnel is not found");
- break;
- default:
- break;
- }
- }
-}
\ No newline at end of file
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/api/AbstractPolicy.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/AbstractPolicy.java
new file mode 100644
index 0000000..4be54a7
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/AbstractPolicy.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.api;
+
+/**
+ * Abstract implementation of the policy interface.
+ */
+public abstract class AbstractPolicy implements Policy {
+ // Shared state among policies
+ protected PolicyId policyId;
+ private PolicyType policyType;
+
+ /**
+ * Init the basic information of a policy.
+ *
+ * @param pType the policy type
+ */
+ protected AbstractPolicy(PolicyType pType) {
+ policyType = pType;
+ }
+
+ @Override
+ public PolicyId policyId() {
+ return policyId;
+ }
+
+ @Override
+ public PolicyType policyType() {
+ return policyType;
+ }
+
+ protected abstract PolicyId computePolicyId();
+
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/api/DropPolicy.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/DropPolicy.java
new file mode 100644
index 0000000..ac2e05e
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/DropPolicy.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.api;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Implementation of the drop policy.
+ */
+public final class DropPolicy extends AbstractPolicy {
+ /**
+ * Builds up a DROP policy.
+ */
+ public DropPolicy() {
+ super(PolicyType.DROP);
+ policyId = computePolicyId();
+ }
+
+ @Override
+ protected PolicyId computePolicyId() {
+ return PolicyId.of(policyType().name());
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof DropPolicy)) {
+ return false;
+ }
+ final DropPolicy other = (DropPolicy) obj;
+ return Objects.equals(policyType(), other.policyType()) &&
+ Objects.equals(policyId(), other.policyId());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(policyId(), policyType());
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("policyId", policyId())
+ .add("policyType", policyType())
+ .toString();
+ }
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/api/Policy.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/Policy.java
new file mode 100644
index 0000000..bc1acf0
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/Policy.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.api;
+
+/**
+ * Represents a policy in TOST.
+ */
+public interface Policy {
+ /**
+ * Represents the type of a policy.
+ */
+ enum PolicyType {
+ /**
+ * The policy drops the associated traffic.
+ */
+ DROP,
+
+ /**
+ * The policy redirects traffic using custom routing.
+ */
+ REDIRECT
+ }
+
+ /**
+ * Returns the policy id.
+ *
+ * @return the policy id
+ */
+ PolicyId policyId();
+
+ /**
+ * Returns the policy type.
+ *
+ * @return the type of a policy
+ */
+ PolicyType policyType();
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyData.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyData.java
new file mode 100644
index 0000000..5e207ae
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyData.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.api;
+
+import java.util.List;
+
+/**
+ * Policy data retrieved from the system.
+ */
+public final class PolicyData {
+ // We want to provide access to the policy data as well as
+ // the policy operations in the system and their status
+ private final PolicyState policyState;
+ private final Policy policy;
+ private final List<String> operations;
+
+ /**
+ * Creates a policy data.
+ *
+ * @param pState the policy state
+ * @param pol the policy
+ * @param ops the operations associated
+ */
+ public PolicyData(PolicyState pState, Policy pol, List<String> ops) {
+ policy = pol;
+ policyState = pState;
+ operations = ops;
+ }
+
+ /**
+ * Returns the current state of the policy.
+ *
+ * @return the policy state
+ */
+ public PolicyState policyState() {
+ return policyState;
+ }
+
+
+ /**
+ * Returns the policy associated.
+ *
+ * @return the policy
+ */
+ public Policy policy() {
+ return policy;
+ }
+
+ /**
+ * Returns the operations in the system in form of strings.
+ *
+ * @return the operations
+ */
+ public List<String> operations() {
+ return operations;
+ }
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyId.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyId.java
new file mode 100644
index 0000000..e3e0cc1
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyId.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.api;
+
+import org.onlab.util.Identifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Representation of a policy id.
+ */
+public final class PolicyId extends Identifier<String> {
+
+ protected PolicyId(String id) {
+ super(id);
+ }
+
+ /**
+ * Returns the id of the policy given the value.
+ *
+ * @param name policy id value
+ * @return policy id
+ */
+ public static PolicyId of(String name) {
+ checkNotNull(name);
+ checkArgument(!name.isEmpty(), "Name cannot be empty");
+ return new PolicyId(name);
+ }
+
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyService.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyService.java
new file mode 100644
index 0000000..2e188ab
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyService.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.api;
+
+import java.util.Set;
+
+/**
+ * Policies to drop, reroute, apply QoS and overlay the traffic.
+ */
+public interface PolicyService {
+ /**
+ * Traffic match priority.
+ */
+ int TRAFFIC_MATCH_PRIORITY = 60000;
+
+ /**
+ * Creates or updates a policy.
+ *
+ * @param policy the policy to create
+ * @return the id of the policy being created. Otherwise null.
+ */
+ PolicyId addOrUpdatePolicy(Policy policy);
+
+ /**
+ * Issues a policy removal.
+ *
+ * @param policyId the id of the policy to remove
+ * @return whether or not the operation was successful
+ */
+ boolean removePolicy(PolicyId policyId);
+
+ /**
+ * Returns a set of policies. The policy types can be used
+ * as filter.
+ *
+ * @param filter the policy types
+ * @return the policies stored in the system observing
+ * the filtering rule
+ */
+ Set<PolicyData> policies(Set<Policy.PolicyType> filter);
+
+ /**
+ * Attaches a traffic match to a policy.
+ *
+ * @param trafficMatch the traffic match
+ * @return the traffic match id or null if not successful
+ */
+ TrafficMatchId addOrUpdateTrafficMatch(TrafficMatch trafficMatch);
+
+ /**
+ * Issues a traffic match removal.
+ *
+ * @param trafficMatchId the id of the traffic match to remove
+ * @return whether or not the operation was successful
+ */
+ boolean removeTrafficMatch(TrafficMatchId trafficMatchId);
+
+ /**
+ * Returns a set of traffic matches.
+ *
+ * @return the traffic matches stored in the system
+ */
+ Set<TrafficMatchData> trafficMatches();
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyState.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyState.java
new file mode 100644
index 0000000..ad767ec
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyState.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.api;
+
+/**
+ * Represents the state of a policy as seen by the system.
+ */
+public enum PolicyState {
+ /**
+ * The policy is in the process of being added.
+ */
+ PENDING_ADD,
+
+ /**
+ * The policy has been added.
+ */
+ ADDED,
+
+ /**
+ * The policy is in the process of being removed.
+ */
+ PENDING_REMOVE
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatch.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatch.java
new file mode 100644
index 0000000..83098fe
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatch.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.api;
+
+
+import com.google.common.hash.Funnel;
+import com.google.common.hash.HashCode;
+import com.google.common.hash.HashFunction;
+import com.google.common.hash.Hashing;
+import org.onosproject.net.flow.TrafficSelector;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Representation of a traffic match.
+ */
+public final class TrafficMatch {
+ // Traffic match internal state
+ private TrafficMatchId trafficMatchId;
+ private TrafficSelector trafficSelector;
+ private PolicyId policyId;
+
+ /**
+ * Builds a traffic match.
+ *
+ * @param trafficselector the traffic selector
+ * @param policyid the associated policy id
+ */
+ public TrafficMatch(TrafficSelector trafficselector, PolicyId policyid) {
+ trafficSelector = trafficselector;
+ trafficMatchId = TrafficMatchId.trafficMatchId(computeTrafficMatchId());
+ policyId = policyid;
+ }
+
+ /**
+ * Returns the traffic match id.
+ *
+ * @return the id of the traffic match
+ */
+ public TrafficMatchId trafficMatchId() {
+ return trafficMatchId;
+ }
+
+ /**
+ * Returns the id of the policy associated with.
+ *
+ * @return the policy id
+ */
+ public PolicyId policyId() {
+ return policyId;
+ }
+
+ /**
+ * Returns the traffic selector associated with.
+ *
+ * @return the traffic selector
+ */
+ public TrafficSelector trafficSelector() {
+ return trafficSelector;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(trafficMatchId, trafficSelector, policyId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof TrafficMatch) {
+ final TrafficMatch other = (TrafficMatch) obj;
+ return Objects.equals(this.trafficMatchId, other.trafficMatchId) &&
+ Objects.equals(trafficSelector, other.trafficSelector) &&
+ Objects.equals(policyId, other.policyId);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("trafficMatchId", trafficMatchId)
+ .add("trafficSelector", trafficSelector)
+ .add("policyId", policyId)
+ .toString();
+ }
+
+ // Compute the id using the traffic selector. This method results to be consistent across the cluster.
+ private int computeTrafficMatchId() {
+ Funnel<TrafficSelector> selectorFunnel = (from, into) -> from.criteria()
+ .forEach(c -> into.putUnencodedChars(c.toString()));
+ HashFunction hashFunction = Hashing.murmur3_32();
+ HashCode hashCode = hashFunction.newHasher()
+ .putObject(trafficSelector, selectorFunnel)
+ .hash();
+ return hashCode.asInt();
+ }
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatchData.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatchData.java
new file mode 100644
index 0000000..3932b4c
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatchData.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.api;
+
+import java.util.List;
+
+/**
+ * Traffic match data retrieved from the system.
+ */
+public final class TrafficMatchData {
+ // We want to provide access to the traffic match data as well as
+ // the traffic match operations in the system and their status
+ private final TrafficMatchState trafficMatchState;
+ private final TrafficMatch trafficMatch;
+ private final List<String> operations;
+
+
+ public TrafficMatchData(TrafficMatchState tState, TrafficMatch tMatch, List<String> ops) {
+ trafficMatch = tMatch;
+ trafficMatchState = tState;
+ operations = ops;
+ }
+
+ /**
+ * Returns the current state of the traffic match.
+ *
+ * @return the traffic match state
+ */
+ public TrafficMatchState trafficMatchState() {
+ return trafficMatchState;
+ }
+
+
+ /**
+ * Returns the traffic match associated.
+ *
+ * @return the traffic match
+ */
+ public TrafficMatch trafficMatch() {
+ return trafficMatch;
+ }
+
+ /**
+ * Returns the operations in the system in form of strings.
+ *
+ * @return the operations
+ */
+ public List<String> operations() {
+ return operations;
+ }
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatchId.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatchId.java
new file mode 100644
index 0000000..5833f66
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatchId.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.api;
+
+import org.onlab.util.Identifier;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Representation of a traffic match id.
+ */
+public final class TrafficMatchId extends Identifier<Integer> {
+
+ protected TrafficMatchId(int value) {
+ super(value);
+ }
+
+ /**
+ * Converts an int into a traffic match id.
+ *
+ * @param value the value of the id
+ * @return the traffic match id
+ */
+ public static TrafficMatchId trafficMatchId(int value) {
+ return new TrafficMatchId(value);
+ }
+
+ /**
+ * Returns the id of the traffic match given the value.
+ *
+ * @param name traffic match id value
+ * @return traffic match id
+ */
+ public static TrafficMatchId of(String name) {
+ checkNotNull(name);
+ checkArgument(!name.isEmpty(), "Name cannot be empty");
+ return new TrafficMatchId(Integer.parseInt(name));
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(this.identifier);
+ }
+
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatchState.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatchState.java
new file mode 100644
index 0000000..f775c50
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatchState.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.api;
+
+/**
+ * Represents the state of a traffic match as seen by the system.
+ */
+public enum TrafficMatchState {
+ /**
+ * The traffic match is in the process of being added.
+ */
+ PENDING_ADD,
+
+ /**
+ * The traffic match has been added.
+ */
+ ADDED,
+
+ /**
+ * The traffic match is in the process of being removed.
+ */
+ PENDING_REMOVE
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/api/package-info.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/package-info.java
new file mode 100644
index 0000000..cfbaa28
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/api/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-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.
+ */
+
+/**
+ * Policy API.
+ */
+package org.onosproject.segmentrouting.policy.api;
\ No newline at end of file
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/Operation.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/Operation.java
new file mode 100644
index 0000000..99c9fd4
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/Operation.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.impl;
+
+import java.util.Objects;
+import java.util.Optional;
+
+import com.google.common.base.MoreObjects;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.segmentrouting.policy.api.Policy;
+import org.onosproject.segmentrouting.policy.api.TrafficMatch;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * keep track of the operation and of its status in the system.
+ */
+final class Operation {
+ private boolean isInstall;
+ private boolean isDone;
+ private Objective objectiveOperation;
+ private Policy policy;
+ private TrafficMatch trafficMatch;
+
+ private Operation(boolean install, boolean done, Objective objective,
+ Policy pol, TrafficMatch tMatch) {
+ isInstall = install;
+ isDone = done;
+ objectiveOperation = objective;
+ policy = pol;
+ trafficMatch = tMatch;
+ }
+
+ /**
+ * Returns whether or not the operation is done.
+ *
+ * @return true if operation is done. False otherwise.
+ */
+ public boolean isDone() {
+ return isDone;
+ }
+
+ /**
+ * Returns whether or not it is an installation.
+ *
+ * @return true if it is an installation. False for removal
+ */
+ public boolean isInstall() {
+ return isInstall;
+ }
+
+ /**
+ * Returns the objective operation.
+ *
+ * @return the associated flow objective
+ */
+ public Objective objectiveOperation() {
+ return objectiveOperation;
+ }
+
+ /**
+ * Returns the policy if present.
+ *
+ * @return the policy
+ */
+ public Optional<Policy> policy() {
+ return Optional.ofNullable(policy);
+ }
+
+ /**
+ * Returns the traffic match if present.
+ *
+ * @return the traffic match
+ */
+ public Optional<TrafficMatch> trafficMatch() {
+ return Optional.ofNullable(trafficMatch);
+ }
+
+ /**
+ * Updates isDone.
+ *
+ * @param isDone if it is done
+ */
+ public void isDone(boolean isDone) {
+ this.isDone = isDone;
+ }
+
+ /**
+ * Updates the flowObjective.
+ *
+ * @param objectiveOperation the flowObjective
+ */
+ public void objectiveOperation(Objective objectiveOperation) {
+ this.objectiveOperation = objectiveOperation;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof Operation)) {
+ return false;
+ }
+ final Operation other = (Operation) obj;
+ return this.isInstall == other.isInstall &&
+ this.isDone == other.isDone &&
+ Objects.equals(this.objectiveOperation, other.objectiveOperation) &&
+ Objects.equals(this.policy, other.policy) &&
+ Objects.equals(this.trafficMatch, other.trafficMatch);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(isInstall, isDone, objectiveOperation, policy, trafficMatch);
+ }
+
+ @Override
+ public String toString() {
+ MoreObjects.ToStringHelper helper = toStringHelper(this)
+ .add("isInstall", isInstall)
+ .add("isDone", isDone)
+ .add("objective", objectiveOperation);
+ if (policy != null) {
+ helper.add("policy", policy);
+ }
+ if (trafficMatch != null) {
+ helper.add("trafficMatch", trafficMatch);
+ }
+ return helper.toString();
+ }
+
+ public String toStringMinimal() {
+ MoreObjects.ToStringHelper helper = toStringHelper(this)
+ .add("isInstall", isInstall)
+ .add("isDone", isDone);
+ if (policy != null) {
+ helper.add("policy", policy);
+ }
+ if (trafficMatch != null) {
+ helper.add("trafficMatch", trafficMatch);
+ }
+ return helper.toString();
+ }
+
+ /**
+ * Creates a new operation builder.
+ *
+ * @return an operation builder
+ */
+ public static Operation.Builder builder() {
+ return new Operation.Builder();
+ }
+
+ /**
+ * Creates a new operation builder using the supplied operation.
+ *
+ * @param operation the operation
+ * @return an operation builder
+ */
+ public static Operation.Builder builder(Operation operation) {
+ return new Operation.Builder(operation);
+ }
+
+ /**
+ * Builder for Operation objects.
+ */
+ public static final class Builder {
+ private boolean isInstall;
+ private boolean isDone;
+ private Objective objectiveOperation;
+ private Policy policy;
+ private TrafficMatch trafficMatch;
+
+ private Builder() {
+ // Hide constructor
+ }
+
+ private Builder(Operation operation) {
+ isInstall = operation.isInstall();
+ isDone = operation.isDone();
+ objectiveOperation = operation.objectiveOperation();
+ policy = operation.policy().orElse(null);
+ trafficMatch = operation.trafficMatch().orElse(null);
+ }
+
+ /**
+ * Sets the flowObjective.
+ *
+ * @param objectiveOperation the flowObjective
+ * @return this builder
+ */
+ public Builder objectiveOperation(Objective objectiveOperation) {
+ this.objectiveOperation = objectiveOperation;
+ return this;
+ }
+
+ /**
+ * Sets if it is done.
+ *
+ * @param isDone if it is done
+ * @return this builder
+ */
+ public Builder isDone(boolean isDone) {
+ this.isDone = isDone;
+ return this;
+ }
+
+ /**
+ * Sets if it is an installation.
+ *
+ * @param isInstall if it is an installation
+ * @return this builder
+ */
+ public Builder isInstall(boolean isInstall) {
+ this.isInstall = isInstall;
+ return this;
+ }
+
+ /**
+ * Sets the policy.
+ *
+ * @param policy the policy
+ * @return this builder
+ */
+ public Builder policy(Policy policy) {
+ this.policy = policy;
+ return this;
+ }
+
+ /**
+ * Sets the traffic match.
+ *
+ * @param trafficMatch the traffic match
+ * @return this builder
+ */
+ public Builder trafficMatch(TrafficMatch trafficMatch) {
+ this.trafficMatch = trafficMatch;
+ return this;
+ }
+
+ /**
+ * Builds an operation object from the accumulated parameters.
+ *
+ * @return operation object
+ */
+ public Operation build() {
+ if ((policy == null && trafficMatch == null) ||
+ (policy != null && trafficMatch != null)) {
+ throw new IllegalArgumentException("Policy and traffic cannot be both null or both set");
+ }
+ return new Operation(isInstall, isDone, objectiveOperation, policy, trafficMatch);
+ }
+ }
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/PolicyKey.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/PolicyKey.java
new file mode 100644
index 0000000..e0eac06
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/PolicyKey.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.impl;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.segmentrouting.policy.api.PolicyId;
+
+import java.util.Objects;
+import java.util.StringTokenizer;
+
+/**
+ * Policy key used by the store.
+ */
+public class PolicyKey {
+ private DeviceId deviceId;
+ private PolicyId policyId;
+
+ /**
+ * Constructs new policy key with given device id and policy id.
+ *
+ * @param deviceId device id
+ * @param policyId policy id
+ */
+ public PolicyKey(DeviceId deviceId, PolicyId policyId) {
+ this.deviceId = deviceId;
+ this.policyId = policyId;
+ }
+
+ /**
+ * Gets device id.
+ *
+ * @return device id of the policy key
+ */
+ public DeviceId deviceId() {
+ return deviceId;
+ }
+
+ /**
+ * Gets policy id.
+ *
+ * @return the id of the policy
+ */
+ public PolicyId policyId() {
+ return policyId;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof PolicyKey)) {
+ return false;
+ }
+ final PolicyKey other = (PolicyKey) obj;
+ return Objects.equals(this.deviceId, other.deviceId) &&
+ Objects.equals(this.policyId, other.policyId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(deviceId, policyId);
+ }
+
+ /**
+ * Parses from a string the police key.
+ *
+ * @param str the string to parse
+ * @return the policy key if present in the str, null otherwise
+ */
+ public static PolicyKey fromString(String str) {
+ PolicyKey policyKey = null;
+ if (str != null && str.contains(PolicyManager.KEY_SEPARATOR)) {
+ StringTokenizer tokenizer = new StringTokenizer(str, PolicyManager.KEY_SEPARATOR);
+ if (tokenizer.countTokens() == 2) {
+ policyKey = new PolicyKey(DeviceId.deviceId(tokenizer.nextToken()),
+ PolicyId.of(tokenizer.nextToken()));
+ }
+ }
+ return policyKey;
+ }
+
+ @Override
+ public String toString() {
+ return deviceId.toString() + PolicyManager.KEY_SEPARATOR + policyId.toString();
+ }
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/PolicyManager.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/PolicyManager.java
new file mode 100644
index 0000000..dbd5667
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/PolicyManager.java
@@ -0,0 +1,821 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.impl;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.hash.HashFunction;
+import com.google.common.hash.Hashing;
+import org.glassfish.jersey.internal.guava.Sets;
+import org.onlab.util.KryoNamespace;
+import org.onlab.util.PredictableExecutor;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.DefaultObjectiveContext;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.flowobjective.ObjectiveContext;
+import org.onosproject.net.intent.WorkPartitionService;
+import org.onosproject.segmentrouting.SegmentRoutingService;
+import org.onosproject.segmentrouting.policy.api.DropPolicy;
+import org.onosproject.segmentrouting.policy.api.Policy;
+import org.onosproject.segmentrouting.policy.api.Policy.PolicyType;
+import org.onosproject.segmentrouting.policy.api.PolicyData;
+import org.onosproject.segmentrouting.policy.api.PolicyId;
+import org.onosproject.segmentrouting.policy.api.PolicyService;
+import org.onosproject.segmentrouting.policy.api.PolicyState;
+import org.onosproject.segmentrouting.policy.api.TrafficMatch;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchData;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchId;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchState;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.MapEvent;
+import org.onosproject.store.service.MapEventListener;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageException;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.Versioned;
+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.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.slf4j.Logger;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+
+import static org.onlab.util.Tools.groupedThreads;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of the policy service interface.
+ */
+@Component(immediate = true, service = PolicyService.class)
+public class PolicyManager implements PolicyService {
+
+ // App related things
+ private static final String APP_NAME = "org.onosproject.segmentrouting.policy";
+ private ApplicationId appId;
+ private Logger log = getLogger(getClass());
+ static final String KEY_SEPARATOR = "|";
+
+ // Policy/TrafficMatch store related objects. We use these consistent maps to keep track of the
+ // lifecycle of a policy/traffic match. These are decomposed in multiple operations which have
+ // to be performed on multiple devices in order to have a policy/traffic match in ADDED state.
+ private static final String POLICY_STORE = "sr-policy-store";
+ private ConsistentMap<PolicyId, PolicyRequest> policies;
+ private MapEventListener<PolicyId, PolicyRequest> mapPolListener = new InternalPolMapEventListener();
+ private Map<PolicyId, PolicyRequest> policiesMap;
+
+ private static final String OPS_STORE = "sr-ops-store";
+ private ConsistentMap<String, Operation> operations;
+ private MapEventListener<String, Operation> mapOpsListener = new InternalOpsMapEventListener();
+ private Map<String, Operation> opsMap;
+
+ private static final String TRAFFIC_MATCH_STORE = "sr-tmatch-store";
+ private ConsistentMap<TrafficMatchId, TrafficMatchRequest> trafficMatches;
+ private MapEventListener<TrafficMatchId, TrafficMatchRequest> mapTMatchListener =
+ new InternalTMatchMapEventListener();
+ private Map<TrafficMatchId, TrafficMatchRequest> trafficMatchesMap;
+
+ // Leadership related objects - consistent hashing
+ private static final HashFunction HASH_FN = Hashing.md5();
+ // Read only cache of the Policy leader
+ private Map<PolicyId, NodeId> policyLeaderCache;
+
+ // Worker threads for policy and traffic match related ops
+ private static final int DEFAULT_THREADS = 4;
+ protected PredictableExecutor workers;
+
+ // Serializers and ONOS services
+ private static final KryoNamespace.Builder APP_KRYO_BUILDER = KryoNamespace.newBuilder()
+ .register(KryoNamespaces.API)
+ .register(PolicyId.class)
+ .register(PolicyType.class)
+ .register(DropPolicy.class)
+ .register(PolicyState.class)
+ .register(PolicyRequest.class)
+ .register(TrafficMatchId.class)
+ .register(TrafficMatchState.class)
+ .register(TrafficMatch.class)
+ .register(TrafficMatchRequest.class)
+ .register(Operation.class);
+ private Serializer serializer = Serializer.using(Lists.newArrayList(APP_KRYO_BUILDER.build()));
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ private CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ private StorageService storageService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ private ClusterService clusterService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ public WorkPartitionService workPartitionService;
+
+ @Reference(cardinality = ReferenceCardinality.OPTIONAL)
+ public SegmentRoutingService srService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ public FlowObjectiveService flowObjectiveService;
+
+ @Activate
+ public void activate() {
+ appId = coreService.registerApplication(APP_NAME);
+
+ policies = storageService.<PolicyId, PolicyRequest>consistentMapBuilder()
+ .withName(POLICY_STORE)
+ .withSerializer(serializer).build();
+ policies.addListener(mapPolListener);
+ policiesMap = policies.asJavaMap();
+
+ trafficMatches = storageService.<TrafficMatchId, TrafficMatchRequest>consistentMapBuilder()
+ .withName(TRAFFIC_MATCH_STORE)
+ .withSerializer(serializer).build();
+ trafficMatches.addListener(mapTMatchListener);
+ trafficMatchesMap = trafficMatches.asJavaMap();
+
+ operations = storageService.<String, Operation>consistentMapBuilder()
+ .withName(OPS_STORE)
+ .withSerializer(serializer).build();
+ operations.addListener(mapOpsListener);
+ opsMap = operations.asJavaMap();
+
+ policyLeaderCache = Maps.newConcurrentMap();
+
+ workers = new PredictableExecutor(DEFAULT_THREADS,
+ groupedThreads("sr-policy", "worker-%d", log));
+
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ // Teardown everything
+ policies.removeListener(mapPolListener);
+ policies.destroy();
+ policiesMap.clear();
+ trafficMatches.removeListener(mapTMatchListener);
+ trafficMatches.destroy();
+ trafficMatchesMap.clear();
+ operations.removeListener(mapOpsListener);
+ operations.destroy();
+ operations.clear();
+ workers.shutdown();
+
+ log.info("Stopped");
+ }
+
+ @Override
+ //FIXME update does not work well
+ public PolicyId addOrUpdatePolicy(Policy policy) {
+ PolicyId policyId = policy.policyId();
+ try {
+ policies.put(policyId, new PolicyRequest(policy));
+ } catch (StorageException e) {
+ log.error("{} thrown a storage exception: {}", e.getStackTrace()[0].getMethodName(),
+ e.getMessage(), e);
+ policyId = null;
+ }
+ return policyId;
+ }
+
+ @Override
+ public boolean removePolicy(PolicyId policyId) {
+ boolean result;
+ try {
+ result = Versioned.valueOrNull(policies.computeIfPresent(policyId, (k, v) -> {
+ if (v.policyState() != PolicyState.PENDING_REMOVE) {
+ v.policyState(PolicyState.PENDING_REMOVE);
+ }
+ return v;
+ })) != null;
+ } catch (StorageException e) {
+ log.error("{} thrown a storage exception: {}", e.getStackTrace()[0].getMethodName(),
+ e.getMessage(), e);
+ result = false;
+ }
+ return result;
+ }
+
+ @Override
+ public Set<PolicyData> policies(Set<PolicyType> filter) {
+ Set<PolicyData> policyData = Sets.newHashSet();
+ List<DeviceId> edgeDeviceIds = srService.getEdgeDeviceIds();
+ Set<PolicyRequest> policyRequests;
+ if (filter.isEmpty()) {
+ policyRequests = ImmutableSet.copyOf(policiesMap.values());
+ } else {
+ policyRequests = policiesMap.values().stream()
+ .filter(policyRequest -> filter.contains(policyRequest.policyType()))
+ .collect(Collectors.toSet());
+ }
+ PolicyKey policyKey;
+ List<String> ops;
+ for (PolicyRequest policyRequest : policyRequests) {
+ ops = Lists.newArrayList();
+ for (DeviceId deviceId : edgeDeviceIds) {
+ policyKey = new PolicyKey(deviceId, policyRequest.policyId());
+ Operation operation = Versioned.valueOrNull(operations.get(policyKey.toString()));
+ if (operation != null) {
+ ops.add(deviceId + " -> " + operation.toStringMinimal());
+ }
+ }
+ policyData.add(new PolicyData(policyRequest.policyState(), policyRequest.policy(), ops));
+ }
+ return policyData;
+ }
+
+ @Override
+ //FIXME update does not work well
+ public TrafficMatchId addOrUpdateTrafficMatch(TrafficMatch trafficMatch) {
+ TrafficMatchId trafficMatchId = trafficMatch.trafficMatchId();
+ try {
+ trafficMatches.put(trafficMatchId, new TrafficMatchRequest(trafficMatch));
+ } catch (StorageException e) {
+ log.error("{} thrown a storage exception: {}", e.getStackTrace()[0].getMethodName(),
+ e.getMessage(), e);
+ trafficMatchId = null;
+ }
+ return trafficMatchId;
+ }
+
+ @Override
+ public boolean removeTrafficMatch(TrafficMatchId trafficMatchId) {
+ boolean result;
+ try {
+ result = Versioned.valueOrNull(trafficMatches.computeIfPresent(trafficMatchId, (k, v) -> {
+ if (v.trafficMatchState() != TrafficMatchState.PENDING_REMOVE) {
+ v.trafficMatchState(TrafficMatchState.PENDING_REMOVE);
+ }
+ return v;
+ })) != null;
+ } catch (StorageException e) {
+ log.error("{} thrown a storage exception: {}", e.getStackTrace()[0].getMethodName(),
+ e.getMessage(), e);
+ result = false;
+ }
+ return result;
+ }
+
+ @Override
+ public Set<TrafficMatchData> trafficMatches() {
+ Set<TrafficMatchData> trafficMatchData = Sets.newHashSet();
+ List<DeviceId> edgeDeviceIds = srService.getEdgeDeviceIds();
+ Set<TrafficMatchRequest> trafficMatchRequests = ImmutableSet.copyOf(trafficMatchesMap.values());
+ TrafficMatchKey trafficMatchKey;
+ List<String> ops;
+ for (TrafficMatchRequest trafficMatchRequest : trafficMatchRequests) {
+ ops = Lists.newArrayList();
+ for (DeviceId deviceId : edgeDeviceIds) {
+ trafficMatchKey = new TrafficMatchKey(deviceId, trafficMatchRequest.trafficMatch().trafficMatchId());
+ Operation operation = Versioned.valueOrNull(operations.get(trafficMatchKey.toString()));
+ if (operation != null) {
+ ops.add(deviceId + " -> " + operation.toStringMinimal());
+ }
+ }
+ trafficMatchData.add(new TrafficMatchData(trafficMatchRequest.trafficMatchState(),
+ trafficMatchRequest.trafficMatch(), ops));
+ }
+ return trafficMatchData;
+ }
+
+ // Install/remove the policies on the edge devices
+ private void sendPolicy(Policy policy, boolean install) {
+ if (!isLeader(policy.policyId())) {
+ if (log.isDebugEnabled()) {
+ log.debug("Instance is not leader for policy {}", policy.policyId());
+ }
+ return;
+ }
+ // We know that we are the leader, offloads to the workers the remaining
+ // part: issue fobj installation/removal and update the maps
+ List<DeviceId> edgeDeviceIds = srService.getEdgeDeviceIds();
+ for (DeviceId deviceId : edgeDeviceIds) {
+ workers.execute(() -> {
+ if (install) {
+ installPolicyInDevice(deviceId, policy);
+ } else {
+ removePolicyInDevice(deviceId, policy);
+ }
+ }, deviceId.hashCode());
+ }
+ }
+
+ // Orchestrate policy installation according to the type
+ private void installPolicyInDevice(DeviceId deviceId, Policy policy) {
+ PolicyKey policyKey;
+ Operation operation;
+ if (policy.policyType() == PolicyType.DROP) {
+ if (log.isDebugEnabled()) {
+ log.debug("Installing DROP policy {}", policy.policyId());
+ }
+ // DROP policies do not need the next objective installation phase
+ // we can update directly the map and signal the ops as done
+ policyKey = new PolicyKey(deviceId, policy.policyId());
+ operation = Operation.builder()
+ .isDone(true)
+ .isInstall(true)
+ .policy(policy)
+ .build();
+ operations.put(policyKey.toString(), operation);
+ } else if (policy.policyType() == PolicyType.REDIRECT) {
+ if (log.isDebugEnabled()) {
+ log.debug("Installing REDIRECT policy {}", policy.policyId());
+ }
+ // REDIRECT Uses objective context to update the ops as done when it returns
+ // successfully. In the other cases leaves the ops as undone and the
+ // relative policy will remain in pending.
+ } else {
+ log.warn("Policy {} type {} not yet supported",
+ policy.policyId(), policy.policyType());
+ }
+ }
+
+ // Remove policy in a device according to the type
+ private void removePolicyInDevice(DeviceId deviceId, Policy policy) {
+ if (log.isDebugEnabled()) {
+ log.debug("Removing policy {}", policy.policyId());
+ }
+ PolicyKey policyKey = new PolicyKey(deviceId, policy.policyId());
+ Operation operation = Versioned.valueOrNull(operations.get(policyKey.toString()));
+ // Policy might be still in pending or not present anymore
+ if (operation == null || operation.objectiveOperation() == null) {
+ log.warn("There are no ops associated with {}", policyKey);
+ operation = Operation.builder()
+ .isDone(true)
+ .isInstall(false)
+ .policy(policy)
+ .build();
+ operations.put(policyKey.toString(), operation);
+ } else {
+ if (policy.policyType() == PolicyType.DROP) {
+ if (log.isDebugEnabled()) {
+ log.debug("Removing DROP policy {}", policy.policyId());
+ }
+ operation = Operation.builder()
+ .isDone(true)
+ .isInstall(false)
+ .policy(policy)
+ .build();
+ operations.put(policyKey.toString(), operation);
+ } else if (policy.policyType() == PolicyType.REDIRECT) {
+ if (log.isDebugEnabled()) {
+ log.debug("Removing REDIRECT policy {}", policy.policyId());
+ }
+ // REDIRECT has to remove first a next objective
+ } else {
+ log.warn("Policy {} type {} not yet supported",
+ policy.policyId(), policy.policyType());
+ }
+ }
+ }
+
+ // Updates policy status if all the pending ops are done
+ private void updatePolicy(PolicyId policyId, boolean install) {
+ if (!isLeader(policyId)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Instance is not leader for policy {}", policyId);
+ }
+ return;
+ }
+ workers.execute(() -> updatePolicyInternal(policyId, install), policyId.hashCode());
+ }
+
+ private void updatePolicyInternal(PolicyId policyId, boolean install) {
+ // If there are no more pending ops we are ready to go; potentially we can check
+ // if the id is contained. Updates policies only if they are still present
+ Optional<Map.Entry<String, Versioned<Operation>>> notYetDone = operations.entrySet().stream()
+ .filter(entry -> entry.getValue().value().policy().isPresent())
+ .filter(entry -> PolicyKey.fromString(entry.getKey()).policyId().equals(policyId))
+ .filter(entry -> !entry.getValue().value().isDone() && entry.getValue().value().isInstall() == install)
+ .findFirst();
+ if (notYetDone.isEmpty()) {
+ PolicyRequest policyRequest = Versioned.valueOrNull(policies.computeIfPresent(policyId, (k, v) -> {
+ if (v.policyState() == PolicyState.PENDING_ADD && install) {
+ if (log.isDebugEnabled()) {
+ log.debug("Policy {} is ready", policyId);
+ }
+ v.policyState(PolicyState.ADDED);
+ } else if (v.policyState() == PolicyState.PENDING_REMOVE && !install) {
+ if (log.isDebugEnabled()) {
+ log.debug("Policy {} is removed", policyId);
+ }
+ v = null;
+ }
+ return v;
+ }));
+ // Greedy check for pending traffic matches
+ if (policyRequest != null && policyRequest.policyState() == PolicyState.ADDED) {
+ updatePendingTrafficMatches(policyRequest.policyId());
+ }
+ }
+ }
+
+ // Install/remove the traffic match on the edge devices
+ private void sendTrafficMatch(TrafficMatch trafficMatch, boolean install) {
+ if (!isLeader(trafficMatch.policyId())) {
+ if (log.isDebugEnabled()) {
+ log.debug("Instance is not leader for policy {}", trafficMatch.policyId());
+ }
+ return;
+ }
+ // We know that we are the leader, offloads to the workers the remaining
+ // part: issue fobj installation/removal and update the maps
+ List<DeviceId> edgeDeviceIds = srService.getEdgeDeviceIds();
+ for (DeviceId deviceId : edgeDeviceIds) {
+ workers.execute(() -> {
+ if (install) {
+ installTrafficMatchToDevice(deviceId, trafficMatch);
+ } else {
+ removeTrafficMatchInDevice(deviceId, trafficMatch);
+ }
+ }, deviceId.hashCode());
+ }
+ }
+
+ // Orchestrate traffic match installation according to the type
+ private void installTrafficMatchToDevice(DeviceId deviceId, TrafficMatch trafficMatch) {
+ if (log.isDebugEnabled()) {
+ log.debug("Installing traffic match {} associated to policy {}",
+ trafficMatch.trafficMatchId(), trafficMatch.policyId());
+ }
+ // Updates the store and then send the versatile fwd objective to the pipeliner
+ TrafficMatchKey trafficMatchKey = new TrafficMatchKey(deviceId, trafficMatch.trafficMatchId());
+ Operation trafficOperation = Operation.builder()
+ .isInstall(true)
+ .trafficMatch(trafficMatch)
+ .build();
+ operations.put(trafficMatchKey.toString(), trafficOperation);
+ // For the DROP policy we need to set an ACL drop in the fwd objective. The other
+ // policies require to retrieve the next Id and sets the next step.
+ PolicyKey policyKey = new PolicyKey(deviceId, trafficMatch.policyId());
+ Operation policyOperation = Versioned.valueOrNull(operations.get(policyKey.toString()));
+ if (policyOperation == null || !policyOperation.isDone() ||
+ !policyOperation.isInstall() || policyOperation.policy().isEmpty()) {
+ log.info("Deferring traffic match {} installation on device {}. Policy {} not yet installed",
+ trafficMatch.trafficMatchId(), deviceId, trafficMatch.policyId());
+ return;
+ }
+ Policy policy = policyOperation.policy().get();
+ ForwardingObjective.Builder builder = trafficMatchFwdObjective(trafficMatch);
+ // TODO we can try to reuse some code: context and completable future logic
+ if (policy.policyType() == PolicyType.DROP) {
+ // Firstly builds the fwd objective with the wipeDeferred action. Once, the fwd
+ // objective has completed its execution, we update the policiesOps map
+ TrafficTreatment dropTreatment = DefaultTrafficTreatment.builder()
+ .wipeDeferred()
+ .build();
+ builder.withTreatment(dropTreatment);
+ CompletableFuture<Objective> future = new CompletableFuture<>();
+ if (log.isDebugEnabled()) {
+ log.debug("Installing ACL drop forwarding objectives for dev: {}", deviceId);
+ }
+ ObjectiveContext context = new DefaultObjectiveContext(
+ (objective) -> {
+ if (log.isDebugEnabled()) {
+ log.debug("ACL drop rule for policy {} installed", trafficMatch.policyId());
+ }
+ future.complete(objective);
+ },
+ (objective, error) -> {
+ log.warn("Failed to install ACL drop rule for policy {}: {}", trafficMatch.policyId(), error);
+ future.complete(null);
+ });
+ // Context is not serializable
+ ForwardingObjective serializableObjective = builder.add();
+ flowObjectiveService.forward(deviceId, builder.add(context));
+ future.whenComplete((objective, ex) -> {
+ if (ex != null) {
+ log.error("Exception installing ACL drop rule", ex);
+ } else if (objective != null) {
+ operations.computeIfPresent(trafficMatchKey.toString(), (k, v) -> {
+ if (!v.isDone() && v.isInstall()) {
+ v.isDone(true);
+ v.objectiveOperation(serializableObjective);
+ }
+ return v;
+ });
+ }
+ });
+ } else {
+ log.warn("Policy {} type {} not yet supported", policy.policyId(), policy.policyType());
+ }
+ }
+
+ // Updates traffic match status if all the pending ops are done
+ private void updateTrafficMatch(TrafficMatch trafficMatch, boolean install) {
+ if (!isLeader(trafficMatch.policyId())) {
+ if (log.isDebugEnabled()) {
+ log.debug("Instance is not leader for policy {}", trafficMatch.policyId());
+ }
+ return;
+ }
+ workers.execute(() -> updateTrafficMatchInternal(trafficMatch.trafficMatchId(), install),
+ trafficMatch.policyId().hashCode());
+ }
+
+ private void updateTrafficMatchInternal(TrafficMatchId trafficMatchId, boolean install) {
+ // If there are no more pending ops we are ready to go; potentially we can check
+ // if the id is contained. Updates traffic matches only if they are still present
+ Optional<Map.Entry<String, Versioned<Operation>>> notYetDone = operations.entrySet().stream()
+ .filter(entry -> entry.getValue().value().trafficMatch().isPresent())
+ .filter(entry -> TrafficMatchKey.fromString(entry.getKey()).trafficMatchId().equals(trafficMatchId))
+ .filter(entry -> !entry.getValue().value().isDone() && entry.getValue().value().isInstall() == install)
+ .findFirst();
+ if (notYetDone.isEmpty()) {
+ trafficMatches.computeIfPresent(trafficMatchId, (k, v) -> {
+ if (v.trafficMatchState() == TrafficMatchState.PENDING_ADD && install) {
+ if (log.isDebugEnabled()) {
+ log.debug("Traffic match {} is ready", trafficMatchId);
+ }
+ v.trafficMatchState(TrafficMatchState.ADDED);
+ } else if (v.trafficMatchState() == TrafficMatchState.PENDING_REMOVE && !install) {
+ if (log.isDebugEnabled()) {
+ log.debug("Traffic match {} is removed", trafficMatchId);
+ }
+ v = null;
+ }
+ return v;
+ });
+ }
+ }
+
+ // Look for any pending traffic match waiting for the policy
+ private void updatePendingTrafficMatches(PolicyId policyId) {
+ Set<TrafficMatchRequest> pendingTrafficMatches = trafficMatches.stream()
+ .filter(trafficMatchEntry -> trafficMatchEntry.getValue().value().policyId().equals(policyId) &&
+ trafficMatchEntry.getValue().value().trafficMatchState() == TrafficMatchState.PENDING_ADD)
+ .map(trafficMatchEntry -> trafficMatchEntry.getValue().value())
+ .collect(Collectors.toSet());
+ for (TrafficMatchRequest trafficMatch : pendingTrafficMatches) {
+ sendTrafficMatch(trafficMatch.trafficMatch(), true);
+ }
+ }
+
+ // Traffic match removal in a device
+ private void removeTrafficMatchInDevice(DeviceId deviceId, TrafficMatch trafficMatch) {
+ if (log.isDebugEnabled()) {
+ log.debug("Removing traffic match {} associated to policy {}",
+ trafficMatch.trafficMatchId(), trafficMatch.policyId());
+ }
+ TrafficMatchKey trafficMatchKey = new TrafficMatchKey(deviceId, trafficMatch.trafficMatchId());
+ Operation operation = Versioned.valueOrNull(operations.get(trafficMatchKey.toString()));
+ if (operation == null || operation.objectiveOperation() == null) {
+ log.warn("There are no ops associated with {}", trafficMatchKey);
+ operation = Operation.builder()
+ .isDone(true)
+ .isInstall(false)
+ .trafficMatch(trafficMatch)
+ .build();
+ operations.put(trafficMatchKey.toString(), operation);
+ } else {
+ ForwardingObjective oldObj = (ForwardingObjective) operation.objectiveOperation();
+ operation = Operation.builder(operation)
+ .isDone(false)
+ .isInstall(false)
+ .build();
+ operations.put(trafficMatchKey.toString(), operation);
+ ForwardingObjective.Builder builder = DefaultForwardingObjective.builder(oldObj);
+ CompletableFuture<Objective> future = new CompletableFuture<>();
+ if (log.isDebugEnabled()) {
+ log.debug("Removing ACL drop forwarding objectives for dev: {}", deviceId);
+ }
+ ObjectiveContext context = new DefaultObjectiveContext(
+ (objective) -> {
+ if (log.isDebugEnabled()) {
+ log.debug("ACL drop rule for policy {} removed", trafficMatch.policyId());
+ }
+ future.complete(objective);
+ },
+ (objective, error) -> {
+ log.warn("Failed to remove ACL drop rule for policy {}: {}", trafficMatch.policyId(), error);
+ future.complete(null);
+ });
+ ForwardingObjective serializableObjective = builder.remove();
+ flowObjectiveService.forward(deviceId, builder.remove(context));
+ future.whenComplete((objective, ex) -> {
+ if (ex != null) {
+ log.error("Exception removing ACL drop rule", ex);
+ } else if (objective != null) {
+ operations.computeIfPresent(trafficMatchKey.toString(), (k, v) -> {
+ if (!v.isDone() && !v.isInstall()) {
+ v.isDone(true);
+ v.objectiveOperation(serializableObjective);
+ }
+ return v;
+ });
+ }
+ });
+ }
+ }
+
+ // Update any depending traffic match on the policy. It is used when a policy
+ // has been removed but there are still traffic matches depending on it
+ private void updateDependingTrafficMatches(PolicyId policyId) {
+ if (!isLeader(policyId)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Instance is not leader for policy {}", policyId);
+ }
+ return;
+ }
+ workers.execute(() -> updateDependingTrafficMatchesInternal(policyId), policyId.hashCode());
+ }
+
+ private void updateDependingTrafficMatchesInternal(PolicyId policyId) {
+ Set<TrafficMatchRequest> pendingTrafficMatches = trafficMatches.stream()
+ .filter(trafficMatchEntry -> trafficMatchEntry.getValue().value().policyId().equals(policyId) &&
+ trafficMatchEntry.getValue().value().trafficMatchState() == TrafficMatchState.ADDED)
+ .map(trafficMatchEntry -> trafficMatchEntry.getValue().value())
+ .collect(Collectors.toSet());
+ for (TrafficMatchRequest trafficMatchRequest : pendingTrafficMatches) {
+ trafficMatches.computeIfPresent(trafficMatchRequest.trafficMatchId(), (k, v) -> {
+ if (v.trafficMatchState() == TrafficMatchState.ADDED) {
+ v.trafficMatchState(TrafficMatchState.PENDING_REMOVE);
+ }
+ return v;
+ });
+ }
+ }
+
+ // Utility that removes operations related to a policy or to a traffic match.
+ private void removeOperations(PolicyId policyId, Optional<TrafficMatchId> trafficMatchId) {
+ if (!isLeader(policyId)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Instance is not leader for policy {}", policyId);
+ }
+ return;
+ }
+ List<DeviceId> edgeDeviceIds = srService.getEdgeDeviceIds();
+ for (DeviceId deviceId : edgeDeviceIds) {
+ workers.execute(() -> {
+ String key;
+ if (trafficMatchId.isPresent()) {
+ key = new TrafficMatchKey(deviceId, trafficMatchId.get()).toString();
+ } else {
+ key = new PolicyKey(deviceId, policyId).toString();
+ }
+ operations.remove(key);
+ }, deviceId.hashCode());
+ }
+ }
+
+ private ForwardingObjective.Builder trafficMatchFwdObjective(TrafficMatch trafficMatch) {
+ return DefaultForwardingObjective.builder()
+ .withPriority(PolicyService.TRAFFIC_MATCH_PRIORITY)
+ .withSelector(trafficMatch.trafficSelector())
+ .fromApp(appId)
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .makePermanent();
+ }
+
+ // Each map has an event listener enabling the events distribution across the cluster
+ private class InternalPolMapEventListener implements MapEventListener<PolicyId, PolicyRequest> {
+ @Override
+ public void event(MapEvent<PolicyId, PolicyRequest> event) {
+ Versioned<PolicyRequest> value = event.type() == MapEvent.Type.REMOVE ?
+ event.oldValue() : event.newValue();
+ PolicyRequest policyRequest = value.value();
+ Policy policy = policyRequest.policy();
+ switch (event.type()) {
+ case INSERT:
+ case UPDATE:
+ switch (policyRequest.policyState()) {
+ case PENDING_ADD:
+ sendPolicy(policy, true);
+ break;
+ case PENDING_REMOVE:
+ sendPolicy(policy, false);
+ break;
+ case ADDED:
+ break;
+ default:
+ log.warn("Unknown policy state type {}", policyRequest.policyState());
+ }
+ break;
+ case REMOVE:
+ removeOperations(policy.policyId(), Optional.empty());
+ updateDependingTrafficMatches(policy.policyId());
+ break;
+ default:
+ log.warn("Unknown event type {}", event.type());
+
+ }
+ }
+ }
+
+ private class InternalTMatchMapEventListener implements MapEventListener<TrafficMatchId, TrafficMatchRequest> {
+ @Override
+ public void event(MapEvent<TrafficMatchId, TrafficMatchRequest> event) {
+ Versioned<TrafficMatchRequest> value = event.type() == MapEvent.Type.REMOVE ?
+ event.oldValue() : event.newValue();
+ TrafficMatchRequest trafficMatchRequest = value.value();
+ TrafficMatch trafficMatch = trafficMatchRequest.trafficMatch();
+ switch (event.type()) {
+ case INSERT:
+ case UPDATE:
+ switch (trafficMatchRequest.trafficMatchState()) {
+ case PENDING_ADD:
+ sendTrafficMatch(trafficMatch, true);
+ break;
+ case PENDING_REMOVE:
+ sendTrafficMatch(trafficMatch, false);
+ break;
+ case ADDED:
+ break;
+ default:
+ log.warn("Unknown traffic match state type {}", trafficMatchRequest.trafficMatchState());
+ }
+ break;
+ case REMOVE:
+ removeOperations(trafficMatch.policyId(), Optional.of(trafficMatch.trafficMatchId()));
+ break;
+ default:
+ log.warn("Unknown event type {}", event.type());
+ }
+ }
+ }
+
+ private class InternalOpsMapEventListener implements MapEventListener<String, Operation> {
+ @Override
+ public void event(MapEvent<String, Operation> event) {
+ String key = event.key();
+ Versioned<Operation> value = event.type() == MapEvent.Type.REMOVE ?
+ event.oldValue() : event.newValue();
+ Operation operation = value.value();
+ switch (event.type()) {
+ case INSERT:
+ case UPDATE:
+ if (operation.isDone()) {
+ if (operation.policy().isPresent()) {
+ PolicyKey policyKey = PolicyKey.fromString(key);
+ updatePolicy(policyKey.policyId(), operation.isInstall());
+ } else if (operation.trafficMatch().isPresent()) {
+ updateTrafficMatch(operation.trafficMatch().get(), operation.isInstall());
+ } else {
+ log.warn("Unknown pending operation");
+ }
+ }
+ break;
+ case REMOVE:
+ break;
+ default:
+ log.warn("Unknown event type {}", event.type());
+ }
+ }
+ }
+
+ // Using the work partition service defines who is in charge of a given policy.
+ private boolean isLeader(PolicyId policyId) {
+ final NodeId currentNodeId = clusterService.getLocalNode().id();
+ final NodeId leader = workPartitionService.getLeader(policyId, this::hasher);
+ if (leader == null) {
+ log.error("Fail to elect a leader for {}.", policyId);
+ return false;
+ }
+ policyLeaderCache.put(policyId, leader);
+ return currentNodeId.equals(leader);
+ }
+
+ private Long hasher(PolicyId policyId) {
+ return HASH_FN.newHasher()
+ .putUnencodedChars(policyId.toString())
+ .hash()
+ .asLong();
+ }
+
+ // Check periodically for any issue and try to resolve automatically if possible
+ private final class PolicyChecker implements Runnable {
+ @Override
+ public void run() {
+ }
+ }
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/PolicyRequest.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/PolicyRequest.java
new file mode 100644
index 0000000..451c1a9
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/PolicyRequest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.impl;
+
+import org.onosproject.segmentrouting.policy.api.Policy;
+import org.onosproject.segmentrouting.policy.api.PolicyId;
+import org.onosproject.segmentrouting.policy.api.PolicyState;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Policy request tracked by the system.
+ */
+final class PolicyRequest {
+ // Stores need to track policy info and the state
+ private final Policy policy;
+ private PolicyState policyState;
+
+ /**
+ * Creates a policy request in pending add.
+ *
+ * @param pol the policy
+ */
+ public PolicyRequest(Policy pol) {
+ policy = pol;
+ policyState = PolicyState.PENDING_ADD;
+ }
+
+ /**
+ * Returns the current state of the request.
+ *
+ * @return the policy state
+ */
+ public PolicyState policyState() {
+ return policyState;
+ }
+
+ /**
+ * Returns the policy id.
+ *
+ * @return the policy id
+ */
+ public PolicyId policyId() {
+ return policy.policyId();
+ }
+
+ /**
+ * Returns the policy type.
+ *
+ * @return the type of a policy
+ */
+ public Policy.PolicyType policyType() {
+ return policy.policyType();
+ }
+
+ /**
+ * To update the policy state.
+ *
+ * @param policystate the new state.
+ */
+ public void policyState(PolicyState policystate) {
+ policyState = policystate;
+ }
+
+ /**
+ * Returns the policy associated to this request.
+ *
+ * @return the policy
+ */
+ public Policy policy() {
+ return policy;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof PolicyRequest)) {
+ return false;
+ }
+ final PolicyRequest other = (PolicyRequest) obj;
+ return Objects.equals(this.policy, other.policy);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(policy);
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("policyState", policyState)
+ .add("policy", policy)
+ .toString();
+ }
+
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchKey.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchKey.java
new file mode 100644
index 0000000..68181a6
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchKey.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.impl;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchId;
+
+import java.util.Objects;
+import java.util.StringTokenizer;
+
+/**
+ * Traffic match key used by the store.
+ */
+public class TrafficMatchKey {
+ private DeviceId deviceId;
+ private TrafficMatchId trafficMatchId;
+
+ /**
+ * Constructs new traffic match key with given device id and traffic match id.
+ *
+ * @param deviceId device id
+ * @param trafficMatchId traffic match id
+ */
+ public TrafficMatchKey(DeviceId deviceId, TrafficMatchId trafficMatchId) {
+ this.deviceId = deviceId;
+ this.trafficMatchId = trafficMatchId;
+ }
+
+ /**
+ * Gets device id.
+ *
+ * @return device id of the policy key
+ */
+ public DeviceId deviceId() {
+ return deviceId;
+ }
+
+ /**
+ * Gets traffic match id.
+ *
+ * @return the id of the traffic match
+ */
+ public TrafficMatchId trafficMatchId() {
+ return trafficMatchId;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof TrafficMatchKey)) {
+ return false;
+ }
+ final TrafficMatchKey other = (TrafficMatchKey) obj;
+ return Objects.equals(this.deviceId, other.deviceId) &&
+ Objects.equals(this.trafficMatchId, other.trafficMatchId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(deviceId, trafficMatchId);
+ }
+
+ /**
+ * Parses from a string the police key.
+ *
+ * @param str the string to parse
+ * @return the policy key if present in the str, null otherwise
+ */
+ public static TrafficMatchKey fromString(String str) {
+ TrafficMatchKey policyKey = null;
+ if (str != null && str.contains(PolicyManager.KEY_SEPARATOR)) {
+ StringTokenizer tokenizer = new StringTokenizer(str, PolicyManager.KEY_SEPARATOR);
+ if (tokenizer.countTokens() == 2) {
+ policyKey = new TrafficMatchKey(DeviceId.deviceId(tokenizer.nextToken()),
+ TrafficMatchId.of(tokenizer.nextToken()));
+ }
+ }
+ return policyKey;
+ }
+
+ @Override
+ public String toString() {
+ return deviceId.toString() + PolicyManager.KEY_SEPARATOR + trafficMatchId.toString();
+ }
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchRequest.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchRequest.java
new file mode 100644
index 0000000..6e01e01
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchRequest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2021-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.segmentrouting.policy.impl;
+
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.segmentrouting.policy.api.PolicyId;
+import org.onosproject.segmentrouting.policy.api.TrafficMatch;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchId;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchState;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Representation of a traffic match.
+ */
+public final class TrafficMatchRequest {
+ // Stores need to track the traffic match info and the state
+ private final TrafficMatch trafficMatch;
+ private TrafficMatchState trafficMatchState;
+
+ /**
+ * Builds a traffic match request in pending add.
+ *
+ * @param tMatch the traffic match
+ */
+ public TrafficMatchRequest(TrafficMatch tMatch) {
+ trafficMatch = tMatch;
+ trafficMatchState = TrafficMatchState.PENDING_ADD;
+ }
+
+ /**
+ * To update the traffic match state.
+ *
+ * @param trafficMatchState the new state
+ */
+ public void trafficMatchState(TrafficMatchState trafficMatchState) {
+ this.trafficMatchState = trafficMatchState;
+ }
+
+ /**
+ * Returns the traffic match state.
+ *
+ * @return the state of the traffic match
+ */
+ public TrafficMatchState trafficMatchState() {
+ return trafficMatchState;
+ }
+
+ /**
+ * Returns the traffic match id.
+ *
+ * @return the id of the traffic match
+ */
+ public TrafficMatchId trafficMatchId() {
+ return trafficMatch.trafficMatchId();
+ }
+
+ /**
+ * Returns the id of the policy associated with.
+ *
+ * @return the policy id
+ */
+ public PolicyId policyId() {
+ return trafficMatch.policyId();
+ }
+
+ /**
+ * Returns the traffic selector associated with.
+ *
+ * @return the traffic selector
+ */
+ public TrafficSelector trafficSelector() {
+ return trafficMatch.trafficSelector();
+ }
+
+ /**
+ * Returns the traffic match associated with.
+ *
+ * @return the traffic match
+ */
+ public TrafficMatch trafficMatch() {
+ return trafficMatch;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(trafficMatch);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof TrafficMatchRequest) {
+ final TrafficMatchRequest other = (TrafficMatchRequest) obj;
+ return Objects.equals(trafficMatch, other.trafficMatch);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("trafficMatch", trafficMatch)
+ .add("trafficMatchState", trafficMatchState)
+ .toString();
+ }
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/package-info.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/package-info.java
new file mode 100644
index 0000000..f5199ca
--- /dev/null
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-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.
+ */
+
+/**
+ * Policy implementation.
+ */
+package org.onosproject.segmentrouting.policy.impl;
\ No newline at end of file