Work toward IPv6 support in BGP: implement decoding of the
BGP UPDATE attributes: MP_REACH_NLRI and MP_UNREACH_NLRI (RFC 4760).
Note: currently, the IPv6 NLRI is decoded, but it not used.
This work is in the context of ONOS-422.
Change-Id: Ia61b94dedfe0b1a7d7f563e805a3086f56d4da03
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpConstants.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpConstants.java
index 1d7d4c5..b009c17 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpConstants.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpConstants.java
@@ -376,6 +376,46 @@
/** BGP UPDATE Attributes Type Code AGGREGATOR length. */
public static final int LENGTH = 6;
}
+
+ /**
+ * BGP UPDATE: MP_REACH_NLRI related constants.
+ */
+ public static final class MpReachNlri {
+ /**
+ * Default constructor.
+ * <p>
+ * The constructor is private to prevent creating an instance of
+ * this utility class.
+ */
+ private MpReachNlri() {
+ }
+
+ /** BGP UPDATE Attributes Type Code MP_REACH_NLRI. */
+ public static final int TYPE = 14;
+
+ /** BGP UPDATE Attributes Type Code MP_REACH_NLRI min length. */
+ public static final int MIN_LENGTH = 5;
+ }
+
+ /**
+ * BGP UPDATE: MP_UNREACH_NLRI related constants.
+ */
+ public static final class MpUnreachNlri {
+ /**
+ * Default constructor.
+ * <p>
+ * The constructor is private to prevent creating an instance of
+ * this utility class.
+ */
+ private MpUnreachNlri() {
+ }
+
+ /** BGP UPDATE Attributes Type Code MP_UNREACH_NLRI. */
+ public static final int TYPE = 15;
+
+ /** BGP UPDATE Attributes Type Code MP_UNREACH_NLRI min length. */
+ public static final int MIN_LENGTH = 3;
+ }
}
/**
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSession.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSession.java
index 52c6827..15c4e3a 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSession.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpSession.java
@@ -36,6 +36,7 @@
import org.jboss.netty.util.TimerTask;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.Ip6Prefix;
import org.onosproject.sdnip.bgp.BgpConstants.Notifications;
import org.onosproject.sdnip.bgp.BgpConstants.Notifications.HoldTimerExpired;
import org.slf4j.Logger;
@@ -62,6 +63,8 @@
private long remoteAs4Octet; // 4 octets
private long remoteHoldtime; // 2 octets
private Ip4Address remoteBgpId; // 4 octets -> IPv4 address
+ private boolean remoteMpExtensions; // Peer Multiprotocol
+ // Extensions enabled: RFC 4760
private boolean remoteIpv4Unicast; // Peer IPv4/UNICAST AFI/SAFI
private boolean remoteIpv4Multicast; // Peer IPv4/MULTICAST AFI/SAFI
private boolean remoteIpv6Unicast; // Peer IPv6/UNICAST AFI/SAFI
@@ -74,6 +77,8 @@
private long localAs; // 2 octets
private long localHoldtime; // 2 octets
private Ip4Address localBgpId; // 4 octets -> IPv4 address
+ private boolean localMpExtensions; // Local Multiprotocol
+ // Extensions enabled: RFC 4760
private boolean localIpv4Unicast; // Local IPv4/UNICAST AFI/SAFI
private boolean localIpv4Multicast; // Local IPv4/MULTICAST AFI/SAFI
private boolean localIpv6Unicast; // Local IPv6/UNICAST AFI/SAFI
@@ -88,7 +93,9 @@
private volatile Timeout sessionTimeout; // Session timeout
// BGP RIB-IN routing entries from this peer
- private ConcurrentMap<Ip4Prefix, BgpRouteEntry> bgpRibIn =
+ private ConcurrentMap<Ip4Prefix, BgpRouteEntry> bgpRibIn4 =
+ new ConcurrentHashMap<>();
+ private ConcurrentMap<Ip6Prefix, BgpRouteEntry> bgpRibIn6 =
new ConcurrentHashMap<>();
/**
@@ -113,22 +120,41 @@
}
/**
- * Gets the BGP RIB-IN routing entries.
+ * Gets the BGP RIB-IN IPv4 routing entries.
*
- * @return the BGP RIB-IN routing entries
+ * @return the BGP RIB-IN IPv4 routing entries
*/
- public Map<Ip4Prefix, BgpRouteEntry> bgpRibIn() {
- return bgpRibIn;
+ public Map<Ip4Prefix, BgpRouteEntry> bgpRibIn4() {
+ return bgpRibIn4;
}
/**
- * Finds a BGP routing entry in the BGP RIB-IN.
+ * Gets the BGP RIB-IN IPv6 routing entries.
*
- * @param prefix the prefix of the route to search for
- * @return the BGP routing entry if found, otherwise null
+ * @return the BGP RIB-IN IPv6 routing entries
+ */
+ public Map<Ip6Prefix, BgpRouteEntry> bgpRibIn6() {
+ return bgpRibIn6;
+ }
+
+ /**
+ * Finds a BGP IPv4 routing entry in the BGP RIB-IN.
+ *
+ * @param prefix the IPv4 prefix of the route to search for
+ * @return the IPv4 BGP routing entry if found, otherwise null
*/
public BgpRouteEntry findBgpRouteEntry(Ip4Prefix prefix) {
- return bgpRibIn.get(prefix);
+ return bgpRibIn4.get(prefix);
+ }
+
+ /**
+ * Finds a BGP IPv6 routing entry in the BGP RIB-IN.
+ *
+ * @param prefix the IPv6 prefix of the route to search for
+ * @return the IPv6 BGP routing entry if found, otherwise null
+ */
+ public BgpRouteEntry findBgpRouteEntry(Ip6Prefix prefix) {
+ return bgpRibIn6.get(prefix);
}
/**
@@ -256,6 +282,16 @@
}
/**
+ * Gets the BGP Multiprotocol Extensions for the session.
+ *
+ * @return true if the BGP Multiprotocol Extensions are enabled for the
+ * session, otherwise false
+ */
+ public boolean getMpExtensions() {
+ return remoteMpExtensions && localMpExtensions;
+ }
+
+ /**
* Gets the BGP session remote AFI/SAFI configuration for IPv4 unicast.
*
* @return the BGP session remote AFI/SAFI configuration for IPv4 unicast
@@ -268,10 +304,11 @@
* Sets the BGP session remote AFI/SAFI configuration for IPv4 unicast.
*/
void setRemoteIpv4Unicast() {
+ this.remoteMpExtensions = true;
this.remoteIpv4Unicast = true;
// Copy the remote AFI/SAFI setting to the local configuration
- // NOTE: Uncomment the line below if the AFI/SAFI is supported locally
- // this.localIpv4Unicast = true;
+ this.localMpExtensions = true;
+ this.localIpv4Unicast = true;
}
/**
@@ -287,10 +324,11 @@
* Sets the BGP session remote AFI/SAFI configuration for IPv4 multicast.
*/
void setRemoteIpv4Multicast() {
+ this.remoteMpExtensions = true;
this.remoteIpv4Multicast = true;
// Copy the remote AFI/SAFI setting to the local configuration
- // NOTE: Uncomment the line below if the AFI/SAFI is supported locally
- // this.localIpv4Multicast = true;
+ this.localMpExtensions = true;
+ this.localIpv4Multicast = true;
}
/**
@@ -306,10 +344,11 @@
* Sets the BGP session remote AFI/SAFI configuration for IPv6 unicast.
*/
void setRemoteIpv6Unicast() {
+ this.remoteMpExtensions = true;
this.remoteIpv6Unicast = true;
// Copy the remote AFI/SAFI setting to the local configuration
- // NOTE: Uncomment the line below if the AFI/SAFI is supported locally
- // this.localIpv6Unicast = true;
+ this.localMpExtensions = true;
+ this.localIpv6Unicast = true;
}
/**
@@ -325,10 +364,11 @@
* Sets the BGP session remote AFI/SAFI configuration for IPv6 multicast.
*/
void setRemoteIpv6Multicast() {
+ this.remoteMpExtensions = true;
this.remoteIpv6Multicast = true;
// Copy the remote AFI/SAFI setting to the local configuration
- // NOTE: Uncomment the line below if the AFI/SAFI is supported locally
- // this.localIpv6Multicast = true;
+ this.localMpExtensions = true;
+ this.localIpv6Multicast = true;
}
/**
@@ -576,14 +616,17 @@
// for further processing. Otherwise, the BGP Decision Process
// will use those routes again.
//
- Collection<BgpRouteEntry> deletedRoutes = bgpRibIn.values();
- bgpRibIn = new ConcurrentHashMap<>();
+ Collection<BgpRouteEntry> deletedRoutes4 = bgpRibIn4.values();
+ Collection<BgpRouteEntry> deletedRoutes6 = bgpRibIn6.values();
+ bgpRibIn4 = new ConcurrentHashMap<>();
+ bgpRibIn6 = new ConcurrentHashMap<>();
// Push the updates to the BGP Merged RIB
BgpSessionManager.BgpRouteSelector bgpRouteSelector =
bgpSessionManager.getBgpRouteSelector();
Collection<BgpRouteEntry> addedRoutes = Collections.emptyList();
- bgpRouteSelector.routeUpdates(this, addedRoutes, deletedRoutes);
+ bgpRouteSelector.routeUpdates(this, addedRoutes, deletedRoutes4);
+ bgpRouteSelector.routeUpdates(this, addedRoutes, deletedRoutes6);
bgpSessionManager.peerDisconnected(this);
}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpUpdate.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpUpdate.java
index f7bfa32..2dabfd9 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpUpdate.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/bgp/BgpUpdate.java
@@ -25,9 +25,13 @@
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip6Address;
import org.onlab.packet.Ip4Prefix;
-import org.onosproject.sdnip.bgp.BgpConstants.Update.AsPath;
+import org.onlab.packet.Ip6Prefix;
import org.onosproject.sdnip.bgp.BgpConstants.Notifications.UpdateMessageError;
+import org.onosproject.sdnip.bgp.BgpConstants.Open.Capabilities.MultiprotocolExtensions;
+import org.onosproject.sdnip.bgp.BgpConstants.Update;
+import org.onosproject.sdnip.bgp.BgpConstants.Update.AsPath;
import org.onosproject.sdnip.bgp.BgpMessage.BgpParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -57,8 +61,7 @@
static void processBgpUpdate(BgpSession bgpSession,
ChannelHandlerContext ctx,
ChannelBuffer message) {
- Collection<BgpRouteEntry> addedRoutes = null;
- Map<Ip4Prefix, BgpRouteEntry> deletedRoutes = new HashMap<>();
+ DecodedBgpRoutes decodedBgpRoutes = new DecodedBgpRoutes();
int minLength =
BgpConstants.BGP_UPDATE_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
@@ -97,8 +100,8 @@
}
Collection<Ip4Prefix> withdrawnPrefixes = null;
try {
- withdrawnPrefixes = parsePackedPrefixes(withdrawnRoutesLength,
- message);
+ withdrawnPrefixes = parsePackedIp4Prefixes(withdrawnRoutesLength,
+ message);
} catch (BgpParseException e) {
// ERROR: Invalid Network Field
log.debug("Exception parsing Withdrawn Prefixes from BGP peer {}: ",
@@ -109,9 +112,10 @@
for (Ip4Prefix prefix : withdrawnPrefixes) {
log.debug("BGP RX UPDATE message WITHDRAWN from {}: {}",
bgpSession.getRemoteAddress(), prefix);
- BgpRouteEntry bgpRouteEntry = bgpSession.bgpRibIn().get(prefix);
+ BgpRouteEntry bgpRouteEntry = bgpSession.bgpRibIn4().get(prefix);
if (bgpRouteEntry != null) {
- deletedRoutes.put(prefix, bgpRouteEntry);
+ decodedBgpRoutes.deletedUnicastRoutes4.put(prefix,
+ bgpRouteEntry);
}
}
@@ -119,31 +123,53 @@
// Parse the Path Attributes
//
try {
- addedRoutes = parsePathAttributes(bgpSession, ctx, message);
+ parsePathAttributes(bgpSession, ctx, message, decodedBgpRoutes);
} catch (BgpParseException e) {
log.debug("Exception parsing Path Attributes from BGP peer {}: ",
bgpSession.getRemoteBgpId(), e);
// NOTE: The session was already closed, so nothing else to do
return;
}
- // Ignore WITHDRAWN routes that are ADDED
- for (BgpRouteEntry bgpRouteEntry : addedRoutes) {
- deletedRoutes.remove(bgpRouteEntry.prefix());
- }
+ //
// Update the BGP RIB-IN
- for (BgpRouteEntry bgpRouteEntry : deletedRoutes.values()) {
- bgpSession.bgpRibIn().remove(bgpRouteEntry.prefix());
+ //
+ Collection<BgpRouteEntry> bgpRoutes;
+ //
+ bgpRoutes = decodedBgpRoutes.deletedUnicastRoutes4.values();
+ for (BgpRouteEntry bgpRouteEntry : bgpRoutes) {
+ bgpSession.bgpRibIn4().remove(bgpRouteEntry.prefix());
}
- for (BgpRouteEntry bgpRouteEntry : addedRoutes) {
- bgpSession.bgpRibIn().put(bgpRouteEntry.prefix(), bgpRouteEntry);
+ //
+ bgpRoutes = decodedBgpRoutes.addedUnicastRoutes4.values();
+ for (BgpRouteEntry bgpRouteEntry : bgpRoutes) {
+ bgpSession.bgpRibIn4().put(bgpRouteEntry.prefix(), bgpRouteEntry);
}
+ //
+ bgpRoutes = decodedBgpRoutes.deletedUnicastRoutes6.values();
+ for (BgpRouteEntry bgpRouteEntry : bgpRoutes) {
+ bgpSession.bgpRibIn6().remove(bgpRouteEntry.prefix());
+ }
+ //
+ bgpRoutes = decodedBgpRoutes.addedUnicastRoutes6.values();
+ // TODO: fix/enable for IPv6
+ /*
+ for (BgpRouteEntry bgpRouteEntry : bgpRoutes) {
+ bgpSession.bgpRibIn6().put(bgpRouteEntry.prefix(), bgpRouteEntry);
+ }
+ */
+ //
// Push the updates to the BGP Merged RIB
+ //
BgpSessionManager.BgpRouteSelector bgpRouteSelector =
bgpSession.getBgpSessionManager().getBgpRouteSelector();
- bgpRouteSelector.routeUpdates(bgpSession, addedRoutes,
- deletedRoutes.values());
+ bgpRouteSelector.routeUpdates(bgpSession,
+ decodedBgpRoutes.addedUnicastRoutes4.values(),
+ decodedBgpRoutes.deletedUnicastRoutes4.values());
+ bgpRouteSelector.routeUpdates(bgpSession,
+ decodedBgpRoutes.addedUnicastRoutes6.values(),
+ decodedBgpRoutes.deletedUnicastRoutes6.values());
// Start the Session Timeout timer
bgpSession.restartSessionTimeoutTimer(ctx);
@@ -155,27 +181,34 @@
* @param bgpSession the BGP Session to use
* @param ctx the Channel Handler Context
* @param message the message to parse
- * @return a collection of the result BGP Route Entries
+ * @param decodedBgpRoutes the container to store the decoded BGP Route
+ * Entries. It might already contain some route entries such as withdrawn
+ * IPv4 prefixes
* @throws BgpParseException
*/
- private static Collection<BgpRouteEntry> parsePathAttributes(
- BgpSession bgpSession,
- ChannelHandlerContext ctx,
- ChannelBuffer message)
+ // CHECKSTYLE IGNORE MethodLength FOR NEXT 300 LINES
+ private static void parsePathAttributes(
+ BgpSession bgpSession,
+ ChannelHandlerContext ctx,
+ ChannelBuffer message,
+ DecodedBgpRoutes decodedBgpRoutes)
throws BgpParseException {
- Map<Ip4Prefix, BgpRouteEntry> addedRoutes = new HashMap<>();
//
// Parsed values
//
Short origin = -1; // Mandatory
BgpRouteEntry.AsPath asPath = null; // Mandatory
- Ip4Address nextHop = null; // Mandatory
+ // Legacy NLRI (RFC 4271). Mandatory NEXT_HOP if legacy NLRI is used
+ MpNlri legacyNlri = new MpNlri(MultiprotocolExtensions.AFI_IPV4,
+ MultiprotocolExtensions.SAFI_UNICAST);
long multiExitDisc = // Optional
- BgpConstants.Update.MultiExitDisc.LOWEST_MULTI_EXIT_DISC;
+ Update.MultiExitDisc.LOWEST_MULTI_EXIT_DISC;
Long localPref = null; // Mandatory
Long aggregatorAsNumber = null; // Optional: unused
Ip4Address aggregatorIpAddress = null; // Optional: unused
+ Collection<MpNlri> mpNlriReachList = new ArrayList<>(); // Optional
+ Collection<MpNlri> mpNlriUnreachList = new ArrayList<>(); // Optional
//
// Get and verify the Path Attributes Length
@@ -188,7 +221,7 @@
throw new BgpParseException(errorMsg);
}
if (pathAttributeLength == 0) {
- return addedRoutes.values();
+ return;
}
//
@@ -244,28 +277,29 @@
//
switch (attrTypeCode) {
- case BgpConstants.Update.Origin.TYPE:
+ case Update.Origin.TYPE:
// Attribute Type Code ORIGIN
origin = parseAttributeTypeOrigin(bgpSession, ctx,
attrTypeCode, attrLen,
attrFlags, message);
break;
- case BgpConstants.Update.AsPath.TYPE:
+ case Update.AsPath.TYPE:
// Attribute Type Code AS_PATH
asPath = parseAttributeTypeAsPath(bgpSession, ctx,
attrTypeCode, attrLen,
attrFlags, message);
break;
- case BgpConstants.Update.NextHop.TYPE:
+ case Update.NextHop.TYPE:
// Attribute Type Code NEXT_HOP
- nextHop = parseAttributeTypeNextHop(bgpSession, ctx,
- attrTypeCode, attrLen,
- attrFlags, message);
+ legacyNlri.nextHop4 =
+ parseAttributeTypeNextHop(bgpSession, ctx,
+ attrTypeCode, attrLen,
+ attrFlags, message);
break;
- case BgpConstants.Update.MultiExitDisc.TYPE:
+ case Update.MultiExitDisc.TYPE:
// Attribute Type Code MULTI_EXIT_DISC
multiExitDisc =
parseAttributeTypeMultiExitDisc(bgpSession, ctx,
@@ -273,7 +307,7 @@
attrFlags, message);
break;
- case BgpConstants.Update.LocalPref.TYPE:
+ case Update.LocalPref.TYPE:
// Attribute Type Code LOCAL_PREF
localPref =
parseAttributeTypeLocalPref(bgpSession, ctx,
@@ -281,7 +315,7 @@
attrFlags, message);
break;
- case BgpConstants.Update.AtomicAggregate.TYPE:
+ case Update.AtomicAggregate.TYPE:
// Attribute Type Code ATOMIC_AGGREGATE
parseAttributeTypeAtomicAggregate(bgpSession, ctx,
attrTypeCode, attrLen,
@@ -289,7 +323,7 @@
// Nothing to do: this attribute is primarily informational
break;
- case BgpConstants.Update.Aggregator.TYPE:
+ case Update.Aggregator.TYPE:
// Attribute Type Code AGGREGATOR
Pair<Long, Ip4Address> aggregator =
parseAttributeTypeAggregator(bgpSession, ctx,
@@ -299,6 +333,29 @@
aggregatorIpAddress = aggregator.getRight();
break;
+ case Update.MpReachNlri.TYPE:
+ // Attribute Type Code MP_REACH_NLRI
+ MpNlri mpNlriReach =
+ parseAttributeTypeMpReachNlri(bgpSession, ctx,
+ attrTypeCode,
+ attrLen,
+ attrFlags, message);
+ if (mpNlriReach != null) {
+ mpNlriReachList.add(mpNlriReach);
+ }
+ break;
+
+ case Update.MpUnreachNlri.TYPE:
+ // Attribute Type Code MP_UNREACH_NLRI
+ MpNlri mpNlriUnreach =
+ parseAttributeTypeMpUnreachNlri(bgpSession, ctx,
+ attrTypeCode, attrLen,
+ attrFlags, message);
+ if (mpNlriUnreach != null) {
+ mpNlriUnreachList.add(mpNlriUnreach);
+ }
+ break;
+
default:
// NOTE: Parse any new Attribute Types if needed
if (!optionalBit) {
@@ -320,17 +377,15 @@
}
}
- // Verify the Well-known Attributes
- verifyBgpUpdateWellKnownAttributes(bgpSession, ctx, origin, asPath,
- nextHop, localPref);
-
//
// Parse the NLRI (Network Layer Reachability Information)
//
- Collection<Ip4Prefix> addedPrefixes = null;
int nlriLength = message.readableBytes();
try {
- addedPrefixes = parsePackedPrefixes(nlriLength, message);
+ Collection<Ip4Prefix> addedPrefixes4 =
+ parsePackedIp4Prefixes(nlriLength, message);
+ // Store it inside the legacy NLRI wrapper
+ legacyNlri.nlri4 = addedPrefixes4;
} catch (BgpParseException e) {
// ERROR: Invalid Network Field
log.debug("Exception parsing NLRI from BGP peer {}: ",
@@ -340,25 +395,92 @@
throw e;
}
- // Generate the added routes
- for (Ip4Prefix prefix : addedPrefixes) {
- BgpRouteEntry bgpRouteEntry =
- new BgpRouteEntry(bgpSession, prefix, nextHop,
- origin.byteValue(), asPath, localPref);
- bgpRouteEntry.setMultiExitDisc(multiExitDisc);
- if (bgpRouteEntry.hasAsPathLoop(bgpSession.getLocalAs())) {
- log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
- "nextHop {}: contains AS Path loop",
- bgpSession.getRemoteAddress(), prefix, nextHop);
- continue;
- } else {
- log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
- bgpSession.getRemoteAddress(), prefix, nextHop);
+ // Verify the Well-known Attributes
+ verifyBgpUpdateWellKnownAttributes(bgpSession, ctx, origin, asPath,
+ localPref, legacyNlri,
+ mpNlriReachList);
+
+ //
+ // Generate the deleted routes
+ //
+ for (MpNlri mpNlri : mpNlriUnreachList) {
+ BgpRouteEntry bgpRouteEntry;
+
+ // The deleted IPv4 routes
+ for (Ip4Prefix prefix : mpNlri.nlri4) {
+ bgpRouteEntry = bgpSession.bgpRibIn4().get(prefix);
+ if (bgpRouteEntry != null) {
+ decodedBgpRoutes.deletedUnicastRoutes4.put(prefix,
+ bgpRouteEntry);
+ }
}
- addedRoutes.put(prefix, bgpRouteEntry);
+
+ // The deleted IPv6 routes
+ for (Ip6Prefix prefix : mpNlri.nlri6) {
+ bgpRouteEntry = bgpSession.bgpRibIn6().get(prefix);
+ if (bgpRouteEntry != null) {
+ decodedBgpRoutes.deletedUnicastRoutes6.put(prefix,
+ bgpRouteEntry);
+ }
+ }
}
- return addedRoutes.values();
+ //
+ // Generate the added routes
+ //
+ mpNlriReachList.add(legacyNlri);
+ for (MpNlri mpNlri : mpNlriReachList) {
+ BgpRouteEntry bgpRouteEntry;
+
+ // The added IPv4 routes
+ for (Ip4Prefix prefix : mpNlri.nlri4) {
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession, prefix, mpNlri.nextHop4,
+ origin.byteValue(), asPath, localPref);
+ bgpRouteEntry.setMultiExitDisc(multiExitDisc);
+ if (bgpRouteEntry.hasAsPathLoop(bgpSession.getLocalAs())) {
+ log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
+ "nextHop {}: contains AS Path loop",
+ bgpSession.getRemoteAddress(), prefix,
+ mpNlri.nextHop4);
+ continue;
+ } else {
+ log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
+ bgpSession.getRemoteAddress(), prefix,
+ mpNlri.nextHop4);
+ }
+ // Remove from the collection of deleted routes
+ decodedBgpRoutes.deletedUnicastRoutes4.remove(prefix);
+ decodedBgpRoutes.addedUnicastRoutes4.put(prefix,
+ bgpRouteEntry);
+ }
+
+ // The added IPv6 routes
+ // TODO: fix/enable for IPv6
+ /*
+ for (Ip6Prefix prefix : mpNlri.nlri6) {
+ bgpRouteEntry =
+ new BgpRouteEntry(bgpSession, prefix, mpNlri.nextHop6,
+ origin.byteValue(), asPath, localPref);
+ bgpRouteEntry.setMultiExitDisc(multiExitDisc);
+ if (bgpRouteEntry.hasAsPathLoop(bgpSession.getLocalAs())) {
+ log.debug("BGP RX UPDATE message IGNORED from {}: {} " +
+ "nextHop {}: contains AS Path loop",
+ bgpSession.getRemoteAddress(), prefix,
+ mpNlri.nextHop6);
+ continue;
+ } else {
+ log.debug("BGP RX UPDATE message ADDED from {}: {} nextHop {}",
+ bgpSession.getRemoteAddress(), prefix,
+ mpNlri.nextHop6);
+ }
+ // Remove from the collection of deleted routes
+ decodedBgpRoutes.deletedUnicastRoutes6.remove(prefix);
+ decodedBgpRoutes.addedUnicastRoutes6.put(prefix,
+ bgpRouteEntry);
+ }
+ */
+ }
}
/**
@@ -368,8 +490,10 @@
* @param ctx the Channel Handler Context
* @param origin the ORIGIN well-known mandatory attribute
* @param asPath the AS_PATH well-known mandatory attribute
- * @param nextHop the NEXT_HOP well-known mandatory attribute
* @param localPref the LOCAL_PREF required attribute
+ * @param legacyNlri the legacy NLRI. Encapsulates the NEXT_HOP well-known
+ * mandatory attribute (mandatory if legacy NLRI is used).
+ * @param mpNlriReachList the Multiprotocol NLRI attributes
* @throws BgpParseException
*/
private static void verifyBgpUpdateWellKnownAttributes(
@@ -377,41 +501,65 @@
ChannelHandlerContext ctx,
Short origin,
BgpRouteEntry.AsPath asPath,
- Ip4Address nextHop,
- Long localPref)
+ Long localPref,
+ MpNlri legacyNlri,
+ Collection<MpNlri> mpNlriReachList)
throws BgpParseException {
+ boolean hasNlri = false;
+ boolean hasLegacyNlri = false;
+
+ //
+ // Convenience flags that are used to check for missing attributes.
+ //
+ // NOTE: The hasLegacyNlri flag is always set to true if the
+ // Multiprotocol Extensions are not enabled, even if the UPDATE
+ // message doesn't contain the legacy NLRI (per RFC 4271).
+ //
+ if (!bgpSession.getMpExtensions()) {
+ hasNlri = true;
+ hasLegacyNlri = true;
+ } else {
+ if (!legacyNlri.nlri4.isEmpty()) {
+ hasNlri = true;
+ hasLegacyNlri = true;
+ }
+ if (!mpNlriReachList.isEmpty()) {
+ hasNlri = true;
+ }
+ }
+
//
// Check for Missing Well-known Attributes
//
- if ((origin == null) || (origin == -1)) {
+ if (hasNlri && ((origin == null) || (origin == -1))) {
// Missing Attribute Type Code ORIGIN
- int type = BgpConstants.Update.Origin.TYPE;
+ int type = Update.Origin.TYPE;
actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
String errorMsg = "Missing Well-known Attribute: ORIGIN";
throw new BgpParseException(errorMsg);
}
- if (asPath == null) {
+ if (hasNlri && (asPath == null)) {
// Missing Attribute Type Code AS_PATH
- int type = BgpConstants.Update.AsPath.TYPE;
+ int type = Update.AsPath.TYPE;
actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
String errorMsg = "Missing Well-known Attribute: AS_PATH";
throw new BgpParseException(errorMsg);
}
- if (nextHop == null) {
- // Missing Attribute Type Code NEXT_HOP
- int type = BgpConstants.Update.NextHop.TYPE;
- actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
- String errorMsg = "Missing Well-known Attribute: NEXT_HOP";
- throw new BgpParseException(errorMsg);
- }
- if (localPref == null) {
+ if (hasNlri && (localPref == null)) {
// Missing Attribute Type Code LOCAL_PREF
// NOTE: Required for iBGP
- int type = BgpConstants.Update.LocalPref.TYPE;
+ int type = Update.LocalPref.TYPE;
actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
String errorMsg = "Missing Well-known Attribute: LOCAL_PREF";
throw new BgpParseException(errorMsg);
}
+ if (hasLegacyNlri && (legacyNlri.nextHop4 == null)) {
+ // Missing Attribute Type Code NEXT_HOP
+ int type = Update.NextHop.TYPE;
+ actionsBgpUpdateMissingWellKnownAttribute(bgpSession, ctx, type);
+ String errorMsg = "Missing Well-known Attribute: NEXT_HOP";
+ throw new BgpParseException(errorMsg);
+ }
}
/**
@@ -440,34 +588,42 @@
String typeName = "UNKNOWN";
boolean isWellKnown = false;
switch (attrTypeCode) {
- case BgpConstants.Update.Origin.TYPE:
+ case Update.Origin.TYPE:
isWellKnown = true;
typeName = "ORIGIN";
break;
- case BgpConstants.Update.AsPath.TYPE:
+ case Update.AsPath.TYPE:
isWellKnown = true;
typeName = "AS_PATH";
break;
- case BgpConstants.Update.NextHop.TYPE:
+ case Update.NextHop.TYPE:
isWellKnown = true;
typeName = "NEXT_HOP";
break;
- case BgpConstants.Update.MultiExitDisc.TYPE:
+ case Update.MultiExitDisc.TYPE:
isWellKnown = false;
typeName = "MULTI_EXIT_DISC";
break;
- case BgpConstants.Update.LocalPref.TYPE:
+ case Update.LocalPref.TYPE:
isWellKnown = true;
typeName = "LOCAL_PREF";
break;
- case BgpConstants.Update.AtomicAggregate.TYPE:
+ case Update.AtomicAggregate.TYPE:
isWellKnown = true;
typeName = "ATOMIC_AGGREGATE";
break;
- case BgpConstants.Update.Aggregator.TYPE:
+ case Update.Aggregator.TYPE:
isWellKnown = false;
typeName = "AGGREGATOR";
break;
+ case Update.MpReachNlri.TYPE:
+ isWellKnown = false;
+ typeName = "MP_REACH_NLRI";
+ break;
+ case Update.MpUnreachNlri.TYPE:
+ isWellKnown = false;
+ typeName = "MP_UNREACH_NLRI";
+ break;
default:
isWellKnown = false;
typeName = "UNKNOWN(" + attrTypeCode + ")";
@@ -521,7 +677,7 @@
throws BgpParseException {
// Check the Attribute Length
- if (attrLen != BgpConstants.Update.Origin.LENGTH) {
+ if (attrLen != Update.Origin.LENGTH) {
// ERROR: Attribute Length Error
actionsBgpUpdateAttributeLengthError(
bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
@@ -532,11 +688,11 @@
message.markReaderIndex();
short origin = message.readUnsignedByte();
switch (origin) {
- case BgpConstants.Update.Origin.IGP:
+ case Update.Origin.IGP:
// FALLTHROUGH
- case BgpConstants.Update.Origin.EGP:
+ case Update.Origin.EGP:
// FALLTHROUGH
- case BgpConstants.Update.Origin.INCOMPLETE:
+ case Update.Origin.INCOMPLETE:
break;
default:
// ERROR: Invalid ORIGIN Attribute
@@ -590,13 +746,13 @@
// Verify the Path Segment Type
switch (pathSegmentType) {
- case BgpConstants.Update.AsPath.AS_SET:
+ case Update.AsPath.AS_SET:
// FALLTHROUGH
- case BgpConstants.Update.AsPath.AS_SEQUENCE:
+ case Update.AsPath.AS_SEQUENCE:
// FALLTHROUGH
- case BgpConstants.Update.AsPath.AS_CONFED_SEQUENCE:
+ case Update.AsPath.AS_CONFED_SEQUENCE:
// FALLTHROUGH
- case BgpConstants.Update.AsPath.AS_CONFED_SET:
+ case Update.AsPath.AS_CONFED_SET:
break;
default:
// ERROR: Invalid Path Segment Type
@@ -669,7 +825,7 @@
throws BgpParseException {
// Check the Attribute Length
- if (attrLen != BgpConstants.Update.NextHop.LENGTH) {
+ if (attrLen != Update.NextHop.LENGTH) {
// ERROR: Attribute Length Error
actionsBgpUpdateAttributeLengthError(
bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
@@ -725,7 +881,7 @@
throws BgpParseException {
// Check the Attribute Length
- if (attrLen != BgpConstants.Update.MultiExitDisc.LENGTH) {
+ if (attrLen != Update.MultiExitDisc.LENGTH) {
// ERROR: Attribute Length Error
actionsBgpUpdateAttributeLengthError(
bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
@@ -759,7 +915,7 @@
throws BgpParseException {
// Check the Attribute Length
- if (attrLen != BgpConstants.Update.LocalPref.LENGTH) {
+ if (attrLen != Update.LocalPref.LENGTH) {
// ERROR: Attribute Length Error
actionsBgpUpdateAttributeLengthError(
bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
@@ -792,7 +948,7 @@
throws BgpParseException {
// Check the Attribute Length
- if (attrLen != BgpConstants.Update.AtomicAggregate.LENGTH) {
+ if (attrLen != Update.AtomicAggregate.LENGTH) {
// ERROR: Attribute Length Error
actionsBgpUpdateAttributeLengthError(
bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
@@ -825,7 +981,7 @@
throws BgpParseException {
// Check the Attribute Length
- if (attrLen != BgpConstants.Update.Aggregator.LENGTH) {
+ if (attrLen != Update.Aggregator.LENGTH) {
// ERROR: Attribute Length Error
actionsBgpUpdateAttributeLengthError(
bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
@@ -845,6 +1001,214 @@
}
/**
+ * Parses BGP UPDATE Attribute Type MP_REACH_NLRI.
+ *
+ * @param bgpSession the BGP Session to use
+ * @param ctx the Channel Handler Context
+ * @param attrTypeCode the attribute type code
+ * @param attrLen the attribute length (in octets)
+ * @param attrFlags the attribute flags
+ * @param message the message to parse
+ * @return the parsed MP_REACH_NLRI information if recognized, otherwise
+ * null
+ * @throws BgpParseException
+ */
+ private static MpNlri parseAttributeTypeMpReachNlri(
+ BgpSession bgpSession,
+ ChannelHandlerContext ctx,
+ int attrTypeCode,
+ int attrLen,
+ int attrFlags,
+ ChannelBuffer message)
+ throws BgpParseException {
+ int attributeEnd = message.readerIndex() + attrLen;
+
+ // Check the Attribute Length
+ if (attrLen < Update.MpReachNlri.MIN_LENGTH) {
+ // ERROR: Attribute Length Error
+ actionsBgpUpdateAttributeLengthError(
+ bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
+ String errorMsg = "Attribute Length Error";
+ throw new BgpParseException(errorMsg);
+ }
+
+ message.markReaderIndex();
+ int afi = message.readUnsignedShort();
+ int safi = message.readUnsignedByte();
+ int nextHopLen = message.readUnsignedByte();
+
+ //
+ // Verify the AFI/SAFI, and skip the attribute if not recognized.
+ // NOTE: Currently, we support only IPv4/IPv6 UNICAST
+ //
+ if (((afi != MultiprotocolExtensions.AFI_IPV4) &&
+ (afi != MultiprotocolExtensions.AFI_IPV6)) ||
+ (safi != MultiprotocolExtensions.SAFI_UNICAST)) {
+ // Skip the attribute
+ message.resetReaderIndex();
+ message.skipBytes(attrLen);
+ return null;
+ }
+
+ //
+ // Verify the next-hop length
+ //
+ int expectedNextHopLen = 0;
+ switch (afi) {
+ case MultiprotocolExtensions.AFI_IPV4:
+ expectedNextHopLen = Ip4Address.BYTE_LENGTH;
+ break;
+ case MultiprotocolExtensions.AFI_IPV6:
+ expectedNextHopLen = Ip6Address.BYTE_LENGTH;
+ break;
+ default:
+ // UNREACHABLE
+ break;
+ }
+ if (nextHopLen != expectedNextHopLen) {
+ // ERROR: Optional Attribute Error
+ message.resetReaderIndex();
+ actionsBgpUpdateOptionalAttributeError(
+ bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
+ String errorMsg = "Invalid next-hop network address length. " +
+ "Received " + nextHopLen + " expected " + expectedNextHopLen;
+ throw new BgpParseException(errorMsg);
+ }
+ // NOTE: We use "+ 1" to take into account the Reserved field (1 octet)
+ if (message.readerIndex() + nextHopLen + 1 >= attributeEnd) {
+ // ERROR: Optional Attribute Error
+ message.resetReaderIndex();
+ actionsBgpUpdateOptionalAttributeError(
+ bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
+ String errorMsg = "Malformed next-hop network address";
+ throw new BgpParseException(errorMsg);
+ }
+
+ //
+ // Get the Next-hop address, skip the Reserved field, and get the NLRI
+ //
+ byte[] nextHopBuffer = new byte[nextHopLen];
+ message.readBytes(nextHopBuffer, 0, nextHopLen);
+ int reserved = message.readUnsignedByte();
+ MpNlri mpNlri = new MpNlri(afi, safi);
+ try {
+ switch (afi) {
+ case MultiprotocolExtensions.AFI_IPV4:
+ // The next-hop address
+ mpNlri.nextHop4 = Ip4Address.valueOf(nextHopBuffer);
+ // The NLRI
+ mpNlri.nlri4 = parsePackedIp4Prefixes(
+ attributeEnd - message.readerIndex(),
+ message);
+ break;
+ case MultiprotocolExtensions.AFI_IPV6:
+ // The next-hop address
+ mpNlri.nextHop6 = Ip6Address.valueOf(nextHopBuffer);
+ // The NLRI
+ mpNlri.nlri6 = parsePackedIp6Prefixes(
+ attributeEnd - message.readerIndex(),
+ message);
+ break;
+ default:
+ // UNREACHABLE
+ break;
+ }
+ } catch (BgpParseException e) {
+ // ERROR: Optional Attribute Error
+ message.resetReaderIndex();
+ actionsBgpUpdateOptionalAttributeError(
+ bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
+ String errorMsg = "Malformed network layer reachability information";
+ throw new BgpParseException(errorMsg);
+ }
+
+ return mpNlri;
+ }
+
+ /**
+ * Parses BGP UPDATE Attribute Type MP_UNREACH_NLRI.
+ *
+ * @param bgpSession the BGP Session to use
+ * @param ctx the Channel Handler Context
+ * @param attrTypeCode the attribute type code
+ * @param attrLen the attribute length (in octets)
+ * @param attrFlags the attribute flags
+ * @param message the message to parse
+ * @return the parsed MP_UNREACH_NLRI information if recognized, otherwise
+ * null
+ * @throws BgpParseException
+ */
+ private static MpNlri parseAttributeTypeMpUnreachNlri(
+ BgpSession bgpSession,
+ ChannelHandlerContext ctx,
+ int attrTypeCode,
+ int attrLen,
+ int attrFlags,
+ ChannelBuffer message)
+ throws BgpParseException {
+ int attributeEnd = message.readerIndex() + attrLen;
+
+ // Check the Attribute Length
+ if (attrLen < Update.MpUnreachNlri.MIN_LENGTH) {
+ // ERROR: Attribute Length Error
+ actionsBgpUpdateAttributeLengthError(
+ bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
+ String errorMsg = "Attribute Length Error";
+ throw new BgpParseException(errorMsg);
+ }
+
+ message.markReaderIndex();
+ int afi = message.readUnsignedShort();
+ int safi = message.readUnsignedByte();
+
+ //
+ // Verify the AFI/SAFI, and skip the attribute if not recognized.
+ // NOTE: Currently, we support only IPv4/IPv6 UNICAST
+ //
+ if (((afi != MultiprotocolExtensions.AFI_IPV4) &&
+ (afi != MultiprotocolExtensions.AFI_IPV6)) ||
+ (safi != MultiprotocolExtensions.SAFI_UNICAST)) {
+ // Skip the attribute
+ message.resetReaderIndex();
+ message.skipBytes(attrLen);
+ return null;
+ }
+
+ //
+ // Get the Withdrawn Routes
+ //
+ MpNlri mpNlri = new MpNlri(afi, safi);
+ try {
+ switch (afi) {
+ case MultiprotocolExtensions.AFI_IPV4:
+ // The Withdrawn Routes
+ mpNlri.nlri4 = parsePackedIp4Prefixes(
+ attributeEnd - message.readerIndex(),
+ message);
+ break;
+ case MultiprotocolExtensions.AFI_IPV6:
+ // The Withdrawn Routes
+ mpNlri.nlri6 = parsePackedIp6Prefixes(
+ attributeEnd - message.readerIndex(),
+ message);
+ break;
+ default:
+ // UNREACHABLE
+ break;
+ }
+ } catch (BgpParseException e) {
+ // ERROR: Optional Attribute Error
+ message.resetReaderIndex();
+ actionsBgpUpdateOptionalAttributeError(
+ bgpSession, ctx, attrTypeCode, attrLen, attrFlags, message);
+ String errorMsg = "Malformed withdrawn routes";
+ throw new BgpParseException(errorMsg);
+ }
+
+ return mpNlri;
+ }
+
+ /**
* Parses a message that contains encoded IPv4 network prefixes.
* <p>
* The IPv4 prefixes are encoded in the form:
@@ -857,7 +1221,7 @@
* @return a collection of parsed IPv4 network prefixes
* @throws BgpParseException
*/
- private static Collection<Ip4Prefix> parsePackedPrefixes(
+ private static Collection<Ip4Prefix> parsePackedIp4Prefixes(
int totalLength,
ChannelBuffer message)
throws BgpParseException {
@@ -868,6 +1232,7 @@
}
// Parse the data
+ byte[] buffer = new byte[Ip4Address.BYTE_LENGTH];
int dataEnd = message.readerIndex() + totalLength;
while (message.readerIndex() < dataEnd) {
int prefixBitlen = message.readUnsignedByte();
@@ -877,17 +1242,52 @@
throw new BgpParseException(errorMsg);
}
- long address = 0;
- long extraShift = (4 - prefixBytelen) * 8;
- while (prefixBytelen > 0) {
- address <<= 8;
- address |= message.readUnsignedByte();
- prefixBytelen--;
+ message.readBytes(buffer, 0, prefixBytelen);
+ Ip4Prefix prefix = Ip4Prefix.valueOf(Ip4Address.valueOf(buffer),
+ prefixBitlen);
+ result.add(prefix);
+ }
+
+ return result;
+ }
+
+ /**
+ * Parses a message that contains encoded IPv6 network prefixes.
+ * <p>
+ * The IPv6 prefixes are encoded in the form:
+ * <Length, Prefix> where Length is the length in bits of the IPv6 prefix,
+ * and Prefix is the IPv6 prefix (padded with trailing bits to the end
+ * of an octet).
+ *
+ * @param totalLength the total length of the data to parse
+ * @param message the message with data to parse
+ * @return a collection of parsed IPv6 network prefixes
+ * @throws BgpParseException
+ */
+ private static Collection<Ip6Prefix> parsePackedIp6Prefixes(
+ int totalLength,
+ ChannelBuffer message)
+ throws BgpParseException {
+ Collection<Ip6Prefix> result = new ArrayList<>();
+
+ if (totalLength == 0) {
+ return result;
+ }
+
+ // Parse the data
+ byte[] buffer = new byte[Ip6Address.BYTE_LENGTH];
+ int dataEnd = message.readerIndex() + totalLength;
+ while (message.readerIndex() < dataEnd) {
+ int prefixBitlen = message.readUnsignedByte();
+ int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
+ if (message.readerIndex() + prefixBytelen > dataEnd) {
+ String errorMsg = "Malformed Network Prefixes";
+ throw new BgpParseException(errorMsg);
}
- address <<= extraShift;
- Ip4Prefix prefix =
- Ip4Prefix.valueOf(Ip4Address.valueOf((int) address),
- prefixBitlen);
+
+ message.readBytes(buffer, 0, prefixBytelen);
+ Ip6Prefix prefix = Ip6Prefix.valueOf(Ip6Address.valueOf(buffer),
+ prefixBitlen);
result.add(prefix);
}
@@ -1078,7 +1478,7 @@
bgpSession.getRemoteAddress(), nextHop);
//
- // ERROR: Invalid ORIGIN Attribute
+ // ERROR: Invalid NEXT_HOP Attribute
//
// Send NOTIFICATION and close the connection
int errorCode = UpdateMessageError.ERROR_CODE;
@@ -1135,6 +1535,45 @@
/**
* Applies the appropriate actions after detecting BGP UPDATE
+ * Optional Attribute Error: send NOTIFICATION and close
+ * the channel.
+ *
+ * @param bgpSession the BGP Session to use
+ * @param ctx the Channel Handler Context
+ * @param attrTypeCode the attribute type code
+ * @param attrLen the attribute length (in octets)
+ * @param attrFlags the attribute flags
+ * @param message the message with the data
+ */
+ private static void actionsBgpUpdateOptionalAttributeError(
+ BgpSession bgpSession,
+ ChannelHandlerContext ctx,
+ int attrTypeCode,
+ int attrLen,
+ int attrFlags,
+ ChannelBuffer message) {
+ log.debug("BGP RX UPDATE Error from {}: Optional Attribute Error: {}",
+ bgpSession.getRemoteAddress(), attrTypeCode);
+
+ //
+ // ERROR: Optional Attribute Error
+ //
+ // Send NOTIFICATION and close the connection
+ int errorCode = UpdateMessageError.ERROR_CODE;
+ int errorSubcode =
+ UpdateMessageError.OPTIONAL_ATTRIBUTE_ERROR;
+ ChannelBuffer data =
+ prepareBgpUpdateNotificationDataPayload(attrTypeCode, attrLen,
+ attrFlags, message);
+ ChannelBuffer txMessage =
+ BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
+ data);
+ ctx.getChannel().write(txMessage);
+ bgpSession.closeSession(ctx);
+ }
+
+ /**
+ * Applies the appropriate actions after detecting BGP UPDATE
* Attribute Length Error: send NOTIFICATION and close the channel.
*
* @param bgpSession the BGP Session to use
@@ -1227,4 +1666,42 @@
data.writeBytes(message, attrLen);
return data;
}
+
+ /**
+ * Helper class for storing Multiprotocol Network Layer Reachability
+ * information.
+ */
+ private static final class MpNlri {
+ private final int afi;
+ private final int safi;
+ private Ip4Address nextHop4;
+ private Ip6Address nextHop6;
+ private Collection<Ip4Prefix> nlri4 = new ArrayList<>();
+ private Collection<Ip6Prefix> nlri6 = new ArrayList<>();
+
+ /**
+ * Constructor.
+ *
+ * @param afi the Address Family Identifier
+ * @param safi the Subsequent Address Family Identifier
+ */
+ private MpNlri(int afi, int safi) {
+ this.afi = afi;
+ this.safi = safi;
+ }
+ }
+
+ /**
+ * Helper class for storing decoded BGP routing information.
+ */
+ private static final class DecodedBgpRoutes {
+ private final Map<Ip4Prefix, BgpRouteEntry> addedUnicastRoutes4 =
+ new HashMap<>();
+ private final Map<Ip6Prefix, BgpRouteEntry> addedUnicastRoutes6 =
+ new HashMap<>();
+ private final Map<Ip4Prefix, BgpRouteEntry> deletedUnicastRoutes4 =
+ new HashMap<>();
+ private final Map<Ip6Prefix, BgpRouteEntry> deletedUnicastRoutes6 =
+ new HashMap<>();
+ }
}
diff --git a/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/BgpRoutesListCommand.java b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/BgpRoutesListCommand.java
index d7b7cc7..56ad480 100644
--- a/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/BgpRoutesListCommand.java
+++ b/apps/sdnip/src/main/java/org/onosproject/sdnip/cli/BgpRoutesListCommand.java
@@ -81,7 +81,8 @@
// Print the routes
if (foundBgpSession != null) {
- printRoutes(foundBgpSession.bgpRibIn().values());
+ printRoutes(foundBgpSession.bgpRibIn4().values());
+ printRoutes(foundBgpSession.bgpRibIn6().values());
} else {
printRoutes(service.getBgpRoutes());
}
diff --git a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/BgpSessionManagerTest.java b/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/BgpSessionManagerTest.java
index 0eaaa22..a4e0bab 100644
--- a/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/BgpSessionManagerTest.java
+++ b/apps/sdnip/src/test/java/org/onosproject/sdnip/bgp/BgpSessionManagerTest.java
@@ -303,7 +303,7 @@
private Collection<BgpRouteEntry> waitForBgpRibIn(BgpSession bgpSession,
long expectedRoutes)
throws InterruptedException {
- Collection<BgpRouteEntry> bgpRibIn = bgpSession.bgpRibIn().values();
+ Collection<BgpRouteEntry> bgpRibIn = bgpSession.bgpRibIn4().values();
final int maxChecks = 500; // Max wait of 5 seconds
for (int i = 0; i < maxChecks; i++) {
@@ -311,7 +311,7 @@
break;
}
Thread.sleep(10);
- bgpRibIn = bgpSession.bgpRibIn().values();
+ bgpRibIn = bgpSession.bgpRibIn4().values();
}
return bgpRibIn;