[SEBA-815]Multi Tcont support by OLT app.
[VOL-2525] Fixing the OLT app meter removal and optimizing the bandwith profile to meter map with a Multimap
Change-Id: I024ef2fcb3d3e59cc86bd2088726ae513fcff796
diff --git a/api/src/main/java/org/opencord/olt/AccessDeviceEvent.java b/api/src/main/java/org/opencord/olt/AccessDeviceEvent.java
index 3c189dd..3a4146c 100644
--- a/api/src/main/java/org/opencord/olt/AccessDeviceEvent.java
+++ b/api/src/main/java/org/opencord/olt/AccessDeviceEvent.java
@@ -29,21 +29,12 @@
private final Optional<VlanId> sVlan;
private final Optional<VlanId> cVlan;
+ private final Optional<Integer> tpId;
private final Optional<Port> port;
public enum Type {
/**
- * A subscriber was registered and provisioned.
- */
- SUBSCRIBER_REGISTERED,
-
- /**
- * A subscriber was unregistered and deprovisioned.
- */
- SUBSCRIBER_UNREGISTERED,
-
- /**
* An access device connected.
*/
DEVICE_CONNECTED,
@@ -61,55 +52,87 @@
/**
* An existing UNI port was removed.
*/
- UNI_REMOVED
+ UNI_REMOVED,
+
+ /**
+ * A uniTag (one service) was registered and provisioned.
+ */
+ SUBSCRIBER_UNI_TAG_REGISTERED,
+
+ /**
+ * A uniTag (one service) was unregistered and deprovisioned.
+ */
+ SUBSCRIBER_UNI_TAG_UNREGISTERED,
+
+ /**
+ * A uniTag (one service) was failed while registration.
+ */
+ SUBSCRIBER_UNI_TAG_REGISTRATION_FAILED,
+
+ /**
+ * A uniTag (one service) was failed while unregistration.
+ */
+ SUBSCRIBER_UNI_TAG_UNREGISTRATION_FAILED
}
/**
+ * Creates an event of a given type and for the specified device, port,
+ * along with the cVlanId, sVlanId, and tpId. The vlan fields may not be provisioned
+ * if the event is related to the access device (dis)connection.
*
+ * @param type the event type
+ * @param deviceId the device id
+ * @param port the device port
+ * @param sVlanId the service vlan
+ * @param cVlanId the customer vlan
+ * @param tpId the technology profile
+ */
+ public AccessDeviceEvent(Type type, DeviceId deviceId,
+ Port port,
+ VlanId sVlanId,
+ VlanId cVlanId,
+ Integer tpId) {
+ super(type, deviceId);
+ this.port = Optional.ofNullable(port);
+ this.sVlan = Optional.ofNullable(sVlanId);
+ this.cVlan = Optional.ofNullable(cVlanId);
+ this.tpId = Optional.ofNullable(tpId);
+ }
+
+ /**
* Creates an event of a given type and for the specified device,
* along with the cVlanId and sVlanId. The vlan fields may not be provisioned
* if the event is related to the access device (dis)connection.
*
- * @param type the event type
+ * @param type the event type
* @param deviceId the device id
- * @param sVlanId the service vlan
- * @param cVlanId the customer vlan
+ * @param sVlanId the service vlan
+ * @param cVlanId the customer vlan
+ * @param tpId the technology profile id
*/
public AccessDeviceEvent(Type type, DeviceId deviceId,
VlanId sVlanId,
- VlanId cVlanId) {
+ VlanId cVlanId,
+ Integer tpId) {
super(type, deviceId);
this.sVlan = Optional.ofNullable(sVlanId);
this.cVlan = Optional.ofNullable(cVlanId);
+ this.tpId = Optional.ofNullable(tpId);
this.port = Optional.empty();
}
/**
+ * Creates an event of a given type and for the specified device and port.
*
- * Creates an event of a given type and for the specified device, and timestamp
- * along with the cVlanId and sVlanId. The vlan fields may not be provisioned
- * if the event is related to the access device (dis)connection.
- *
- * @param type the event type
+ * @param type the event type
* @param deviceId the device id
- * @param time a timestamp
- * @param sVlanId the service vlan
- * @param cVlanId the customer vlan
+ * @param port the device port
*/
- protected AccessDeviceEvent(Type type, DeviceId deviceId, long time,
- VlanId sVlanId,
- VlanId cVlanId) {
- super(type, deviceId, time);
- this.sVlan = Optional.ofNullable(sVlanId);
- this.cVlan = Optional.ofNullable(cVlanId);
- this.port = Optional.empty();
-
- }
-
public AccessDeviceEvent(Type type, DeviceId deviceId, Port port) {
super(type, deviceId);
this.sVlan = Optional.empty();
this.cVlan = Optional.empty();
+ this.tpId = Optional.empty();
this.port = Optional.ofNullable(port);
}
@@ -125,4 +148,8 @@
return port;
}
+ public Optional<Integer> tpId() {
+ return tpId;
+ }
+
}
diff --git a/api/src/main/java/org/opencord/olt/AccessDeviceService.java b/api/src/main/java/org/opencord/olt/AccessDeviceService.java
index 32c2ed0..06c5188 100644
--- a/api/src/main/java/org/opencord/olt/AccessDeviceService.java
+++ b/api/src/main/java/org/opencord/olt/AccessDeviceService.java
@@ -16,20 +16,17 @@
package org.opencord.olt;
-import java.util.Collection;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
+import java.util.Set;
-import com.google.common.collect.ImmutableSet;
import org.onlab.packet.VlanId;
import org.onosproject.event.ListenerService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
-import org.onosproject.net.meter.MeterKey;
-import org.opencord.sadis.SubscriberAndDeviceInformation;
import com.google.common.collect.ImmutableMap;
+import org.opencord.sadis.UniTagInformation;
/**
* Service for interacting with an access device (OLT).
@@ -39,6 +36,7 @@
/**
* Provisions connectivity for a subscriber on an access device.
+ * Installs flows for all uni tag information
*
* @param port subscriber's connection point
* @return true if successful false otherwise
@@ -47,6 +45,7 @@
/**
* Removes provisioned connectivity for a subscriber from an access device.
+ * Removes flows for all uni tag information
*
* @param port subscriber's connection point
* @return true if successful false otherwise
@@ -54,31 +53,32 @@
boolean removeSubscriber(ConnectPoint port);
/**
- * Provisions flows for the specific subscriber.
+ * Provisions a uni tag information for the specific subscriber.
+ * It finds the related uni tag information from the subscriber uni tag list
+ * and installs it
*
* @param subscriberId Identification of the subscriber
- * @param sTag additional outer tag on this port
- * @param cTag additional inner tag on this port
+ * @param sTag additional outer tag on this port
+ * @param cTag additional inner tag on this port
+ * @param tpId additional technology profile id
* @return true if successful false otherwise
*/
- boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag);
+ boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag,
+ Optional<VlanId> cTag, Optional<Integer> tpId);
/**
- * Removes flows for the specific subscriber.
+ * Removes a uni tag information for the specific subscriber.
+ * It finds the related uni tag information from the subscriber uni tag list
+ * and remove it
*
* @param subscriberId Identification of the subscriber
- * @param sTag additional outer tag on this port
- * @param cTag additional inner tag on this port
+ * @param sTag additional outer tag on this port
+ * @param cTag additional inner tag on this port
+ * @param tpId additional technology profile id
* @return true if successful false otherwise
*/
- boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag);
-
- /**
- * Returns information about the provisioned subscribers.
- *
- * @return subscribers
- */
- Collection<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> getSubscribers();
+ boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag,
+ Optional<VlanId> cTag, Optional<Integer> tpId);
/**
* Returns the list of active OLTs.
@@ -89,26 +89,11 @@
/**
* Returns information about subscribers that have been programmed in the
- * data-plane.
+ * data-plane. It shows all uni tag information list of the subscribers even if
+ * these have not been programmed.
*
* @return an immutable map of locations and subscriber information
*/
- ImmutableMap<ConnectPoint, SubscriberAndDeviceInformation> getProgSubs();
-
- /**
- * Returns information about device-meter mappings that have been programmed in the
- * data-plane.
- *
- * @return an immutable set of device-meter mappings
- */
- ImmutableSet<MeterKey> getProgMeters();
-
- /**
- * Returns information about bandwidthProfile-meterKey (device / meter) mappings
- * that have been programmed in the data-plane.
- *
- * @return an immutable map of bandwidthProfile-meterKey (device / meter) mappings
- */
- ImmutableMap<String, List<MeterKey>> getBpMeterMappings();
+ ImmutableMap<ConnectPoint, Set<UniTagInformation>> getProgSubs();
}
diff --git a/app/src/main/java/org/opencord/olt/cli/ShowBpMeterMappingsCommand.java b/app/src/main/java/org/opencord/olt/cli/ShowBpMeterMappingsCommand.java
index 3eec456..eb1b47d 100644
--- a/app/src/main/java/org/opencord/olt/cli/ShowBpMeterMappingsCommand.java
+++ b/app/src/main/java/org/opencord/olt/cli/ShowBpMeterMappingsCommand.java
@@ -20,9 +20,9 @@
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.meter.MeterKey;
-import org.opencord.olt.AccessDeviceService;
+import org.opencord.olt.internalapi.AccessDeviceMeterService;
-import java.util.List;
+import java.util.Collection;
import java.util.Map;
@Service
@@ -32,12 +32,12 @@
@Override
protected void doExecute() {
- AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
- Map<String, List<MeterKey>> bpMeterMappings = service.getBpMeterMappings();
+ AccessDeviceMeterService service = AbstractShellCommand.get(AccessDeviceMeterService.class);
+ Map<String, Collection<MeterKey>> bpMeterMappings = service.getBpMeterMappings();
bpMeterMappings.forEach(this::display);
}
- private void display(String bpInfo, List<MeterKey> meterKeyList) {
+ private void display(String bpInfo, Collection<MeterKey> meterKeyList) {
meterKeyList.forEach(meterKey ->
print("bpInfo=%s deviceId=%s meterId=%s",
bpInfo, meterKey.deviceId(), meterKey.meterId()));
diff --git a/app/src/main/java/org/opencord/olt/cli/ShowOltCommand.java b/app/src/main/java/org/opencord/olt/cli/ShowOltCommand.java
index 18aa935..e67c05f 100644
--- a/app/src/main/java/org/opencord/olt/cli/ShowOltCommand.java
+++ b/app/src/main/java/org/opencord/olt/cli/ShowOltCommand.java
@@ -32,8 +32,6 @@
@Override
protected void doExecute() {
AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
- service.fetchOlts().forEach(did -> {
- print("OLT %s", did);
- });
+ service.fetchOlts().forEach(did -> print("OLT %s", did));
}
}
diff --git a/app/src/main/java/org/opencord/olt/cli/ShowProgrammedMetersCommand.java b/app/src/main/java/org/opencord/olt/cli/ShowProgrammedMetersCommand.java
index f4734d4..a7dbd39 100644
--- a/app/src/main/java/org/opencord/olt/cli/ShowProgrammedMetersCommand.java
+++ b/app/src/main/java/org/opencord/olt/cli/ShowProgrammedMetersCommand.java
@@ -20,7 +20,7 @@
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.meter.MeterKey;
-import org.opencord.olt.AccessDeviceService;
+import org.opencord.olt.internalapi.AccessDeviceMeterService;
import java.util.Set;
@@ -35,7 +35,7 @@
@Override
protected void doExecute() {
- AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
+ AccessDeviceMeterService service = AbstractShellCommand.get(AccessDeviceMeterService.class);
Set<MeterKey> programmedMeters = service.getProgMeters();
programmedMeters.forEach(this::display);
}
diff --git a/app/src/main/java/org/opencord/olt/cli/ShowProgrammedSubscribersCommand.java b/app/src/main/java/org/opencord/olt/cli/ShowProgrammedSubscribersCommand.java
index 22acb57..413272b 100644
--- a/app/src/main/java/org/opencord/olt/cli/ShowProgrammedSubscribersCommand.java
+++ b/app/src/main/java/org/opencord/olt/cli/ShowProgrammedSubscribersCommand.java
@@ -21,9 +21,10 @@
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.ConnectPoint;
import org.opencord.olt.AccessDeviceService;
-import org.opencord.sadis.SubscriberAndDeviceInformation;
+import org.opencord.sadis.UniTagInformation;
import java.util.Map;
+import java.util.Set;
/**
* Shows subscriber information for those subscriber which have been programmed
@@ -37,11 +38,12 @@
@Override
protected void doExecute() {
AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
- Map<ConnectPoint, SubscriberAndDeviceInformation> info = service.getProgSubs();
+ Map<ConnectPoint, Set<UniTagInformation>> info = service.getProgSubs();
info.forEach(this::display);
}
- private void display(ConnectPoint cp, SubscriberAndDeviceInformation sub) {
- print("location=%s subscriber=%s", cp, sub);
+ private void display(ConnectPoint cp, Set<UniTagInformation> uniTagInformation) {
+ uniTagInformation.forEach(uniTag ->
+ print("location=%s tagInformation=%s", cp, uniTag));
}
}
diff --git a/app/src/main/java/org/opencord/olt/cli/ShowSubscribersCommand.java b/app/src/main/java/org/opencord/olt/cli/ShowSubscribersCommand.java
deleted file mode 100644
index 4d2d583..0000000
--- a/app/src/main/java/org/opencord/olt/cli/ShowSubscribersCommand.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2016-present Open Networking Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.opencord.olt.cli;
-
-import org.apache.karaf.shell.api.action.Command;
-import org.apache.karaf.shell.api.action.lifecycle.Service;
-import org.onlab.packet.VlanId;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.net.ConnectPoint;
-import org.opencord.olt.AccessDeviceService;
-
-import java.util.Map;
-
-/**
- * Shows provisioned (configured) subscribers. The data plane flows for the
- * subscribers may or may not have been programmed.
- */
-@Service
-@Command(scope = "onos", name = "volt-subscribers",
- description = "Shows pre-provisioned subscribers")
-public class ShowSubscribersCommand extends AbstractShellCommand {
-
- private static final String FORMAT = "port=%s, svlan=%s, cvlan=%s";
-
- @Override
- protected void doExecute() {
- AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
- service.getSubscribers().forEach(this::display);
- }
-
- private void display(Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>> subscriber) {
- print(FORMAT, subscriber.getKey(), subscriber.getValue().getKey(),
- subscriber.getValue().getValue());
- }
-}
diff --git a/app/src/main/java/org/opencord/olt/cli/UniTagAddCommand.java b/app/src/main/java/org/opencord/olt/cli/UniTagAddCommand.java
new file mode 100644
index 0000000..4eb6495
--- /dev/null
+++ b/app/src/main/java/org/opencord/olt/cli/UniTagAddCommand.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opencord.olt.cli;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.onlab.packet.VlanId;
+import org.onosproject.cli.AbstractShellCommand;
+import org.opencord.olt.AccessDeviceService;
+import org.opencord.olt.AccessSubscriberId;
+
+import java.util.Optional;
+
+/**
+ * Adds a subscriber uni tag.
+ */
+@Service
+@Command(scope = "onos", name = "volt-add-subscriber-unitag",
+ description = "Adds a uni tag to an access device")
+public class UniTagAddCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "portName", description = "Port name",
+ required = true, multiValued = false)
+ private String strPortName = null;
+
+ @Option(name = "--cTag", description = "Inner vlan id",
+ required = false, multiValued = false)
+ private String strCtag = null;
+
+ @Option(name = "--sTag", description = "Outer vlan id",
+ required = false, multiValued = false)
+ private String strStag = null;
+
+ @Option(name = "--tpId", description = "Technology profile id",
+ required = false, multiValued = false)
+ private String strTpId = null;
+
+ @Override
+ protected void doExecute() {
+
+ AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
+ AccessSubscriberId portName = new AccessSubscriberId(strPortName);
+
+ Optional<VlanId> cTag = strCtag == null ? Optional.empty() : Optional.of(VlanId.vlanId(strCtag));
+ Optional<VlanId> sTag = strStag == null ? Optional.empty() : Optional.of(VlanId.vlanId(strStag));
+ Optional<Integer> tpId = strTpId == null ? Optional.empty() : Optional.of(Integer.parseInt(strTpId));
+ service.provisionSubscriber(portName, sTag, cTag, tpId);
+ }
+}
diff --git a/app/src/main/java/org/opencord/olt/cli/UniTagRemoveCommand.java b/app/src/main/java/org/opencord/olt/cli/UniTagRemoveCommand.java
new file mode 100644
index 0000000..6ebe17a
--- /dev/null
+++ b/app/src/main/java/org/opencord/olt/cli/UniTagRemoveCommand.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.opencord.olt.cli;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.jvnet.hk2.annotations.Service;
+import org.onlab.packet.VlanId;
+import org.onosproject.cli.AbstractShellCommand;
+import org.opencord.olt.AccessDeviceService;
+import org.opencord.olt.AccessSubscriberId;
+
+import java.util.Optional;
+
+/**
+ * Removes a uni tag from a subscriber (portname).
+ */
+@Service
+@Command(scope = "onos", name = "volt-remove-subscriber-unitag",
+ description = "Removes a uni tag from an access device")
+public class UniTagRemoveCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "portName", description = "Port name",
+ required = true, multiValued = false)
+ private String strPortName = null;
+
+ @Option(name = "--cTag", description = "Inner vlan id",
+ required = false, multiValued = false)
+ private String strCtag = null;
+
+ @Option(name = "--sTag", description = "Outer vlan id",
+ required = false, multiValued = false)
+ private String strStag = null;
+
+ @Option(name = "--tpId", description = "Technology profile id",
+ required = false, multiValued = false)
+ private String strTpId = null;
+
+ @Override
+ protected void doExecute() {
+
+ AccessDeviceService service = AbstractShellCommand.get(AccessDeviceService.class);
+ AccessSubscriberId portName = new AccessSubscriberId(strPortName);
+
+ Optional<VlanId> cTag = strCtag == null ? Optional.empty() : Optional.of(VlanId.vlanId(strCtag));
+ Optional<VlanId> sTag = strStag == null ? Optional.empty() : Optional.of(VlanId.vlanId(strStag));
+ Optional<Integer> tpId = strTpId == null ? Optional.empty() : Optional.of(Integer.parseInt(strTpId));
+ service.removeSubscriber(portName, sTag, cTag, tpId);
+ }
+}
diff --git a/app/src/main/java/org/opencord/olt/impl/Olt.java b/app/src/main/java/org/opencord/olt/impl/Olt.java
index 3775060..e392b41 100644
--- a/app/src/main/java/org/opencord/olt/impl/Olt.java
+++ b/app/src/main/java/org/opencord/olt/impl/Olt.java
@@ -16,15 +16,9 @@
package org.opencord.olt.impl;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-import org.onlab.packet.EthType;
-import org.onlab.packet.IPv4;
-import org.onlab.packet.IPv6;
-import org.onlab.packet.TpPort;
import org.onlab.packet.VlanId;
-import org.onlab.util.Tools;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
@@ -39,43 +33,23 @@
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.flow.DefaultTrafficSelector;
-import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.TrafficSelector;
-import org.onosproject.net.flow.TrafficTreatment;
-import org.onosproject.net.flow.criteria.Criteria;
-import org.onosproject.net.flowobjective.DefaultFilteringObjective;
-import org.onosproject.net.flowobjective.DefaultForwardingObjective;
-import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.flowobjective.ObjectiveContext;
import org.onosproject.net.flowobjective.ObjectiveError;
-import org.onosproject.net.meter.Band;
-import org.onosproject.net.meter.DefaultBand;
-import org.onosproject.net.meter.DefaultMeterRequest;
-import org.onosproject.net.meter.Meter;
-import org.onosproject.net.meter.MeterContext;
-import org.onosproject.net.meter.MeterEvent;
-import org.onosproject.net.meter.MeterFailReason;
import org.onosproject.net.meter.MeterId;
-import org.onosproject.net.meter.MeterKey;
-import org.onosproject.net.meter.MeterListener;
-import org.onosproject.net.meter.MeterRequest;
-import org.onosproject.net.meter.MeterService;
-import org.onosproject.store.serializers.KryoNamespaces;
-import org.onosproject.store.service.ConsistentMultimap;
-import org.onosproject.store.service.Serializer;
-import org.onosproject.store.service.StorageService;
import org.opencord.olt.AccessDeviceEvent;
import org.opencord.olt.AccessDeviceListener;
import org.opencord.olt.AccessDeviceService;
import org.opencord.olt.AccessSubscriberId;
+import org.opencord.olt.internalapi.AccessDeviceFlowService;
+import org.opencord.olt.internalapi.AccessDeviceMeterService;
import org.opencord.sadis.BandwidthProfileInformation;
import org.opencord.sadis.BaseInformationService;
import org.opencord.sadis.SadisService;
import org.opencord.sadis.SubscriberAndDeviceInformation;
+import org.opencord.sadis.UniTagInformation;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
@@ -85,10 +59,7 @@
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.slf4j.Logger;
-import java.util.AbstractMap;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.Dictionary;
import java.util.List;
import java.util.Map;
@@ -97,34 +68,15 @@
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Strings.isNullOrEmpty;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static org.onlab.util.Tools.get;
import static org.onlab.util.Tools.groupedThreads;
-import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_BP_ID;
-import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_BP_ID_DEFAULT;
-import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_TP_ID;
-import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_TP_ID_DEFAULT;
-import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_VLAN;
-import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_VLAN_DEFAULT;
-import static org.opencord.olt.impl.OsgiPropertyConstants.DELETE_METERS;
-import static org.opencord.olt.impl.OsgiPropertyConstants.DELETE_METERS_DEFAULT;
-import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_ON_PROVISIONING;
-import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_ON_PROVISIONING_DEFAULT;
-import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_V4;
-import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_V4_DEFAULT;
-import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_V6;
-import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_DHCP_V6_DEFAULT;
-import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_EAPOL;
-import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_EAPOL_DEFAULT;
-import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_IGMP_ON_PROVISIONING;
-import static org.opencord.olt.impl.OsgiPropertyConstants.ENABLE_IGMP_ON_PROVISIONING_DEFAULT;
+import static org.opencord.olt.impl.OsgiPropertyConstants.*;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -132,15 +84,8 @@
*/
@Component(immediate = true,
property = {
- DEFAULT_VLAN + ":Integer=" + DEFAULT_VLAN_DEFAULT,
- ENABLE_DHCP_ON_PROVISIONING + ":Boolean=" + ENABLE_DHCP_ON_PROVISIONING_DEFAULT,
- ENABLE_DHCP_V4 + ":Boolean=" + ENABLE_DHCP_V4_DEFAULT,
- ENABLE_DHCP_V6 + ":Boolean=" + ENABLE_DHCP_V6_DEFAULT,
- ENABLE_IGMP_ON_PROVISIONING + ":Boolean=" + ENABLE_IGMP_ON_PROVISIONING_DEFAULT,
- DELETE_METERS + ":Boolean=" + DELETE_METERS_DEFAULT,
- DEFAULT_TP_ID + ":Integer=" + DEFAULT_TP_ID_DEFAULT,
DEFAULT_BP_ID + ":String=" + DEFAULT_BP_ID_DEFAULT,
- ENABLE_EAPOL + ":Boolean=" + ENABLE_EAPOL_DEFAULT,
+ DEFAULT_MCAST_SERVICE_NAME + ":String=" + DEFAULT_MCAST_SERVICE_NAME_DEFAULT,
})
public class Olt
extends AbstractListenerManager<AccessDeviceEvent, AccessDeviceListener>
@@ -148,12 +93,7 @@
private static final String APP_NAME = "org.opencord.olt";
private static final short EAPOL_DEFAULT_VLAN = 4091;
- private static final String ADDITIONAL_VLANS = "additional-vlans";
private static final String NO_UPLINK_PORT = "No uplink port found for OLT device {}";
- private static final String INSTALLED = "installed";
- private static final String REMOVED = "removed";
- private static final String INSTALLATION = "installation";
- private static final String REMOVAL = "removal";
private final Logger log = getLogger(getClass());
@@ -176,45 +116,10 @@
protected SadisService sadisService;
@Reference(cardinality = ReferenceCardinality.MANDATORY)
- protected MeterService meterService;
+ protected AccessDeviceFlowService oltFlowService;
@Reference(cardinality = ReferenceCardinality.MANDATORY)
- protected StorageService storageService;
-
- /**
- * Default VLAN RG<->ONU traffic.
- **/
- private int defaultVlan = DEFAULT_VLAN_DEFAULT;
-
- /**
- * Create the DHCP Flow rules when a subscriber is provisioned.
- **/
- protected boolean enableDhcpOnProvisioning = ENABLE_DHCP_ON_PROVISIONING_DEFAULT;
-
- /**
- * Enable flows for DHCP v4.
- **/
- protected boolean enableDhcpV4 = ENABLE_DHCP_V4_DEFAULT;
-
- /**
- * Enable flows for DHCP v6.
- **/
- protected boolean enableDhcpV6 = ENABLE_DHCP_V6_DEFAULT;
-
- /**
- * Create IGMP Flow rules when a subscriber is provisioned.
- **/
- protected boolean enableIgmpOnProvisioning = ENABLE_IGMP_ON_PROVISIONING_DEFAULT;
-
- /**
- * Deleting Meters based on flow count statistics.
- **/
- protected boolean deleteMeters = DELETE_METERS_DEFAULT;
-
- /**
- * Default technology profile id that is used for authentication trap flows.
- **/
- protected int defaultTechProfileId = DEFAULT_TP_ID_DEFAULT;
+ protected AccessDeviceMeterService oltMeterService;
/**
* Default bandwidth profile id that is used for authentication trap flows.
@@ -222,49 +127,41 @@
protected String defaultBpId = DEFAULT_BP_ID_DEFAULT;
/**
- * Send EAPOL authentication trap flows before subscriber provisioning.
+ * Deleting Meters based on flow count statistics.
**/
- protected boolean enableEapol = ENABLE_EAPOL_DEFAULT;
+ protected String multicastServiceName = DEFAULT_MCAST_SERVICE_NAME;
private final DeviceListener deviceListener = new InternalDeviceListener();
- private final MeterListener meterListener = new InternalMeterListener();
- private ApplicationId appId;
protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
private BaseInformationService<BandwidthProfileInformation> bpService;
- private Map<String, List<MeterKey>> bpInfoToMeter = new ConcurrentHashMap<>();
-
private ExecutorService oltInstallers = Executors.newFixedThreadPool(4,
- groupedThreads("onos/olt-service",
- "olt-installer-%d"));
-
- private ConsistentMultimap<ConnectPoint, Map.Entry<VlanId, VlanId>> additionalVlans;
+ groupedThreads("onos/olt-service",
+ "olt-installer-%d"));
protected ExecutorService eventExecutor;
- private Map<ConnectPoint, SubscriberAndDeviceInformation> programmedSubs;
- private Set<MeterKey> programmedMeters;
-
+ private Map<ConnectPoint, Set<UniTagInformation>> programmedSubs;
@Activate
public void activate(ComponentContext context) {
- eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt", "events-%d", log));
+ eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/olt",
+ "events-%d", log));
modified(context);
- appId = coreService.registerApplication(APP_NAME);
+ ApplicationId appId = coreService.registerApplication(APP_NAME);
// ensure that flow rules are purged from flow-store upon olt-disconnection
// when olt reconnects, the port-numbers may change for the ONUs
// making flows pushed earlier invalid
componentConfigService
.preSetProperty("org.onosproject.net.flow.impl.FlowRuleManager",
- "purgeOnDisconnection", "true");
+ "purgeOnDisconnection", "true");
componentConfigService
.preSetProperty("org.onosproject.net.meter.impl.MeterManager",
- "purgeOnDisconnection", "true");
+ "purgeOnDisconnection", "true");
componentConfigService.registerProperties(getClass());
programmedSubs = Maps.newConcurrentMap();
- programmedMeters = ConcurrentHashMap.newKeySet();
eventDispatcher.addSink(AccessDeviceEvent.class, listenerRegistry);
@@ -278,15 +175,7 @@
checkAndCreateDeviceFlows(d);
}
- additionalVlans = storageService.<ConnectPoint, Map.Entry<VlanId, VlanId>>consistentMultimapBuilder()
- .withName(ADDITIONAL_VLANS)
- .withSerializer(Serializer.using(Arrays.asList(KryoNamespaces.API),
- AbstractMap.SimpleEntry.class))
- .build();
-
deviceService.addListener(deviceListener);
- meterService.addListener(meterListener);
-
log.info("Started with Application ID {}", appId.id());
}
@@ -294,7 +183,6 @@
public void deactivate() {
componentConfigService.unregisterProperties(getClass(), false);
deviceService.removeListener(deviceListener);
- meterService.removeListener(meterListener);
eventDispatcher.removeSink(AccessDeviceEvent.class);
log.info("Stopped");
}
@@ -304,50 +192,16 @@
Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
try {
- String s = get(properties, "defaultVlan");
- defaultVlan = isNullOrEmpty(s) ? DEFAULT_VLAN_DEFAULT : Integer.parseInt(s.trim());
-
- Boolean o = Tools.isPropertyEnabled(properties, "enableDhcpOnProvisioning");
- if (o != null) {
- enableDhcpOnProvisioning = o;
- }
-
- Boolean v4 = Tools.isPropertyEnabled(properties, "enableDhcpV4");
- if (v4 != null) {
- enableDhcpV4 = v4;
- }
-
- Boolean v6 = Tools.isPropertyEnabled(properties, "enableDhcpV6");
- if (v6 != null) {
- enableDhcpV6 = v6;
- }
-
- Boolean p = Tools.isPropertyEnabled(properties, "enableIgmpOnProvisioning");
- if (p != null) {
- enableIgmpOnProvisioning = p;
- }
-
- log.info("DHCP Settings [enableDhcpOnProvisioning: {}, enableDhcpV4: {}, enableDhcpV6: {}]",
- enableDhcpOnProvisioning, enableDhcpV4, enableDhcpV6);
-
- Boolean d = Tools.isPropertyEnabled(properties, "deleteMeters");
- if (d != null) {
- deleteMeters = d;
- }
-
- String tpId = get(properties, "defaultTechProfileId");
- defaultTechProfileId = isNullOrEmpty(s) ? DEFAULT_TP_ID_DEFAULT : Integer.parseInt(tpId.trim());
-
String bpId = get(properties, "defaultBpId");
defaultBpId = bpId;
- Boolean eap = Tools.isPropertyEnabled(properties, "enableEapol");
- if (eap != null) {
- enableEapol = eap;
- }
+ String mcastSN = get(properties, "multicastServiceName");
+ multicastServiceName = mcastSN;
+
+ log.debug("OLT properties: DefaultBpId: {}, MulticastServiceName: {}", defaultBpId, multicastServiceName);
} catch (Exception e) {
- defaultVlan = DEFAULT_VLAN_DEFAULT;
+ log.error("Error while modifying the properties", e);
}
}
@@ -358,15 +212,7 @@
PortNumber subscriberPortNo = connectPoint.port();
checkNotNull(deviceService.getPort(deviceId, subscriberPortNo),
- "Invalid connect point");
-
- // If the subscriber is modified then first remove the previous and proceed
- SubscriberAndDeviceInformation subscriber = programmedSubs.get(connectPoint);
- if (subscriber != null) {
- log.info("Subscriber on connectionPoint {} was previously programmed, " +
- "remove it before adding again", connectPoint);
- removeSubscriber(connectPoint);
- }
+ "Invalid connect point:" + connectPoint);
// Find the subscriber on this connect point
SubscriberAndDeviceInformation sub = getSubscriber(connectPoint);
@@ -382,37 +228,17 @@
return false;
}
- SubscriberAndDeviceInformation prgSub = programmedSubs.get(connectPoint);
- if (prgSub != null) {
- log.warn("Subscriber {} on connectionPoint {} was previously programmed .. "
- + "taking no action. Note that updating a subscribers params "
- + "(vlans, bw, tpid etc) requires removing the subscriber"
- + "before re-provisioning the subscriber", prgSub.id(),
- connectPoint);
- return true;
- }
-
//delete Eapol authentication flow with default bandwidth
//wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
- CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
- processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, filterFuture,
- VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
- // do not remove meter from bpInfoToMeter mapping as flows for other ONUs
- // could still be using it - this also prevents duplicate meters from being
- // created for the same bandwidth profile
- // we still need to remove from programmedMeters so the meter can be
- // deleted if its reference count drops to zero
- removeMeterIdFromPrgMeters(deviceId, defaultBpId);
-
//install subscriber flows
+ CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
+ oltFlowService.processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId, filterFuture,
+ VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
filterFuture.thenAcceptAsync(filterStatus -> {
if (filterStatus == null) {
- provisionSubscriberBasedFlows(connectPoint, uplinkPort.number(), Optional.empty(), sub);
+ provisionUniTagList(connectPoint, uplinkPort.number(), sub);
}
});
-
- // cache subscriber info
- programmedSubs.put(connectPoint, sub);
return true;
}
@@ -425,10 +251,10 @@
DeviceId deviceId = connectPoint.deviceId();
PortNumber subscriberPortNo = connectPoint.port();
- SubscriberAndDeviceInformation subscriber = programmedSubs.get(connectPoint);
- if (subscriber == null) {
+ Set<UniTagInformation> uniTagInformationSet = programmedSubs.get(connectPoint);
+ if (uniTagInformationSet == null || uniTagInformationSet.isEmpty()) {
log.warn("Subscriber on connectionPoint {} was not previously programmed, " +
- "no need to remove it", connectPoint);
+ "no need to remove it", connectPoint);
return true;
}
@@ -439,53 +265,38 @@
return false;
}
- //delete dhcp & igmp trap flows
- MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.upstreamBandwidthProfile());
+ for (UniTagInformation uniTag : uniTagInformationSet) {
- // remove dhcp filters
- processDhcpFilteringObjectives(deviceId, subscriberPortNo,
- upstreamMeterId, subscriber.technologyProfileId(), false, true);
+ if (multicastServiceName.equals(uniTag.getServiceName())) {
+ continue;
+ }
- // remove igmp filters
- processIgmpFilteringObjectives(deviceId, subscriberPortNo,
- upstreamMeterId, subscriber.technologyProfileId(), false);
+ unprovisionVlans(deviceId, uplinkPort.number(), subscriberPortNo, uniTag);
- //unprovision vlans
- unprovisionVlans(deviceId, uplinkPort.number(), subscriberPortNo, subscriber, Optional.empty());
+ // re-install eapol with default bandwidth profile
+ oltFlowService.processEapolFilteringObjectives(deviceId, subscriberPortNo,
+ uniTag.getUpstreamBandwidthProfile(),
+ null, uniTag.getPonCTag(), false);
- // Remove if there are any flows for the additional Vlans
- Collection<? extends Map.Entry<VlanId, VlanId>> vlansList = additionalVlans.get(connectPoint).value();
-
- // Remove the flows for the additional vlans for this subscriber
- for (Map.Entry<VlanId, VlanId> vlans : vlansList) {
- unprovisionTransparentFlows(deviceId, uplinkPort.number(), subscriberPortNo,
- vlans.getValue(), vlans.getKey());
-
- // Remove it from the map also
- additionalVlans.remove(connectPoint, vlans);
+ Port port = deviceService.getPort(deviceId, subscriberPortNo);
+ if (port != null && port.isEnabled()) {
+ oltFlowService.processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId,
+ null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
+ } else {
+ log.debug("Port {} is no longer enabled or it's unavailable. Not "
+ + "reprogramming default eapol flow", connectPoint);
+ }
}
-
- // re-install eapol with default bandwidth profile
- processEapolFilteringObjectives(deviceId, subscriberPortNo,
- subscriber.upstreamBandwidthProfile(), null, subscriber.cTag(), false);
-
- Port port = deviceService.getPort(deviceId, subscriberPortNo);
- if (port != null && port.isEnabled()) {
- processEapolFilteringObjectives(deviceId, subscriberPortNo, defaultBpId,
- null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
- } else {
- log.debug("Port {} is no longer enabled or it's unavailable. Not "
- + "reprogramming default eapol flow", connectPoint);
- }
-
- programmedSubs.remove(connectPoint);
return true;
}
- @Override
- public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
- log.info("Provisioning subscriber using subscriberId {}, sTag {}, cTag {}", subscriberId, sTag, cTag);
+ @Override
+ public boolean provisionSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag,
+ Optional<VlanId> cTag, Optional<Integer> tpId) {
+
+ log.info("Provisioning subscriber using subscriberId {}, sTag {}, cTag {}, tpId {}" +
+ "", subscriberId, sTag, cTag, tpId);
// Check if we can find the connect point to which this subscriber is connected
ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
@@ -496,31 +307,23 @@
if (!sTag.isPresent() && !cTag.isPresent()) {
return provisionSubscriber(subsPort);
- } else if (sTag.isPresent() && cTag.isPresent()) {
+ } else if (sTag.isPresent() && cTag.isPresent() && tpId.isPresent()) {
Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
if (uplinkPort == null) {
log.warn(NO_UPLINK_PORT, subsPort.deviceId());
return false;
}
- CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
-
//delete Eapol authentication flow with default bandwidth
//wait until Eapol rule with defaultBpId is removed to install subscriber-based rules
- processEapolFilteringObjectives(subsPort.deviceId(), subsPort.port(), defaultBpId, filterFuture,
- VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
- // do not remove meter from bpInfoToMeter mapping as flows for other ONUs
- // could still be using it - this also prevents duplicate meters from being
- // created for the same bandwidth profile
- // we still need to remove from programmedMeters so the meter can be
- // deleted if its reference count drops to zero
- removeMeterIdFromPrgMeters(subsPort.deviceId(), defaultBpId);
-
//install subscriber flows
+ CompletableFuture<ObjectiveError> filterFuture = new CompletableFuture();
+ oltFlowService.processEapolFilteringObjectives(subsPort.deviceId(), subsPort.port(), defaultBpId,
+ filterFuture, VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
filterFuture.thenAcceptAsync(filterStatus -> {
if (filterStatus == null) {
- provisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
- cTag.get(), sTag.get());
+ provisionUniTagInformation(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
+ cTag.get(), sTag.get(), tpId.get());
}
});
return true;
@@ -531,7 +334,8 @@
}
@Override
- public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag, Optional<VlanId> cTag) {
+ public boolean removeSubscriber(AccessSubscriberId subscriberId, Optional<VlanId> sTag,
+ Optional<VlanId> cTag, Optional<Integer> tpId) {
// Check if we can find the connect point to which this subscriber is connected
ConnectPoint subsPort = findSubscriberConnectPoint(subscriberId.toString());
if (subsPort == null) {
@@ -541,7 +345,7 @@
if (!sTag.isPresent() && !cTag.isPresent()) {
return removeSubscriber(subsPort);
- } else if (sTag.isPresent() && cTag.isPresent()) {
+ } else if (sTag.isPresent() && cTag.isPresent() && tpId.isPresent()) {
// Get the uplink port
Port uplinkPort = getUplinkPort(deviceService.getDevice(subsPort.deviceId()));
if (uplinkPort == null) {
@@ -549,60 +353,28 @@
return false;
}
- unprovisionTransparentFlows(subsPort.deviceId(), uplinkPort.number(), subsPort.port(),
- cTag.get(), sTag.get());
+ Optional<UniTagInformation> tagInfo = getUniTagInformation(subsPort, cTag.get(), sTag.get(), tpId.get());
+ if (!tagInfo.isPresent()) {
+ log.warn("UniTagInformation does not exist for Device/Port {}, cTag {}, sTag {}, tpId {}",
+ subsPort, cTag, sTag, tpId);
+ return false;
+ }
- programmedSubs.remove(subsPort);
-
+ unprovisionVlans(subsPort.deviceId(), uplinkPort.number(), subsPort.port(), tagInfo.get());
return true;
} else {
- log.warn("Removing subscriber failed for: {}", subscriberId);
+ log.warn("Removing subscriber is not possible - please check the provided information" +
+ "for the subscriber: {}", subscriberId);
return false;
}
}
@Override
- public Collection<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> getSubscribers() {
- ArrayList<Map.Entry<ConnectPoint, Map.Entry<VlanId, VlanId>>> subs = new ArrayList<>();
-
- // Get the subscribers for all the devices configured in sadis
- // If the port is UNI, is enabled and exists in Sadis then copy it
- for (Device d : deviceService.getDevices()) {
- if (getOltInfo(d) == null) {
- continue; // not an olt, or not configured in sadis
- }
- for (Port p : deviceService.getPorts(d.id())) {
- if (isUniPort(d, p) && p.isEnabled()) {
- ConnectPoint cp = new ConnectPoint(d.id(), p.number());
-
- SubscriberAndDeviceInformation sub = getSubscriber(cp);
- if (sub != null) {
- Map.Entry<VlanId, VlanId> vlans = new AbstractMap.SimpleEntry(sub.sTag(), sub.cTag());
- subs.add(new AbstractMap.SimpleEntry(cp, vlans));
- }
- }
- }
- }
-
- return subs;
- }
-
- @Override
- public ImmutableMap<ConnectPoint, SubscriberAndDeviceInformation> getProgSubs() {
+ public ImmutableMap<ConnectPoint, Set<UniTagInformation>> getProgSubs() {
return ImmutableMap.copyOf(programmedSubs);
}
@Override
- public ImmutableSet<MeterKey> getProgMeters() {
- return ImmutableSet.copyOf(programmedMeters);
- }
-
- @Override
- public ImmutableMap<String, List<MeterKey>> getBpMeterMappings() {
- return ImmutableMap.copyOf(bpInfoToMeter);
- }
-
- @Override
public List<DeviceId> fetchOlts() {
// look through all the devices and find the ones that are OLTs as per Sadis
List<DeviceId> olts = new ArrayList<>();
@@ -637,6 +409,12 @@
return null;
}
+ /**
+ * Gets the context of the bandwidth profile information for the given parameter.
+ *
+ * @param bandwidthProfile the bandwidth profile id
+ * @return the context of the bandwidth profile information
+ */
private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
if (bandwidthProfile == null) {
return null;
@@ -650,30 +428,37 @@
* @param deviceId the device identifier
* @param uplink uplink port of the OLT
* @param subscriberPort uni port
- * @param subscriber subscriber info that includes s, c tags, tech profile and bandwidth profile references
- * @param defaultVlan default vlan of the subscriber
+ * @param uniTag uni tag information
*/
private void unprovisionVlans(DeviceId deviceId, PortNumber uplink,
- PortNumber subscriberPort, SubscriberAndDeviceInformation subscriber,
- Optional<VlanId> defaultVlan) {
- log.info("Unprovisioning vlans for subscriber {} on dev/port: {}/{}",
- subscriber, deviceId, subscriberPort);
+ PortNumber subscriberPort, UniTagInformation uniTag) {
+
+ log.info("Unprovisioning vlans for {} at {}/{}", uniTag, deviceId, subscriberPort);
CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
- VlanId deviceVlan = subscriber.sTag();
- VlanId subscriberVlan = subscriber.cTag();
+ VlanId deviceVlan = uniTag.getPonSTag();
+ VlanId subscriberVlan = uniTag.getPonCTag();
- MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.upstreamBandwidthProfile());
- MeterId downstreamMeterId = getMeterIdFromBpMapping(deviceId, subscriber.downstreamBandwidthProfile());
+ MeterId upstreamMeterId = oltMeterService
+ .getMeterIdFromBpMapping(deviceId, uniTag.getUpstreamBandwidthProfile());
+ MeterId downstreamMeterId = oltMeterService
+ .getMeterIdFromBpMapping(deviceId, uniTag.getDownstreamBandwidthProfile());
- ForwardingObjective.Builder upFwd = upBuilder(uplink, subscriberPort,
- subscriberVlan, deviceVlan,
- defaultVlan, upstreamMeterId, subscriber.technologyProfileId());
- ForwardingObjective.Builder downFwd = downBuilder(uplink, subscriberPort,
- subscriberVlan, deviceVlan,
- defaultVlan, downstreamMeterId, subscriber.technologyProfileId());
+ ForwardingObjective.Builder upFwd =
+ oltFlowService.createUpBuilder(uplink, subscriberPort, upstreamMeterId, uniTag);
+ ForwardingObjective.Builder downFwd =
+ oltFlowService.createDownBuilder(uplink, subscriberPort, downstreamMeterId, uniTag);
+
+ if (uniTag.getIsIgmpRequired()) {
+ oltFlowService.processIgmpFilteringObjectives(deviceId, subscriberPort,
+ upstreamMeterId, uniTag, false, true);
+ }
+ if (uniTag.getIsDhcpRequired()) {
+ oltFlowService.processDhcpFilteringObjectives(deviceId, subscriberPort,
+ upstreamMeterId, uniTag, false, true);
+ }
flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
@Override
@@ -700,317 +485,148 @@
}));
upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
+ AccessDeviceEvent.Type type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTERED;
if (upStatus == null && downStatus == null) {
- post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNREGISTERED,
- deviceId,
- deviceVlan,
- subscriberVlan));
+ log.debug("Uni tag information is unregistered successfully for cTag {}, sTag {}, tpId {}, and" +
+ "Device/Port{}", uniTag.getPonCTag(), uniTag.getPonSTag(),
+ uniTag.getTechnologyProfileId(), subscriberPort);
+ updateProgrammedSubscriber(new ConnectPoint(deviceId, subscriberPort), uniTag, false);
} else if (downStatus != null) {
log.error("Subscriber with vlan {} on device {} " +
- "on port {} failed downstream uninstallation: {}",
- subscriberVlan, deviceId, subscriberPort, downStatus);
+ "on port {} failed downstream uninstallation: {}",
+ subscriberVlan, deviceId, subscriberPort, downStatus);
+ type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTRATION_FAILED;
} else if (upStatus != null) {
log.error("Subscriber with vlan {} on device {} " +
- "on port {} failed upstream uninstallation: {}",
- subscriberVlan, deviceId, subscriberPort, upStatus);
+ "on port {} failed upstream uninstallation: {}",
+ subscriberVlan, deviceId, subscriberPort, upStatus);
+ type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_UNREGISTRATION_FAILED;
}
+ Port port = deviceService.getPort(deviceId, subscriberPort);
+ post(new AccessDeviceEvent(type, deviceId, port, deviceVlan, subscriberVlan,
+ uniTag.getTechnologyProfileId()));
}, oltInstallers);
-
- programmedMeters.remove(MeterKey.key(deviceId, upstreamMeterId));
- programmedMeters.remove(MeterKey.key(deviceId, downstreamMeterId));
- log.debug("programmed Meters size {}", programmedMeters.size());
}
/**
* Adds subscriber vlan flows, dhcp, eapol and igmp trap flows for the related uni port.
*
- * @param port the connection point of the subscriber
- * @param uplinkPort uplink port of the OLT
- * @param defaultVlan default vlan of the subscriber
- * @param sub subscriber information that includes s, c tags, tech profile and bandwidth profile references
+ * @param connectPoint the connection point of the subscriber
+ * @param uplinkPort uplink port of the OLT (the nni port)
+ * @param sub subscriber information that includes s, c tags, tech profile and bandwidth profile references
*/
- private void provisionSubscriberBasedFlows(ConnectPoint port, PortNumber uplinkPort,
- Optional<VlanId> defaultVlan,
- SubscriberAndDeviceInformation sub) {
+ private void provisionUniTagList(ConnectPoint connectPoint, PortNumber uplinkPort,
+ SubscriberAndDeviceInformation sub) {
- log.info("Provisioning vlans for subscriber {} on dev/port: {}",
- sub, port);
+ log.info("Provisioning vlans for subscriber {} on dev/port: {}", sub, connectPoint);
- DeviceId deviceId = port.deviceId();
- PortNumber subscriberPort = port.port();
- VlanId deviceVlan = sub.sTag();
- VlanId subscriberVlan = sub.cTag();
- int techProfId = sub.technologyProfileId();
+ if (sub.uniTagList() == null || sub.uniTagList().isEmpty()) {
+ log.warn("Unitaglist doesn't exist for the subscriber {}", sub.id());
+ return;
+ }
- BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(sub.upstreamBandwidthProfile());
- BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(sub.downstreamBandwidthProfile());
+ DeviceId deviceId = connectPoint.deviceId();
+ PortNumber subscriberPort = connectPoint.port();
- CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
- CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
- CompletableFuture<Object> upstreamMeterFuture = new CompletableFuture<>();
- CompletableFuture<Object> downsteamMeterFuture = new CompletableFuture<>();
+ for (UniTagInformation uniTag : sub.uniTagList()) {
+ handleSubscriberFlows(deviceId, uplinkPort, subscriberPort, uniTag);
+ }
+ }
- MeterId upstreamMeterId = createMeter(deviceId, upstreamBpInfo, upstreamMeterFuture);
- MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo, downsteamMeterFuture);
+ /**
+ * Finds the uni tag information and provisions the found information.
+ * If the uni tag information is not found, returns
+ *
+ * @param deviceId the access device id
+ * @param uplinkPort the nni port
+ * @param subscriberPort the uni port
+ * @param innerVlan the pon c tag
+ * @param outerVlan the pon s tag
+ * @param tpId the technology profile id
+ */
+ private void provisionUniTagInformation(DeviceId deviceId, PortNumber uplinkPort,
+ PortNumber subscriberPort,
+ VlanId innerVlan,
+ VlanId outerVlan,
+ Integer tpId) {
- //install upstream flows
- upstreamMeterFuture.thenAcceptAsync(result -> {
- if (result == null) {
- log.info("Upstream Meter {} is in the device {}. " +
- "Sending subscriber flows.", upstreamMeterId, deviceId);
- ForwardingObjective.Builder upFwd = upBuilder(uplinkPort, subscriberPort,
- subscriberVlan, deviceVlan,
- defaultVlan, upstreamMeterId, techProfId);
+ ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
+ Optional<UniTagInformation> gotTagInformation = getUniTagInformation(cp, innerVlan, outerVlan, tpId);
+ if (!gotTagInformation.isPresent()) {
+ return;
+ }
+ UniTagInformation tagInformation = gotTagInformation.get();
+ handleSubscriberFlows(deviceId, uplinkPort, subscriberPort, tagInformation);
+ }
-
- flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
- @Override
- public void onSuccess(Objective objective) {
- upFuture.complete(null);
- }
-
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- upFuture.complete(error);
- }
- }));
- } else {
- log.warn("Meter installation error while sending upstream flows. " +
- "Result {} and MeterId {}", result, upstreamMeterId);
- }
- });
-
- //install downstream flows
- downsteamMeterFuture.thenAcceptAsync(result -> {
- if (result == null) {
- log.info("Downstream Meter {} is in the device {}. " +
- "Sending subscriber flows.", downstreamMeterId, deviceId);
- ForwardingObjective.Builder downFwd = downBuilder(uplinkPort, subscriberPort,
- subscriberVlan, deviceVlan,
- defaultVlan, downstreamMeterId, techProfId);
-
- flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
- @Override
- public void onSuccess(Objective objective) {
- downFuture.complete(null);
- }
-
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- downFuture.complete(error);
- }
- }));
- } else {
- log.warn("Meter installation error while sending downstream flows. " +
- "Result {} and MeterId {}", result, downstreamMeterId);
- }
- });
-
- //send eapol & dhcp & igmp flows
- //send Subscriber Registered event
- upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
- if (upStatus == null && downStatus == null) {
-
- if (upstreamMeterId != null) {
- //re-install Eapol authentication flow with the subscribers' upstream bandwidth profile
- processEapolFilteringObjectives(deviceId, subscriberPort, sub.upstreamBandwidthProfile(),
- null, sub.cTag(), true);
-
- processDhcpFilteringObjectives(deviceId, subscriberPort,
- upstreamMeterId, sub.technologyProfileId(), true, true);
-
- processIgmpFilteringObjectives(deviceId, subscriberPort,
- upstreamMeterId, sub.technologyProfileId(), true);
+ private void updateProgrammedSubscriber(ConnectPoint connectPoint, UniTagInformation tagInformation, Boolean add) {
+ programmedSubs.compute(connectPoint, (k, v) -> {
+ if (add) {
+ if (v == null) {
+ v = Sets.newHashSet();
}
-
- post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_REGISTERED,
- deviceId,
- deviceVlan,
- subscriberVlan));
-
- } else if (downStatus != null) {
- log.error("Subscriber with vlan {} on device {} " +
- "on port {} failed downstream installation: {}",
- subscriberVlan, deviceId, subscriberPort, downStatus);
- } else if (upStatus != null) {
- log.error("Subscriber with vlan {} on device {} " +
- "on port {} failed upstream installation: {}",
- subscriberVlan, deviceId, subscriberPort, upStatus);
+ v.add(tagInformation);
+ } else {
+ if (v != null) {
+ v.remove(tagInformation);
+ }
}
- }, oltInstallers);
+ return v;
+ });
}
- private MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo,
- CompletableFuture<Object> meterFuture) {
- if (bpInfo == null) {
- log.warn("Bandwidth profile information cannot be null when creating meter");
- return null;
+ /**
+ * Installs a uni tag information flow.
+ *
+ * @param deviceId the access device id
+ * @param uplinkPort the nni port
+ * @param subscriberPort the uni port
+ * @param tagInfo the uni tag information
+ */
+ private void handleSubscriberFlows(DeviceId deviceId, PortNumber uplinkPort, PortNumber subscriberPort,
+ UniTagInformation tagInfo) {
+
+ log.info("Provisioning vlan-based flows for the uniTagInformation {}", tagInfo);
+
+ Port port = deviceService.getPort(deviceId, subscriberPort);
+
+ if (multicastServiceName.equals(tagInfo.getServiceName())) {
+ // IGMP flows are taken care of along with VOD service
+ // Please note that for each service, Subscriber Registered event will be sent
+ post(new AccessDeviceEvent(AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTERED,
+ deviceId, port, tagInfo.getPonSTag(), tagInfo.getPonCTag(),
+ tagInfo.getTechnologyProfileId()));
+ return;
}
- MeterId meterId = getMeterIdFromBpMapping(deviceId, bpInfo.id());
- if (meterId != null) {
- log.debug("Meter {} was previously created for bp {}", meterId,
- bpInfo.id());
- meterFuture.complete(null);
- return meterId;
- }
-
- List<Band> meterBands = createMeterBands(bpInfo);
-
- MeterRequest meterRequest = DefaultMeterRequest.builder()
- .withBands(meterBands)
- .withUnit(Meter.Unit.KB_PER_SEC)
- .withContext(new MeterContext() {
- @Override
- public void onSuccess(MeterRequest op) {
- log.debug("meter addition confirmed for bpInfo:{}", bpInfo);
- meterFuture.complete(null);
- }
-
- @Override
- public void onError(MeterRequest op, MeterFailReason reason) {
- meterFuture.complete(reason);
- }
- })
- .forDevice(deviceId)
- .fromApp(appId)
- .burst()
- .add();
-
- Meter meter = meterService.submit(meterRequest);
- addMeterIdToBpMapping(deviceId, meter.id(), bpInfo.id());
- log.info("Meter creation message sent for Meter Id {}", meter.id());
- programmedMeters.add(MeterKey.key(deviceId, meter.id()));
- return meter.id();
- }
-
- private List<Band> createMeterBands(BandwidthProfileInformation bpInfo) {
- List<Band> meterBands = new ArrayList<>();
-
- meterBands.add(createMeterBand(bpInfo.committedInformationRate(), bpInfo.committedBurstSize()));
- meterBands.add(createMeterBand(bpInfo.exceededInformationRate(), bpInfo.exceededBurstSize()));
- meterBands.add(createMeterBand(bpInfo.assuredInformationRate(), 0L));
-
- return meterBands;
- }
-
- private Band createMeterBand(long rate, Long burst) {
- return DefaultBand.builder()
- .withRate(rate) //already Kbps
- .burstSize(burst) // already Kbits
- .ofType(Band.Type.DROP) // no matter
- .build();
- }
-
- private ForwardingObjective.Builder downBuilder(PortNumber uplinkPort,
- PortNumber subscriberPort,
- VlanId subscriberVlan,
- VlanId deviceVlan,
- Optional<VlanId> defaultVlan,
- MeterId meterId,
- int techProfId) {
- TrafficSelector downstream = DefaultTrafficSelector.builder()
- .matchVlanId(deviceVlan)
- .matchInPort(uplinkPort)
- .matchInnerVlanId(subscriberVlan)
- .build();
-
- TrafficTreatment.Builder downstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
- .popVlan()
- .setVlanId(defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan)))
- .setOutput(subscriberPort);
-
- if (meterId != null) {
- downstreamTreatmentBuilder.meter(meterId);
- }
-
- downstreamTreatmentBuilder.writeMetadata(createMetadata(subscriberVlan, techProfId, subscriberPort), 0);
-
- return DefaultForwardingObjective.builder()
- .withFlag(ForwardingObjective.Flag.VERSATILE)
- .withPriority(1000)
- .makePermanent()
- .withSelector(downstream)
- .fromApp(appId)
- .withTreatment(downstreamTreatmentBuilder.build());
- }
-
- private ForwardingObjective.Builder upBuilder(PortNumber uplinkPort,
- PortNumber subscriberPort,
- VlanId subscriberVlan,
- VlanId deviceVlan,
- Optional<VlanId> defaultVlan,
- MeterId meterId,
- int technologyProfileId) {
-
-
- VlanId dVlan = defaultVlan.orElse(VlanId.vlanId((short) this.defaultVlan));
-
- if (subscriberVlan.toShort() == 4096) {
- dVlan = subscriberVlan;
- }
-
- TrafficSelector upstream = DefaultTrafficSelector.builder()
- .matchVlanId(dVlan)
- .matchInPort(subscriberPort)
- .build();
-
-
- TrafficTreatment.Builder upstreamTreatmentBuilder = DefaultTrafficTreatment.builder()
- .pushVlan()
- .setVlanId(subscriberVlan)
- .pushVlan()
- .setVlanId(deviceVlan)
- .setOutput(uplinkPort);
-
- if (meterId != null) {
- upstreamTreatmentBuilder.meter(meterId);
- }
-
- upstreamTreatmentBuilder.writeMetadata(createMetadata(deviceVlan, technologyProfileId, uplinkPort), 0L);
-
- return DefaultForwardingObjective.builder()
- .withFlag(ForwardingObjective.Flag.VERSATILE)
- .withPriority(1000)
- .makePermanent()
- .withSelector(upstream)
- .fromApp(appId)
- .withTreatment(upstreamTreatmentBuilder.build());
- }
-
- private void provisionTransparentFlows(DeviceId deviceId, PortNumber uplinkPort,
- PortNumber subscriberPort,
- VlanId innerVlan,
- VlanId outerVlan) {
-
ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
- SubscriberAndDeviceInformation subInfo = getSubscriber(cp);
-
- BandwidthProfileInformation upstreamBpInfo = getBandwidthProfileInformation(
- subInfo.upstreamBandwidthProfile());
- BandwidthProfileInformation downstreamBpInfo = getBandwidthProfileInformation(
- subInfo.downstreamBandwidthProfile());
+ BandwidthProfileInformation upstreamBpInfo =
+ getBandwidthProfileInformation(tagInfo.getUpstreamBandwidthProfile());
+ BandwidthProfileInformation downstreamBpInfo =
+ getBandwidthProfileInformation(tagInfo.getDownstreamBandwidthProfile());
CompletableFuture<Object> upstreamMeterFuture = new CompletableFuture<>();
CompletableFuture<Object> downsteamMeterFuture = new CompletableFuture<>();
- CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
- CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
+ CompletableFuture<ObjectiveError> upFuture = new CompletableFuture<>();
+ CompletableFuture<ObjectiveError> downFuture = new CompletableFuture<>();
- MeterId upstreamMeterId = createMeter(deviceId, upstreamBpInfo, upstreamMeterFuture);
- MeterId downstreamMeterId = createMeter(deviceId, downstreamBpInfo, downsteamMeterFuture);
+ MeterId upstreamMeterId = oltMeterService.createMeter(deviceId, upstreamBpInfo, upstreamMeterFuture);
+
+ MeterId downstreamMeterId = oltMeterService.createMeter(deviceId, downstreamBpInfo, downsteamMeterFuture);
upstreamMeterFuture.thenAcceptAsync(result -> {
if (result == null) {
log.info("Upstream Meter {} is sent to the device {}. " +
- "Sending subscriber flows.", upstreamMeterId, deviceId);
+ "Sending subscriber flows.", upstreamMeterId, deviceId);
- ForwardingObjective.Builder upFwd = transparentUpBuilder(uplinkPort, subscriberPort,
- innerVlan, outerVlan, upstreamMeterId, subInfo);
+ ForwardingObjective.Builder upFwd =
+ oltFlowService.createUpBuilder(uplinkPort, subscriberPort, upstreamMeterId, tagInfo);
flowObjectiveService.forward(deviceId, upFwd.add(new ObjectiveContext() {
@Override
public void onSuccess(Objective objective) {
+ log.info("Upstream flow installed successfully");
upFuture.complete(null);
}
@@ -1020,23 +636,30 @@
}
}));
+ } else if (upstreamBpInfo == null) {
+ log.warn("No meter installed since no Upstream BW Profile definition found for " +
+ "ctag {} stag {} tpId {} and Device/port: {}:{}",
+ tagInfo.getPonCTag(), tagInfo.getPonSTag(),
+ tagInfo.getTechnologyProfileId(),
+ deviceId, subscriberPort);
} else {
log.warn("Meter installation error while sending upstream flows. " +
- "Result {} and MeterId {}", result, upstreamMeterId);
+ "Result {} and MeterId {}", result, upstreamMeterId);
}
});
downsteamMeterFuture.thenAcceptAsync(result -> {
if (result == null) {
log.info("Downstream Meter {} is sent to the device {}. " +
- "Sending subscriber flows.", downstreamMeterId, deviceId);
+ "Sending subscriber flows.", downstreamMeterId, deviceId);
- ForwardingObjective.Builder downFwd = transparentDownBuilder(uplinkPort, subscriberPort,
- innerVlan, outerVlan, downstreamMeterId, subInfo);
+ ForwardingObjective.Builder downFwd =
+ oltFlowService.createDownBuilder(uplinkPort, subscriberPort, downstreamMeterId, tagInfo);
flowObjectiveService.forward(deviceId, downFwd.add(new ObjectiveContext() {
@Override
public void onSuccess(Objective objective) {
+ log.info("Downstream flow installed successfully");
downFuture.complete(null);
}
@@ -1045,500 +668,95 @@
downFuture.complete(error);
}
}));
+
+ } else if (downstreamBpInfo == null) {
+ log.warn("No meter installed since no Downstream BW Profile definition found for " +
+ "ctag {} stag {} tpId {} and Device/port: {}:{}",
+ tagInfo.getPonCTag(), tagInfo.getPonSTag(),
+ tagInfo.getTechnologyProfileId(),
+ deviceId, subscriberPort);
} else {
log.warn("Meter installation error while sending upstream flows. " +
- "Result {} and MeterId {}", result, downstreamMeterId);
+ "Result {} and MeterId {}", result, downstreamMeterId);
}
});
- additionalVlans.put(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
-
upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
+ AccessDeviceEvent.Type type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTERED;
if (downStatus != null) {
log.error("Flow with innervlan {} and outerVlan {} on device {} " +
- "on port {} failed downstream installation: {}",
- innerVlan, outerVlan, deviceId, cp, downStatus);
+ "on port {} failed downstream installation: {}",
+ tagInfo.getPonCTag(), tagInfo.getPonSTag(), deviceId, cp, downStatus);
+ type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTRATION_FAILED;
} else if (upStatus != null) {
log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
- "on port {} failed upstream installation: {}",
- innerVlan, outerVlan, deviceId, cp, upStatus);
+ "on port {} failed upstream installation: {}",
+ tagInfo.getPonCTag(), tagInfo.getPonSTag(), deviceId, cp, upStatus);
+ type = AccessDeviceEvent.Type.SUBSCRIBER_UNI_TAG_REGISTRATION_FAILED;
} else {
- processEapolFilteringObjectives(deviceId, subscriberPort, subInfo.upstreamBandwidthProfile(),
- null, subInfo.cTag(), true);
+ log.info("Upstream and downstream data plane flows are installed successfully.");
+ oltFlowService.processEapolFilteringObjectives(deviceId, subscriberPort,
+ tagInfo.getUpstreamBandwidthProfile(),
+ null, tagInfo.getPonCTag(), true);
+ if (tagInfo.getIsDhcpRequired()) {
+ oltFlowService.processDhcpFilteringObjectives(deviceId, subscriberPort,
+ upstreamMeterId, tagInfo, true, true);
+ }
- // cache subscriber info
- programmedSubs.put(cp, subInfo);
+ if (tagInfo.getIsIgmpRequired()) {
+ oltFlowService.processIgmpFilteringObjectives(deviceId, subscriberPort, upstreamMeterId, tagInfo,
+ true, true);
+ }
+ updateProgrammedSubscriber(cp, tagInfo, true);
+ post(new AccessDeviceEvent(type, deviceId, port, tagInfo.getPonSTag(), tagInfo.getPonCTag(),
+ tagInfo.getTechnologyProfileId()));
}
}, oltInstallers);
-
}
- private ForwardingObjective.Builder transparentDownBuilder(PortNumber uplinkPort,
- PortNumber subscriberPort,
- VlanId innerVlan,
- VlanId outerVlan,
- MeterId downstreamMeterId,
- SubscriberAndDeviceInformation subInfo) {
- TrafficSelector downstream = DefaultTrafficSelector.builder()
- .matchVlanId(outerVlan)
- .matchInPort(uplinkPort)
- .matchInnerVlanId(innerVlan)
- .build();
-
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- if (downstreamMeterId != null) {
- tBuilder.meter(downstreamMeterId);
- }
-
- TrafficTreatment downstreamTreatment = tBuilder
- .setOutput(subscriberPort)
- .writeMetadata(createMetadata(subInfo.cTag(), subInfo.technologyProfileId(), subscriberPort), 0)
- .build();
-
- return DefaultForwardingObjective.builder()
- .withFlag(ForwardingObjective.Flag.VERSATILE)
- .withPriority(1000)
- .makePermanent()
- .withSelector(downstream)
- .fromApp(appId)
- .withTreatment(downstreamTreatment);
- }
-
- private ForwardingObjective.Builder transparentUpBuilder(PortNumber uplinkPort,
- PortNumber subscriberPort,
- VlanId innerVlan,
- VlanId outerVlan,
- MeterId upstreamMeterId,
- SubscriberAndDeviceInformation subInfo) {
-
- TrafficSelector upstream = DefaultTrafficSelector.builder()
- .matchVlanId(outerVlan)
- .matchInPort(subscriberPort)
- .matchInnerVlanId(innerVlan)
- .build();
-
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- if (upstreamMeterId != null) {
- tBuilder.meter(upstreamMeterId);
- }
-
- TrafficTreatment upstreamTreatment = tBuilder
- .setOutput(uplinkPort)
- .writeMetadata(createMetadata(subInfo.sTag(), subInfo.technologyProfileId(), uplinkPort), 0)
- .build();
-
- return DefaultForwardingObjective.builder()
- .withFlag(ForwardingObjective.Flag.VERSATILE)
- .withPriority(1000)
- .makePermanent()
- .withSelector(upstream)
- .fromApp(appId)
- .withTreatment(upstreamTreatment);
- }
-
- private void unprovisionTransparentFlows(DeviceId deviceId, PortNumber uplink,
- PortNumber subscriberPort, VlanId innerVlan,
- VlanId outerVlan) {
-
- ConnectPoint cp = new ConnectPoint(deviceId, subscriberPort);
-
- SubscriberAndDeviceInformation subInfo = programmedSubs.get(cp);
+ /**
+ * Checks the subscriber uni tag list and find the uni tag information.
+ * using the pon c tag, pon s tag and the technology profile id
+ * May return Optional<null>
+ *
+ * @param cp the connection point of the subscriber
+ * @param innerVlan pon c tag
+ * @param outerVlan pon s tag
+ * @param tpId the technology profile id
+ * @return the found uni tag information
+ */
+ private Optional<UniTagInformation> getUniTagInformation(ConnectPoint cp, VlanId innerVlan, VlanId outerVlan,
+ int tpId) {
+ log.info("Getting uni tag information for cp: {}, innerVlan: {}, outerVlan: {}, tpId: {}", cp, innerVlan,
+ outerVlan, tpId);
+ SubscriberAndDeviceInformation subInfo = getSubscriber(cp);
if (subInfo == null) {
- log.warn("Subscriber is not programmed before for the connectPoint {}", cp);
- return;
+ log.warn("Subscriber information doesn't exist for the connect point {}", cp);
+ return Optional.empty();
}
- additionalVlans.remove(cp, new AbstractMap.SimpleEntry(outerVlan, innerVlan));
+ List<UniTagInformation> uniTagList = subInfo.uniTagList();
+ if (uniTagList == null) {
+ log.warn("Uni tag list is not found for the subscriber {}", subInfo.id());
+ return Optional.empty();
+ }
- CompletableFuture<ObjectiveError> downFuture = new CompletableFuture();
- CompletableFuture<ObjectiveError> upFuture = new CompletableFuture();
-
- MeterId upstreamMeterId = getMeterIdFromBpMapping(deviceId, subInfo.upstreamBandwidthProfile());
- MeterId downstreamMeterId = getMeterIdFromBpMapping(deviceId, subInfo.downstreamBandwidthProfile());
-
- ForwardingObjective.Builder upFwd = transparentUpBuilder(uplink, subscriberPort,
- innerVlan, outerVlan, upstreamMeterId, subInfo);
- ForwardingObjective.Builder downFwd = transparentDownBuilder(uplink, subscriberPort,
- innerVlan, outerVlan, downstreamMeterId, subInfo);
-
- flowObjectiveService.forward(deviceId, upFwd.remove(new ObjectiveContext() {
- @Override
- public void onSuccess(Objective objective) {
- upFuture.complete(null);
- }
-
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- upFuture.complete(error);
- }
- }));
-
- flowObjectiveService.forward(deviceId, downFwd.remove(new ObjectiveContext() {
- @Override
- public void onSuccess(Objective objective) {
- downFuture.complete(null);
- }
-
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- downFuture.complete(error);
- }
- }));
-
- upFuture.thenAcceptBothAsync(downFuture, (upStatus, downStatus) -> {
- if (downStatus != null) {
- log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
- "on port {} failed downstream uninstallation: {}",
- innerVlan, outerVlan, deviceId, subscriberPort, downStatus);
- } else if (upStatus != null) {
- log.error("Flow with innerVlan {} and outerVlan {} on device {} " +
- "on port {} failed upstream uninstallation: {}",
- innerVlan, outerVlan, deviceId, subscriberPort, upStatus);
- }
- }, oltInstallers);
-
- //re-install eapol
- processEapolFilteringObjectives(deviceId, subscriberPort,
- subInfo.upstreamBandwidthProfile(), null, subInfo.cTag(), false);
- processEapolFilteringObjectives(deviceId, subscriberPort, defaultBpId,
- null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
-
- programmedMeters.remove(MeterKey.key(deviceId, upstreamMeterId));
- programmedMeters.remove(MeterKey.key(deviceId, downstreamMeterId));
- }
-
- private int getDefaultTechProfileId(DeviceId devId, PortNumber portNumber) {
- Port port = deviceService.getPort(devId, portNumber);
- if (port != null) {
- SubscriberAndDeviceInformation info = subsService.get(port.annotations().value(AnnotationKeys.PORT_NAME));
- if (info != null && info.technologyProfileId() != -1) {
- return info.technologyProfileId();
+ UniTagInformation service = null;
+ for (UniTagInformation tagInfo : subInfo.uniTagList()) {
+ if (innerVlan.equals(tagInfo.getPonCTag()) && outerVlan.equals(tagInfo.getPonSTag())
+ && tpId == tagInfo.getTechnologyProfileId()) {
+ service = tagInfo;
+ break;
}
}
- return defaultTechProfileId;
- }
- /**
- * Returns the write metadata value including tech profile reference and innerVlan.
- * For param cVlan, null can be sent
- *
- * @param cVlan c (customer) tag of one subscriber
- * @param techProfileId tech profile id of one subscriber
- * @return the write metadata value including tech profile reference and innerVlan
- */
- private Long createTechProfValueForWm(VlanId cVlan, int techProfileId) {
- if (cVlan == null) {
- return (long) techProfileId << 32;
- }
- return ((long) (cVlan.id()) << 48 | (long) techProfileId << 32);
- }
-
- /**
- * Trap eapol authentication packets to the controller.
- *
- * @param devId the device identifier
- * @param portNumber the port for which this trap flow is designated
- * @param bpId bandwidth profile id to add the related meter to the flow
- * @param filterFuture completable future for this filtering objective operation
- * @param vlanId the default or customer tag for a subscriber
- * @param install true to install the flow, false to remove the flow
- */
- private void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, String bpId,
- CompletableFuture<ObjectiveError> filterFuture,
- VlanId vlanId, boolean install) {
- if (!enableEapol) {
- log.debug("Eapol filtering is disabled.");
- if (filterFuture != null) {
- filterFuture.complete(null);
- }
- return;
+ if (service == null) {
+ log.warn("SADIS doesn't include the service with ponCtag {} ponStag {} and tpId {}",
+ innerVlan, outerVlan, tpId);
+ return Optional.empty();
}
- if (!mastershipService.isLocalMaster(devId)) {
- return;
- }
- DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
- TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
- CompletableFuture<Object> meterFuture = new CompletableFuture<>();
-
- BandwidthProfileInformation bpInfo = getBandwidthProfileInformation(bpId);
- if (bpInfo == null) {
- log.warn("Bandwidth profile {} is not found. Authentication flow"
- + " will not be installed", bpId);
- return;
- }
-
- // check if meter exists and create it only for an install
- MeterId meterId = getMeterIdFromBpMapping(devId, bpInfo.id());
- if (meterId == null) {
- if (install) {
- meterId = createMeter(devId, bpInfo, meterFuture);
- treatmentBuilder.meter(meterId);
- } else {
- // this case should not happen as the request to remove an eapol
- // flow should mean that the flow points to a meter that exists.
- // Nevertheless we can still delete the flow as we only need the
- // correct 'match' to do so.
- log.warn("Unknown meter id for bp {}, still proceeding with "
- + "delete of eapol flow for {}/{}", bpInfo.id(), devId,
- portNumber);
- meterFuture.complete(null);
- }
- } else {
- log.debug("Meter {} was previously created for bp {}", meterId,
- bpInfo.id());
- treatmentBuilder.meter(meterId);
- meterFuture.complete(null);
- }
-
- final MeterId mId = meterId;
- meterFuture.thenAcceptAsync(result -> {
- if (result == null) {
- log.info("Meter {} for {} on {}/{} exists. {} EAPOL trap flow",
- mId, bpId, devId, portNumber,
- (install) ? "Installing " : "Removing ");
- int techProfileId = getDefaultTechProfileId(devId, portNumber);
-
- //Authentication trap flow uses only tech profile id as write metadata value
- FilteringObjective eapol = (install ? builder.permit() : builder.deny())
- .withKey(Criteria.matchInPort(portNumber))
- .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
- .addCondition(Criteria.matchVlanId(vlanId))
- .withMeta(treatmentBuilder
- .writeMetadata(createTechProfValueForWm(vlanId, techProfileId), 0)
- .setOutput(PortNumber.CONTROLLER).build())
- .fromApp(appId)
- .withPriority(10000)
- .add(new ObjectiveContext() {
- @Override
- public void onSuccess(Objective objective) {
- log.info("Eapol filter for {} on {} {} with meter {}.",
- devId, portNumber, (install) ? INSTALLED : REMOVED, mId);
- if (filterFuture != null) {
- filterFuture.complete(null);
- }
- }
-
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.info("Eapol filter for {} on {} with meter {} failed {} because {}",
- devId, portNumber, mId, (install) ? INSTALLATION : REMOVAL,
- error);
- if (filterFuture != null) {
- filterFuture.complete(error);
- }
- }
- });
-
- flowObjectiveService.filter(devId, eapol);
- } else {
- log.warn("Meter installation error while sending eapol trap flow. " +
- "Result {} and MeterId {}", result, mId);
- }
- });
- }
-
- /**
- * Installs trap filtering objectives for particular traffic types on an
- * NNI port.
- *
- * @param devId device ID
- * @param port port number
- * @param install true to install, false to remove
- */
- private void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
- processLldpFilteringObjective(devId, port, install);
- processDhcpFilteringObjectives(devId, port, null, -1, install, false);
- }
-
- private void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
- if (!mastershipService.isLocalMaster(devId)) {
- return;
- }
- DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
-
- FilteringObjective lldp = (install ? builder.permit() : builder.deny())
- .withKey(Criteria.matchInPort(port))
- .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
- .withMeta(DefaultTrafficTreatment.builder()
- .setOutput(PortNumber.CONTROLLER).build())
- .fromApp(appId)
- .withPriority(10000)
- .add(new ObjectiveContext() {
- @Override
- public void onSuccess(Objective objective) {
- log.info("LLDP filter for device {} on port {} {}.",
- devId, port, (install) ? INSTALLED : REMOVED);
- }
-
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.info("LLDP filter for device {} on port {} failed {} because {}",
- devId, port, (install) ? INSTALLATION : REMOVAL,
- error);
- }
- });
-
- flowObjectiveService.filter(devId, lldp);
-
- }
-
- /**
- * Trap dhcp packets to the controller.
- *
- * @param devId the device identifier
- * @param port the port for which this trap flow is designated
- * @param upstreamMeterId the upstream meter id that includes the upstream
- * bandwidth profile values such as PIR,CIR. If no meter id needs to be referenced,
- * null can be sent
- * @param techProfileId the technology profile id that is used to create write
- * metadata instruction value. If no tech profile id needs to be referenced,
- * -1 can be sent
- * @param install true to install the flow, false to remove the flow
- * @param upstream true if trapped packets are flowing upstream towards
- * server, false if packets are flowing downstream towards client
- */
- private void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
- MeterId upstreamMeterId,
- int techProfileId,
- boolean install,
- boolean upstream) {
-
- if (!enableDhcpOnProvisioning) {
- log.debug("Dhcp provisioning is disabled.");
- return;
- }
-
- if (!mastershipService.isLocalMaster(devId)) {
- return;
- }
-
- if (enableDhcpV4) {
- int udpSrc = (upstream) ? 68 : 67;
- int udpDst = (upstream) ? 67 : 68;
-
- EthType ethType = EthType.EtherType.IPV4.ethType();
- byte protocol = IPv4.PROTOCOL_UDP;
-
- this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
- upstreamMeterId, techProfileId, protocol, install);
- }
-
- if (enableDhcpV6) {
- int udpSrc = (upstream) ? 547 : 546;
- int udpDst = (upstream) ? 546 : 547;
-
- EthType ethType = EthType.EtherType.IPV6.ethType();
- byte protocol = IPv6.PROTOCOL_UDP;
-
- this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
- upstreamMeterId, techProfileId, protocol, install);
- }
-
- }
-
- private void addDhcpFilteringObjectives(DeviceId devId,
- PortNumber port,
- int udpSrc,
- int udpDst,
- EthType ethType,
- MeterId upstreamMeterId,
- int techProfileId,
- byte protocol,
- boolean install) {
-
- DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
- TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
-
- if (upstreamMeterId != null) {
- treatmentBuilder.meter(upstreamMeterId);
- }
-
- if (techProfileId != -1) {
- treatmentBuilder.writeMetadata(createTechProfValueForWm(null, techProfileId), 0);
- }
-
- FilteringObjective dhcpUpstream = (install ? builder.permit() : builder.deny())
- .withKey(Criteria.matchInPort(port))
- .addCondition(Criteria.matchEthType(ethType))
- .addCondition(Criteria.matchIPProtocol(protocol))
- .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
- .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
- .withMeta(treatmentBuilder
- .setOutput(PortNumber.CONTROLLER).build())
- .fromApp(appId)
- .withPriority(10000)
- .add(new ObjectiveContext() {
- @Override
- public void onSuccess(Objective objective) {
- log.info("DHCP {} filter for device {} on port {} {}.",
- (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
- devId, port, (install) ? INSTALLED : REMOVED);
- }
-
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.info("DHCP {} filter for device {} on port {} failed {} because {}",
- (ethType.equals(EthType.EtherType.IPV4.ethType())) ? "v4" : "v6",
- devId, port, (install) ? INSTALLATION : REMOVAL,
- error);
- }
- });
-
- flowObjectiveService.filter(devId, dhcpUpstream);
- }
-
- private void processIgmpFilteringObjectives(DeviceId devId, PortNumber port,
- MeterId upstreamMeterId,
- int techProfileId,
- boolean install) {
-
- if (!enableIgmpOnProvisioning) {
- log.debug("Igmp provisioning is disabled.");
- return;
- }
-
- if (!mastershipService.isLocalMaster(devId)) {
- return;
- }
-
- DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
- TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
-
- if (upstreamMeterId != null) {
- treatmentBuilder.meter(upstreamMeterId);
- }
-
- if (techProfileId != -1) {
- treatmentBuilder.writeMetadata(createTechProfValueForWm(null, techProfileId), 0);
- }
-
- builder = install ? builder.permit() : builder.deny();
-
- FilteringObjective igmp = builder
- .withKey(Criteria.matchInPort(port))
- .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
- .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
- .withMeta(treatmentBuilder
- .setOutput(PortNumber.CONTROLLER).build())
- .fromApp(appId)
- .withPriority(10000)
- .add(new ObjectiveContext() {
- @Override
- public void onSuccess(Objective objective) {
- log.info("Igmp filter for {} on {} {}.",
- devId, port, (install) ? INSTALLED : REMOVED);
- }
-
- @Override
- public void onError(Objective objective, ObjectiveError error) {
- log.info("Igmp filter for {} on {} failed {} because {}.",
- devId, port, (install) ? INSTALLATION : REMOVAL,
- error);
- }
- });
-
- flowObjectiveService.filter(devId, igmp);
+ return Optional.of(service);
}
/**
@@ -1554,16 +772,20 @@
}
// check if this device is provisioned in Sadis
SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
- log.debug("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
+ log.info("checkAndCreateDeviceFlows: deviceInfo {}", deviceInfo);
if (deviceInfo != null) {
// This is an OLT device as per Sadis, we create flows for UNI and NNI ports
for (Port p : deviceService.getPorts(dev.id())) {
+ if (PortNumber.LOCAL.equals(p.number())) {
+ continue;
+ }
if (isUniPort(dev, p)) {
- processEapolFilteringObjectives(dev.id(), p.number(), defaultBpId, null,
- VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
+ log.info("Creating Eapol for the uni {}", p);
+ oltFlowService.processEapolFilteringObjectives(dev.id(), p.number(), defaultBpId, null,
+ VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
} else {
- processNniFilteringObjectives(dev.id(), p.number(), true);
+ oltFlowService.processNniFilteringObjectives(dev.id(), p.number(), true);
}
}
}
@@ -1585,7 +807,7 @@
log.trace("getUplinkPort: deviceInfo {}", deviceInfo);
if (deviceInfo == null) {
log.warn("Device {} is not configured in SADIS .. cannot fetch device"
- + " info", dev.id());
+ + " info", dev.id());
return null;
}
// Return the port that has been configured as the uplink port of this OLT in Sadis
@@ -1614,22 +836,12 @@
}
/**
- * Write metadata instruction value (metadata) is 8 bytes.
- * <p>
- * MS 2 bytes: C Tag
- * Next 2 bytes: Technology Profile Id
- * Next 4 bytes: Port number (uni or nni)
+ * Checks whether the given port of the device is a uni port or not.
+ *
+ * @param d the access device
+ * @param p the port of the device
+ * @return true if the given port is a uni port
*/
-
- private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
-
- if (techProfileId == -1) {
- techProfileId = defaultTechProfileId;
- }
-
- return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
- }
-
private boolean isUniPort(Device d, Port p) {
Port ulPort = getUplinkPort(d);
if (ulPort != null) {
@@ -1638,64 +850,18 @@
return false;
}
+ /**
+ * Gets the given device details from SADIS.
+ * If the device is not found, returns null
+ *
+ * @param dev the access device
+ * @return the olt information
+ */
private SubscriberAndDeviceInformation getOltInfo(Device dev) {
String devSerialNo = dev.serialNumber();
return subsService.get(devSerialNo);
}
- private MeterId getMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfile) {
- if (bpInfoToMeter.get(bandwidthProfile) == null) {
- log.warn("Bandwidth Profile '{}' is not currently mapped to a meter",
- bandwidthProfile);
- return null;
- }
-
- Optional<MeterKey> meterKeyForDevice = bpInfoToMeter.get(bandwidthProfile)
- .stream()
- .filter(meterKey -> meterKey.deviceId().equals(deviceId))
- .findFirst();
- if (meterKeyForDevice.isPresent()) {
- log.debug("Found meter {} for bandwidth profile {}",
- meterKeyForDevice.get().meterId(), bandwidthProfile);
- return meterKeyForDevice.get().meterId();
- } else {
- log.warn("Bandwidth profile '{}' is not currently mapped to a meter",
- bandwidthProfile);
- return null;
- }
- }
-
- private void addMeterIdToBpMapping(DeviceId deviceId, MeterId meterId, String bandwidthProfile) {
-
- if (bpInfoToMeter.get(bandwidthProfile) == null) {
- bpInfoToMeter.put(bandwidthProfile,
- new ArrayList<>(Arrays.asList(MeterKey.key(deviceId, meterId))));
- } else {
- List<MeterKey> meterKeyListForBp = bpInfoToMeter.get(bandwidthProfile);
- meterKeyListForBp.add(MeterKey.key(deviceId, meterId));
- }
- }
-
- /**
- * Removes meter key from programmed meters. If the meter has no reference
- * count in the data plane and is not present in the programmed-meters store
- * it will be removed.
- *
- * @param deviceId device identifier
- * @param bandwidthProfileId name of bandwidth profile
- */
- private void removeMeterIdFromPrgMeters(DeviceId deviceId,
- String bandwidthProfileId) {
- List<MeterKey> meterKeysForBp = bpInfoToMeter.get(bandwidthProfileId);
- if (meterKeysForBp != null) {
- meterKeysForBp.stream()
- .filter(meterKey -> meterKey.deviceId().equals(deviceId))
- .findFirst().ifPresent(mk -> {
- programmedMeters.remove(mk);
- });
- }
- }
-
private class InternalDeviceListener implements DeviceListener {
private Set<DeviceId> programmedDevices = Sets.newConcurrentHashSet();
@@ -1705,126 +871,131 @@
DeviceId devId = event.subject().id();
Device dev = event.subject();
Port port = event.port();
+ DeviceEvent.Type eventType = event.type();
- if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
+ if (DeviceEvent.Type.PORT_STATS_UPDATED.equals(eventType) ||
+ DeviceEvent.Type.DEVICE_SUSPENDED.equals(eventType) ||
+ DeviceEvent.Type.DEVICE_UPDATED.equals(eventType)) {
return;
}
+ log.debug("OLT got {} event for {} {}", eventType, event.subject(), event.port());
+
if (getOltInfo(dev) == null) {
// it's possible that we got an event for a previously
// programmed OLT that is no longer available in SADIS
// we let such events go through
if (!programmedDevices.contains(devId)) {
log.warn("No device info found for {}, this is either "
- + "not an OLT or not known to sadis", dev);
+ + "not an OLT or not known to sadis", dev);
return;
}
}
- log.debug("OLT got {} event for {}: {}", event.type(),
- event.subject().id(), event);
-
switch (event.type()) {
//TODO: Port handling and bookkeeping should be improved once
// olt firmware handles correct behaviour.
case PORT_ADDED:
if (isUniPort(dev, port)) {
post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
- if (port.isEnabled()) {
- processEapolFilteringObjectives(devId, port.number(), defaultBpId,
- null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
+
+ if (port.isEnabled() && !port.number().equals(PortNumber.LOCAL)) {
+ log.info("eapol will be sent for port added {}", port);
+ oltFlowService.processEapolFilteringObjectives(devId, port.number(), defaultBpId,
+ null,
+ VlanId.vlanId(EAPOL_DEFAULT_VLAN), true);
}
} else {
- checkAndCreateDeviceFlows(dev);
+ SubscriberAndDeviceInformation deviceInfo = getOltInfo(dev);
+ if (deviceInfo != null) {
+ oltFlowService.processNniFilteringObjectives(dev.id(), port.number(), true);
+ }
}
break;
case PORT_REMOVED:
if (isUniPort(dev, port)) {
removeSubscriber(new ConnectPoint(devId, port.number()));
- processEapolFilteringObjectives(devId, port.number(), defaultBpId,
- null, VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
+ log.info("eapol will be send for port removed", port);
+ oltFlowService.processEapolFilteringObjectives(devId, port.number(), defaultBpId,
+ null,
+ VlanId.vlanId(EAPOL_DEFAULT_VLAN), false);
post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
}
-
break;
case PORT_UPDATED:
if (!isUniPort(dev, port)) {
break;
}
-
- SubscriberAndDeviceInformation sub = programmedSubs
+ Set<UniTagInformation> uniTagInformationSet = programmedSubs
.get(new ConnectPoint(devId, port.number()));
- VlanId vlanId = sub == null ? VlanId.vlanId(EAPOL_DEFAULT_VLAN) : sub.cTag();
-
- String bpId = getCurrentBandwidthProfile(new ConnectPoint(devId, port.number()));
-
+ if (uniTagInformationSet == null || uniTagInformationSet.isEmpty()) {
+ if (port.isEnabled() && !port.number().equals(PortNumber.LOCAL)) {
+ log.info("eapol will be processed for port updated {}", port);
+ oltFlowService.processEapolFilteringObjectives(devId, port.number(), DEFAULT_BP_ID,
+ null,
+ VlanId.vlanId(EAPOL_DEFAULT_VLAN),
+ port.isEnabled());
+ }
+ } else {
+ log.info("eapol will be processed for port updated {}", port);
+ uniTagInformationSet.forEach(uniTag ->
+ oltFlowService.processEapolFilteringObjectives(devId, port.number(),
+ uniTag.getUpstreamBandwidthProfile(), null,
+ uniTag.getPonCTag(), port.isEnabled()));
+ }
if (port.isEnabled()) {
- processEapolFilteringObjectives(devId, port.number(), bpId,
- null, vlanId, true);
-
post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_ADDED, devId, port));
} else {
- processEapolFilteringObjectives(devId, port.number(), bpId,
- null, vlanId, false);
post(new AccessDeviceEvent(AccessDeviceEvent.Type.UNI_REMOVED, devId, port));
}
break;
case DEVICE_ADDED:
- post(new AccessDeviceEvent(
- AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
- null, null));
- programmedDevices.add(devId);
- // Send UNI_ADDED events for all existing ports
- deviceService.getPorts(devId).stream()
- .filter(p -> isUniPort(dev, p))
- .filter(Port::isEnabled)
- .forEach(p -> post(new AccessDeviceEvent(
- AccessDeviceEvent.Type.UNI_ADDED, devId, p)));
-
- checkAndCreateDeviceFlows(dev);
+ handleDeviceConnection(dev, true);
break;
case DEVICE_REMOVED:
- deviceService.getPorts(devId).stream()
- .filter(p -> isUniPort(dev, p))
- .forEach(p -> post(new AccessDeviceEvent(
- AccessDeviceEvent.Type.UNI_REMOVED, devId, p)));
- programmedDevices.remove(devId);
- removeAllSubscribers(devId);
- post(new AccessDeviceEvent(
- AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
- null, null));
+ handleDeviceDisconnection(dev, true);
break;
case DEVICE_AVAILABILITY_CHANGED:
if (deviceService.isAvailable(devId)) {
- post(new AccessDeviceEvent(
- AccessDeviceEvent.Type.DEVICE_CONNECTED, devId,
- null, null));
- programmedDevices.add(devId);
- checkAndCreateDeviceFlows(dev);
+ handleDeviceConnection(dev, false);
} else {
- programmedDevices.remove(devId);
- removeAllSubscribers(devId);
- post(new AccessDeviceEvent(
- AccessDeviceEvent.Type.DEVICE_DISCONNECTED, devId,
- null, null));
+ handleDeviceDisconnection(dev, false);
}
break;
- case DEVICE_UPDATED:
- case DEVICE_SUSPENDED:
- case PORT_STATS_UPDATED:
default:
return;
}
});
}
- private String getCurrentBandwidthProfile(ConnectPoint connectPoint) {
- SubscriberAndDeviceInformation sub = programmedSubs.get(connectPoint);
- if (sub != null) {
- return sub.upstreamBandwidthProfile();
+ private void sendUniEvent(Device device, AccessDeviceEvent.Type eventType) {
+ deviceService.getPorts(device.id()).stream()
+ .filter(p -> !PortNumber.LOCAL.equals(p.number()))
+ .filter(p -> isUniPort(device, p))
+ .forEach(p -> post(new AccessDeviceEvent(eventType, device.id(), p)));
+ }
+
+ private void handleDeviceDisconnection(Device device, boolean sendUniEvent) {
+ programmedDevices.remove(device.id());
+ removeAllSubscribers(device.id());
+ post(new AccessDeviceEvent(
+ AccessDeviceEvent.Type.DEVICE_DISCONNECTED, device.id(),
+ null, null, null));
+ if (sendUniEvent) {
+ sendUniEvent(device, AccessDeviceEvent.Type.UNI_REMOVED);
}
- return defaultBpId;
+ }
+
+ private void handleDeviceConnection(Device dev, boolean sendUniEvent) {
+ post(new AccessDeviceEvent(
+ AccessDeviceEvent.Type.DEVICE_CONNECTED, dev.id(),
+ null, null, null));
+ programmedDevices.add(dev.id());
+ checkAndCreateDeviceFlows(dev);
+ if (sendUniEvent) {
+ sendUniEvent(dev, AccessDeviceEvent.Type.UNI_ADDED);
+ }
}
private void removeAllSubscribers(DeviceId deviceId) {
@@ -1834,53 +1005,6 @@
connectPoints.forEach(cp -> programmedSubs.remove(cp));
}
- }
- private class InternalMeterListener implements MeterListener {
-
- @Override
- public void event(MeterEvent meterEvent) {
- if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
- log.debug("Zero Count Meter {} received", meterEvent.subject());
- Meter meter = meterEvent.subject();
- if (meter != null && appId.equals(meter.appId()) &&
- !programmedMeters.contains(MeterKey.key(meter.deviceId(), meter.id()))) {
- log.info("Deleting unreferenced, no longer programmed Meter {}",
- meter.id());
- deleteMeter(meter.deviceId(), meter.id());
- }
- } else if (MeterEvent.Type.METER_REMOVED.equals(meterEvent.type())) {
- log.debug("Meter removed event is received. Meter is {}",
- meterEvent.subject());
- removeMeterFromBpMap(meterEvent.subject());
- }
- }
-
- private void deleteMeter(DeviceId deviceId, MeterId meterId) {
- Meter meter = meterService.getMeter(deviceId, meterId);
- if (meter != null) {
- MeterRequest meterRequest = DefaultMeterRequest.builder()
- .withBands(meter.bands())
- .withUnit(meter.unit())
- .forDevice(deviceId)
- .fromApp(appId)
- .burst()
- .remove();
-
- meterService.withdraw(meterRequest, meterId);
- }
- }
-
- private void removeMeterFromBpMap(Meter meter) {
- bpInfoToMeter.values().forEach(meterKeys -> meterKeys.stream()
- .filter(meterKey -> (meterKey.deviceId().equals(meter.deviceId()))
- && meterKey.meterId().equals(meter.id())).findFirst().
- ifPresent(mk -> {
- meterKeys.remove(mk);
- programmedMeters.remove(mk);
- log.info("Deleted from the internal map. MeterKey {}", mk);
- log.info("Programmed meters {}", programmedMeters);
- }));
- }
}
}
diff --git a/app/src/main/java/org/opencord/olt/impl/OltFlowService.java b/app/src/main/java/org/opencord/olt/impl/OltFlowService.java
new file mode 100644
index 0000000..e04255c
--- /dev/null
+++ b/app/src/main/java/org/opencord/olt/impl/OltFlowService.java
@@ -0,0 +1,712 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.olt.impl;
+
+import com.google.common.collect.Sets;
+import org.onlab.packet.EthType;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.IPv6;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.TpPort;
+import org.onlab.packet.VlanId;
+import org.onlab.util.Tools;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flowobjective.DefaultFilteringObjective;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FilteringObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.flowobjective.ObjectiveContext;
+import org.onosproject.net.flowobjective.ObjectiveError;
+import org.onosproject.net.meter.MeterId;
+import org.opencord.olt.internalapi.AccessDeviceFlowService;
+import org.opencord.olt.internalapi.AccessDeviceMeterService;
+import org.opencord.sadis.BandwidthProfileInformation;
+import org.opencord.sadis.BaseInformationService;
+import org.opencord.sadis.SadisService;
+import org.opencord.sadis.SubscriberAndDeviceInformation;
+import org.opencord.sadis.UniTagInformation;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Modified;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.slf4j.Logger;
+
+import java.util.Dictionary;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onlab.util.Tools.get;
+import static org.opencord.olt.impl.OsgiPropertyConstants.*;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provisions flow rules on access devices.
+ */
+@Component(immediate = true, property = {
+ ENABLE_DHCP_ON_PROVISIONING + ":Boolean=" + ENABLE_DHCP_ON_PROVISIONING_DEFAULT,
+ ENABLE_DHCP_V4 + ":Boolean=" + ENABLE_DHCP_V4_DEFAULT,
+ ENABLE_DHCP_V6 + ":Boolean=" + ENABLE_DHCP_V6_DEFAULT,
+ ENABLE_IGMP_ON_PROVISIONING + ":Boolean=" + ENABLE_IGMP_ON_PROVISIONING_DEFAULT,
+ ENABLE_EAPOL + ":Boolean=" + ENABLE_EAPOL_DEFAULT,
+ DEFAULT_TP_ID + ":Integer=" + DEFAULT_TP_ID_DEFAULT
+})
+public class OltFlowService implements AccessDeviceFlowService {
+
+ private static final String APP_NAME = "org.opencord.olt";
+ private static final int NONE_TP_ID = -1;
+ private static final int NO_PCP = -1;
+ private static final Integer MAX_PRIORITY = 10000;
+ private static final Integer MIN_PRIORITY = 1000;
+ private static final int DEFAULT_TP_ID = 64;
+ private static final String INSTALLED = "installed";
+ private static final String REMOVED = "removed";
+ private static final String INSTALLATION = "installation";
+ private static final String REMOVAL = "removal";
+ private static final String V4 = "V4";
+ private static final String V6 = "V6";
+ private static final String NO_MAC = "A4:23:05:00:00:00";
+
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected FlowObjectiveService flowObjectiveService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected MastershipService mastershipService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected SadisService sadisService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected AccessDeviceMeterService oltMeterService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected ComponentConfigService componentConfigService;
+
+ /**
+ * Create the DHCP Flow rules when a subscriber is provisioned.
+ **/
+ protected boolean enableDhcpOnProvisioning = ENABLE_DHCP_ON_PROVISIONING_DEFAULT;
+
+ /**
+ * Enable flows for DHCP v4.
+ **/
+ protected boolean enableDhcpV4 = ENABLE_DHCP_V4_DEFAULT;
+
+ /**
+ * Enable flows for DHCP v6.
+ **/
+ protected boolean enableDhcpV6 = ENABLE_DHCP_V6_DEFAULT;
+
+ /**
+ * Create IGMP Flow rules when a subscriber is provisioned.
+ **/
+ protected boolean enableIgmpOnProvisioning = ENABLE_IGMP_ON_PROVISIONING_DEFAULT;
+
+ /**
+ * Send EAPOL authentication trap flows before subscriber provisioning.
+ **/
+ protected boolean enableEapol = ENABLE_EAPOL_DEFAULT;
+
+ /**
+ * Default technology profile id that is used for authentication trap flows.
+ **/
+ protected int defaultTechProfileId = DEFAULT_TP_ID_DEFAULT;
+
+ protected ApplicationId appId;
+ protected BaseInformationService<BandwidthProfileInformation> bpService;
+ protected BaseInformationService<SubscriberAndDeviceInformation> subsService;
+ private Set<PortNumber> pendingAddEapol = Sets.newConcurrentHashSet();
+
+ @Activate
+ public void activate(ComponentContext context) {
+ bpService = sadisService.getBandwidthProfileService();
+ subsService = sadisService.getSubscriberInfoService();
+ componentConfigService.registerProperties(getClass());
+ appId = coreService.getAppId(APP_NAME);
+ log.info("Olt Flow Service started");
+ }
+
+
+ @Deactivate
+ public void deactivate(ComponentContext context) {
+ componentConfigService.unregisterProperties(getClass(), false);
+ log.info("Olt flow service stopped");
+ }
+
+ @Modified
+ public void modified(ComponentContext context) {
+
+ Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
+
+ Boolean o = Tools.isPropertyEnabled(properties, "enableDhcpOnProvisioning");
+ if (o != null) {
+ enableDhcpOnProvisioning = o;
+ }
+
+ Boolean v4 = Tools.isPropertyEnabled(properties, "enableDhcpV4");
+ if (v4 != null) {
+ enableDhcpV4 = v4;
+ }
+
+ Boolean v6 = Tools.isPropertyEnabled(properties, "enableDhcpV6");
+ if (v6 != null) {
+ enableDhcpV6 = v6;
+ }
+
+ Boolean p = Tools.isPropertyEnabled(properties, "enableIgmpOnProvisioning");
+ if (p != null) {
+ enableIgmpOnProvisioning = p;
+ }
+
+ Boolean eap = Tools.isPropertyEnabled(properties, "enableEapol");
+ if (eap != null) {
+ enableEapol = eap;
+ }
+
+ String tpId = get(properties, "defaultTechProfileId");
+ defaultTechProfileId = isNullOrEmpty(tpId) ? DEFAULT_TP_ID : Integer.parseInt(tpId.trim());
+
+ }
+
+ @Override
+ public void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
+ MeterId upstreamMeterId,
+ UniTagInformation tagInformation,
+ boolean install,
+ boolean upstream) {
+ if (!enableDhcpOnProvisioning && !upstream) {
+ log.debug("Dhcp provisioning is disabled.");
+ return;
+ }
+
+ if (!mastershipService.isLocalMaster(devId)) {
+ return;
+ }
+
+ int techProfileId = tagInformation != null ? tagInformation.getTechnologyProfileId() : NONE_TP_ID;
+ VlanId cTag = tagInformation != null ? tagInformation.getPonCTag() : VlanId.NONE;
+ VlanId unitagMatch = tagInformation != null ? tagInformation.getUniTagMatch() : VlanId.ANY;
+
+ if (enableDhcpV4) {
+ int udpSrc = (upstream) ? 68 : 67;
+ int udpDst = (upstream) ? 67 : 68;
+
+ EthType ethType = EthType.EtherType.IPV4.ethType();
+ byte protocol = IPv4.PROTOCOL_UDP;
+
+ this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
+ upstreamMeterId, techProfileId, protocol, cTag, unitagMatch, install);
+ }
+
+ if (enableDhcpV6) {
+ int udpSrc = (upstream) ? 547 : 546;
+ int udpDst = (upstream) ? 546 : 547;
+
+ EthType ethType = EthType.EtherType.IPV6.ethType();
+ byte protocol = IPv6.PROTOCOL_UDP;
+
+ this.addDhcpFilteringObjectives(devId, port, udpSrc, udpDst, ethType,
+ upstreamMeterId, techProfileId, protocol, cTag, unitagMatch, install);
+ }
+ }
+
+ private void addDhcpFilteringObjectives(DeviceId devId, PortNumber port, int udpSrc, int udpDst,
+ EthType ethType, MeterId upstreamMeterId, int techProfileId, byte protocol,
+ VlanId cTag, VlanId unitagMatch, boolean install) {
+
+ DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
+ TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+
+ if (upstreamMeterId != null) {
+ treatmentBuilder.meter(upstreamMeterId);
+ }
+
+ if (techProfileId != NONE_TP_ID) {
+ treatmentBuilder.writeMetadata(createTechProfValueForWm(unitagMatch, techProfileId), 0);
+ }
+
+ FilteringObjective.Builder dhcpUpstreamBuilder = (install ? builder.permit() : builder.deny())
+ .withKey(Criteria.matchInPort(port))
+ .addCondition(Criteria.matchEthType(ethType))
+ .addCondition(Criteria.matchIPProtocol(protocol))
+ .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(udpSrc)))
+ .addCondition(Criteria.matchUdpDst(TpPort.tpPort(udpDst)))
+ .withMeta(treatmentBuilder
+ .setOutput(PortNumber.CONTROLLER).build())
+ .fromApp(appId)
+ .withPriority(MAX_PRIORITY);
+
+ if (!VlanId.NONE.equals(cTag)) {
+ dhcpUpstreamBuilder.addCondition(Criteria.matchVlanId(cTag));
+ }
+
+ FilteringObjective dhcpUpstream = dhcpUpstreamBuilder.add(new ObjectiveContext() {
+ @Override
+ public void onSuccess(Objective objective) {
+ log.info("DHCP {} filter for device {} on port {} {}.",
+ (ethType.equals(EthType.EtherType.IPV4.ethType())) ? V4 : V6,
+ devId, port, (install) ? INSTALLED : REMOVED);
+ }
+
+ @Override
+ public void onError(Objective objective, ObjectiveError error) {
+ log.info("DHCP {} filter for device {} on port {} failed {} because {}",
+ (ethType.equals(EthType.EtherType.IPV4.ethType())) ? V4 : V6,
+ devId, port, (install) ? INSTALLATION : REMOVAL,
+ error);
+ }
+ });
+
+ flowObjectiveService.filter(devId, dhcpUpstream);
+
+ }
+
+ @Override
+ public void processIgmpFilteringObjectives(DeviceId devId, PortNumber port,
+ MeterId upstreamMeterId,
+ UniTagInformation tagInformation,
+ boolean install,
+ boolean upstream) {
+ if (!enableIgmpOnProvisioning && !upstream) {
+ log.debug("Igmp provisioning is disabled.");
+ return;
+ }
+
+ if (!mastershipService.isLocalMaster(devId)) {
+ return;
+ }
+
+ DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
+ TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+ if (upstream) {
+
+ if (tagInformation.getTechnologyProfileId() != NONE_TP_ID) {
+ treatmentBuilder.writeMetadata(createTechProfValueForWm(null,
+ tagInformation.getTechnologyProfileId()), 0);
+ }
+
+
+ if (upstreamMeterId != null) {
+ treatmentBuilder.meter(upstreamMeterId);
+ }
+
+ if (!VlanId.NONE.equals(tagInformation.getPonCTag())) {
+ builder.addCondition(Criteria.matchVlanId(tagInformation.getPonCTag()));
+ }
+
+ if (tagInformation.getUsPonCTagPriority() != NO_PCP) {
+ builder.addCondition(Criteria.matchVlanPcp((byte) tagInformation.getUsPonCTagPriority()));
+ }
+ }
+
+ builder = install ? builder.permit() : builder.deny();
+
+ FilteringObjective igmp = builder
+ .withKey(Criteria.matchInPort(port))
+ .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
+ .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
+ .withMeta(treatmentBuilder
+ .setOutput(PortNumber.CONTROLLER).build())
+ .fromApp(appId)
+ .withPriority(MAX_PRIORITY)
+ .add(new ObjectiveContext() {
+ @Override
+ public void onSuccess(Objective objective) {
+ log.info("Igmp filter for {} on {} {}.",
+ devId, port, (install) ? INSTALLED : REMOVED);
+ }
+
+ @Override
+ public void onError(Objective objective, ObjectiveError error) {
+ log.info("Igmp filter for {} on {} failed {} because {}.",
+ devId, port, (install) ? INSTALLATION : REMOVAL,
+ error);
+ }
+ });
+
+ flowObjectiveService.filter(devId, igmp);
+ }
+
+ @Override
+ public void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, String bpId,
+ CompletableFuture<ObjectiveError> filterFuture,
+ VlanId vlanId, boolean install) {
+
+ if (!enableEapol) {
+ log.debug("Eapol filtering is disabled. Completing filteringFuture immediately for the device {}", devId);
+ if (filterFuture != null) {
+ filterFuture.complete(null);
+ }
+ return;
+ }
+
+ if (!mastershipService.isLocalMaster(devId)) {
+ log.warn("The master of the device {} is another instance", devId);
+ if (filterFuture != null) {
+ filterFuture.complete(ObjectiveError.DEVICEMISSING);
+ }
+ return;
+ }
+
+ BandwidthProfileInformation bpInfo = getBandwidthProfileInformation(bpId);
+ if (bpInfo == null) {
+ log.warn("Bandwidth profile {} is not found. Authentication flow"
+ + " will not be installed", bpId);
+ if (filterFuture != null) {
+ filterFuture.complete(ObjectiveError.BADPARAMS);
+ }
+ return;
+ }
+
+ if (install) {
+ boolean added = pendingAddEapol.add(portNumber);
+ if (!added) {
+ if (filterFuture != null) {
+ log.warn("The eapol flow is processing for the port {}. Ignoring this request", portNumber);
+ filterFuture.complete(null);
+ }
+ return;
+ }
+ log.info("portNumber added to pendingAddEapol map {}", portNumber);
+ }
+
+ DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
+ TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+ CompletableFuture<Object> meterFuture = new CompletableFuture<>();
+
+ // check if meter exists and create it only for an install
+ MeterId meterId = oltMeterService.getMeterIdFromBpMapping(devId, bpInfo.id());
+ if (meterId == null) {
+ if (install) {
+ meterId = oltMeterService.createMeter(devId, bpInfo, meterFuture);
+ treatmentBuilder.meter(meterId);
+ } else {
+ // this case should not happen as the request to remove an eapol
+ // flow should mean that the flow points to a meter that exists.
+ // Nevertheless we can still delete the flow as we only need the
+ // correct 'match' to do so.
+ log.warn("Unknown meter id for bp {}, still proceeding with "
+ + "delete of eapol flow for {}/{}", bpInfo.id(), devId, portNumber);
+ meterFuture.complete(null);
+ }
+ } else {
+ log.debug("Meter {} was previously created for bp {}", meterId, bpInfo.id());
+ treatmentBuilder.meter(meterId);
+ meterFuture.complete(null);
+ }
+
+ final MeterId mId = meterId;
+ meterFuture.thenAcceptAsync(result -> {
+ if (result == null) {
+ log.info("Meter {} for {} on {}/{} exists. {} EAPOL trap flow",
+ mId, bpId, devId, portNumber,
+ (install) ? "Installing" : "Removing");
+ int techProfileId = getDefaultTechProfileId(devId, portNumber);
+
+ //Authentication trap flow uses only tech profile id as write metadata value
+ FilteringObjective eapol = (install ? builder.permit() : builder.deny())
+ .withKey(Criteria.matchInPort(portNumber))
+ .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
+ .addCondition(Criteria.matchVlanId(vlanId))
+ .withMeta(treatmentBuilder
+ .writeMetadata(createTechProfValueForWm(vlanId, techProfileId), 0)
+ .setOutput(PortNumber.CONTROLLER).build())
+ .fromApp(appId)
+ .withPriority(MAX_PRIORITY)
+ .add(new ObjectiveContext() {
+ @Override
+ public void onSuccess(Objective objective) {
+ log.info("Eapol filter for {} on {} {} with meter {}.",
+ devId, portNumber, (install) ? INSTALLED : REMOVED, mId);
+ if (filterFuture != null) {
+ filterFuture.complete(null);
+ }
+ pendingAddEapol.remove(portNumber);
+ }
+
+ @Override
+ public void onError(Objective objective, ObjectiveError error) {
+ log.info("Eapol filter for {} on {} with meter {} failed {} because {}",
+ devId, portNumber, mId, (install) ? INSTALLATION : REMOVAL,
+ error);
+ if (filterFuture != null) {
+ filterFuture.complete(error);
+ }
+ pendingAddEapol.remove(portNumber);
+ }
+ });
+
+ flowObjectiveService.filter(devId, eapol);
+ } else {
+ log.warn("Meter installation error while sending eapol trap flow. " +
+ "Result {} and MeterId {}", result, mId);
+ }
+ });
+ }
+
+ /**
+ * Installs trap filtering objectives for particular traffic types on an
+ * NNI port.
+ *
+ * @param devId device ID
+ * @param port port number
+ * @param install true to install, false to remove
+ */
+ @Override
+ public void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install) {
+ log.info("Sending flows for NNI port {} of the device {}", port, devId);
+ processLldpFilteringObjective(devId, port, install);
+ processDhcpFilteringObjectives(devId, port, null, null, install, false);
+ processIgmpFilteringObjectives(devId, port, null, null, install, false);
+ }
+
+
+ @Override
+ public void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install) {
+ if (!mastershipService.isLocalMaster(devId)) {
+ return;
+ }
+ DefaultFilteringObjective.Builder builder = DefaultFilteringObjective.builder();
+
+ FilteringObjective lldp = (install ? builder.permit() : builder.deny())
+ .withKey(Criteria.matchInPort(port))
+ .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
+ .withMeta(DefaultTrafficTreatment.builder()
+ .setOutput(PortNumber.CONTROLLER).build())
+ .fromApp(appId)
+ .withPriority(MAX_PRIORITY)
+ .add(new ObjectiveContext() {
+ @Override
+ public void onSuccess(Objective objective) {
+ log.info("LLDP filter for device {} on port {} {}.",
+ devId, port, (install) ? INSTALLED : REMOVED);
+ }
+
+ @Override
+ public void onError(Objective objective, ObjectiveError error) {
+ log.info("LLDP filter for device {} on port {} failed {} because {}",
+ devId, port, (install) ? INSTALLATION : REMOVAL,
+ error);
+ }
+ });
+
+ flowObjectiveService.filter(devId, lldp);
+ }
+
+ @Override
+ public ForwardingObjective.Builder createTransparentBuilder(PortNumber uplinkPort,
+ PortNumber subscriberPort,
+ MeterId meterId,
+ UniTagInformation tagInfo,
+ boolean upstream) {
+
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchVlanId(tagInfo.getPonSTag())
+ .matchInPort(upstream ? subscriberPort : uplinkPort)
+ .matchInnerVlanId(tagInfo.getPonCTag())
+ .build();
+
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ if (meterId != null) {
+ tBuilder.meter(meterId);
+ }
+
+ TrafficTreatment treatment = tBuilder
+ .setOutput(upstream ? uplinkPort : subscriberPort)
+ .writeMetadata(createMetadata(upstream ? tagInfo.getPonSTag() : tagInfo.getPonCTag(),
+ tagInfo.getTechnologyProfileId(), upstream ? uplinkPort : subscriberPort), 0)
+ .build();
+
+ return createForwardingObjectiveBuilder(selector, treatment, MIN_PRIORITY);
+ }
+
+ @Override
+ public ForwardingObjective.Builder createUpBuilder(PortNumber uplinkPort,
+ PortNumber subscriberPort,
+ MeterId upstreamMeterId,
+ UniTagInformation uniTagInformation) {
+
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchInPort(subscriberPort)
+ .matchVlanId(uniTagInformation.getUniTagMatch())
+ .build();
+
+ TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder()
+ .pushVlan()
+ .setVlanId(uniTagInformation.getPonCTag());
+
+ if (uniTagInformation.getUsPonCTagPriority() != NO_PCP) {
+ treatmentBuilder.setVlanPcp((byte) uniTagInformation.getUsPonCTagPriority());
+ }
+
+ treatmentBuilder.pushVlan()
+ .setVlanId(uniTagInformation.getPonSTag());
+
+ if (uniTagInformation.getUsPonSTagPriority() != NO_PCP) {
+ treatmentBuilder.setVlanPcp((byte) uniTagInformation.getUsPonSTagPriority());
+ }
+
+ treatmentBuilder.setOutput(uplinkPort)
+ .writeMetadata(createMetadata(uniTagInformation.getPonCTag(),
+ uniTagInformation.getTechnologyProfileId(), uplinkPort), 0L);
+
+ if (upstreamMeterId != null) {
+ treatmentBuilder.meter(upstreamMeterId);
+ }
+
+ return createForwardingObjectiveBuilder(selector, treatmentBuilder.build(), MIN_PRIORITY);
+ }
+
+ @Override
+ public ForwardingObjective.Builder createDownBuilder(PortNumber uplinkPort,
+ PortNumber subscriberPort,
+ MeterId downstreamMeterId,
+ UniTagInformation tagInformation) {
+ TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder()
+ .matchVlanId(tagInformation.getPonSTag())
+ .matchInPort(uplinkPort)
+ .matchInnerVlanId(tagInformation.getPonCTag())
+ .matchMetadata(tagInformation.getPonCTag().toShort());
+
+ if (tagInformation.getDsPonSTagPriority() != NO_PCP) {
+ selectorBuilder.matchVlanPcp((byte) tagInformation.getDsPonSTagPriority());
+ }
+
+ if (tagInformation.getConfiguredMacAddress() != null &&
+ !NO_MAC.equals(tagInformation.getConfiguredMacAddress())) {
+ selectorBuilder.matchEthDst(MacAddress.valueOf(tagInformation.getConfiguredMacAddress()));
+ }
+
+ TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder()
+ .popVlan()
+ .setOutput(subscriberPort)
+ .writeMetadata(createMetadata(tagInformation.getPonCTag(), tagInformation.getTechnologyProfileId(),
+ subscriberPort), 0);
+
+ // to remark inner vlan header
+ if (tagInformation.getUsPonCTagPriority() != NO_PCP) {
+ treatmentBuilder.setVlanPcp((byte) tagInformation.getUsPonCTagPriority());
+ }
+
+ if (!VlanId.NONE.equals(tagInformation.getUniTagMatch())) {
+ treatmentBuilder.setVlanId(tagInformation.getUniTagMatch());
+ }
+
+ if (downstreamMeterId != null) {
+ treatmentBuilder.meter(downstreamMeterId);
+ }
+
+ return createForwardingObjectiveBuilder(selectorBuilder.build(), treatmentBuilder.build(), MIN_PRIORITY);
+ }
+
+ private DefaultForwardingObjective.Builder createForwardingObjectiveBuilder(TrafficSelector selector,
+ TrafficTreatment treatment,
+ Integer priority) {
+ return DefaultForwardingObjective.builder()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withPriority(priority)
+ .makePermanent()
+ .withSelector(selector)
+ .fromApp(appId)
+ .withTreatment(treatment);
+ }
+
+ /**
+ * Returns the write metadata value including tech profile reference and innerVlan.
+ * For param cVlan, null can be sent
+ *
+ * @param cVlan c (customer) tag of one subscriber
+ * @param techProfileId tech profile id of one subscriber
+ * @return the write metadata value including tech profile reference and innerVlan
+ */
+ private Long createTechProfValueForWm(VlanId cVlan, int techProfileId) {
+ if (cVlan == null || VlanId.NONE.equals(cVlan)) {
+ return (long) techProfileId << 32;
+ }
+ return ((long) (cVlan.id()) << 48 | (long) techProfileId << 32);
+ }
+
+ private BandwidthProfileInformation getBandwidthProfileInformation(String bandwidthProfile) {
+ if (bandwidthProfile == null) {
+ return null;
+ }
+ return bpService.get(bandwidthProfile);
+ }
+
+ /**
+ * It will be used to support AT&T use case (for EAPOL flows).
+ * If multiple services are found in uniServiceList, returns default tech profile id
+ * If one service is found, returns the found one
+ *
+ * @param devId
+ * @param portNumber
+ * @return the default technology profile id
+ */
+ private int getDefaultTechProfileId(DeviceId devId, PortNumber portNumber) {
+ Port port = deviceService.getPort(devId, portNumber);
+ if (port != null) {
+ SubscriberAndDeviceInformation info = subsService.get(port.annotations().value(AnnotationKeys.PORT_NAME));
+ if (info != null && info.uniTagList().size() == 1) {
+ return info.uniTagList().get(0).getTechnologyProfileId();
+ }
+ }
+ return defaultTechProfileId;
+ }
+
+ /**
+ * Write metadata instruction value (metadata) is 8 bytes.
+ * <p>
+ * MS 2 bytes: C Tag
+ * Next 2 bytes: Technology Profile Id
+ * Next 4 bytes: Port number (uni or nni)
+ */
+ private Long createMetadata(VlanId innerVlan, int techProfileId, PortNumber egressPort) {
+ if (techProfileId == NONE_TP_ID) {
+ techProfileId = DEFAULT_TP_ID;
+ }
+
+ return ((long) (innerVlan.id()) << 48 | (long) techProfileId << 32) | egressPort.toLong();
+ }
+
+
+}
diff --git a/app/src/main/java/org/opencord/olt/impl/OltMeterService.java b/app/src/main/java/org/opencord/olt/impl/OltMeterService.java
new file mode 100644
index 0000000..825604c
--- /dev/null
+++ b/app/src/main/java/org/opencord/olt/impl/OltMeterService.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.olt.impl;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+import org.onlab.util.Tools;
+import org.onosproject.cfg.ComponentConfigService;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flowobjective.ObjectiveError;
+import org.onosproject.net.meter.Band;
+import org.onosproject.net.meter.DefaultBand;
+import org.onosproject.net.meter.DefaultMeterRequest;
+import org.onosproject.net.meter.Meter;
+import org.onosproject.net.meter.MeterContext;
+import org.onosproject.net.meter.MeterEvent;
+import org.onosproject.net.meter.MeterFailReason;
+import org.onosproject.net.meter.MeterId;
+import org.onosproject.net.meter.MeterKey;
+import org.onosproject.net.meter.MeterListener;
+import org.onosproject.net.meter.MeterRequest;
+import org.onosproject.net.meter.MeterService;
+import org.opencord.olt.internalapi.AccessDeviceMeterService;
+import org.opencord.sadis.BandwidthProfileInformation;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Modified;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static org.onlab.util.Tools.groupedThreads;
+import static org.opencord.olt.impl.OsgiPropertyConstants.DELETE_METERS;
+import static org.opencord.olt.impl.OsgiPropertyConstants.DELETE_METERS_DEFAULT;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provisions Meters on access devices.
+ */
+@Component(immediate = true, property = {
+ DELETE_METERS + ":Boolean=" + DELETE_METERS_DEFAULT,
+ })
+public class OltMeterService implements AccessDeviceMeterService {
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected MeterService meterService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected CoreService coreService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected ComponentConfigService componentConfigService;
+
+ protected boolean deleteMeters = true;
+
+ protected SetMultimap<String, MeterKey> bpInfoToMeter =
+ Multimaps.synchronizedSetMultimap(HashMultimap.create());
+ protected Set<MeterKey> programmedMeters;
+ private ApplicationId appId;
+ private static final String APP_NAME = "org.opencord.olt";
+
+ private final MeterListener meterListener = new InternalMeterListener();
+
+ private final Logger log = getLogger(getClass());
+
+ protected ExecutorService eventExecutor;
+
+ @Activate
+ public void activate(ComponentContext context) {
+ eventExecutor = Executors.newFixedThreadPool(5, groupedThreads("onos/olt",
+ "events-%d", log));
+ appId = coreService.registerApplication(APP_NAME);
+ programmedMeters = Sets.newConcurrentHashSet();
+ meterService.addListener(meterListener);
+ componentConfigService.registerProperties(getClass());
+ log.info("Olt Meter service started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ meterService.removeListener(meterListener);
+ }
+
+
+ @Modified
+ public void modified(ComponentContext context) {
+ Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
+
+ Boolean d = Tools.isPropertyEnabled(properties, "deleteMeters");
+ if (d != null) {
+ deleteMeters = d;
+ }
+ }
+
+ @Override
+ public ImmutableMap<String, Collection<MeterKey>> getBpMeterMappings() {
+ return ImmutableMap.copyOf(bpInfoToMeter.asMap());
+ }
+
+ @Override
+ public void addMeterIdToBpMapping(DeviceId deviceId, MeterId meterId, String bandwidthProfile) {
+ bpInfoToMeter.put(bandwidthProfile, MeterKey.key(deviceId, meterId));
+ }
+
+ @Override
+ public MeterId getMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfile) {
+ if (bpInfoToMeter.get(bandwidthProfile) == null) {
+ log.warn("Bandwidth Profile '{}' is not currently mapped to a meter",
+ bandwidthProfile);
+ return null;
+ }
+
+ Optional<MeterKey> meterKeyForDevice = bpInfoToMeter.get(bandwidthProfile)
+ .stream()
+ .filter(meterKey -> meterKey.deviceId().equals(deviceId))
+ .findFirst();
+ if (meterKeyForDevice.isPresent()) {
+ log.debug("Found meter {} for bandwidth profile {}",
+ meterKeyForDevice.get().meterId(), bandwidthProfile);
+ return meterKeyForDevice.get().meterId();
+ } else {
+ log.warn("Bandwidth profile '{}' is not currently mapped to a meter",
+ bandwidthProfile);
+ return null;
+ }
+ }
+
+ @Override
+ public ImmutableSet<MeterKey> getProgMeters() {
+ return ImmutableSet.copyOf(programmedMeters);
+ }
+
+ @Override
+ public MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo,
+ CompletableFuture<Object> meterFuture) {
+ if (bpInfo == null) {
+ log.warn("Requested bandwidth profile information is NULL");
+ meterFuture.complete(ObjectiveError.BADPARAMS);
+ return null;
+ }
+
+ MeterId meterId = getMeterIdFromBpMapping(deviceId, bpInfo.id());
+ if (meterId != null) {
+ log.debug("Meter {} was previously created for bp {}", meterId, bpInfo.id());
+ meterFuture.complete(null);
+ return meterId;
+ }
+
+ List<Band> meterBands = createMeterBands(bpInfo);
+
+ final AtomicReference<MeterId> meterIdRef = new AtomicReference<>();
+ MeterRequest meterRequest = DefaultMeterRequest.builder()
+ .withBands(meterBands)
+ .withUnit(Meter.Unit.KB_PER_SEC)
+ .withContext(new MeterContext() {
+ @Override
+ public void onSuccess(MeterRequest op) {
+ meterFuture.complete(null);
+ }
+
+ @Override
+ public void onError(MeterRequest op, MeterFailReason reason) {
+ bpInfoToMeter.remove(bpInfo.id(),
+ MeterKey.key(deviceId, meterIdRef.get()));
+ meterFuture.complete(reason);
+ }
+ })
+ .forDevice(deviceId)
+ .fromApp(appId)
+ .burst()
+ .add();
+
+ Meter meter = meterService.submit(meterRequest);
+ meterIdRef.set(meter.id());
+ addMeterIdToBpMapping(deviceId, meterIdRef.get(), bpInfo.id());
+ programmedMeters.add(MeterKey.key(deviceId, meter.id()));
+ log.info("Meter is created. Meter Id {}", meter.id());
+ return meter.id();
+ }
+
+ private List<Band> createMeterBands(BandwidthProfileInformation bpInfo) {
+ List<Band> meterBands = new ArrayList<>();
+
+ meterBands.add(createMeterBand(bpInfo.committedInformationRate(), bpInfo.committedBurstSize()));
+ meterBands.add(createMeterBand(bpInfo.exceededInformationRate(), bpInfo.exceededBurstSize()));
+ meterBands.add(createMeterBand(bpInfo.assuredInformationRate(), 0L));
+
+ return meterBands;
+ }
+
+ private Band createMeterBand(long rate, Long burst) {
+ return DefaultBand.builder()
+ .withRate(rate) //already Kbps
+ .burstSize(burst) // already Kbits
+ .ofType(Band.Type.DROP) // no matter
+ .build();
+ }
+
+ private class InternalMeterListener implements MeterListener {
+
+ Map<MeterKey, AtomicInteger> pendingRemoveMeters = Maps.newConcurrentMap();
+
+ @Override
+ public void event(MeterEvent meterEvent) {
+ eventExecutor.execute(() -> {
+ Meter meter = meterEvent.subject();
+ if (meter == null) {
+ log.error("Meter in event {} is null", meterEvent);
+ return;
+ }
+ MeterKey key = MeterKey.key(meter.deviceId(), meter.id());
+ if (deleteMeters && MeterEvent.Type.METER_REFERENCE_COUNT_ZERO.equals(meterEvent.type())) {
+ log.info("Zero Count Meter Event is received. Meter is {}", meter.id());
+ incrementMeterCount(key);
+
+ if (appId.equals(meter.appId()) && pendingRemoveMeters.get(key).get() == 3) {
+ log.info("Deleting unreferenced, no longer programmed Meter {}", meter.id());
+ deleteMeter(meter.deviceId(), meter.id());
+ }
+ }
+ if (MeterEvent.Type.METER_REMOVED.equals(meterEvent.type())) {
+ log.info("Meter Removed Event is received for {}", meter.id());
+ programmedMeters.remove(key);
+ pendingRemoveMeters.remove(key);
+ removeMeterFromBpMapping(key);
+ }
+ });
+ }
+
+ private void incrementMeterCount(MeterKey key) {
+ if (key == null) {
+ return;
+ }
+ pendingRemoveMeters.compute(key,
+ (k, v) -> {
+ if (v == null) {
+ return new AtomicInteger(1);
+ }
+ v.addAndGet(1);
+ return v;
+ });
+ }
+
+ private void deleteMeter(DeviceId deviceId, MeterId meterId) {
+ Meter meter = meterService.getMeter(deviceId, meterId);
+ if (meter != null) {
+ MeterRequest meterRequest = DefaultMeterRequest.builder()
+ .withBands(meter.bands())
+ .withUnit(meter.unit())
+ .forDevice(deviceId)
+ .fromApp(appId)
+ .burst()
+ .remove();
+
+ meterService.withdraw(meterRequest, meterId);
+ }
+ }
+
+ private void removeMeterFromBpMapping(MeterKey meterKey) {
+ Iterator<Map.Entry<String, MeterKey>> iterator = bpInfoToMeter.entries().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry<String, MeterKey> entry = iterator.next();
+ if (entry.getValue().equals(meterKey)) {
+ iterator.remove();
+ log.info("Deleted meter for MeterKey {} - Last prog meters {}", meterKey, programmedMeters);
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/opencord/olt/impl/OsgiPropertyConstants.java b/app/src/main/java/org/opencord/olt/impl/OsgiPropertyConstants.java
index 8fe9906..3efeee8 100644
--- a/app/src/main/java/org/opencord/olt/impl/OsgiPropertyConstants.java
+++ b/app/src/main/java/org/opencord/olt/impl/OsgiPropertyConstants.java
@@ -24,6 +24,9 @@
private OsgiPropertyConstants() {
}
+ public static final String DEFAULT_MCAST_SERVICE_NAME = "multicastServiceName";
+ public static final String DEFAULT_MCAST_SERVICE_NAME_DEFAULT = "MC";
+
public static final String DEFAULT_VLAN = "defaultVlan";
public static final short DEFAULT_VLAN_DEFAULT = 0;
diff --git a/app/src/main/java/org/opencord/olt/internalapi/AccessDeviceFlowService.java b/app/src/main/java/org/opencord/olt/internalapi/AccessDeviceFlowService.java
new file mode 100644
index 0000000..362b154
--- /dev/null
+++ b/app/src/main/java/org/opencord/olt/internalapi/AccessDeviceFlowService.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.olt.internalapi;
+
+import org.onlab.packet.VlanId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.ObjectiveError;
+import org.onosproject.net.meter.MeterId;
+import org.opencord.sadis.UniTagInformation;
+
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Olt service for flow operations.
+ */
+public interface AccessDeviceFlowService {
+
+ /**
+ * Provisions or removes trap-to-controller DHCP packets.
+ *
+ * @param devId the target device identifier
+ * @param port the uni port for which this trap flow is designated
+ * @param upstreamMeterId the upstream meter id that includes the upstream
+ * bandwidth profile values such as PIR,CIR. If no meter id needs to be referenced,
+ * null can be sent
+ * @param tagInformation the uni tag (ctag, stag) information
+ * @param install true to install the flow, false to remove the flow
+ * @param upstream true if trapped packets are flowing upstream towards
+ * server, false if packets are flowing downstream towards client
+ */
+ void processDhcpFilteringObjectives(DeviceId devId, PortNumber port,
+ MeterId upstreamMeterId,
+ UniTagInformation tagInformation,
+ boolean install,
+ boolean upstream);
+
+ /**
+ * Trap igmp packets to the controller.
+ *
+ * @param devId Device identifier to send the flow
+ * @param port Uni Port number
+ * @param upstreamMeterId upstream meter id that represents the upstream bandwidth profile
+ * @param tagInformation the uni tag information of the subscriber
+ * @param install the indicator to install or to remove the flow
+ * @param upstream determines the direction of the flow
+ */
+ void processIgmpFilteringObjectives(DeviceId devId, PortNumber port,
+ MeterId upstreamMeterId,
+ UniTagInformation tagInformation,
+ boolean install,
+ boolean upstream);
+
+ /**
+ * Trap eapol authentication packets to the controller.
+ *
+ * @param devId the device identifier
+ * @param portNumber the port for which this trap flow is designated
+ * @param bpId bandwidth profile id to add the related meter to the flow
+ * @param filterFuture completable future for this filtering objective operation
+ * @param vlanId the default or customer tag for a subscriber
+ * @param install true to install the flow, false to remove the flow
+ */
+ void processEapolFilteringObjectives(DeviceId devId, PortNumber portNumber, String bpId,
+ CompletableFuture<ObjectiveError> filterFuture,
+ VlanId vlanId, boolean install);
+
+ /**
+ * Trap lldp packets to the controller.
+ *
+ * @param devId the device identifier
+ * @param port the port for which this trap flow is designated
+ * @param install true to install the flow, false to remove the flow
+ */
+ void processLldpFilteringObjective(DeviceId devId, PortNumber port, boolean install);
+
+ /**
+ * Installs trap filtering objectives for particular traffic types (LLDP, IGMP and DHCP) on an
+ * NNI port.
+ *
+ * @param devId device ID
+ * @param port port number
+ * @param install true to install, false to remove
+ */
+ void processNniFilteringObjectives(DeviceId devId, PortNumber port, boolean install);
+
+ /**
+ * Creates a ForwardingObjective builder with double-tag match criteria and output
+ * action. The treatment will not contain pop or push actions.
+ * If the last parameter is true, use the upstream meter id and vice versa.
+ *
+ * @param uplinkPort the nni port
+ * @param subscriberPort the uni port
+ * @param meterId the meter id that is assigned to upstream or downstream flows
+ * @param tagInfo the uni tag information
+ * @param upstream true to create upstream, false to create downstream builder
+ * @return ForwardingObjective.Builder
+ */
+ ForwardingObjective.Builder createTransparentBuilder(PortNumber uplinkPort,
+ PortNumber subscriberPort,
+ MeterId meterId,
+ UniTagInformation tagInfo,
+ boolean upstream);
+
+ /**
+ * Creates a ForwardingObjective builder for the upstream flows.
+ * The treatment will contain push action
+ *
+ * @param uplinkPort the nni port
+ * @param subscriberPort the uni port
+ * @param upstreamMeterId the meter id that is assigned to upstream flows
+ * @param uniTagInformation the uni tag information
+ * @return ForwardingObjective.Builder
+ */
+ ForwardingObjective.Builder createUpBuilder(PortNumber uplinkPort,
+ PortNumber subscriberPort,
+ MeterId upstreamMeterId,
+ UniTagInformation uniTagInformation);
+
+ /**
+ * Creates a ForwardingObjective builder for the downstream flows.
+ * The treatment will contain pop action
+ *
+ * @param uplinkPort the nni port
+ * @param subscriberPort the uni port
+ * @param downstreamMeterId the meter id that is assigned to downstream flows
+ * @param tagInformation the uni tag information
+ * @return ForwardingObjective.Builder
+ */
+ ForwardingObjective.Builder createDownBuilder(PortNumber uplinkPort,
+ PortNumber subscriberPort,
+ MeterId downstreamMeterId,
+ UniTagInformation tagInformation);
+}
diff --git a/app/src/main/java/org/opencord/olt/internalapi/AccessDeviceMeterService.java b/app/src/main/java/org/opencord/olt/internalapi/AccessDeviceMeterService.java
new file mode 100644
index 0000000..4f07131
--- /dev/null
+++ b/app/src/main/java/org/opencord/olt/internalapi/AccessDeviceMeterService.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.olt.internalapi;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.meter.MeterId;
+import org.onosproject.net.meter.MeterKey;
+import org.opencord.sadis.BandwidthProfileInformation;
+
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Olt service for meter operations.
+ */
+public interface AccessDeviceMeterService {
+
+ /**
+ * Returns information about bandwidthProfile-meterKey (device / meter) mappings
+ * that have been programmed in the data-plane.
+ *
+ * @return an immutable map of bandwidthProfile-meterKey (device / meter) mappings
+ */
+ ImmutableMap<String, Collection<MeterKey>> getBpMeterMappings();
+
+ /**
+ * Adds a bandwidthProfile-meterKey (device / meter) mapping that have been programmed
+ * in the data plane.
+ *
+ * @param deviceId the access device id
+ * @param meterId the meter id that is mapped to the bandwidth profile
+ * @param bandwidthProfile the bandwidth profile id
+ */
+ void addMeterIdToBpMapping(DeviceId deviceId, MeterId meterId, String bandwidthProfile);
+
+ /**
+ * Returns the meter id for a given bandwidth profile.
+ *
+ * @param deviceId the access device id
+ * @param bandwidthProfile the bandwidth profile id
+ * @return the meter id
+ */
+ MeterId getMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfile);
+
+ /**
+ * Returns information about device-meter relations that have been programmed in the
+ * data-plane.
+ *
+ * @return an immutable set of device-meter mappings
+ */
+ ImmutableSet<MeterKey> getProgMeters();
+
+ /**
+ * Creates a meter and sends it to the device.
+ *
+ * @param deviceId the access device id
+ * @param bpInfo the bandwidth profile information
+ * @param meterFuture the meter future to indicate whether the meter creation is
+ * successful or not.
+ * @return meter id that is generated for the given parameters
+ */
+ MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo,
+ CompletableFuture<Object> meterFuture);
+
+
+}
diff --git a/app/src/main/java/org/opencord/olt/internalapi/package-info.java b/app/src/main/java/org/opencord/olt/internalapi/package-info.java
new file mode 100644
index 0000000..2b5d98d
--- /dev/null
+++ b/app/src/main/java/org/opencord/olt/internalapi/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Internal APIs for the OLT application.
+ */
+package org.opencord.olt.internalapi;
diff --git a/app/src/main/java/org/opencord/olt/rest/OltWebResource.java b/app/src/main/java/org/opencord/olt/rest/OltWebResource.java
index 1631b09..54af4ac 100644
--- a/app/src/main/java/org/opencord/olt/rest/OltWebResource.java
+++ b/app/src/main/java/org/opencord/olt/rest/OltWebResource.java
@@ -24,6 +24,7 @@
import org.opencord.olt.AccessSubscriberId;
import java.util.Optional;
+import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
@@ -32,7 +33,7 @@
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-import static javax.ws.rs.core.Response.Status.NOT_FOUND;
+import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
/**
* OLT REST APIs.
@@ -46,19 +47,23 @@
*
* @param device device id
* @param port port number
- * @return 200 OK
+ * @return 200 OK or 500 Internal Server Error
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
@Path("{device}/{port}")
public Response provisionSubscriber(
- @PathParam("device")String device,
- @PathParam("port")long port) {
+ @PathParam("device") String device,
+ @PathParam("port") long port) {
AccessDeviceService service = get(AccessDeviceService.class);
DeviceId deviceId = DeviceId.deviceId(device);
PortNumber portNumber = PortNumber.portNumber(port);
ConnectPoint connectPoint = new ConnectPoint(deviceId, portNumber);
- service.provisionSubscriber(connectPoint);
+ try {
+ service.provisionSubscriber(connectPoint);
+ } catch (Exception e) {
+ return Response.status(INTERNAL_SERVER_ERROR).build();
+ }
return ok("").build();
}
@@ -86,90 +91,102 @@
* Provision service for a subscriber.
*
* @param portName Name of the port on which the subscriber is connected
- * @return 200 OK or 404 NOT_FOUND
+ * @return 200 OK or 204 NO CONTENT
*/
@POST
@Produces(MediaType.APPLICATION_JSON)
@Path("services/{portName}")
public Response provisionServices(
- @PathParam("portName")String portName) {
+ @PathParam("portName") String portName) {
AccessDeviceService service = get(AccessDeviceService.class);
Optional<VlanId> emptyVlan = Optional.empty();
- if (service.provisionSubscriber(new AccessSubscriberId(portName), emptyVlan, emptyVlan)) {
+ Optional<Integer> emptyTpId = Optional.empty();
+ if (service.provisionSubscriber(new AccessSubscriberId(portName), emptyVlan, emptyVlan, emptyTpId)) {
return ok("").build();
}
- return Response.status(NOT_FOUND).build();
+ return Response.noContent().build();
}
/**
* Provision service with particular tags for a subscriber.
*
* @param portName Name of the port on which the subscriber is connected
- * @param sTagVal additional outer tag on this port
- * @param cTagVal additional innter tag on this port
- * @return 200 OK or 404 NOT_FOUND
+ * @param sTagVal additional outer tag on this port
+ * @param cTagVal additional innter tag on this port
+ * @param tpIdVal technology profile id
+ * @return 200 OK or 204 NO CONTENT
*/
@POST
+ @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
- @Path("services/{portName}/{sTag}/{cTag}")
+ @Path("services/{portName}/{sTag}/{cTag}/{tpId}")
public Response provisionAdditionalVlans(
- @PathParam("portName")String portName,
- @PathParam("sTag")String sTagVal,
- @PathParam("cTag")String cTagVal) {
+ @PathParam("portName") String portName,
+ @PathParam("sTag") String sTagVal,
+ @PathParam("cTag") String cTagVal,
+ @PathParam("tpId") String tpIdVal) {
AccessDeviceService service = get(AccessDeviceService.class);
VlanId cTag = VlanId.vlanId(cTagVal);
VlanId sTag = VlanId.vlanId(sTagVal);
+ Integer tpId = Integer.valueOf(tpIdVal);
- if (service.provisionSubscriber(new AccessSubscriberId(portName), Optional.of(sTag), Optional.of(cTag))) {
+ if (service.provisionSubscriber(new AccessSubscriberId(portName), Optional.of(sTag),
+ Optional.of(cTag), Optional.of(tpId))) {
return ok("").build();
}
- return Response.status(NOT_FOUND).build();
+ return Response.noContent().build();
}
/**
* Removes services for a subscriber.
*
* @param portName Name of the port on which the subscriber is connected
- * @return 200 OK or 404 NOT_FOUND
+ * @return 200 OK or 204 NO CONTENT
*/
@DELETE
@Produces(MediaType.APPLICATION_JSON)
@Path("services/{portName}")
public Response deleteServices(
- @PathParam("portName")String portName) {
+ @PathParam("portName") String portName) {
AccessDeviceService service = get(AccessDeviceService.class);
Optional<VlanId> emptyVlan = Optional.empty();
- if (service.removeSubscriber(new AccessSubscriberId(portName), emptyVlan, emptyVlan)) {
+ Optional<Integer> emptyTpId = Optional.empty();
+ if (service.removeSubscriber(new AccessSubscriberId(portName), emptyVlan, emptyVlan, emptyTpId)) {
return ok("").build();
}
- return Response.status(NOT_FOUND).build();
+ return Response.noContent().build();
}
/**
* Removes additional vlans of a particular subscriber.
*
* @param portName Name of the port on which the subscriber is connected
- * @param sTagVal additional outer tag on this port which needs to be removed
- * @param cTagVal additional inner tag on this port which needs to be removed
- * @return 200 OK or 404 NOT_FOUND
+ * @param sTagVal additional outer tag on this port which needs to be removed
+ * @param cTagVal additional inner tag on this port which needs to be removed
+ * @param tpIdVal additional technology profile id
+ * @return 200 OK or 204 NO CONTENT
*/
@DELETE
+ @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
- @Path("services/{portName}/{sTag}/{cTag}")
+ @Path("services/{portName}/{sTag}/{cTag}/{tpId}")
public Response removeAdditionalVlans(
- @PathParam("portName")String portName,
- @PathParam("sTag")String sTagVal,
- @PathParam("cTag")String cTagVal) {
+ @PathParam("portName") String portName,
+ @PathParam("sTag") String sTagVal,
+ @PathParam("cTag") String cTagVal,
+ @PathParam("tpId") String tpIdVal) {
AccessDeviceService service = get(AccessDeviceService.class);
VlanId cTag = VlanId.vlanId(cTagVal);
VlanId sTag = VlanId.vlanId(sTagVal);
+ Integer tpId = Integer.valueOf(tpIdVal);
- if (service.removeSubscriber(new AccessSubscriberId(portName), Optional.of(sTag), Optional.of(cTag))) {
+ if (service.removeSubscriber(new AccessSubscriberId(portName), Optional.of(sTag),
+ Optional.of(cTag), Optional.of(tpId))) {
return ok("").build();
}
- return Response.status(NOT_FOUND).build();
+ return Response.noContent().build();
}
}
diff --git a/app/src/main/resources/vlan_cfg.json b/app/src/main/resources/vlan_cfg.json
index 133aed7..3bb577f 100644
--- a/app/src/main/resources/vlan_cfg.json
+++ b/app/src/main/resources/vlan_cfg.json
@@ -1,6 +1,6 @@
{
-"apps" : {
- "org.opencord.sadis" : {
+ "apps" : {
+ "org.opencord.sadis" : {
"sadis" : {
"integration" : {
"cache" : {
@@ -11,12 +11,44 @@
},
"entries" : [ {
"id" : "s1-eth1",
- "cTag" : 2,
- "sTag" : 4,
"nasPortId" : "s1-eth1",
- "technologyProfileId" : 10,
- "upstreamBandwidthProfile" : "High-Speed-Internet",
- "downstreamBandwidthProfile" : "User1-Specific"
+ "uniTagList": [
+ {
+ "uniTagMatch": 35,
+ "ponCTag":33,
+ "ponSTag":7,
+ "technologyProfileId": 2,
+ "upstreamBandwidthProfile":"High-Speed-Internet",
+ "downstreamBandwidthProfile":"Service1"
+ },
+ {
+ "uniTagMatch": 45,
+ "ponCTag":43,
+ "ponSTag":10,
+ "technologyProfileId": 3,
+ "upstreamBandwidthProfile":"VOIP",
+ "downstreamBandwidthProfile":"Service2",
+ "isDhcpRequired":"true"
+ },
+ {
+ "uniTagMatch": 55,
+ "ponCTag": 55,
+ "ponSTag": 550,
+ "technologyProfileId": 4,
+ "upstreamBandwidthProfile": "VOD",
+ "downstreamBandwidthProfile": "Service3",
+ "isDhcpRequired": "true",
+ "isIgmpRequired": "true"
+ },
+ {
+ "ponCTag": 55,
+ "ponSTag": 555,
+ "dsPonCTagPriority": 5,
+ "dsPonSTagPriority": 5,
+ "technologyProfileId": 4,
+ "serviceName": "MC"
+ }
+ ]
}, {
"id" : "1",
"hardwareIdentifier" : "00:00:00:00:00:01",
@@ -24,39 +56,76 @@
"uplinkPort": "2"
} ]
},
- "bandwidthprofile":{
- "integration":{
- "cache":{
- "enabled":true,
- "maxsize":40,
- "ttl":"PT1m"
- }
- },
- "entries":[
- {
- "id":"High-Speed-Internet",
- "cir":200000000,
- "cbs":348000,
- "eir":10000000,
- "ebs":348000,
- "air":10000000
- },
- {
- "id":"User1-Specific",
- "cir":300000000,
- "cbs":348000,
- "eir":20000000,
- "ebs":348000
- }
- ]
- }
+ "bandwidthprofile":{
+ "integration":{
+ "cache":{
+ "enabled":true,
+ "maxsize":40,
+ "ttl":"PT1m"
+ }
+ },
+ "entries":[
+ {
+ "id":"High-Speed-Internet",
+ "cir": 500000,
+ "cbs": 10000,
+ "eir": 500000,
+ "ebs": 10000,
+ "air": 100000
+ },
+ {
+ "id":"VOIP",
+ "cir": 500000,
+ "cbs": 10000,
+ "eir": 500000,
+ "ebs": 10000,
+ "air": 100000
+ },
+ {
+ "id":"Service1",
+ "cir": 600000,
+ "cbs": 10000,
+ "eir": 400000,
+ "ebs": 10000
+ },
+ {
+ "id":"Service2",
+ "cir": 600000,
+ "cbs": 10000,
+ "eir": 400000,
+ "ebs": 10000
+ },
+ {
+ "id":"VOD",
+ "cir": 600000,
+ "cbs": 10000,
+ "eir": 400000,
+ "ebs": 10000
+ },
+ {
+ "id":"Service3",
+ "cir": 600000,
+ "cbs": 10000,
+ "eir": 400000,
+ "ebs": 10000
+ },
+ {
+ "id":"Default",
+ "cir": 0,
+ "cbs": 0,
+ "eir": 512,
+ "ebs": 30,
+ "air": 0
+ }
+ ]
+ }
}
},
- "devices":{
- "of:0000000000000001":{
- "basic":{
- "driver":"pmc-olt"
- }
+ "devices":{
+ "of:0000000000000001":{
+ "basic":{
+ "driver":"pmc-olt"
}
- }
+ }
+ }
}
diff --git a/app/src/main/resources/vlan_cfg_with_default.json b/app/src/main/resources/vlan_cfg_with_default.json
index 7cd792a..e168283 100644
--- a/app/src/main/resources/vlan_cfg_with_default.json
+++ b/app/src/main/resources/vlan_cfg_with_default.json
@@ -11,12 +11,17 @@
},
"entries" : [ {
"id" : "s1-eth1",
- "cTag" : 2,
- "sTag" : 4,
"nasPortId" : "s1-eth1",
- "technologyProfileId" : 10,
- "upstreamBandwidthProfile" : "High-Speed-Internet",
- "downstreamBandwidthProfile" : "User1-Specific"
+ "uniTagList": [
+ {
+ "uniTagMatch": 35,
+ "ponCTag":33,
+ "ponSTag":7,
+ "technologyProfileId": 2,
+ "upstreamBandwidthProfile":"High-Speed-Internet",
+ "downstreamBandwidthProfile":"Service1"
+ }
+ ]
}, {
"id" : "1",
"hardwareIdentifier" : "00:00:00:00:00:01",
@@ -35,26 +40,55 @@
"entries":[
{
"id":"High-Speed-Internet",
- "cir":200000000,
- "cbs":348000,
- "eir":10000000,
- "ebs":348000,
- "air":10000000
+ "cir": 500000,
+ "cbs": 10000,
+ "eir": 500000,
+ "ebs": 10000,
+ "air": 100000
},
{
- "id":"User1-Specific",
- "cir":300000000,
- "cbs":348000,
- "eir":20000000,
- "ebs":348000
+ "id":"VOIP",
+ "cir": 500000,
+ "cbs": 10000,
+ "eir": 500000,
+ "ebs": 10000,
+ "air": 100000
+ },
+ {
+ "id":"Service1",
+ "cir": 600000,
+ "cbs": 10000,
+ "eir": 400000,
+ "ebs": 10000
+ },
+ {
+ "id":"Service2",
+ "cir": 600000,
+ "cbs": 10000,
+ "eir": 400000,
+ "ebs": 10000
+ },
+ {
+ "id":"VOD",
+ "cir": 600000,
+ "cbs": 10000,
+ "eir": 400000,
+ "ebs": 10000
+ },
+ {
+ "id":"Service3",
+ "cir": 600000,
+ "cbs": 10000,
+ "eir": 400000,
+ "ebs": 10000
},
{
"id":"Default",
- "cir":0,
- "cbs":0,
- "eir":512,
- "ebs":30,
- "air":0
+ "cir": 0,
+ "cbs": 0,
+ "eir": 512,
+ "ebs": 30,
+ "air": 0
}
]
}
diff --git a/app/src/test/java/org/opencord/olt/impl/OltFlowTest.java b/app/src/test/java/org/opencord/olt/impl/OltFlowTest.java
new file mode 100644
index 0000000..16b407b
--- /dev/null
+++ b/app/src/test/java/org/opencord/olt/impl/OltFlowTest.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.olt.impl;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ListMultimap;
+import org.apache.commons.lang3.tuple.Pair;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.EthType;
+import org.onlab.packet.VlanId;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.cluster.RoleInfo;
+import org.onosproject.mastership.MastershipInfo;
+import org.onosproject.mastership.MastershipListener;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.MastershipRole;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.EthTypeCriterion;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flowobjective.FilteringObjQueueKey;
+import org.onosproject.net.flowobjective.FilteringObjective;
+import org.onosproject.net.flowobjective.ForwardingObjQueueKey;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.NextObjQueueKey;
+import org.onosproject.net.flowobjective.NextObjective;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.meter.MeterId;
+import org.onosproject.net.meter.MeterKey;
+import org.opencord.sadis.BandwidthProfileInformation;
+import org.opencord.sadis.UniTagInformation;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+
+public class OltFlowTest extends TestBase {
+ private OltFlowService oltFlowService;
+
+ PortNumber uniPortNumber = PortNumber.portNumber(1);
+ PortNumber nniPortNumber = PortNumber.portNumber(65535);
+
+ UniTagInformation.Builder tagInfoBuilder = new UniTagInformation.Builder();
+ UniTagInformation uniTagInfo = tagInfoBuilder.setUniTagMatch(VlanId.vlanId((short) 35))
+ .setPonCTag(VlanId.vlanId((short) 33))
+ .setPonSTag(VlanId.vlanId((short) 7))
+ .setDsPonCTagPriority(0)
+ .setUsPonSTagPriority(0)
+ .setTechnologyProfileId(64)
+ .setDownstreamBandwidthProfile(dsBpId)
+ .setUpstreamBandwidthProfile(usBpId)
+ .build();
+
+ @Before
+ public void setUp() {
+ oltFlowService = new OltFlowService();
+ oltFlowService.oltMeterService = new MockOltMeterService();
+ oltFlowService.flowObjectiveService = new MockOltFlowObjectiveService();
+ oltFlowService.mastershipService = new MockMastershipService();
+ oltFlowService.sadisService = new MockSadisService();
+ oltFlowService.bpService = oltFlowService.sadisService.getBandwidthProfileService();
+ oltFlowService.appId = appId;
+ }
+
+ @Test
+ public void testDhcpFiltering() {
+ oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber, usMeterId, uniTagInfo,
+ true, true);
+ oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber, usMeterId, uniTagInfo,
+ false, true);
+ oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber, dsMeterId, uniTagInfo,
+ true, false);
+ oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber, usMeterId, uniTagInfo,
+ false, false);
+ }
+
+ @Test
+ public void testIgmpFiltering() {
+ oltFlowService.processIgmpFilteringObjectives(DEVICE_ID_1, uniPortNumber, usMeterId, uniTagInfo,
+ true, true);
+ oltFlowService.processIgmpFilteringObjectives(DEVICE_ID_1, uniPortNumber, usMeterId, uniTagInfo,
+ false, true);
+ }
+
+ @Test
+ public void testEapolFiltering() {
+ addBandwidthProfile(uniTagInfo.getUpstreamBandwidthProfile());
+ oltFlowService.enableEapol = true;
+
+ //will install
+ oltFlowService.processEapolFilteringObjectives(DEVICE_ID_1, uniPortNumber,
+ uniTagInfo.getUpstreamBandwidthProfile(), new CompletableFuture<>(),
+ uniTagInfo.getUniTagMatch(), true);
+
+ //bp profile doesn't exist
+ oltFlowService.processEapolFilteringObjectives(DEVICE_ID_1, uniPortNumber,
+ uniTagInfo.getDownstreamBandwidthProfile(), new CompletableFuture<>(),
+ uniTagInfo.getUniTagMatch(), true);
+ }
+
+ @Test
+ public void testLldpFiltering() {
+ oltFlowService.processLldpFilteringObjective(DEVICE_ID_1, nniPortNumber, true);
+ oltFlowService.processLldpFilteringObjective(DEVICE_ID_1, nniPortNumber, false);
+ }
+
+ @Test
+ public void testNniFiltering() {
+ oltFlowService.enableDhcpOnProvisioning = true;
+ oltFlowService.enableIgmpOnProvisioning = true;
+ oltFlowService.processNniFilteringObjectives(DEVICE_ID_1, nniPortNumber, true);
+ oltFlowService.processNniFilteringObjectives(DEVICE_ID_1, nniPortNumber, false);
+ }
+
+ @Test
+ public void testUpBuilder() {
+ ForwardingObjective objective =
+ oltFlowService.createUpBuilder(nniPortNumber, uniPortNumber, usMeterId, uniTagInfo).add();
+ checkObjective(objective, true);
+ }
+
+ @Test
+ public void testDownBuilder() {
+ ForwardingObjective objective =
+ oltFlowService.createDownBuilder(nniPortNumber, uniPortNumber, dsMeterId, uniTagInfo).remove();
+ checkObjective(objective, false);
+ }
+
+ private void checkObjective(ForwardingObjective fwd, boolean upstream) {
+ TrafficTreatment treatment = fwd.treatment();
+
+ //check instructions
+ Set<Instructions.MeterInstruction> meters = treatment.meters();
+ assert !meters.isEmpty();
+
+ Instructions.MetadataInstruction writeMetadata = treatment.writeMetadata();
+ assert writeMetadata != null;
+
+ List<Instruction> immediateInstructions = treatment.immediate();
+ Optional<Instruction> vlanInstruction = immediateInstructions.stream()
+ .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
+ .filter(i -> ((L2ModificationInstruction) i).subtype() ==
+ L2ModificationInstruction.L2SubType.VLAN_PUSH ||
+ ((L2ModificationInstruction) i).subtype() ==
+ L2ModificationInstruction.L2SubType.VLAN_POP)
+ .findAny();
+
+ assert vlanInstruction.isPresent();
+
+ //check match criteria
+ TrafficSelector selector = fwd.selector();
+ assert selector.getCriterion(Criterion.Type.IN_PORT) != null;
+ assert selector.getCriterion(Criterion.Type.VLAN_VID) != null;
+
+ if (!upstream) {
+ assert selector.getCriterion(Criterion.Type.METADATA) != null;
+ }
+ }
+
+ private class MockOltMeterService implements org.opencord.olt.internalapi.AccessDeviceMeterService {
+ @Override
+ public ImmutableMap<String, Collection<MeterKey>> getBpMeterMappings() {
+ return null;
+ }
+
+ @Override
+ public void addMeterIdToBpMapping(DeviceId deviceId, MeterId meterId, String bandwidthProfile) {
+
+ }
+
+ @Override
+ public MeterId getMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfile) {
+ return null;
+ }
+
+
+ @Override
+ public ImmutableSet<MeterKey> getProgMeters() {
+ return null;
+ }
+
+ @Override
+ public MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo,
+ CompletableFuture<Object> meterFuture) {
+ return usMeterId;
+ }
+ }
+
+ private class MockOltFlowObjectiveService implements org.onosproject.net.flowobjective.FlowObjectiveService {
+ @Override
+ public void filter(DeviceId deviceId, FilteringObjective filteringObjective) {
+
+ EthTypeCriterion ethType = (EthTypeCriterion)
+ filterForCriterion(filteringObjective.conditions(), Criterion.Type.ETH_TYPE);
+
+ Instructions.MeterInstruction meter = filteringObjective.meta().metered();
+ Instruction writeMetadata = filteringObjective.meta().writeMetadata();
+ VlanIdCriterion vlanIdCriterion = (VlanIdCriterion)
+ filterForCriterion(filteringObjective.conditions(), Criterion.Type.VLAN_VID);
+ PortCriterion portCriterion = (PortCriterion) filteringObjective.key();
+
+
+ if (ethType.ethType().equals(EthType.EtherType.LLDP.ethType()) ||
+ portCriterion.port().equals(nniPortNumber)) {
+ assert meter == null;
+ assert writeMetadata == null;
+ assert vlanIdCriterion == null;
+ } else {
+ assert meter.meterId().equals(usMeterId) || meter.meterId().equals(dsMeterId);
+ assert writeMetadata != null;
+ assert vlanIdCriterion.vlanId() == uniTagInfo.getPonCTag();
+ }
+
+ }
+
+ @Override
+ public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
+
+ }
+
+ @Override
+ public void next(DeviceId deviceId, NextObjective nextObjective) {
+
+ }
+
+ @Override
+ public int allocateNextId() {
+ return 0;
+ }
+
+ @Override
+ public void initPolicy(String s) {
+
+ }
+
+ @Override
+ public void apply(DeviceId deviceId, Objective objective) {
+
+ }
+
+ @Override
+ public Map<Pair<Integer, DeviceId>, List<String>> getNextMappingsChain() {
+ return null;
+ }
+
+ @Override
+ public List<String> getNextMappings() {
+ return null;
+ }
+
+ @Override
+ public List<String> getPendingFlowObjectives() {
+ return null;
+ }
+
+ @Override
+ public ListMultimap<FilteringObjQueueKey, Objective> getFilteringObjQueue() {
+ return null;
+ }
+
+ @Override
+ public ListMultimap<ForwardingObjQueueKey, Objective> getForwardingObjQueue() {
+ return null;
+ }
+
+ @Override
+ public ListMultimap<NextObjQueueKey, Objective> getNextObjQueue() {
+ return null;
+ }
+
+ @Override
+ public Map<FilteringObjQueueKey, Objective> getFilteringObjQueueHead() {
+ return null;
+ }
+
+ @Override
+ public Map<ForwardingObjQueueKey, Objective> getForwardingObjQueueHead() {
+ return null;
+ }
+
+ @Override
+ public Map<NextObjQueueKey, Objective> getNextObjQueueHead() {
+ return null;
+ }
+
+ @Override
+ public void clearQueue() {
+
+ }
+
+ private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
+ return criteria.stream()
+ .filter(c -> c.type().equals(type))
+ .limit(1)
+ .findFirst().orElse(null);
+ }
+ }
+
+ private class MockMastershipService implements org.onosproject.mastership.MastershipService {
+ @Override
+ public MastershipRole getLocalRole(DeviceId deviceId) {
+ return null;
+ }
+
+ @Override
+ public boolean isLocalMaster(DeviceId deviceId) {
+ return true;
+ }
+
+ @Override
+ public CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId) {
+ return null;
+ }
+
+ @Override
+ public CompletableFuture<Void> relinquishMastership(DeviceId deviceId) {
+ return null;
+ }
+
+ @Override
+ public NodeId getMasterFor(DeviceId deviceId) {
+ return null;
+ }
+
+ @Override
+ public RoleInfo getNodesFor(DeviceId deviceId) {
+ return null;
+ }
+
+ @Override
+ public MastershipInfo getMastershipFor(DeviceId deviceId) {
+ return null;
+ }
+
+ @Override
+ public Set<DeviceId> getDevicesOf(NodeId nodeId) {
+ return null;
+ }
+
+ @Override
+ public void addListener(MastershipListener mastershipListener) {
+
+ }
+
+ @Override
+ public void removeListener(MastershipListener mastershipListener) {
+
+ }
+ }
+}
diff --git a/app/src/test/java/org/opencord/olt/impl/OltMeterTest.java b/app/src/test/java/org/opencord/olt/impl/OltMeterTest.java
new file mode 100644
index 0000000..da7e3e1
--- /dev/null
+++ b/app/src/test/java/org/opencord/olt/impl/OltMeterTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.olt.impl;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.Sets;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.meter.DefaultMeter;
+import org.onosproject.net.meter.Meter;
+import org.onosproject.net.meter.MeterId;
+import org.onosproject.net.meter.MeterKey;
+import org.onosproject.net.meter.MeterListener;
+import org.onosproject.net.meter.MeterRequest;
+import org.opencord.sadis.BandwidthProfileInformation;
+
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
+
+public class OltMeterTest extends TestBase {
+ private OltMeterService oltMeterService;
+
+ private BandwidthProfileInformation bandwidthProfileInformation = new BandwidthProfileInformation();
+
+ @Before
+ public void setUp() {
+ oltMeterService = new OltMeterService();
+ oltMeterService.bpInfoToMeter = Multimaps.synchronizedSetMultimap(HashMultimap.create());
+ oltMeterService.programmedMeters = Sets.newConcurrentHashSet();
+ oltMeterService.meterService = new MockMeterService();
+ }
+
+ @Test
+ public void testAddAndGetMeterIdToBpMapping() {
+ oltMeterService.addMeterIdToBpMapping(DEVICE_ID_1, usMeterId, usBpId);
+ MeterId usMeterId = oltMeterService.getMeterIdFromBpMapping(DEVICE_ID_1, usBpId);
+ assert usMeterId.equals(this.usMeterId);
+
+ oltMeterService.addMeterIdToBpMapping(DEVICE_ID_1, dsMeterId, dsBpId);
+ MeterId dsMeterId = oltMeterService.getMeterIdFromBpMapping(DEVICE_ID_1, dsBpId);
+ assert dsMeterId.equals(this.dsMeterId);
+
+ ImmutableMap<String, Collection<MeterKey>> meterMappings = oltMeterService.getBpMeterMappings();
+ assert meterMappings.size() == 2;
+ }
+
+ @Test
+ public void testCreateMeter() {
+ //with provided bandwidth profile information
+ bandwidthProfileInformation.setId(usBpId);
+ bandwidthProfileInformation.setExceededInformationRate(10000);
+ bandwidthProfileInformation.setExceededBurstSize(10000L);
+ bandwidthProfileInformation.setCommittedBurstSize(10000L);
+ bandwidthProfileInformation.setCommittedInformationRate(10000);
+
+ oltMeterService.addMeterIdToBpMapping(DEVICE_ID_1, usMeterId, usBpId);
+
+
+ MeterId meterId =
+ oltMeterService.createMeter(DEVICE_ID_1, bandwidthProfileInformation, new CompletableFuture<>());
+ assert meterId != null;
+
+ //with null bandwidth profile information
+ meterId = oltMeterService.createMeter(DEVICE_ID_1, null, new CompletableFuture<>());
+ assert meterId == null;
+ }
+
+
+ private class MockMeterService implements org.onosproject.net.meter.MeterService {
+ @Override
+ public Meter submit(MeterRequest meterRequest) {
+ return DefaultMeter.builder()
+ .forDevice(DEVICE_ID_1)
+ .fromApp(appId)
+ .withId(usMeterId)
+ .build();
+ }
+
+ @Override
+ public void withdraw(MeterRequest meterRequest, MeterId meterId) {
+
+ }
+
+ @Override
+ public Meter getMeter(DeviceId deviceId, MeterId meterId) {
+ return null;
+ }
+
+ @Override
+ public Collection<Meter> getAllMeters() {
+ return null;
+ }
+
+ @Override
+ public Collection<Meter> getMeters(DeviceId deviceId) {
+ return null;
+ }
+
+ @Override
+ public MeterId allocateMeterId(DeviceId deviceId) {
+ return null;
+ }
+
+ @Override
+ public void freeMeterId(DeviceId deviceId, MeterId meterId) {
+
+ }
+
+ @Override
+ public void addListener(MeterListener meterListener) {
+
+ }
+
+ @Override
+ public void removeListener(MeterListener meterListener) {
+
+ }
+ }
+}
diff --git a/app/src/test/java/org/opencord/olt/impl/OltTest.java b/app/src/test/java/org/opencord/olt/impl/OltTest.java
index a925aa3..c417590 100644
--- a/app/src/test/java/org/opencord/olt/impl/OltTest.java
+++ b/app/src/test/java/org/opencord/olt/impl/OltTest.java
@@ -18,14 +18,10 @@
import static org.junit.Assert.assertEquals;
import java.util.Set;
-
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.ChassisId;
-import org.onlab.packet.Ip4Address;
-import org.onlab.packet.MacAddress;
-import org.onlab.packet.VlanId;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.Annotations;
import org.onosproject.net.ConnectPoint;
@@ -38,24 +34,15 @@
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceServiceAdapter;
import org.onosproject.net.provider.ProviderId;
-import org.opencord.sadis.BandwidthProfileInformation;
-import org.opencord.sadis.BaseInformationService;
import org.opencord.sadis.SubscriberAndDeviceInformation;
-import org.opencord.sadis.SadisService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class OltTest {
+public class OltTest extends TestBase {
private final Logger log = LoggerFactory.getLogger(getClass());
private Olt olt;
- private static final VlanId CLIENT_C_TAG = VlanId.vlanId((short) 999);
- private static final VlanId CLIENT_S_TAG = VlanId.vlanId((short) 111);
- private static final String CLIENT_NAS_PORT_ID = "PON 1/1";
- private static final String CLIENT_CIRCUIT_ID = "CIR-PON 1/1";
- private static final String OLT_DEV_ID = "of:00000000000000aa";
- private static final DeviceId DEVICE_ID_1 = DeviceId.deviceId(OLT_DEV_ID);
private static final String SCHEME_NAME = "olt";
private static final DefaultAnnotations DEVICE_ANNOTATIONS = DefaultAnnotations.builder()
.set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase()).build();
@@ -66,7 +53,6 @@
olt.deviceService = new MockDeviceService();
olt.sadisService = new MockSadisService();
olt.subsService = olt.sadisService.getSubscriberInfoService();
-
}
/**
@@ -92,8 +78,6 @@
SubscriberAndDeviceInformation s = olt.getSubscriber(cp);
assertEquals(s.circuitId(), CLIENT_CIRCUIT_ID);
- assertEquals(s.cTag(), CLIENT_C_TAG);
- assertEquals(s.sTag(), CLIENT_S_TAG);
assertEquals(s.nasPortId(), CLIENT_NAS_PORT_ID);
}
@@ -103,7 +87,7 @@
String manufacturer, String hwVersion, String swVersion,
String serialNumber, ChassisId chassisId, Annotations... annotations) {
super(providerId, id, type, manufacturer, hwVersion, swVersion, serialNumber,
- chassisId, annotations);
+ chassisId, annotations);
}
}
@@ -111,8 +95,8 @@
private ProviderId providerId = new ProviderId("of", "foo");
private final Device device1 = new MockDevice(providerId, DEVICE_ID_1, Device.Type.SWITCH,
- "foo.inc", "0", "0", OLT_DEV_ID, new ChassisId(),
- DEVICE_ANNOTATIONS);
+ "foo.inc", "0", "0", OLT_DEV_ID, new ChassisId(),
+ DEVICE_ANNOTATIONS);
@Override
public Device getDevice(DeviceId devId) {
@@ -170,53 +154,8 @@
}
}
- private class MockSadisService implements SadisService {
- @Override
- public BaseInformationService<SubscriberAndDeviceInformation> getSubscriberInfoService() {
- return new MockSubService();
- }
- @Override
- public BaseInformationService<BandwidthProfileInformation> getBandwidthProfileService() {
- return null;
- }
- }
-
- private class MockSubService implements BaseInformationService<SubscriberAndDeviceInformation> {
- MockSubscriberAndDeviceInformation sub =
- new MockSubscriberAndDeviceInformation(CLIENT_NAS_PORT_ID, CLIENT_C_TAG,
- CLIENT_S_TAG, CLIENT_NAS_PORT_ID, CLIENT_CIRCUIT_ID, null, null);
- @Override
- public SubscriberAndDeviceInformation get(String id) {
- return sub;
- }
-
- @Override
- public void invalidateAll() {}
- @Override
- public void invalidateId(String id) {}
- @Override
- public SubscriberAndDeviceInformation getfromCache(String id) {
- return null;
- }
- }
-
- private class MockSubscriberAndDeviceInformation extends SubscriberAndDeviceInformation {
-
- MockSubscriberAndDeviceInformation(String id, VlanId ctag,
- VlanId stag, String nasPortId,
- String circuitId, MacAddress hardId,
- Ip4Address ipAddress) {
- this.setCTag(ctag);
- this.setHardwareIdentifier(hardId);
- this.setId(id);
- this.setIPAddress(ipAddress);
- this.setSTag(stag);
- this.setNasPortId(nasPortId);
- this.setCircuitId(circuitId);
- }
- }
}
\ No newline at end of file
diff --git a/app/src/test/java/org/opencord/olt/impl/TestBase.java b/app/src/test/java/org/opencord/olt/impl/TestBase.java
new file mode 100644
index 0000000..b8447a9
--- /dev/null
+++ b/app/src/test/java/org/opencord/olt/impl/TestBase.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.opencord.olt.impl;
+
+import com.google.common.collect.Maps;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
+import org.onosproject.core.DefaultApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.meter.MeterId;
+import org.opencord.sadis.BandwidthProfileInformation;
+import org.opencord.sadis.BaseInformationService;
+import org.opencord.sadis.SadisService;
+import org.opencord.sadis.SubscriberAndDeviceInformation;
+
+import java.util.Map;
+
+public class TestBase {
+
+ protected static final String CLIENT_NAS_PORT_ID = "PON 1/1";
+ protected static final String CLIENT_CIRCUIT_ID = "CIR-PON 1/1";
+ protected static final String OLT_DEV_ID = "of:00000000000000aa";
+ protected static final DeviceId DEVICE_ID_1 = DeviceId.deviceId(OLT_DEV_ID);
+ protected MeterId usMeterId = MeterId.meterId(1);
+ protected MeterId dsMeterId = MeterId.meterId(2);
+ protected String usBpId = "HSIA-US";
+ protected String dsBpId = "HSIA-DS";
+ protected DefaultApplicationId appId = new DefaultApplicationId(1, "OltServices");
+
+ Map<String, BandwidthProfileInformation> bpInformation = Maps.newConcurrentMap();
+
+ protected void addBandwidthProfile(String id) {
+ BandwidthProfileInformation bpInfo = new BandwidthProfileInformation();
+ bpInfo.setAssuredInformationRate(0);
+ bpInfo.setCommittedInformationRate(10000);
+ bpInfo.setCommittedBurstSize(1000L);
+ bpInfo.setExceededBurstSize(2000L);
+ bpInfo.setExceededInformationRate(20000);
+ bpInformation.put(id, bpInfo);
+ }
+
+ protected class MockSadisService implements SadisService {
+
+ @Override
+ public BaseInformationService<SubscriberAndDeviceInformation> getSubscriberInfoService() {
+ return new MockSubService();
+ }
+
+ @Override
+ public BaseInformationService<BandwidthProfileInformation> getBandwidthProfileService() {
+ return new MockBpService();
+ }
+ }
+
+ private class MockBpService implements BaseInformationService<BandwidthProfileInformation> {
+
+ @Override
+ public void invalidateAll() {
+
+ }
+
+ @Override
+ public void invalidateId(String id) {
+
+ }
+
+ @Override
+ public BandwidthProfileInformation get(String id) {
+ return bpInformation.get(id);
+ }
+
+ @Override
+ public BandwidthProfileInformation getfromCache(String id) {
+ return null;
+ }
+ }
+
+ private class MockSubService implements BaseInformationService<SubscriberAndDeviceInformation> {
+ MockSubscriberAndDeviceInformation sub =
+ new MockSubscriberAndDeviceInformation(CLIENT_NAS_PORT_ID,
+ CLIENT_NAS_PORT_ID, CLIENT_CIRCUIT_ID, null, null);
+
+ @Override
+ public SubscriberAndDeviceInformation get(String id) {
+ return sub;
+ }
+
+ @Override
+ public void invalidateAll() {
+ }
+
+ @Override
+ public void invalidateId(String id) {
+ }
+
+ @Override
+ public SubscriberAndDeviceInformation getfromCache(String id) {
+ return null;
+ }
+ }
+
+ private class MockSubscriberAndDeviceInformation extends SubscriberAndDeviceInformation {
+
+ MockSubscriberAndDeviceInformation(String id, String nasPortId,
+ String circuitId, MacAddress hardId,
+ Ip4Address ipAddress) {
+ this.setHardwareIdentifier(hardId);
+ this.setId(id);
+ this.setIPAddress(ipAddress);
+ this.setNasPortId(nasPortId);
+ this.setCircuitId(circuitId);
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index bf02e6e..e102c59 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,7 +31,7 @@
<packaging>pom</packaging>
<properties>
- <sadis.api.version>4.0.1</sadis.api.version>
+ <sadis.api.version>5.0.0-SNAPSHOT</sadis.api.version>
</properties>
<modules>
@@ -56,6 +56,18 @@
</dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <configuration>
+ <sourceDirectories>${project.build.sourceDirectory}</sourceDirectories>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
<repositories>
<repository>
<id>central</id>