/** * Copyright (c) 2015, 2016 NEC Corporation 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.nic.vtn.renderer; import java.util.List; import java.util.Map; import java.util.Set; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; import org.opendaylight.nic.utils.exceptions.IntentElementNotFoundException; import org.opendaylight.nic.utils.IntentUtils; import org.opendaylight.nic.utils.MdsalUtils; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.Intent.Status; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.Intents; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.Actions; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.Subjects; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.Action; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action.Allow; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intent.actions.action.Block; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.Intent; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.IntentKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.types.rev150122.Uuid; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The VTNRenderer class parse the intents received. */ public class VTNRenderer implements BindingAwareProvider, AutoCloseable ,DataChangeListener { private static final Logger LOG = LoggerFactory .getLogger(VTNRenderer.class); private VTNIntentParser vtnIntentParser; private VTNRendererUtility vtnRendererUtility; /** * The index of the source end point group in an intent. */ private static final int INDEX_OF_SRC_END_POINT_GROUP = 0; /** * The index of the destination end point group in an intent. */ private static final int INDEX_OF_DST_END_POINT_GROUP = 1; private ListenerRegistration<DataChangeListener> vtnRendererListener = null; public static final InstanceIdentifier<Intents> INTENTS_IID = InstanceIdentifier.builder(Intents.class).build(); /** * {@inheritDoc} */ @Override public void close() throws Exception { LOG.trace("VTNRendererListener closed."); if (vtnRendererListener != null) { vtnRendererListener.close(); } } /** * Gets called on start of a bundle. * @param session the session object */ @Override public void onSessionInitiated(final ProviderContext session) { final DataBroker dataBroker = session.getSALService(DataBroker.class); final MdsalUtils md = new MdsalUtils(dataBroker); final VTNManagerService vtn = new VTNManagerService(md, session); this.vtnIntentParser = new VTNIntentParser(dataBroker , vtn); this.vtnRendererUtility = new VTNRendererUtility(dataBroker); vtnRendererListener = dataBroker.registerDataChangeListener( LogicalDatastoreType.CONFIGURATION, INTENTS_IID, this, DataChangeScope.SUBTREE); } /** * This method is called on intent data requests. */ @Override public void onDataChanged( final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> ev) { LOG.trace("Intent configuration changed."); for (DataObject dao: ev.getCreatedData().values()) { LOG.trace("A new data object is created: {}", dao); if (dao instanceof Intent) { Intent intent = (Intent) dao; LOG.trace("A new intent is created: {}", intent.getId()); intentParser(intent); } } for (DataObject dao: ev.getUpdatedData().values()) { LOG.trace("A data object is updated: {}", dao); if (dao instanceof Intent) { Intent intent = (Intent) dao; LOG.trace("An intent is updated: {}", intent.getId()); intentParser(intent); } } Map<InstanceIdentifier<?>, DataObject> originalDataObject = ev.getOriginalData(); Set<InstanceIdentifier<?>> iiD = ev.getRemovedPaths(); for (InstanceIdentifier<?> instanceIdentifier : iiD) { try { if (originalDataObject.get(instanceIdentifier) instanceof Intent) { Intent lclIntent = (Intent) originalDataObject.get(instanceIdentifier); IntentKey lclIntentKey = lclIntent.getKey(); Uuid uuid = lclIntentKey.getId(); LOG.trace(" Intent Deleted :{} ", uuid.getValue()); String encodeUUID = vtnRendererUtility.encodeUUID(uuid.getValue()); vtnIntentParser.delFlowCondFilter(encodeUUID); if (!vtnRendererUtility.deleteIntent(lclIntent)) { LOG.error("Intent data's are not deleted from operational data store", uuid.getValue()); return; } LOG.trace("Intent data's are successfully deleted from operational data store", uuid.getValue()); } } catch (Exception e) { LOG.error("Could not delete VTN Renderer :{}", e); } } } /** * This method parse the intent and calls the VTN renderer * */ private void intentParser(Intent intent) { if (!IntentUtils.verifyIntent(intent)) { return; } // Retrieve the Intent ID. String intentID = intent.getId().getValue(); // Retrieve the end points. final List<String> endPointGroups = IntentUtils.extractEndPointGroup(intent); String endPointSrc = endPointGroups.get(INDEX_OF_SRC_END_POINT_GROUP); String endPointDst = endPointGroups.get(INDEX_OF_DST_END_POINT_GROUP); // Get the type of the action. String actionType = getAction(intent); // get the encode UUID value String encodeUUID = vtnRendererUtility.encodeUUID(intentID); Status intentStatus = Status.CompletedError; // Convert the intent to VTN configuration. if (vtnIntentParser.containsIntentID(encodeUUID)) { intentStatus = vtnIntentParser.updateRendering(endPointSrc, endPointDst, actionType, intentID, encodeUUID, intent); } else { intentStatus = vtnIntentParser.rendering(endPointSrc, endPointDst, actionType, encodeUUID, intent); } LOG.trace("intent status: intentID={}, intentStatus={}", intentID, intentStatus); vtnRendererUtility.addIntent(intent, intentStatus); } /** * To get the action from the intent. * * @return action type. */ private String getAction(Intent intent) { Action action = intent.getActions().get(0).getAction(); String actionType = null; if (action instanceof Allow) { actionType = "allow"; } else if (action instanceof Block) { actionType = "block"; } else { throw new IntentElementNotFoundException("VTN Renderer supports only allow or block: {}" + intent.getId()); } return actionType; } }