blob: 25827a00614e2996d60d3e480bd748a5d13e8f1d [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.lisp.msg.protocols;
import com.google.common.base.Objects;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.onosproject.lisp.msg.types.LispAfiAddress;
import org.onosproject.lisp.msg.authentication.LispAuthenticationFactory;
import org.onosproject.lisp.msg.authentication.LispAuthenticationKeyEnum;
import org.onosproject.lisp.msg.exceptions.LispParseError;
import org.onosproject.lisp.msg.exceptions.LispReaderException;
import org.onosproject.lisp.msg.exceptions.LispWriterException;
import org.onosproject.lisp.msg.types.LispLcafAddress.LcafAddressReader;
import org.onosproject.lisp.msg.types.LispLcafAddress.LcafAddressWriter;
import org.onosproject.lisp.msg.types.LispNatLcafAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import static com.google.common.base.MoreObjects.toStringHelper;
import static org.onosproject.lisp.msg.authentication.LispAuthenticationKeyEnum.valueOf;
/**
* Default LISP info reply message class.
*/
public final class DefaultLispInfoReply extends DefaultLispInfo implements LispInfoReply {
private static final Logger log = LoggerFactory.getLogger(DefaultLispInfoReply.class);
private final LispNatLcafAddress natLcafAddress;
static final InfoReplyWriter WRITER;
static {
WRITER = new InfoReplyWriter();
}
/**
* A private constructor that protects object instantiation from external.
*
* @param infoReply info reply flag
* @param nonce nonce
* @param keyId key identifier
* @param authDataLength authentication data length
* @param authData authentication data
* @param ttl Time-To-Live value
* @param maskLength EID prefix mask length
* @param eidPrefix EID prefix
* @param natLcafAddress NAT LCAF address
*/
protected DefaultLispInfoReply(boolean infoReply, long nonce, short keyId, short authDataLength,
byte[] authData, int ttl, byte maskLength,
LispAfiAddress eidPrefix, LispNatLcafAddress natLcafAddress) {
super(infoReply, nonce, keyId, authDataLength, authData, ttl, maskLength, eidPrefix);
this.natLcafAddress = natLcafAddress;
}
@Override
public LispNatLcafAddress getNatLcafAddress() {
return natLcafAddress;
}
@Override
public void writeTo(ByteBuf byteBuf) throws LispWriterException {
WRITER.writeTo(byteBuf, this);
}
@Override
public String toString() {
return toStringHelper(this)
.add("type", getType())
.add("nonce", nonce)
.add("keyId", keyId)
.add("authentication data length", authDataLength)
.add("authentication data", authData)
.add("TTL", ttl)
.add("EID mask length", maskLength)
.add("EID prefix", eidPrefix)
.add("NAT LCAF address", natLcafAddress).toString();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DefaultLispInfoReply that = (DefaultLispInfoReply) o;
return Objects.equal(nonce, that.nonce) &&
Objects.equal(keyId, that.keyId) &&
Objects.equal(authDataLength, that.authDataLength) &&
Arrays.equals(authData, that.authData) &&
Objects.equal(ttl, that.ttl) &&
Objects.equal(maskLength, that.maskLength) &&
Objects.equal(eidPrefix, that.eidPrefix) &&
Objects.equal(natLcafAddress, that.natLcafAddress);
}
@Override
public int hashCode() {
return Objects.hashCode(nonce, keyId, authDataLength, ttl, maskLength,
eidPrefix, natLcafAddress) + Arrays.hashCode(authData);
}
public static final class DefaultInfoReplyBuilder implements InfoReplyBuilder {
private boolean infoReply;
private long nonce;
private short keyId;
private short authDataLength;
private byte[] authData;
private String authKey;
private int ttl;
private byte maskLength;
private LispAfiAddress eidPrefix;
private LispNatLcafAddress natLcafAddress;
@Override
public LispType getType() {
return LispType.LISP_INFO;
}
@Override
public InfoReplyBuilder withIsInfoReply(boolean infoReply) {
this.infoReply = infoReply;
return this;
}
@Override
public InfoReplyBuilder withNonce(long nonce) {
this.nonce = nonce;
return this;
}
@Override
public InfoReplyBuilder withAuthDataLength(short authDataLength) {
this.authDataLength = authDataLength;
return this;
}
@Override
public InfoReplyBuilder withKeyId(short keyId) {
this.keyId = keyId;
return this;
}
@Override
public InfoReplyBuilder withAuthData(byte[] authenticationData) {
if (authenticationData != null) {
this.authData = authenticationData;
}
return this;
}
@Override
public InfoReplyBuilder withAuthKey(String key) {
this.authKey = key;
return this;
}
@Override
public InfoReplyBuilder withTtl(int ttl) {
this.ttl = ttl;
return this;
}
@Override
public InfoReplyBuilder withMaskLength(byte maskLength) {
this.maskLength = maskLength;
return this;
}
@Override
public InfoReplyBuilder withEidPrefix(LispAfiAddress eidPrefix) {
this.eidPrefix = eidPrefix;
return this;
}
@Override
public InfoReplyBuilder withNatLcafAddress(LispNatLcafAddress natLcafAddress) {
this.natLcafAddress = natLcafAddress;
return this;
}
@Override
public LispInfoReply build() {
// if authentication data is not specified, we will calculate it
if (authData == null) {
LispAuthenticationFactory factory = LispAuthenticationFactory.getInstance();
authDataLength = LispAuthenticationKeyEnum.valueOf(keyId).getHashLength();
byte[] tmpAuthData = new byte[authDataLength];
Arrays.fill(tmpAuthData, (byte) 0);
authData = tmpAuthData;
ByteBuf byteBuf = Unpooled.buffer();
try {
new DefaultLispInfoReply(infoReply, nonce, keyId, authDataLength,
authData, ttl, maskLength, eidPrefix, natLcafAddress).writeTo(byteBuf);
} catch (LispWriterException e) {
log.warn("Failed to serialize info reply", e);
}
byte[] bytes = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(bytes);
if (authKey == null) {
log.warn("Must specify authentication key");
}
authData = factory.createAuthenticationData(valueOf(keyId), authKey, bytes);
}
return new DefaultLispInfoReply(infoReply, nonce, keyId, authDataLength,
authData, ttl, maskLength, eidPrefix, natLcafAddress);
}
}
/**
* A LISP message reader for InfoReply message.
*/
public static final class InfoReplyReader implements LispMessageReader<LispInfoReply> {
@Override
public LispInfoReply readFrom(ByteBuf byteBuf) throws LispParseError, LispReaderException {
LispInfo lispInfo = deserialize(byteBuf);
LispNatLcafAddress natLcafAddress = (LispNatLcafAddress)
new LcafAddressReader().readFrom(byteBuf);
return new DefaultInfoReplyBuilder()
.withIsInfoReply(lispInfo.isInfoReply())
.withNonce(lispInfo.getNonce())
.withKeyId(lispInfo.getKeyId())
.withAuthDataLength(lispInfo.getAuthDataLength())
.withAuthData(lispInfo.getAuthData())
.withTtl(lispInfo.getTtl())
.withMaskLength(lispInfo.getMaskLength())
.withEidPrefix(lispInfo.getPrefix())
.withNatLcafAddress(natLcafAddress).build();
}
}
public static final class InfoReplyWriter implements LispMessageWriter<LispInfoReply> {
@Override
public void writeTo(ByteBuf byteBuf, LispInfoReply message) throws LispWriterException {
serialize(byteBuf, message);
new LcafAddressWriter().writeTo(byteBuf, message.getNatLcafAddress());
}
}
}