CORD-61 Dynamic XConnect support
- Add new XConnectConfig with unit test - Gather XConnect features into XConnectHandler - Introduce ObjectiveError.Type.GROUPREMOVALFAILED - Rename - NetworkConfigEventHandler -> AppConfigHandler - XConnectNextObjectiveStoreKey -> XConnectStoreKey - Test json file - Refactor Change-Id: I8ca3176ed976c71ce9e28b7f3722ce80d49c816f
Showing
21 changed files
with
350 additions
and
243 deletions
... | @@ -35,29 +35,29 @@ import java.util.HashSet; | ... | @@ -35,29 +35,29 @@ import java.util.HashSet; |
35 | import java.util.Set; | 35 | import java.util.Set; |
36 | 36 | ||
37 | /** | 37 | /** |
38 | - * Handles network config events. | 38 | + * Handles Segment Routing app config events. |
39 | */ | 39 | */ |
40 | -public class NetworkConfigEventHandler { | 40 | +public class AppConfigHandler { |
41 | - private static final Logger log = LoggerFactory.getLogger(NetworkConfigEventHandler.class); | 41 | + private static final Logger log = LoggerFactory.getLogger(AppConfigHandler.class); |
42 | private final SegmentRoutingManager srManager; | 42 | private final SegmentRoutingManager srManager; |
43 | private final DeviceService deviceService; | 43 | private final DeviceService deviceService; |
44 | 44 | ||
45 | /** | 45 | /** |
46 | - * Constructs Network Config Event Handler. | 46 | + * Constructs Segment Routing App Config Handler. |
47 | * | 47 | * |
48 | * @param srManager instance of {@link SegmentRoutingManager} | 48 | * @param srManager instance of {@link SegmentRoutingManager} |
49 | */ | 49 | */ |
50 | - public NetworkConfigEventHandler(SegmentRoutingManager srManager) { | 50 | + public AppConfigHandler(SegmentRoutingManager srManager) { |
51 | this.srManager = srManager; | 51 | this.srManager = srManager; |
52 | this.deviceService = srManager.deviceService; | 52 | this.deviceService = srManager.deviceService; |
53 | } | 53 | } |
54 | 54 | ||
55 | /** | 55 | /** |
56 | - * Processes vRouter config added event. | 56 | + * Processes Segment Routing App Config added event. |
57 | * | 57 | * |
58 | * @param event network config added event | 58 | * @param event network config added event |
59 | */ | 59 | */ |
60 | - protected void processVRouterConfigAdded(NetworkConfigEvent event) { | 60 | + protected void processAppConfigAdded(NetworkConfigEvent event) { |
61 | log.info("Processing vRouter CONFIG_ADDED"); | 61 | log.info("Processing vRouter CONFIG_ADDED"); |
62 | SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get(); | 62 | SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get(); |
63 | deviceService.getAvailableDevices().forEach(device -> { | 63 | deviceService.getAvailableDevices().forEach(device -> { |
... | @@ -66,11 +66,11 @@ public class NetworkConfigEventHandler { | ... | @@ -66,11 +66,11 @@ public class NetworkConfigEventHandler { |
66 | } | 66 | } |
67 | 67 | ||
68 | /** | 68 | /** |
69 | - * Processes vRouter config updated event. | 69 | + * Processes Segment Routing App Config updated event. |
70 | * | 70 | * |
71 | * @param event network config updated event | 71 | * @param event network config updated event |
72 | */ | 72 | */ |
73 | - protected void processVRouterConfigUpdated(NetworkConfigEvent event) { | 73 | + protected void processAppConfigUpdated(NetworkConfigEvent event) { |
74 | log.info("Processing vRouter CONFIG_UPDATED"); | 74 | log.info("Processing vRouter CONFIG_UPDATED"); |
75 | SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get(); | 75 | SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get(); |
76 | SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get(); | 76 | SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get(); |
... | @@ -91,11 +91,11 @@ public class NetworkConfigEventHandler { | ... | @@ -91,11 +91,11 @@ public class NetworkConfigEventHandler { |
91 | } | 91 | } |
92 | 92 | ||
93 | /** | 93 | /** |
94 | - * Processes vRouter config removed event. | 94 | + * Processes Segment Routing App Config removed event. |
95 | * | 95 | * |
96 | * @param event network config removed event | 96 | * @param event network config removed event |
97 | */ | 97 | */ |
98 | - protected void processVRouterConfigRemoved(NetworkConfigEvent event) { | 98 | + protected void processAppConfigRemoved(NetworkConfigEvent event) { |
99 | log.info("Processing vRouter CONFIG_REMOVED"); | 99 | log.info("Processing vRouter CONFIG_REMOVED"); |
100 | SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get(); | 100 | SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get(); |
101 | deviceService.getAvailableDevices().forEach(device -> { | 101 | deviceService.getAvailableDevices().forEach(device -> { | ... | ... |
... | @@ -564,7 +564,6 @@ public class DefaultRoutingHandler { | ... | @@ -564,7 +564,6 @@ public class DefaultRoutingHandler { |
564 | * @param deviceId Switch ID to set the rules | 564 | * @param deviceId Switch ID to set the rules |
565 | */ | 565 | */ |
566 | public void populatePortAddressingRules(DeviceId deviceId) { | 566 | public void populatePortAddressingRules(DeviceId deviceId) { |
567 | - rulePopulator.populateXConnectVlanFilters(deviceId); | ||
568 | rulePopulator.populateRouterIpPunts(deviceId); | 567 | rulePopulator.populateRouterIpPunts(deviceId); |
569 | 568 | ||
570 | // Although device is added, sometimes device store does not have the | 569 | // Although device is added, sometimes device store does not have the | ... | ... |
... | @@ -79,8 +79,8 @@ public class McastHandler { | ... | @@ -79,8 +79,8 @@ public class McastHandler { |
79 | private static final Logger log = LoggerFactory.getLogger(McastHandler.class); | 79 | private static final Logger log = LoggerFactory.getLogger(McastHandler.class); |
80 | private final SegmentRoutingManager srManager; | 80 | private final SegmentRoutingManager srManager; |
81 | private final ApplicationId coreAppId; | 81 | private final ApplicationId coreAppId; |
82 | - private StorageService storageService; | 82 | + private final StorageService storageService; |
83 | - private TopologyService topologyService; | 83 | + private final TopologyService topologyService; |
84 | private final ConsistentMap<McastStoreKey, NextObjective> mcastNextObjStore; | 84 | private final ConsistentMap<McastStoreKey, NextObjective> mcastNextObjStore; |
85 | private final KryoNamespace.Builder mcastKryo; | 85 | private final KryoNamespace.Builder mcastKryo; |
86 | private final ConsistentMap<McastStoreKey, McastRole> mcastRoleStore; | 86 | private final ConsistentMap<McastStoreKey, McastRole> mcastRoleStore; |
... | @@ -132,7 +132,7 @@ public class McastHandler { | ... | @@ -132,7 +132,7 @@ public class McastHandler { |
132 | /** | 132 | /** |
133 | * Read initial multicast from mcast store. | 133 | * Read initial multicast from mcast store. |
134 | */ | 134 | */ |
135 | - public void init() { | 135 | + protected void init() { |
136 | srManager.multicastRouteService.getRoutes().forEach(mcastRoute -> { | 136 | srManager.multicastRouteService.getRoutes().forEach(mcastRoute -> { |
137 | ConnectPoint source = srManager.multicastRouteService.fetchSource(mcastRoute); | 137 | ConnectPoint source = srManager.multicastRouteService.fetchSource(mcastRoute); |
138 | Set<ConnectPoint> sinks = srManager.multicastRouteService.fetchSinks(mcastRoute); | 138 | Set<ConnectPoint> sinks = srManager.multicastRouteService.fetchSinks(mcastRoute); |
... | @@ -472,7 +472,7 @@ public class McastHandler { | ... | @@ -472,7 +472,7 @@ public class McastHandler { |
472 | log.warn("Failed to update {} on {}/{}, vlan {}: {}", | 472 | log.warn("Failed to update {} on {}/{}, vlan {}: {}", |
473 | mcastIp, deviceId, port.toLong(), assignedVlan, error)); | 473 | mcastIp, deviceId, port.toLong(), assignedVlan, error)); |
474 | newNextObj = nextObjBuilder(mcastIp, assignedVlan, existingPorts).add(); | 474 | newNextObj = nextObjBuilder(mcastIp, assignedVlan, existingPorts).add(); |
475 | - fwdObj = fwdObjBuilder(mcastIp, assignedVlan, newNextObj.id()).add(); | 475 | + fwdObj = fwdObjBuilder(mcastIp, assignedVlan, newNextObj.id()).add(context); |
476 | mcastNextObjStore.put(mcastStoreKey, newNextObj); | 476 | mcastNextObjStore.put(mcastStoreKey, newNextObj); |
477 | srManager.flowObjectiveService.next(deviceId, newNextObj); | 477 | srManager.flowObjectiveService.next(deviceId, newNextObj); |
478 | srManager.flowObjectiveService.forward(deviceId, fwdObj); | 478 | srManager.flowObjectiveService.forward(deviceId, fwdObj); |
... | @@ -779,11 +779,7 @@ public class McastHandler { | ... | @@ -779,11 +779,7 @@ public class McastHandler { |
779 | // Spine-facing port should have no subnet and no xconnect | 779 | // Spine-facing port should have no subnet and no xconnect |
780 | if (srManager.deviceConfiguration != null && | 780 | if (srManager.deviceConfiguration != null && |
781 | srManager.deviceConfiguration.getPortSubnet(ingressDevice, port) == null && | 781 | srManager.deviceConfiguration.getPortSubnet(ingressDevice, port) == null && |
782 | - srManager.deviceConfiguration.getXConnects().values().stream() | 782 | + !srManager.xConnectHandler.hasXConnect(new ConnectPoint(ingressDevice, port))) { |
783 | - .allMatch(connectPoints -> | ||
784 | - connectPoints.stream().noneMatch(connectPoint -> | ||
785 | - connectPoint.port().equals(port)) | ||
786 | - )) { | ||
787 | return port; | 783 | return port; |
788 | } | 784 | } |
789 | } | 785 | } | ... | ... |
... | @@ -50,7 +50,6 @@ import org.slf4j.LoggerFactory; | ... | @@ -50,7 +50,6 @@ import org.slf4j.LoggerFactory; |
50 | import java.util.ArrayList; | 50 | import java.util.ArrayList; |
51 | import java.util.HashSet; | 51 | import java.util.HashSet; |
52 | import java.util.List; | 52 | import java.util.List; |
53 | -import java.util.Map; | ||
54 | import java.util.Set; | 53 | import java.util.Set; |
55 | import java.util.concurrent.atomic.AtomicLong; | 54 | import java.util.concurrent.atomic.AtomicLong; |
56 | 55 | ||
... | @@ -694,85 +693,6 @@ public class RoutingRulePopulator { | ... | @@ -694,85 +693,6 @@ public class RoutingRulePopulator { |
694 | }); | 693 | }); |
695 | } | 694 | } |
696 | 695 | ||
697 | - /** | ||
698 | - * Creates a filtering objective to permit VLAN cross-connect traffic. | ||
699 | - * | ||
700 | - * @param deviceId the DPID of the switch | ||
701 | - */ | ||
702 | - public void populateXConnectVlanFilters(DeviceId deviceId) { | ||
703 | - Map<VlanId, List<ConnectPoint>> xConnectsForDevice = | ||
704 | - config.getXConnects(); | ||
705 | - xConnectsForDevice.forEach((vlanId, connectPoints) -> { | ||
706 | - // Only proceed the xConnect for given device | ||
707 | - for (ConnectPoint connectPoint : connectPoints) { | ||
708 | - if (!connectPoint.deviceId().equals(deviceId)) { | ||
709 | - return; | ||
710 | - } | ||
711 | - } | ||
712 | - | ||
713 | - connectPoints.forEach(connectPoint -> { | ||
714 | - FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); | ||
715 | - fob.withKey(Criteria.matchInPort(connectPoint.port())) | ||
716 | - .addCondition(Criteria.matchVlanId(vlanId)) | ||
717 | - .addCondition(Criteria.matchEthDst(MacAddress.NONE)) | ||
718 | - .withPriority(SegmentRoutingService.XCONNECT_PRIORITY); | ||
719 | - fob.permit().fromApp(srManager.appId); | ||
720 | - ObjectiveContext context = new DefaultObjectiveContext( | ||
721 | - (objective) -> log.debug("XConnect filter for {} populated", connectPoint), | ||
722 | - (objective, error) -> | ||
723 | - log.warn("Failed to populate xconnect filter for {}: {}", connectPoint, error)); | ||
724 | - srManager.flowObjectiveService.filter(deviceId, fob.add(context)); | ||
725 | - }); | ||
726 | - }); | ||
727 | - } | ||
728 | - | ||
729 | - /** | ||
730 | - * Populates a forwarding objective that points the VLAN cross-connect | ||
731 | - * packets to a broadcast group. | ||
732 | - * | ||
733 | - * @param deviceId switch ID to set the rules | ||
734 | - */ | ||
735 | - public void populateXConnectBroadcastRule(DeviceId deviceId) { | ||
736 | - Map<VlanId, List<ConnectPoint>> xConnects = | ||
737 | - config.getXConnects(); | ||
738 | - xConnects.forEach((vlanId, connectPoints) -> { | ||
739 | - // Only proceed the xConnect for given device | ||
740 | - for (ConnectPoint connectPoint : connectPoints) { | ||
741 | - if (!connectPoint.deviceId().equals(deviceId)) { | ||
742 | - return; | ||
743 | - } | ||
744 | - } | ||
745 | - | ||
746 | - int nextId = srManager.getXConnectNextObjectiveId(deviceId, vlanId); | ||
747 | - if (nextId < 0) { | ||
748 | - log.error("Cannot install cross-connect broadcast rule in dev:{} " + | ||
749 | - "due to missing nextId:{}", deviceId, nextId); | ||
750 | - return; | ||
751 | - } | ||
752 | - | ||
753 | - /* | ||
754 | - * Driver should treat objectives with MacAddress.NONE and !VlanId.NONE | ||
755 | - * as the VLAN cross-connect broadcast rules | ||
756 | - */ | ||
757 | - TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); | ||
758 | - sbuilder.matchVlanId(vlanId); | ||
759 | - sbuilder.matchEthDst(MacAddress.NONE); | ||
760 | - | ||
761 | - ForwardingObjective.Builder fob = DefaultForwardingObjective.builder(); | ||
762 | - fob.withFlag(Flag.SPECIFIC) | ||
763 | - .withSelector(sbuilder.build()) | ||
764 | - .nextStep(nextId) | ||
765 | - .withPriority(SegmentRoutingService.DEFAULT_PRIORITY) | ||
766 | - .fromApp(srManager.appId) | ||
767 | - .makePermanent(); | ||
768 | - ObjectiveContext context = new DefaultObjectiveContext( | ||
769 | - (objective) -> log.debug("XConnect rule for {} populated", xConnects), | ||
770 | - (objective, error) -> | ||
771 | - log.warn("Failed to populate xconnect rule for {}: {}", xConnects, error)); | ||
772 | - srManager.flowObjectiveService.forward(deviceId, fob.add(context)); | ||
773 | - }); | ||
774 | - } | ||
775 | - | ||
776 | private int getPriorityFromPrefix(IpPrefix prefix) { | 696 | private int getPriorityFromPrefix(IpPrefix prefix) { |
777 | return (prefix.isIp4()) ? | 697 | return (prefix.isIp4()) ? |
778 | 2000 * prefix.prefixLength() + SegmentRoutingService.MIN_IP_PRIORITY : | 698 | 2000 * prefix.prefixLength() + SegmentRoutingService.MIN_IP_PRIORITY : | ... | ... |
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
... | @@ -39,7 +39,6 @@ import org.slf4j.LoggerFactory; | ... | @@ -39,7 +39,6 @@ import org.slf4j.LoggerFactory; |
39 | import java.util.ArrayList; | 39 | import java.util.ArrayList; |
40 | import java.util.HashMap; | 40 | import java.util.HashMap; |
41 | import java.util.HashSet; | 41 | import java.util.HashSet; |
42 | -import java.util.LinkedList; | ||
43 | import java.util.List; | 42 | import java.util.List; |
44 | import java.util.Map; | 43 | import java.util.Map; |
45 | import java.util.Optional; | 44 | import java.util.Optional; |
... | @@ -58,7 +57,6 @@ public class DeviceConfiguration implements DeviceProperties { | ... | @@ -58,7 +57,6 @@ public class DeviceConfiguration implements DeviceProperties { |
58 | private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class); | 57 | private static final Logger log = LoggerFactory.getLogger(DeviceConfiguration.class); |
59 | private final List<Integer> allSegmentIds = new ArrayList<>(); | 58 | private final List<Integer> allSegmentIds = new ArrayList<>(); |
60 | private final Map<DeviceId, SegmentRouterInfo> deviceConfigMap = new ConcurrentHashMap<>(); | 59 | private final Map<DeviceId, SegmentRouterInfo> deviceConfigMap = new ConcurrentHashMap<>(); |
61 | - private final Map<VlanId, List<ConnectPoint>> xConnects = new ConcurrentHashMap<>(); | ||
62 | private ApplicationId appId; | 60 | private ApplicationId appId; |
63 | private NetworkConfigService cfgService; | 61 | private NetworkConfigService cfgService; |
64 | 62 | ||
... | @@ -148,28 +146,6 @@ public class DeviceConfiguration implements DeviceProperties { | ... | @@ -148,28 +146,6 @@ public class DeviceConfiguration implements DeviceProperties { |
148 | } | 146 | } |
149 | info.subnets.put(port, interfaceAddress.subnetAddress().getIp4Prefix()); | 147 | info.subnets.put(port, interfaceAddress.subnetAddress().getIp4Prefix()); |
150 | }); | 148 | }); |
151 | - | ||
152 | - // Extract VLAN cross-connect information | ||
153 | - // Do not setup cross-connect if VLAN is NONE | ||
154 | - if (vlanId.equals(VlanId.NONE)) { | ||
155 | - return; | ||
156 | - } | ||
157 | - List<ConnectPoint> connectPoints = xConnects.get(vlanId); | ||
158 | - if (connectPoints != null) { | ||
159 | - if (connectPoints.size() != 1) { | ||
160 | - log.warn("Cross-connect should only have two endpoints. Aborting."); | ||
161 | - return; | ||
162 | - } | ||
163 | - if (!connectPoints.get(0).deviceId().equals(connectPoint.deviceId())) { | ||
164 | - log.warn("Cross-connect endpoints must be on the same switch. Aborting."); | ||
165 | - return; | ||
166 | - } | ||
167 | - connectPoints.add(connectPoint); | ||
168 | - } else { | ||
169 | - connectPoints = new LinkedList<>(); | ||
170 | - connectPoints.add(connectPoint); | ||
171 | - xConnects.put(vlanId, connectPoints); | ||
172 | - } | ||
173 | } | 149 | } |
174 | }); | 150 | }); |
175 | }); | 151 | }); |
... | @@ -298,11 +274,6 @@ public class DeviceConfiguration implements DeviceProperties { | ... | @@ -298,11 +274,6 @@ public class DeviceConfiguration implements DeviceProperties { |
298 | return subnetPortMap; | 274 | return subnetPortMap; |
299 | } | 275 | } |
300 | 276 | ||
301 | - @Override | ||
302 | - public Map<VlanId, List<ConnectPoint>> getXConnects() { | ||
303 | - return xConnects; | ||
304 | - } | ||
305 | - | ||
306 | /** | 277 | /** |
307 | * Returns the device identifier or data plane identifier (dpid) | 278 | * Returns the device identifier or data plane identifier (dpid) |
308 | * of a segment router given its segment id. | 279 | * of a segment router given its segment id. | ... | ... |
... | @@ -21,8 +21,6 @@ import java.util.Map; | ... | @@ -21,8 +21,6 @@ import java.util.Map; |
21 | import org.onlab.packet.Ip4Address; | 21 | import org.onlab.packet.Ip4Address; |
22 | import org.onlab.packet.Ip4Prefix; | 22 | import org.onlab.packet.Ip4Prefix; |
23 | import org.onlab.packet.MacAddress; | 23 | import org.onlab.packet.MacAddress; |
24 | -import org.onlab.packet.VlanId; | ||
25 | -import org.onosproject.net.ConnectPoint; | ||
26 | import org.onosproject.net.DeviceId; | 24 | import org.onosproject.net.DeviceId; |
27 | import org.onosproject.net.PortNumber; | 25 | import org.onosproject.net.PortNumber; |
28 | 26 | ||
... | @@ -97,11 +95,4 @@ public interface DeviceProperties { | ... | @@ -97,11 +95,4 @@ public interface DeviceProperties { |
97 | */ | 95 | */ |
98 | Map<Ip4Prefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId) | 96 | Map<Ip4Prefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId) |
99 | throws DeviceConfigNotFoundException; | 97 | throws DeviceConfigNotFoundException; |
100 | - | ||
101 | - /** | ||
102 | - * Returns the VLAN cross-connect configuration. | ||
103 | - * | ||
104 | - * @return A map of that maps VLAN ID to a list of cross-connect endpoints | ||
105 | - */ | ||
106 | - Map<VlanId, List<ConnectPoint>> getXConnects(); | ||
107 | } | 98 | } | ... | ... |
apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/XConnectConfig.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.segmentrouting.config; | ||
18 | + | ||
19 | +import com.fasterxml.jackson.databind.JsonNode; | ||
20 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
21 | +import com.google.common.collect.ImmutableSet; | ||
22 | +import org.onlab.packet.VlanId; | ||
23 | +import org.onosproject.core.ApplicationId; | ||
24 | +import org.onosproject.net.DeviceId; | ||
25 | +import org.onosproject.net.PortNumber; | ||
26 | +import org.onosproject.net.config.Config; | ||
27 | +import org.onosproject.segmentrouting.storekey.XConnectStoreKey; | ||
28 | + | ||
29 | +import java.util.Set; | ||
30 | + | ||
31 | +import static com.google.common.base.Preconditions.checkArgument; | ||
32 | + | ||
33 | +/** | ||
34 | + * Configuration object for cross-connect. | ||
35 | + */ | ||
36 | +public class XConnectConfig extends Config<ApplicationId> { | ||
37 | + private static final String VLAN = "vlan"; | ||
38 | + private static final String PORTS = "ports"; | ||
39 | + private static final String NAME = "name"; // dummy field for naming | ||
40 | + | ||
41 | + private static final String UNEXPECTED_FIELD_NAME = "Unexpected field name"; | ||
42 | + | ||
43 | + @Override | ||
44 | + public boolean isValid() { | ||
45 | + try { | ||
46 | + getXconnects().forEach(this::getPorts); | ||
47 | + } catch (IllegalArgumentException e) { | ||
48 | + return false; | ||
49 | + } | ||
50 | + return true; | ||
51 | + } | ||
52 | + | ||
53 | + /** | ||
54 | + * Returns all xconnect keys. | ||
55 | + * | ||
56 | + * @return all keys (device/vlan pairs) | ||
57 | + * @throws IllegalArgumentException if wrong format | ||
58 | + */ | ||
59 | + public Set<XConnectStoreKey> getXconnects() { | ||
60 | + ImmutableSet.Builder<XConnectStoreKey> builder = ImmutableSet.builder(); | ||
61 | + object.fields().forEachRemaining(entry -> { | ||
62 | + DeviceId deviceId = DeviceId.deviceId(entry.getKey()); | ||
63 | + builder.addAll(getXconnects(deviceId)); | ||
64 | + }); | ||
65 | + return builder.build(); | ||
66 | + } | ||
67 | + | ||
68 | + /** | ||
69 | + * Returns xconnect keys of given device. | ||
70 | + * | ||
71 | + * @param deviceId ID of the device from which we want to get XConnect info | ||
72 | + * @return xconnect keys (device/vlan pairs) of given device | ||
73 | + * @throws IllegalArgumentException if wrong format | ||
74 | + */ | ||
75 | + public Set<XConnectStoreKey> getXconnects(DeviceId deviceId) { | ||
76 | + ImmutableSet.Builder<XConnectStoreKey> builder = ImmutableSet.builder(); | ||
77 | + JsonNode vlanPortPair = object.get(deviceId.toString()); | ||
78 | + if (vlanPortPair != null) { | ||
79 | + vlanPortPair.forEach(jsonNode -> { | ||
80 | + if (!hasOnlyFields((ObjectNode) jsonNode, VLAN, PORTS, NAME)) { | ||
81 | + throw new IllegalArgumentException(UNEXPECTED_FIELD_NAME); | ||
82 | + } | ||
83 | + VlanId vlanId = VlanId.vlanId((short) jsonNode.get(VLAN).asInt()); | ||
84 | + builder.add(new XConnectStoreKey(deviceId, vlanId)); | ||
85 | + }); | ||
86 | + } | ||
87 | + return builder.build(); | ||
88 | + } | ||
89 | + | ||
90 | + /** | ||
91 | + * Returns ports of given xconnect key. | ||
92 | + * | ||
93 | + * @param xconnect xconnect key | ||
94 | + * @return set of two ports associated with given xconnect key | ||
95 | + * @throws IllegalArgumentException if wrong format | ||
96 | + */ | ||
97 | + public Set<PortNumber> getPorts(XConnectStoreKey xconnect) { | ||
98 | + ImmutableSet.Builder<PortNumber> builder = ImmutableSet.builder(); | ||
99 | + object.get(xconnect.deviceId().toString()).forEach(vlanPortsPair -> { | ||
100 | + if (xconnect.vlanId().toShort() == vlanPortsPair.get(VLAN).asInt()) { | ||
101 | + int portCount = vlanPortsPair.get(PORTS).size(); | ||
102 | + checkArgument(portCount == 2, | ||
103 | + "Expect 2 ports but found " + portCount + " on " + xconnect); | ||
104 | + vlanPortsPair.get(PORTS).forEach(portNode -> { | ||
105 | + builder.add(PortNumber.portNumber(portNode.asInt())); | ||
106 | + }); | ||
107 | + } | ||
108 | + }); | ||
109 | + return builder.build(); | ||
110 | + } | ||
111 | +} |
... | @@ -35,7 +35,6 @@ import org.onlab.packet.MplsLabel; | ... | @@ -35,7 +35,6 @@ import org.onlab.packet.MplsLabel; |
35 | import org.onlab.packet.VlanId; | 35 | import org.onlab.packet.VlanId; |
36 | import org.onlab.util.KryoNamespace; | 36 | import org.onlab.util.KryoNamespace; |
37 | import org.onosproject.core.ApplicationId; | 37 | import org.onosproject.core.ApplicationId; |
38 | -import org.onosproject.net.ConnectPoint; | ||
39 | import org.onosproject.net.DeviceId; | 38 | import org.onosproject.net.DeviceId; |
40 | import org.onosproject.net.Link; | 39 | import org.onosproject.net.Link; |
41 | import org.onosproject.net.PortNumber; | 40 | import org.onosproject.net.PortNumber; |
... | @@ -55,7 +54,6 @@ import org.onosproject.segmentrouting.config.DeviceProperties; | ... | @@ -55,7 +54,6 @@ import org.onosproject.segmentrouting.config.DeviceProperties; |
55 | import org.onosproject.segmentrouting.storekey.NeighborSetNextObjectiveStoreKey; | 54 | import org.onosproject.segmentrouting.storekey.NeighborSetNextObjectiveStoreKey; |
56 | import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey; | 55 | import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey; |
57 | import org.onosproject.segmentrouting.storekey.SubnetNextObjectiveStoreKey; | 56 | import org.onosproject.segmentrouting.storekey.SubnetNextObjectiveStoreKey; |
58 | -import org.onosproject.segmentrouting.storekey.XConnectNextObjectiveStoreKey; | ||
59 | import org.onosproject.store.service.EventuallyConsistentMap; | 57 | import org.onosproject.store.service.EventuallyConsistentMap; |
60 | import org.slf4j.Logger; | 58 | import org.slf4j.Logger; |
61 | 59 | ||
... | @@ -89,8 +87,6 @@ public class DefaultGroupHandler { | ... | @@ -89,8 +87,6 @@ public class DefaultGroupHandler { |
89 | subnetNextObjStore = null; | 87 | subnetNextObjStore = null; |
90 | protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer> | 88 | protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer> |
91 | portNextObjStore = null; | 89 | portNextObjStore = null; |
92 | - protected EventuallyConsistentMap<XConnectNextObjectiveStoreKey, Integer> | ||
93 | - xConnectNextObjStore = null; | ||
94 | private SegmentRoutingManager srManager; | 90 | private SegmentRoutingManager srManager; |
95 | 91 | ||
96 | protected KryoNamespace.Builder kryo = new KryoNamespace.Builder() | 92 | protected KryoNamespace.Builder kryo = new KryoNamespace.Builder() |
... | @@ -123,7 +119,6 @@ public class DefaultGroupHandler { | ... | @@ -123,7 +119,6 @@ public class DefaultGroupHandler { |
123 | this.nsNextObjStore = srManager.nsNextObjStore; | 119 | this.nsNextObjStore = srManager.nsNextObjStore; |
124 | this.subnetNextObjStore = srManager.subnetNextObjStore; | 120 | this.subnetNextObjStore = srManager.subnetNextObjStore; |
125 | this.portNextObjStore = srManager.portNextObjStore; | 121 | this.portNextObjStore = srManager.portNextObjStore; |
126 | - this.xConnectNextObjStore = srManager.xConnectNextObjStore; | ||
127 | this.srManager = srManager; | 122 | this.srManager = srManager; |
128 | 123 | ||
129 | populateNeighborMaps(); | 124 | populateNeighborMaps(); |
... | @@ -471,32 +466,6 @@ public class DefaultGroupHandler { | ... | @@ -471,32 +466,6 @@ public class DefaultGroupHandler { |
471 | } | 466 | } |
472 | 467 | ||
473 | /** | 468 | /** |
474 | - * Returns the next objective ID of type broadcast associated with the VLAN | ||
475 | - * cross-connection. | ||
476 | - * | ||
477 | - * @param vlanId VLAN ID for the cross-connection | ||
478 | - * @return int if found or created, -1 if there are errors during the | ||
479 | - * creation of the next objective | ||
480 | - */ | ||
481 | - public int getXConnectNextObjectiveId(VlanId vlanId) { | ||
482 | - Integer nextId = xConnectNextObjStore | ||
483 | - .get(new XConnectNextObjectiveStoreKey(deviceId, vlanId)); | ||
484 | - if (nextId == null) { | ||
485 | - log.trace("getXConnectNextObjectiveId: Next objective id " | ||
486 | - + "not found for device {} and vlan {}. Creating", deviceId, vlanId); | ||
487 | - createGroupsForXConnect(deviceId); | ||
488 | - nextId = xConnectNextObjStore.get( | ||
489 | - new XConnectNextObjectiveStoreKey(deviceId, vlanId)); | ||
490 | - if (nextId == null) { | ||
491 | - log.warn("getXConnectNextObjectiveId: Next objective id " | ||
492 | - + "not found for device {} and vlan {}.", deviceId, vlanId); | ||
493 | - return -1; | ||
494 | - } | ||
495 | - } | ||
496 | - return nextId; | ||
497 | - } | ||
498 | - | ||
499 | - /** | ||
500 | * Checks if the next objective ID (group) for the neighbor set exists or not. | 469 | * Checks if the next objective ID (group) for the neighbor set exists or not. |
501 | * | 470 | * |
502 | * @param ns neighbor set to check | 471 | * @param ns neighbor set to check |
... | @@ -743,55 +712,6 @@ public class DefaultGroupHandler { | ... | @@ -743,55 +712,6 @@ public class DefaultGroupHandler { |
743 | } | 712 | } |
744 | 713 | ||
745 | /** | 714 | /** |
746 | - * Creates broadcast groups for VLAN cross-connect ports. | ||
747 | - * | ||
748 | - * @param deviceId the DPID of the switch | ||
749 | - */ | ||
750 | - public void createGroupsForXConnect(DeviceId deviceId) { | ||
751 | - Map<VlanId, List<ConnectPoint>> xConnectsForDevice = deviceConfig.getXConnects(); | ||
752 | - | ||
753 | - xConnectsForDevice.forEach((vlanId, connectPoints) -> { | ||
754 | - // Only proceed the xConnect for given device | ||
755 | - for (ConnectPoint connectPoint : connectPoints) { | ||
756 | - if (!connectPoint.deviceId().equals(deviceId)) { | ||
757 | - return; | ||
758 | - } | ||
759 | - } | ||
760 | - | ||
761 | - // Check if the next obj is already in the store | ||
762 | - XConnectNextObjectiveStoreKey key = | ||
763 | - new XConnectNextObjectiveStoreKey(deviceId, vlanId); | ||
764 | - if (xConnectNextObjStore.containsKey(key)) { | ||
765 | - log.debug("Cross-connect Broadcast group for device {} and vlanId {} exists", | ||
766 | - deviceId, vlanId); | ||
767 | - return; | ||
768 | - } | ||
769 | - | ||
770 | - TrafficSelector metadata = | ||
771 | - DefaultTrafficSelector.builder().matchVlanId(vlanId).build(); | ||
772 | - int nextId = flowObjectiveService.allocateNextId(); | ||
773 | - | ||
774 | - NextObjective.Builder nextObjBuilder = DefaultNextObjective | ||
775 | - .builder().withId(nextId) | ||
776 | - .withType(NextObjective.Type.BROADCAST).fromApp(appId) | ||
777 | - .withMeta(metadata); | ||
778 | - | ||
779 | - connectPoints.forEach(connectPoint -> { | ||
780 | - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); | ||
781 | - tBuilder.setOutput(connectPoint.port()); | ||
782 | - nextObjBuilder.addTreatment(tBuilder.build()); | ||
783 | - }); | ||
784 | - | ||
785 | - NextObjective nextObj = nextObjBuilder.add(); | ||
786 | - flowObjectiveService.next(deviceId, nextObj); | ||
787 | - log.debug("createGroupsForXConnect: Submited next objective {} in device {}", | ||
788 | - nextId, deviceId); | ||
789 | - xConnectNextObjStore.put(key, nextId); | ||
790 | - }); | ||
791 | - } | ||
792 | - | ||
793 | - | ||
794 | - /** | ||
795 | * Create simple next objective for a single port. The treatments can include | 715 | * Create simple next objective for a single port. The treatments can include |
796 | * all outgoing actions that need to happen on the packet. | 716 | * all outgoing actions that need to happen on the packet. |
797 | * | 717 | * | ... | ... |
... | @@ -24,7 +24,7 @@ import java.util.Objects; | ... | @@ -24,7 +24,7 @@ import java.util.Objects; |
24 | /** | 24 | /** |
25 | * Key of VLAN cross-connect next objective store. | 25 | * Key of VLAN cross-connect next objective store. |
26 | */ | 26 | */ |
27 | -public class XConnectNextObjectiveStoreKey { | 27 | +public class XConnectStoreKey { |
28 | private final DeviceId deviceId; | 28 | private final DeviceId deviceId; |
29 | private final VlanId vlanId; | 29 | private final VlanId vlanId; |
30 | 30 | ||
... | @@ -34,7 +34,7 @@ public class XConnectNextObjectiveStoreKey { | ... | @@ -34,7 +34,7 @@ public class XConnectNextObjectiveStoreKey { |
34 | * @param deviceId device ID of the VLAN cross-connection | 34 | * @param deviceId device ID of the VLAN cross-connection |
35 | * @param vlanId VLAN ID of the VLAN cross-connection | 35 | * @param vlanId VLAN ID of the VLAN cross-connection |
36 | */ | 36 | */ |
37 | - public XConnectNextObjectiveStoreKey(DeviceId deviceId, VlanId vlanId) { | 37 | + public XConnectStoreKey(DeviceId deviceId, VlanId vlanId) { |
38 | this.deviceId = deviceId; | 38 | this.deviceId = deviceId; |
39 | this.vlanId = vlanId; | 39 | this.vlanId = vlanId; |
40 | } | 40 | } |
... | @@ -62,11 +62,11 @@ public class XConnectNextObjectiveStoreKey { | ... | @@ -62,11 +62,11 @@ public class XConnectNextObjectiveStoreKey { |
62 | if (this == o) { | 62 | if (this == o) { |
63 | return true; | 63 | return true; |
64 | } | 64 | } |
65 | - if (!(o instanceof XConnectNextObjectiveStoreKey)) { | 65 | + if (!(o instanceof XConnectStoreKey)) { |
66 | return false; | 66 | return false; |
67 | } | 67 | } |
68 | - XConnectNextObjectiveStoreKey that = | 68 | + XConnectStoreKey that = |
69 | - (XConnectNextObjectiveStoreKey) o; | 69 | + (XConnectStoreKey) o; |
70 | return (Objects.equals(this.deviceId, that.deviceId) && | 70 | return (Objects.equals(this.deviceId, that.deviceId) && |
71 | Objects.equals(this.vlanId, that.vlanId)); | 71 | Objects.equals(this.vlanId, that.vlanId)); |
72 | } | 72 | } | ... | ... |
... | @@ -41,9 +41,6 @@ import static org.junit.Assert.*; | ... | @@ -41,9 +41,6 @@ import static org.junit.Assert.*; |
41 | * Tests for class {@link SegmentRoutingAppConfig}. | 41 | * Tests for class {@link SegmentRoutingAppConfig}. |
42 | */ | 42 | */ |
43 | public class SegmentRoutingAppConfigTest { | 43 | public class SegmentRoutingAppConfigTest { |
44 | - private static final ApplicationId APP_ID = | ||
45 | - new TestApplicationId(SegmentRoutingManager.SR_APP_ID); | ||
46 | - | ||
47 | private SegmentRoutingAppConfig config; | 44 | private SegmentRoutingAppConfig config; |
48 | private SegmentRoutingAppConfig invalidConfig; | 45 | private SegmentRoutingAppConfig invalidConfig; |
49 | 46 | ||
... | @@ -67,12 +64,12 @@ public class SegmentRoutingAppConfigTest { | ... | @@ -67,12 +64,12 @@ public class SegmentRoutingAppConfigTest { |
67 | @Before | 64 | @Before |
68 | public void setUp() throws Exception { | 65 | public void setUp() throws Exception { |
69 | InputStream jsonStream = SegmentRoutingAppConfigTest.class | 66 | InputStream jsonStream = SegmentRoutingAppConfigTest.class |
70 | - .getResourceAsStream("/sr-app-config.json"); | 67 | + .getResourceAsStream("/app.json"); |
71 | InputStream invalidJsonStream = SegmentRoutingAppConfigTest.class | 68 | InputStream invalidJsonStream = SegmentRoutingAppConfigTest.class |
72 | - .getResourceAsStream("/sr-app-config-invalid.json"); | 69 | + .getResourceAsStream("/app-invalid.json"); |
73 | 70 | ||
74 | - ApplicationId subject = APP_ID; | ||
75 | String key = SegmentRoutingManager.SR_APP_ID; | 71 | String key = SegmentRoutingManager.SR_APP_ID; |
72 | + ApplicationId subject = new TestApplicationId(key); | ||
76 | ObjectMapper mapper = new ObjectMapper(); | 73 | ObjectMapper mapper = new ObjectMapper(); |
77 | JsonNode jsonNode = mapper.readTree(jsonStream); | 74 | JsonNode jsonNode = mapper.readTree(jsonStream); |
78 | JsonNode invalidJsonNode = mapper.readTree(invalidJsonStream); | 75 | JsonNode invalidJsonNode = mapper.readTree(invalidJsonStream); | ... | ... |
... | @@ -47,7 +47,7 @@ public class SegmentRoutingDeviceConfigTest { | ... | @@ -47,7 +47,7 @@ public class SegmentRoutingDeviceConfigTest { |
47 | @Before | 47 | @Before |
48 | public void setUp() throws Exception { | 48 | public void setUp() throws Exception { |
49 | InputStream jsonStream = SegmentRoutingDeviceConfigTest.class | 49 | InputStream jsonStream = SegmentRoutingDeviceConfigTest.class |
50 | - .getResourceAsStream("/sr-device-config.json"); | 50 | + .getResourceAsStream("/device.json"); |
51 | 51 | ||
52 | adjacencySids1 = new HashMap<>(); | 52 | adjacencySids1 = new HashMap<>(); |
53 | Set<Integer> ports1 = new HashSet<>(); | 53 | Set<Integer> ports1 = new HashSet<>(); | ... | ... |
apps/segmentrouting/src/test/java/org/onosproject/segmentrouting/config/XConnectConfigTest.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.segmentrouting.config; | ||
18 | + | ||
19 | +import com.fasterxml.jackson.databind.JsonNode; | ||
20 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
21 | +import org.junit.Before; | ||
22 | +import org.junit.Test; | ||
23 | +import org.onlab.packet.VlanId; | ||
24 | +import org.onosproject.TestApplicationId; | ||
25 | +import org.onosproject.core.ApplicationId; | ||
26 | +import org.onosproject.net.DeviceId; | ||
27 | +import org.onosproject.net.PortNumber; | ||
28 | +import org.onosproject.net.config.Config; | ||
29 | +import org.onosproject.net.config.ConfigApplyDelegate; | ||
30 | +import org.onosproject.segmentrouting.SegmentRoutingManager; | ||
31 | +import org.onosproject.segmentrouting.storekey.XConnectStoreKey; | ||
32 | +import java.io.InputStream; | ||
33 | +import java.util.Set; | ||
34 | +import static org.junit.Assert.assertFalse; | ||
35 | +import static org.junit.Assert.assertTrue; | ||
36 | +import static org.junit.Assert.assertThat; | ||
37 | +import static org.hamcrest.Matchers.is; | ||
38 | + | ||
39 | +/** | ||
40 | + * Tests for class {@link XConnectConfig}. | ||
41 | + */ | ||
42 | +public class XConnectConfigTest { | ||
43 | + private static final DeviceId DEV1 = DeviceId.deviceId("of:0000000000000001"); | ||
44 | + private static final DeviceId DEV2 = DeviceId.deviceId("of:0000000000000002"); | ||
45 | + private static final VlanId VLAN10 = VlanId.vlanId((short) 10); | ||
46 | + private static final VlanId VLAN20 = VlanId.vlanId((short) 20); | ||
47 | + private static final PortNumber PORT3 = PortNumber.portNumber(3); | ||
48 | + private static final PortNumber PORT4 = PortNumber.portNumber(4); | ||
49 | + private static final PortNumber PORT5 = PortNumber.portNumber(5); | ||
50 | + private static final XConnectStoreKey KEY1 = new XConnectStoreKey(DEV1, VLAN10); | ||
51 | + private static final XConnectStoreKey KEY2 = new XConnectStoreKey(DEV2, VLAN10); | ||
52 | + private static final XConnectStoreKey KEY3 = new XConnectStoreKey(DEV2, VLAN20); | ||
53 | + private static final XConnectStoreKey KEY4 = new XConnectStoreKey(DEV2, VlanId.NONE); | ||
54 | + | ||
55 | + private XConnectConfig config; | ||
56 | + private XConnectConfig invalidConfig; | ||
57 | + | ||
58 | + @Before | ||
59 | + public void setUp() throws Exception { | ||
60 | + InputStream jsonStream = SegmentRoutingAppConfigTest.class | ||
61 | + .getResourceAsStream("/xconnect.json"); | ||
62 | + InputStream invalidJsonStream = SegmentRoutingAppConfigTest.class | ||
63 | + .getResourceAsStream("/xconnect-invalid.json"); | ||
64 | + | ||
65 | + String key = SegmentRoutingManager.SR_APP_ID; | ||
66 | + ApplicationId subject = new TestApplicationId(key); | ||
67 | + ObjectMapper mapper = new ObjectMapper(); | ||
68 | + JsonNode jsonNode = mapper.readTree(jsonStream); | ||
69 | + JsonNode invalidJsonNode = mapper.readTree(invalidJsonStream); | ||
70 | + ConfigApplyDelegate delegate = new XConnectConfigTest.MockDelegate(); | ||
71 | + | ||
72 | + config = new XConnectConfig(); | ||
73 | + config.init(subject, key, jsonNode, mapper, delegate); | ||
74 | + invalidConfig = new XConnectConfig(); | ||
75 | + invalidConfig.init(subject, key, invalidJsonNode, mapper, delegate); | ||
76 | + } | ||
77 | + | ||
78 | + /** | ||
79 | + * Tests config validity. | ||
80 | + */ | ||
81 | + @Test | ||
82 | + public void testIsValid() { | ||
83 | + assertTrue(config.isValid()); | ||
84 | + assertFalse(invalidConfig.isValid()); | ||
85 | + } | ||
86 | + | ||
87 | + /** | ||
88 | + * Tests getXconnects. | ||
89 | + */ | ||
90 | + @Test | ||
91 | + public void testGetXconnects() { | ||
92 | + Set<XConnectStoreKey> xconnects = config.getXconnects(); | ||
93 | + assertThat(xconnects.size(), is(3)); | ||
94 | + assertTrue(xconnects.contains(KEY1)); | ||
95 | + assertTrue(xconnects.contains(KEY2)); | ||
96 | + assertTrue(xconnects.contains(KEY3)); | ||
97 | + assertFalse(xconnects.contains(KEY4)); | ||
98 | + } | ||
99 | + | ||
100 | + /** | ||
101 | + * Tests getPorts. | ||
102 | + */ | ||
103 | + @Test | ||
104 | + public void testGetPorts() { | ||
105 | + Set<PortNumber> ports; | ||
106 | + | ||
107 | + ports = config.getPorts(KEY1); | ||
108 | + assertThat(ports.size(), is(2)); | ||
109 | + assertTrue(ports.contains(PORT3)); | ||
110 | + assertTrue(ports.contains(PORT4)); | ||
111 | + | ||
112 | + ports = config.getPorts(KEY2); | ||
113 | + assertThat(ports.size(), is(2)); | ||
114 | + assertTrue(ports.contains(PORT3)); | ||
115 | + assertTrue(ports.contains(PORT4)); | ||
116 | + | ||
117 | + ports = config.getPorts(KEY3); | ||
118 | + assertThat(ports.size(), is(2)); | ||
119 | + assertTrue(ports.contains(PORT4)); | ||
120 | + assertTrue(ports.contains(PORT5)); | ||
121 | + } | ||
122 | + | ||
123 | + private class MockDelegate implements ConfigApplyDelegate { | ||
124 | + @Override | ||
125 | + public void onApply(Config config) { | ||
126 | + } | ||
127 | + } | ||
128 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +{ | ||
2 | + "of:0000000000000001": [ | ||
3 | + { | ||
4 | + "vlan": 10, | ||
5 | + "ports": [3, 4], | ||
6 | + "name": "OLT1" | ||
7 | + } | ||
8 | + ], | ||
9 | + "of:0000000000000002": [ | ||
10 | + { | ||
11 | + "vlan": 10, | ||
12 | + "ports": [3, 4] | ||
13 | + }, | ||
14 | + { | ||
15 | + "vlan": 20, | ||
16 | + "ports": [4, 5] | ||
17 | + } | ||
18 | + ] | ||
19 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -34,11 +34,16 @@ public enum ObjectiveError { | ... | @@ -34,11 +34,16 @@ public enum ObjectiveError { |
34 | FLOWINSTALLATIONFAILED, | 34 | FLOWINSTALLATIONFAILED, |
35 | 35 | ||
36 | /** | 36 | /** |
37 | - * THe group installation for this objective failed. | 37 | + * The group installation for this objective failed. |
38 | */ | 38 | */ |
39 | GROUPINSTALLATIONFAILED, | 39 | GROUPINSTALLATIONFAILED, |
40 | 40 | ||
41 | /** | 41 | /** |
42 | + * The group removal for this objective failed. | ||
43 | + */ | ||
44 | + GROUPREMOVALFAILED, | ||
45 | + | ||
46 | + /** | ||
42 | * The group was reported as installed but is missing. | 47 | * The group was reported as installed but is missing. |
43 | */ | 48 | */ |
44 | GROUPMISSING, | 49 | GROUPMISSING, | ... | ... |
... | @@ -114,7 +114,8 @@ public class Ofdpa2GroupHandler { | ... | @@ -114,7 +114,8 @@ public class Ofdpa2GroupHandler { |
114 | 114 | ||
115 | protected DeviceId deviceId; | 115 | protected DeviceId deviceId; |
116 | private FlowObjectiveStore flowObjectiveStore; | 116 | private FlowObjectiveStore flowObjectiveStore; |
117 | - private Cache<GroupKey, List<OfdpaNextGroup>> pendingNextObjectives; | 117 | + private Cache<GroupKey, List<OfdpaNextGroup>> pendingAddNextObjectives; |
118 | + private Cache<NextObjective, List<GroupKey>> pendingRemoveNextObjectives; | ||
118 | private ConcurrentHashMap<GroupKey, Set<GroupChainElem>> pendingGroups; | 119 | private ConcurrentHashMap<GroupKey, Set<GroupChainElem>> pendingGroups; |
119 | private ScheduledExecutorService groupChecker = | 120 | private ScheduledExecutorService groupChecker = |
120 | Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", "ofdpa2-%d", log)); | 121 | Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", "ofdpa2-%d", log)); |
... | @@ -134,7 +135,7 @@ public class Ofdpa2GroupHandler { | ... | @@ -134,7 +135,7 @@ public class Ofdpa2GroupHandler { |
134 | this.storageService = serviceDirectory.get(StorageService.class); | 135 | this.storageService = serviceDirectory.get(StorageService.class); |
135 | this.nextIndex = storageService.getAtomicCounter("group-id-index-counter"); | 136 | this.nextIndex = storageService.getAtomicCounter("group-id-index-counter"); |
136 | 137 | ||
137 | - pendingNextObjectives = CacheBuilder.newBuilder() | 138 | + pendingAddNextObjectives = CacheBuilder.newBuilder() |
138 | .expireAfterWrite(20, TimeUnit.SECONDS) | 139 | .expireAfterWrite(20, TimeUnit.SECONDS) |
139 | .removalListener(( | 140 | .removalListener(( |
140 | RemovalNotification<GroupKey, List<OfdpaNextGroup>> notification) -> { | 141 | RemovalNotification<GroupKey, List<OfdpaNextGroup>> notification) -> { |
... | @@ -142,7 +143,16 @@ public class Ofdpa2GroupHandler { | ... | @@ -142,7 +143,16 @@ public class Ofdpa2GroupHandler { |
142 | notification.getValue().forEach(ofdpaNextGrp -> | 143 | notification.getValue().forEach(ofdpaNextGrp -> |
143 | Ofdpa2Pipeline.fail(ofdpaNextGrp.nextObj, | 144 | Ofdpa2Pipeline.fail(ofdpaNextGrp.nextObj, |
144 | ObjectiveError.GROUPINSTALLATIONFAILED)); | 145 | ObjectiveError.GROUPINSTALLATIONFAILED)); |
146 | + } | ||
147 | + }).build(); | ||
145 | 148 | ||
149 | + pendingRemoveNextObjectives = CacheBuilder.newBuilder() | ||
150 | + .expireAfterWrite(20, TimeUnit.SECONDS) | ||
151 | + .removalListener(( | ||
152 | + RemovalNotification<NextObjective, List<GroupKey>> notification) -> { | ||
153 | + if (notification.getCause() == RemovalCause.EXPIRED) { | ||
154 | + Ofdpa2Pipeline.fail(notification.getKey(), | ||
155 | + ObjectiveError.GROUPREMOVALFAILED); | ||
146 | } | 156 | } |
147 | }).build(); | 157 | }).build(); |
148 | pendingGroups = new ConcurrentHashMap<>(); | 158 | pendingGroups = new ConcurrentHashMap<>(); |
... | @@ -1012,6 +1022,11 @@ public class Ofdpa2GroupHandler { | ... | @@ -1012,6 +1022,11 @@ public class Ofdpa2GroupHandler { |
1012 | */ | 1022 | */ |
1013 | protected void removeGroup(NextObjective nextObjective, NextGroup next) { | 1023 | protected void removeGroup(NextObjective nextObjective, NextGroup next) { |
1014 | List<Deque<GroupKey>> allgkeys = Ofdpa2Pipeline.appKryo.deserialize(next.data()); | 1024 | List<Deque<GroupKey>> allgkeys = Ofdpa2Pipeline.appKryo.deserialize(next.data()); |
1025 | + | ||
1026 | + List<GroupKey> groupKeys = allgkeys.stream() | ||
1027 | + .map(Deque::getFirst).collect(Collectors.toList()); | ||
1028 | + pendingRemoveNextObjectives.put(nextObjective, groupKeys); | ||
1029 | + | ||
1015 | allgkeys.forEach(groupChain -> groupChain.forEach(groupKey -> | 1030 | allgkeys.forEach(groupChain -> groupChain.forEach(groupKey -> |
1016 | groupService.removeGroup(deviceId, groupKey, nextObjective.appId()))); | 1031 | groupService.removeGroup(deviceId, groupKey, nextObjective.appId()))); |
1017 | flowObjectiveStore.removeNextGroup(nextObjective.id()); | 1032 | flowObjectiveStore.removeNextGroup(nextObjective.id()); |
... | @@ -1024,7 +1039,7 @@ public class Ofdpa2GroupHandler { | ... | @@ -1024,7 +1039,7 @@ public class Ofdpa2GroupHandler { |
1024 | private void updatePendingNextObjective(GroupKey key, OfdpaNextGroup value) { | 1039 | private void updatePendingNextObjective(GroupKey key, OfdpaNextGroup value) { |
1025 | List<OfdpaNextGroup> nextList = new CopyOnWriteArrayList<OfdpaNextGroup>(); | 1040 | List<OfdpaNextGroup> nextList = new CopyOnWriteArrayList<OfdpaNextGroup>(); |
1026 | nextList.add(value); | 1041 | nextList.add(value); |
1027 | - List<OfdpaNextGroup> ret = pendingNextObjectives.asMap() | 1042 | + List<OfdpaNextGroup> ret = pendingAddNextObjectives.asMap() |
1028 | .putIfAbsent(key, nextList); | 1043 | .putIfAbsent(key, nextList); |
1029 | if (ret != null) { | 1044 | if (ret != null) { |
1030 | ret.add(value); | 1045 | ret.add(value); |
... | @@ -1079,13 +1094,13 @@ public class Ofdpa2GroupHandler { | ... | @@ -1079,13 +1094,13 @@ public class Ofdpa2GroupHandler { |
1079 | Set<GroupKey> keys = pendingGroups.keySet().stream() | 1094 | Set<GroupKey> keys = pendingGroups.keySet().stream() |
1080 | .filter(key -> groupService.getGroup(deviceId, key) != null) | 1095 | .filter(key -> groupService.getGroup(deviceId, key) != null) |
1081 | .collect(Collectors.toSet()); | 1096 | .collect(Collectors.toSet()); |
1082 | - Set<GroupKey> otherkeys = pendingNextObjectives.asMap().keySet().stream() | 1097 | + Set<GroupKey> otherkeys = pendingAddNextObjectives.asMap().keySet().stream() |
1083 | .filter(otherkey -> groupService.getGroup(deviceId, otherkey) != null) | 1098 | .filter(otherkey -> groupService.getGroup(deviceId, otherkey) != null) |
1084 | .collect(Collectors.toSet()); | 1099 | .collect(Collectors.toSet()); |
1085 | keys.addAll(otherkeys); | 1100 | keys.addAll(otherkeys); |
1086 | 1101 | ||
1087 | keys.stream().forEach(key -> | 1102 | keys.stream().forEach(key -> |
1088 | - processPendingGroupsOrNextObjectives(key, false)); | 1103 | + processPendingAddGroupsOrNextObjs(key, false)); |
1089 | } | 1104 | } |
1090 | } | 1105 | } |
1091 | 1106 | ||
... | @@ -1093,14 +1108,20 @@ public class Ofdpa2GroupHandler { | ... | @@ -1093,14 +1108,20 @@ public class Ofdpa2GroupHandler { |
1093 | @Override | 1108 | @Override |
1094 | public void event(GroupEvent event) { | 1109 | public void event(GroupEvent event) { |
1095 | log.trace("received group event of type {}", event.type()); | 1110 | log.trace("received group event of type {}", event.type()); |
1096 | - if (event.type() == GroupEvent.Type.GROUP_ADDED) { | 1111 | + switch (event.type()) { |
1097 | - GroupKey key = event.subject().appCookie(); | 1112 | + case GROUP_ADDED: |
1098 | - processPendingGroupsOrNextObjectives(key, true); | 1113 | + processPendingAddGroupsOrNextObjs(event.subject().appCookie(), true); |
1114 | + break; | ||
1115 | + case GROUP_REMOVED: | ||
1116 | + processPendingRemoveNextObjs(event.subject().appCookie()); | ||
1117 | + break; | ||
1118 | + default: | ||
1119 | + break; | ||
1099 | } | 1120 | } |
1100 | } | 1121 | } |
1101 | } | 1122 | } |
1102 | 1123 | ||
1103 | - private void processPendingGroupsOrNextObjectives(GroupKey key, boolean added) { | 1124 | + private void processPendingAddGroupsOrNextObjs(GroupKey key, boolean added) { |
1104 | //first check for group chain | 1125 | //first check for group chain |
1105 | Set<GroupChainElem> gceSet = pendingGroups.remove(key); | 1126 | Set<GroupChainElem> gceSet = pendingGroups.remove(key); |
1106 | if (gceSet != null) { | 1127 | if (gceSet != null) { |
... | @@ -1114,9 +1135,9 @@ public class Ofdpa2GroupHandler { | ... | @@ -1114,9 +1135,9 @@ public class Ofdpa2GroupHandler { |
1114 | } | 1135 | } |
1115 | } else { | 1136 | } else { |
1116 | // otherwise chain complete - check for waiting nextObjectives | 1137 | // otherwise chain complete - check for waiting nextObjectives |
1117 | - List<OfdpaNextGroup> nextGrpList = pendingNextObjectives.getIfPresent(key); | 1138 | + List<OfdpaNextGroup> nextGrpList = pendingAddNextObjectives.getIfPresent(key); |
1118 | if (nextGrpList != null) { | 1139 | if (nextGrpList != null) { |
1119 | - pendingNextObjectives.invalidate(key); | 1140 | + pendingAddNextObjectives.invalidate(key); |
1120 | nextGrpList.forEach(nextGrp -> { | 1141 | nextGrpList.forEach(nextGrp -> { |
1121 | log.debug("Group service {} group key {} in device:{}. " | 1142 | log.debug("Group service {} group key {} in device:{}. " |
1122 | + "Done implementing next objective: {} <<-->> gid:0x{}", | 1143 | + "Done implementing next objective: {} <<-->> gid:0x{}", |
... | @@ -1137,6 +1158,17 @@ public class Ofdpa2GroupHandler { | ... | @@ -1137,6 +1158,17 @@ public class Ofdpa2GroupHandler { |
1137 | } | 1158 | } |
1138 | } | 1159 | } |
1139 | 1160 | ||
1161 | + private void processPendingRemoveNextObjs(GroupKey key) { | ||
1162 | + pendingRemoveNextObjectives.asMap().forEach((nextObjective, groupKeys) -> { | ||
1163 | + if (groupKeys.isEmpty()) { | ||
1164 | + pendingRemoveNextObjectives.invalidate(nextObjective); | ||
1165 | + Ofdpa2Pipeline.pass(nextObjective); | ||
1166 | + } else { | ||
1167 | + groupKeys.remove(key); | ||
1168 | + } | ||
1169 | + }); | ||
1170 | + } | ||
1171 | + | ||
1140 | protected int getNextAvailableIndex() { | 1172 | protected int getNextAvailableIndex() { |
1141 | return (int) nextIndex.incrementAndGet(); | 1173 | return (int) nextIndex.incrementAndGet(); |
1142 | } | 1174 | } | ... | ... |
-
Please register or login to post a comment