/*
* Copyright (c) 2017 Hewlett Packard Enterprise, Co. 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.netvirt.policyservice;
import java.util.Optional;
import java.math.BigInteger;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.binding.api.WriteTransaction;
import org.opendaylight.genius.mdsalutil.InstructionInfo;
import org.opendaylight.genius.mdsalutil.MatchInfoBase;
import org.opendaylight.genius.mdsalutil.NwConstants;
import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
import org.opendaylight.netvirt.policyservice.util.PolicyServiceFlowUtil;
import org.opendaylight.netvirt.policyservice.util.PolicyServiceUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Program POLICY_ROUTING_TABLE flows. Each flow is composed from
* * OF matches - logical tunnel lport tag and policy classifier metadata
* bits
* * OF actions - set policy classifier group id based on the remote DPN
* associated with the logical tunnel.
*
*/
@Singleton
public class PolicyRouteFlowProgrammer {
private static final Logger LOG = LoggerFactory.getLogger(PolicyRouteFlowProgrammer.class);
private final DataBroker dataBroker;
private final PolicyIdManager policyIdManager;
private final PolicyServiceUtil policyServiceUtil;
private final PolicyServiceFlowUtil policyFlowUtil;
private final JobCoordinator coordinator;
@Inject
public PolicyRouteFlowProgrammer(final DataBroker dataBroker, final PolicyIdManager policyIdManager,
final PolicyServiceUtil policyServiceUtil, final PolicyServiceFlowUtil policyFlowUtil,
final JobCoordinator coordinator) {
this.dataBroker = dataBroker;
this.policyIdManager = policyIdManager;
this.policyServiceUtil = policyServiceUtil;
this.policyFlowUtil = policyFlowUtil;
this.coordinator = coordinator;
}
public void programPolicyClassifierFlows(String policyClassifierName, List localDpIds,
List remoteDpIds, int addOrRemove) {
long policyClassifierId = policyIdManager.getPolicyClassifierId(policyClassifierName);
if (policyClassifierId == PolicyServiceConstants.INVALID_ID) {
LOG.error("Failed to get policy classifier id for classifier {}", policyClassifierName);
return;
}
coordinator.enqueueJob(policyClassifierName, () -> {
WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
remoteDpIds.forEach(remoteDpId -> {
long groupId = policyIdManager.getPolicyClassifierGroupId(policyClassifierName, remoteDpId);
if (groupId != PolicyServiceConstants.INVALID_ID) {
List instructions = policyFlowUtil.getPolicyRouteInstructions(groupId);
localDpIds.forEach(localDpId -> {
if (!remoteDpId.equals(localDpId)) {
programPolicyClassifierFlow(policyClassifierName, policyClassifierId, instructions,
localDpId, remoteDpId, tx, addOrRemove);
}
});
} else {
LOG.error("Failed to get group id for policy classifier {} DPN {}", policyClassifierName,
remoteDpId);
}
});
return Collections.singletonList(tx.submit());
});
}
public void programPolicyClassifierFlow(String policyClassifierName, BigInteger localDpId, BigInteger remoteDpId,
int addOrRemove) {
programPolicyClassifierFlow(policyClassifierName, localDpId, remoteDpId, addOrRemove, false);
}
public void programPolicyClassifierFlow(String policyClassifierName, BigInteger localDpId, BigInteger remoteDpId,
int addOrRemove, boolean createIfMissing) {
long policyClassifierId = policyIdManager.getPolicyClassifierId(policyClassifierName);
if (policyClassifierId == PolicyServiceConstants.INVALID_ID) {
LOG.error("Failed to get policy classifier id for classifier {}", policyClassifierName);
return;
}
long groupId = policyIdManager.getPolicyClassifierGroupId(policyClassifierName, remoteDpId);
if (groupId == PolicyServiceConstants.INVALID_ID) {
LOG.error("Failed to get group id for policy classifier {} DPN {}", policyClassifierName, remoteDpId);
return;
}
if (addOrRemove == NwConstants.ADD_FLOW && createIfMissing) {
addPolicyClassifierGroup(policyClassifierName, localDpId, remoteDpId, addOrRemove, groupId);
}
List instructions = policyFlowUtil.getPolicyRouteInstructions(groupId);
coordinator.enqueueJob(policyClassifierName, () -> {
WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
programPolicyClassifierFlow(policyClassifierName, policyClassifierId, instructions, localDpId, remoteDpId,
tx, addOrRemove);
return Collections.singletonList(tx.submit());
});
}
private void programPolicyClassifierFlow(String policyClassifierName, long policyClassifierId,
List instructions, BigInteger localDpId, BigInteger remoteDpId, WriteTransaction tx,
int addOrRemove) {
Optional lportTagOpt = policyServiceUtil.getLogicalTunnelLportTag(localDpId, remoteDpId);
if (!lportTagOpt.isPresent()) {
LOG.debug("Missing lport-tag for policy classifier {} logical tunnel for source DPN {} dst DPN {}",
policyClassifierName, localDpId, remoteDpId);
return;
}
List matches = policyFlowUtil.getPolicyRouteMatches(policyClassifierId, lportTagOpt.get());
LOG.debug("{} policy classifier {} route on source DPN {} dest DPN {}",
addOrRemove == NwConstants.ADD_FLOW ? "Installing" : "Removing", policyClassifierName, localDpId,
remoteDpId);
policyFlowUtil.updateFlowToTx(localDpId, NwConstants.EGRESS_POLICY_ROUTING_TABLE,
PolicyIdManager.getPolicyClassifierGroupKey(policyClassifierName, remoteDpId),
PolicyServiceConstants.POLICY_FLOW_PRIOPITY, NwConstants.EGRESS_POLICY_ROUTING_COOKIE, matches,
instructions, addOrRemove, tx);
}
private void addPolicyClassifierGroup(String policyClassifierName, BigInteger localDpId, BigInteger remoteDpId,
int addOrRemove, long groupId) {
coordinator.enqueueJob(policyClassifierName, () -> {
WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
policyFlowUtil.updateGroupToTx(localDpId, groupId,
PolicyIdManager.getPolicyClassifierGroupKey(policyClassifierName, remoteDpId), GroupTypes.GroupFf,
addOrRemove, tx);
return Collections.singletonList(tx.submit());
});
}
}