/* * 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.ospf.protocol.ospfpacket.types; import com.google.common.base.MoreObjects; import com.google.common.primitives.Bytes; import org.jboss.netty.buffer.ChannelBuffer; import org.onosproject.ospf.exceptions.OspfErrorType; import org.onosproject.ospf.exceptions.OspfParseException; import org.onosproject.ospf.protocol.lsa.LsaHeader; import org.onosproject.ospf.protocol.lsa.OpaqueLsaHeader; import org.onosproject.ospf.protocol.ospfpacket.OspfPacketHeader; import org.onosproject.ospf.controller.OspfPacketType; import org.onosproject.ospf.protocol.util.OspfParameters; import org.onosproject.ospf.protocol.util.OspfUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; /** * Representation of an OSPF Link State Acknowledgment Message. * Link State Acknowledgment Packets are OSPF packet type 5. * To make the flooding of LSAs reliable, flooded LSAs are explicitly * acknowledged. This acknowledgment is accomplished through the * sending and receiving of Link State Acknowledgment packets. * Multiple LSAs can be acknowledged in a single Link State Acknowledgment packet. */ public class LsAcknowledge extends OspfPacketHeader { /* 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Version # | 5 | Packet length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Router ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Area ID | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Checksum | AuType | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Authentication | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Authentication | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | +- -+ | | +- An LSA Header -+ | | +- -+ | | +- -+ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ... | */ private static final Logger log = LoggerFactory.getLogger(LsAcknowledge.class); private List<LsaHeader> linkStateHeaders = new ArrayList<>(); /** * Creates an instance of Link State Acknowledgment instance. */ public LsAcknowledge() { } /** * Creates an instance of Link State Acknowledgment instance. * * @param ospfHeader OSPF header instance. */ public LsAcknowledge(OspfPacketHeader ospfHeader) { populateHeader(ospfHeader); } /** * Gets ls headers. * * @return ls headers */ public List<LsaHeader> getLinkStateHeaders() { return linkStateHeaders; } /** * Adds link state header to list. * * @param lsaHeader LSA header */ public void addLinkStateHeader(LsaHeader lsaHeader) { if (!linkStateHeaders.contains(lsaHeader)) { linkStateHeaders.add(lsaHeader); } } @Override public OspfPacketType ospfMessageType() { return OspfPacketType.LSAACK; } @Override public void readFrom(ChannelBuffer channelBuffer) throws OspfParseException { try { //add all the LSA Headers - one header is of 20 bytes while (channelBuffer.readableBytes() >= OspfUtil.LSA_HEADER_LENGTH) { LsaHeader header = OspfUtil.readLsaHeader(channelBuffer); //add the LSAHeader to acknowledge addLinkStateHeader(header); } } catch (Exception e) { log.debug("Error::LsAckPacket:: {}", e.getMessage()); throw new OspfParseException(OspfErrorType.MESSAGE_HEADER_ERROR, OspfErrorType.BAD_MESSAGE_LENGTH); } } @Override public byte[] asBytes() { byte[] lsAckMessage = null; byte[] lsAckHeader = getLsAckAsByteArray(); byte[] lsAckBody = getLsAckBodyAsByteArray(); lsAckMessage = Bytes.concat(lsAckHeader, lsAckBody); return lsAckMessage; } /** * Gets LSAcknowledge as byte array. * * @return byte array */ public byte[] getLsAckAsByteArray() { List<Byte> headerLst = new ArrayList<>(); try { headerLst.add((byte) this.ospfVersion()); headerLst.add((byte) this.ospfType()); headerLst.addAll(Bytes.asList(OspfUtil.convertToTwoBytes(this.ospfPacLength()))); headerLst.addAll(Bytes.asList(this.routerId().toOctets())); headerLst.addAll(Bytes.asList(this.areaId().toOctets())); headerLst.addAll(Bytes.asList(OspfUtil.convertToTwoBytes(this.checksum()))); headerLst.addAll(Bytes.asList(OspfUtil.convertToTwoBytes(this.authType()))); //Authentication is 0 always. Total 8 bytes consist of zero byte[] auth = new byte[OspfUtil.EIGHT_BYTES]; headerLst.addAll(Bytes.asList(auth)); } catch (Exception e) { log.debug("Error::LsAckPacket:: {}", e.getMessage()); return Bytes.toArray(headerLst); } return Bytes.toArray(headerLst); } /** * Gets LsAck body as byte array. * * @return byte array */ public byte[] getLsAckBodyAsByteArray() { List<Byte> bodyLst = new ArrayList<>(); try { for (LsaHeader lsaHeader : linkStateHeaders) { if (lsaHeader.lsType() == OspfParameters.LINK_LOCAL_OPAQUE_LSA || lsaHeader.lsType() == OspfParameters.AREA_LOCAL_OPAQUE_LSA || lsaHeader.lsType() == OspfParameters.AS_OPAQUE_LSA) { OpaqueLsaHeader header = (OpaqueLsaHeader) lsaHeader; bodyLst.addAll(Bytes.asList(header.getOpaqueLsaHeaderAsByteArray())); } else { bodyLst.addAll(Bytes.asList(lsaHeader.getLsaHeaderAsByteArray())); } } } catch (Exception e) { log.debug("Error::getLsAckBodyAsByteArray {}", e.getMessage()); return Bytes.toArray(bodyLst); } return Bytes.toArray(bodyLst); } @Override public String toString() { return MoreObjects.toStringHelper(getClass()) .omitNullValues() .add("linkStateHeaders", linkStateHeaders) .toString(); } }