Committed by
Gerrit Code Review
CORD-348 multicast support in SegmentRouting and vRouter
In this submission:
* Setup/teardown multicast route according to SinkAdded/SinkRemoved event
- ingressVlan and egressVlan is configurable through network config
* Change behavior of OFDPA VLAN assignment
- Always use the VLAN in metadata if present
* Bugfix of writing immutable object
NOT in this submission (coming soon):
* Error handling (e.g. link/device failure recovery)
Change-Id: I9be11af04eb2d6456b865c7e59e96cc02370f846
Showing
17 changed files
with
540 additions
and
96 deletions
| ... | @@ -29,11 +29,13 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; | ... | @@ -29,11 +29,13 @@ import org.apache.felix.scr.annotations.ReferenceCardinality; |
| 29 | import org.onlab.packet.Ethernet; | 29 | import org.onlab.packet.Ethernet; |
| 30 | import org.onlab.packet.IpAddress; | 30 | import org.onlab.packet.IpAddress; |
| 31 | import org.onlab.packet.IpPrefix; | 31 | import org.onlab.packet.IpPrefix; |
| 32 | +import org.onlab.packet.MacAddress; | ||
| 32 | import org.onlab.packet.VlanId; | 33 | import org.onlab.packet.VlanId; |
| 33 | import org.onlab.util.Tools; | 34 | import org.onlab.util.Tools; |
| 34 | import org.onosproject.cfg.ComponentConfigService; | 35 | import org.onosproject.cfg.ComponentConfigService; |
| 35 | import org.onosproject.core.ApplicationId; | 36 | import org.onosproject.core.ApplicationId; |
| 36 | import org.onosproject.core.CoreService; | 37 | import org.onosproject.core.CoreService; |
| 38 | +import org.onosproject.incubator.net.config.basics.McastConfig; | ||
| 37 | import org.onosproject.incubator.net.intf.Interface; | 39 | import org.onosproject.incubator.net.intf.Interface; |
| 38 | import org.onosproject.incubator.net.intf.InterfaceEvent; | 40 | import org.onosproject.incubator.net.intf.InterfaceEvent; |
| 39 | import org.onosproject.incubator.net.intf.InterfaceListener; | 41 | import org.onosproject.incubator.net.intf.InterfaceListener; |
| ... | @@ -44,9 +46,12 @@ import org.onosproject.incubator.net.routing.RouteListener; | ... | @@ -44,9 +46,12 @@ import org.onosproject.incubator.net.routing.RouteListener; |
| 44 | import org.onosproject.incubator.net.routing.RouteService; | 46 | import org.onosproject.incubator.net.routing.RouteService; |
| 45 | import org.onosproject.net.ConnectPoint; | 47 | import org.onosproject.net.ConnectPoint; |
| 46 | import org.onosproject.net.DeviceId; | 48 | import org.onosproject.net.DeviceId; |
| 49 | +import org.onosproject.net.config.ConfigFactory; | ||
| 47 | import org.onosproject.net.config.NetworkConfigEvent; | 50 | import org.onosproject.net.config.NetworkConfigEvent; |
| 48 | import org.onosproject.net.config.NetworkConfigListener; | 51 | import org.onosproject.net.config.NetworkConfigListener; |
| 52 | +import org.onosproject.net.config.NetworkConfigRegistry; | ||
| 49 | import org.onosproject.net.config.NetworkConfigService; | 53 | import org.onosproject.net.config.NetworkConfigService; |
| 54 | +import org.onosproject.net.config.basics.SubjectFactories; | ||
| 50 | import org.onosproject.net.device.DeviceEvent; | 55 | import org.onosproject.net.device.DeviceEvent; |
| 51 | import org.onosproject.net.device.DeviceListener; | 56 | import org.onosproject.net.device.DeviceListener; |
| 52 | import org.onosproject.net.device.DeviceService; | 57 | import org.onosproject.net.device.DeviceService; |
| ... | @@ -102,6 +107,9 @@ public class SingleSwitchFibInstaller { | ... | @@ -102,6 +107,9 @@ public class SingleSwitchFibInstaller { |
| 102 | protected NetworkConfigService networkConfigService; | 107 | protected NetworkConfigService networkConfigService; |
| 103 | 108 | ||
| 104 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 109 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 110 | + protected NetworkConfigRegistry networkConfigRegistry; | ||
| 111 | + | ||
| 112 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 105 | protected ComponentConfigService componentConfigService; | 113 | protected ComponentConfigService componentConfigService; |
| 106 | 114 | ||
| 107 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 115 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| ... | @@ -123,6 +131,7 @@ public class SingleSwitchFibInstaller { | ... | @@ -123,6 +131,7 @@ public class SingleSwitchFibInstaller { |
| 123 | 131 | ||
| 124 | private List<String> interfaces; | 132 | private List<String> interfaces; |
| 125 | 133 | ||
| 134 | + private ApplicationId coreAppId; | ||
| 126 | private ApplicationId routerAppId; | 135 | private ApplicationId routerAppId; |
| 127 | 136 | ||
| 128 | // Reference count for how many times a next hop is used by a route | 137 | // Reference count for how many times a next hop is used by a route |
| ... | @@ -138,13 +147,25 @@ public class SingleSwitchFibInstaller { | ... | @@ -138,13 +147,25 @@ public class SingleSwitchFibInstaller { |
| 138 | private InternalInterfaceListener internalInterfaceList = new InternalInterfaceListener(); | 147 | private InternalInterfaceListener internalInterfaceList = new InternalInterfaceListener(); |
| 139 | private InternalRouteListener routeListener = new InternalRouteListener(); | 148 | private InternalRouteListener routeListener = new InternalRouteListener(); |
| 140 | 149 | ||
| 150 | + private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory = | ||
| 151 | + new ConfigFactory<ApplicationId, McastConfig>(SubjectFactories.APP_SUBJECT_FACTORY, | ||
| 152 | + McastConfig.class, "multicast") { | ||
| 153 | + @Override | ||
| 154 | + public McastConfig createConfig() { | ||
| 155 | + return new McastConfig(); | ||
| 156 | + } | ||
| 157 | + }; | ||
| 158 | + | ||
| 141 | @Activate | 159 | @Activate |
| 142 | protected void activate(ComponentContext context) { | 160 | protected void activate(ComponentContext context) { |
| 143 | componentConfigService.registerProperties(getClass()); | 161 | componentConfigService.registerProperties(getClass()); |
| 144 | modified(context); | 162 | modified(context); |
| 145 | 163 | ||
| 164 | + coreAppId = coreService.registerApplication(CoreService.CORE_APP_NAME); | ||
| 146 | routerAppId = coreService.registerApplication(RoutingService.ROUTER_APP_ID); | 165 | routerAppId = coreService.registerApplication(RoutingService.ROUTER_APP_ID); |
| 147 | 166 | ||
| 167 | + networkConfigRegistry.registerConfigFactory(mcastConfigFactory); | ||
| 168 | + | ||
| 148 | deviceListener = new InternalDeviceListener(); | 169 | deviceListener = new InternalDeviceListener(); |
| 149 | deviceService.addListener(deviceListener); | 170 | deviceService.addListener(deviceListener); |
| 150 | 171 | ||
| ... | @@ -368,6 +389,7 @@ public class SingleSwitchFibInstaller { | ... | @@ -368,6 +389,7 @@ public class SingleSwitchFibInstaller { |
| 368 | } | 389 | } |
| 369 | 390 | ||
| 370 | createFilteringObjective(install, intf); | 391 | createFilteringObjective(install, intf); |
| 392 | + createMcastFilteringObjective(install, intf); | ||
| 371 | } | 393 | } |
| 372 | } | 394 | } |
| 373 | 395 | ||
| ... | @@ -380,10 +402,14 @@ public class SingleSwitchFibInstaller { | ... | @@ -380,10 +402,14 @@ public class SingleSwitchFibInstaller { |
| 380 | } | 402 | } |
| 381 | 403 | ||
| 382 | createFilteringObjective(install, intf); | 404 | createFilteringObjective(install, intf); |
| 405 | + createMcastFilteringObjective(install, intf); | ||
| 383 | } | 406 | } |
| 384 | 407 | ||
| 385 | //create filtering objective for interface | 408 | //create filtering objective for interface |
| 386 | private void createFilteringObjective(boolean install, Interface intf) { | 409 | private void createFilteringObjective(boolean install, Interface intf) { |
| 410 | + VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ? | ||
| 411 | + VlanId.vlanId(ASSIGNED_VLAN) : | ||
| 412 | + egressVlan(); | ||
| 387 | 413 | ||
| 388 | FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); | 414 | FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); |
| 389 | // first add filter for the interface | 415 | // first add filter for the interface |
| ... | @@ -393,12 +419,12 @@ public class SingleSwitchFibInstaller { | ... | @@ -393,12 +419,12 @@ public class SingleSwitchFibInstaller { |
| 393 | fob.withPriority(PRIORITY_OFFSET); | 419 | fob.withPriority(PRIORITY_OFFSET); |
| 394 | if (intf.vlan() == VlanId.NONE) { | 420 | if (intf.vlan() == VlanId.NONE) { |
| 395 | TrafficTreatment tt = DefaultTrafficTreatment.builder() | 421 | TrafficTreatment tt = DefaultTrafficTreatment.builder() |
| 396 | - .pushVlan().setVlanId(VlanId.vlanId(ASSIGNED_VLAN)).build(); | 422 | + .pushVlan().setVlanId(assignedVlan).build(); |
| 397 | fob.withMeta(tt); | 423 | fob.withMeta(tt); |
| 398 | } | 424 | } |
| 399 | - | ||
| 400 | fob.permit().fromApp(routerAppId); | 425 | fob.permit().fromApp(routerAppId); |
| 401 | sendFilteringObjective(install, fob, intf); | 426 | sendFilteringObjective(install, fob, intf); |
| 427 | + | ||
| 402 | if (controlPlaneConnectPoint != null) { | 428 | if (controlPlaneConnectPoint != null) { |
| 403 | // then add the same mac/vlan filters for control-plane connect point | 429 | // then add the same mac/vlan filters for control-plane connect point |
| 404 | fob.withKey(Criteria.matchInPort(controlPlaneConnectPoint.port())); | 430 | fob.withKey(Criteria.matchInPort(controlPlaneConnectPoint.port())); |
| ... | @@ -406,6 +432,27 @@ public class SingleSwitchFibInstaller { | ... | @@ -406,6 +432,27 @@ public class SingleSwitchFibInstaller { |
| 406 | } | 432 | } |
| 407 | } | 433 | } |
| 408 | 434 | ||
| 435 | + //create filtering objective for multicast traffic | ||
| 436 | + private void createMcastFilteringObjective(boolean install, Interface intf) { | ||
| 437 | + VlanId assignedVlan = (egressVlan().equals(VlanId.NONE)) ? | ||
| 438 | + VlanId.vlanId(ASSIGNED_VLAN) : | ||
| 439 | + egressVlan(); | ||
| 440 | + | ||
| 441 | + FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); | ||
| 442 | + // first add filter for the interface | ||
| 443 | + fob.withKey(Criteria.matchInPort(intf.connectPoint().port())) | ||
| 444 | + .addCondition(Criteria.matchEthDstMasked(MacAddress.IPV4_MULTICAST, | ||
| 445 | + MacAddress.IPV4_MULTICAST_MASK)) | ||
| 446 | + .addCondition(Criteria.matchVlanId(ingressVlan())); | ||
| 447 | + fob.withPriority(PRIORITY_OFFSET); | ||
| 448 | + TrafficTreatment tt = DefaultTrafficTreatment.builder() | ||
| 449 | + .pushVlan().setVlanId(assignedVlan).build(); | ||
| 450 | + fob.withMeta(tt); | ||
| 451 | + | ||
| 452 | + fob.permit().fromApp(routerAppId); | ||
| 453 | + sendFilteringObjective(install, fob, intf); | ||
| 454 | + } | ||
| 455 | + | ||
| 409 | private void sendFilteringObjective(boolean install, FilteringObjective.Builder fob, | 456 | private void sendFilteringObjective(boolean install, FilteringObjective.Builder fob, |
| 410 | Interface intf) { | 457 | Interface intf) { |
| 411 | 458 | ||
| ... | @@ -419,6 +466,18 @@ public class SingleSwitchFibInstaller { | ... | @@ -419,6 +466,18 @@ public class SingleSwitchFibInstaller { |
| 419 | flowObjectiveService.filter(deviceId, filter); | 466 | flowObjectiveService.filter(deviceId, filter); |
| 420 | } | 467 | } |
| 421 | 468 | ||
| 469 | + private VlanId ingressVlan() { | ||
| 470 | + McastConfig mcastConfig = | ||
| 471 | + networkConfigService.getConfig(coreAppId, McastConfig.class); | ||
| 472 | + return (mcastConfig != null) ? mcastConfig.ingressVlan() : VlanId.NONE; | ||
| 473 | + } | ||
| 474 | + | ||
| 475 | + private VlanId egressVlan() { | ||
| 476 | + McastConfig mcastConfig = | ||
| 477 | + networkConfigService.getConfig(coreAppId, McastConfig.class); | ||
| 478 | + return (mcastConfig != null) ? mcastConfig.egressVlan() : VlanId.NONE; | ||
| 479 | + } | ||
| 480 | + | ||
| 422 | private class InternalRouteListener implements RouteListener { | 481 | private class InternalRouteListener implements RouteListener { |
| 423 | @Override | 482 | @Override |
| 424 | public void event(RouteEvent event) { | 483 | public void event(RouteEvent event) { |
| ... | @@ -490,7 +549,6 @@ public class SingleSwitchFibInstaller { | ... | @@ -490,7 +549,6 @@ public class SingleSwitchFibInstaller { |
| 490 | } | 549 | } |
| 491 | 550 | ||
| 492 | private class InternalInterfaceListener implements InterfaceListener { | 551 | private class InternalInterfaceListener implements InterfaceListener { |
| 493 | - | ||
| 494 | @Override | 552 | @Override |
| 495 | public void event(InterfaceEvent event) { | 553 | public void event(InterfaceEvent event) { |
| 496 | Interface intf = event.subject(); | 554 | Interface intf = event.subject(); | ... | ... |
| ... | @@ -40,6 +40,7 @@ import org.onosproject.incubator.net.routing.RouteServiceAdapter; | ... | @@ -40,6 +40,7 @@ import org.onosproject.incubator.net.routing.RouteServiceAdapter; |
| 40 | import org.onosproject.net.ConnectPoint; | 40 | import org.onosproject.net.ConnectPoint; |
| 41 | import org.onosproject.net.DeviceId; | 41 | import org.onosproject.net.DeviceId; |
| 42 | import org.onosproject.net.PortNumber; | 42 | import org.onosproject.net.PortNumber; |
| 43 | +import org.onosproject.net.config.NetworkConfigRegistry; | ||
| 43 | import org.onosproject.net.config.NetworkConfigService; | 44 | import org.onosproject.net.config.NetworkConfigService; |
| 44 | import org.onosproject.net.device.DeviceListener; | 45 | import org.onosproject.net.device.DeviceListener; |
| 45 | import org.onosproject.net.device.DeviceService; | 46 | import org.onosproject.net.device.DeviceService; |
| ... | @@ -105,6 +106,7 @@ public class SingleSwitchFibInstallerTest { | ... | @@ -105,6 +106,7 @@ public class SingleSwitchFibInstallerTest { |
| 105 | private final Set<Interface> interfaces = Sets.newHashSet(); | 106 | private final Set<Interface> interfaces = Sets.newHashSet(); |
| 106 | private InterfaceService interfaceService; | 107 | private InterfaceService interfaceService; |
| 107 | private NetworkConfigService networkConfigService; | 108 | private NetworkConfigService networkConfigService; |
| 109 | + private NetworkConfigRegistry networkConfigRegistry; | ||
| 108 | private FlowObjectiveService flowObjectiveService; | 110 | private FlowObjectiveService flowObjectiveService; |
| 109 | private DeviceService deviceService; | 111 | private DeviceService deviceService; |
| 110 | private static final ApplicationId APPID = TestApplicationId.create("foo"); | 112 | private static final ApplicationId APPID = TestApplicationId.create("foo"); |
| ... | @@ -128,13 +130,15 @@ public class SingleSwitchFibInstallerTest { | ... | @@ -128,13 +130,15 @@ public class SingleSwitchFibInstallerTest { |
| 128 | interfaceService = createMock(InterfaceService.class); | 130 | interfaceService = createMock(InterfaceService.class); |
| 129 | 131 | ||
| 130 | networkConfigService = createMock(NetworkConfigService.class); | 132 | networkConfigService = createMock(NetworkConfigService.class); |
| 133 | + networkConfigRegistry = createMock(NetworkConfigRegistry.class); | ||
| 131 | flowObjectiveService = createMock(FlowObjectiveService.class); | 134 | flowObjectiveService = createMock(FlowObjectiveService.class); |
| 132 | deviceService = new TestDeviceService(); | 135 | deviceService = new TestDeviceService(); |
| 133 | CoreService coreService = createNiceMock(CoreService.class); | 136 | CoreService coreService = createNiceMock(CoreService.class); |
| 134 | - expect(coreService.registerApplication(anyString())).andReturn(APPID); | 137 | + expect(coreService.registerApplication(anyString())).andReturn(APPID).anyTimes(); |
| 135 | replay(coreService); | 138 | replay(coreService); |
| 136 | 139 | ||
| 137 | sSfibInstaller.networkConfigService = networkConfigService; | 140 | sSfibInstaller.networkConfigService = networkConfigService; |
| 141 | + sSfibInstaller.networkConfigRegistry = networkConfigRegistry; | ||
| 138 | sSfibInstaller.interfaceService = interfaceService; | 142 | sSfibInstaller.interfaceService = interfaceService; |
| 139 | sSfibInstaller.flowObjectiveService = flowObjectiveService; | 143 | sSfibInstaller.flowObjectiveService = flowObjectiveService; |
| 140 | sSfibInstaller.coreService = coreService; | 144 | sSfibInstaller.coreService = coreService; | ... | ... |
| ... | @@ -3,9 +3,9 @@ COMPILE_DEPS = [ | ... | @@ -3,9 +3,9 @@ COMPILE_DEPS = [ |
| 3 | '//lib:org.apache.karaf.shell.console', | 3 | '//lib:org.apache.karaf.shell.console', |
| 4 | '//lib:javax.ws.rs-api', | 4 | '//lib:javax.ws.rs-api', |
| 5 | '//cli:onos-cli', | 5 | '//cli:onos-cli', |
| 6 | + '//core/store/serializers:onos-core-serializers', | ||
| 6 | '//incubator/api:onos-incubator-api', | 7 | '//incubator/api:onos-incubator-api', |
| 7 | '//utils/rest:onlab-rest', | 8 | '//utils/rest:onlab-rest', |
| 8 | - '//core/store/serializers:onos-core-serializers', | ||
| 9 | ] | 9 | ] |
| 10 | 10 | ||
| 11 | TEST_DEPS = [ | 11 | TEST_DEPS = [ | ... | ... |
| ... | @@ -51,7 +51,11 @@ | ... | @@ -51,7 +51,11 @@ |
| 51 | <artifactId>onos-cli</artifactId> | 51 | <artifactId>onos-cli</artifactId> |
| 52 | <version>${project.version}</version> | 52 | <version>${project.version}</version> |
| 53 | </dependency> | 53 | </dependency> |
| 54 | - | 54 | + <dependency> |
| 55 | + <groupId>org.onosproject</groupId> | ||
| 56 | + <artifactId>onos-core-serializers</artifactId> | ||
| 57 | + <version>${project.version}</version> | ||
| 58 | + </dependency> | ||
| 55 | <dependency> | 59 | <dependency> |
| 56 | <groupId>org.apache.karaf.shell</groupId> | 60 | <groupId>org.apache.karaf.shell</groupId> |
| 57 | <artifactId>org.apache.karaf.shell.console</artifactId> | 61 | <artifactId>org.apache.karaf.shell.console</artifactId> |
| ... | @@ -84,12 +88,10 @@ | ... | @@ -84,12 +88,10 @@ |
| 84 | <groupId>com.fasterxml.jackson.core</groupId> | 88 | <groupId>com.fasterxml.jackson.core</groupId> |
| 85 | <artifactId>jackson-databind</artifactId> | 89 | <artifactId>jackson-databind</artifactId> |
| 86 | </dependency> | 90 | </dependency> |
| 87 | - | ||
| 88 | <dependency> | 91 | <dependency> |
| 89 | <groupId>com.fasterxml.jackson.core</groupId> | 92 | <groupId>com.fasterxml.jackson.core</groupId> |
| 90 | <artifactId>jackson-annotations</artifactId> | 93 | <artifactId>jackson-annotations</artifactId> |
| 91 | </dependency> | 94 | </dependency> |
| 92 | - | ||
| 93 | <dependency> | 95 | <dependency> |
| 94 | <groupId>org.osgi</groupId> | 96 | <groupId>org.osgi</groupId> |
| 95 | <artifactId>org.osgi.compendium</artifactId> | 97 | <artifactId>org.osgi.compendium</artifactId> |
| ... | @@ -103,7 +105,6 @@ | ... | @@ -103,7 +105,6 @@ |
| 103 | <artifactId>onlab-junit</artifactId> | 105 | <artifactId>onlab-junit</artifactId> |
| 104 | <scope>test</scope> | 106 | <scope>test</scope> |
| 105 | </dependency> | 107 | </dependency> |
| 106 | - | ||
| 107 | <dependency> | 108 | <dependency> |
| 108 | <groupId>org.onosproject</groupId> | 109 | <groupId>org.onosproject</groupId> |
| 109 | <artifactId>onos-api</artifactId> | 110 | <artifactId>onos-api</artifactId> | ... | ... |
This diff is collapsed. Click to expand it.
| ... | @@ -73,8 +73,8 @@ public class NetworkConfigEventHandler { | ... | @@ -73,8 +73,8 @@ public class NetworkConfigEventHandler { |
| 73 | SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get(); | 73 | SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get(); |
| 74 | SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get(); | 74 | SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get(); |
| 75 | deviceService.getAvailableDevices().forEach(device -> { | 75 | deviceService.getAvailableDevices().forEach(device -> { |
| 76 | - Set<MacAddress> macAddresses = getMacAddresses(config); | 76 | + Set<MacAddress> macAddresses = new HashSet<>(getMacAddresses(config)); |
| 77 | - Set<MacAddress> prevMacAddresses = getMacAddresses(prevConfig); | 77 | + Set<MacAddress> prevMacAddresses = new HashSet<>(getMacAddresses(prevConfig)); |
| 78 | // Avoid removing and re-adding unchanged MAC addresses since | 78 | // Avoid removing and re-adding unchanged MAC addresses since |
| 79 | // FlowObjective does not guarantee the execution order. | 79 | // FlowObjective does not guarantee the execution order. |
| 80 | Set<MacAddress> sameMacAddresses = new HashSet<>(macAddresses); | 80 | Set<MacAddress> sameMacAddresses = new HashSet<>(macAddresses); | ... | ... |
| ... | @@ -33,6 +33,7 @@ import org.onosproject.cfg.ComponentConfigService; | ... | @@ -33,6 +33,7 @@ import org.onosproject.cfg.ComponentConfigService; |
| 33 | import org.onosproject.core.ApplicationId; | 33 | import org.onosproject.core.ApplicationId; |
| 34 | import org.onosproject.core.CoreService; | 34 | import org.onosproject.core.CoreService; |
| 35 | import org.onosproject.event.Event; | 35 | import org.onosproject.event.Event; |
| 36 | +import org.onosproject.incubator.net.config.basics.McastConfig; | ||
| 36 | import org.onosproject.mastership.MastershipService; | 37 | import org.onosproject.mastership.MastershipService; |
| 37 | import org.onosproject.net.ConnectPoint; | 38 | import org.onosproject.net.ConnectPoint; |
| 38 | import org.onosproject.net.Device; | 39 | import org.onosproject.net.Device; |
| ... | @@ -60,23 +61,27 @@ import org.onosproject.net.flowobjective.ObjectiveContext; | ... | @@ -60,23 +61,27 @@ import org.onosproject.net.flowobjective.ObjectiveContext; |
| 60 | import org.onosproject.net.flowobjective.ObjectiveError; | 61 | import org.onosproject.net.flowobjective.ObjectiveError; |
| 61 | import org.onosproject.net.host.HostEvent; | 62 | import org.onosproject.net.host.HostEvent; |
| 62 | import org.onosproject.net.host.HostListener; | 63 | import org.onosproject.net.host.HostListener; |
| 63 | -import org.onosproject.net.host.HostService; | 64 | +import org.onosproject.net.mcast.McastEvent; |
| 64 | -import org.onosproject.net.link.LinkEvent; | 65 | +import org.onosproject.net.mcast.McastListener; |
| 65 | -import org.onosproject.net.link.LinkListener; | 66 | +import org.onosproject.net.mcast.MulticastRouteService; |
| 66 | -import org.onosproject.net.link.LinkService; | ||
| 67 | -import org.onosproject.net.packet.InboundPacket; | ||
| 68 | -import org.onosproject.net.packet.PacketContext; | ||
| 69 | import org.onosproject.net.packet.PacketPriority; | 67 | import org.onosproject.net.packet.PacketPriority; |
| 70 | -import org.onosproject.net.packet.PacketProcessor; | 68 | +import org.onosproject.net.topology.TopologyService; |
| 71 | -import org.onosproject.net.packet.PacketService; | ||
| 72 | import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException; | 69 | import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException; |
| 73 | import org.onosproject.segmentrouting.config.DeviceConfiguration; | 70 | import org.onosproject.segmentrouting.config.DeviceConfiguration; |
| 74 | -import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig; | ||
| 75 | import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig; | 71 | import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig; |
| 72 | +import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig; | ||
| 76 | import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler; | 73 | import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler; |
| 77 | import org.onosproject.segmentrouting.grouphandler.NeighborSet; | 74 | import org.onosproject.segmentrouting.grouphandler.NeighborSet; |
| 78 | import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey; | 75 | import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey; |
| 79 | import org.onosproject.segmentrouting.grouphandler.PortNextObjectiveStoreKey; | 76 | import org.onosproject.segmentrouting.grouphandler.PortNextObjectiveStoreKey; |
| 77 | +import org.onosproject.net.host.HostService; | ||
| 78 | +import org.onosproject.net.link.LinkEvent; | ||
| 79 | +import org.onosproject.net.link.LinkListener; | ||
| 80 | +import org.onosproject.net.link.LinkService; | ||
| 81 | +import org.onosproject.net.packet.InboundPacket; | ||
| 82 | +import org.onosproject.net.packet.PacketContext; | ||
| 83 | +import org.onosproject.net.packet.PacketProcessor; | ||
| 84 | +import org.onosproject.net.packet.PacketService; | ||
| 80 | import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey; | 85 | import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey; |
| 81 | import org.onosproject.segmentrouting.grouphandler.XConnectNextObjectiveStoreKey; | 86 | import org.onosproject.segmentrouting.grouphandler.XConnectNextObjectiveStoreKey; |
| 82 | import org.onosproject.store.serializers.KryoNamespaces; | 87 | import org.onosproject.store.serializers.KryoNamespaces; |
| ... | @@ -143,6 +148,12 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -143,6 +148,12 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
| 143 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 148 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 144 | protected ComponentConfigService compCfgService; | 149 | protected ComponentConfigService compCfgService; |
| 145 | 150 | ||
| 151 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 152 | + protected MulticastRouteService multicastRouteService; | ||
| 153 | + | ||
| 154 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 155 | + protected TopologyService topologyService; | ||
| 156 | + | ||
| 146 | protected ArpHandler arpHandler = null; | 157 | protected ArpHandler arpHandler = null; |
| 147 | protected IcmpHandler icmpHandler = null; | 158 | protected IcmpHandler icmpHandler = null; |
| 148 | protected IpHandler ipHandler = null; | 159 | protected IpHandler ipHandler = null; |
| ... | @@ -157,8 +168,11 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -157,8 +168,11 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
| 157 | private InternalLinkListener linkListener = null; | 168 | private InternalLinkListener linkListener = null; |
| 158 | private InternalDeviceListener deviceListener = null; | 169 | private InternalDeviceListener deviceListener = null; |
| 159 | private NetworkConfigEventHandler netcfgHandler = null; | 170 | private NetworkConfigEventHandler netcfgHandler = null; |
| 171 | + private McastEventHandler mcastEventHandler = null; | ||
| 160 | private InternalEventHandler eventHandler = new InternalEventHandler(); | 172 | private InternalEventHandler eventHandler = new InternalEventHandler(); |
| 161 | private final InternalHostListener hostListener = new InternalHostListener(); | 173 | private final InternalHostListener hostListener = new InternalHostListener(); |
| 174 | + private final InternalConfigListener cfgListener = new InternalConfigListener(this); | ||
| 175 | + private final InternalMcastListener mcastListener = new InternalMcastListener(); | ||
| 162 | 176 | ||
| 163 | private ScheduledExecutorService executorService = Executors | 177 | private ScheduledExecutorService executorService = Executors |
| 164 | .newScheduledThreadPool(1); | 178 | .newScheduledThreadPool(1); |
| ... | @@ -196,29 +210,32 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -196,29 +210,32 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
| 196 | private EventuallyConsistentMap<String, Tunnel> tunnelStore = null; | 210 | private EventuallyConsistentMap<String, Tunnel> tunnelStore = null; |
| 197 | private EventuallyConsistentMap<String, Policy> policyStore = null; | 211 | private EventuallyConsistentMap<String, Policy> policyStore = null; |
| 198 | 212 | ||
| 199 | - private final InternalConfigListener cfgListener = | 213 | + private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> deviceConfigFactory = |
| 200 | - new InternalConfigListener(this); | ||
| 201 | - | ||
| 202 | - private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> cfgDeviceFactory = | ||
| 203 | new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY, | 214 | new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY, |
| 204 | - SegmentRoutingDeviceConfig.class, | 215 | + SegmentRoutingDeviceConfig.class, "segmentrouting") { |
| 205 | - "segmentrouting") { | ||
| 206 | @Override | 216 | @Override |
| 207 | public SegmentRoutingDeviceConfig createConfig() { | 217 | public SegmentRoutingDeviceConfig createConfig() { |
| 208 | return new SegmentRoutingDeviceConfig(); | 218 | return new SegmentRoutingDeviceConfig(); |
| 209 | } | 219 | } |
| 210 | }; | 220 | }; |
| 211 | - | 221 | + private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> appConfigFactory = |
| 212 | - private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> cfgAppFactory = | ||
| 213 | new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(SubjectFactories.APP_SUBJECT_FACTORY, | 222 | new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(SubjectFactories.APP_SUBJECT_FACTORY, |
| 214 | - SegmentRoutingAppConfig.class, | 223 | + SegmentRoutingAppConfig.class, "segmentrouting") { |
| 215 | - "segmentrouting") { | ||
| 216 | @Override | 224 | @Override |
| 217 | public SegmentRoutingAppConfig createConfig() { | 225 | public SegmentRoutingAppConfig createConfig() { |
| 218 | return new SegmentRoutingAppConfig(); | 226 | return new SegmentRoutingAppConfig(); |
| 219 | } | 227 | } |
| 220 | }; | 228 | }; |
| 221 | 229 | ||
| 230 | + private ConfigFactory<ApplicationId, McastConfig> mcastConfigFactory = | ||
| 231 | + new ConfigFactory<ApplicationId, McastConfig>(SubjectFactories.APP_SUBJECT_FACTORY, | ||
| 232 | + McastConfig.class, "multicast") { | ||
| 233 | + @Override | ||
| 234 | + public McastConfig createConfig() { | ||
| 235 | + return new McastConfig(); | ||
| 236 | + } | ||
| 237 | + }; | ||
| 238 | + | ||
| 222 | private Object threadSchedulerLock = new Object(); | 239 | private Object threadSchedulerLock = new Object(); |
| 223 | private static int numOfEventsQueued = 0; | 240 | private static int numOfEventsQueued = 0; |
| 224 | private static int numOfEventsExecuted = 0; | 241 | private static int numOfEventsExecuted = 0; |
| ... | @@ -312,14 +329,17 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -312,14 +329,17 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
| 312 | linkListener = new InternalLinkListener(); | 329 | linkListener = new InternalLinkListener(); |
| 313 | deviceListener = new InternalDeviceListener(); | 330 | deviceListener = new InternalDeviceListener(); |
| 314 | netcfgHandler = new NetworkConfigEventHandler(this); | 331 | netcfgHandler = new NetworkConfigEventHandler(this); |
| 332 | + mcastEventHandler = new McastEventHandler(this); | ||
| 315 | 333 | ||
| 316 | cfgService.addListener(cfgListener); | 334 | cfgService.addListener(cfgListener); |
| 317 | - cfgService.registerConfigFactory(cfgDeviceFactory); | 335 | + cfgService.registerConfigFactory(deviceConfigFactory); |
| 318 | - cfgService.registerConfigFactory(cfgAppFactory); | 336 | + cfgService.registerConfigFactory(appConfigFactory); |
| 337 | + cfgService.registerConfigFactory(mcastConfigFactory); | ||
| 319 | hostService.addListener(hostListener); | 338 | hostService.addListener(hostListener); |
| 320 | packetService.addProcessor(processor, PacketProcessor.director(2)); | 339 | packetService.addProcessor(processor, PacketProcessor.director(2)); |
| 321 | linkService.addListener(linkListener); | 340 | linkService.addListener(linkListener); |
| 322 | deviceService.addListener(deviceListener); | 341 | deviceService.addListener(deviceListener); |
| 342 | + multicastRouteService.addListener(mcastListener); | ||
| 323 | 343 | ||
| 324 | // Request ARP packet-in | 344 | // Request ARP packet-in |
| 325 | TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | 345 | TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); |
| ... | @@ -351,8 +371,9 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -351,8 +371,9 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
| 351 | @Deactivate | 371 | @Deactivate |
| 352 | protected void deactivate() { | 372 | protected void deactivate() { |
| 353 | cfgService.removeListener(cfgListener); | 373 | cfgService.removeListener(cfgListener); |
| 354 | - cfgService.unregisterConfigFactory(cfgDeviceFactory); | 374 | + cfgService.unregisterConfigFactory(deviceConfigFactory); |
| 355 | - cfgService.unregisterConfigFactory(cfgAppFactory); | 375 | + cfgService.unregisterConfigFactory(appConfigFactory); |
| 376 | + cfgService.unregisterConfigFactory(mcastConfigFactory); | ||
| 356 | 377 | ||
| 357 | // Withdraw ARP packet-in | 378 | // Withdraw ARP packet-in |
| 358 | TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | 379 | TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); |
| ... | @@ -362,12 +383,20 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -362,12 +383,20 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
| 362 | packetService.removeProcessor(processor); | 383 | packetService.removeProcessor(processor); |
| 363 | linkService.removeListener(linkListener); | 384 | linkService.removeListener(linkListener); |
| 364 | deviceService.removeListener(deviceListener); | 385 | deviceService.removeListener(deviceListener); |
| 386 | + multicastRouteService.removeListener(mcastListener); | ||
| 387 | + | ||
| 365 | processor = null; | 388 | processor = null; |
| 366 | linkListener = null; | 389 | linkListener = null; |
| 367 | - deviceService = null; | 390 | + deviceListener = null; |
| 368 | - | ||
| 369 | groupHandlerMap.clear(); | 391 | groupHandlerMap.clear(); |
| 370 | 392 | ||
| 393 | + nsNextObjStore.destroy(); | ||
| 394 | + subnetNextObjStore.destroy(); | ||
| 395 | + portNextObjStore.destroy(); | ||
| 396 | + xConnectNextObjStore.destroy(); | ||
| 397 | + tunnelStore.destroy(); | ||
| 398 | + policyStore.destroy(); | ||
| 399 | + subnetVidStore.destroy(); | ||
| 371 | log.info("Stopped"); | 400 | log.info("Stopped"); |
| 372 | } | 401 | } |
| 373 | 402 | ||
| ... | @@ -1186,6 +1215,27 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -1186,6 +1215,27 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
| 1186 | } | 1215 | } |
| 1187 | } | 1216 | } |
| 1188 | 1217 | ||
| 1218 | + private class InternalMcastListener implements McastListener { | ||
| 1219 | + @Override | ||
| 1220 | + public void event(McastEvent event) { | ||
| 1221 | + switch (event.type()) { | ||
| 1222 | + case SOURCE_ADDED: | ||
| 1223 | + mcastEventHandler.processSourceAdded(event); | ||
| 1224 | + break; | ||
| 1225 | + case SINK_ADDED: | ||
| 1226 | + mcastEventHandler.processSinkAdded(event); | ||
| 1227 | + break; | ||
| 1228 | + case SINK_REMOVED: | ||
| 1229 | + mcastEventHandler.processSinkRemoved(event); | ||
| 1230 | + break; | ||
| 1231 | + case ROUTE_ADDED: | ||
| 1232 | + case ROUTE_REMOVED: | ||
| 1233 | + default: | ||
| 1234 | + break; | ||
| 1235 | + } | ||
| 1236 | + } | ||
| 1237 | + } | ||
| 1238 | + | ||
| 1189 | private static class BridgingTableObjectiveContext implements ObjectiveContext { | 1239 | private static class BridgingTableObjectiveContext implements ObjectiveContext { |
| 1190 | final MacAddress mac; | 1240 | final MacAddress mac; |
| 1191 | final VlanId vlanId; | 1241 | final VlanId vlanId; | ... | ... |
| ... | @@ -496,12 +496,22 @@ public class DeviceConfiguration implements DeviceProperties { | ... | @@ -496,12 +496,22 @@ public class DeviceConfiguration implements DeviceProperties { |
| 496 | return srinfo != null && srinfo.adjacencySids.containsKey(sid); | 496 | return srinfo != null && srinfo.adjacencySids.containsKey(sid); |
| 497 | } | 497 | } |
| 498 | 498 | ||
| 499 | + /** | ||
| 500 | + * Gets connect points for which segment routing does not install subnet rules. | ||
| 501 | + * | ||
| 502 | + * @return set of connect points | ||
| 503 | + */ | ||
| 499 | public Set<ConnectPoint> suppressSubnet() { | 504 | public Set<ConnectPoint> suppressSubnet() { |
| 500 | SegmentRoutingAppConfig appConfig = | 505 | SegmentRoutingAppConfig appConfig = |
| 501 | cfgService.getConfig(appId, SegmentRoutingAppConfig.class); | 506 | cfgService.getConfig(appId, SegmentRoutingAppConfig.class); |
| 502 | return (appConfig != null) ? appConfig.suppressSubnet() : ImmutableSet.of(); | 507 | return (appConfig != null) ? appConfig.suppressSubnet() : ImmutableSet.of(); |
| 503 | } | 508 | } |
| 504 | 509 | ||
| 510 | + /** | ||
| 511 | + * Gets connect points for which segment routing does not install host rules. | ||
| 512 | + * | ||
| 513 | + * @return set of connect points | ||
| 514 | + */ | ||
| 505 | public Set<ConnectPoint> suppressHost() { | 515 | public Set<ConnectPoint> suppressHost() { |
| 506 | SegmentRoutingAppConfig appConfig = | 516 | SegmentRoutingAppConfig appConfig = |
| 507 | cfgService.getConfig(appId, SegmentRoutingAppConfig.class); | 517 | cfgService.getConfig(appId, SegmentRoutingAppConfig.class); | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2015-present Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.segmentrouting.grouphandler; | ||
| 18 | + | ||
| 19 | +import org.onlab.packet.IpAddress; | ||
| 20 | +import org.onosproject.net.DeviceId; | ||
| 21 | +import static com.google.common.base.MoreObjects.toStringHelper; | ||
| 22 | +import static com.google.common.base.Preconditions.checkArgument; | ||
| 23 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 24 | +import java.util.Objects; | ||
| 25 | + | ||
| 26 | +/** | ||
| 27 | + * Key of multicast next objective store. | ||
| 28 | + */ | ||
| 29 | +public class McastNextObjectiveStoreKey { | ||
| 30 | + private final IpAddress mcastIp; | ||
| 31 | + private final DeviceId deviceId; | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * Constructs the key of multicast next objective store. | ||
| 35 | + * | ||
| 36 | + * @param mcastIp multicast group IP address | ||
| 37 | + * @param deviceId device ID | ||
| 38 | + */ | ||
| 39 | + public McastNextObjectiveStoreKey(IpAddress mcastIp, DeviceId deviceId) { | ||
| 40 | + checkNotNull(mcastIp, "mcastIp cannot be null"); | ||
| 41 | + checkNotNull(deviceId, "deviceId cannot be null"); | ||
| 42 | + checkArgument(mcastIp.isMulticast(), "mcastIp must be a multicast address"); | ||
| 43 | + this.mcastIp = mcastIp; | ||
| 44 | + this.deviceId = deviceId; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + /** | ||
| 48 | + * Returns the multicast IP address of this key. | ||
| 49 | + * | ||
| 50 | + * @return multicast IP | ||
| 51 | + */ | ||
| 52 | + public IpAddress mcastIp() { | ||
| 53 | + return this.mcastIp; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * Returns the device ID of this key. | ||
| 58 | + * | ||
| 59 | + * @return device ID | ||
| 60 | + */ | ||
| 61 | + public DeviceId deviceId() { | ||
| 62 | + return this.deviceId; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + @Override | ||
| 66 | + public boolean equals(Object o) { | ||
| 67 | + if (this == o) { | ||
| 68 | + return true; | ||
| 69 | + } | ||
| 70 | + if (!(o instanceof McastNextObjectiveStoreKey)) { | ||
| 71 | + return false; | ||
| 72 | + } | ||
| 73 | + McastNextObjectiveStoreKey that = | ||
| 74 | + (McastNextObjectiveStoreKey) o; | ||
| 75 | + return (Objects.equals(this.mcastIp, that.mcastIp) && | ||
| 76 | + Objects.equals(this.deviceId, that.deviceId)); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + @Override | ||
| 80 | + public int hashCode() { | ||
| 81 | + return Objects.hash(mcastIp, deviceId); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + @Override | ||
| 85 | + public String toString() { | ||
| 86 | + return toStringHelper(getClass()) | ||
| 87 | + .add("mcastIp", mcastIp) | ||
| 88 | + .add("deviceId", deviceId) | ||
| 89 | + .toString(); | ||
| 90 | + } | ||
| 91 | +} |
| ... | @@ -22,6 +22,7 @@ import java.util.Collections; | ... | @@ -22,6 +22,7 @@ import java.util.Collections; |
| 22 | import java.util.Optional; | 22 | import java.util.Optional; |
| 23 | import java.util.Set; | 23 | import java.util.Set; |
| 24 | 24 | ||
| 25 | +import static com.google.common.base.MoreObjects.toStringHelper; | ||
| 25 | import static com.google.common.base.Preconditions.checkNotNull; | 26 | import static com.google.common.base.Preconditions.checkNotNull; |
| 26 | 27 | ||
| 27 | /** | 28 | /** |
| ... | @@ -102,4 +103,13 @@ public final class McastRouteInfo { | ... | @@ -102,4 +103,13 @@ public final class McastRouteInfo { |
| 102 | return sinks; | 103 | return sinks; |
| 103 | } | 104 | } |
| 104 | 105 | ||
| 106 | + @Override | ||
| 107 | + public String toString() { | ||
| 108 | + return toStringHelper(this) | ||
| 109 | + .add("route", route()) | ||
| 110 | + .add("sink", sink()) | ||
| 111 | + .add("source", source()) | ||
| 112 | + .add("sinks", sinks()) | ||
| 113 | + .toString(); | ||
| 114 | + } | ||
| 105 | } | 115 | } | ... | ... |
| ... | @@ -22,8 +22,6 @@ import java.util.Collection; | ... | @@ -22,8 +22,6 @@ import java.util.Collection; |
| 22 | import java.util.Collections; | 22 | import java.util.Collections; |
| 23 | import java.util.Deque; | 23 | import java.util.Deque; |
| 24 | import java.util.List; | 24 | import java.util.List; |
| 25 | -import java.util.Set; | ||
| 26 | -import java.util.concurrent.ConcurrentHashMap; | ||
| 27 | 25 | ||
| 28 | import com.google.common.collect.ImmutableList; | 26 | import com.google.common.collect.ImmutableList; |
| 29 | import com.google.common.collect.ImmutableSet; | 27 | import com.google.common.collect.ImmutableSet; |
| ... | @@ -279,17 +277,6 @@ public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline { | ... | @@ -279,17 +277,6 @@ public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline { |
| 279 | } | 277 | } |
| 280 | 278 | ||
| 281 | for (PortNumber pnum : portnums) { | 279 | for (PortNumber pnum : portnums) { |
| 282 | - // update storage | ||
| 283 | - groupHandler.port2Vlan.put(pnum, storeVlan); | ||
| 284 | - Set<PortNumber> vlanPorts = groupHandler.vlan2Port.get(storeVlan); | ||
| 285 | - if (vlanPorts == null) { | ||
| 286 | - vlanPorts = Collections.newSetFromMap( | ||
| 287 | - new ConcurrentHashMap<PortNumber, Boolean>()); | ||
| 288 | - vlanPorts.add(pnum); | ||
| 289 | - groupHandler.vlan2Port.put(storeVlan, vlanPorts); | ||
| 290 | - } else { | ||
| 291 | - vlanPorts.add(pnum); | ||
| 292 | - } | ||
| 293 | // create rest of flowrule | 280 | // create rest of flowrule |
| 294 | selector.matchInPort(pnum); | 281 | selector.matchInPort(pnum); |
| 295 | FlowRule rule = DefaultFlowRule.builder() | 282 | FlowRule rule = DefaultFlowRule.builder() | ... | ... |
| ... | @@ -65,7 +65,6 @@ import java.util.Collection; | ... | @@ -65,7 +65,6 @@ import java.util.Collection; |
| 65 | import java.util.Collections; | 65 | import java.util.Collections; |
| 66 | import java.util.Deque; | 66 | import java.util.Deque; |
| 67 | import java.util.List; | 67 | import java.util.List; |
| 68 | -import java.util.Map; | ||
| 69 | import java.util.Objects; | 68 | import java.util.Objects; |
| 70 | import java.util.Set; | 69 | import java.util.Set; |
| 71 | import java.util.concurrent.ConcurrentHashMap; | 70 | import java.util.concurrent.ConcurrentHashMap; |
| ... | @@ -123,10 +122,6 @@ public class Ofdpa2GroupHandler { | ... | @@ -123,10 +122,6 @@ public class Ofdpa2GroupHandler { |
| 123 | // index number for group creation | 122 | // index number for group creation |
| 124 | private AtomicCounter nextIndex; | 123 | private AtomicCounter nextIndex; |
| 125 | 124 | ||
| 126 | - // local stores for port-vlan mapping | ||
| 127 | - protected Map<PortNumber, VlanId> port2Vlan = new ConcurrentHashMap<>(); | ||
| 128 | - protected Map<VlanId, Set<PortNumber>> vlan2Port = new ConcurrentHashMap<>(); | ||
| 129 | - | ||
| 130 | // local store for pending bucketAdds - by design there can only be one | 125 | // local store for pending bucketAdds - by design there can only be one |
| 131 | // pending bucket for a group | 126 | // pending bucket for a group |
| 132 | protected ConcurrentHashMap<Integer, NextObjective> pendingBuckets = new ConcurrentHashMap<>(); | 127 | protected ConcurrentHashMap<Integer, NextObjective> pendingBuckets = new ConcurrentHashMap<>(); | ... | ... |
| ... | @@ -313,31 +313,22 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -313,31 +313,22 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
| 313 | } | 313 | } |
| 314 | 314 | ||
| 315 | VlanId assignedVlan = null; | 315 | VlanId assignedVlan = null; |
| 316 | - // For VLAN cross-connect packets, use the configured VLAN | ||
| 317 | if (vidCriterion != null) { | 316 | if (vidCriterion != null) { |
| 318 | - if (vidCriterion.vlanId() != VlanId.NONE) { | 317 | + // Use the VLAN in metadata whenever a metadata is provided |
| 318 | + if (filt.meta() != null) { | ||
| 319 | + assignedVlan = readVlanFromTreatment(filt.meta()); | ||
| 320 | + // Use the VLAN in criterion if metadata is not present and the traffic is tagged | ||
| 321 | + } else if (!vidCriterion.vlanId().equals(VlanId.NONE)) { | ||
| 319 | assignedVlan = vidCriterion.vlanId(); | 322 | assignedVlan = vidCriterion.vlanId(); |
| 323 | + } | ||
| 320 | 324 | ||
| 321 | - // For untagged packets, assign a VLAN ID | 325 | + if (assignedVlan == null) { |
| 322 | - } else { | 326 | + log.error("Driver fails to extract VLAN information. " |
| 323 | - if (filt.meta() == null) { | 327 | + + "Not proccessing VLAN filters on device {}.", deviceId); |
| 324 | - log.error("Missing metadata in filtering objective required " + | 328 | + log.debug("VLAN ID in criterion={}, metadata={}", |
| 325 | - "for vlan assignment in dev {}", deviceId); | 329 | + readVlanFromTreatment(filt.meta()), vidCriterion.vlanId()); |
| 326 | - fail(filt, ObjectiveError.BADPARAMS); | 330 | + fail(filt, ObjectiveError.BADPARAMS); |
| 327 | - return; | 331 | + return; |
| 328 | - } | ||
| 329 | - for (Instruction i : filt.meta().allInstructions()) { | ||
| 330 | - if (i instanceof ModVlanIdInstruction) { | ||
| 331 | - assignedVlan = ((ModVlanIdInstruction) i).vlanId(); | ||
| 332 | - } | ||
| 333 | - } | ||
| 334 | - if (assignedVlan == null) { | ||
| 335 | - log.error("Driver requires an assigned vlan-id to tag incoming " | ||
| 336 | - + "untagged packets. Not processing vlan filters on " | ||
| 337 | - + "device {}", deviceId); | ||
| 338 | - fail(filt, ObjectiveError.BADPARAMS); | ||
| 339 | - return; | ||
| 340 | - } | ||
| 341 | } | 332 | } |
| 342 | } | 333 | } |
| 343 | 334 | ||
| ... | @@ -457,22 +448,14 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -457,22 +448,14 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
| 457 | TrafficSelector.Builder preSelector = null; | 448 | TrafficSelector.Builder preSelector = null; |
| 458 | TrafficTreatment.Builder preTreatment = null; | 449 | TrafficTreatment.Builder preTreatment = null; |
| 459 | 450 | ||
| 460 | - | ||
| 461 | treatment.transition(TMAC_TABLE); | 451 | treatment.transition(TMAC_TABLE); |
| 462 | 452 | ||
| 463 | - VlanId storeVlan = null; | ||
| 464 | if (vidCriterion.vlanId() == VlanId.NONE) { | 453 | if (vidCriterion.vlanId() == VlanId.NONE) { |
| 465 | // untagged packets are assigned vlans | 454 | // untagged packets are assigned vlans |
| 466 | OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(VlanId.NONE); | 455 | OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(VlanId.NONE); |
| 467 | selector.extension(ofdpaMatchVlanVid, deviceId); | 456 | selector.extension(ofdpaMatchVlanVid, deviceId); |
| 468 | OfdpaSetVlanVid ofdpaSetVlanVid = new OfdpaSetVlanVid(assignedVlan); | 457 | OfdpaSetVlanVid ofdpaSetVlanVid = new OfdpaSetVlanVid(assignedVlan); |
| 469 | treatment.extension(ofdpaSetVlanVid, deviceId); | 458 | treatment.extension(ofdpaSetVlanVid, deviceId); |
| 470 | - // ofdpa requires an additional vlan match rule for the assigned vlan | ||
| 471 | - // and it does not require the push when setting the assigned vlan. | ||
| 472 | - // It also requires the extra rule to be sent to the switch before we | ||
| 473 | - // send the untagged match rule. | ||
| 474 | - // None of this in compliance with OF standard. | ||
| 475 | - storeVlan = assignedVlan; | ||
| 476 | 459 | ||
| 477 | preSelector = DefaultTrafficSelector.builder(); | 460 | preSelector = DefaultTrafficSelector.builder(); |
| 478 | OfdpaMatchVlanVid preOfdpaMatchVlanVid = new OfdpaMatchVlanVid(assignedVlan); | 461 | OfdpaMatchVlanVid preOfdpaMatchVlanVid = new OfdpaMatchVlanVid(assignedVlan); |
| ... | @@ -482,7 +465,11 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -482,7 +465,11 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
| 482 | } else { | 465 | } else { |
| 483 | OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(vidCriterion.vlanId()); | 466 | OfdpaMatchVlanVid ofdpaMatchVlanVid = new OfdpaMatchVlanVid(vidCriterion.vlanId()); |
| 484 | selector.extension(ofdpaMatchVlanVid, deviceId); | 467 | selector.extension(ofdpaMatchVlanVid, deviceId); |
| 485 | - storeVlan = vidCriterion.vlanId(); | 468 | + |
| 469 | + if (!assignedVlan.equals(vidCriterion.vlanId())) { | ||
| 470 | + OfdpaSetVlanVid ofdpaSetVlanVid = new OfdpaSetVlanVid(assignedVlan); | ||
| 471 | + treatment.extension(ofdpaSetVlanVid, deviceId); | ||
| 472 | + } | ||
| 486 | } | 473 | } |
| 487 | 474 | ||
| 488 | // ofdpa cannot match on ALL portnumber, so we need to use separate | 475 | // ofdpa cannot match on ALL portnumber, so we need to use separate |
| ... | @@ -499,17 +486,6 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -499,17 +486,6 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
| 499 | } | 486 | } |
| 500 | 487 | ||
| 501 | for (PortNumber pnum : portnums) { | 488 | for (PortNumber pnum : portnums) { |
| 502 | - // update storage | ||
| 503 | - groupHandler.port2Vlan.put(pnum, storeVlan); | ||
| 504 | - Set<PortNumber> vlanPorts = groupHandler.vlan2Port.get(storeVlan); | ||
| 505 | - if (vlanPorts == null) { | ||
| 506 | - vlanPorts = Collections.newSetFromMap( | ||
| 507 | - new ConcurrentHashMap<PortNumber, Boolean>()); | ||
| 508 | - vlanPorts.add(pnum); | ||
| 509 | - groupHandler.vlan2Port.put(storeVlan, vlanPorts); | ||
| 510 | - } else { | ||
| 511 | - vlanPorts.add(pnum); | ||
| 512 | - } | ||
| 513 | // create rest of flowrule | 489 | // create rest of flowrule |
| 514 | selector.matchInPort(pnum); | 490 | selector.matchInPort(pnum); |
| 515 | FlowRule rule = DefaultFlowRule.builder() | 491 | FlowRule rule = DefaultFlowRule.builder() |
| ... | @@ -1112,4 +1088,13 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -1112,4 +1088,13 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline |
| 1112 | Criterion criterion = selector.getCriterion(Criterion.Type.IPV4_DST); | 1088 | Criterion criterion = selector.getCriterion(Criterion.Type.IPV4_DST); |
| 1113 | return (criterion == null) ? null : ((IPCriterion) criterion).ip(); | 1089 | return (criterion == null) ? null : ((IPCriterion) criterion).ip(); |
| 1114 | } | 1090 | } |
| 1091 | + | ||
| 1092 | + private static VlanId readVlanFromTreatment(TrafficTreatment treatment) { | ||
| 1093 | + for (Instruction i : treatment.allInstructions()) { | ||
| 1094 | + if (i instanceof ModVlanIdInstruction) { | ||
| 1095 | + return ((ModVlanIdInstruction) i).vlanId(); | ||
| 1096 | + } | ||
| 1097 | + } | ||
| 1098 | + return null; | ||
| 1099 | + } | ||
| 1115 | } | 1100 | } | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2016-present Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.incubator.net.config.basics; | ||
| 18 | + | ||
| 19 | +import com.google.common.annotations.Beta; | ||
| 20 | +import org.onlab.packet.VlanId; | ||
| 21 | +import org.onosproject.core.ApplicationId; | ||
| 22 | +import org.onosproject.net.config.Config; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * Configuration for multicast. | ||
| 26 | + */ | ||
| 27 | +@Beta | ||
| 28 | +public class McastConfig extends Config<ApplicationId> { | ||
| 29 | + private static final String INGRESS_VLAN = "ingressVlan"; | ||
| 30 | + private static final String EGRESS_VLAN = "egressVlan"; | ||
| 31 | + | ||
| 32 | + @Override | ||
| 33 | + public boolean isValid() { | ||
| 34 | + return hasOnlyFields(INGRESS_VLAN, EGRESS_VLAN) && | ||
| 35 | + ingressVlan() != null && egressVlan() != null; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * Gets ingress VLAN of multicast traffic. | ||
| 40 | + * | ||
| 41 | + * @return Ingress VLAN ID | ||
| 42 | + */ | ||
| 43 | + public VlanId ingressVlan() { | ||
| 44 | + if (!object.has(INGRESS_VLAN)) { | ||
| 45 | + return VlanId.NONE; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + try { | ||
| 49 | + return VlanId.vlanId(object.path(INGRESS_VLAN).asText()); | ||
| 50 | + } catch (IllegalArgumentException e) { | ||
| 51 | + return null; | ||
| 52 | + } | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + /** | ||
| 56 | + * Sets ingress VLAN of multicast traffic. | ||
| 57 | + * | ||
| 58 | + * @param vlanId Ingress VLAN ID | ||
| 59 | + * @return this {@link McastConfig} | ||
| 60 | + */ | ||
| 61 | + public McastConfig setIngressVlan(VlanId vlanId) { | ||
| 62 | + if (vlanId == null) { | ||
| 63 | + object.remove(INGRESS_VLAN); | ||
| 64 | + } else { | ||
| 65 | + object.put(INGRESS_VLAN, vlanId.toString()); | ||
| 66 | + } | ||
| 67 | + return this; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + /** | ||
| 71 | + * Gets egress VLAN of multicast traffic. | ||
| 72 | + * | ||
| 73 | + * @return Egress VLAN ID | ||
| 74 | + */ | ||
| 75 | + public VlanId egressVlan() { | ||
| 76 | + if (!object.has(EGRESS_VLAN)) { | ||
| 77 | + return VlanId.NONE; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + try { | ||
| 81 | + return VlanId.vlanId(object.path(EGRESS_VLAN).asText()); | ||
| 82 | + } catch (IllegalArgumentException e) { | ||
| 83 | + return null; | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + /** | ||
| 88 | + * Sets egress VLAN of multicast traffic. | ||
| 89 | + * | ||
| 90 | + * @param vlanId Egress VLAN ID | ||
| 91 | + * @return this {@link McastConfig} | ||
| 92 | + */ | ||
| 93 | + public McastConfig setEgressVlan(VlanId vlanId) { | ||
| 94 | + if (vlanId == null) { | ||
| 95 | + object.remove(EGRESS_VLAN); | ||
| 96 | + } else { | ||
| 97 | + object.put(EGRESS_VLAN, vlanId.toString()); | ||
| 98 | + } | ||
| 99 | + return this; | ||
| 100 | + } | ||
| 101 | +} |
incubator/api/src/test/java/org/onosproject/incubator/net/config/basics/McastConfigTest.java
0 → 100644
| 1 | +/* | ||
| 2 | + * Copyright 2016-present Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | + | ||
| 17 | +package org.onosproject.incubator.net.config.basics; | ||
| 18 | + | ||
| 19 | +import com.fasterxml.jackson.databind.JsonNode; | ||
| 20 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
| 21 | +import com.google.common.annotations.Beta; | ||
| 22 | +import org.junit.Before; | ||
| 23 | +import org.junit.Test; | ||
| 24 | +import org.onlab.packet.VlanId; | ||
| 25 | +import org.onosproject.TestApplicationId; | ||
| 26 | +import org.onosproject.core.ApplicationId; | ||
| 27 | +import org.onosproject.core.CoreService; | ||
| 28 | +import org.onosproject.net.config.Config; | ||
| 29 | +import org.onosproject.net.config.ConfigApplyDelegate; | ||
| 30 | + | ||
| 31 | +import java.io.InputStream; | ||
| 32 | + | ||
| 33 | +import static org.hamcrest.Matchers.is; | ||
| 34 | +import static org.junit.Assert.*; | ||
| 35 | + | ||
| 36 | +/** | ||
| 37 | + * Tests for class {@link McastConfig}. | ||
| 38 | + */ | ||
| 39 | +@Beta | ||
| 40 | +public class McastConfigTest { | ||
| 41 | + private static final TestApplicationId APP_ID = | ||
| 42 | + new TestApplicationId(CoreService.CORE_APP_NAME); | ||
| 43 | + private McastConfig config; | ||
| 44 | + private McastConfig invalidConfig; | ||
| 45 | + | ||
| 46 | + private static final VlanId INGRESS_VLAN_1 = VlanId.NONE; | ||
| 47 | + private static final VlanId EGRESS_VLAN_1 = VlanId.NONE; | ||
| 48 | + private static final VlanId INGRESS_VLAN_2 = VlanId.vlanId((short) 100); | ||
| 49 | + private static final VlanId EGRESS_VLAN_2 = VlanId.vlanId((short) 100); | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * Initialize test related variables. | ||
| 53 | + * | ||
| 54 | + * @throws Exception | ||
| 55 | + */ | ||
| 56 | + @Before | ||
| 57 | + public void setUp() throws Exception { | ||
| 58 | + InputStream jsonStream = McastConfigTest.class | ||
| 59 | + .getResourceAsStream("/mcast-config.json"); | ||
| 60 | + InputStream invalidJsonStream = McastConfigTest.class | ||
| 61 | + .getResourceAsStream("/mcast-config-invalid.json"); | ||
| 62 | + | ||
| 63 | + ApplicationId subject = APP_ID; | ||
| 64 | + String key = CoreService.CORE_APP_NAME; | ||
| 65 | + ObjectMapper mapper = new ObjectMapper(); | ||
| 66 | + JsonNode jsonNode = mapper.readTree(jsonStream); | ||
| 67 | + JsonNode invalidJsonNode = mapper.readTree(invalidJsonStream); | ||
| 68 | + ConfigApplyDelegate delegate = new MockDelegate(); | ||
| 69 | + | ||
| 70 | + config = new McastConfig(); | ||
| 71 | + config.init(subject, key, jsonNode, mapper, delegate); | ||
| 72 | + invalidConfig = new McastConfig(); | ||
| 73 | + invalidConfig.init(subject, key, invalidJsonNode, mapper, delegate); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + /** | ||
| 77 | + * Tests config validity. | ||
| 78 | + * | ||
| 79 | + * @throws Exception | ||
| 80 | + */ | ||
| 81 | + @Test | ||
| 82 | + public void isValid() throws Exception { | ||
| 83 | + assertTrue(config.isValid()); | ||
| 84 | + assertFalse(invalidConfig.isValid()); | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + /** | ||
| 88 | + * Tests ingress VLAN getter. | ||
| 89 | + * | ||
| 90 | + * @throws Exception | ||
| 91 | + */ | ||
| 92 | + @Test | ||
| 93 | + public void ingressVlan() throws Exception { | ||
| 94 | + VlanId ingressVlan = config.ingressVlan(); | ||
| 95 | + assertNotNull("ingressVlan should not be null", ingressVlan); | ||
| 96 | + assertThat(ingressVlan, is(INGRESS_VLAN_1)); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + /** | ||
| 100 | + * Tests ingress VLAN setter. | ||
| 101 | + * | ||
| 102 | + * @throws Exception | ||
| 103 | + */ | ||
| 104 | + @Test | ||
| 105 | + public void setIngressVlan() throws Exception { | ||
| 106 | + config.setIngressVlan(INGRESS_VLAN_2); | ||
| 107 | + | ||
| 108 | + VlanId ingressVlan = config.ingressVlan(); | ||
| 109 | + assertNotNull("ingressVlan should not be null", ingressVlan); | ||
| 110 | + assertThat(ingressVlan, is(INGRESS_VLAN_2)); | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + /** | ||
| 114 | + * Tests egress VLAN getter. | ||
| 115 | + * | ||
| 116 | + * @throws Exception | ||
| 117 | + */ | ||
| 118 | + @Test | ||
| 119 | + public void egressVlan() throws Exception { | ||
| 120 | + VlanId egressVlan = config.egressVlan(); | ||
| 121 | + assertNotNull("egressVlan should not be null", egressVlan); | ||
| 122 | + assertThat(egressVlan, is(EGRESS_VLAN_1)); | ||
| 123 | + } | ||
| 124 | + | ||
| 125 | + /** | ||
| 126 | + * Tests egress VLAN setter. | ||
| 127 | + * | ||
| 128 | + * @throws Exception | ||
| 129 | + */ | ||
| 130 | + @Test | ||
| 131 | + public void setEgressVlan() throws Exception { | ||
| 132 | + config.setEgressVlan(EGRESS_VLAN_2); | ||
| 133 | + | ||
| 134 | + VlanId egressVlan = config.egressVlan(); | ||
| 135 | + assertNotNull("egressVlan should not be null", egressVlan); | ||
| 136 | + assertThat(egressVlan, is(EGRESS_VLAN_2)); | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + private class MockDelegate implements ConfigApplyDelegate { | ||
| 140 | + @Override | ||
| 141 | + public void onApply(Config config) { | ||
| 142 | + } | ||
| 143 | + } | ||
| 144 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or login to post a comment