diff --git a/src/main/java/org/javamrt/mrt/Attributes.java b/src/main/java/org/javamrt/mrt/Attributes.java index 9be360b..89485f9 100644 --- a/src/main/java/org/javamrt/mrt/Attributes.java +++ b/src/main/java/org/javamrt/mrt/Attributes.java @@ -251,15 +251,16 @@ private void decode(byte[] record, int attrLen, int attrBytes) case MRTConstants.LARGE_COMMUNITY: if (buffer.length > 0) { - Attribute largeCommunity = new LargeCommunity(buffer); - attributes.set(MRTConstants.ATTRIBUTE_LARGE_COMMUNITY, largeCommunity); + int numberLargeCommunities = len/12; //12 bytes per large community + Attribute largeCommunities = new LargeCommunities(buffer, numberLargeCommunities); + attributes.set(MRTConstants.ATTRIBUTE_LARGE_COMMUNITIES, largeCommunities); } break; default: // make sure to not overwrite other attributes in the Vector, // as index in the Vector is not the same as type value - if (type > MRTConstants.ATTRIBUTE_LARGE_COMMUNITY && type < MRTConstants.ATTRIBUTE_TOTAL) { + if (type > MRTConstants.ATTRIBUTE_LARGE_COMMUNITIES && type < MRTConstants.ATTRIBUTE_TOTAL) { final UnsupportedAttribute attribute = new UnsupportedAttribute(type, buffer); attributes.set(type, attribute); } else { @@ -318,9 +319,9 @@ public Community getCommunity() { return Community.empty(); } - public LargeCommunity getLargeCommunity() { - return (LargeCommunity) - attributes.elementAt(MRTConstants.ATTRIBUTE_LARGE_COMMUNITY); + public LargeCommunities getLargeCommunities() { + return (LargeCommunities) + attributes.elementAt(MRTConstants.ATTRIBUTE_LARGE_COMMUNITIES); } public Med getMed() { diff --git a/src/main/java/org/javamrt/mrt/LargeCommunities.java b/src/main/java/org/javamrt/mrt/LargeCommunities.java new file mode 100644 index 0000000..acc2224 --- /dev/null +++ b/src/main/java/org/javamrt/mrt/LargeCommunities.java @@ -0,0 +1,28 @@ +package org.javamrt.mrt; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class LargeCommunities implements Attribute { + private List largeCommunities; + + LargeCommunities(byte[] buffer, int numberOfCommunities) { + largeCommunities = new ArrayList<>(); + for (int i = 0; i < numberOfCommunities; i++) { + byte[] part = Arrays.copyOfRange(buffer, i * 12, (i + 1) * 12); + largeCommunities.add(new LargeCommunity(part)); + } + } + + List getLargeCommunities() { + return largeCommunities; + } + + @Override + public String toString() { + return "[" + largeCommunities.stream().map(LargeCommunity::toString) + .collect(Collectors.joining(", ")) + "]"; + } +} diff --git a/src/main/java/org/javamrt/mrt/LargeCommunity.java b/src/main/java/org/javamrt/mrt/LargeCommunity.java index 8c05696..f196eef 100644 --- a/src/main/java/org/javamrt/mrt/LargeCommunity.java +++ b/src/main/java/org/javamrt/mrt/LargeCommunity.java @@ -8,7 +8,7 @@ import org.javamrt.utils.RecordAccess; -public class LargeCommunity implements Attribute { +public class LargeCommunity { protected long globalAdministrator; protected long localData1; protected long localData2; diff --git a/src/main/java/org/javamrt/mrt/MRTConstants.java b/src/main/java/org/javamrt/mrt/MRTConstants.java index b557bf1..cd251a3 100644 --- a/src/main/java/org/javamrt/mrt/MRTConstants.java +++ b/src/main/java/org/javamrt/mrt/MRTConstants.java @@ -83,7 +83,7 @@ public static String asPathString(int type) { public static final int ATTRIBUTE_AS4_AGGREGATOR = 17; public static final int ATTRIBUTE_CONNECTOR = 20; public static final int ATTRIBUTE_ASPATHLIMIT = 21; - public static final int ATTRIBUTE_LARGE_COMMUNITY = 22; + public static final int ATTRIBUTE_LARGE_COMMUNITIES = 22; public static final int ATTRIBUTE_TOTAL = 256; public static final int AFI_IPv4 = 1; diff --git a/src/test/java/org/javamrt/mrt/LargeCommunitiesTest.java b/src/test/java/org/javamrt/mrt/LargeCommunitiesTest.java index 1221a9c..cdaf09c 100644 --- a/src/test/java/org/javamrt/mrt/LargeCommunitiesTest.java +++ b/src/test/java/org/javamrt/mrt/LargeCommunitiesTest.java @@ -7,13 +7,16 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.ArrayList; -import java.util.Base64; +import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.Base64; import java.util.stream.Collectors; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + public class LargeCommunitiesTest { @Test @@ -36,10 +39,14 @@ public void testParseDump() Bgp4Update bgp4update = (Bgp4Update) mrtRecord; Attributes attributes = bgp4update.getAttributes(); if (attributes != null) { - LargeCommunity largeCommunity = - attributes.getLargeCommunity(); - if (largeCommunity != null) { - largeCommunities.add(largeCommunity); + LargeCommunities communities = + attributes.getLargeCommunities(); + if (communities != null) { + for (LargeCommunity community : communities.getLargeCommunities()) { + if (community != null) { + largeCommunities.add(community); + } + } } } } @@ -73,4 +80,45 @@ public void should_parse_large_community_with_zero_length() throws Exception { assertEquals(mrtRecord.getClass(), Advertisement.class); assertEquals(mrtRecord.toString(), "BGP4MP|1602194848|A|91.206.52.130|58299|158.247.123.0/24|58299 6939 32261|IGP|91.206.52.130|0|0|58299:1000|NAG||"); } + + @Test + public void should_parse_multiple_large_communities() { + Exception exception = null; + Set foundCommunities = new HashSet<>(); + try (InputStream inputStream = getClass().getResourceAsStream("/updates.20260527.2305")) { + BGPFileReader bgpFileReader = + new BGPFileReader(new BufferedInputStream(inputStream)); + while (true) { + MRTRecord mrtRecord = bgpFileReader.readNext(); + if (mrtRecord == null) { + break; + } + if (mrtRecord instanceof Bgp4Update) { + Bgp4Update bgp4update = (Bgp4Update) mrtRecord; + Attributes attributes = bgp4update.getAttributes(); + if (attributes != null) { + LargeCommunities largeCommunity = attributes.getLargeCommunities(); + if (largeCommunity != null) { + for (LargeCommunity community : largeCommunity.getLargeCommunities()) { + if (community.globalAdministrator == 26162) { + foundCommunities.add(community.toString()); + } + } + } + } + } + } + } catch (Exception e) { + exception = e; + } + assertNull(exception); + assertTrue(foundCommunities.contains("26162:0:65071"), "community not found"); + assertTrue(foundCommunities.contains("26162:0:266416"), "community not found"); + assertTrue(foundCommunities.contains("26162:100:2"), "community not found"); + assertTrue(foundCommunities.contains("26162:200:2"), "community not found"); + assertTrue(foundCommunities.contains("26162:300:1"), "community not found"); + assertTrue(foundCommunities.contains("26162:660:1"), "community not found"); + assertTrue(foundCommunities.contains("26162:670:1"), "community not found"); + assertTrue(foundCommunities.contains("26162:680:2"), "community not found"); + } } diff --git a/src/test/resources/updates.20260527.2305 b/src/test/resources/updates.20260527.2305 new file mode 100644 index 0000000..54a464d Binary files /dev/null and b/src/test/resources/updates.20260527.2305 differ