/** * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.frm.reconil; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.util.concurrent.ListenableFuture; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ExecutionException; import org.opendaylight.controller.frm.AbstractChangeListener; import org.opendaylight.controller.frm.FlowCookieProducer; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * forwardingrules-manager * org.opendaylight.controller.frm * * FlowNode Reconciliation Listener * Reconciliation for a new FlowNode * Remove CookieMapKey for removed FlowNode * * @author Vaclav Demcak * * Created: Jun 13, 2014 */ public class FlowNodeReconcilListener extends AbstractChangeListener { private static final Logger LOG = LoggerFactory.getLogger(FlowNodeReconcilListener.class); private final FlowNodeReconcilProvider provider; public FlowNodeReconcilListener(final FlowNodeReconcilProvider provider) { this.provider = Preconditions.checkNotNull(provider, "Flow Node Reconcil Provider can not be null!"); } @Override public void onDataChanged(final AsyncDataChangeEvent, DataObject> changeEvent) { /* FlowCapableNode DataObjects for reconciliation */ final Set, DataObject>> createdEntries = changeEvent.getCreatedData().entrySet(); /* FlowCapableNode DataObjects for clean FlowCookieHolder */ final Set> removeEntriesInstanceIdentifiers = changeEvent.getRemovedPaths(); for (final Entry, DataObject> createdEntry : createdEntries) { InstanceIdentifier entryKey = createdEntry.getKey(); DataObject entryValue = createdEntry.getValue(); if (preconditionForChange(entryKey, entryValue, null)) { this.add(entryKey, entryValue); } } for (final InstanceIdentifier instanceId : removeEntriesInstanceIdentifiers) { Map, DataObject> origConfigData = changeEvent.getOriginalData(); final DataObject removeValue = origConfigData.get(instanceId); if (preconditionForChange(instanceId, removeValue, null)) { this.remove(instanceId, removeValue); } } } @Override /* Cleaning FlowCookieManager holder for all node tables */ protected void remove(final InstanceIdentifier identifier, final DataObject removeDataObj) { final InstanceIdentifier flowNodeIdent = identifier.firstIdentifierOf(FlowCapableNode.class); final FlowCapableNode flowNode = ((FlowCapableNode) removeDataObj); for (Table flowTable : flowNode.getTable()) { final InstanceIdentifier tableIdent = flowNodeIdent.child(Table.class, flowTable.getKey()); FlowCookieProducer.INSTANCE.clean(tableIdent); } } @Override /* Reconciliation by connect new FlowCapableNode */ protected void add(final InstanceIdentifier identifier, final DataObject addDataObj) { final InstanceIdentifier flowNodeIdent = identifier.firstIdentifierOf(FlowCapableNode.class); final Optional flowCapNode = this.readFlowCapableNode(flowNodeIdent); if (flowCapNode.isPresent()) { final InstanceIdentifier nodeIdent = identifier.firstIdentifierOf(Node.class); final NodeRef nodeRef = new NodeRef(nodeIdent); /* Groups - have to be first */ List groups = flowCapNode.get().getGroup(); if(groups != null) { for (Group group : groups) { final GroupRef groupRef = new GroupRef(flowNodeIdent.child(Group.class, group.getKey())); final AddGroupInputBuilder groupBuilder = new AddGroupInputBuilder(group); groupBuilder.setGroupRef(groupRef); groupBuilder.setNode(nodeRef); this.provider.getSalGroupService().addGroup(groupBuilder.build()); } } /* Meters */ List meters = flowCapNode.get().getMeter(); if(meters != null) { for (Meter meter : meters) { final MeterRef meterRef = new MeterRef(flowNodeIdent.child(Meter.class, meter.getKey())); final AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder(meter); meterBuilder.setMeterRef(meterRef); meterBuilder.setNode(nodeRef); this.provider.getSalMeterService().addMeter(meterBuilder.build()); } } /* Flows */ List
tables = flowCapNode.get().getTable(); if(tables != null) { for (Table flowTable : tables) { final InstanceIdentifier
tableIdent = flowNodeIdent.child(Table.class, flowTable.getKey()); List flows = flowTable.getFlow(); if(flows != null) { for (Flow flow : flows) { final FlowCookie flowCookie = new FlowCookie(FlowCookieProducer.INSTANCE.getNewCookie(tableIdent)); final FlowRef flowRef = new FlowRef(tableIdent.child(Flow.class, flow.getKey())); final FlowTableRef flowTableRef = new FlowTableRef(tableIdent); final AddFlowInputBuilder flowBuilder = new AddFlowInputBuilder(flow); flowBuilder.setCookie(flowCookie); flowBuilder.setNode(nodeRef); flowBuilder.setFlowTable(flowTableRef); flowBuilder.setFlowRef(flowRef); this.provider.getSalFlowService().addFlow(flowBuilder.build()); } } } } } } @Override protected void update(final InstanceIdentifier identifier, final DataObject original, final DataObject update) { // NOOP - Listener is registered for DataChangeScope.BASE only } @Override protected boolean preconditionForChange(final InstanceIdentifier identifier, final DataObject dataObj, final DataObject update) { return (dataObj instanceof FlowCapableNode); } private Optional readFlowCapableNode(final InstanceIdentifier flowNodeIdent) { ReadOnlyTransaction readTrans = this.provider.getDataService().newReadOnlyTransaction(); try { ListenableFuture> confFlowNode = readTrans.read(LogicalDatastoreType.CONFIGURATION, flowNodeIdent); if (confFlowNode.get().isPresent()) { return Optional. of(confFlowNode.get().get()); } else { return Optional.absent(); } } catch (InterruptedException | ExecutionException e) { LOG.error("Unexpected exception by reading flow ".concat(flowNodeIdent.toString()), e); return Optional.absent(); } finally { readTrans.close(); } } }