--- /dev/null
+/*
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.protocol.bgp.parser;
+
+import static java.util.Objects.requireNonNull;
+
+import org.eclipse.jdt.annotation.NonNull;
+
+/**
+ * Abstract class supporting common aspects of {@link BGPDocumentedException} and {@link BGPTreatAsWithdrawException}.
+ */
+public abstract class AbstractBGPException extends Exception {
+ private static final long serialVersionUID = 1L;
+ private static final byte @NonNull [] EMPTY = new byte[0];
+
+ private final @NonNull BGPError error;
+ private final byte[] data;
+
+ /**
+ * Used when an error occurred that is described in an RFC or a draft.
+ *
+ * @param message message bound with this exception
+ * @param error specific documented error
+ * @param data data associated with the error
+ * @param cause cause for the error
+ */
+ AbstractBGPException(final String message, final BGPError error, final byte[] data, final Exception cause) {
+ super(message, cause);
+ this.error = requireNonNull(error);
+ this.data = data == null || data.length == 0 ? null : data.clone();
+ }
+
+ /**
+ * Returns specific documented error.
+ *
+ * @return documented error
+ */
+ public final BGPError getError() {
+ return error;
+ }
+
+ /**
+ * Returns data associated with this error.
+ *
+ * @return byte array data
+ */
+ public final byte @NonNull [] getData() {
+ return data != null ? data.clone() : EMPTY;
+ }
+}
* There are several errors documented in RFC4271 or in draft, that have specific meaning for the BGP.
* This exception is used, when any of those errors occurs.
*/
-public final class BGPDocumentedException extends Exception {
-
+public final class BGPDocumentedException extends AbstractBGPException {
private static final long serialVersionUID = -6212702584439430736L;
-
private static final Logger LOG = LoggerFactory.getLogger(BGPDocumentedException.class);
- private static final byte[] EMPTY = new byte[0];
-
- private final BGPError error;
-
- private final byte[] data;
-
/**
* Used when an error occurred that is described in an RFC or a draft.
*
*/
public BGPDocumentedException(final String message, final BGPError error, final byte[] data,
final Exception cause) {
- super(message, cause);
- this.error = error;
- this.data = data == null || data.length == 0 ? null : data.clone();
+ super(message, error, data, cause);
+ // FIXME: remove this error?
LOG.error("Error = {}", error, this);
}
/**
- * Returns specific documented error.
- *
- * @return documented error
- */
- public BGPError getError() {
- return error;
- }
-
- /**
- * Returns data associated with this error.
+ * Used when an error occurred that is described in an RFC or a draft.
*
- * @return byte array data
+ * @param cause cause for the error
*/
- public byte[] getData() {
- return data != null ? data.clone() : EMPTY;
+ public BGPDocumentedException(final BGPTreatAsWithdrawException cause) {
+ this(cause.getMessage(), cause.getError(), cause.getData(), cause);
}
public static BGPDocumentedException badMessageLength(final String message, final int length) {
*/
package org.opendaylight.protocol.bgp.parser;
-import static java.util.Objects.requireNonNull;
-
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
*
* @author Robert Varga
*/
-public final class BGPTreatAsWithdrawException extends Exception {
+public final class BGPTreatAsWithdrawException extends AbstractBGPException {
private static final long serialVersionUID = 1L;
- private final @NonNull BGPError error;
-
public BGPTreatAsWithdrawException(final @NonNull BGPError error, final @NonNull String format,
final Object... args) {
- this(error, null, format, args);
+ this(error, (Exception) null, format, args);
}
- public BGPTreatAsWithdrawException(final @NonNull BGPError error, @Nullable final Exception cause,
- final @NonNull String format, final Object... args) {
- super(String.format(format, args), cause);
- this.error = requireNonNull(error);
- }
-
- public @NonNull BGPError getError() {
- return error;
+ public BGPTreatAsWithdrawException(final @NonNull BGPError error, final byte[] data, final @NonNull String format,
+ final Object... args) {
+ super(String.format(format, args), error, data, null);
}
- // FIXME: remove this method, as it makes checkstyle unhappy
- public @NonNull BGPDocumentedException toDocumentedException() {
- return new BGPDocumentedException(getMessage(), error, this);
+ public BGPTreatAsWithdrawException(final @NonNull BGPError error, @Nullable final Exception cause,
+ final @NonNull String format, final Object... args) {
+ super(String.format(format, args), error, null, cause);
}
}
import org.opendaylight.protocol.bgp.parser.spi.ParsedAttributes;
import org.opendaylight.protocol.bgp.parser.spi.PathIdUtil;
import org.opendaylight.protocol.bgp.parser.spi.PeerSpecificParserConstraint;
+import org.opendaylight.protocol.bgp.parser.spi.RevisedErrorHandling;
import org.opendaylight.protocol.util.ByteBufWriteUtil;
import org.opendaylight.protocol.util.Ipv4Util;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
}
/**
- * Parse Update message from buffer.
- * Calls {@link #checkMandatoryAttributesPresence(Update)} to check for presence of mandatory attributes.
+ * Parse Update message from buffer. Calls {@link #checkMandatoryAttributesPresence(Update, RevisedErrorHandling)}
+ * to check for presence of mandatory attributes.
*
* @param buffer Encoded BGP message in ByteBuf
* @param messageLength Length of the BGP message
final UpdateBuilder builder = new UpdateBuilder();
final boolean isMultiPathSupported = MultiPathSupportUtil.isTableTypeSupported(constraint,
new BgpTableTypeImpl(Ipv4AddressFamily.class, UnicastSubsequentAddressFamily.class));
+ final RevisedErrorHandling errorHandling = RevisedErrorHandling.from(constraint);
final int withdrawnRoutesLength = buffer.readUnsignedShort();
if (withdrawnRoutesLength > 0) {
if (withdrawnRoutesLength == 0 && totalPathAttrLength == 0) {
return builder.build();
}
- final Optional<BGPTreatAsWithdrawException> withdrawCause;
+ Optional<BGPTreatAsWithdrawException> withdrawCauseOpt;
if (totalPathAttrLength > 0) {
final ParsedAttributes attributes = parseAttributes(buffer, totalPathAttrLength, constraint);
builder.setAttributes(attributes.getAttributes());
- withdrawCause = attributes.getWithdrawCause();
+ withdrawCauseOpt = attributes.getWithdrawCause();
} else {
- withdrawCause = Optional.empty();
+ withdrawCauseOpt = Optional.empty();
}
final List<Nlri> nlri = new ArrayList<>();
while (buffer.isReadable()) {
if (!nlri.isEmpty()) {
builder.setNlri(nlri);
}
+
+ try {
+ checkMandatoryAttributesPresence(builder.build(), errorHandling);
+ } catch (BGPTreatAsWithdrawException e) {
+ LOG.debug("Well-known mandatory attributes missing", e);
+ if (withdrawCauseOpt.isPresent()) {
+ final BGPTreatAsWithdrawException exception = withdrawCauseOpt.get();
+ exception.addSuppressed(e);
+ withdrawCauseOpt = Optional.of(exception);
+ } else {
+ withdrawCauseOpt = Optional.of(e);
+ }
+ }
+
Update msg = builder.build();
- checkMandatoryAttributesPresence(msg);
- if (withdrawCause.isPresent()) {
+ if (withdrawCauseOpt.isPresent()) {
// FIXME: BGPCEP-359: check if we can treat the message as withdraw and convert the message
- throw withdrawCause.get().toDocumentedException();
+ throw new BGPDocumentedException(withdrawCauseOpt.get());
}
LOG.debug("BGP Update message was parsed {}.", msg);
* Check for presence of well known mandatory path attributes ORIGIN, AS_PATH and NEXT_HOP in Update message.
*
* @param message Update message
+ * @param errorHandling Error handling type
*/
- private static void checkMandatoryAttributesPresence(final Update message) throws BGPDocumentedException {
+ private static void checkMandatoryAttributesPresence(final Update message,
+ final RevisedErrorHandling errorHandling) throws BGPDocumentedException, BGPTreatAsWithdrawException {
requireNonNull(message, "Update message cannot be null");
final Attributes attrs = message.getAttributes();
-
- if (message.getNlri() != null) {
- if (attrs == null || attrs.getCNextHop() == null) {
- throw new BGPDocumentedException(BGPError.MANDATORY_ATTR_MISSING_MSG + "NEXT_HOP",
- BGPError.WELL_KNOWN_ATTR_MISSING,
- new byte[] { NextHopAttributeParser.TYPE });
- }
+ if (message.getNlri() != null && (attrs == null || attrs.getCNextHop() == null)) {
+ throw reportMissingAttribute(errorHandling, "NEXT_HOP", NextHopAttributeParser.TYPE);
}
if (MessageUtil.isAnyNlriPresent(message)) {
if (attrs == null || attrs.getOrigin() == null) {
- throw new BGPDocumentedException(BGPError.MANDATORY_ATTR_MISSING_MSG + "ORIGIN",
- BGPError.WELL_KNOWN_ATTR_MISSING,
- new byte[] { OriginAttributeParser.TYPE });
+ throw reportMissingAttribute(errorHandling, "ORIGIN", OriginAttributeParser.TYPE);
}
-
if (attrs.getAsPath() == null) {
- throw new BGPDocumentedException(BGPError.MANDATORY_ATTR_MISSING_MSG + "AS_PATH",
- BGPError.WELL_KNOWN_ATTR_MISSING,
- new byte[] { AsPathAttributeParser.TYPE });
+ throw reportMissingAttribute(errorHandling, "AS_PATH", AsPathAttributeParser.TYPE);
}
}
}
+
+ private static BGPDocumentedException reportMissingAttribute(final RevisedErrorHandling errorHandling,
+ final String attrName, final int attrType) throws BGPDocumentedException, BGPTreatAsWithdrawException {
+ return errorHandling.reportError(BGPError.WELL_KNOWN_ATTR_MISSING, new byte[] { (byte) attrType },
+ "Well known mandatory attribute missing: %s", attrName);
+ }
}
*/
public BGPDocumentedException reportError(final BGPError error, final String format, final Object... args)
throws BGPDocumentedException, BGPTreatAsWithdrawException {
- throw reportError(error, null, format, args);
+ throw reportError(error, (Exception) null, format, args);
+ }
+
+ /**
+ * Report a failure to parse an attribute resulting either in treat-as-withdraw if RFC7606 is in effect, or
+ * connection teardown if it is not.
+ *
+ * @param error {@link BGPError} to report in case of a session teardown
+ * @param format Message format string
+ * @param args Message format arguments
+ * @return This method does not return
+ * @throws BGPTreatAsWithdrawException if Revised Error Handling is in effect
+ * @throws BGPDocumentedException if Revised Error Handling is in not effect
+ */
+ public BGPDocumentedException reportError(final BGPError error, final byte[] data, final String format,
+ final Object... args) throws BGPDocumentedException, BGPTreatAsWithdrawException {
+ throw new BGPTreatAsWithdrawException(error, data, format, args);
}
}