/*
* 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.groupbasedpolicy.renderer.ofoverlay.endpoint;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledExecutorService;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.NotificationService;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.groupbasedpolicy.dto.EgKey;
import org.opendaylight.groupbasedpolicy.dto.EpKey;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.EndpointListener;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.arp.ArpTasker;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.statistics.OFStatisticsManager;
import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
import org.opendaylight.groupbasedpolicy.util.IidFactory;
import org.opendaylight.groupbasedpolicy.util.SetUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointFields;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.l3endpoint.rev151217.NatAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayConfig;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayL3Context;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3Context;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ExternalImplicitGroup;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
/**
* Keep track of endpoints on the system. Maintain an index of endpoints and
* their locations for rendering. The endpoint manager will maintain
* appropriate indexes only for switches that are attached to the current
* controller node.
* In order to render the policy, we need to be able to efficiently enumerate
* all endpoints on a particular switch and also all the switches containing
* each particular endpoint group
*/
public class EndpointManager implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(EndpointManager.class);
private final EndpointManagerListener endpointListener;
private final OfOverlayContextListener ofOverlayContextListener;
private final OfOverlayL3ContextListener ofOverlayL3ContextListener;
private final ConcurrentMap<EpKey, Endpoint> endpoints = new ConcurrentHashMap<>();
private final ConcurrentMap<EpKey, Endpoint> externalEndpointsWithoutLocation = new ConcurrentHashMap<>();
private final ConcurrentMap<NodeId, ConcurrentMap<EgKey, Set<EpKey>>> endpointsByGroupByNode =
new ConcurrentHashMap<>();
private final ConcurrentMap<NodeId, Set<EpKey>> endpointsByNode = new ConcurrentHashMap<>();
private final ConcurrentMap<EgKey, Set<EpKey>> endpointsByGroup = new ConcurrentHashMap<>();
private final ScheduledExecutorService executor;
private final DataBroker dataProvider;
private final ArpTasker arpTasker;
private final ListenerRegistration<ArpTasker> notificationListenerRegistration;
private List<EndpointListener> listeners = new CopyOnWriteArrayList<>();
private Function<EpKey, Endpoint> indexTransform = new Function<EpKey, Endpoint>() {
@Override
public Endpoint apply(EpKey input) {
return endpoints.get(input);
}
};
public EndpointManager(DataBroker dataProvider,PacketProcessingService packetProcessingService,
SalFlowService flowService, NotificationService notificationService,
ScheduledExecutorService executor, SwitchManager switchManager) {
this.executor = executor;
this.dataProvider = dataProvider;
if (notificationService != null && dataProvider != null) {
this.arpTasker = new ArpTasker(dataProvider, packetProcessingService, flowService);
notificationListenerRegistration = notificationService.registerNotificationListener(arpTasker);
} else {
LOG.info("Missing service {}", NotificationService.class.getSimpleName());
this.arpTasker = null;
this.notificationListenerRegistration = null;
}
if (dataProvider != null) {
endpointListener = new EndpointManagerListener(this.dataProvider, this);
ofOverlayContextListener = new OfOverlayContextListener(dataProvider, switchManager);
ofOverlayL3ContextListener = new OfOverlayL3ContextListener(dataProvider, switchManager);
} else {
endpointListener = null;
ofOverlayContextListener = null;
ofOverlayL3ContextListener = null;
}
LOG.debug("Initialized OFOverlay endpoint manager");
}
/**
* Add a {@link EndpointListener} to get notifications of switch events
*
* @param listener - the {@link EndpointListener} to add
*/
public void registerListener(EndpointListener listener) {
listeners.add(listener);
}
/**
* Get a collection of endpoints attached to a particular switch
*
* @param nodeId - the nodeId of the switch to get endpoints for
* @return a collection of {@link Endpoint} objects.
*/
public synchronized Set<EgKey> getGroupsForNode(NodeId nodeId) {
Map<EgKey, Set<EpKey>> nodeEps = endpointsByGroupByNode.get(nodeId);
if (nodeEps == null)
return Collections.emptySet();
return ImmutableSet.copyOf(nodeEps.keySet());
}
/**
* Get the set of nodes
*
* @param egKey - the egKey of the endpoint group to get nodes for
* @return a collection of {@link NodeId} objects.
*/
public synchronized Set<NodeId> getNodesForGroup(final EgKey egKey) {
return ImmutableSet.copyOf(Sets.filter(endpointsByGroupByNode.keySet(), new Predicate<NodeId>() {
@Override
public boolean apply(NodeId input) {
Map<EgKey, Set<EpKey>> nodeEps = endpointsByGroupByNode.get(input);
return (nodeEps != null && nodeEps.containsKey(egKey));
}
}));
}
/**
* Get the endpoints in a particular group on a particular node
*
* @param nodeId - the node ID to look up
* @param eg - the group to look up
* @return the endpoints
*/
public synchronized Collection<Endpoint> getEndpointsForNode(NodeId nodeId, EgKey eg) {
// TODO: alagalah Create method findEndpointsByNode() that uses
// data store
Map<EgKey, Set<EpKey>> nodeEps = endpointsByGroupByNode.get(nodeId);
if (nodeEps == null)
return Collections.emptyList();
Collection<EpKey> ebn = nodeEps.get(eg);
if (ebn == null)
return Collections.emptyList();
return ImmutableList.copyOf(Collections2.transform(ebn, indexTransform));
}
/**
* Get the endpoints on a particular node
*
* @param nodeId - the node ID to look up
* @return the endpoints
*/
public synchronized Collection<Endpoint> getEndpointsForNode(final NodeId nodeId) {
// TODO: alagalah Create method findEndpointsByNode() that uses
// data store. See commented code below.
Collection<EpKey> ebn = endpointsByNode.get(nodeId);
if (ebn == null)
return Collections.emptyList();
return ImmutableList.copyOf(Collections2.transform(ebn, indexTransform));
}
/**
* Get the endpoint object for the given key
*
* @param epKey - the key
* @return the {@link Endpoint} corresponding to the key
*/
public Endpoint getEndpoint(EpKey epKey) {
return endpoints.get(epKey);
}
/**
* Get all endpoint objects
* @return the {@link Endpoint} corresponding to the key
*/
public HashSet<Endpoint> getEndpoints() {
return new HashSet<>(endpoints.values());
}
/**
* Get a collection of endpoints in a particular endpoint group
*
* @param eg - Endpoint group key (contains endpoint group and tenant ID)
* @return a collection of {@link Endpoint} objects.
*/
public synchronized Collection<Endpoint> getEndpointsForGroup(EgKey eg) {
Collection<EpKey> ebg = endpointsByGroup.get(eg);
if (ebg == null)
return Collections.emptyList();
return ImmutableList.copyOf(Collections2.transform(ebg, indexTransform));
}
/**
* Return set of external endpoints without location belonging to a particular endpoint group
*
* @param eg - Endpoint group key (contains endpoint group and tenant ID)
* @return a collection of {@link Endpoint} objects.
*/
public synchronized Collection<Endpoint> getExtEpsNoLocForGroup(final EgKey eg) {
return ImmutableSet
.copyOf(Collections2.filter(externalEndpointsWithoutLocation.values(), new Predicate<Endpoint>() {
@Override
public boolean apply(Endpoint input) {
Set<EndpointGroupId> epgIds = new HashSet<>();
if (input.getEndpointGroup() != null) {
epgIds.add(input.getEndpointGroup());
}
if (input.getEndpointGroups() != null) {
epgIds.addAll(input.getEndpointGroups());
}
if (epgIds.isEmpty()) {
LOG.error("No EPGs for {}. This is not a valid Endpoint.", input.getKey());
return false;
}
return (epgIds.contains(eg.getEgId()));
}
}));
}
/**
* Character of input parameters will determine action - create, update or delete L3Endpoint
*
* @param oldL3Ep the old L3 endpoint
* @param newL3Ep the new L3 endpoint
*/
protected synchronized void processL3Endpoint(EndpointL3 oldL3Ep, EndpointL3 newL3Ep) {
// TODO Bug 3543
// create L3 endpoint
if (oldL3Ep == null && newL3Ep != null) {
createL3Endpoint(newL3Ep);
OFStatisticsManager.addL3Endpoint(newL3Ep);
}
// update L3 endpoint
if (oldL3Ep != null && newL3Ep != null) {
updateL3Endpoint(newL3Ep);
}
// remove L3 endpoint
if (oldL3Ep != null && newL3Ep == null) {
OFStatisticsManager.removeL3Endpoint(oldL3Ep);
removeL3Endpoint(oldL3Ep);
}
}
/**
* Character of input parameters will determine action - create, update or delete Endpoint
*
* @param oldEp - oldEp the new endpoint
* @param newEp - newEp the new endpoint
*/
protected synchronized void processEndpoint(Endpoint oldEp, Endpoint newEp) {
NodeId oldLoc = getLocation(oldEp);
NodeId newLoc = getLocation(newEp);
EpKey oldEpKey = getEpKey(oldEp);
EpKey newEpKey = getEpKey(newEp);
TenantId tenantId = (newEp == null) ? null : newEp.getTenant();
if (newEp != null && !isValidEp(newEp)) {
LOG.info("Endpoint is not valid: {}", newEp);
return;
}
Set<EndpointGroupId> oldEpgIds = getEndpointGroupsFromEndpoint(oldEp);
Set<EndpointGroupId> newEpgIds = getEndpointGroupsFromEndpoint(newEp);
boolean notifyOldLoc = false;
boolean notifyNewLoc = false;
boolean notifyOldEg = false;
boolean notifyNewEg = false;
// create endpoint
if (oldEp == null && newEp != null) {
if (newLoc != null) {
createEndpoint(newLoc, newEpKey, newEpgIds, tenantId);
endpoints.put(newEpKey, newEp);
notifyEndpointUpdated(newEpKey);
notifyNewLoc = true;
notifyNewEg = true;
} else {
externalEndpointsWithoutLocation.put(newEpKey, newEp);
}
}
// update endpoint
else if (oldEp != null && newEp != null && oldEpKey != null && newEpKey != null) {
// endpoint is not external anymore
if (newLoc != null && oldLoc == null) {
createEndpoint(newLoc, newEpKey, newEpgIds, tenantId);
externalEndpointsWithoutLocation.remove(oldEpKey);
endpoints.put(newEpKey, newEp);
notifyEndpointUpdated(newEpKey);
notifyNewLoc = true;
notifyNewEg = true;
}
// endpoint changed to external
else if (newLoc == null && oldLoc != null) {
removeEndpoint(oldEp, oldLoc, oldEpKey, oldEpgIds);
externalEndpointsWithoutLocation.put(newEpKey, newEp);
endpoints.remove(oldEpKey);
notifyEndpointUpdated(oldEpKey);
notifyOldLoc = true;
notifyOldEg = true;
// endpoint might have changed location, EPGs or it's properties
} else if (newLoc != null && oldLoc != null) {
// endpoit changed location
if (!(oldLoc.getValue().equals(newLoc.getValue()))) {
notifyOldLoc = true;
notifyNewLoc = true;
}
// endpoint changed EPGs
if (!oldEpgIds.equals(newEpgIds)) {
notifyOldEg = true;
notifyNewEg = true;
}
removeEndpoint(oldEp, oldLoc, oldEpKey, oldEpgIds);
createEndpoint(newLoc, newEpKey, newEpgIds, tenantId);
notifyEndpointUpdated(newEpKey);
}
}
// remove endpoint
else if (oldEp != null && newEp == null) {
if (oldLoc != null) {
removeEndpoint(oldEp, oldLoc, oldEpKey, oldEpgIds);
endpoints.remove(oldEpKey);
notifyEndpointUpdated(oldEpKey);
notifyOldLoc = true;
notifyOldEg = true;
} else {
externalEndpointsWithoutLocation.remove(oldEpKey);
}
}
// notifications
if (notifyOldLoc)
notifyNodeEndpointUpdated(oldLoc, oldEpKey);
if (notifyNewLoc)
notifyNodeEndpointUpdated(newLoc, newEpKey);
if (notifyOldEg)
for (EndpointGroupId oldEpgId : oldEpgIds) {
EgKey oldEgKey = new EgKey(oldEp.getTenant(), oldEpgId);
notifyGroupEndpointUpdated(oldEgKey, oldEpKey);
}
if (notifyNewEg)
for (EndpointGroupId newEpgId : newEpgIds) {
EgKey newEgKey = new EgKey(newEp.getTenant(), newEpgId);
notifyGroupEndpointUpdated(newEgKey, newEpKey);
}
}
private void createEndpoint(NodeId newLoc, EpKey newEpKey, Set<EndpointGroupId> newEpgIds, TenantId tenantId) {
// Update endpointsByNode
if (endpointsByNode.get(newLoc) == null) {
Set<EpKey> epsNode = new HashSet<>();
epsNode.add(newEpKey);
endpointsByNode.put(newLoc, epsNode);
SwitchManager.activatingSwitch(newLoc);
} else {
Set<EpKey> epsNode = endpointsByNode.get(newLoc);
epsNode.add(newEpKey);
}
// Update endpointsByGroupByNode and endpointsByGroup
for (EndpointGroupId newEpgId : newEpgIds) {
// endpointsByGroupByNode
EgKey newEgKey = new EgKey(tenantId, newEpgId);
Set<EpKey> eps = getEpNGSet(newLoc, newEgKey);
eps.add(newEpKey);
// endpointsByGroup
Set<EpKey> geps = endpointsByGroup.get(newEgKey);
if (geps == null) {
geps = new HashSet<>();
}
geps.add(newEpKey);
endpointsByGroup.put(newEgKey, geps);
LOG.debug("Endpoint {} added to node {}", newEpKey, newLoc);
}
}
private void removeEndpoint(Endpoint oldEp, NodeId oldLoc, EpKey oldEpKey, Set<EndpointGroupId> oldEpgIds) {
// Update endpointsByNode
Set<EpKey> epsNode = endpointsByNode.get(oldLoc);
if (epsNode != null) {
epsNode.remove(oldEpKey);
if (epsNode.isEmpty()) {
endpointsByNode.remove(oldLoc);
SwitchManager.deactivatingSwitch(oldLoc);
}
}
// Update endpointsByGroupByNode and endpointsByGroup, get map of EPGs and their Endpoints
// for Node
ConcurrentMap<EgKey, Set<EpKey>> map = endpointsByGroupByNode.get(oldLoc);
for (EndpointGroupId oldEpgId : oldEpgIds) {
// endpointsByGroupByNode
EgKey oldEgKey = new EgKey(oldEp.getTenant(), oldEpgId);
Set<EpKey> eps = map.get(oldEgKey);
if (eps != null) {
eps.remove(oldEpKey);
if (eps.isEmpty())
map.remove(oldEgKey, Collections.emptySet());
}
// endpointsByGroup
Set<EpKey> geps = endpointsByGroup.get(oldEgKey);
if (geps != null) {
geps.remove(oldEpKey);
if (geps.isEmpty())
endpointsByGroup.remove(oldEgKey);
}
}
// If map is empty, no more EPGs on this node, remove node from map
if (map.isEmpty())
endpointsByGroupByNode.remove(oldLoc);
}
private void createL3Endpoint(EndpointL3 newL3Ep) {
LOG.trace("Processing L3Endpoint {}", newL3Ep.getKey());
if (isValidL3Ep(newL3Ep)) {
if (newL3Ep.getMacAddress() == null) {
if (newL3Ep.getNetworkContainment() != null) {
arpTasker.addMacForL3EpAndCreateEp(newL3Ep);
} else {
LOG.error("Cannot generate MacAddress for L3Endpoint {}. NetworkContainment is null.", newL3Ep);
return;
}
}
if (newL3Ep.getL2Context() != null && newL3Ep.getMacAddress() != null) {
notifyEndpointUpdated(new EpKey(newL3Ep.getL2Context(), newL3Ep.getMacAddress()));
return;
}
} else {
LOG.error("{} is not a valid L3 Endpoint", newL3Ep);
return;
}
if (newL3Ep.getAugmentation(OfOverlayL3Context.class) == null) {
LOG.info("L3Endpoint created but no augmentation information");
}
}
private void updateL3Endpoint(EndpointL3 newL3Ep) {
LOG.trace("Updating L3 Endpoint {}");
notifyEndpointUpdated(new EpKey(newL3Ep.getL2Context(), newL3Ep.getMacAddress()));
if (newL3Ep.getAugmentation(OfOverlayL3Context.class) == null) {
LOG.info("L3Endpoint updated but no augmentation information");
}
}
private void removeL3Endpoint(EndpointL3 oldL3Ep) {
LOG.trace("Removing L3 Endpoint {}");
notifyEndpointUpdated(new EpKey(oldL3Ep.getL2Context(), oldL3Ep.getMacAddress()));
}
// auto closeable
@Override
public void close() throws Exception {
if (endpointListener != null) {
endpointListener.close();
}
if (notificationListenerRegistration != null) {
notificationListenerRegistration.close();
}
if (ofOverlayContextListener != null) {
ofOverlayContextListener.close();
}
if (ofOverlayL3ContextListener != null) {
ofOverlayL3ContextListener.close();
}
}
private Set<EpKey> getEpNGSet(NodeId location, EgKey eg) {
ConcurrentMap<EgKey, Set<EpKey>> map = endpointsByGroupByNode.get(location);
if (map == null) {
map = new ConcurrentHashMap<>();
ConcurrentMap<EgKey, Set<EpKey>> old = endpointsByGroupByNode.putIfAbsent(location, map);
if (old != null)
map = old;
}
return SetUtils.getNestedSet(eg, map);
}
/**
* An endpoint is external if its endpoint-group is external implicit group.
*
* @param ep an endpoint
* @param eigs external implicit groups
* @return {@code true} if the given endpoint has EPG representing external implicit group;
* {@code false} otherwise
* @throws NullPointerException if the given endpoint is {@code null}
* @throws IllegalArgumentException if the given endpoint does not contain any endpoint-group
*/
public static boolean isExternal(Endpoint ep, @Nullable Collection<ExternalImplicitGroup> eigs) {
return !isInternal(ep, eigs);
}
/**
* An endpoint is internal if none of its endpoint-groups is external implicit group.
*
* @param ep an endpoint
* @param eigs external implicit groups
* @return {@code true} if the given endpoint does not have EPG representing external implicit
* group;
* {@code false} otherwise
* @throws NullPointerException if the given endpoint is {@code null}
* @throws IllegalArgumentException if the given endpoint does not contain any endpoint-group
*/
public static boolean isInternal(Endpoint ep, @Nullable Collection<ExternalImplicitGroup> eigs) {
Preconditions.checkNotNull(ep);
if (eigs == null || eigs.isEmpty()) {
return true;
}
Set<EndpointGroupId> epgs = getEpgs(ep);
Preconditions.checkArgument(!epgs.isEmpty());
for (EndpointGroupId epg : epgs) {
for (ExternalImplicitGroup eig : eigs) {
if (epg.equals(eig.getId())) {
return false;
}
}
}
return true;
}
private static Set<EndpointGroupId> getEpgs(EndpointFields ep) {
EndpointGroupId epgId = ep.getEndpointGroup();
List<EndpointGroupId> epgsId = ep.getEndpointGroups();
Set<EndpointGroupId> result = new HashSet<>();
if (epgId != null) {
result.add(epgId);
}
if (epgsId != null) {
result.addAll(epgsId);
}
return result;
}
/**
* Get the endpoints container from data store.
* Note: There are maps maintained by listener when higher performance is required.
*
* @return the
* {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.Endpoints}
*/
protected Endpoints getEndpointsFromDataStore() {
/*
* XXX: alagalah I wanted to avoid adding another Map. Due to not being able to
* get to the granularity of the L3PrefixEndpoint List within the Endpoints container
* in the data store, we have to pull all the Endpoints. If this causes performance issues
* we may have to revisit a Map in updateEndpoint but note, this Endpoint doesn't have a
* location
* and hence we would have to process it outside the null location check.
*/
if (dataProvider == null) {
LOG.error("Null DataProvider in EndpointManager getEndpointsL3Prefix");
return null;
}
ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
Optional<Endpoints> endpoints =
DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
IidFactory.endpointsIidWildcard(), rTx);
if (!endpoints.isPresent()) {
LOG.warn("No Endpoints present in data store.");
return null;
}
return endpoints.get();
}
/**
* Return all L3Endpoints from data store.
*
* @return the
* {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3}
* @return {@link Collection} of the {@link EndpointL3}.
* Empty {@link Collection} if no {@link EndpointL3} is found.
*/
protected Collection<EndpointL3> getL3Endpoints() {
Endpoints endpoints = getEndpointsFromDataStore();
if (endpoints == null || endpoints.getEndpointL3() == null) {
LOG.warn("No L3 Endpoints present in data store.");
return null;
}
return endpoints.getEndpointL3();
}
/**
* Reads L2 endpoint from data store using appropriate {@link EndpointL3}
*
* @return {@link EndpointL3} if exists, otherwise null
*/
public Endpoint getL2EndpointFromL3(EndpointL3 endpointL3) {
if (endpointL3 != null) {
L2BridgeDomainId l2Context = endpointL3.getL2Context();
MacAddress macAddress = endpointL3.getMacAddress();
if (l2Context == null || macAddress == null) {
LOG.debug("[L2Context: {}, MacAddress: {}] Cannot read endpoint from DS unless both keys are specified!",
l2Context, macAddress);
return null;
}
EpKey l2EndpointKey = new EpKey(l2Context, macAddress);
if (endpoints.get(l2EndpointKey) != null) {
return endpoints.get(l2EndpointKey);
}
return externalEndpointsWithoutLocation.get(l2EndpointKey);
}
return null;
}
/**
* Reads endpointL3 from data store
* @param l3c id of {@link L3Context}
* @param ipAddress IP address of the endpoint
* @param tenantId ID of {@link Tenant} can be optionally specified
* @return {@link EndpointL3} if exists, otherwise null.
*/
public EndpointL3 getL3Endpoint(L3ContextId l3c, IpAddress ipAddress, @Nullable TenantId tenantId) {
if (l3c == null || ipAddress == null) {
LOG.warn("[ContextId: {}, IpAddress: {}] Cannot read endpoint from DS unless both keys are specified!",
l3c, ipAddress);
return null;
}
ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction();
Optional<EndpointL3> endpointL3 = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
IidFactory.l3EndpointIid(l3c, ipAddress), rTx);
rTx.close();
if (!endpointL3.isPresent()) {
LOG.warn("EndpointL3 [{},{}] not found in data store.", l3c, ipAddress);
return null;
}
if(tenantId != null && !endpointL3.get().getTenant().equals(tenantId)) {
LOG.warn("EndpointL3 [{},{}] not found in data store for tenant: {}", l3c, ipAddress, tenantId);
return null;
}
return endpointL3.get();
}
/**
* Return all L3Prefix Endpoints from data store.
*
* @return the
* {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix}
*/
private Collection<EndpointL3Prefix> getEndpointsL3Prefix() {
Endpoints endpoints = getEndpointsFromDataStore();
if (endpoints == null || endpoints.getEndpointL3Prefix() == null) {
LOG.warn("No L3 Prefix Endpoints present in data store.");
return null;
}
return endpoints.getEndpointL3Prefix();
}
/**
* Return all L3Prefix Endpoints which come under particular tenant
*
* @param tenantId - the
* {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId}
* to resolve
* @return the
* {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix}
*/
public Collection<EndpointL3Prefix> getEndpointsL3PrefixForTenant(final TenantId tenantId) {
Collection<EndpointL3Prefix> l3PrefixEndpoints = getEndpointsL3Prefix();
if (l3PrefixEndpoints == null) {
// Log message already generated in getEndpointsL3Prefix()
return null;
}
return ImmutableSet.copyOf(Collections2.filter(l3PrefixEndpoints, new Predicate<EndpointL3Prefix>() {
@Override
public boolean apply(EndpointL3Prefix input) {
return (input.getTenant().equals(tenantId));
}
}));
}
/**
* Return all L3Endpoints containing network and port address translation in augmentation
*
* @return the
* {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3}
*/
public @Nonnull Collection<EndpointL3> getL3EndpointsWithNat() {
Collection<EndpointL3> l3Endpoints = getL3Endpoints();
if (l3Endpoints == null) {
return Collections.emptySet();
}
l3Endpoints = Collections2.filter(l3Endpoints, new Predicate<EndpointL3>() {
@Override
public boolean apply(EndpointL3 input) {
return !((input.getAugmentation(NatAddress.class) == null)
|| (input.getAugmentation(NatAddress.class).getNatAddress() == null));
}
});
return ImmutableSet.copyOf(l3Endpoints);
}
/**
* Set the learning mode to the specified value
*
* @param learningMode - the learning mode to set
*/
@SuppressWarnings({"UnusedParameters", "EmptyMethod"})
public void setLearningMode(OfOverlayConfig.LearningMode learningMode) {
// No-op for now
}
/**
* Get the effective list of conditions that apply to a particular endpoint.
* This could include additional conditions over the condition labels
* directly represented in the endpoint object
* set
*
* @param endpoint - the
* {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint}
* to resolve
* @return the list of
* {@link org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName}
*/
public List<ConditionName> getConditionsForEndpoint(Endpoint endpoint) {
// TODO Be alagalah From Helium: consider group conditions as well. Also
// need to notify
// endpoint updated if the endpoint group conditions change
if (endpoint.getCondition() != null)
return endpoint.getCondition();
else
return Collections.emptyList();
}
/**
* @param endpoint - {@link Endpoint} which should contain location
* @return {@link NodeId} of node endpoint is placed on
*/
public NodeId getEndpointNodeId(Endpoint endpoint) {
if (endpoint.getAugmentation(OfOverlayContext.class) != null) {
return endpoint.getAugmentation(OfOverlayContext.class).getNodeId();
}
return null;
}
/**
* @param endpoint - {@link Endpoint} which should contain location
* @return {@link NodeConnectorId} of node endpoint is connected to
*/
public NodeConnectorId getEndpointNodeConnectorId(Endpoint endpoint) {
if (endpoint.getAugmentation(OfOverlayContext.class) != null) {
return endpoint.getAugmentation(OfOverlayContext.class).getNodeConnectorId();
}
return null;
}
private void notifyEndpointUpdated(EpKey epKey) {
for (EndpointListener l : listeners) {
l.endpointUpdated(epKey);
}
}
private void notifyNodeEndpointUpdated(NodeId nodeId, EpKey epKey) {
for (EndpointListener l : listeners) {
l.nodeEndpointUpdated(nodeId, epKey);
}
}
private void notifyGroupEndpointUpdated(EgKey egKey, EpKey epKey) {
for (EndpointListener l : listeners) {
l.groupEndpointUpdated(egKey, epKey);
}
}
private boolean isValidEp(Endpoint endpoint) {
return (endpoint != null && endpoint.getTenant() != null
&& (endpoint.getEndpointGroup() != null || (endpoint.getEndpointGroups() != null && !endpoint.getEndpointGroups().isEmpty()))
&& endpoint.getL2Context() != null && endpoint.getMacAddress() != null);
}
private boolean isValidL3Ep(EndpointL3 endpoint) {
return (endpoint != null && endpoint.getTenant() != null
&& (endpoint.getEndpointGroup() != null || endpoint.getEndpointGroups() != null)
&& endpoint.getL3Context() != null && endpoint.getIpAddress() != null);
}
private NodeId getLocation(Endpoint endpoint) {
if (isValidEp(endpoint)) {
OfOverlayContext context = endpoint.getAugmentation(OfOverlayContext.class);
if (context != null)
return context.getNodeId();
}
return null;
}
private EpKey getEpKey(Endpoint endpoint) {
if (isValidEp(endpoint))
return new EpKey(endpoint.getL2Context(), endpoint.getMacAddress());
return null;
}
public Set<EgKey> getEgKeysForEndpoint(Endpoint ep) {
Set<EgKey> egKeys = new HashSet<>();
if (ep.getEndpointGroup() != null) {
egKeys.add(new EgKey(ep.getTenant(), ep.getEndpointGroup()));
}
if (ep.getEndpointGroups() != null) {
for (EndpointGroupId epgId : ep.getEndpointGroups()) {
egKeys.add(new EgKey(ep.getTenant(), epgId));
}
}
return egKeys;
}
private Set<EndpointGroupId> getEndpointGroupsFromEndpoint(Endpoint ep) {
if (ep == null)
return new HashSet<>();
Set<EndpointGroupId> epgIds = new HashSet<>();
if (ep.getEndpointGroups() != null) {
epgIds.addAll(ep.getEndpointGroups());
}
if (ep.getEndpointGroup() != null) {
epgIds.add(ep.getEndpointGroup());
}
return epgIds;
}
protected Map<EndpointKey, EndpointL3> getL3EpWithNatByL2Key() {
Map<EndpointKey, EndpointL3> l3EpByL2EpKey = new HashMap<>();
Collection<EndpointL3> l3Eps = getL3EndpointsWithNat();
if (l3Eps == null) {
l3EpByL2EpKey = Collections.emptyMap();
return l3EpByL2EpKey;
}
for (EndpointL3 l3Ep : l3Eps) {
if (l3Ep.getL2Context() != null && l3Ep.getMacAddress() != null) {
EndpointKey epKey = new EndpointKey(l3Ep.getL2Context(), l3Ep.getMacAddress());
l3EpByL2EpKey.put(epKey, l3Ep);
}
}
if (l3EpByL2EpKey.isEmpty()) {
l3EpByL2EpKey = Collections.emptyMap();
}
return l3EpByL2EpKey;
}
public EgKey getEgKey(Endpoint endpoint) {
if (!isValidEp(endpoint))
return null;
return new EgKey(endpoint.getTenant(), endpoint.getEndpointGroup());
}
}