summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/lumaserv/bgp/BGPFsm.java21
-rw-r--r--src/main/java/com/lumaserv/bgp/BGPSession.java11
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/ASPathAttribute.java25
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/attribute/PathAttribute.java6
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/message/BGPOpen.java85
-rw-r--r--src/main/java/com/lumaserv/bgp/protocol/message/BGPUpdate.java5
6 files changed, 133 insertions, 20 deletions
diff --git a/src/main/java/com/lumaserv/bgp/BGPFsm.java b/src/main/java/com/lumaserv/bgp/BGPFsm.java
index 7929d36..9bfc30b 100644
--- a/src/main/java/com/lumaserv/bgp/BGPFsm.java
+++ b/src/main/java/com/lumaserv/bgp/BGPFsm.java
@@ -8,6 +8,7 @@ import lombok.Getter;
import lombok.Setter;
import java.io.IOException;
+import java.util.Optional;
import java.util.Timer;
import java.util.TimerTask;
@@ -277,7 +278,15 @@ public class BGPFsm {
@Override
void openMsg(BGPOpen msg) {
System.out.println("openMsg:" + msg);
- if(session.getConfiguration().getRemoteAs() == msg.getAsn()) {
+
+ Optional<BGPOpen.AS4Capability> as4Opt =
+ msg.getAS4Capability();
+ int remoteAsn = session.getConfiguration().getRemoteAs();
+ int openAsn = as4Opt.isPresent()
+ ? as4Opt.get().getAsn()
+ : msg.getAsn();
+
+ if(remoteAsn == openAsn) {
// - resets the DelayOpenTimer to zero,
// - sets the BGP ConnectRetryTimer to zero,
session.keepAlive();
@@ -290,8 +299,14 @@ public class BGPFsm {
setState(OPEN_CONFIRM);
} else {
System.out.println("Bad asn");
- // - sends a NOTIFICATION message with the appropriate error code,
- // - sets the ConnectRetryTimer to zero,
+ try {
+ BGPNotification notification = new BGPNotification()
+ .setMajorErrorCode(BGPNotification.Error.OPEN_MESSAGE_ERROR.getCode())
+ .setMinorErrorCode(BGPNotification.OpenMessageError.BAD_PEER_AS.getCode());
+ session.sendNotification(notification);
+ } catch (IOException ex) {
+ }
+ setConnectRetryTimer(0);
// - releases all BGP resources,
session.dropConnection();
connectRetryCounter++;
diff --git a/src/main/java/com/lumaserv/bgp/BGPSession.java b/src/main/java/com/lumaserv/bgp/BGPSession.java
index c6a8cd2..bb38ebf 100644
--- a/src/main/java/com/lumaserv/bgp/BGPSession.java
+++ b/src/main/java/com/lumaserv/bgp/BGPSession.java
@@ -29,6 +29,9 @@ public class BGPSession implements Runnable {
boolean outgoing;
BGPFsm fsm;
Thread thread;
+ boolean isAdvAS4Capability;
+ @Getter
+ boolean isAS4Capability;
public BGPSession(Socket socket, BGPSessionConfiguration configuration, BGPFsm fsm) throws IOException {
this.configuration = configuration;
@@ -75,10 +78,11 @@ public class BGPSession implements Runnable {
break;
case OPEN:
BGPOpen open = new BGPOpen(packet.getMessage());
+ isAS4Capability = isAdvAS4Capability && open.getAS4Capability().isPresent();
fsm.getCurrentState().openMsg(open);
break;
case UPDATE: {
- BGPUpdate update = new BGPUpdate(packet.getMessage());
+ BGPUpdate update = new BGPUpdate(this, packet.getMessage());
fsm.getCurrentState().updateMsg(update);
configuration.getListener().onUpdate(this, update);
break;
@@ -103,6 +107,7 @@ public class BGPSession implements Runnable {
}
void sendOpen(BGPOpen request) throws IOException {
+ isAdvAS4Capability = request.getAS4Capability().isPresent();
outputStream.write(new BGPPacket().setType(BGPPacket.Type.OPEN).setMessage(request.build()).build());
System.out.println("Sent open");
}
@@ -111,12 +116,14 @@ System.out.println("Sent open");
BGPOpen.Capabilities caps = new BGPOpen.Capabilities();
caps.getCapabilities().add(new BGPOpen.MultiprotocolExtensionCapability(AFI.IPV4.getValue(), SAFI.UNICAST.getValue()));
caps.getCapabilities().add(new BGPOpen.MultiprotocolExtensionCapability(AFI.IPV6.getValue(), SAFI.UNICAST.getValue()));
+ caps.getCapabilities().add(new BGPOpen.AS4Capability(configuration.getLocalAs()));
BGPOpen request = new BGPOpen()
- .setAsn(configuration.getLocalAs())
.setHoldTime(BGPFsm.CONFIG_HOLD_TIME)
.setVersion(BGPFsm.CONFIG_VERSION)
.setIdentifier(configuration.getLocalIdentifier());
+ if ((configuration.getLocalAs() & 0xFFFFFFFFL) < 0xFFFF)
+ request.setAsn(configuration.getLocalAs());
request.getOptionalParameters().add(caps);
sendOpen(request);
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/ASPathAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/ASPathAttribute.java
index 6405924..c4c6962 100644
--- a/src/main/java/com/lumaserv/bgp/protocol/attribute/ASPathAttribute.java
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/ASPathAttribute.java
@@ -1,5 +1,7 @@
package com.lumaserv.bgp.protocol.attribute;
+import com.lumaserv.bgp.BGPSession;
+
import lombok.Getter;
import lombok.Setter;
@@ -12,14 +14,27 @@ public class ASPathAttribute implements PathAttribute {
List<Segment> segments = new ArrayList<>();
- public ASPathAttribute(byte typeCode, byte[] data) {
+ public ASPathAttribute(BGPSession session, byte typeCode, byte[] data) {
+ final boolean isAS4 = session.isAS4Capability();
+ final int asnLen = isAS4 ? 4 : 2;
int offset = 0;
while (offset < data.length) {
Segment segment = new Segment().setType(data[offset]);
byte length = data[offset + 1];
- for(int i=0; i<length; i++)
- segment.asns.add(((data[offset + 2 + (i * 2)] & 0xFF) << 8) | (data[offset + 3 + (i * 2)] & 0xFF));
- offset += 2 + (length * 2);
+ for(int i=0; i<length; i++) {
+ int asn;
+ if (isAS4) {
+ asn = ((data[offset + 2 + (i * 4)] & 0xFF) << 24)
+ | ((data[offset + 3 + (i * 4)] & 0xFF) << 16)
+ | ((data[offset + 4 + (i * 4)] & 0xFF) << 8)
+ | (data[offset + 5 + (i * 4)] & 0xFF);
+ } else {
+ asn = (((data[offset + 2 + (i * 2)] & 0xFF) << 8)
+ | (data[offset + 3 + (i * 2)] & 0xFF));
+ }
+ segment.asns.add(asn);
+ }
+ offset += 2 + (length * asnLen);
segments.add(segment);
}
}
@@ -45,7 +60,7 @@ public class ASPathAttribute implements PathAttribute {
for(Integer asn : asns) {
if (buf.length() > 1)
buf.append(" ");
- buf.append(asn);
+ buf.append((long)asn & 0xFFFFFFFFL);
}
buf.append(")");
return buf.toString();
diff --git a/src/main/java/com/lumaserv/bgp/protocol/attribute/PathAttribute.java b/src/main/java/com/lumaserv/bgp/protocol/attribute/PathAttribute.java
index 1ba5ce4..06bbed5 100644
--- a/src/main/java/com/lumaserv/bgp/protocol/attribute/PathAttribute.java
+++ b/src/main/java/com/lumaserv/bgp/protocol/attribute/PathAttribute.java
@@ -1,16 +1,18 @@
package com.lumaserv.bgp.protocol.attribute;
+import com.lumaserv.bgp.BGPSession;
+
public interface PathAttribute {
byte getTypeCode();
byte[] build();
- static PathAttribute from(byte typeCode, byte[] data) {
+ static PathAttribute from(BGPSession session, byte typeCode, byte[] data) {
switch (typeCode & 0xFF) {
case 1:
return new OriginAttribute(typeCode, data);
case 2:
- return new ASPathAttribute(typeCode, data);
+ return new ASPathAttribute(session, typeCode, data);
case 3:
return new NextHopAttribute(typeCode, data);
case 6:
diff --git a/src/main/java/com/lumaserv/bgp/protocol/message/BGPOpen.java b/src/main/java/com/lumaserv/bgp/protocol/message/BGPOpen.java
index ae4e32a..4937e1b 100644
--- a/src/main/java/com/lumaserv/bgp/protocol/message/BGPOpen.java
+++ b/src/main/java/com/lumaserv/bgp/protocol/message/BGPOpen.java
@@ -7,7 +7,9 @@ import lombok.Setter;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.EnumSet;
import java.util.List;
+import java.util.Optional;
@Getter
@Setter
@@ -21,7 +23,7 @@ public class BGPOpen {
List<Parameter> optionalParameters = new ArrayList<>();
@Getter
- enum ParameterType {
+ public enum ParameterType {
CAPABILITIES(2);
byte type;
@@ -31,7 +33,7 @@ public class BGPOpen {
}
}
- interface Parameter {
+ public interface Parameter {
byte getType();
int getValue(byte[] dst, int offset);
}
@@ -77,6 +79,12 @@ public class BGPOpen {
return offset - first;
}
+ public Optional<Capability> getCapability(Capability.Code capabilityCode) {
+ return capabilities.stream()
+ .filter(c -> c.getCode() == capabilityCode.getCode())
+ .findAny();
+ }
+
Capabilities(byte[] src, int offset, int length) {
int first = offset;
while ((offset - first) < length) {
@@ -85,6 +93,8 @@ public class BGPOpen {
if (code == Capability.Code.MULTIPROTOCOL_EXTENSION.getCode()) {
capabilities.add(new MultiprotocolExtensionCapability(src, offset, capLength));
+ } else if (code == Capability.Code.AS4.getCode()) {
+ capabilities.add(new AS4Capability(src, offset, capLength));
} else {
byte[] value = new byte[capLength];
System.arraycopy(src, offset, value, 0, capLength);
@@ -112,16 +122,31 @@ public class BGPOpen {
}
}
- interface Capability {
+ public interface Capability {
@Getter
enum Code {
- MULTIPROTOCOL_EXTENSION(1);
+ MULTIPROTOCOL_EXTENSION(1),
+ ROUTE_REFRESH(2),
+ EXTENDED_NEXT_HOP(5),
+ GRACEFUL_RESTART(64),
+ AS4(65),
+ ENHANCED_ROUTE_REFRESH(70),
+ LONG_LIVED_GRACEFUL_RESTART(71);
byte code;
Code(int code) {
this.code = (byte)code;
}
+
+ public static Code fromInt(int code) {
+ return EnumSet
+ .allOf(Code.class)
+ .stream()
+ .filter(e -> e.getCode() == code)
+ .findAny()
+ .orElseThrow(() -> new IllegalArgumentException("unknown capability: " + code));
+ }
}
byte getCode();
@@ -142,7 +167,7 @@ public class BGPOpen {
@Override
public String toString() {
- return "Unknown{code=" + code + ", length=" + value.length + "}";
+ return "Unknown{code=" + Code.fromInt(code) + ", length=" + value.length + "}";
}
}
@@ -178,8 +203,41 @@ public class BGPOpen {
}
}
+ @AllArgsConstructor
+ @Getter
+ public static class AS4Capability implements Capability {
+ int asn;
+
+ @Override
+ public byte getCode() { return Capability.Code.AS4.getCode(); }
+
+ @Override
+ public int getValue(byte[] dst, int offset) {
+ dst[offset] = (byte)((asn >> 24) & 0xFF);
+ dst[offset + 1] = (byte)((asn >> 16) & 0xFF);
+ dst[offset + 2] = (byte)((asn >> 8) & 0xFF);
+ dst[offset + 3] = (byte)(asn & 0xFF);
+ return 4;
+ }
+
+ AS4Capability(byte[] src, int offset, int length) {
+ if (length != 4) {
+ throw new RuntimeException("Bad AS4Capability");
+ }
+
+ asn = ((src[offset] & 0xFF) << 24)
+ | ((src[offset + 1] & 0xFF) << 16)
+ | ((src[offset + 2] & 0xFF) << 8)
+ | (src[offset + 3] & 0xFF);
+ }
+
+ @Override
+ public String toString() {
+ return "as4: " + (asn & 0xFFFFFFFFL);
+ }
+ }
+
public BGPOpen(ByteBuffer message) {
-System.out.println("BGPOpen pos:" + message.position());
version = message.get();
asn = message.getShort() & 0xFFFF;
holdTime = message.getShort() & 0xFFFF;
@@ -210,6 +268,21 @@ System.out.println("BGPOpen pos:" + message.position());
this(ByteBuffer.wrap(message));
}
+ public Optional<Parameter> getOptionalParameter(ParameterType type) {
+ return optionalParameters.stream()
+ .filter(o -> o.getType() == type.getType())
+ .findAny();
+ }
+
+ public Optional<Capability> getCapability(Capability.Code capabilityCode) {
+ Capabilities caps = (Capabilities)getOptionalParameter(BGPOpen.ParameterType.CAPABILITIES).orElse(new Capabilities());
+ return caps.getCapability(capabilityCode);
+ }
+
+ public Optional<AS4Capability> getAS4Capability() {
+ return getCapability(Capability.Code.AS4).map(c -> (AS4Capability)c);
+ }
+
public byte[] build() {
ByteBuffer buf = ByteBuffer.allocate(256);
build(buf);
diff --git a/src/main/java/com/lumaserv/bgp/protocol/message/BGPUpdate.java b/src/main/java/com/lumaserv/bgp/protocol/message/BGPUpdate.java
index fa23432..f5af399 100644
--- a/src/main/java/com/lumaserv/bgp/protocol/message/BGPUpdate.java
+++ b/src/main/java/com/lumaserv/bgp/protocol/message/BGPUpdate.java
@@ -1,5 +1,6 @@
package com.lumaserv.bgp.protocol.message;
+import com.lumaserv.bgp.BGPSession;
import com.lumaserv.bgp.protocol.IPPrefix;
import com.lumaserv.bgp.protocol.attribute.PathAttribute;
import lombok.Getter;
@@ -16,7 +17,7 @@ public class BGPUpdate {
List<PathAttribute> attributes = new ArrayList<>();
List<IPPrefix> prefixes = new ArrayList<>();
- public BGPUpdate(byte[] message) {
+ public BGPUpdate(BGPSession session, byte[] message) {
int routesLength = ((message[0] & 0xFF) << 8) | (message[1] & 0xFF);
int offset = 2;
int offsetOffset = 2;
@@ -46,7 +47,7 @@ public class BGPUpdate {
byte[] data = new byte[length];
System.arraycopy(message, offset, data, 0, length);
offset += length;
- attributes.add(PathAttribute.from(typeCode, data));
+ attributes.add(PathAttribute.from(session, typeCode, data));
}
while (offset < message.length) {
IPPrefix prefix = new IPPrefix()