*/
package org.opendaylight.protocol.bgp.rib.impl;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-
-import org.opendaylight.protocol.bgp.concepts.BGPObject;
-import org.opendaylight.protocol.bgp.parser.BGPLink;
-import org.opendaylight.protocol.bgp.parser.BGPNode;
-import org.opendaylight.protocol.bgp.parser.BGPPrefix;
-import org.opendaylight.protocol.bgp.parser.BGPRoute;
-import org.opendaylight.protocol.bgp.parser.BGPSession;
-import org.opendaylight.protocol.bgp.parser.BGPSessionListener;
-import org.opendaylight.protocol.bgp.parser.BGPTableType;
-import org.opendaylight.protocol.bgp.parser.BGPUpdateMessage;
-import org.opendaylight.protocol.bgp.parser.BGPUpdateSynchronized;
-import org.opendaylight.protocol.bgp.util.BGPIPv4RouteImpl;
-import org.opendaylight.protocol.bgp.util.BGPIPv6RouteImpl;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.LinkstateAddressFamily;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev130918.LinkstateSubsequentAddressFamily;
+import org.opendaylight.protocol.bgp.rib.spi.BGPSession;
+import org.opendaylight.protocol.bgp.rib.spi.BGPSessionListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.UpdateBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.AttributesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.Attributes2Builder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpUnreachNlriBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.rib.TablesKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv4AddressFamily;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.Ipv6AddressFamily;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.UnicastSubsequentAddressFamily;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Maps;
-
/**
* BGP speaker (without Graceful restart capability) sends KeepAlive message after sending all initial Update messages
* with certain AFI/SAFI. For each AFI/SAFI, it sends one KA message. As it is undetermined which KA message belongs to
*/
public class BGPSynchronization {
- private static final Logger logger = LoggerFactory.getLogger(BGPSynchronization.class);
-
- private static class SyncVariables {
-
- private boolean upd = false;
- private boolean eor = false;
-
- public void setUpd(final boolean upd) {
- this.upd = upd;
- }
-
- public void setEorTrue() {
- this.eor = true;
- }
-
- public boolean getEor() {
- return this.eor;
- }
-
- public boolean getUpd() {
- return this.upd;
- }
- }
-
- private final Map<BGPTableType, SyncVariables> syncStorage = Maps.newHashMap();
-
- private final BGPSessionListener listener;
-
- private final BGPSession session;
-
- public BGPSynchronization(final BGPSession session, final BGPSessionListener listener, final Set<BGPTableType> types) {
- this.listener = Preconditions.checkNotNull(listener);
- this.session = Preconditions.checkNotNull(session);
-
- for (final BGPTableType type : types) {
- this.syncStorage.put(type, new SyncVariables());
- }
- }
-
- /**
- * For each received Update message, the upd sync variable needs to be updated to true, for particular AFI/SAFI
- * combination. Currently we only assume Unicast SAFI. From the Update message we have to extract the AFI. Each
- * Update message can contain BGP Object with one type of AFI. If the object is BGP Link, BGP Node or BGPPrefix<?>
- * the AFI is Linkstate. In case of BGPRoute, the AFI depends on the IP Address of the prefix.
- *
- * @param msg received Update message
- */
- public void updReceived(final BGPUpdateMessage msg) {
- BGPTableType type = null;
- if (!msg.getAddedObjects().isEmpty()) {
- final BGPObject obj = msg.getAddedObjects().iterator().next();
- if (obj instanceof BGPRoute) {
- if ((BGPRoute) obj instanceof BGPIPv4RouteImpl) {
- type = new BGPTableType(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
- } else if ((BGPRoute) obj instanceof BGPIPv6RouteImpl) {
- type = new BGPTableType(Ipv6AddressFamily.class, UnicastSubsequentAddressFamily.class);
- }
- } else if (obj instanceof BGPLink || obj instanceof BGPNode || obj instanceof BGPPrefix<?>) {
- type = new BGPTableType(LinkstateAddressFamily.class, LinkstateSubsequentAddressFamily.class);
- }
- }
- final SyncVariables s = this.syncStorage.get(type);
- if (s == null) {
- logger.warn("BGPTableType was not present in open message : {}", type);
- return;
- }
- s.setUpd(true);
- }
-
- /**
- * This method is called, when the second KA message is received. It checks each AFI/SAFI sync variables. If they
- * are all false, which means, that there was at least one update message followed by one KA, the EOR is sent to
- * session.
- */
- public void kaReceived() {
- for (final Entry<BGPTableType, SyncVariables> entry : this.syncStorage.entrySet()) {
- final SyncVariables s = entry.getValue();
- if (!s.getEor()) {
- if (!s.getUpd()) {
- s.setEorTrue();
- final BGPUpdateSynchronized up = generateEOR(entry.getKey());
- logger.debug("Sending synchronization message: {}", up);
- this.listener.onMessage(this.session, up);
- }
- s.setUpd(false);
- }
- }
- }
-
- private BGPUpdateSynchronized generateEOR(final BGPTableType type) {
- return new BGPUpdateSynchronizedImpl(type);
- }
+ private static final Logger LOG = LoggerFactory.getLogger(BGPSynchronization.class);
+
+ private static class SyncVariables {
+
+ private boolean upd = false;
+ private boolean eor = false;
+
+ public void setUpd(final boolean upd) {
+ this.upd = upd;
+ }
+
+ public void setEorTrue() {
+ this.eor = true;
+ }
+
+ public boolean getEor() {
+ return this.eor;
+ }
+
+ public boolean getUpd() {
+ return this.upd;
+ }
+ }
+
+ private final Map<TablesKey, SyncVariables> syncStorage = Maps.newHashMap();
+
+ private final BGPSessionListener listener;
+
+ private final BGPSession session;
+
+ public BGPSynchronization(final BGPSession bgpSession, final BGPSessionListener listener, final Set<TablesKey> types) {
+ this.listener = Preconditions.checkNotNull(listener);
+ this.session = Preconditions.checkNotNull(bgpSession);
+
+ for (final TablesKey type : types) {
+ this.syncStorage.put(type, new SyncVariables());
+ }
+ }
+
+ /**
+ * For each received Update message, the upd sync variable needs to be updated to true, for particular AFI/SAFI
+ * combination. Currently we only assume Unicast SAFI. From the Update message we have to extract the AFI. Each
+ * Update message can contain BGP Object with one type of AFI. If the object is BGP Link, BGP Node or a BGPPrefix
+ * the AFI is Linkstate. In case of BGPRoute, the AFI depends on the IP Address of the prefix.
+ *
+ * @param msg received Update message
+ */
+ public void updReceived(final Update msg) {
+ TablesKey type = new TablesKey(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class);
+ boolean isEOR = false;
+ if (msg.getNlri() == null && msg.getWithdrawnRoutes() == null) {
+ if (msg.getAttributes() != null) {
+ if (msg.getAttributes().getAugmentation(Attributes1.class) != null) {
+ final Attributes1 pa = msg.getAttributes().getAugmentation(Attributes1.class);
+ if (pa.getMpReachNlri() != null) {
+ type = new TablesKey(pa.getMpReachNlri().getAfi(), pa.getMpReachNlri().getSafi());
+ }
+ } else if (msg.getAttributes().getAugmentation(Attributes2.class) != null) {
+ final Attributes2 pa = msg.getAttributes().getAugmentation(Attributes2.class);
+ if (pa.getMpUnreachNlri() != null) {
+ type = new TablesKey(pa.getMpUnreachNlri().getAfi(), pa.getMpUnreachNlri().getSafi());
+ }
+ if (pa.getMpUnreachNlri().getWithdrawnRoutes() == null) {
+ // EOR message contains only MPUnreach attribute and no NLRI
+ isEOR = true;
+ }
+ }
+ } else {
+ // true for empty Update Message
+ isEOR = true;
+ }
+ }
+ final SyncVariables s = this.syncStorage.get(type);
+ if (s == null) {
+ LOG.warn("BGPTableType was not present in open message : {}", type);
+ return;
+ }
+ s.setUpd(true);
+ if (isEOR) {
+ s.setEorTrue();
+ LOG.info("BGP Synchronization finished for table {} ", type);
+ }
+ }
+
+ /**
+ * This method is called, when the second KA message is received. It checks each AFI/SAFI sync variables. If they
+ * are all false, which means, that there was at least one update message followed by one KA, the EOR is sent to
+ * session.
+ */
+ public void kaReceived() {
+ for (final Entry<TablesKey, SyncVariables> entry : this.syncStorage.entrySet()) {
+ final SyncVariables s = entry.getValue();
+ if (!s.getEor()) {
+ if (!s.getUpd()) {
+ s.setEorTrue();
+ LOG.info("BGP Synchronization finished for table {} ", entry.getKey());
+ final Update up = generateEOR(entry.getKey());
+ LOG.debug("Sending synchronization message: {}", up);
+ this.listener.onMessage(this.session, up);
+ }
+ s.setUpd(false);
+ }
+ }
+ }
+
+ private Update generateEOR(final TablesKey type) {
+ return new UpdateBuilder().setAttributes(
+ new AttributesBuilder().addAugmentation(
+ Attributes2.class,
+ new Attributes2Builder().setMpUnreachNlri(
+ new MpUnreachNlriBuilder().setAfi(type.getAfi()).setSafi(type.getSafi()).build()).build()).build()).build();
+ }
}