/* * 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.listeners; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.inject.Singleton; import org.opendaylight.mdsal.binding.api.DataBroker; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase; import org.opendaylight.genius.mdsalutil.NwConstants; import org.opendaylight.netvirt.policyservice.PolicyAceFlowProgrammer; import org.opendaylight.netvirt.policyservice.PolicyRouteFlowProgrammer; import org.opendaylight.netvirt.policyservice.PolicyRouteGroupProgrammer; import org.opendaylight.netvirt.policyservice.util.PolicyServiceUtil; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.UnderlayNetworks; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.policy.profiles.policy.profile.PolicyAclRule; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.policy.profiles.policy.profile.policy.acl.rule.AceRule; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.UnderlayNetwork; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.DpnToInterface; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.PolicyProfile; import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.policy.rev170207.underlay.networks.underlay.network.dpn.to._interface.TunnelInterface; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Listen on {@link DpnToInterface} operational updates for each underlay * network. When new DPN is added/removed, all policy pipeline associated flows * and groups will be populated to the new DPN.
* When new tunnel interfaces are added/removed from underlay network, the * corresponding policy classifier group buckets would be updated accordingly. */ @Singleton public class UnderlayNetworkDpnListener extends AsyncDataTreeChangeListenerBase { private static final Logger LOG = LoggerFactory.getLogger(UnderlayNetworkDpnListener.class); private final DataBroker dataBroker; private final PolicyServiceUtil policyServiceUtil; private final PolicyAceFlowProgrammer aceFlowProgrammer; private final PolicyRouteFlowProgrammer routeFlowProgrammer; private final PolicyRouteGroupProgrammer routeGroupProgramer; @Inject public UnderlayNetworkDpnListener(final DataBroker dataBroker, final PolicyServiceUtil policyServiceUtil, final PolicyAceFlowProgrammer aceFlowProgrammer, final PolicyRouteFlowProgrammer routeFlowProgrammer, final PolicyRouteGroupProgrammer routeGroupProgramer) { this.dataBroker = dataBroker; this.policyServiceUtil = policyServiceUtil; this.aceFlowProgrammer = aceFlowProgrammer; this.routeFlowProgrammer = routeFlowProgrammer; this.routeGroupProgramer = routeGroupProgramer; } @Override @PostConstruct public void init() { LOG.info("init"); registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker); } @Override protected InstanceIdentifier getWildCardPath() { return InstanceIdentifier.create(UnderlayNetworks.class).child(UnderlayNetwork.class) .child(DpnToInterface.class); } @Override protected UnderlayNetworkDpnListener getDataTreeChangeListener() { return this; } @Override protected void remove(InstanceIdentifier key, DpnToInterface dpnToInterface) { String underlayNetwork = key.firstKeyOf(UnderlayNetwork.class).getNetworkName(); BigInteger dpId = dpnToInterface.getDpId(); List tunnelInterfaces = dpnToInterface.getTunnelInterface(); LOG.info("DPN {} removed from underlay network {} with tunnels {}", dpId, underlayNetwork, tunnelInterfaces); List profiles = policyServiceUtil.getUnderlayNetworkPolicyProfiles(underlayNetwork); if (profiles == null || profiles.isEmpty()) { LOG.debug("No policy profiles found for underlay network {}", underlayNetwork); return; } populatePolicyGroupBucketsToDpn(underlayNetwork, profiles, tunnelInterfaces, dpId, NwConstants.DEL_FLOW); } @Override protected void update(InstanceIdentifier key, DpnToInterface origDpnToInterface, DpnToInterface updatedDpnToInterface) { String underlayNetwork = key.firstKeyOf(UnderlayNetwork.class).getNetworkName(); BigInteger dpId = updatedDpnToInterface.getDpId(); LOG.info("DPN {} updated to underlay network {} with tunnels {}", dpId, underlayNetwork, updatedDpnToInterface.getTunnelInterface()); List profiles = policyServiceUtil.getUnderlayNetworkPolicyProfiles(underlayNetwork); if (profiles == null || profiles.isEmpty()) { LOG.debug("No policy profiles found for underlay network {}", underlayNetwork); return; } List origTunnelInterfaces = origDpnToInterface.getTunnelInterface(); if (origTunnelInterfaces == null) { origTunnelInterfaces = Collections.emptyList(); } List updatedTunnelInterfaces = updatedDpnToInterface.getTunnelInterface(); if (updatedTunnelInterfaces == null) { updatedTunnelInterfaces = Collections.emptyList(); } List removedTunnelInterfaces = new ArrayList<>(origTunnelInterfaces); removedTunnelInterfaces.removeAll(updatedTunnelInterfaces); List addedTunnelInterfaces = new ArrayList<>(updatedTunnelInterfaces); addedTunnelInterfaces.removeAll(origTunnelInterfaces); populatePolicyGroupBucketsToDpn(underlayNetwork, profiles, removedTunnelInterfaces, dpId, NwConstants.DEL_FLOW); populatePolicyGroupsToDpn(profiles, addedTunnelInterfaces, dpId, NwConstants.ADD_FLOW); populatePolicyGroupBucketsToDpn(underlayNetwork, profiles, addedTunnelInterfaces, dpId, NwConstants.ADD_FLOW); } @Override protected void add(InstanceIdentifier key, DpnToInterface dpnToInterface) { String underlayNetwork = key.firstKeyOf(UnderlayNetwork.class).getNetworkName(); BigInteger dpId = dpnToInterface.getDpId(); List tunnelInterfaces = dpnToInterface.getTunnelInterface(); LOG.info("DPN {} added to underlay network {} with tunnels {}", dpId, underlayNetwork, tunnelInterfaces); List profiles = policyServiceUtil.getUnderlayNetworkPolicyProfiles(underlayNetwork); if (profiles == null || profiles.isEmpty()) { LOG.debug("No policy profiles found for underlay network {}", underlayNetwork); return; } populatePolicyGroupsToDpn(profiles, tunnelInterfaces, dpId, NwConstants.ADD_FLOW); populatePolicyGroupBucketsToDpn(underlayNetwork, profiles, tunnelInterfaces, dpId, NwConstants.ADD_FLOW); populatePolicyAclRulesToDpn(dpId, profiles, NwConstants.ADD_FLOW); populatePolicyRoutesToDpn(profiles, tunnelInterfaces, dpId, NwConstants.ADD_FLOW); } private void populatePolicyGroupsToDpn(List profiles, List tunnelInterfaces, BigInteger dpId, int addOrRemove) { profiles.forEach(profile -> { String policyClassifier = profile.getPolicyClassifier(); routeGroupProgramer.programPolicyClassifierGroups(policyClassifier, dpId, tunnelInterfaces, addOrRemove); }); } private void populatePolicyGroupBucketsToDpn(String underlayNetwork, List profiles, List tunnelInterfaces, BigInteger dpId, int addOrRemove) { profiles.forEach(profile -> { String policyClassifier = profile.getPolicyClassifier(); List underlayNetworks = policyServiceUtil.getUnderlayNetworksForClassifier(policyClassifier); if (underlayNetworks != null) { int bucketId = underlayNetworks.indexOf(underlayNetwork); if (bucketId != -1) { routeGroupProgramer.programPolicyClassifierGroupBuckets(policyClassifier, tunnelInterfaces, dpId, bucketId, addOrRemove); } else { LOG.warn("Policy classifier {} routes do not contain {}", policyClassifier, underlayNetwork); } } else { LOG.warn("No underlay networks found for classifier {} while populating {} flows", policyClassifier, underlayNetwork); } }); } private void populatePolicyAclRulesToDpn(BigInteger dpId, List profiles, int addOrRemove) { profiles.forEach(profile -> { String policyClassifier = profile.getPolicyClassifier(); List policyClassifierAclRules = policyServiceUtil.getPolicyClassifierAclRules(policyClassifier); if (policyClassifierAclRules != null) { policyClassifierAclRules.forEach(aclRule -> { List aceRules = aclRule.getAceRule(); if (aceRules != null) { aceRules.forEach(aceRule -> { com.google.common.base.Optional policyAceOpt = policyServiceUtil .getPolicyAce(aclRule.getAclName(), aceRule.getRuleName()); if (policyAceOpt.isPresent()) { aceFlowProgrammer.programAceFlows(policyAceOpt.get(), dpId, addOrRemove); } else { LOG.warn("Failed to get ACL {} rule {}", aclRule.getAclName(), aceRule.getRuleName()); } }); } else { LOG.debug("No ACE rule found for policy ACL {}", aclRule.getAclName()); } }); } }); } private void populatePolicyRoutesToDpn(List profiles, List tunnelInterfaces, BigInteger dpId, int addOrRemove) { if (tunnelInterfaces == null) { LOG.debug("No tunnel interfaces found for DPN {}", dpId); return; } profiles.forEach(policyProfile -> { String policyClassifier = policyProfile.getPolicyClassifier(); tunnelInterfaces.forEach(tunnelInterface -> { BigInteger remoteDpId = tunnelInterface.getRemoteDpId(); routeFlowProgrammer.programPolicyClassifierFlow(policyClassifier, dpId, remoteDpId, addOrRemove); }); }); } }