diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/AppConfigHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/AppConfigHandler.java index f54ee9e419..034ddfe841 100644 --- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/AppConfigHandler.java +++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/AppConfigHandler.java @@ -16,6 +16,8 @@ package org.onosproject.segmentrouting; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; import org.onosproject.net.DeviceId; import org.onosproject.net.PortNumber; @@ -62,6 +64,9 @@ public class AppConfigHandler { SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get(); deviceService.getAvailableDevices().forEach(device -> { populateVRouter(device.id(), getMacAddresses(config)); + config.blackholeIPs().forEach(ipPrefix -> { + srManager.routingRulePopulator.populateDefaultRouteBlackhole(device.id(), ipPrefix); + }); }); } @@ -86,6 +91,14 @@ public class AppConfigHandler { revokeVRouter(device.id(), prevMacAddresses); populateVRouter(device.id(), macAddresses); + Set toRemove = Sets.difference(prevConfig.blackholeIPs(), config.blackholeIPs()); + toRemove.forEach(ipPrefix -> { + srManager.routingRulePopulator.removeDefaultRouteBlackhole(device.id(), ipPrefix); + }); + Set toAdd = Sets.difference(config.blackholeIPs(), prevConfig.blackholeIPs()); + toAdd.forEach(ipPrefix -> { + srManager.routingRulePopulator.populateDefaultRouteBlackhole(device.id(), ipPrefix); + }); }); } @@ -100,11 +113,14 @@ public class AppConfigHandler { SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get(); deviceService.getAvailableDevices().forEach(device -> { revokeVRouter(device.id(), getMacAddresses(prevConfig)); + prevConfig.blackholeIPs().forEach(ipPrefix -> { + srManager.routingRulePopulator.removeDefaultRouteBlackhole(device.id(), ipPrefix); + }); }); } /** - * Populates initial vRouter rules. + * Populates initial vRouter and blackhole rules. * * @param deviceId device ID */ @@ -112,6 +128,9 @@ public class AppConfigHandler { SegmentRoutingAppConfig config = srManager.cfgService.getConfig(srManager.appId, SegmentRoutingAppConfig.class); populateVRouter(deviceId, getMacAddresses(config)); + config.blackholeIPs().forEach(ipPrefix -> { + srManager.routingRulePopulator.populateDefaultRouteBlackhole(deviceId, ipPrefix); + }); } private void populateVRouter(DeviceId deviceId, Set pendingAdd) { @@ -166,7 +185,9 @@ public class AppConfigHandler { if (srManager.deviceConfiguration.isEdgeDevice(deviceId)) { return true; } - } catch (DeviceConfigNotFoundException e) { } + } catch (DeviceConfigNotFoundException e) { + log.warn("Device configuration for {} is not present.", deviceId); + } return false; } } diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java index 094d28736a..64fe2fc46d 100644 --- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java +++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java @@ -1373,6 +1373,75 @@ public class RoutingRulePopulator { return fwdObjBuilder(sBuilder.build(), tBuilder.build(), priority); } + /** + * Populates a forwarding objective to send packets that miss other high + * priority Bridging Table entries to a group that contains all ports of + * its subnet. + * + * @param address the address to block + * @param deviceId switch ID to set the rules + */ + void populateDefaultRouteBlackhole(DeviceId deviceId, IpPrefix address) { + updateDefaultRouteBlackhole(deviceId, address, true); + } + + /** + * Populates a forwarding objective to send packets that miss other high + * priority Bridging Table entries to a group that contains all ports of + * its subnet. + * + * @param address the address to block + * @param deviceId switch ID to set the rules + */ + void removeDefaultRouteBlackhole(DeviceId deviceId, IpPrefix address) { + updateDefaultRouteBlackhole(deviceId, address, false); + } + + private void updateDefaultRouteBlackhole(DeviceId deviceId, IpPrefix address, boolean install) { + try { + if (srManager.deviceConfiguration.isEdgeDevice(deviceId)) { + + TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); + if (address.isIp4()) { + sbuilder.matchIPDst(address); + sbuilder.matchEthType(EthType.EtherType.IPV4.ethType().toShort()); + } else { + sbuilder.matchIPv6Dst(address); + sbuilder.matchEthType(EthType.EtherType.IPV6.ethType().toShort()); + } + + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); + + tBuilder.transition(60); + tBuilder.wipeDeferred(); + + ForwardingObjective.Builder fob = DefaultForwardingObjective.builder(); + fob.withFlag(Flag.SPECIFIC) + .withSelector(sbuilder.build()) + .withTreatment(tBuilder.build()) + .withPriority(getPriorityFromPrefix(address)) + .fromApp(srManager.appId) + .makePermanent(); + + log.debug("{} blackhole forwarding objectives for dev: {}", + install ? "Installing" : "Removing", deviceId); + ObjectiveContext context = new DefaultObjectiveContext( + (objective) -> log.debug("Forward for {} {}", deviceId, + install ? "installed" : "removed"), + (objective, error) -> log.warn("Failed to {} forward for {}: {}", + install ? "install" : "remove", deviceId, error)); + if (install) { + srManager.flowObjectiveService.forward(deviceId, fob.add(context)); + } else { + srManager.flowObjectiveService.forward(deviceId, fob.remove(context)); + } + } + } catch (DeviceConfigNotFoundException e) { + log.info("Not populating blackhole for un-configured device {}", deviceId); + } + + } + /** * Populates a forwarding objective to send packets that miss other high * priority Bridging Table entries to a group that contains all ports of diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingAppConfig.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingAppConfig.java index 3e4d17cda3..9741f78960 100644 --- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingAppConfig.java +++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingAppConfig.java @@ -19,6 +19,7 @@ package org.onosproject.segmentrouting.config; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.google.common.collect.ImmutableSet; +import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; import org.onosproject.core.ApplicationId; import org.onosproject.net.ConnectPoint; @@ -38,14 +39,68 @@ public class SegmentRoutingAppConfig extends Config { // TODO We might want to move SUPPRESS_HOST_BY_PROVIDER to Component Config private static final String SUPPRESS_HOST_BY_PROVIDER = "suppressHostByProvider"; private static final String MPLS_ECMP = "MPLS-ECMP"; + private static final String BLACKHOLE_IPS = "blackholeIps"; @Override public boolean isValid() { return hasOnlyFields(VROUTER_MACS, SUPPRESS_SUBNET, - SUPPRESS_HOST_BY_PORT, SUPPRESS_HOST_BY_PROVIDER, MPLS_ECMP) && + SUPPRESS_HOST_BY_PORT, SUPPRESS_HOST_BY_PROVIDER, MPLS_ECMP, BLACKHOLE_IPS) && vRouterMacs() != null && suppressSubnet() != null && suppressHostByPort() != null && - suppressHostByProvider() != null; + suppressHostByProvider() != null && + blackholeIPs() != null; + } + + /** + * Gets ips to blackhole from the config. + * + * @return Set of ips to blackhole, empty is not specified, + * or null if not valid + */ + public Set blackholeIPs() { + if (!object.has(BLACKHOLE_IPS)) { + return ImmutableSet.of(); + } + + ImmutableSet.Builder builder = ImmutableSet.builder(); + ArrayNode arrayNode = (ArrayNode) object.path(BLACKHOLE_IPS); + for (JsonNode jsonNode : arrayNode) { + IpPrefix address; + + String addrStr = jsonNode.asText(null); + if (addrStr == null) { + return null; + } + try { + address = IpPrefix.valueOf(addrStr); + } catch (IllegalArgumentException e) { + return null; + } + + builder.add(address); + } + return builder.build(); + } + + /** + * Sets ips to blackhole to the config. + * + * @param blackholeIps a set of ips to blackhole + * @return this {@link SegmentRoutingAppConfig} + */ + public SegmentRoutingAppConfig setBalckholeIps(Set blackholeIps) { + if (blackholeIps == null) { + object.remove(BLACKHOLE_IPS); + } else { + ArrayNode arrayNode = mapper.createArrayNode(); + + blackholeIps.forEach(ip -> { + arrayNode.add(ip.toString()); + }); + + object.set(BLACKHOLE_IPS, arrayNode); + } + return this; } /** @@ -262,6 +317,7 @@ public class SegmentRoutingAppConfig extends Config { .add("suppressHostByPort", suppressHostByPort()) .add("suppressHostByProvider", suppressHostByProvider()) .add("mplsEcmp", mplsEcmp()) + .add("blackholeIps", blackholeIPs()) .toString(); } } diff --git a/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/config/SegmentRoutingAppConfigTest.java b/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/config/SegmentRoutingAppConfigTest.java index 72b1ef5ff1..2a10f5639c 100644 --- a/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/config/SegmentRoutingAppConfigTest.java +++ b/apps/segmentrouting/app/src/test/java/org/onosproject/segmentrouting/config/SegmentRoutingAppConfigTest.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableSet; import org.junit.Before; import org.junit.Test; +import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; import org.onosproject.core.ApplicationId; import org.onosproject.TestApplicationId; @@ -55,6 +56,8 @@ public class SegmentRoutingAppConfigTest { private static final String PROVIDER_1 = "org.onosproject.provider.host"; private static final String PROVIDER_2 = "org.onosproject.netcfghost"; private static final String PROVIDER_3 = "org.onosproject.anotherprovider"; + private static final IpPrefix BLACKHOLE_IP = IpPrefix.valueOf("10.0.0.0/8"); + private static final IpPrefix BLACKHOLE_IP_2 = IpPrefix.valueOf("20.0.0.0/8"); /** * Initialize test related variables. @@ -263,6 +266,34 @@ public class SegmentRoutingAppConfigTest { assertTrue(supprsuppressHostByProvider.contains(PROVIDER_3)); } + /** + * Tests BlackHoleIps getter. + * + * @throws Exception + */ + @Test + public void testBlackHoleIps() throws Exception { + Set blackHoleIps = config.blackholeIPs(); + assertNotNull("BlackHoleIps should not be null", blackHoleIps); + assertThat(blackHoleIps.size(), is(1)); + assertTrue(blackHoleIps.contains(BLACKHOLE_IP)); + } + + /** + * Tests BlackHoleIps setter. + * + * @throws Exception + */ + @Test + public void testSetBlackHoleIps() throws Exception { + + config.setBalckholeIps(ImmutableSet.of(BLACKHOLE_IP_2)); + + Set blackHoleIps = config.blackholeIPs(); + assertThat(blackHoleIps.size(), is(1)); + assertTrue(blackHoleIps.contains(BLACKHOLE_IP_2)); + } + private class MockDelegate implements ConfigApplyDelegate { @Override public void onApply(Config config) { diff --git a/apps/segmentrouting/app/src/test/resources/app.json b/apps/segmentrouting/app/src/test/resources/app.json index dab6384fb3..2e59b0dbef 100644 --- a/apps/segmentrouting/app/src/test/resources/app.json +++ b/apps/segmentrouting/app/src/test/resources/app.json @@ -14,5 +14,8 @@ "suppressHostByProvider" : [ "org.onosproject.provider.host", "org.onosproject.netcfghost" + ], + "blackholeIps": [ + "10.0.0.0/8" ] } diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java index 04d581adcf..d834b4865b 100644 --- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java +++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java @@ -284,6 +284,15 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline return false; } + /** + * Determines whether this driver supports installing a clearDeferred action on table 30. + * + * @return true if required + */ + protected boolean supportsUnicastBlackHole() { + return true; + } + ////////////////////////////////////// // Flow Objectives ////////////////////////////////////// @@ -1462,6 +1471,15 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline tb.transition(ACL_TABLE); } + if (fwd.treatment() != null && fwd.treatment().clearedDeferred()) { + if (supportsUnicastBlackHole()) { + tb.wipeDeferred(); + } else { + log.warn("Clear Deferred is not supported Unicast Routing Table on device {}", deviceId); + return Collections.emptySet(); + } + } + FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() .fromApp(fwd.appId()) .withPriority(fwd.priority()) diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java index 7377a20647..13fe2b1e69 100644 --- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java +++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java @@ -65,7 +65,10 @@ import java.util.List; import static org.onlab.packet.MacAddress.NONE; import static org.onosproject.driver.extensions.Ofdpa3MplsType.VPWS; -import static org.onosproject.net.flow.criteria.Criterion.Type.*; +import static org.onosproject.net.flow.criteria.Criterion.Type.INNER_VLAN_VID; +import static org.onosproject.net.flow.criteria.Criterion.Type.IN_PORT; +import static org.onosproject.net.flow.criteria.Criterion.Type.TUNNEL_ID; +import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID; import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION; import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction; import static org.slf4j.LoggerFactory.getLogger; @@ -99,6 +102,11 @@ public class Ofdpa3Pipeline extends Ofdpa2Pipeline { return false; } + @Override + protected boolean supportsUnicastBlackHole() { + return true; + } + @Override protected void processFilter(FilteringObjective filteringObjective, boolean install, diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpa2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpa2Pipeline.java index 013b98e578..3aa88651ee 100644 --- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpa2Pipeline.java +++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/OvsOfdpa2Pipeline.java @@ -50,4 +50,9 @@ public class OvsOfdpa2Pipeline extends CpqdOfdpa2Pipeline { protected boolean supportPuntGroup() { return true; } + + @Override + protected boolean supportsUnicastBlackHole() { + return true; + } }