Draft implementation of Tor App
Change-Id: I783c324e6d2308c0afd4ab5ede12d32d3ae138aa
diff --git a/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java b/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java
index 18f1e8c..e106823 100644
--- a/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java
+++ b/apps/pi-demo/common/src/main/java/org/onosproject/pi/demo/app/common/AbstractUpgradableFabricApp.java
@@ -46,7 +46,6 @@
import org.onosproject.net.host.HostService;
import org.onosproject.net.pi.model.PiPipeconf;
import org.onosproject.net.pi.model.PiPipeconfId;
-import org.onosproject.net.pi.model.PiPipelineInterpreter;
import org.onosproject.net.pi.runtime.PiPipeconfService;
import org.onosproject.net.pi.runtime.PiTableId;
import org.onosproject.net.topology.Topology;
@@ -71,7 +70,6 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
-import static java.lang.String.format;
import static java.util.stream.Collectors.toSet;
import static java.util.stream.Stream.concat;
import static org.onlab.util.Tools.groupedThreads;
@@ -151,7 +149,7 @@
/**
* Creates a new PI fabric app.
*
- * @param appName app name
+ * @param appName app name
* @param appPipeconfs collection of compatible pipeconfs
*/
protected AbstractUpgradableFabricApp(String appName, Collection<PiPipeconf> appPipeconfs) {
@@ -228,7 +226,7 @@
one, it generates the necessary flow rules and starts the deploy process on each device.
*/
scheduledExecutorService.scheduleAtFixedRate(this::checkTopologyAndGenerateFlowRules,
- 0, CHECK_TOPOLOGY_INTERVAL_SECONDS, TimeUnit.SECONDS);
+ 0, CHECK_TOPOLOGY_INTERVAL_SECONDS, TimeUnit.SECONDS);
}
private void setAppFreezed(boolean appFreezed) {
@@ -260,7 +258,7 @@
* @return a list of flow rules
* @throws FlowRuleGeneratorException if flow rules cannot be generated
*/
- public abstract List<FlowRule> generateLeafRules(DeviceId leaf, Host srcHost, Collection<Host> dstHosts,
+ public abstract List<FlowRule> generateLeafRules(DeviceId leaf, Host srcHost, Set<Host> dstHosts,
Collection<DeviceId> spines, Topology topology)
throws FlowRuleGeneratorException;
@@ -273,7 +271,7 @@
* @return a list of flow rules
* @throws FlowRuleGeneratorException if flow rules cannot be generated
*/
- public abstract List<FlowRule> generateSpineRules(DeviceId deviceId, Collection<Host> dstHosts, Topology topology)
+ public abstract List<FlowRule> generateSpineRules(DeviceId deviceId, Set<Host> dstHosts, Topology topology)
throws FlowRuleGeneratorException;
private void deployAllDevices() {
@@ -453,27 +451,14 @@
/**
* Returns a new, pre-configured flow rule builder.
*
- * @param did a device id
- * @param tableName a table name
+ * @param did a device id
+ * @param tableId a PI table ID
* @return a new flow rule builder
*/
- protected FlowRule.Builder flowRuleBuilder(DeviceId did, String tableName) throws FlowRuleGeneratorException {
-
- final Device device = deviceService.getDevice(did);
- if (!device.is(PiPipelineInterpreter.class)) {
- throw new FlowRuleGeneratorException(format("Device %s has no PiPipelineInterpreter", did));
- }
- final PiPipelineInterpreter interpreter = device.as(PiPipelineInterpreter.class);
- final int flowRuleTableId;
- if (interpreter.mapPiTableId(PiTableId.of(tableName)).isPresent()) {
- flowRuleTableId = interpreter.mapPiTableId(PiTableId.of(tableName)).get();
- } else {
- throw new FlowRuleGeneratorException(format("Unknown table %s in interpreter", tableName));
- }
-
+ protected FlowRule.Builder flowRuleBuilder(DeviceId did, PiTableId tableId) throws FlowRuleGeneratorException {
return DefaultFlowRule.builder()
.forDevice(did)
- .forTable(flowRuleTableId)
+ .forTable(tableId)
.fromApp(appId)
.withPriority(FLOW_PRIORITY)
.makePermanent();
diff --git a/apps/pi-demo/ecmp/src/main/java/org/onosproject/pi/demo/app/ecmp/EcmpFabricApp.java b/apps/pi-demo/ecmp/src/main/java/org/onosproject/pi/demo/app/ecmp/EcmpFabricApp.java
index fccbab5..26ff775 100644
--- a/apps/pi-demo/ecmp/src/main/java/org/onosproject/pi/demo/app/ecmp/EcmpFabricApp.java
+++ b/apps/pi-demo/ecmp/src/main/java/org/onosproject/pi/demo/app/ecmp/EcmpFabricApp.java
@@ -39,6 +39,7 @@
import org.onosproject.net.pi.runtime.PiActionParamId;
import org.onosproject.net.pi.runtime.PiHeaderFieldId;
import org.onosproject.net.pi.runtime.PiTableAction;
+import org.onosproject.net.pi.runtime.PiTableId;
import org.onosproject.net.topology.DefaultTopologyVertex;
import org.onosproject.net.topology.Topology;
import org.onosproject.net.topology.TopologyGraph;
@@ -64,6 +65,8 @@
public class EcmpFabricApp extends AbstractUpgradableFabricApp {
private static final String APP_NAME = "org.onosproject.pi-ecmp-fabric";
+ private static final PiTableId TABLE0_ID = PiTableId.of(TABLE0);
+ private static final PiTableId ECMP_GROUP_TABLE_ID = PiTableId.of(ECMP_GROUP_TABLE);
private static final Map<DeviceId, Map<Set<PortNumber>, Short>> DEVICE_GROUP_ID_MAP = Maps.newHashMap();
@@ -78,7 +81,7 @@
}
@Override
- public List<FlowRule> generateLeafRules(DeviceId leaf, Host srcHost, Collection<Host> dstHosts,
+ public List<FlowRule> generateLeafRules(DeviceId leaf, Host srcHost, Set<Host> dstHosts,
Collection<DeviceId> availableSpines, Topology topo)
throws FlowRuleGeneratorException {
@@ -120,7 +123,7 @@
// From srHost to dstHosts.
for (Host dstHost : dstHosts) {
- FlowRule rule = flowRuleBuilder(leaf, EcmpInterpreter.TABLE0)
+ FlowRule rule = flowRuleBuilder(leaf, TABLE0_ID)
.withSelector(
DefaultTrafficSelector.builder()
.matchInPort(hostPort)
@@ -135,7 +138,7 @@
// From fabric ports to this leaf host.
for (PortNumber port : fabricPorts) {
- FlowRule rule = flowRuleBuilder(leaf, EcmpInterpreter.TABLE0)
+ FlowRule rule = flowRuleBuilder(leaf, TABLE0_ID)
.withSelector(
DefaultTrafficSelector.builder()
.matchInPort(port)
@@ -154,7 +157,7 @@
}
@Override
- public List<FlowRule> generateSpineRules(DeviceId deviceId, Collection<Host> dstHosts, Topology topo)
+ public List<FlowRule> generateSpineRules(DeviceId deviceId, Set<Host> dstHosts, Topology topo)
throws FlowRuleGeneratorException {
List<FlowRule> rules = Lists.newArrayList();
@@ -183,7 +186,7 @@
treatment = DefaultTrafficTreatment.builder().piTableAction(result.getLeft()).build();
}
- FlowRule rule = flowRuleBuilder(deviceId, EcmpInterpreter.TABLE0)
+ FlowRule rule = flowRuleBuilder(deviceId, TABLE0_ID)
.withSelector(
DefaultTrafficSelector.builder()
.matchEthType(IPV4.ethType().toShort())
@@ -212,7 +215,7 @@
Iterator<PortNumber> portIterator = fabricPorts.iterator();
List<FlowRule> rules = Lists.newArrayList();
for (short i = 0; i < HASHED_LINKS; i++) {
- FlowRule rule = flowRuleBuilder(deviceId, EcmpInterpreter.ECMP_GROUP_TABLE)
+ FlowRule rule = flowRuleBuilder(deviceId, ECMP_GROUP_TABLE_ID)
.withSelector(
buildEcmpTrafficSelector(groupId, i))
.withTreatment(
@@ -248,7 +251,7 @@
.build();
}
- public int groupIdOf(DeviceId deviceId, Set<PortNumber> ports) {
+ private int groupIdOf(DeviceId deviceId, Set<PortNumber> ports) {
DEVICE_GROUP_ID_MAP.putIfAbsent(deviceId, Maps.newHashMap());
// Counts the number of unique portNumber sets for each deviceId.
// Each distinct set of portNumbers will have a unique ID.
diff --git a/apps/pi-demo/tor/src/main/java/org/onosproject/pi/demo/app/tor/Combination.java b/apps/pi-demo/tor/src/main/java/org/onosproject/pi/demo/app/tor/Combination.java
new file mode 100644
index 0000000..5275fa8
--- /dev/null
+++ b/apps/pi-demo/tor/src/main/java/org/onosproject/pi/demo/app/tor/Combination.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2017-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.pi.demo.app.tor;
+
+import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.math.IntMath;
+
+import java.util.AbstractSet;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Combination algorithm implementation, taken from Guava 23.
+ */
+final class Combination {
+
+ private Combination() {
+ // Hides constructor.
+ }
+
+ /**
+ * Returns a map from the ith element of list to i.
+ */
+ private static <E> ImmutableMap<E, Integer> indexMap(Collection<E> list) {
+ ImmutableMap.Builder<E, Integer> builder = ImmutableMap.builder();
+ int i = 0;
+ for (E e : list) {
+ builder.put(e, i++);
+ }
+ return builder.build();
+ }
+
+ /**
+ * Returns the set of all subsets of {@code set} of size {@code size}. For example, {@code
+ * combinations(ImmutableSet.of(1, 2, 3), 2)} returns the set {@code {{1, 2}, {1, 3}, {2, 3}}}.
+ * <p>
+ * <p>Elements appear in these subsets in the same iteration order as they appeared in the input set. The order in
+ * which these subsets appear in the outer set is undefined.
+ * <p>
+ * <p>The returned set and its constituent sets use {@code equals} to decide whether two elements are identical,
+ * even if the input set uses a different concept of equivalence.
+ * <p>
+ * <p><i>Performance notes:</i> the memory usage of the returned set is only {@code O(n)}. When the result set is
+ * constructed, the input set is merely copied. Only as the result set is iterated are the individual subsets
+ * created. Each of these subsets occupies an additional O(n) memory but only for as long as the user retains a
+ * reference to it. That is, the set returned by {@code combinations} does not retain the individual subsets.
+ *
+ * @param set the set of elements to take combinations of
+ * @param size the number of elements per combination
+ * @return the set of all combinations of {@code size} elements from {@code set}
+ * @throws IllegalArgumentException if {@code size} is not between 0 and {@code set.size()} inclusive
+ * @throws NullPointerException if {@code set} is or contains {@code null}
+ * @since 23.0
+ */
+ static <E> Set<Set<E>> combinations(Set<E> set, final int size) {
+ final ImmutableMap<E, Integer> index = indexMap(set);
+ checkArgument(size > 0, "size");
+ checkArgument(size <= index.size(), "size (%s) must be <= set.size() (%s)", size, index.size());
+ if (size == 0) {
+ return ImmutableSet.of(ImmutableSet.<E>of());
+ } else if (size == index.size()) {
+ return ImmutableSet.of(index.keySet());
+ }
+ return new AbstractSet<Set<E>>() {
+ @Override
+ public boolean contains(Object o) {
+ if (o instanceof Set) {
+ Set<?> s = (Set<?>) o;
+ return s.size() == size && index.keySet().containsAll(s);
+ }
+ return false;
+ }
+
+ @Override
+ public Iterator<Set<E>> iterator() {
+ return new AbstractIterator<Set<E>>() {
+ final BitSet bits = new BitSet(index.size());
+
+ @Override
+ protected Set<E> computeNext() {
+ if (bits.isEmpty()) {
+ bits.set(0, size);
+ } else {
+ int firstSetBit = bits.nextSetBit(0);
+ int bitToFlip = bits.nextClearBit(firstSetBit);
+
+ if (bitToFlip == index.size()) {
+ return endOfData();
+ }
+
+ /*
+ * The current set in sorted order looks like
+ * {firstSetBit, firstSetBit + 1, ..., bitToFlip - 1, ...}
+ * where it does *not* contain bitToFlip.
+ *
+ * The next combination is
+ *
+ * {0, 1, ..., bitToFlip - firstSetBit - 2, bitToFlip, ...}
+ *
+ * This is lexicographically next if you look at the combinations in descending order
+ * e.g. {2, 1, 0}, {3, 1, 0}, {3, 2, 0}, {3, 2, 1}, {4, 1, 0}...
+ */
+
+ bits.set(0, bitToFlip - firstSetBit - 1);
+ bits.clear(bitToFlip - firstSetBit - 1, bitToFlip);
+ bits.set(bitToFlip);
+ }
+ final BitSet copy = (BitSet) bits.clone();
+ return new AbstractSet<E>() {
+ @Override
+ public boolean contains(Object o) {
+ Integer i = index.get(o);
+ return i != null && copy.get(i);
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return new AbstractIterator<E>() {
+ int i = -1;
+
+ @Override
+ protected E computeNext() {
+ i = copy.nextSetBit(i + 1);
+ if (i == -1) {
+ return endOfData();
+ }
+ return index.keySet().asList().get(i);
+ }
+ };
+ }
+
+ @Override
+ public int size() {
+ return size;
+ }
+ };
+ }
+ };
+ }
+
+ @Override
+ public int size() {
+ return IntMath.binomial(index.size(), size);
+ }
+
+ @Override
+ public String toString() {
+ return "Sets.combinations(" + index.keySet() + ", " + size + ")";
+ }
+ };
+ }
+
+}
\ No newline at end of file
diff --git a/apps/pi-demo/tor/src/main/java/org/onosproject/pi/demo/app/tor/TorApp.java b/apps/pi-demo/tor/src/main/java/org/onosproject/pi/demo/app/tor/TorApp.java
index 5b1eea3..6ce8697 100644
--- a/apps/pi-demo/tor/src/main/java/org/onosproject/pi/demo/app/tor/TorApp.java
+++ b/apps/pi-demo/tor/src/main/java/org/onosproject/pi/demo/app/tor/TorApp.java
@@ -16,33 +16,47 @@
package org.onosproject.pi.demo.app.tor;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Maps;
+import com.google.common.collect.Lists;
import org.apache.felix.scr.annotations.Component;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
+import org.onosproject.net.Path;
+import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.pi.runtime.PiAction;
+import org.onosproject.net.pi.runtime.PiActionId;
+import org.onosproject.net.pi.runtime.PiActionParam;
+import org.onosproject.net.topology.DefaultTopologyVertex;
import org.onosproject.net.topology.Topology;
+import org.onosproject.net.topology.TopologyGraph;
import org.onosproject.pi.demo.app.common.AbstractUpgradableFabricApp;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.google.common.collect.Collections2.permutations;
+import static org.onlab.util.ImmutableByteSequence.copyFrom;
+import static org.onosproject.pi.demo.app.tor.Combination.combinations;
+import static org.onosproject.pi.demo.app.tor.TorInterpreter.*;
/**
* Implementation of an upgradable fabric app for TOR configuration.
*/
-//TODO implement
@Component(immediate = true)
public class TorApp extends AbstractUpgradableFabricApp {
private static final String APP_NAME = "org.onosproject.pi-tor";
- private static final Map<DeviceId, Map<Set<PortNumber>, Short>> DEVICE_GROUP_ID_MAP = Maps.newHashMap();
-
public TorApp() {
super(APP_NAME, TorPipeconfFactory.getAll());
}
@@ -54,18 +68,178 @@
}
@Override
- public List<FlowRule> generateLeafRules(DeviceId leaf, Host srcHost, Collection<Host> dstHosts,
+ public List<FlowRule> generateLeafRules(DeviceId leaf, Host localHost, Set<Host> remoteHosts,
Collection<DeviceId> availableSpines, Topology topo)
throws FlowRuleGeneratorException {
- return ImmutableList.of();
+ // Get ports which connect this leaf switch to hosts.
+ Set<PortNumber> hostPorts = deviceService.getPorts(leaf)
+ .stream()
+ .filter(port -> !isFabricPort(port, topo))
+ .map(Port::number)
+ .collect(Collectors.toSet());
+
+ // Get ports which connect this leaf to the given available spines.
+ TopologyGraph graph = topologyService.getGraph(topo);
+ Set<PortNumber> fabricPorts = graph.getEdgesFrom(new DefaultTopologyVertex(leaf))
+ .stream()
+ .filter(e -> availableSpines.contains(e.dst().deviceId()))
+ .map(e -> e.link().src().port())
+ .collect(Collectors.toSet());
+
+ if (hostPorts.size() != 1 || fabricPorts.size() == 0) {
+ log.error("Leaf switch has invalid port configuration: hostPorts={}, fabricPorts={}",
+ hostPorts.size(), fabricPorts.size());
+ throw new FlowRuleGeneratorException();
+ }
+ PortNumber hostPort = hostPorts.iterator().next();
+
+ List<FlowRule> rules = Lists.newArrayList();
+
+ // Filtering rules
+ rules.addAll(generateFilteringRules(leaf, remoteHosts));
+ rules.addAll(generateFilteringRules(leaf, Collections.singleton(localHost)));
+
+ // FIXME: ignore ECMP for the moment
+ // if (fabricPorts.size() > 1) {
+ // // Do ECMP.
+ // Pair<PiTableAction, List<FlowRule>> result = provisionEcmpPiTableAction(leaf, fabricPorts);
+ // rules.addAll(result.getRight());
+ // treatment = DefaultTrafficTreatment.builder().piTableAction(result.getLeft()).build();
+ // } else {
+ // // Output on port.
+ // PortNumber outPort = fabricPorts.iterator().next();
+ // treatment = DefaultTrafficTreatment.builder().setOutput(outPort).build();
+ // }
+
+
+ PortNumber outPort = fabricPorts.iterator().next();
+
+ // From local host to remote ones.
+ for (Host remoteHost : remoteHosts) {
+ for (IpAddress ipAddr : remoteHost.ipAddresses()) {
+ FlowRule rule = flowRuleBuilder(leaf, L3_FWD_TBL_ID)
+ .withSelector(
+ DefaultTrafficSelector.builder()
+ .matchIPDst(ipAddr.toIpPrefix())
+ .build())
+ .withTreatment(
+ DefaultTrafficTreatment.builder()
+ .piTableAction(nextHopAction(outPort, localHost.mac(), remoteHost.mac()))
+ .build())
+ .build();
+ rules.add(rule);
+ }
+ }
+
+ // From remote hosts to the local one
+ for (IpAddress dstIpAddr : localHost.ipAddresses()) {
+ for (Host remoteHost : remoteHosts) {
+ FlowRule rule = flowRuleBuilder(leaf, L3_FWD_TBL_ID)
+ .withSelector(
+ DefaultTrafficSelector.builder()
+ .matchIPDst(dstIpAddr.toIpPrefix())
+ .build())
+ .withTreatment(
+ DefaultTrafficTreatment.builder()
+ .piTableAction(nextHopAction(hostPort, remoteHost.mac(), localHost.mac()))
+ .build())
+ .build();
+ rules.add(rule);
+ }
+ }
+
+ return rules;
+ }
+
+ private PiAction nextHopAction(PortNumber port, MacAddress smac, MacAddress dmac) {
+ return PiAction.builder()
+ .withId(SET_NEXT_HOP_ACT_ID)
+ .withParameter(new PiActionParam(PORT_ACT_PRM_ID, copyFrom(port.toLong())))
+ // Ignore L3 routing behaviour by keeping the original host mac addresses at each hop.
+ .withParameter(new PiActionParam(SMAC_ACT_PRM_ID, copyFrom(smac.toBytes())))
+ .withParameter(new PiActionParam(DMAC_ACT_PRM_ID, copyFrom(dmac.toBytes())))
+ .build();
}
@Override
- public List<FlowRule> generateSpineRules(DeviceId deviceId, Collection<Host> dstHosts, Topology topo)
+ public List<FlowRule> generateSpineRules(DeviceId spine, Set<Host> hosts, Topology topo)
throws FlowRuleGeneratorException {
- return ImmutableList.of();
+ List<FlowRule> rules = Lists.newArrayList();
+
+ rules.addAll(generateFilteringRules(spine, hosts));
+
+ // For each host pair (src -> dst)
+ for (Set<Host> hostCombs : combinations(hosts, 2)) {
+ for (List<Host> hostPair : permutations(hostCombs)) {
+
+ Host srcHost = hostPair.get(0);
+ Host dstHost = hostPair.get(1);
+
+ Set<Path> paths = topologyService.getPaths(topo, spine, dstHost.location().deviceId());
+
+ if (paths.size() == 0) {
+ log.warn("Can't find any path between spine {} and host {}", spine, dstHost);
+ throw new FlowRuleGeneratorException();
+ }
+
+ TrafficTreatment treatment;
+
+ // FIXME: ingore ECMP for the moment
+ // if (paths.size() == 1) {
+ // // Only one path, do output on port.
+ // PortNumber port = paths.iterator().next().src().port();
+ // treatment = DefaultTrafficTreatment.builder().setOutput(port).build();
+ // } else {
+ // // Multiple paths, do ECMP.
+ // Set<PortNumber> portNumbers = paths.stream().map(p -> p.src().port()).collect(toSet());
+ // Pair<PiTableAction, List<FlowRule>> result = provisionEcmpPiTableAction(deviceId, portNumbers);
+ // rules.addAll(result.getRight());
+ // treatment = DefaultTrafficTreatment.builder().piTableAction(result.getLeft()).build();
+ // }
+
+ PortNumber port = paths.iterator().next().src().port();
+ treatment = DefaultTrafficTreatment.builder()
+ .piTableAction(nextHopAction(port, srcHost.mac(), dstHost.mac()))
+ .build();
+
+ for (IpAddress dstIpAddr : dstHost.ipAddresses()) {
+ FlowRule rule = flowRuleBuilder(spine, L3_FWD_TBL_ID)
+ .withSelector(
+ DefaultTrafficSelector.builder()
+ .matchIPDst(dstIpAddr.toIpPrefix())
+ .build())
+ .withTreatment(treatment)
+ .build();
+
+ rules.add(rule);
+ }
+ }
+ }
+
+ return rules;
+ }
+
+ private List<FlowRule> generateFilteringRules(DeviceId deviceId, Collection<Host> dstHosts)
+ throws FlowRuleGeneratorException {
+
+ List<FlowRule> rules = Lists.newArrayList();
+ for (Host host : dstHosts) {
+ MacAddress ethAddr = host.mac();
+ FlowRule rule = flowRuleBuilder(deviceId, L3_FILTER_TBL_ID)
+ .withSelector(DefaultTrafficSelector.builder()
+ .matchEthDst(ethAddr)
+ .build())
+ .withTreatment(DefaultTrafficTreatment.builder()
+ .piTableAction(PiAction.builder()
+ .withId(PiActionId.of("NoAction"))
+ .build())
+ .build())
+ .build();
+ rules.add(rule);
+ }
+ return rules;
}
}
\ No newline at end of file
diff --git a/apps/pi-demo/tor/src/main/java/org/onosproject/pi/demo/app/tor/TorInterpreter.java b/apps/pi-demo/tor/src/main/java/org/onosproject/pi/demo/app/tor/TorInterpreter.java
index 5bd3864..c893e4a 100644
--- a/apps/pi-demo/tor/src/main/java/org/onosproject/pi/demo/app/tor/TorInterpreter.java
+++ b/apps/pi-demo/tor/src/main/java/org/onosproject/pi/demo/app/tor/TorInterpreter.java
@@ -77,19 +77,34 @@
private static final String EGRESS_PORT = "egress_physical_port";
private static final String INGRESS_PORT = "ingress_physical_port";
+ static final PiTableId L3_FILTER_TBL_ID = PiTableId.of("l3_fwd", "l3_routing_classifier_table");
+ static final PiTableId L3_FWD_TBL_ID = PiTableId.of("l3_fwd", "l3_ipv4_override_table");
+ static final PiActionId SET_NEXT_HOP_ACT_ID = PiActionId.of("l3_fwd.set_nexthop");
+ static final PiActionParamId PORT_ACT_PRM_ID = PiActionParamId.of("port");
+ static final PiActionParamId SMAC_ACT_PRM_ID = PiActionParamId.of("smac");
+ static final PiActionParamId DMAC_ACT_PRM_ID = PiActionParamId.of("dmac");
+
// Set as per value in headers.p4 in packet_out_header
private static final int PORT_FIELD_BITWIDTH = 9;
private static final PiHeaderFieldId ETH_TYPE_ID = PiHeaderFieldId.of("ethernet", "ether_type");
+ private static final PiHeaderFieldId ETH_DST_ID = PiHeaderFieldId.of("ethernet", "dst_addr");
+ private static final PiHeaderFieldId ETH_SRC_ID = PiHeaderFieldId.of("ethernet", "src_addr");
+ private static final PiHeaderFieldId IPV4_DST_ID = PiHeaderFieldId.of("ipv4_base", "dst_addr");
private static final ImmutableBiMap<Integer, PiTableId> TABLE_MAP = ImmutableBiMap.of(
// If we use the DefaultSingleTable pipeliner, then we need to map only table ID 0,
// which in this case will be the one used by proxyarp, lldpprovider, etc., i.e. the punt table.
- 0, PUNT_TABLE_ID);
+ 0, PUNT_TABLE_ID,
+ 1, L3_FILTER_TBL_ID,
+ 2, L3_FWD_TBL_ID);
private ImmutableBiMap<Criterion.Type, PiHeaderFieldId> criterionMap =
new ImmutableBiMap.Builder<Criterion.Type, PiHeaderFieldId>()
+ .put(Criterion.Type.ETH_DST, ETH_DST_ID)
+ .put(Criterion.Type.ETH_SRC, ETH_SRC_ID)
.put(Criterion.Type.ETH_TYPE, ETH_TYPE_ID)
+ .put(Criterion.Type.IPV4_DST, IPV4_DST_ID)
.build();
//FIXME figure out what queque id is, we set as all zeros for now.