Initial import of CFM and SOAM api
Change-Id: Icf5cc2d5fb34b75460e80e8cced0d70265bcd33b
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/CfmWebComponent.java b/apps/cfm/src/main/java/org/onosproject/cfm/CfmWebComponent.java
new file mode 100644
index 0000000..6ead985
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/CfmWebComponent.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.VlanId;
+import org.onosproject.cfm.web.ComponentCodec;
+import org.onosproject.cfm.web.FngAddressCodec;
+import org.onosproject.cfm.web.MaintenanceAssociationCodec;
+import org.onosproject.cfm.web.MaintenanceDomainCodec;
+import org.onosproject.cfm.web.MepCodec;
+import org.onosproject.cfm.web.MepEntryCodec;
+import org.onosproject.cfm.web.MepLbCreateCodec;
+import org.onosproject.cfm.web.MepLbEntryCodec;
+import org.onosproject.cfm.web.MepLtCreateCodec;
+import org.onosproject.cfm.web.RemoteMepEntryCodec;
+import org.onosproject.cfm.web.VidCodec;
+import org.onosproject.codec.CodecService;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep.FngAddress;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLbCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLbEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLtCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.RemoteMepEntry;
+import org.onosproject.incubator.net.l2monitoring.soam.StartTime;
+import org.onosproject.incubator.net.l2monitoring.soam.StopTime;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementCreate;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementCreate.MeasurementOption;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementEntry;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementStat;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementStatCurrent;
+import org.onosproject.incubator.net.l2monitoring.soam.delay.DelayMeasurementStatHistory;
+import org.onosproject.incubator.net.l2monitoring.soam.loss.LossAvailabilityStat;
+import org.onosproject.incubator.net.l2monitoring.soam.loss.LossAvailabilityStatCurrent;
+import org.onosproject.incubator.net.l2monitoring.soam.loss.LossAvailabilityStatHistory;
+import org.onosproject.incubator.net.l2monitoring.soam.loss.LossMeasurementCreate;
+import org.onosproject.incubator.net.l2monitoring.soam.loss.LossMeasurementCreate.CounterOption;
+import org.onosproject.incubator.net.l2monitoring.soam.loss.LossMeasurementEntry;
+import org.onosproject.incubator.net.l2monitoring.soam.loss.LossMeasurementStat;
+import org.onosproject.incubator.net.l2monitoring.soam.loss.LossMeasurementStatCurrent;
+import org.onosproject.incubator.net.l2monitoring.soam.loss.LossMeasurementStatHistory;
+import org.onosproject.incubator.net.l2monitoring.soam.loss.LossMeasurementThreshold;
+import org.onosproject.soam.web.DelayMeasurementStatCodec;
+import org.onosproject.soam.web.DelayMeasurementStatCurrentCodec;
+import org.onosproject.soam.web.DelayMeasurementStatHistoryCodec;
+import org.onosproject.soam.web.DmCreateCodec;
+import org.onosproject.soam.web.DmEntryCodec;
+import org.onosproject.soam.web.DmMeasurementOptionCodec;
+import org.onosproject.soam.web.LmCounterOptionCodec;
+import org.onosproject.soam.web.LmCreateCodec;
+import org.onosproject.soam.web.LmEntryCodec;
+import org.onosproject.soam.web.LmThresholdOptionCodec;
+import org.onosproject.soam.web.LossAvailabilityStatCodec;
+import org.onosproject.soam.web.LossAvailabilityStatCurrentCodec;
+import org.onosproject.soam.web.LossAvailabilityStatHistoryCodec;
+import org.onosproject.soam.web.LossMeasurementStatCodec;
+import org.onosproject.soam.web.LossMeasurementStatCurrentCodec;
+import org.onosproject.soam.web.LossMeasurementStatHistoryCodec;
+import org.onosproject.soam.web.LossMeasurementThresholdCodec;
+import org.onosproject.soam.web.StartTimeCodec;
+import org.onosproject.soam.web.StopTimeCodec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.onosproject.incubator.net.l2monitoring.soam.loss.LossMeasurementThreshold.*;
+
+/**
+ * Enables the CFM REST Web Service component at /onos/cfm.
+ * Each codec for the rest interfaces should be registered here.
+ */
+@Component(immediate = true)
+public class CfmWebComponent {
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected CodecService codecService;
+
+ @Activate
+ public void activate() {
+ codecService.registerCodec(MaintenanceDomain.class,
+ new MaintenanceDomainCodec());
+ codecService.registerCodec(MaintenanceAssociation.class,
+ new MaintenanceAssociationCodec());
+ codecService.registerCodec(org.onosproject.incubator.net.l2monitoring.cfm.Component.class,
+ new ComponentCodec());
+ codecService.registerCodec(VlanId.class, new VidCodec());
+ codecService.registerCodec(Mep.class, new MepCodec());
+ codecService.registerCodec(MepEntry.class, new MepEntryCodec());
+ codecService.registerCodec(MepLbCreate.class, new MepLbCreateCodec());
+ codecService.registerCodec(MepLbEntry.class, new MepLbEntryCodec());
+ codecService.registerCodec(MepLtCreate.class, new MepLtCreateCodec());
+ codecService.registerCodec(RemoteMepEntry.class, new RemoteMepEntryCodec());
+ codecService.registerCodec(FngAddress.class, new FngAddressCodec());
+
+
+ codecService.registerCodec(DelayMeasurementCreate.class,
+ new DmCreateCodec());
+ codecService.registerCodec(DelayMeasurementEntry.class,
+ new DmEntryCodec());
+ codecService.registerCodec(DelayMeasurementStat.class,
+ new DelayMeasurementStatCodec());
+ codecService.registerCodec(DelayMeasurementStatCurrent.class,
+ new DelayMeasurementStatCurrentCodec());
+ codecService.registerCodec(DelayMeasurementStatHistory.class,
+ new DelayMeasurementStatHistoryCodec());
+ codecService.registerCodec(MeasurementOption.class,
+ new DmMeasurementOptionCodec());
+
+ codecService.registerCodec(LossMeasurementCreate.class,
+ new LmCreateCodec());
+ codecService.registerCodec(LossMeasurementThreshold.class,
+ new LossMeasurementThresholdCodec());
+ codecService.registerCodec(LossMeasurementEntry.class,
+ new LmEntryCodec());
+ codecService.registerCodec(LossMeasurementStat.class,
+ new LossMeasurementStatCodec());
+ codecService.registerCodec(LossMeasurementStatCurrent.class,
+ new LossMeasurementStatCurrentCodec());
+ codecService.registerCodec(LossMeasurementStatHistory.class,
+ new LossMeasurementStatHistoryCodec());
+ codecService.registerCodec(LossAvailabilityStat.class,
+ new LossAvailabilityStatCodec());
+ codecService.registerCodec(LossAvailabilityStatCurrent.class,
+ new LossAvailabilityStatCurrentCodec());
+ codecService.registerCodec(LossAvailabilityStatHistory.class,
+ new LossAvailabilityStatHistoryCodec());
+ codecService.registerCodec(CounterOption.class,
+ new LmCounterOptionCodec());
+ codecService.registerCodec(ThresholdOption.class,
+ new LmThresholdOptionCodec());
+
+ codecService.registerCodec(StartTime.class, new StartTimeCodec());
+ codecService.registerCodec(StopTime.class, new StopTimeCodec());
+
+ log.info("CFM Web Component Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("CFM Web Component Stopped");
+ codecService.unregisterCodec(MaintenanceDomain.class);
+ codecService.unregisterCodec(MaintenanceAssociation.class);
+ codecService.unregisterCodec(org.onosproject.incubator.net.l2monitoring.cfm.Component.class);
+ codecService.unregisterCodec(VlanId.class);
+ codecService.unregisterCodec(Mep.class);
+ codecService.unregisterCodec(MepEntry.class);
+ codecService.unregisterCodec(MepLbCreate.class);
+ codecService.unregisterCodec(MepLbEntry.class);
+ codecService.unregisterCodec(MepLtCreate.class);
+ codecService.unregisterCodec(RemoteMepEntry.class);
+ codecService.unregisterCodec(FngAddress.class);
+
+ codecService.unregisterCodec(DelayMeasurementCreate.class);
+ codecService.unregisterCodec(DelayMeasurementEntry.class);
+ codecService.unregisterCodec(DelayMeasurementStat.class);
+ codecService.unregisterCodec(DelayMeasurementStatCurrent.class);
+ codecService.unregisterCodec(DelayMeasurementStatHistory.class);
+ codecService.unregisterCodec(MeasurementOption.class);
+ codecService.unregisterCodec(StartTime.class);
+ codecService.unregisterCodec(StopTime.class);
+
+ codecService.unregisterCodec(LossMeasurementCreate.class);
+ codecService.unregisterCodec(LossMeasurementThreshold.class);
+ codecService.unregisterCodec(LossMeasurementEntry.class);
+ codecService.unregisterCodec(LossMeasurementStat.class);
+ codecService.unregisterCodec(LossMeasurementStatCurrent.class);
+ codecService.unregisterCodec(LossMeasurementStatHistory.class);
+ codecService.unregisterCodec(LossAvailabilityStat.class);
+ codecService.unregisterCodec(LossAvailabilityStatCurrent.class);
+ codecService.unregisterCodec(LossAvailabilityStatHistory.class);
+ codecService.unregisterCodec(CounterOption.class);
+ codecService.unregisterCodec(ThresholdOption.class);
+
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMaAddCommand.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMaAddCommand.java
new file mode 100644
index 0000000..d449cce
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMaAddCommand.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.VlanId;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.l2monitoring.cfm.Component;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultComponent;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaId2Octet;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdIccY1731;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdPrimaryVid;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdRfc2685VpnId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdDomainName;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdMacUint;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdNone;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+
+/**
+ * Adds a Maintenance Association to a Maintenance Domain.
+ */
+@Command(scope = "onos", name = "cfm-ma-add",
+ description = "Add a CFM Maintenance Association to a Maintenance Domain.")
+public class CfmMaAddCommand extends AbstractShellCommand {
+ @Argument(index = 0, name = "name",
+ description = "Maintenance Domain name and type (in brackets)",
+ required = true, multiValued = false)
+ String mdName = null;
+
+ @Argument(index = 1, name = "name-type",
+ description = "Maintenance Assocation name type",
+ required = true, multiValued = false)
+ String nameType = null;
+
+ @Argument(index = 2, name = "name",
+ description = "Maintenance Assocation name. Restrictions apply depending " +
+ "on name-type",
+ required = true, multiValued = false)
+ String name = null;
+
+ @Argument(index = 3, name = "ccm-interval",
+ description = "CCM Interval values from list",
+ required = true, multiValued = false)
+ String ccmInterval = null;
+
+ @Argument(index = 4, name = "numeric-id",
+ description = "An optional numeric id for Maintenance Association [1-65535]",
+ required = false, multiValued = false)
+ short numericId = 0;
+
+ @Argument(index = 5, name = "component-id",
+ description = "An id for a Component in the Component List [1-65535]." +
+ "The CLI allows creation of only 1 component. If more are " +
+ "required use the REST interface",
+ required = false, multiValued = false)
+ short componentId = 0;
+
+ @Argument(index = 6, name = "component-tag-type",
+ description = "Tag Type value for the component",
+ required = false, multiValued = false)
+ String tagType = null;
+
+ @Argument(index = 7, name = "component-mhf-creation",
+ description = "MEP Half function creation type for the component",
+ required = false, multiValued = false)
+ String mhfCreationType = null;
+
+ @Argument(index = 8, name = "component-vid",
+ description = "A VID for the component [1-4095]. This CLI allows " +
+ "only the specification of 1 VID. If more are required use " +
+ "the REST interface",
+ required = false, multiValued = false)
+ short vid = 0;
+
+ @Argument(index = 9, name = "rmep",
+ description = "Remote Mep numeric identifier [1-8192]",
+ required = true, multiValued = true)
+ String[] rmepArray = null;
+
+ @Override
+ protected void execute() {
+ CfmMdService service = get(CfmMdService.class);
+
+ String[] mdNameParts = mdName.split("[()]");
+ if (mdNameParts.length != 2) {
+ throw new IllegalArgumentException("Invalid name format. " +
+ "Must be in the format of <identifier(name-type)>");
+ }
+
+ MdId mdId = null;
+ MdId.MdNameType mdNameTypeEnum = MdId.MdNameType.valueOf(mdNameParts[1]);
+ switch (mdNameTypeEnum) {
+ case DOMAINNAME:
+ mdId = MdIdDomainName.asMdId(mdNameParts[0]);
+ break;
+ case MACANDUINT:
+ mdId = MdIdMacUint.asMdId(mdNameParts[0]);
+ break;
+ case NONE:
+ mdId = MdIdNone.asMdId();
+ break;
+ case CHARACTERSTRING:
+ default:
+ mdId = MdIdCharStr.asMdId(mdNameParts[0]);
+ }
+
+ MaIdShort maId = null;
+ MaIdShort.MaIdType maNameTypeEnum = MaIdShort.MaIdType.valueOf(nameType);
+ switch (maNameTypeEnum) {
+ case TWOOCTET:
+ maId = MaId2Octet.asMaId(name);
+ break;
+ case ICCY1731:
+ maId = MaIdIccY1731.asMaId(name);
+ break;
+ case PRIMARYVID:
+ maId = MaIdPrimaryVid.asMaId(name);
+ break;
+ case RFC2685VPNID:
+ maId = MaIdRfc2685VpnId.asMaIdHex(name);
+ break;
+ case CHARACTERSTRING:
+ default:
+ maId = MaIdCharStr.asMaId(name);
+ }
+
+ MaintenanceAssociation.MaBuilder builder = null;
+ try {
+ builder = DefaultMaintenanceAssociation.builder(maId, mdId.getNameLength());
+ if (ccmInterval != null && !ccmInterval.isEmpty()) {
+ builder = builder.ccmInterval(MaintenanceAssociation.CcmInterval.valueOf(ccmInterval));
+ }
+ for (String rmep:rmepArray) {
+ builder = builder.addToRemoteMepIdList(MepId.valueOf(Short.parseShort(rmep)));
+ }
+ if (numericId > 0) {
+ builder = builder.maNumericId(numericId);
+ }
+ if (componentId > 0) {
+ Component.ComponentBuilder compBuilder =
+ DefaultComponent.builder(componentId);
+ if (tagType != null && !tagType.isEmpty()) {
+ compBuilder = compBuilder.tagType(
+ Component.TagType.valueOf(tagType));
+ }
+ if (mhfCreationType != null && !mhfCreationType.isEmpty()) {
+ compBuilder = compBuilder.mhfCreationType(
+ Component.MhfCreationType.valueOf(mhfCreationType));
+ }
+ if (vid > 0) {
+ compBuilder = compBuilder.addToVidList(VlanId.vlanId(vid));
+ }
+ builder = builder.addToComponentList(compBuilder.build());
+ }
+ boolean created = service.createMaintenanceAssociation(mdId, builder.build());
+ print("Maintenance Association %s is successfully %s on MD %s",
+ maId, created ? "updated" : "created", mdId);
+ } catch (CfmConfigException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMaDeleteCommand.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMaDeleteCommand.java
new file mode 100644
index 0000000..4228b78
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMaDeleteCommand.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaId2Octet;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdIccY1731;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdPrimaryVid;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdRfc2685VpnId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdDomainName;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdMacUint;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdNone;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+
+/**
+ * Delete a Maintenance Association from the existing list of a Maintenance Domain.
+ */
+@Command(scope = "onos", name = "cfm-ma-delete",
+ description = "Delete a CFM Maintenance Association and its children.")
+public class CfmMaDeleteCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "name",
+ description = "Maintenance Domain name and type (in brackets) " +
+ "and the Maintenance Association name and type (in brackets)",
+ required = true, multiValued = false)
+ String name = null;
+
+ @Override
+ protected void execute() {
+ CfmMdService service = get(CfmMdService.class);
+
+ String[] nameParts = name.split("[()]");
+ if (nameParts.length != 4) {
+ throw new IllegalArgumentException("Invalid name format. Must be in " +
+ "the format of <identifier(name-type)identifier(name-type)>");
+ }
+
+ MdId mdId = null;
+ MdId.MdNameType nameTypeEnum = MdId.MdNameType.valueOf(nameParts[1]);
+ switch (nameTypeEnum) {
+ case DOMAINNAME:
+ mdId = MdIdDomainName.asMdId(nameParts[0]);
+ break;
+ case MACANDUINT:
+ mdId = MdIdMacUint.asMdId(nameParts[0]);
+ break;
+ case NONE:
+ mdId = MdIdNone.asMdId();
+ break;
+ case CHARACTERSTRING:
+ default:
+ mdId = MdIdCharStr.asMdId(nameParts[0]);
+ }
+
+ MaIdShort maId = null;
+ MaIdShort.MaIdType maNameTypeEnum = MaIdShort.MaIdType.valueOf(nameParts[3]);
+ switch (maNameTypeEnum) {
+ case TWOOCTET:
+ maId = MaId2Octet.asMaId(nameParts[2]);
+ break;
+ case ICCY1731:
+ maId = MaIdIccY1731.asMaId(nameParts[2]);
+ break;
+ case PRIMARYVID:
+ maId = MaIdPrimaryVid.asMaId(nameParts[2]);
+ break;
+ case RFC2685VPNID:
+ maId = MaIdRfc2685VpnId.asMaIdHex(nameParts[2]);
+ break;
+ case CHARACTERSTRING:
+ default:
+ maId = MaIdCharStr.asMaId(nameParts[2]);
+ }
+
+ try {
+ boolean deleted = service.deleteMaintenanceAssociation(mdId, maId);
+ print("Maintenance Association %s-%s is %ssuccessfully deleted.",
+ mdId, maId, deleted ? "" : "NOT ");
+ } catch (CfmConfigException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdAddCommand.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdAddCommand.java
new file mode 100644
index 0000000..922ed64
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdAddCommand.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.cli;
+
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Argument;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdDomainName;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdMacUint;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdNone;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+
+import java.util.Optional;
+
+/**
+ * Adds a Maintenance Domain to the existing list.
+ */
+@Command(scope = "onos", name = "cfm-md-add",
+ description = "Add a CFM Maintenance Domain.")
+public class CfmMdAddCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "name-type",
+ description = "Maintenance Domain name type",
+ required = true, multiValued = false)
+ String nameType = null;
+
+ @Argument(index = 1, name = "name",
+ description = "Maintenance Domain name. Restrictions apply depending " +
+ "on name-type. Leave empty if name type is none",
+ required = true, multiValued = false)
+ String name = null;
+
+ @Argument(index = 2, name = "level",
+ description = "Maintenance Domain level LEVEL0-LEVEL7",
+ required = true, multiValued = false)
+ String level = null;
+
+ @Argument(index = 3, name = "numeric-id",
+ description = "An optional numeric id for Maintenance Domain [1-65535]",
+ required = false, multiValued = false)
+ short numericId = 0;
+
+ @Override
+ protected void execute() {
+ CfmMdService service = get(CfmMdService.class);
+ MdId mdId = null;
+ MdId.MdNameType nameTypeEnum = MdId.MdNameType.valueOf(nameType);
+ switch (nameTypeEnum) {
+ case DOMAINNAME:
+ mdId = MdIdDomainName.asMdId(name);
+ break;
+ case MACANDUINT:
+ mdId = MdIdMacUint.asMdId(name);
+ break;
+ case NONE:
+ mdId = MdIdNone.asMdId();
+ break;
+ case CHARACTERSTRING:
+ default:
+ mdId = MdIdCharStr.asMdId(name);
+ }
+ MaintenanceDomain.MdLevel levelEnum =
+ MaintenanceDomain.MdLevel.valueOf(level);
+ Optional<Short> numericIdOpt = Optional.empty();
+ if (numericId > 0) {
+ numericIdOpt = Optional.of(numericId);
+ }
+
+ MaintenanceDomain.MdBuilder builder = null;
+ try {
+ builder = DefaultMaintenanceDomain.builder(mdId).mdLevel(levelEnum);
+ if (numericIdOpt.isPresent()) {
+ builder = builder.mdNumericId(numericIdOpt.get());
+ }
+ boolean created = service.createMaintenanceDomain(builder.build());
+ print("Maintenance Domain with id %s is successfully %s.",
+ mdId, created ? "updated" : "created");
+ } catch (CfmConfigException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdDeleteCommand.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdDeleteCommand.java
new file mode 100644
index 0000000..3cf3c26
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdDeleteCommand.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdDomainName;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdMacUint;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdNone;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+
+/**
+ * Deletes a Maintenance Domain from the existing list.
+ */
+@Command(scope = "onos", name = "cfm-md-delete",
+ description = "Delete a CFM Maintenance Domain and its children.")
+public class CfmMdDeleteCommand extends AbstractShellCommand {
+
+ @Argument(index = 0, name = "name",
+ description = "Maintenance Domain name and type (in brackets)",
+ required = true, multiValued = false)
+ String name = null;
+
+ @Override
+ protected void execute() {
+ CfmMdService service = get(CfmMdService.class);
+
+ String[] nameParts = name.split("[()]");
+ if (nameParts.length != 2) {
+ throw new IllegalArgumentException("Invalid name format. " +
+ "Must be in the format of <identifier(name-type)>");
+ }
+
+ MdId mdId = null;
+ MdId.MdNameType nameTypeEnum = MdId.MdNameType.valueOf(nameParts[1]);
+ switch (nameTypeEnum) {
+ case DOMAINNAME:
+ mdId = MdIdDomainName.asMdId(nameParts[0]);
+ break;
+ case MACANDUINT:
+ mdId = MdIdMacUint.asMdId(nameParts[0]);
+ break;
+ case NONE:
+ mdId = MdIdNone.asMdId();
+ break;
+ case CHARACTERSTRING:
+ default:
+ mdId = MdIdCharStr.asMdId(nameParts[0]);
+ }
+
+ try {
+ boolean deleted = service.deleteMaintenanceDomain(mdId);
+ print("Maintenance Domain %s is %ssuccessfully deleted.",
+ mdId, deleted ? "" : "NOT ");
+ } catch (CfmConfigException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdListMdCommand.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdListMdCommand.java
new file mode 100644
index 0000000..341bd7d
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/CfmMdListMdCommand.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.cli;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdDomainName;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdMacUint;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdNone;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+
+import java.util.Optional;
+
+/**
+ * Lists a particular Maintenance Domain.
+ */
+@Command(scope = "onos", name = "cfm-md-list",
+ description = "Lists a single CFM Maintenance Domain or all if none specified.")
+public class CfmMdListMdCommand extends AbstractShellCommand {
+ @Argument(index = 0, name = "name",
+ description = "Maintenance Domain name and type (in brackets)",
+ required = false, multiValued = false)
+ String name = null;
+
+ @Override
+ protected void execute() {
+ CfmMdService service = get(CfmMdService.class);
+
+ if (name != null) {
+ String[] nameParts = name.split("[()]");
+ if (nameParts.length != 2) {
+ throw new IllegalArgumentException("Invalid name format. " +
+ "Must be in the format of <identifier(name-type)>");
+ }
+
+ MdId mdId = null;
+ MdId.MdNameType nameTypeEnum = MdId.MdNameType.valueOf(nameParts[1]);
+ switch (nameTypeEnum) {
+ case DOMAINNAME:
+ mdId = MdIdDomainName.asMdId(nameParts[0]);
+ break;
+ case MACANDUINT:
+ mdId = MdIdMacUint.asMdId(nameParts[0]);
+ break;
+ case NONE:
+ mdId = MdIdNone.asMdId();
+ break;
+ case CHARACTERSTRING:
+ default:
+ mdId = MdIdCharStr.asMdId(nameParts[0]);
+ }
+
+ print("Maintenance Domain:");
+ Optional<MaintenanceDomain> md = service.getMaintenanceDomain(mdId);
+ print(printMd(md));
+ md.get().maintenanceAssociationList().forEach(ma -> printMa(Optional.of(ma)));
+ } else {
+ service.getAllMaintenanceDomain().forEach(md -> {
+ print(printMd(Optional.of(md)));
+ });
+ }
+ }
+
+ public static String printMd(Optional<MaintenanceDomain> md) {
+ if (!md.isPresent()) {
+ return new String("MD not found");
+ } else {
+ StringBuffer sb = new StringBuffer("\tMD: ");
+ sb.append(md.get().mdId().mdName());
+ sb.append("(" + md.get().mdId().nameType());
+ sb.append(") Lvl:" + md.get().mdLevel().ordinal());
+ sb.append(", Num: " + md.get().mdNumericId());
+
+ md.get().maintenanceAssociationList().
+ forEach(ma -> sb.append(printMa(Optional.of(ma))));
+ return sb.toString();
+ }
+ }
+
+ public static String printMa(Optional<MaintenanceAssociation> ma) {
+ if (!ma.isPresent()) {
+ return "\n\tNo MA found";
+ }
+
+ StringBuilder sb = new StringBuilder("\n\t\tMA: ");
+ sb.append(ma.get().maId().maName());
+ sb.append("(");
+ sb.append(ma.get().maId().nameType());
+ sb.append(") CCM: ");
+ sb.append(ma.get().ccmInterval());
+ sb.append(" Num: ");
+ sb.append(ma.get().maNumericId());
+
+ ma.get().remoteMepIdList().forEach(rmep -> {
+ sb.append("\n\t\t\tRmep: ");
+ sb.append(rmep);
+ });
+ ma.get().componentList().forEach(comp -> {
+ sb.append("\n\t\t\tComponent: ");
+ sb.append(comp.componentId());
+ sb.append(" Perm: ");
+ sb.append(comp.idPermission());
+ sb.append(" MHF: ");
+ sb.append(comp.mhfCreationType());
+ sb.append(" Tag: ");
+ sb.append(comp.tagType());
+
+ comp.vidList().forEach(vid -> {
+ sb.append("\n\t\t\t\tVID: ");
+ sb.append(vid);
+ });
+ });
+
+ return sb.toString();
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmCompMhfCompleter.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmCompMhfCompleter.java
new file mode 100644
index 0000000..499b84d
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmCompMhfCompleter.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.cli.completer;
+
+import org.onosproject.cli.AbstractChoicesCompleter;
+import org.onosproject.incubator.net.l2monitoring.cfm.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * CLI completer for Component MEP Half Function creation.
+ */
+public class CfmCompMhfCompleter extends AbstractChoicesCompleter {
+ @Override
+ public List<String> choices() {
+ List<String> choices = new ArrayList<>();
+
+ for (Component.MhfCreationType mhfCreationType: Component.MhfCreationType.values()) {
+ choices.add(String.valueOf(mhfCreationType.toString()));
+ }
+
+ return choices;
+ }
+
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmCompTagTypeCompleter.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmCompTagTypeCompleter.java
new file mode 100644
index 0000000..d919780
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmCompTagTypeCompleter.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.cli.completer;
+
+import org.onosproject.cli.AbstractChoicesCompleter;
+import org.onosproject.incubator.net.l2monitoring.cfm.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * CLI completer for Component TagType creation.
+ */
+public class CfmCompTagTypeCompleter extends AbstractChoicesCompleter {
+ @Override
+ public List<String> choices() {
+ List<String> choices = new ArrayList<>();
+
+ for (Component.TagType tagType: Component.TagType.values()) {
+ choices.add(String.valueOf(tagType.toString()));
+ }
+
+ return choices;
+ }
+
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMaCcmIntervalCompleter.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMaCcmIntervalCompleter.java
new file mode 100644
index 0000000..6599ed3
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMaCcmIntervalCompleter.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.cli.completer;
+
+import org.onosproject.cli.AbstractChoicesCompleter;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * CLI completer for Ccm Interval creation.
+ */
+public class CfmMaCcmIntervalCompleter extends AbstractChoicesCompleter {
+ @Override
+ public List<String> choices() {
+ List<String> choices = new ArrayList<>();
+
+ for (MaintenanceAssociation.CcmInterval ccmInterval: MaintenanceAssociation.CcmInterval.values()) {
+ choices.add(ccmInterval.toString());
+ }
+
+ return choices;
+ }
+
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMaNameCompleter.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMaNameCompleter.java
new file mode 100644
index 0000000..b484212
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMaNameCompleter.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.cli.completer;
+
+import org.onosproject.cli.AbstractChoicesCompleter;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.onosproject.cli.AbstractShellCommand.get;
+
+/**
+ * CLI completer for MA Name creation.
+ */
+public class CfmMaNameCompleter extends AbstractChoicesCompleter {
+ @Override
+ public List<String> choices() {
+ List<String> choices = new ArrayList<>();
+
+ CfmMdService service = get(CfmMdService.class);
+ service.getAllMaintenanceDomain().forEach(md ->
+ md.maintenanceAssociationList().forEach(ma ->
+ choices.add(new StringBuilder(md.mdId().mdName())
+ .append("(")
+ .append(md.mdId().nameType())
+ .append(")")
+ .append(ma.maId().maName())
+ .append("(")
+ .append(ma.maId().nameType())
+ .append(")").toString())
+ )
+ );
+
+ return choices;
+ }
+
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMaNameTypeCompleter.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMaNameTypeCompleter.java
new file mode 100644
index 0000000..d59a5c8
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMaNameTypeCompleter.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.cli.completer;
+
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * CLI completer for MA name type creation.
+ */
+public class CfmMaNameTypeCompleter implements Completer {
+ @Override
+ public int complete(String buffer, int cursor, List<String> candidates) {
+ // Delegate string completer
+ StringsCompleter delegate = new StringsCompleter();
+ SortedSet<String> strings = delegate.getStrings();
+
+ for (MaIdShort.MaIdType nameType : MaIdShort.MaIdType.values()) {
+ strings.add(nameType.toString());
+ }
+
+ // Now let the completer do the work for figuring out what to offer.
+ return delegate.complete(buffer, cursor, candidates);
+ }
+
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMdLevelCompleter.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMdLevelCompleter.java
new file mode 100644
index 0000000..374e549
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMdLevelCompleter.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.cli.completer;
+
+import org.onosproject.cli.AbstractChoicesCompleter;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * CLI completer for MD Level creation.
+ */
+public class CfmMdLevelCompleter extends AbstractChoicesCompleter {
+ @Override
+ public List<String> choices() {
+ List<String> choices = new ArrayList<>();
+
+ for (MaintenanceDomain.MdLevel mdLevel:MaintenanceDomain.MdLevel.values()) {
+ choices.add(String.valueOf(mdLevel.toString()));
+ }
+
+ return choices;
+ }
+
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMdNameCompleter.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMdNameCompleter.java
new file mode 100644
index 0000000..7a336e7
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMdNameCompleter.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.cli.completer;
+
+import org.onosproject.cli.AbstractChoicesCompleter;
+import static org.onosproject.cli.AbstractShellCommand.get;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * CLI completer for MD Name creation.
+ */
+public class CfmMdNameCompleter extends AbstractChoicesCompleter {
+ @Override
+ public List<String> choices() {
+ List<String> choices = new ArrayList<>();
+
+ CfmMdService service = get(CfmMdService.class);
+ service.getAllMaintenanceDomain().forEach(md ->
+ choices.add(md.mdId().mdName() + "(" + md.mdId().nameType() + ")"));
+
+ return choices;
+ }
+
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMdNameTypeCompleter.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMdNameTypeCompleter.java
new file mode 100644
index 0000000..6e24fc7
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/CfmMdNameTypeCompleter.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.cli.completer;
+
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+
+import java.util.List;
+import java.util.SortedSet;
+
+/**
+ * CLI completer for MD Name Type creation.
+ */
+public class CfmMdNameTypeCompleter implements Completer {
+ @Override
+ public int complete(String buffer, int cursor, List<String> candidates) {
+ // Delegate string completer
+ StringsCompleter delegate = new StringsCompleter();
+ SortedSet<String> strings = delegate.getStrings();
+
+ for (MdId.MdNameType nameType : MdId.MdNameType.values()) {
+ strings.add(nameType.toString());
+ }
+
+ // Now let the completer do the work for figuring out what to offer.
+ return delegate.complete(buffer, cursor, candidates);
+ }
+
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/package-info.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/package-info.java
new file mode 100644
index 0000000..419084d
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/completer/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Completion of Commands for creating and deleting Maintenance Domains and Maintenance Associations.
+ */
+package org.onosproject.cfm.cli.completer;
\ No newline at end of file
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/cli/package-info.java b/apps/cfm/src/main/java/org/onosproject/cfm/cli/package-info.java
new file mode 100644
index 0000000..4c57e22
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/cli/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Commands for creating and deleting Maintenance Domains and Maintenance Associations.
+ */
+package org.onosproject.cfm.cli;
\ No newline at end of file
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/impl/CfmWebApplication.java b/apps/cfm/src/main/java/org/onosproject/cfm/impl/CfmWebApplication.java
new file mode 100644
index 0000000..f21b66d
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/impl/CfmWebApplication.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.cfm.impl;
+
+import java.util.Set;
+
+import org.onlab.rest.AbstractWebApplication;
+import org.onosproject.soam.impl.DmWebResource;
+import org.onosproject.soam.impl.LmWebResource;
+
+/**
+ * CFM REST API web application.
+ */
+public class CfmWebApplication extends AbstractWebApplication {
+ @Override
+ public Set<Class<?>> getClasses() {
+ return getClasses(
+ MdWebResource.class,
+ MaWebResource.class,
+ MepWebResource.class,
+ DmWebResource.class,
+ LmWebResource.class);
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/impl/MaWebResource.java b/apps/cfm/src/main/java/org/onosproject/cfm/impl/MaWebResource.java
new file mode 100644
index 0000000..c861314
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/impl/MaWebResource.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.impl;
+
+import java.io.InputStream;
+import java.net.URI;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.onosproject.cfm.web.MaintenanceAssociationCodec;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Layer 2 CFM Maintenance Association web resource.
+ */
+@Path("md/{md_name}/ma")
+public class MaWebResource extends AbstractWebResource {
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ /**
+ * Get Maintenance Association by MD and MA name.
+ *
+ * @param mdName The name of a Maintenance Domain
+ * @param maName The name of a Maintenance Association belonging to the MD
+ * @return 200 OK with details of MA or 500 on Error
+ */
+ @GET
+ @Path("{ma_name}")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response getMa(@PathParam("md_name") String mdName,
+ @PathParam("ma_name") String maName) {
+ log.debug("GET called for MA {}/{}", mdName, maName);
+ try {
+ MdId mdId = MdIdCharStr.asMdId(mdName);
+ MaIdShort maId = MaIdCharStr.asMaId(maName);
+ MaintenanceAssociation ma = get(CfmMdService.class)
+ .getMaintenanceAssociation(mdId, maId)
+ .orElseThrow(() -> new IllegalArgumentException(
+ "MA " + maName + " not Found"));
+ ObjectNode node = mapper().createObjectNode();
+ node.set("ma", codec(MaintenanceAssociation.class).encode(ma, this));
+ return ok(node).build();
+ } catch (IllegalArgumentException e) {
+ log.error("Get MA {} failed", mdName + "/" + maName, e);
+ return Response.serverError()
+ .entity("{ \"failure\":\"" + e.toString() + "\" }").build();
+ }
+ }
+
+ /**
+ * Delete the Maintenance Association by MD and MA name.
+ *
+ * @param mdName The name of a Maintenance Domain
+ * @param maName The name of a Maintenance Association belonging to the MD
+ * @return 200 OK if removed, 304 if item was not found or 500 on Error
+ */
+ @DELETE
+ @Path("{ma_name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response deleteMa(@PathParam("md_name") String mdName,
+ @PathParam("ma_name") String maName) {
+ log.debug("DELETE called for MA {}/{}", mdName, maName);
+ try {
+ MdId mdId = MdIdCharStr.asMdId(mdName);
+ MaIdShort maId = MaIdCharStr.asMaId(maName);
+ boolean deleted = get(CfmMdService.class)
+ .deleteMaintenanceAssociation(mdId, maId);
+ if (!deleted) {
+ return Response.notModified(mdName + "/"
+ + maName + " did not exist").build();
+ } else {
+ return ok("{ \"success\":\"deleted " + mdName
+ + "/" + maName + "\" }").build();
+ }
+ } catch (CfmConfigException e) {
+ log.error("Delete Maintenance Association {} failed",
+ mdName + "/" + maName, e);
+ return Response.serverError().entity("{ \"failure\":\"" +
+ e.toString() + "\" }").build();
+ }
+ }
+
+ /**
+ * Create Maintenance Association by MD and MA name.
+ *
+ * @param mdName The name of a Maintenance Domain
+ * @param input A JSON formatted input stream specifying the MA parameters
+ * @return 200 OK or 500 on error
+ */
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response createMaintenanceAssociation(@PathParam("md_name") String mdName,
+ InputStream input) {
+ log.debug("POST called to Create MA");
+ try {
+ MdId mdId = MdIdCharStr.asMdId(mdName);
+ MaintenanceDomain md = get(CfmMdService.class)
+ .getMaintenanceDomain(mdId).get();
+ if (md == null) {
+ return Response.serverError().entity("{ \"failure\":\"md "
+ + mdName + " does not exist\" }").build();
+ }
+
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode cfg = mapper.readTree(input);
+ JsonCodec<MaintenanceAssociation> maCodec =
+ codec(MaintenanceAssociation.class);
+
+ MaintenanceAssociation ma;
+ try {
+ ma = ((MaintenanceAssociationCodec) maCodec)
+ .decode((ObjectNode) cfg, this, mdId.getNameLength());
+ } catch (Exception e) {
+ log.error("Create MaintenanceAssociation on MD {} failed", mdName, e);
+ return Response.serverError()
+ .entity("{ \"failure\":\"" + e.toString() + "\" }")
+ .build();
+ }
+
+ Boolean alreadyExists = get(CfmMdService.class)
+ .createMaintenanceAssociation(mdId, ma);
+ if (alreadyExists) {
+ return Response.notModified(mdName + "/" + ma.maId() +
+ " already exists").build();
+ }
+ return Response
+ .created(new URI("md/" + mdName + "/ma/" + ma.maId()))
+ .entity("{ \"success\":\"" + mdName + "/" + ma.maId() + " created\" }")
+ .build();
+
+ } catch (Exception | CfmConfigException e) {
+ log.error("Create MaintenanceAssociation on MD {} failed", mdName, e);
+ return Response.serverError()
+ .entity("{ \"failure\":\"" + e.toString() + "\" }")
+ .build();
+ }
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/impl/MdWebResource.java b/apps/cfm/src/main/java/org/onosproject/cfm/impl/MdWebResource.java
new file mode 100644
index 0000000..ecf1fe9
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/impl/MdWebResource.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.impl;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Collection;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Layer 2 CFM Maintenance Domain web resource.
+ */
+@Path("md")
+public class MdWebResource extends AbstractWebResource {
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ public static final String JSON_NOT_NULL = "JsonNode can not be null";
+
+ /**
+ * Get all Maintenance Domains.
+ *
+ * @return 200 OK with a list of MDs and their children
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response getMds() {
+ log.debug("GET called for all MDs");
+ Collection<MaintenanceDomain> mdMap =
+ get(CfmMdService.class).getAllMaintenanceDomain();
+ ArrayNode arrayNode = mapper().createArrayNode();
+ arrayNode.add(codec(MaintenanceDomain.class).encode(mdMap, this));
+ return ok(mapper().createObjectNode().set("mds", arrayNode)).build();
+ }
+
+ /**
+ * Get Maintenance Domain by name.
+ *
+ * @param mdName The name of a Maintenance Domain
+ * @return 200 OK with the details of the MD and its children or 500 on error
+ */
+ @GET
+ @Path("{md_name}")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response getMd(@PathParam("md_name") String mdName) {
+ log.debug("GET called for MD {}", mdName);
+ try {
+ MaintenanceDomain md = get(CfmMdService.class)
+ .getMaintenanceDomain(MdIdCharStr.asMdId(mdName))
+ .orElseThrow(() -> new IllegalArgumentException(
+ "MD " + mdName + " not Found"));
+ ObjectNode result = mapper().createObjectNode();
+ result.set("md", codec(MaintenanceDomain.class).encode(md, this));
+ return ok(result.toString()).build();
+ } catch (IllegalArgumentException e) {
+ log.error("Get MD {} failed", mdName, e);
+ return Response.serverError()
+ .entity("{ \"failure\":\"" + e.toString() + "\" }").build();
+ }
+ }
+
+ /**
+ * Delete Maintenance Domain by name.
+ *
+ * @param mdName The name of a Maintenance Domain
+ * @return 200 OK, or 304 if not found or 500 on error
+ */
+ @DELETE
+ @Path("{md_name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response deleteMd(@PathParam("md_name") String mdName) {
+ log.debug("DELETE called for MD {}", mdName);
+ try {
+ MdId mdId = MdIdCharStr.asMdId(mdName);
+ boolean deleted = get(CfmMdService.class).deleteMaintenanceDomain(mdId);
+ if (!deleted) {
+ return Response.notModified(mdName + " did not exist").build();
+ } else {
+ return ok("{ \"success\":\"deleted " + mdName + "\" }").build();
+ }
+ } catch (CfmConfigException e) {
+ log.error("Delete Maintenance Domain {} failed", mdName, e);
+ return Response.serverError()
+ .entity("{ \"failure\":\"" + e.toString() + "\" }").build();
+ }
+ }
+
+ /**
+ * Create Maintenance Domain.
+ *
+ * @param input A JSON formatted input stream specifying the MA parameters
+ * @return 200 OK, 304 if MD already exists or 500 on error
+ */
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response createMaintenanceDomain(InputStream input) {
+ log.debug("POST called to Create MD");
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode cfg = mapper.readTree(input);
+ MaintenanceDomain md = codec(MaintenanceDomain.class).decode((ObjectNode) cfg, this);
+
+ if (get(CfmMdService.class).createMaintenanceDomain(md)) {
+ return Response.notModified(md.mdId().toString() + " already exists").build();
+ }
+ return Response
+ .created(new URI("md/" + md.mdId()))
+ .entity("{ \"success\":\"" + md.mdId() + " created\" }")
+ .build();
+
+ } catch (Exception | CfmConfigException e) {
+ log.error("Create MaintenanceDomain", e);
+ return Response.serverError()
+ .entity("{ \"failure\":\"" + e.toString() + "\" }")
+ .build();
+ }
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/impl/MepWebResource.java b/apps/cfm/src/main/java/org/onosproject/cfm/impl/MepWebResource.java
new file mode 100644
index 0000000..2486df0
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/impl/MepWebResource.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.impl;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Collection;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.onosproject.cfm.web.MepCodec;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLbCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLtCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Layer 2 CFM Maintenance Association Endpoint (MEP) web resource.
+ */
+@Path("md/{md_name}/ma/{ma_name}/mep")
+public class MepWebResource extends AbstractWebResource {
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ /**
+ * Get all MEPs by MD name, MA name.
+ *
+ * @param mdName The name of a Maintenance Domain
+ * @param maName The name of a Maintenance Association belonging to the MD
+ * @return 200 OK with a list of MEPS or 500 on error
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response getAllMepsForMa(@PathParam("md_name") String mdName,
+ @PathParam("ma_name") String maName) {
+ log.debug("GET all Meps called for MA {}", mdName + "/" + maName);
+ try {
+ MdId mdId = MdIdCharStr.asMdId(mdName);
+ MaIdShort maId = MaIdCharStr.asMaId(maName);
+ Collection<MepEntry> mepCollection = get(CfmMepService.class).getAllMeps(mdId, maId);
+ ArrayNode an = mapper().createArrayNode();
+ an.add(codec(MepEntry.class).encode(mepCollection, this));
+ return ok(mapper().createObjectNode().set("meps", an)).build();
+ } catch (CfmConfigException e) {
+ log.error("Get all Meps on {} failed because of exception",
+ mdName + "/" + maName, e);
+ return Response.serverError().entity("{ \"failure\":\"" + e.toString() + "\" }").build();
+ }
+
+ }
+
+ /**
+ * Get MEP by MD name, MA name and Mep Id.
+ *
+ * @param mdName The name of a Maintenance Domain
+ * @param maName The name of a Maintenance Association belonging to the MD
+ * @param mepId The Id of the MEP
+ * @return 200 OK with details of the MEP or 500 on error
+ */
+ @GET
+ @Path("{mep_id}")
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response getMep(@PathParam("md_name") String mdName,
+ @PathParam("ma_name") String maName,
+ @PathParam("mep_id") short mepId) {
+ log.debug("GET called for MEP {}", mdName + "/" + maName + "/" + mepId);
+ try {
+ MdId mdId = MdIdCharStr.asMdId(mdName);
+ MaIdShort maId = MaIdCharStr.asMaId(maName);
+ MepEntry mepEntry = get(CfmMepService.class)
+ .getMep(mdId, maId, MepId.valueOf(mepId));
+ if (mepEntry == null) {
+ return Response.serverError().entity("{ \"failure\":\"MEP " +
+ mdName + "/" + maName + "/" + mepId + " not found\" }").build();
+ }
+ ObjectNode node = mapper().createObjectNode();
+ node.set("mep", codec(MepEntry.class).encode(mepEntry, this));
+ return ok(node).build();
+ } catch (CfmConfigException e) {
+ log.error("Get Mep {} failed because of exception",
+ mdName + "/" + maName + "/" + mepId, e);
+ return Response.serverError().entity("{ \"failure\":\"" + e.toString() + "\" }").build();
+ }
+ }
+
+ /**
+ * Delete MEP by MD name, MA name and Mep Id.
+ *
+ * @param mdName The name of a Maintenance Domain
+ * @param maName The name of a Maintenance Association belonging to the MD
+ * @param mepIdShort The Id of the MEP
+ * @return 200 OK or 304 if not found, or 500 on error
+ */
+ @DELETE
+ @Path("{mep_id}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response deleteMep(@PathParam("md_name") String mdName,
+ @PathParam("ma_name") String maName,
+ @PathParam("mep_id") short mepIdShort) {
+ log.debug("DELETE called for MEP " + mdName + "/" + maName + "/" + mepIdShort);
+ try {
+ MdId mdId = MdIdCharStr.asMdId(mdName);
+ MaIdShort maId = MaIdCharStr.asMaId(maName);
+ boolean deleted = get(CfmMepService.class)
+ .deleteMep(mdId, maId, MepId.valueOf(mepIdShort));
+ if (!deleted) {
+ return Response.notModified(mdName + "/" + maName + "/" +
+ mepIdShort + " did not exist").build();
+ } else {
+ return ok("{ \"success\":\"deleted " + mdName + "/" + maName +
+ "/" + mepIdShort + "\" }").build();
+ }
+ } catch (CfmConfigException e) {
+ log.error("Delete Mep {} failed because of exception ",
+ mdName + "/" + maName + "/" + mepIdShort, e);
+ return Response.serverError().entity("{ \"failure\":\"" +
+ e.toString() + "\" }").build();
+ }
+ }
+
+ /**
+ * Create MEP with MD name, MA name and Mep Json.
+ *
+ * @param mdName The name of a Maintenance Domain
+ * @param maName The name of a Maintenance Association belonging to the MD
+ * @param input A JSON formatted input stream specifying the Mep parameters
+ * @return 201 Created or 304 if already exists or 500 on error
+ */
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response createMep(@PathParam("md_name") String mdName,
+ @PathParam("ma_name") String maName, InputStream input) {
+ log.debug("POST called to Create Mep");
+ try {
+ MdId mdId = MdIdCharStr.asMdId(mdName);
+ MaIdShort maId = MaIdCharStr.asMaId(maName);
+ MaintenanceAssociation ma = get(CfmMdService.class).getMaintenanceAssociation(mdId, maId).get();
+
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode cfg = mapper.readTree(input);
+ JsonCodec<Mep> mepCodec = codec(Mep.class);
+
+ Mep mep = ((MepCodec) mepCodec).decode((ObjectNode) cfg, this, mdName, maName);
+
+ Boolean issuccess = get(CfmMepService.class).createMep(mdId, maId, mep);
+ if (!issuccess) {
+ return Response.notModified(mdName + "/" + ma.maId() + "/" + mep.mepId() +
+ " already exists").build();
+ }
+ return Response
+ .created(new URI("md/" + mdName + "/ma/" + ma.maId() + "/mep/" + mep.mepId()))
+ .entity("{ \"success\":\"mep " + mdName + "/" + ma.maId() + "/" + mep.mepId() + " created\" }")
+ .build();
+ } catch (Exception | CfmConfigException e) {
+ log.error("Create Mep on " + mdName + "/" + maName + " failed because of exception {}",
+ e.toString());
+ return Response.serverError()
+ .entity("{ \"failure\":\"" + e.toString() + "\" }")
+ .build();
+ }
+ }
+
+ /**
+ * Transmit Loopback on MEP with MD name, MA name and Mep Id.
+ *
+ * @param mdName The name of a Maintenance Domain
+ * @param maName The name of a Maintenance Association belonging to the MD
+ * @param mepIdShort The id of a MEP belonging to the MA
+ * @param input A JSON formatted input stream specifying the Mep parameters
+ * @return 202 Received with success message or 500 on error
+ */
+ @PUT
+ @Path("{mep_id}/transmit-loopback")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response transmitLoopback(
+ @PathParam("md_name") String mdName,
+ @PathParam("ma_name") String maName,
+ @PathParam("mep_id") short mepIdShort,
+ InputStream input) {
+ log.debug("PUT called to Transmit Loopback on Mep");
+
+ MdId mdId = MdIdCharStr.asMdId(mdName);
+ MaIdShort maId = MaIdCharStr.asMaId(maName);
+ MaintenanceDomain md = get(CfmMdService.class).getMaintenanceDomain(mdId).get();
+ MaintenanceAssociation ma = get(CfmMdService.class)
+ .getMaintenanceAssociation(mdId, maId).get();
+
+ MepId mepId = MepId.valueOf(mepIdShort);
+
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode cfg = mapper.readTree(input);
+ JsonCodec<MepLbCreate> mepLbCreateCodec = codec(MepLbCreate.class);
+
+ MepLbCreate lbCreate = mepLbCreateCodec.decode((ObjectNode) cfg, this);
+ get(CfmMepService.class).transmitLoopback(md.mdId(), ma.maId(), mepId, lbCreate);
+ } catch (Exception | CfmConfigException e) {
+ log.error("Transmit Loopback on " + mdName + "/" + maName +
+ "/{} failed", String.valueOf(mepIdShort), e);
+ return Response.serverError()
+ .entity("{ \"failure\":\"" + e.toString() + "\" }")
+ .build();
+ }
+
+ return Response.accepted()
+ .entity("{ \"success\":\"Loopback on MEP " + mdName + "/" + ma.maId() + "/"
+ + mepId.id() + " started\" }").build();
+ }
+
+ /**
+ * Abort Loopback on MEP with MD name, MA name and Mep Id.
+ *
+ * @param mdName The name of a Maintenance Domain
+ * @param maName The name of a Maintenance Association belonging to the MD
+ * @param mepIdShort The id of a MEP belonging to the MA
+ * @return 202 Received with success message or 500 on error
+ */
+ @PUT
+ @Path("{mep_id}/abort-loopback")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response abortLoopback(
+ @PathParam("md_name") String mdName,
+ @PathParam("ma_name") String maName,
+ @PathParam("mep_id") short mepIdShort) {
+ log.debug("PUT called to Abort Loopback on Mep");
+
+ MdId mdId = MdIdCharStr.asMdId(mdName);
+ MaIdShort maId = MaIdCharStr.asMaId(maName);
+ MaintenanceDomain md = get(CfmMdService.class).getMaintenanceDomain(mdId).get();
+ MaintenanceAssociation ma = get(CfmMdService.class)
+ .getMaintenanceAssociation(mdId, maId).get();
+
+ MepId mepId = MepId.valueOf(mepIdShort);
+
+ try {
+ get(CfmMepService.class).abortLoopback(md.mdId(), ma.maId(), mepId);
+ } catch (CfmConfigException e) {
+ log.error("Abort Loopback on " + mdName + "/" + maName +
+ "/{} failed", String.valueOf(mepIdShort), e);
+ return Response.serverError()
+ .entity("{ \"failure\":\"" + e.toString() + "\" }")
+ .build();
+ }
+
+ return Response.accepted()
+ .entity("{ \"success\":\"Loopback on MEP " + mdName + "/" + ma.maId() + "/"
+ + mepId.id() + " aborted\" }").build();
+ }
+
+ /**
+ * Transmit Linktrace on MEP with MD name, MA name and Mep Id.
+ *
+ * @param mdName The name of a Maintenance Domain
+ * @param maName The name of a Maintenance Association belonging to the MD
+ * @param mepIdShort The id of a MEP belonging to the MA
+ * @param input A JSON formatted input stream specifying the Linktrace parameters
+ * @return 202 Received with success message or 500 on error
+ */
+ @PUT
+ @Path("{mep_id}/transmit-linktrace")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response transmitLinktrace(
+ @PathParam("md_name") String mdName,
+ @PathParam("ma_name") String maName,
+ @PathParam("mep_id") short mepIdShort,
+ InputStream input) {
+ log.debug("PUT called to Transmit Linktrace on Mep");
+
+ MdId mdId = MdIdCharStr.asMdId(mdName);
+ MaIdShort maId = MaIdCharStr.asMaId(maName);
+ MaintenanceDomain md = get(CfmMdService.class).getMaintenanceDomain(mdId).get();
+ MaintenanceAssociation ma = get(CfmMdService.class)
+ .getMaintenanceAssociation(mdId, maId).get();
+
+ MepId mepId = MepId.valueOf(mepIdShort);
+
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode cfg = mapper.readTree(input);
+ JsonCodec<MepLtCreate> mepLtCreateCodec = codec(MepLtCreate.class);
+
+ MepLtCreate ltCreate = mepLtCreateCodec.decode((ObjectNode) cfg, this);
+ get(CfmMepService.class).transmitLinktrace(md.mdId(), ma.maId(), mepId, ltCreate);
+ } catch (Exception | CfmConfigException e) {
+ log.error("Transmit Linktrace on " + mdName + "/" + maName +
+ "/{} failed", String.valueOf(mepIdShort), e);
+ return Response.serverError()
+ .entity("{ \"failure\":\"" + e.toString() + "\" }")
+ .build();
+ }
+
+ return Response.accepted()
+ .entity("{ \"success\":\"Linktrace on MEP " + mdName + "/" + ma.maId() + "/"
+ + mepId.id() + " started\" }").build();
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/impl/package-info.java b/apps/cfm/src/main/java/org/onosproject/cfm/impl/package-info.java
new file mode 100644
index 0000000..798317d
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/impl/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * REST Web Application for CFM.
+ */
+package org.onosproject.cfm.impl;
\ No newline at end of file
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/package-info.java b/apps/cfm/src/main/java/org/onosproject/cfm/package-info.java
new file mode 100644
index 0000000..2522fb4
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * REST Web Component for CFM and SOAM.
+ */
+package org.onosproject.cfm;
\ No newline at end of file
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/web/ComponentCodec.java b/apps/cfm/src/main/java/org/onosproject/cfm/web/ComponentCodec.java
new file mode 100644
index 0000000..6a53497
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/web/ComponentCodec.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.web;
+
+import static org.onlab.util.Tools.nullIsIllegal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onlab.packet.VlanId;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.l2monitoring.cfm.Component;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultComponent;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Encode and decode to/from JSON to Component object.
+ */
+public class ComponentCodec extends JsonCodec<Component> {
+
+ private static final String COMPONENT_ID = "component-id";
+ private static final String COMPONENT = "component";
+ private static final String VID_LIST = "vid-list";
+ private static final String TAG_TYPE = "tag-type";
+ private static final String MHF_CREATION_TYPE = "mhf-creation-type";
+ private static final String ID_PERMISSION = "id-permission";
+
+ @Override
+ public ObjectNode encode(Component component, CodecContext context) {
+
+ ObjectNode node = context.mapper().createObjectNode()
+ .put(COMPONENT_ID, component.componentId());
+
+ node.set(VID_LIST, new VidCodec().encode(component.vidList(), context));
+
+ if (component.mhfCreationType() != null) {
+ node.put(MHF_CREATION_TYPE, component.mhfCreationType().name());
+ }
+ if (component.idPermission() != null) {
+ node.put(ID_PERMISSION, component.idPermission().name());
+ }
+ if (component.tagType() != null) {
+ node.put(TAG_TYPE, component.tagType().name());
+ }
+
+ return (ObjectNode) context.mapper().createObjectNode().set(COMPONENT, node);
+ }
+
+ @Override
+ public ArrayNode encode(Iterable<Component> components, CodecContext context) {
+ ArrayNode an = context.mapper().createArrayNode();
+ components.forEach(component -> {
+ an.add(encode(component, context));
+ });
+ return an;
+ }
+
+ @Override
+ public Component decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ JsonNode componentNode = json.get(COMPONENT);
+
+ int componentId = nullIsIllegal(componentNode.get(COMPONENT_ID),
+ "component-id is required").asInt();
+ Component.ComponentBuilder componentBuilder =
+ DefaultComponent.builder(componentId);
+
+ List<VlanId> vidList = (new VidCodec()).decode((ArrayNode)
+ nullIsIllegal(componentNode.get(VID_LIST), "vid-list is required"), context);
+ if (vidList == null || vidList.size() < 1) {
+ throw new IllegalArgumentException("A least one VID is required in component: " + componentId);
+ }
+ for (VlanId vid:vidList) {
+ componentBuilder = componentBuilder.addToVidList(vid);
+ }
+
+ if (componentNode.get(TAG_TYPE) != null) {
+ componentBuilder = componentBuilder
+ .tagType(Component.TagType.valueOf(
+ componentNode.get(TAG_TYPE).asText()));
+ }
+
+ if (componentNode.get(MHF_CREATION_TYPE) != null) {
+ componentBuilder = componentBuilder
+ .mhfCreationType(Component.MhfCreationType.valueOf(
+ componentNode.get(MHF_CREATION_TYPE).asText()));
+ }
+ if (componentNode.get(ID_PERMISSION) != null) {
+ componentBuilder = componentBuilder
+ .idPermission(Component.IdPermissionType.valueOf(
+ componentNode.get(ID_PERMISSION).asText()));
+ }
+
+ return componentBuilder.build();
+ }
+
+ @Override
+ public List<Component> decode(ArrayNode json, CodecContext context) {
+ List<Component> componentList = new ArrayList<>();
+ json.forEach(node -> componentList.add(decode((ObjectNode) node, context)));
+ return componentList;
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/web/FngAddressCodec.java b/apps/cfm/src/main/java/org/onosproject/cfm/web/FngAddressCodec.java
new file mode 100644
index 0000000..47cc9b6
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/web/FngAddressCodec.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip6Address;
+import org.onlab.packet.IpAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep.FngAddress;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+
+/**
+ * Encode and decode to/from JSON to FngAddress object.
+ */
+public class FngAddressCodec extends JsonCodec<FngAddress> {
+
+ @Override
+ public ObjectNode encode(FngAddress fngAddress, CodecContext context) {
+ checkNotNull(fngAddress, "FngAddress cannot be null");
+ ObjectNode result = context.mapper().createObjectNode()
+ .put("address-type", fngAddress.addressType().name());
+
+ if (fngAddress.addressType().equals(Mep.FngAddressType.IPV4) ||
+ fngAddress.addressType().equals(Mep.FngAddressType.IPV6)) {
+ result.put("ip-address", fngAddress.ipAddress().toString());
+ }
+
+ return result;
+ }
+
+ @Override
+ public FngAddress decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ JsonNode node = json.get("fng-address");
+
+ String addressType = nullIsIllegal(node.get("address-type"),
+ "address type is required").asText();
+ Mep.FngAddressType type = Mep.FngAddressType.valueOf(addressType.toUpperCase());
+ JsonNode ipAddressNode = node.get("ipAddress");
+
+ switch (type) {
+ case IPV4:
+ return FngAddress.ipV4Address(Ip4Address.valueOf(ipAddressNode.asText()));
+ case IPV6:
+ return FngAddress.ipV6Address(Ip6Address.valueOf(ipAddressNode.asText()));
+ case NOT_TRANSMITTED:
+ return FngAddress.notTransmitted(IpAddress.valueOf(ipAddressNode.asText()));
+ case NOT_SPECIFIED:
+ default:
+ return FngAddress.notSpecified();
+ }
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/web/MaintenanceAssociationCodec.java b/apps/cfm/src/main/java/org/onosproject/cfm/web/MaintenanceAssociationCodec.java
new file mode 100644
index 0000000..62be35d
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/web/MaintenanceAssociationCodec.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+
+import java.util.List;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.l2monitoring.cfm.Component;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation.CcmInterval;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation.MaBuilder;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaId2Octet;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdIccY1731;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdPrimaryVid;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdRfc2685VpnId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Encode and decode to/from JSON to MaintenanceAssociation object.
+ */
+public class MaintenanceAssociationCodec extends JsonCodec<MaintenanceAssociation> {
+
+ private static final String MA_NAME_TYPE = "maNameType";
+ private static final String MA_NUMERIC_ID = "maNumericId";
+ private static final String MA_NAME = "maName";
+ private static final String CCM_INTERVAL = "ccm-interval";
+ private static final String COMPONENT_LIST = "component-list";
+ private static final String RMEP_LIST = "rmep-list";
+ private static final String MA = "ma";
+
+ @Override
+ public ObjectNode encode(MaintenanceAssociation ma, CodecContext context) {
+ checkNotNull(ma, "Maintenance Association cannot be null");
+ ObjectNode result = context.mapper().createObjectNode()
+ .put(MA_NAME, ma.maId().toString())
+ .put(MA_NAME_TYPE, ma.maId().nameType().name());
+ if (ma.maNumericId() > 0) {
+ result = result.put(MA_NUMERIC_ID, ma.maNumericId());
+ }
+ if (ma.ccmInterval() != null) {
+ result = result.put(CCM_INTERVAL, ma.ccmInterval().name());
+ }
+
+ result.set(COMPONENT_LIST, new ComponentCodec().encode(ma.componentList(), context));
+ result.set(RMEP_LIST, new RMepCodec().encode(ma.remoteMepIdList(), context));
+
+ return result;
+ }
+
+ public MaintenanceAssociation decode(ObjectNode json, CodecContext context, int mdNameLen) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ JsonNode maNode = json.get(MA);
+
+ String maName = nullIsIllegal(maNode.get(MA_NAME), "maName is required").asText();
+ String maNameType = MaIdShort.MaIdType.CHARACTERSTRING.name();
+ if (maNode.get(MA_NAME_TYPE) != null) {
+ maNameType = maNode.get(MA_NAME_TYPE).asText();
+ }
+
+ try {
+ MaIdShort maId = null;
+ MaIdShort.MaIdType maIdType = MaIdShort.MaIdType.valueOf(maNameType);
+ switch (maIdType) {
+ case PRIMARYVID:
+ maId = MaIdPrimaryVid.asMaId(maName);
+ break;
+ case TWOOCTET:
+ maId = MaId2Octet.asMaId(maName);
+ break;
+ case RFC2685VPNID:
+ maId = MaIdRfc2685VpnId.asMaIdHex(maName);
+ break;
+ case ICCY1731:
+ maId = MaIdIccY1731.asMaId(maName);
+ break;
+ case CHARACTERSTRING:
+ default:
+ maId = MaIdCharStr.asMaId(maName);
+ }
+ MaBuilder builder =
+ DefaultMaintenanceAssociation.builder(maId, mdNameLen);
+
+ JsonNode maNumericIdNode = maNode.get(MA_NUMERIC_ID);
+ if (maNumericIdNode != null) {
+ short mdNumericId = (short) maNumericIdNode.asInt();
+ builder = builder.maNumericId(mdNumericId);
+ }
+ if (maNode.get(CCM_INTERVAL) != null) {
+ builder.ccmInterval(CcmInterval.valueOf(maNode.get(CCM_INTERVAL).asText()));
+ }
+
+ List<Component> componentList = (new ComponentCodec()).decode((ArrayNode)
+ nullIsIllegal(maNode.get(COMPONENT_LIST),
+ "component-list is required"), context);
+ for (Component component:componentList) {
+ builder = builder.addToComponentList(component);
+ }
+
+ List<MepId> remoteMeps = (new RMepCodec()).decode(
+ (ArrayNode) nullIsIllegal(maNode.get(RMEP_LIST), "rmep-list is required"), context);
+ for (MepId remoteMep:remoteMeps) {
+ builder = builder.addToRemoteMepIdList(remoteMep);
+ }
+
+ return builder.build();
+ } catch (CfmConfigException e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ }
+
+ @Override
+ public ArrayNode encode(Iterable<MaintenanceAssociation> maEntities, CodecContext context) {
+ ArrayNode an = context.mapper().createArrayNode();
+ maEntities.forEach(ma -> an.add(encode(ma, context)));
+ return an;
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/web/MaintenanceDomainCodec.java b/apps/cfm/src/main/java/org/onosproject/cfm/web/MaintenanceDomainCodec.java
new file mode 100644
index 0000000..a6bcf01
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/web/MaintenanceDomainCodec.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain.MdLevel;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdDomainName;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdMacUint;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdNone;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Encode and decode to/from JSON to MaintenanceDomain object.
+ */
+public class MaintenanceDomainCodec extends JsonCodec<MaintenanceDomain> {
+
+ private static final String MD_LEVEL = "mdLevel";
+ private static final String MD_NUMERIC_ID = "mdNumericId";
+ private static final String MD = "md";
+ private static final String MD_NAME = "mdName";
+ private static final String MD_NAME_TYPE = "mdNameType";
+
+ public MaintenanceDomainCodec() {
+ super();
+
+ }
+
+ @Override
+ public ObjectNode encode(MaintenanceDomain md, CodecContext context) {
+ checkNotNull(md, "Maintenance Domain cannot be null");
+ ObjectNode result = context.mapper().createObjectNode()
+ .put(MD_NAME, md.mdId().toString())
+ .put(MD_NAME_TYPE, md.mdId().nameType().name())
+ .put(MD_LEVEL, md.mdLevel().name());
+ if (md.mdNumericId() > 0) {
+ result = result.put(MD_NUMERIC_ID, md.mdNumericId());
+ }
+ result.set("maList",
+ new MaintenanceAssociationCodec()
+ .encode(md.maintenanceAssociationList(), context));
+
+ return result;
+ }
+
+ @Override
+ public MaintenanceDomain decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ JsonNode mdNode = json.get(MD);
+
+ String mdName = nullIsIllegal(mdNode.get(MD_NAME), "mdName is required").asText();
+ String mdNameType = MdId.MdNameType.CHARACTERSTRING.name();
+ if (mdNode.get(MD_NAME_TYPE) != null) {
+ mdNameType = mdNode.get(MD_NAME_TYPE).asText();
+ }
+
+ try {
+ MdId mdId = null;
+ MdId.MdNameType nameType =
+ MdId.MdNameType.valueOf(mdNameType);
+ switch (nameType) {
+ case DOMAINNAME:
+ mdId = MdIdDomainName.asMdId(mdName);
+ break;
+ case MACANDUINT:
+ mdId = MdIdMacUint.asMdId(mdName);
+ break;
+ case NONE:
+ mdId = MdIdNone.asMdId();
+ break;
+ case CHARACTERSTRING:
+ default:
+ mdId = MdIdCharStr.asMdId(mdName);
+ }
+
+ MaintenanceDomain.MdBuilder builder = DefaultMaintenanceDomain.builder(mdId);
+ JsonNode mdLevelNode = mdNode.get(MD_LEVEL);
+ if (mdLevelNode != null) {
+ MdLevel mdLevel = MdLevel.valueOf(mdLevelNode.asText());
+ builder = builder.mdLevel(mdLevel);
+ }
+ JsonNode mdNumericIdNode = mdNode.get(MD_NUMERIC_ID);
+ if (mdNumericIdNode != null) {
+ short mdNumericId = (short) mdNumericIdNode.asInt();
+ builder = builder.mdNumericId(mdNumericId);
+ }
+
+ return builder.build();
+ } catch (CfmConfigException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ @Override
+ public ArrayNode encode(Iterable<MaintenanceDomain> mdEntities, CodecContext context) {
+ ArrayNode an = context.mapper().createArrayNode();
+ mdEntities.forEach(md -> an.add(encode(md, context)));
+ return an;
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/web/MepCodec.java b/apps/cfm/src/main/java/org/onosproject/cfm/web/MepCodec.java
new file mode 100644
index 0000000..73a58b6
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/web/MepCodec.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+
+import org.onlab.packet.VlanId;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMep;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep.MepBuilder;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep.MepDirection;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep.Priority;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import java.time.Duration;
+
+/**
+ * Encode and decode to/from JSON to Mep object.
+ */
+public class MepCodec extends JsonCodec<Mep> {
+ private static final String ADMINISTRATIVE_STATE = "administrative-state";
+ private static final String PRIMARY_VID = "primary-vid";
+ private static final String CCM_LTM_PRIORITY = "ccm-ltm-priority";
+ private static final String CCI_ENABLED = "cci-enabled";
+ private static final String FNG_ADDRESS = "fng-address";
+ private static final String LOWEST_FAULT_PRIORITY_DEFECT = "lowest-fault-priority-defect";
+ private static final String DEFECT_PRESENT_TIME = "defect-present-time";
+ private static final String DEFECT_ABSENT_TIME = "defect-absent-time";
+
+ public Mep decode(ObjectNode json, CodecContext context, String
+ mdName, String maName) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ JsonNode mepNode = json.get("mep");
+
+ int mepId = Integer.parseInt(
+ nullIsIllegal(mepNode.get("mepId"), "mepId is required").asText());
+ DeviceId deviceId = DeviceId.deviceId(
+ nullIsIllegal(mepNode.get("deviceId"), "deviceId is required")
+ .asText());
+ PortNumber port = PortNumber
+ .portNumber(Long.parseLong(
+ nullIsIllegal(mepNode.get("port"), "port is required")
+ .asText()));
+ MepDirection direction = MepDirection.valueOf(
+ nullIsIllegal(mepNode.get("direction"), "direction is required").
+ asText());
+
+ try {
+ MdId mdId = MdIdCharStr.asMdId(mdName);
+ MaIdShort maId = MaIdCharStr.asMaId(maName);
+ MepBuilder mepBuilder = DefaultMep
+ .builder(MepId.valueOf((short) mepId),
+ deviceId, port, direction, mdId, maId);
+
+ if (mepNode.get(PRIMARY_VID) != null) {
+ mepBuilder.primaryVid(VlanId.vlanId(
+ (short) mepNode.get(PRIMARY_VID).asInt(0)));
+ }
+
+ if (mepNode.get(ADMINISTRATIVE_STATE) != null) {
+ mepBuilder.administrativeState(mepNode.get(ADMINISTRATIVE_STATE)
+ .asBoolean());
+ }
+
+ if (mepNode.get(CCM_LTM_PRIORITY) != null) {
+ mepBuilder.ccmLtmPriority(
+ Priority.values()[mepNode.get(CCM_LTM_PRIORITY).asInt(0)]);
+ }
+
+ if (mepNode.get(CCI_ENABLED) != null) {
+ mepBuilder.cciEnabled(mepNode.get(CCI_ENABLED).asBoolean());
+ }
+
+ if (mepNode.get(LOWEST_FAULT_PRIORITY_DEFECT) != null) {
+ mepBuilder.lowestFaultPriorityDefect(
+ Mep.LowestFaultDefect.values()[mepNode.get(LOWEST_FAULT_PRIORITY_DEFECT).asInt()]);
+ }
+
+ if (mepNode.get(DEFECT_ABSENT_TIME) != null) {
+ mepBuilder.defectAbsentTime(
+ Duration.parse(mepNode.get(DEFECT_ABSENT_TIME).asText()));
+ }
+
+ if (mepNode.get(DEFECT_PRESENT_TIME) != null) {
+ mepBuilder.defectPresentTime(
+ Duration.parse(mepNode.get(DEFECT_PRESENT_TIME).asText()));
+ }
+
+ if (mepNode.get(FNG_ADDRESS) != null) {
+ mepBuilder.fngAddress((new FngAddressCodec())
+ .decode((ObjectNode) mepNode, context));
+ }
+
+
+ return mepBuilder.build();
+ } catch (CfmConfigException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ @Override
+ public ObjectNode encode(Mep mep, CodecContext context) {
+ checkNotNull(mep, "Mep cannot be null");
+ ObjectNode result = context.mapper().createObjectNode()
+ .put("mepId", mep.mepId().id())
+ .put("deviceId", mep.deviceId().toString())
+ .put("port", mep.port().toLong())
+ .put("direction", mep.direction().name())
+ .put("mdName", mep.mdId().toString())
+ .put("maName", mep.maId().toString())
+ .put(ADMINISTRATIVE_STATE, mep.administrativeState())
+ .put(CCI_ENABLED, mep.cciEnabled());
+ if (mep.ccmLtmPriority() != null) {
+ result.put(CCM_LTM_PRIORITY, mep.ccmLtmPriority().ordinal());
+ }
+ if (mep.primaryVid() != null) {
+ result.put(PRIMARY_VID, mep.primaryVid().toShort());
+ }
+ if (mep.fngAddress() != null) {
+ result.put(FNG_ADDRESS, new FngAddressCodec().encode(mep.fngAddress(), context));
+ }
+ if (mep.lowestFaultPriorityDefect() != null) {
+ result.put(LOWEST_FAULT_PRIORITY_DEFECT, mep.lowestFaultPriorityDefect().ordinal());
+ }
+ if (mep.defectPresentTime() != null) {
+ result.put(DEFECT_PRESENT_TIME, mep.defectPresentTime().toString());
+ }
+ if (mep.defectAbsentTime() != null) {
+ result.put(DEFECT_ABSENT_TIME, mep.defectAbsentTime().toString());
+ }
+
+ return result;
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/web/MepEntryCodec.java b/apps/cfm/src/main/java/org/onosproject/cfm/web/MepEntryCodec.java
new file mode 100644
index 0000000..d1618a7
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/web/MepEntryCodec.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Iterator;
+import java.util.Map.Entry;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Encode and decode to/from JSON to MepEntry object.
+ */
+public class MepEntryCodec extends JsonCodec<MepEntry> {
+
+ @Override
+ public ObjectNode encode(MepEntry mepEntry, CodecContext context) {
+ checkNotNull(mepEntry, "Mep cannot be null");
+
+ ObjectNode result = context.mapper().createObjectNode();
+
+ //Get the common attributes
+ Mep mep = (Mep) mepEntry;
+ ObjectNode mepAttrs = new MepCodec().encode(mep, context);
+ Iterator<Entry<String, JsonNode>> elements = mepAttrs.fields();
+ while (elements.hasNext()) {
+ Entry<String, JsonNode> element = elements.next();
+ result.set(element.getKey(), element.getValue());
+ }
+
+ if (mepEntry.macAddress() != null) {
+ result.put("macAddress", mepEntry.macAddress().toString());
+ }
+
+ if (mepEntry.loopbackAttributes() != null) {
+ result.set("loopback", new MepLbEntryCodec()
+ .encode(mepEntry.loopbackAttributes(), context));
+ }
+
+ if (mepEntry.activeRemoteMepList() != null) {
+ result.set("remoteMeps", new RemoteMepEntryCodec()
+ .encode(mepEntry.activeRemoteMepList(), context));
+ }
+
+ if (mepEntry.activeErrorCcmDefect()) {
+ result.put("activeErrorCcmDefect", true);
+ }
+ if (mepEntry.activeMacStatusDefect()) {
+ result.put("activeMacStatusDefect", true);
+ }
+ if (mepEntry.activeRdiCcmDefect()) {
+ result.put("activeRdiCcmDefect", true);
+ }
+ if (mepEntry.activeRemoteCcmDefect()) {
+ result.put("activeRemoteCcmDefect", true);
+ }
+ if (mepEntry.activeXconCcmDefect()) {
+ result.put("activeXconCcmDefect", true);
+ }
+ return result;
+ }
+
+ @Override
+ public ArrayNode encode(Iterable<MepEntry> mepEntryEntities, CodecContext context) {
+ ArrayNode an = context.mapper().createArrayNode();
+ if (mepEntryEntities != null) {
+ mepEntryEntities.forEach(mepEntry -> an.add(encode(mepEntry, context)));
+ }
+ return an;
+ }
+
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/web/MepLbCreateCodec.java b/apps/cfm/src/main/java/org/onosproject/cfm/web/MepLbCreateCodec.java
new file mode 100644
index 0000000..e29415c
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/web/MepLbCreateCodec.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.web;
+
+import org.onlab.packet.MacAddress;
+import org.onlab.util.HexString;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMepLbCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep.Priority;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLbCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Encode and decode to/from JSON to MepLbCreate object.
+ */
+public class MepLbCreateCodec extends JsonCodec<MepLbCreate> {
+
+ public static final String NUMBER_MESSAGES = "numberMessages";
+ public static final String REMOTE_MEP_ID = "remoteMepId";
+ public static final String REMOTE_MEP_MAC = "remoteMepMac";
+ public static final String DATA_TLV_HEX = "dataTlvHex";
+ public static final String VLAN_DROP_ELIGIBLE = "vlanDropEligible";
+ public static final String VLAN_PRIORITY = "vlanPriority";
+ public static final String LOOPBACK = "loopback";
+
+ @Override
+ public ObjectNode encode(MepLbCreate mepLbCreate, CodecContext context) {
+ checkNotNull(mepLbCreate, "Mep Lb Create cannot be null");
+ ObjectNode result = context.mapper().createObjectNode()
+ .put(NUMBER_MESSAGES, mepLbCreate.numberMessages());
+
+ if (mepLbCreate.remoteMepId() != null) {
+ result.put(REMOTE_MEP_ID, mepLbCreate.remoteMepId().value());
+ } else {
+ result.put(REMOTE_MEP_MAC, mepLbCreate.remoteMepAddress().toString());
+ }
+
+ if (mepLbCreate.dataTlvHex() != null) {
+ result.put(DATA_TLV_HEX, mepLbCreate.dataTlvHex());
+ }
+ if (mepLbCreate.vlanDropEligible() != null) {
+ result.put(VLAN_DROP_ELIGIBLE, mepLbCreate.vlanDropEligible());
+ }
+ if (mepLbCreate.vlanPriority() != null) {
+ result.put(VLAN_PRIORITY, mepLbCreate.vlanPriority().ordinal());
+ }
+ return result;
+ }
+
+
+ @Override
+ public MepLbCreate decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ JsonNode loopbackNode = json.get(LOOPBACK);
+
+ JsonNode remoteMepIdNode = loopbackNode.get(REMOTE_MEP_ID);
+ JsonNode remoteMepMacNode = loopbackNode.get(REMOTE_MEP_MAC);
+
+ MepLbCreate.MepLbCreateBuilder lbCreateBuilder = null;
+ if (remoteMepIdNode != null) {
+ MepId remoteMepId = MepId.valueOf((short) remoteMepIdNode.asInt());
+ lbCreateBuilder = DefaultMepLbCreate.builder(remoteMepId);
+ } else if (remoteMepMacNode != null) {
+ MacAddress remoteMepMac = MacAddress.valueOf(
+ remoteMepMacNode.asText());
+ lbCreateBuilder = DefaultMepLbCreate.builder(remoteMepMac);
+ } else {
+ throw new IllegalArgumentException(
+ "Either a remoteMepId or a remoteMepMac");
+ }
+
+ JsonNode numMessagesNode = loopbackNode.get(NUMBER_MESSAGES);
+ if (numMessagesNode != null) {
+ int numMessages = numMessagesNode.asInt();
+ lbCreateBuilder.numberMessages(numMessages);
+ }
+
+ JsonNode vlanDropEligibleNode = loopbackNode.get(VLAN_DROP_ELIGIBLE);
+ if (vlanDropEligibleNode != null) {
+ boolean vlanDropEligible = vlanDropEligibleNode.asBoolean();
+ lbCreateBuilder.vlanDropEligible(vlanDropEligible);
+ }
+
+ JsonNode vlanPriorityNode = loopbackNode.get(VLAN_PRIORITY);
+ if (vlanPriorityNode != null) {
+ short vlanPriority = (short) vlanPriorityNode.asInt();
+ lbCreateBuilder.vlanPriority(Priority.values()[vlanPriority]);
+ }
+
+ JsonNode dataTlvHexNode = loopbackNode.get(DATA_TLV_HEX);
+ if (dataTlvHexNode != null) {
+ String dataTlvHex = loopbackNode.get(DATA_TLV_HEX).asText();
+ if (!dataTlvHex.isEmpty()) {
+ lbCreateBuilder.dataTlv(HexString.fromHexString(dataTlvHex));
+ }
+ }
+
+ return lbCreateBuilder.build();
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/web/MepLbEntryCodec.java b/apps/cfm/src/main/java/org/onosproject/cfm/web/MepLbEntryCodec.java
new file mode 100644
index 0000000..62409cd
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/web/MepLbEntryCodec.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLbEntry;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Encode and decode to/from JSON to MepLbEntry object.
+ */
+public class MepLbEntryCodec extends JsonCodec<MepLbEntry> {
+
+ @Override
+ public ObjectNode encode(MepLbEntry mepLbEntry, CodecContext context) {
+ checkNotNull(mepLbEntry, "Mep Lb Entry cannot be null");
+ ObjectNode result = context.mapper().createObjectNode()
+ .put("nextLbmIdentifier", mepLbEntry.nextLbmIdentifier())
+ .put("countLbrTransmitted", mepLbEntry.countLbrTransmitted())
+ .put("countLbrReceived", mepLbEntry.countLbrReceived())
+ .put("countLbrValidInOrder", mepLbEntry.countLbrValidInOrder())
+ .put("countLbrValidOutOfOrder", mepLbEntry.countLbrValidOutOfOrder())
+ .put("countLbrMacMisMatch", mepLbEntry.countLbrMacMisMatch());
+
+ return result;
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/web/MepLtCreateCodec.java b/apps/cfm/src/main/java/org/onosproject/cfm/web/MepLtCreateCodec.java
new file mode 100644
index 0000000..0141a73
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/web/MepLtCreateCodec.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onlab.packet.MacAddress;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.l2monitoring.cfm.DefaultMepLtCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLtCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+
+import java.util.BitSet;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Encode and decode to/from JSON to MepLtCreate object.
+ */
+public class MepLtCreateCodec extends JsonCodec<MepLtCreate> {
+
+ private static final String REMOTE_MEP_ID = "remoteMepId";
+ private static final String REMOTE_MEP_MAC = "remoteMepMac";
+ private static final String DEFAULT_TTL = "defaultTtl";
+ private static final String TRANSMIT_LTM_FLAGS = "transmitLtmFlags";
+ private static final String LINKTRACE = "linktrace";
+ private static final String USE_FDB_ONLY = "use-fdb-only";
+
+ @Override
+ public ObjectNode encode(MepLtCreate mepLtCreate, CodecContext context) {
+ checkNotNull(mepLtCreate, "Mep Lt Create cannot be null");
+ ObjectNode result = context.mapper().createObjectNode();
+
+ if (mepLtCreate.remoteMepId() != null) {
+ result.put(REMOTE_MEP_ID, mepLtCreate.remoteMepId().value());
+ } else {
+ result.put(REMOTE_MEP_MAC, mepLtCreate.remoteMepAddress().toString());
+ }
+
+ if (mepLtCreate.defaultTtl() != null) {
+ result.put(DEFAULT_TTL, mepLtCreate.defaultTtl());
+ }
+ if (mepLtCreate.transmitLtmFlags() != null) {
+ result.put(TRANSMIT_LTM_FLAGS,
+ mepLtCreate.transmitLtmFlags().get(0) ? USE_FDB_ONLY : "");
+ }
+
+ return result;
+ }
+
+
+ @Override
+ public MepLtCreate decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ JsonNode linktraceNode = json.get(LINKTRACE);
+
+ JsonNode remoteMepIdNode = linktraceNode.get(REMOTE_MEP_ID);
+ JsonNode remoteMepMacNode = linktraceNode.get(REMOTE_MEP_MAC);
+
+ MepLtCreate.MepLtCreateBuilder ltCreateBuilder = null;
+ if (remoteMepIdNode != null) {
+ MepId remoteMepId = MepId.valueOf((short) remoteMepIdNode.asInt());
+ ltCreateBuilder = DefaultMepLtCreate.builder(remoteMepId);
+ } else if (remoteMepMacNode != null) {
+ MacAddress remoteMepMac = MacAddress.valueOf(
+ remoteMepMacNode.asText());
+ ltCreateBuilder = DefaultMepLtCreate.builder(remoteMepMac);
+ } else {
+ throw new IllegalArgumentException(
+ "Either a remoteMepId or a remoteMepMac");
+ }
+
+ JsonNode defaultTtlNode = linktraceNode.get(DEFAULT_TTL);
+ if (defaultTtlNode != null) {
+ short defaultTtl = (short) defaultTtlNode.asInt();
+ ltCreateBuilder.defaultTtl(defaultTtl);
+ }
+
+ JsonNode transmitLtmFlagsNode = linktraceNode.get(TRANSMIT_LTM_FLAGS);
+ if (transmitLtmFlagsNode != null) {
+ if (transmitLtmFlagsNode.asText().isEmpty()) {
+ ltCreateBuilder.transmitLtmFlags(BitSet.valueOf(new long[]{0}));
+ } else if (transmitLtmFlagsNode.asText().equals(USE_FDB_ONLY)) {
+ ltCreateBuilder.transmitLtmFlags(BitSet.valueOf(new long[]{1}));
+ } else {
+ throw new IllegalArgumentException("Expecting value 'use-fdb-only' " +
+ "or '' for " + TRANSMIT_LTM_FLAGS);
+ }
+ }
+
+ return ltCreateBuilder.build();
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/web/RMepCodec.java b/apps/cfm/src/main/java/org/onosproject/cfm/web/RMepCodec.java
new file mode 100644
index 0000000..7edb204
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/web/RMepCodec.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.web;
+
+import static org.onlab.util.Tools.nullIsIllegal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Encode and decode to/from JSON to RMep object.
+ */
+public class RMepCodec extends JsonCodec<MepId> {
+
+ @Override
+ public ObjectNode encode(MepId rmep, CodecContext context) {
+ return context.mapper().createObjectNode().put("rmep", rmep.id());
+ }
+
+ @Override
+ public ArrayNode encode(Iterable<MepId> rmeps, CodecContext context) {
+ ArrayNode an = context.mapper().createArrayNode();
+ rmeps.forEach(rmep -> {
+ an.add(encode(rmep, context));
+ });
+ return an;
+ }
+
+ @Override
+ public MepId decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ JsonNode vidNode = json.get("rmep");
+
+ return MepId.valueOf(
+ nullIsIllegal((short) vidNode.asInt(), "rmep is required"));
+
+ }
+
+ @Override
+ public List<MepId> decode(ArrayNode json, CodecContext context) {
+ List<MepId> rmepList = new ArrayList<>();
+ json.forEach(node -> rmepList.add(decode((ObjectNode) node, context)));
+ return rmepList;
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/web/RemoteMepEntryCodec.java b/apps/cfm/src/main/java/org/onosproject/cfm/web/RemoteMepEntryCodec.java
new file mode 100644
index 0000000..4f8344a
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/web/RemoteMepEntryCodec.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.l2monitoring.cfm.RemoteMepEntry;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Encode and decode to/from JSON to RemoteMepEntry object.
+ */
+public class RemoteMepEntryCodec extends JsonCodec<RemoteMepEntry> {
+
+ @Override
+ public ObjectNode encode(RemoteMepEntry remoteMepEntry, CodecContext context) {
+ checkNotNull(remoteMepEntry, "Mep cannot be null");
+ ObjectNode result = context.mapper().createObjectNode()
+ .put("remoteMepId", remoteMepEntry.remoteMepId().toString())
+ .put("remoteMepState", remoteMepEntry.state().name())
+ .put("rdi", remoteMepEntry.rdi());
+
+ if (remoteMepEntry.failedOrOkTime() != null) {
+ result = result.put("failedOrOkTime",
+ remoteMepEntry.failedOrOkTime().toString());
+ }
+
+ if (remoteMepEntry.macAddress() != null) {
+ result = result.put("macAddress", remoteMepEntry.macAddress().toString());
+ }
+
+ if (remoteMepEntry.portStatusTlvType() != null) {
+ result = result.put("portStatusTlvType",
+ remoteMepEntry.portStatusTlvType().name());
+ }
+ if (remoteMepEntry.interfaceStatusTlvType() != null) {
+ result = result.put("interfaceStatusTlvType",
+ remoteMepEntry.interfaceStatusTlvType().name());
+ }
+ if (remoteMepEntry.senderIdTlvType() != null) {
+ result = result.put("senderIdTlvType",
+ remoteMepEntry.senderIdTlvType().name());
+ }
+
+ return result;
+ }
+
+ @Override
+ public ArrayNode encode(Iterable<RemoteMepEntry> remoteMepEntries,
+ CodecContext context) {
+ ArrayNode an = context.mapper().createArrayNode();
+ remoteMepEntries.forEach(remoteMepEntry ->
+ an.add(encode(remoteMepEntry, context)));
+ return an;
+ }
+
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/web/VidCodec.java b/apps/cfm/src/main/java/org/onosproject/cfm/web/VidCodec.java
new file mode 100644
index 0000000..a673719
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/web/VidCodec.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cfm.web;
+
+import static org.onlab.util.Tools.nullIsIllegal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.onlab.packet.VlanId;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Encode and decode to/from JSON to Vid object.
+ */
+public class VidCodec extends JsonCodec<VlanId> {
+
+ @Override
+ public ObjectNode encode(VlanId vid, CodecContext context) {
+ return context.mapper().createObjectNode().put("vid", vid.toString());
+ }
+
+ @Override
+ public ArrayNode encode(Iterable<VlanId> vids, CodecContext context) {
+ ArrayNode an = context.mapper().createArrayNode();
+ vids.forEach(vid -> {
+ an.add(encode(vid, context));
+ });
+ return an;
+ }
+
+ @Override
+ public VlanId decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ JsonNode vidNode = json.get("vid");
+
+ int vid = (nullIsIllegal(vidNode.asInt(), "vid is required"));
+ if (vid < 0 || vid > 4095) {
+ throw new IllegalArgumentException("VID values must be between 0 and 4095");
+ }
+ return VlanId.vlanId((short) vid);
+ }
+
+ @Override
+ public List<VlanId> decode(ArrayNode json, CodecContext context) {
+ List<VlanId> vidList = new ArrayList<>();
+ json.forEach(node -> vidList.add(decode((ObjectNode) node, context)));
+ return vidList;
+ }
+}
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/web/package-info.java b/apps/cfm/src/main/java/org/onosproject/cfm/web/package-info.java
new file mode 100644
index 0000000..265a1fa
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/web/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Codecs for converting CFM objects to and from JSON.
+ */
+package org.onosproject.cfm.web;
\ No newline at end of file