This splits out the policy tracker and implemnts proper policy tracking.
We optimize for lookup speeds, expecting the peers not to change much.
Change-Id: I92b27d54abb77ce10864d9ec8709a57aab7b87c7
Signed-off-by: Robert Varga <rovarga@cisco.com>
--- /dev/null
+/*
+ * Copyright (c) 2015 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.protocol.bgp.rib.impl;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Multimap;
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tracks peers for adj-rib-out writeout.
+ */
+final class ExportPolicyPeerTracker extends AbstractPeerRoleTracker {
+ private static final Logger LOG = LoggerFactory.getLogger(ExportPolicyPeerTracker.class);
+ private static final Function<YangInstanceIdentifier, Entry<PeerId, YangInstanceIdentifier>> GENERATE_PEERID = new Function<YangInstanceIdentifier, Entry<PeerId, YangInstanceIdentifier>>() {
+ @Override
+ public Entry<PeerId, YangInstanceIdentifier> apply(final YangInstanceIdentifier input) {
+ final PeerId peerId = IdentifierUtils.peerId((NodeIdentifierWithPredicates) input.getLastPathArgument());
+ return new AbstractMap.SimpleImmutableEntry<>(peerId, input);
+ }
+ };
+
+ private final Map<YangInstanceIdentifier, PeerRole> peerRoles = new HashMap<>();
+ private volatile Map<PeerRole, PeerExportGroup> groups = Collections.emptyMap();
+
+ protected ExportPolicyPeerTracker(final DOMDataTreeChangeService service, final YangInstanceIdentifier ribId) {
+ super(service, ribId);
+ }
+
+ private static Map<PeerRole, PeerExportGroup> createGroups(final Map<YangInstanceIdentifier, PeerRole> peerPathRoles) {
+ if (peerPathRoles.isEmpty()) {
+ return Collections.emptyMap();
+ }
+
+ // Index things nicely for easy access
+ final Multimap<PeerRole, YangInstanceIdentifier> roleToIds = ArrayListMultimap.create(PeerRole.values().length, 2);
+ final Map<PeerId, PeerRole> idToRole = new HashMap<>();
+ for (Entry<YangInstanceIdentifier, PeerRole> e : peerPathRoles.entrySet()) {
+ roleToIds.put(e.getValue(), e.getKey());
+ idToRole.put(IdentifierUtils.peerId((NodeIdentifierWithPredicates) e.getKey().getLastPathArgument()), e.getValue());
+ }
+
+ // Optimized immutable copy, reused for all PeerGroups
+ final Map<PeerId, PeerRole> peerRoles = ImmutableMap.copyOf(idToRole);
+
+ final Map<PeerRole, PeerExportGroup> ret = new EnumMap<>(PeerRole.class);
+ for (Entry<PeerRole, Collection<YangInstanceIdentifier>> e : roleToIds.asMap().entrySet()) {
+ final AbstractExportPolicy policy = AbstractExportPolicy.forRole(e.getKey());
+ final Collection<Entry<PeerId, YangInstanceIdentifier>> peers = ImmutableList.copyOf(Collections2.transform(e.getValue(), GENERATE_PEERID));
+
+ ret.put(e.getKey(), new PeerExportGroup(peers, peerRoles, policy));
+ }
+
+ return ret;
+ }
+
+ @Override
+ protected void peerRoleChanged(final YangInstanceIdentifier peerPath, final PeerRole role) {
+ /*
+ * This is a sledgehammer approach to the problem: modify the role map first,
+ * then construct the group map from scratch.
+ */
+ final PeerRole oldRole;
+ if (role != null) {
+ oldRole = peerRoles.put(peerPath, role);
+ } else {
+ oldRole = peerRoles.remove(peerPath);
+ }
+
+ if (role != oldRole) {
+ LOG.debug("Peer {} changed role from {} to {}", peerPath, oldRole, role);
+ groups = createGroups(peerRoles);
+ }
+ }
+
+ PeerExportGroup getPeerGroup(final PeerRole role) {
+ return groups.get(Preconditions.checkNotNull(role));
+ }
+}
\ No newline at end of file
import com.google.common.base.Preconditions;
import com.google.common.primitives.UnsignedInteger;
import java.util.Collection;
-import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
// FIXME: instantiate for each table, listen on wildcard peer and routes
@NotThreadSafe
-final class LocRibWriter implements DOMDataTreeChangeListener {
+final class LocRibWriter implements AutoCloseable, DOMDataTreeChangeListener {
private final Map<PathArgument, RouteEntry> routeEntries = new HashMap<>();
private final YangInstanceIdentifier target;
private final DOMTransactionChain chain;
+ private final ExportPolicyPeerTracker peerPolicyTracker;
private final RIBSupport ribSupport;
private final Long ourAs;
- // FIXME: these maps need to be populated
- private final Map<PeerRole, Map<PeerId, YangInstanceIdentifier>> peersToUpdate = new EnumMap<>(PeerRole.class);
- private final Map<PeerId, PeerRole> peers = new HashMap<>();
-
LocRibWriter(final RIBSupport ribSupport, final DOMTransactionChain chain, final YangInstanceIdentifier target, final Long ourAs) {
this.chain = Preconditions.checkNotNull(chain);
this.target = Preconditions.checkNotNull(target);
this.ourAs = Preconditions.checkNotNull(ourAs);
this.ribSupport = Preconditions.checkNotNull(ribSupport);
+
+ // FIXME: proper values
+ this.peerPolicyTracker = new ExportPolicyPeerTracker(null, null);
+ }
+
+ @Override
+ public void close() {
+ peerPolicyTracker.close();
}
@Override
* if we have two eBGP peers, for example, there is no reason why we should perform the translation
* multiple times.
*/
- for (Entry<PeerRole, AbstractExportPolicy> pe : AbstractExportPolicy.POLICIES.entrySet()) {
- final Map<PeerId, YangInstanceIdentifier> toPeers = peersToUpdate.get(pe.getKey());
- if (toPeers == null || toPeers.isEmpty()) {
- continue;
- }
-
- final ContainerNode attributes = null;
- final PeerId peerId = e.getKey().getPeerId();
- final ContainerNode effectiveAttributes = pe.getValue().effectiveAttributes(peers.get(peerId), attributes);
-
- for (Entry<PeerId, YangInstanceIdentifier> pid : toPeers.entrySet()) {
- // This points to adj-rib-out for a particlar peer/table combination
- final YangInstanceIdentifier routeTarget = pid.getValue().node(e.getKey().getRouteId());
-
- if (effectiveAttributes != null && value != null && !peerId.equals(pid.getKey())) {
- tx.put(LogicalDatastoreType.OPERATIONAL, routeTarget, value);
- tx.put(LogicalDatastoreType.OPERATIONAL, routeTarget.node(ribSupport.routeAttributes()), effectiveAttributes);
- } else {
- tx.delete(LogicalDatastoreType.OPERATIONAL, routeTarget);
+ for (PeerRole role : PeerRole.values()) {
+ final PeerExportGroup peerGroup = peerPolicyTracker.getPeerGroup(role);
+ if (peerGroup != null) {
+ final ContainerNode attributes = null;
+ final PeerId peerId = e.getKey().getPeerId();
+ final ContainerNode effectiveAttributes = peerGroup.effectiveAttributes(peerId, attributes);
+
+ for (Entry<PeerId, YangInstanceIdentifier> pid : peerGroup.getPeers()) {
+ // This points to adj-rib-out for a particular peer/table combination
+ final YangInstanceIdentifier routeTarget = pid.getValue().node(e.getKey().getRouteId());
+
+ if (effectiveAttributes != null && value != null && !peerId.equals(pid.getKey())) {
+ tx.put(LogicalDatastoreType.OPERATIONAL, routeTarget, value);
+ tx.put(LogicalDatastoreType.OPERATIONAL, routeTarget.node(ribSupport.routeAttributes()), effectiveAttributes);
+ } else {
+ tx.delete(LogicalDatastoreType.OPERATIONAL, routeTarget);
+ }
}
}
}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.protocol.bgp.rib.impl;
+
+import com.google.common.base.Preconditions;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+
+/**
+ * A collection of peers sharing the same export policy.
+ */
+final class PeerExportGroup {
+ private final Collection<Entry<PeerId, YangInstanceIdentifier>> peers;
+ private final Map<PeerId, PeerRole> peerRoles;
+ private final AbstractExportPolicy policy;
+
+ PeerExportGroup(final Collection<Entry<PeerId, YangInstanceIdentifier>> peers, final Map<PeerId, PeerRole> peerRoles, final AbstractExportPolicy policy) {
+ this.peers = Preconditions.checkNotNull(peers);
+ this.peerRoles = Preconditions.checkNotNull(peerRoles);
+ this.policy = Preconditions.checkNotNull(policy);
+ }
+
+ ContainerNode effectiveAttributes(final PeerId sourcePeerId, final ContainerNode attributes) {
+ return policy.effectiveAttributes(peerRoles.get(sourcePeerId), attributes);
+ }
+
+ Collection<Entry<PeerId, YangInstanceIdentifier>> getPeers() {
+ return peers;
+ }
+}
\ No newline at end of file