From 2dace9ee1047a897bc6c0f3d1a8b05301797bc99 Mon Sep 17 00:00:00 2001 From: Vishal Thapar Date: Fri, 11 Dec 2015 17:31:25 +0530 Subject: [PATCH] Add pkt handling to DHCPService Add flow to send DHCP pkts to controller Parse DHCP Pkt and respond based on NeutronPort and Subnet associated with the port. Add Neutron bundle Fix Javadoc style errors Change-Id: Iebbc279fc105e67b481c911e196a710409711ca8 Signed-off-by: Vishal Thapar --- dhcpservice/dhcpservice-api/pom.xml | 20 +- .../vpnservice/dhcpservice/api/DHCP.java | 578 +++++++++++++++++ .../dhcpservice/api/DHCPOptions.java | 225 +++++++ .../vpnservice/dhcpservice/DhcpInfo.java | 98 +++ .../vpnservice/dhcpservice/DhcpManager.java | 189 ++++++ .../dhcpservice/DhcpPktHandler.java | 494 ++++++++++++++- .../vpnservice/dhcpservice/DhcpProvider.java | 20 +- .../vpnservice/dhcpservice/NodeListener.java | 92 +++ .../impl/rev150710/DhcpServiceImplModule.java | 1 + features/pom.xml | 19 + features/src/main/features/features.xml | 12 +- .../vpnservice/mdsalutil/packet/ARP.java | 4 - .../vpnservice/mdsalutil/packet/Ethernet.java | 3 + .../vpnservice/mdsalutil/packet/ICMP.java | 248 ++++++++ .../mdsalutil/packet/IPProtocols.java | 300 +++++++++ .../vpnservice/mdsalutil/packet/IPv4.java | 595 ++++++++++++++++++ .../vpnservice/mdsalutil/packet/TCP.java | 245 ++++++++ .../vpnservice/mdsalutil/packet/UDP.java | 161 +++++ 18 files changed, 3287 insertions(+), 17 deletions(-) create mode 100644 dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCP.java create mode 100644 dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPOptions.java create mode 100644 dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInfo.java create mode 100644 dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpManager.java create mode 100644 dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/NodeListener.java create mode 100644 mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ICMP.java create mode 100644 mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IPProtocols.java create mode 100644 mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IPv4.java create mode 100644 mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/TCP.java create mode 100644 mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/UDP.java diff --git a/dhcpservice/dhcpservice-api/pom.xml b/dhcpservice/dhcpservice-api/pom.xml index f40230dc..e725c3d3 100644 --- a/dhcpservice/dhcpservice-api/pom.xml +++ b/dhcpservice/dhcpservice-api/pom.xml @@ -19,5 +19,23 @@ and is available at http://www.eclipse.org/legal/epl-v10.html dhcpservice-api ${vpnservices.version} bundle - + + + org.opendaylight.mdsal + yang-binding + + + org.opendaylight.mdsal.model + yang-ext + + + org.opendaylight.mdsal.model + iana-if-type-2014-05-08 + + + ${project.groupId} + mdsalutil-api + ${vpnservices.version} + + diff --git a/dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCP.java b/dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCP.java new file mode 100644 index 00000000..a2267711 --- /dev/null +++ b/dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCP.java @@ -0,0 +1,578 @@ +/* + * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. 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.vpnservice.dhcpservice.api; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.opendaylight.controller.liblldp.BitBufferHelper; +import org.opendaylight.controller.liblldp.BufferException; +import org.opendaylight.controller.liblldp.HexEncode; +import org.opendaylight.controller.liblldp.NetUtils; +import org.opendaylight.controller.liblldp.Packet; +import org.opendaylight.controller.liblldp.PacketException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.opendaylight.vpnservice.dhcpservice.api.DHCPConstants.*; + +public class DHCP extends Packet { + protected static final Logger logger = LoggerFactory + .getLogger(DHCP.class); + private static final String OP = "Op"; + private static final String HTYPE = "Htype"; + private static final String HLEN = "Hlen"; + private static final String HOPS = "Hops"; + private static final String XID = "Xid"; + private static final String SECS = "Secs"; + private static final String FLAGS = "Flags"; + private static final String CIADDR = "Ciaddr"; + private static final String YIADDR = "Yiaddr"; + private static final String SIADDR = "Siaddr"; + private static final String GIADDR = "Giaddr"; + private static final String CHADDR = "Chaddr"; + private static final String SNAME = "Sname"; + private static final String FILE = "File"; + private static final String MCOOKIE = "Mcookie"; + private static final String OPTIONS = "Options"; + private DHCPOptions dhcpOptions = null; + + private static Map> fieldCoordinates = new LinkedHashMap>() { + private static final long serialVersionUID = 1L; + { + put(OP, new ImmutablePair(0, 8)); + put(HTYPE, new ImmutablePair(8, 8)); + put(HLEN, new ImmutablePair(16, 8)); + put(HOPS, new ImmutablePair(24, 8)); + put(XID, new ImmutablePair(32, 32)); + put(SECS, new ImmutablePair(64, 16)); + put(FLAGS, new ImmutablePair(80, 16)); + put(CIADDR, new ImmutablePair(96, 32)); + put(YIADDR, new ImmutablePair(128, 32)); + put(SIADDR, new ImmutablePair(160, 32)); + put(GIADDR, new ImmutablePair(192, 32)); + put(CHADDR, new ImmutablePair(224, 128)); + put(SNAME, new ImmutablePair(352, 512)); + put(FILE, new ImmutablePair(864, 1024)); + put(MCOOKIE, new ImmutablePair(1888, 32)); + put(OPTIONS, new ImmutablePair(1920, 0)); + } + }; + + private final Map fieldValues; + + public DHCP() { + this(false); + } + + public DHCP(boolean writeAccess) { + super(writeAccess); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + corrupted = false; + + setOp(BOOTREPLY); + setHtype(HTYPE_ETHER); + setHlen((byte)6); + setHops((byte)0); + setXid(0); + setSecs((short) 0); + setFlags((short) 0); + setCiaddr(0); + setYiaddr(0); + setSiaddr(0); + setGiaddr(0); + setChaddr(new byte[16]); + setSname(new byte[64]); + setFile(new byte[128]); + setMcookie(MAGIC_COOKIE); + setOptions(new byte[0]); + this.dhcpOptions = new DHCPOptions(); + } + + //Getters + public byte getOp() { + return (BitBufferHelper.getByte(fieldValues.get(OP))); + } + + public byte getHtype() { + return (BitBufferHelper.getByte(fieldValues.get(HTYPE))); + } + + public byte getHlen() { + return (BitBufferHelper.getByte(fieldValues.get(HLEN))); + } + + public byte getHops() { + return (BitBufferHelper.getByte(fieldValues.get(HOPS))); + } + + public int getXid() { + return (BitBufferHelper.getInt(fieldValues.get(XID))); + } + + public short getSecs() { + return (BitBufferHelper.getShort(fieldValues.get(SECS))); + } + + public short getFlags() { + return (BitBufferHelper.getShort(fieldValues.get(FLAGS))); + } + + public byte[] getCiaddr() { + return fieldValues.get(CIADDR); + } + + public byte[] getYiaddr() { + return fieldValues.get(YIADDR); + } + + + public byte[] getSiaddr() { + return fieldValues.get(SIADDR); + } + + public InetAddress getSiaddrAsInetAddr() { + return DHCPUtils.byteArrayToInetAddr(fieldValues.get(SIADDR)); + } + + public byte[] getGiaddr() { + return fieldValues.get(GIADDR); + } + + public byte[] getChaddr() { + return fieldValues.get(CHADDR); + } + + public byte[] getSname() { + return fieldValues.get(SNAME); + } + + public byte[] getFile() { + return fieldValues.get(FILE); + } + + public int getMCookie() { + return (BitBufferHelper.getInt(fieldValues.get(MCOOKIE))); + } + + public byte[] getOptions() { + return fieldValues.get(OPTIONS); + } + +// TODO: +// public byte[] getPadding() { +// return this.pad; +// } + + // Setters + @Override + public void setHeaderField(String headerField, byte[] readValue) { + if (headerField.equals(OPTIONS) && + (readValue == null || readValue.length == 0)) { + hdrFieldsMap.remove(headerField); + return; + } + hdrFieldsMap.put(headerField, readValue); + } + + public DHCP setOp(byte dhcpOp) { + byte[] op = BitBufferHelper.toByteArray(dhcpOp); + fieldValues.put(OP, op); + return this; + } + + public DHCP setHtype(byte dhcpHtype) { + byte[] htype = BitBufferHelper.toByteArray(dhcpHtype); + fieldValues.put(HTYPE, htype); + return this; + } + + public DHCP setHlen(byte dhcpHlen) { + byte[] hlen = BitBufferHelper.toByteArray(dhcpHlen); + fieldValues.put(HLEN, hlen); + return this; + } + + public DHCP setHops(byte dhcpHops ) { + byte[] hops = BitBufferHelper.toByteArray(dhcpHops); + fieldValues.put(HOPS, hops); + return this; + } + + public DHCP setXid(int dhcpXid ) { + byte[] xid = BitBufferHelper.toByteArray(dhcpXid); + fieldValues.put(XID, xid); + return this; + } + + public DHCP setSecs(short dhcpSecs ) { + byte[] secs = BitBufferHelper.toByteArray(dhcpSecs); + fieldValues.put(SECS, secs); + return this; + } + + public DHCP setFlags(short dhcpFlags ) { + byte[] flags = BitBufferHelper.toByteArray(dhcpFlags); + fieldValues.put(FLAGS, flags); + return this; + } + + public DHCP setCiaddr(byte[] ciaddr) { + fieldValues.put(CIADDR, ciaddr); + return this; + } + + public DHCP setCiaddr(int dhcpCiaddr ) { + byte[] ciaddr = BitBufferHelper.toByteArray(dhcpCiaddr); + fieldValues.put(CIADDR, ciaddr); + return this; + } + + public DHCP setCiaddr(InetAddress dhcpCiaddr ) { + byte[] ciaddr = dhcpCiaddr.getAddress(); + fieldValues.put(CIADDR, ciaddr); + return this; + } + + public DHCP setCiaddr(String dhcpCiaddr) { + byte[] ciaddr = NetUtils.parseInetAddress(dhcpCiaddr).getAddress(); + fieldValues.put(CIADDR, ciaddr); + return this; + } + + public DHCP setYiaddr(byte[] yiaddr) { + fieldValues.put(YIADDR, yiaddr); + return this; + } + + public DHCP setYiaddr(int dhcpYiaddr ) { + byte[] yiaddr = BitBufferHelper.toByteArray(dhcpYiaddr); + fieldValues.put(YIADDR, yiaddr); + return this; + } + + public DHCP setYiaddr(InetAddress dhcpYiaddr ) { + byte[] yiaddr = dhcpYiaddr.getAddress(); + fieldValues.put(YIADDR, yiaddr); + return this; + } + + public DHCP setYiaddr(String dhcpYiaddr) { + byte[] yiaddr = NetUtils.parseInetAddress(dhcpYiaddr).getAddress(); + fieldValues.put(YIADDR, yiaddr); + return this; + } + + public DHCP setSiaddr(byte[] siaddr) { + fieldValues.put(SIADDR, siaddr); + return this; + } + + public DHCP setSiaddr(int dhcpSiaddr ) { + byte[] siaddr = BitBufferHelper.toByteArray(dhcpSiaddr); + fieldValues.put(SIADDR, siaddr); + return this; + } + + public DHCP setSiaddr(InetAddress dhcpSiaddr ) { + byte[] siaddr = dhcpSiaddr.getAddress(); + fieldValues.put(SIADDR, siaddr); + return this; + } + + public DHCP setSiaddr(String dhcpSiaddr) { + byte[] siaddr = NetUtils.parseInetAddress(dhcpSiaddr).getAddress(); + fieldValues.put(SIADDR, siaddr); + return this; + } + + public DHCP setGiaddr(byte[] giaddr) { + fieldValues.put(GIADDR, giaddr); + return this; + } + + public DHCP setGiaddr(int dhcpGiaddr ) { + byte[] giaddr = BitBufferHelper.toByteArray(dhcpGiaddr); + fieldValues.put(GIADDR, giaddr); + return this; + } + + public DHCP setGiaddr(InetAddress dhcpGiaddr ) { + byte[] giaddr = dhcpGiaddr.getAddress(); + fieldValues.put(GIADDR, giaddr); + return this; + } + + public DHCP setGiaddr(String dhcpGiaddr) { + byte[] giaddr = NetUtils.parseInetAddress(dhcpGiaddr).getAddress(); + fieldValues.put(GIADDR, giaddr); + return this; + } + + public DHCP setChaddr(byte[] chaddr) { + fieldValues.put(CHADDR, chaddr); + return this; + } + + public DHCP setSname(byte[] sname) { + fieldValues.put(SNAME, sname); + return this; + } + + public DHCP setFile(byte[] file) { + fieldValues.put(FILE, file); + return this; + } + + public DHCP setMcookie(int dhcpMc ) { + byte[] mc = BitBufferHelper.toByteArray(dhcpMc); + fieldValues.put(MCOOKIE, mc); + return this; + } + + public DHCP setOptions(byte[] options) { + fieldValues.put(OPTIONS, options); + return this; + } + +// public void setPadding(byte[] pad) { +// this.pad = pad; +// } + + /** + * This method deserializes the data bits obtained from the wire into the + * respective header and payload which are of type Packet + * + * @param data byte[] data from wire to deserialize + * @param bitOffset int bit position where packet header starts in data + * array + * @param size int size of packet in bits + * @return Packet + * @throws PacketException + * + * Note: Copied from org.opendaylight.controller.sal.packet.Packet + */ + @Override + public Packet deserialize(byte[] data, int bitOffset, int size) + throws PacketException { + + // Deserialize the header fields one by one + int startOffset = 0, numBits = 0; + for (Entry> pairs : hdrFieldCoordMap + .entrySet()) { + String hdrField = pairs.getKey(); + startOffset = bitOffset + this.getfieldOffset(hdrField); + if(hdrField.equals(OPTIONS)) { + numBits = (size - DHCP_NOOPT_HDR_SIZE) * 8; + } else { + numBits = this.getfieldnumBits(hdrField); + } + byte[] hdrFieldBytes = null; + try { + hdrFieldBytes = BitBufferHelper.getBits(data, startOffset, + numBits); + } catch (BufferException e) { + throw new PacketException(e.getMessage()); + } + + /* + * Store the raw read value, checks the payload type and set the + * payloadClass accordingly + */ + this.setHeaderField(hdrField, hdrFieldBytes); + + if (logger.isTraceEnabled()) { + logger.trace("{}: {}: {} (offset {} bitsize {})", + new Object[] { this.getClass().getSimpleName(), hdrField, + HexEncode.bytesToHexString(hdrFieldBytes), + startOffset, numBits }); + } + } + + // Deserialize the payload now + int payloadStart = startOffset + numBits; + int payloadSize = data.length * NetUtils.NumBitsInAByte - payloadStart; + + if (payloadClass != null) { + try { + payload = payloadClass.newInstance(); + } catch (Exception e) { + throw new RuntimeException( + "Error parsing payload for Ethernet packet", e); + } + payload.deserialize(data, payloadStart, payloadSize); + payload.setParent(this); + } else { + /* + * The payload class was not set, it means no class for parsing + * this payload is present. Let's store the raw payload if any. + */ + int start = payloadStart / NetUtils.NumBitsInAByte; + int stop = start + payloadSize / NetUtils.NumBitsInAByte; + rawPayload = Arrays.copyOfRange(data, start, stop); + } + // Take care of computation that can be done only after deserialization + postDeserializeCustomOperation(data, payloadStart - getHeaderSize()); + + return this; + } + + @Override + public byte[] serialize() throws PacketException { + this.setOptions(this.dhcpOptions.serialize()); + byte[] data = super.serialize(); + // Check for OPT_END at end of options + if (data.length > DHCP_MAX_SIZE) { + // shouldn't have happened + // Add exception? + logger.error("DHCP Packet too big"); + } else if (data[data.length - 1] != (byte)255) { + // DHCP Options not ended properly + //throw new PacketException("Missing DHCP Option END"); + logger.error("Missing DHCP Option END"); + }else if(data.length < DHCP_MIN_SIZE) { + byte[] padding = new byte[DHCP_MIN_SIZE - data.length]; + logger.debug("DHCP Pkt too small: {}, padding added {}", + data.length, padding.length); + data = ArrayUtils.addAll(data, padding); + } + return data; + } + @Override + /** + * Gets the number of bits for the fieldname specified + * If the fieldname has variable length like "Options", then this value is computed using the header length + * @param fieldname - String + * @return number of bits for fieldname - int + */ + public int getfieldnumBits(String fieldName) { + if (fieldName.equals(OPTIONS)) { + byte[] barr = fieldValues.get(OPTIONS); + return (barr.length) * NetUtils.NumBitsInAByte; + } + return hdrFieldCoordMap.get(fieldName).getRight(); + } + + @Override + public int getHeaderSize() { + byte[] barr = fieldValues.get(OPTIONS); + int len = 0; + if(barr != null) { len = barr.length; } + return (DHCP_NOOPT_HDR_SIZE + len) * 8; + } + + + @Override + protected void postDeserializeCustomOperation(byte[] data, int startBitOffset) { + //TODO: Anything need to be done here? + // Check for MAGIC_COOKIE. This means we only support DHCP, not BOOTP + int cookie = BitBufferHelper.getInt(fieldValues.get(MCOOKIE)); + if (cookie != MAGIC_COOKIE) { + logger.debug("Not DHCP packet"); + // Throw exception? + } + // parse options into DHCPOptions + this.dhcpOptions.deserialize(this.getOptions()); + // reset options byte array, this will also drop padding + this.setOptions(this.dhcpOptions.serialize()); + } + + // Set/get operations for Options + public void setMsgType(byte type) { + dhcpOptions.setOptionByte(OPT_MESSAGE_TYPE, type); + } + + public byte getMsgType() { + return dhcpOptions.getOptionByte(OPT_MESSAGE_TYPE); + } + + public void setOptionByte(byte code, byte opt) { + dhcpOptions.setOptionByte(code, opt); + } + + public byte getOptionByte(byte code) { + return dhcpOptions.getOptionByte(code); + } + + public void setOptionBytes(byte code, byte[] opt) { + dhcpOptions.setOption(code, opt); + } + + public byte[] getOptionBytes(byte code) { + return dhcpOptions.getOptionBytes(code); + } + + public void setOptionShort(byte code, short s) { + dhcpOptions.setOptionShort(code, s); + } + + public short getOptionShort(byte code) { + return dhcpOptions.getOptionShort(code); + } + + public void setOptionInt(byte code, int i) { + dhcpOptions.setOptionInt(code, i); + } + + public int getOptionInt(byte code) { + return dhcpOptions.getOptionInt(code); + } + + public void setOptionInetAddr(byte code, InetAddress addr) { + dhcpOptions.setOptionInetAddr(code, addr); + } + + public InetAddress getOptionInetAddr(byte code) { + return dhcpOptions.getOptionInetAddr(code); + } + + public void setOptionInetAddr(byte code, String addr) throws UnknownHostException { + dhcpOptions.setOptionStrAddr(code, addr); + } + + public String getOptionStrAddr(byte code) { + return dhcpOptions.getOptionStrAddr(code); + } + + public void setOptionStrAddrs(byte code, List opt) throws UnknownHostException { + dhcpOptions.setOptionStrAddrs(code, opt); + } + + public void setOptionString(byte code, String str) { + dhcpOptions.setOptionString(code, str); + } + public boolean containsOption(byte code) { + // TODO Auto-generated method stub + return dhcpOptions.containsOption(code); + } + + public void unsetOption(byte code) { + dhcpOptions.unsetOption(code); + } + + @Override + public String toString() { + StringBuilder ret = new StringBuilder(); + ret.append(super.toString()) + .append(dhcpOptions); + + return ret.toString(); + } +} diff --git a/dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPOptions.java b/dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPOptions.java new file mode 100644 index 00000000..47d3ed74 --- /dev/null +++ b/dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPOptions.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. 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.vpnservice.dhcpservice.api; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.LinkedHashMap; + + + +import java.util.List; + +import org.apache.commons.lang3.ArrayUtils; +import org.opendaylight.controller.liblldp.HexEncode; +import org.opendaylight.controller.liblldp.NetUtils; +//import org.apache.commons.lang3.ArrayUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.opendaylight.vpnservice.dhcpservice.api.DHCPConstants.*; + +public class DHCPOptions { + protected static final Logger logger = LoggerFactory + .getLogger(DHCPOptions.class); + + class DhcpOption extends Object { + private byte code; + private byte length; + private byte[] value; + + public DhcpOption(byte code, byte[] value) { + if ((code != OPT_PAD) && (code != OPT_END) && (value != null)) { + this.code = code; + this.value = value; + this.length = (byte) value.length; + } + } + + public byte getCode() { + return this.code; + } + + public byte[] getValue() { + return this.value; + } + + public byte[] serialize() { + byte[] opt1 = new byte[2]; + opt1[0] = this.code; + opt1[1] = this.length; + return ArrayUtils.addAll(opt1, this.value); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("{ ") + .append("code: ").append(this.code) + .append(", len: ").append(this.length) + .append(", value: 0x").append(HexEncode.bytesToHexString(this.value)) + .append(" }"); + return sb.toString(); + } + } + + private LinkedHashMap options; + + public DHCPOptions() { + options = new LinkedHashMap(); + } + + private void setOption(DhcpOption opt) { + this.options.put(opt.getCode(), opt); + } + + private DhcpOption getOption(byte code) { + return this.options.get(code); + } + + public void setOption(byte code, byte[] opt) { + this.setOption(new DhcpOption(code, opt)); + } + + public byte[] getOptionBytes(byte code) { + try{ + return this.getOption(code).getValue(); + } + catch (NullPointerException e) + { + return null; + } + } + + public void setOptionByte(byte code, byte opt) { + this.setOption(new DhcpOption(code, DHCPUtils.byteToByteArray(opt))); + } + + public byte getOptionByte(byte code) { + return this.getOption(code).getValue()[0]; + } + + public void setOptionShort(byte code, short opt) { + this.setOption(new DhcpOption(code, DHCPUtils.shortToByteArray(opt))); + } + + public short getOptionShort(byte code) { + byte[] opt = this.getOptionBytes(code); + return DHCPUtils.byteArrayToShort(opt); + } + + public void setOptionInt(byte code, int opt) { + this.setOption(new DhcpOption(code, DHCPUtils.intToByteArray(opt))); + } + + public int getOptionInt(byte code) { + byte[] opt = this.getOptionBytes(code); + return NetUtils.byteArray4ToInt(opt); + } + + public void setOptionInetAddr(byte code, InetAddress opt) { + this.setOption(new DhcpOption(code, DHCPUtils.inetAddrToByteArray(opt))); + } + + public InetAddress getOptionInetAddr(byte code) { + byte[] opt = this.getOptionBytes(code); + try { + return InetAddress.getByAddress(opt); + } catch (UnknownHostException | NullPointerException e) { + return null; + } + } + + public void setOptionStrAddr(byte code, String opt) throws UnknownHostException { + this.setOption(new DhcpOption(code, DHCPUtils.strAddrToByteArray(opt))); + } + + public String getOptionStrAddr(byte code) { + byte[] opt = this.getOptionBytes(code); + try { + return InetAddress.getByAddress(opt).getHostAddress(); + } catch (UnknownHostException| NullPointerException e) { + return null; + } + } + + public void setOptionStrAddrs(byte code, List addrs) throws UnknownHostException { + if(!addrs.isEmpty()) { + this.setOption(new DhcpOption(code, DHCPUtils.strListAddrsToByteArray(addrs))); + } + } + + public void setOptionString(byte code, String str) { + this.setOption(new DhcpOption(code, str.getBytes())); + } + + public byte[] serialize() { + byte[] options = new byte[0]; + for(DhcpOption dOpt: this.options.values()) { + options = ArrayUtils.addAll(options, dOpt.serialize()); + } + byte[] end = new byte[] {(byte)255}; + options = ArrayUtils.addAll(options, end); + return options; + } + + private byte[] getOptionValArray(byte[] opt, int pos, int len) { + byte[] val = new byte[len]; + for(int i = 0; i < len; i++) { + val[i] = opt[pos + i]; + } + return val; + } + + public void deserialize(byte[] options) { + int pos = 0; + byte code, len; + byte[] value; + if (options != null) { + while (pos < options.length) { + code = options[pos++]; + if (code == OPT_END) { + break; + } + len = options[pos++]; + if ((len + pos) > options.length) { + // Throw exception??? + break; + } + value = getOptionValArray(options, pos, len); + setOption(code, value); + pos += len; + } + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("{"); + int i = 1; + for(DhcpOption dOpt: this.options.values()) { + //options = ArrayUtils.addAll(options, dOpt.serialize()); + sb.append("Option").append(i++) + .append(dOpt.toString()); + } + sb.append("}"); + return sb.toString(); + } + + public boolean containsOption(byte code) { + return options.containsKey(code); + } + + public DhcpOption unsetOption(byte code) { + return options.remove(code); + } + +} + diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInfo.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInfo.java new file mode 100644 index 00000000..dfb40467 --- /dev/null +++ b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInfo.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. 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.vpnservice.dhcpservice; + +import java.util.ArrayList; +import java.util.List; + +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.HostRoutes; + +public class DhcpInfo { + private String _clientIp; + private String _serverIp; + private String _gatewayIp; + private String _cidr; + private List _dnsServers; + private List _hostRoutes; + + public DhcpInfo() { + //Empty constructor + } + + protected DhcpInfo setClientIp(String clientIp) { + _clientIp = clientIp; + return this; + } + + protected DhcpInfo setCidr(String cidr) { + _cidr = cidr; + return this; + } + + protected DhcpInfo setServerIp(String serverIp) { + _serverIp = serverIp; + return this; + } + + protected DhcpInfo setGatewayIp(String gwIp) { + _gatewayIp = gwIp; + return this; + } + + protected DhcpInfo setHostRoutes(List hostRoutes) { + _hostRoutes = hostRoutes; + return this; + } + + protected DhcpInfo setDnsServers(List dnsServers) { + _dnsServers = dnsServers; + return this; + } + + protected DhcpInfo setDnsServersIpAddrs(List dnsServers) { + for (IpAddress ipAddr: dnsServers) { + addDnsServer(ipAddr.getIpv4Address().getValue()); + } + return this; + } + + protected DhcpInfo addDnsServer(String dnsServerIp) { + if(_dnsServers == null) { + _dnsServers = new ArrayList(); + } + _dnsServers.add(dnsServerIp); + return this; + } + + + protected String getClientIp() { + return _clientIp; + } + + protected String getCidr() { + return _cidr; + } + + protected String getServerIp() { + return _serverIp ; + } + + protected String getGatewayIp() { + return _gatewayIp ; + } + + protected List getDnsServers() { + return _dnsServers; + } + + protected List getHostRoutes() { + return _hostRoutes; + } + +} diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpManager.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpManager.java new file mode 100644 index 00000000..458ad968 --- /dev/null +++ b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpManager.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. 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.vpnservice.dhcpservice; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey; + +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets; +import com.google.common.base.Optional; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron; +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import com.google.common.util.concurrent.FutureCallback; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants; +import org.opendaylight.vpnservice.mdsalutil.ActionInfo; +import org.opendaylight.vpnservice.mdsalutil.ActionType; +import org.opendaylight.vpnservice.mdsalutil.FlowEntity; +import org.opendaylight.vpnservice.mdsalutil.InstructionInfo; +import org.opendaylight.vpnservice.mdsalutil.InstructionType; +import org.opendaylight.vpnservice.mdsalutil.MDSALUtil; +import org.opendaylight.vpnservice.mdsalutil.MatchFieldType; +import org.opendaylight.vpnservice.mdsalutil.MatchInfo; +import org.opendaylight.vpnservice.mdsalutil.NwConstants; +import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager; +import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols; +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port; +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DhcpManager implements AutoCloseable { + + private static final Logger logger = LoggerFactory.getLogger(DhcpManager.class); + private final DataBroker broker; + IMdsalApiManager mdsalUtil; + + private int dhcpOptLeaseTime = 0; + private int dhcpOptRenewalTime = 0; + private int dhcpOptRebindingTime = 0; + private String dhcpOptDefDomainName = "openstacklocal"; + + private static final FutureCallback DEFAULT_CALLBACK = + new FutureCallback() { + public void onSuccess(Void result) { + logger.debug("Success in Datastore write operation"); + } + public void onFailure(Throwable error) { + logger.error("Error in Datastore write operation", error); + }; + }; + + /** + * @param db - dataBroker reference + */ + public DhcpManager(final DataBroker db) { + broker = db; + configureLeaseDuration(DHCPMConstants.DEFAULT_LEASE_TIME); + } + + public void setMdsalManager(IMdsalApiManager mdsalManager) { + this.mdsalUtil = mdsalManager; + } + + @Override + public void close() throws Exception { + logger.info("DHCP Manager Closed"); + } + + public void installDhcpEntries(BigInteger dpnId) { + logger.debug("Installing Default DHCP Flow tp DPN: {}", dpnId); + setupDefaultDhcpFlow(dpnId, DHCPMConstants.DHCP_TABLE, NwConstants.ADD_FLOW); + } + + private void setupDefaultDhcpFlow(BigInteger dpId, short tableId, int addOrRemove) { + + List matches = new ArrayList(); + + matches.add(new MatchInfo(MatchFieldType.eth_type, + new long[] { NwConstants.ETHTYPE_IPV4 })); + matches.add(new MatchInfo(MatchFieldType.ip_proto, + new long[] { IPProtocols.UDP.intValue() })); + matches.add(new MatchInfo(MatchFieldType.udp_src, + new long[] { DHCPMConstants.dhcpClientPort })); + matches.add(new MatchInfo(MatchFieldType.udp_dst, + new long[] { DHCPMConstants.dhcpServerPort })); + + List instructions = new ArrayList(); + List actionsInfos = new ArrayList(); + + // Punt to controller + actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, + new String[] {})); + instructions.add(new InstructionInfo(InstructionType.write_actions, + actionsInfos)); + FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, + getDefaultDhcpFlowRef(dpId, tableId),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0, + DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions); + mdsalUtil.installFlow(flowEntity); + } + + private String getDefaultDhcpFlowRef(BigInteger dpId, long tableId) { + return new StringBuffer().append(DHCPMConstants.FLOWID_PREFIX).append(dpId) + .append(NwConstants.FLOWID_SEPARATOR).append(tableId).toString(); + } + + public int setLeaseDuration(int leaseDuration) { + configureLeaseDuration(leaseDuration); + return getDhcpLeaseTime(); + } + + public String setDefaultDomain(String defaultDomain) { + this.dhcpOptDefDomainName = defaultDomain; + return getDhcpDefDomain(); + } + + protected int getDhcpLeaseTime() { + return this.dhcpOptLeaseTime; + } + + protected int getDhcpRenewalTime() { + return this.dhcpOptLeaseTime; + } + + protected int getDhcpRebindingTime() { + return this.dhcpOptLeaseTime; + } + + protected String getDhcpDefDomain() { + return this.dhcpOptDefDomainName; + } + + private void configureLeaseDuration(int leaseTime) { + this.dhcpOptLeaseTime = leaseTime; + if(leaseTime > 0) { + this.dhcpOptRenewalTime = this.dhcpOptLeaseTime/2; + this.dhcpOptRebindingTime = (this.dhcpOptLeaseTime*7)/8; + } else { + this.dhcpOptRenewalTime = -1; + this.dhcpOptRebindingTime = -1; + } + } + + public Subnet getNeutronSubnet(Port nPort) { + /* TODO: Once NeutronVpn is merged, use it to get Subnet + if (nPort != null) { + try { + return neutronVpnService.getNeutronSubnet(nPort.getFixedIps().get(0).getSubnetId()); + } catch (Exception e) { + logger.warn("Failed to get Neutron Subnet from Port: {}", e); + } + } + */ + if (nPort.getFixedIps() != null && !nPort.getFixedIps().isEmpty()) { + InstanceIdentifier sIid = + InstanceIdentifier.create(Neutron.class).child(Subnets.class) + .child(Subnet.class, new SubnetKey(nPort.getFixedIps().get(0).getSubnetId())); + Optional optSubnet = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, sIid, broker); + if (optSubnet.isPresent()) { + return optSubnet.get(); + } + } + return null; + } + + public Port getNeutronPort(String name) { + // TODO Once NeutronVpn is merged, use it to get port + //return neutronVpnService.getNeutronPort(name); + InstanceIdentifier pIid = InstanceIdentifier.create(Neutron.class).child(Ports.class); + Optional optPorts = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, pIid, broker); + if(optPorts.isPresent()) { + for(Port port: optPorts.get().getPort()) { + if(port.getUuid().getValue().startsWith(name.substring(3))) { + return port; + } + } + } + return null; + } + +} diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpPktHandler.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpPktHandler.java index 16a2dc19..3d10fa42 100644 --- a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpPktHandler.java +++ b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpPktHandler.java @@ -7,31 +7,515 @@ */ package org.opendaylight.vpnservice.dhcpservice; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.net.util.SubnetUtils; +import org.apache.commons.net.util.SubnetUtils.SubnetInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - +import org.opendaylight.controller.liblldp.EtherTypes; +import org.opendaylight.controller.liblldp.HexEncode; +import org.opendaylight.controller.liblldp.NetUtils; +import org.opendaylight.controller.liblldp.PacketException; import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.vpnservice.dhcpservice.api.DHCP; +import org.opendaylight.vpnservice.dhcpservice.api.DHCPConstants; +import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants; +import org.opendaylight.vpnservice.dhcpservice.api.DHCPUtils; +import org.opendaylight.vpnservice.mdsalutil.MDSALDataStoreUtils; +import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet; +import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols; +import org.opendaylight.vpnservice.mdsalutil.packet.IPv4; +import org.opendaylight.vpnservice.mdsalutil.packet.UDP; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port; +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.HostRoutes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketInReason; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService; import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived; import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.SendToController; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import com.google.common.base.Optional; public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener { private static final Logger LOG = LoggerFactory.getLogger(DhcpPktHandler.class); private final DataBroker dataBroker; + private final DhcpManager dhcpMgr; + + private boolean computeUdpChecksum = true; + private PacketProcessingService pktService; - public DhcpPktHandler(final DataBroker broker) { + public DhcpPktHandler(final DataBroker broker, final DhcpManager dhcpManager) { this.dataBroker = broker; + dhcpMgr = dhcpManager; } + //TODO: Handle this in a separate thread @Override - public void onPacketReceived(PacketReceived pktReceived) { - LOG.info("Pkt received: {}",pktReceived); + public void onPacketReceived(PacketReceived packet) { + LOG.trace("Pkt received: {}", packet); + Class pktInReason = packet.getPacketInReason(); + short tableId = packet.getTableId().getValue(); + if (isPktInReasonSendtoCtrl(pktInReason) && ((DHCPMConstants.DHCP_TABLE == tableId))) { + byte[] inPayload = packet.getPayload(); + Ethernet ethPkt = new Ethernet(); + try { + ethPkt.deserialize(inPayload, 0, inPayload.length * NetUtils.NumBitsInAByte); + } catch (Exception e) { + LOG.warn("Failed to decode DHCP Packet", e); + return; + } + try { + DHCP pktIn = getDhcpPktIn(ethPkt); + LOG.trace("DHCPPkt received: {}", pktIn); + if (pktIn != null) { + NodeConnectorRef inNcRef = packet.getIngress(); + FlowCapableNodeConnector fcNc = this.getFlowCapableNodeConnector(inNcRef); + DHCP replyPkt = handleDhcpPacket(pktIn, fcNc); + byte[] pktOut = getDhcpPacketOut(replyPkt, ethPkt, fcNc); + sendPacketOut(pktOut, inNcRef); + } + } catch (Exception e) { + LOG.warn("Failed to get DHCP Reply", e); + } + } + } + + private void sendPacketOut(byte[] pktOut, NodeConnectorRef ingress) { + // We go out the same port we came in on + InstanceIdentifier egressNodePath = getNodePath(ingress.getValue()); + TransmitPacketInput input = new TransmitPacketInputBuilder() + .setPayload(pktOut).setNode(new NodeRef(egressNodePath)) + .setEgress(ingress).build(); + LOG.trace("Transmitting packet: {}",input); + this.pktService.transmitPacket(input); + } + + private InstanceIdentifier getNodePath(InstanceIdentifier nodeInstanceId) { + return nodeInstanceId.firstIdentifierOf(Node.class); + } + + private DHCP handleDhcpPacket(DHCP dhcpPkt, FlowCapableNodeConnector fcNc) { + LOG.debug("DHCP pkt rcvd {}", dhcpPkt); + byte msgType = dhcpPkt.getMsgType(); + if (msgType == DHCPConstants.MSG_DECLINE) { + LOG.debug("DHCPDECLINE received"); + return null; + } else if (msgType == DHCPConstants.MSG_RELEASE) { + LOG.debug("DHCPRELEASE received"); + return null; + } + + Port nPort = getNeutronPort(fcNc); + Subnet nSubnet = getNeutronSubnet(nPort); + DhcpInfo dhcpInfo = getDhcpInfo(nPort, nSubnet); + LOG.trace("NeutronPort: {} \n NeutronSubnet: {}, dhcpInfo{}",nPort, nSubnet, dhcpInfo); + DHCP reply = null; + if (dhcpInfo != null) { + if (msgType == DHCPConstants.MSG_DISCOVER) { + reply = getReplyToDiscover(dhcpPkt, dhcpInfo); + } else if (msgType == DHCPConstants.MSG_REQUEST) { + reply = getReplyToRequest(dhcpPkt, dhcpInfo); + } + } + + return reply; + } + + private DhcpInfo getDhcpInfo(Port nPort, Subnet nSubnet) { + DhcpInfo dhcpInfo = null; + if( (nPort != null) && (nSubnet != null) ) { + String clientIp = nPort.getFixedIps().get(0).getIpAddress().getIpv4Address().getValue(); + String serverIp = nSubnet.getGatewayIp().getIpv4Address().getValue(); + List dnsServers = nSubnet.getDnsNameservers(); + dhcpInfo = new DhcpInfo(); + dhcpInfo.setClientIp(clientIp).setServerIp(serverIp) + .setCidr(nSubnet.getCidr()).setHostRoutes(nSubnet.getHostRoutes()) + .setDnsServersIpAddrs(dnsServers).setGatewayIp(serverIp); + } else { + //FIXME: Delete this test code + LOG.error("TestOnly Code"); + dhcpInfo = new DhcpInfo(); + dhcpInfo.setClientIp("1.1.1.3").setServerIp("1.1.1.1") + .setCidr("1.1.1.0/24").addDnsServer("1.1.1.1"); + LOG.warn("Failed to get Subnet info for DHCP reply"); + } + return dhcpInfo; + } + + private Subnet getNeutronSubnet(Port nPort) { + return dhcpMgr.getNeutronSubnet(nPort); + } + + private Port getNeutronPort(FlowCapableNodeConnector fcNc) { + return dhcpMgr.getNeutronPort(fcNc.getName()); + } + + private FlowCapableNodeConnector getFlowCapableNodeConnector(NodeConnectorRef inNcRef) { + InstanceIdentifier ncId = inNcRef.getValue().firstIdentifierOf(NodeConnector.class); + Optional nodeConnector = + MDSALDataStoreUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, ncId); + if(nodeConnector.isPresent()) { + NodeConnector nc = nodeConnector.get(); + LOG.trace("Incoming pkt's NodeConnector: {}", nc); + FlowCapableNodeConnector fcnc = nc.getAugmentation(FlowCapableNodeConnector.class); + return fcnc; + } + return null; + } + + private DHCP getDhcpPktIn(Ethernet ethPkt) { + if (ethPkt.getPayload() instanceof IPv4) { + IPv4 ipPkt = (IPv4) ethPkt.getPayload(); + if (ipPkt.getPayload() instanceof UDP) { + UDP udpPkt = (UDP) ipPkt.getPayload(); + if ((udpPkt.getSourcePort() == DHCPMConstants.dhcpClientPort) + && (udpPkt.getDestinationPort() == DHCPMConstants.dhcpServerPort)) { + byte[] rawDhcpPayload = udpPkt.getRawPayload(); + DHCP reply = new DHCP(); + try { + reply.deserialize(rawDhcpPayload, 0, rawDhcpPayload.length); + } catch (PacketException e) { + LOG.warn("Failed to deserialize DHCP pkt", e); + return null; + } + return reply; + } + } + } + return null; + } + + DHCP getReplyToDiscover(DHCP dhcpPkt, DhcpInfo dhcpInfo) { + DHCP reply = new DHCP(); + reply.setOp(DHCPConstants.BOOTREPLY); + reply.setHtype(dhcpPkt.getHtype()); + reply.setHlen(dhcpPkt.getHlen()); + reply.setHops((byte) 0); + reply.setXid(dhcpPkt.getXid()); + reply.setSecs((short) 0); + + reply.setYiaddr(dhcpInfo.getClientIp()); + reply.setSiaddr(dhcpInfo.getServerIp()); + + reply.setFlags(dhcpPkt.getFlags()); + reply.setGiaddr(dhcpPkt.getGiaddr()); + reply.setChaddr(dhcpPkt.getChaddr()); + + reply.setMsgType(DHCPConstants.MSG_OFFER); + if(dhcpPkt.containsOption(DHCPConstants.OPT_PARAMETER_REQUEST_LIST)) { + setParameterListOptions(dhcpPkt, reply, dhcpInfo); + } + setCommonOptions(reply, dhcpInfo); + return reply; + } + + DHCP getReplyToRequest(DHCP dhcpPkt, DhcpInfo dhcpInfo) { + boolean sendAck = false; + byte[] requestedIp = null; + DHCP reply = new DHCP(); + reply.setOp(DHCPConstants.BOOTREPLY); + reply.setHtype(dhcpPkt.getHtype()); + reply.setHlen(dhcpPkt.getHlen()); + reply.setHops((byte) 0); + reply.setXid(dhcpPkt.getXid()); + reply.setSecs((short) 0); + + reply.setFlags(dhcpPkt.getFlags()); + reply.setGiaddr(dhcpPkt.getGiaddr()); + reply.setChaddr(dhcpPkt.getChaddr()); + byte[] allocatedIp = DHCPUtils.strAddrToByteArray(dhcpInfo.getClientIp()); + if(Arrays.equals(allocatedIp, dhcpPkt.getCiaddr())) { + //This means a renew request + sendAck = true; + } else { + requestedIp = dhcpPkt.getOptionBytes(DHCPConstants.OPT_REQUESTED_ADDRESS); + sendAck = Arrays.equals(allocatedIp, requestedIp); + } + + if (sendAck) { + reply.setCiaddr(dhcpPkt.getCiaddr()); + reply.setYiaddr(dhcpInfo.getClientIp()); + reply.setSiaddr(dhcpInfo.getServerIp()); + reply.setMsgType(DHCPConstants.MSG_ACK); + if(dhcpPkt.containsOption(DHCPConstants.OPT_PARAMETER_REQUEST_LIST)) { + setParameterListOptions(dhcpPkt, reply, dhcpInfo); + } + setCommonOptions(reply, dhcpInfo); + } + else { + reply.setMsgType(DHCPConstants.MSG_NAK); + } + return reply; + } + + protected byte[] getDhcpPacketOut(DHCP reply, Ethernet etherPkt, FlowCapableNodeConnector fcNc) { + if (reply == null) { + /* + * DECLINE or RELEASE don't result in reply packet + */ + return null; + } + LOG.debug("Sending DHCP Pkt {}", reply); + // create UDP pkt + UDP udpPkt = new UDP(); + byte[] rawPkt; + try { + rawPkt = reply.serialize(); + } catch (PacketException e2) { + // TODO Auto-generated catch block + e2.printStackTrace(); + return null; + } + udpPkt.setRawPayload(rawPkt); + udpPkt.setDestinationPort(DHCPMConstants.dhcpClientPort); + udpPkt.setSourcePort(DHCPMConstants.dhcpServerPort); + udpPkt.setLength((short) (rawPkt.length + 8)); + //Create IP Pkt + IPv4 ip4Reply = new IPv4(); + try { + rawPkt = udpPkt.serialize(); + } catch (PacketException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + short checkSum = 0; + if(this.computeUdpChecksum) { + checkSum = computeChecksum(rawPkt, reply.getSiaddr(), + NetUtils.intToByteArray4(DHCPMConstants.BCAST_IP)); + } + udpPkt.setChecksum(checkSum); + ip4Reply.setPayload(udpPkt); + ip4Reply.setProtocol(IPProtocols.UDP.byteValue()); + ip4Reply.setSourceAddress(reply.getSiaddrAsInetAddr()); + ip4Reply.setDestinationAddress(DHCPMConstants.BCAST_IP); + ip4Reply.setTotalLength((short) (rawPkt.length+20)); + ip4Reply.setTtl((byte) 32); + // create Ethernet Frame + Ethernet ether = new Ethernet(); + //TODO: + ether.setSourceMACAddress(getServerMacAddress(fcNc)); + ether.setDestinationMACAddress(etherPkt.getSourceMACAddress()); + ether.setEtherType(EtherTypes.IPv4.shortValue()); + ether.setPayload(ip4Reply); + try { + rawPkt = ether.serialize(); + } catch (PacketException e) { + LOG.warn("Failed to serialize ethernet reply",e); + return null; + } + return rawPkt; + } + + private byte[] getServerMacAddress(FlowCapableNodeConnector fcNc) { + // Should we return ControllerMac instead? + MacAddress macAddress = fcNc.getHardwareAddress(); + return DHCPUtils.strMacAddrtoByteArray(macAddress.getValue()); + } + + public short computeChecksum(byte[] inData, byte[] srcAddr, byte[] destAddr) { + short checkSum = (short) 0; + int sum = 0, carry = 0; + int wordData, i; + + for (i = 0; i < inData.length - 1; i = i + 2) { + // Skip, if the current bytes are checkSum bytes + wordData = ((inData[i] << 8) & 0xFF00) + (inData[i + 1] & 0xFF); + sum = sum + wordData; + } + + if (i < inData.length) { + wordData = ((inData[i] << 8) & 0xFF00) + (0 & 0xFF); + sum = sum + wordData; + } + + for (i = 0; i < 4; i = i + 2) { + wordData = ((srcAddr[i] << 8) & 0xFF00) + (srcAddr[i + 1] & 0xFF); + sum = sum + wordData; + } + + for (i = 0; i < 4; i = i + 2) { + wordData = ((destAddr[i] << 8) & 0xFF00) + (destAddr[i + 1] & 0xFF); + sum = sum + wordData; + } + sum = sum + 17 + inData.length; + + while((sum >> 16) != 0) { + carry = (sum >> 16); + sum = (sum & 0xFFFF)+ carry; + } + checkSum = (short) ~((short) sum & 0xFFFF); + if(checkSum == 0) { + checkSum = (short)0xffff; + } + return checkSum; + } + + private void setCommonOptions(DHCP pkt, DhcpInfo dhcpInfo) { + pkt.setOptionInt(DHCPConstants.OPT_LEASE_TIME, dhcpMgr.getDhcpLeaseTime()); + if (dhcpMgr.getDhcpDefDomain() != null) { + pkt.setOptionString(DHCPConstants.OPT_DOMAIN_NAME, dhcpMgr.getDhcpDefDomain()); + } + if(dhcpMgr.getDhcpLeaseTime() > 0) { + pkt.setOptionInt(DHCPConstants.OPT_REBINDING_TIME, dhcpMgr.getDhcpRebindingTime()); + pkt.setOptionInt(DHCPConstants.OPT_RENEWAL_TIME, dhcpMgr.getDhcpRenewalTime()); + } + SubnetUtils util = null; + SubnetInfo info = null; + util = new SubnetUtils(dhcpInfo.getCidr()); + info = util.getInfo(); + String gwIp = dhcpInfo.getGatewayIp(); + List dnServers = dhcpInfo.getDnsServers(); + try { + /* + * setParameterListOptions may have initialized some of these + * options to maintain order. If we can't fill them, unset to avoid + * sending wrong information in reply. + */ + if (gwIp != null) { + pkt.setOptionInetAddr(DHCPConstants.OPT_SERVER_IDENTIFIER, gwIp); + pkt.setOptionInetAddr(DHCPConstants.OPT_ROUTERS, gwIp); + } else { + pkt.unsetOption(DHCPConstants.OPT_SERVER_IDENTIFIER); + pkt.unsetOption(DHCPConstants.OPT_ROUTERS); + } + if (info != null) { + pkt.setOptionInetAddr(DHCPConstants.OPT_SUBNET_MASK, info.getNetmask()); + pkt.setOptionInetAddr(DHCPConstants.OPT_BROADCAST_ADDRESS, info.getBroadcastAddress()); + } else { + pkt.unsetOption(DHCPConstants.OPT_SUBNET_MASK); + pkt.unsetOption(DHCPConstants.OPT_BROADCAST_ADDRESS); + } + if ((dnServers != null) && (dnServers.size() > 0)) { + pkt.setOptionStrAddrs(DHCPConstants.OPT_DOMAIN_NAME_SERVERS, dnServers); + } else { + pkt.unsetOption(DHCPConstants.OPT_DOMAIN_NAME_SERVERS); + } + } catch (UnknownHostException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + private void setParameterListOptions(DHCP req, DHCP reply, DhcpInfo dhcpInfo) { + byte[] paramList = req.getOptionBytes(DHCPConstants.OPT_PARAMETER_REQUEST_LIST); + for(int i = 0; i < paramList.length; i++) { + switch (paramList[i]) { + case DHCPConstants.OPT_SUBNET_MASK: + case DHCPConstants.OPT_ROUTERS: + case DHCPConstants.OPT_SERVER_IDENTIFIER: + case DHCPConstants.OPT_DOMAIN_NAME_SERVERS: + case DHCPConstants.OPT_BROADCAST_ADDRESS: + case DHCPConstants.OPT_LEASE_TIME: + case DHCPConstants.OPT_RENEWAL_TIME: + case DHCPConstants.OPT_REBINDING_TIME: + /* These values will be filled in setCommonOptions + * Setting these just to preserve order as + * specified in PARAMETER_REQUEST_LIST. + */ + reply.setOptionInt(paramList[i], 0); + break; + case DHCPConstants.OPT_DOMAIN_NAME: + reply.setOptionString(paramList[i], " "); + break; + case DHCPConstants.OPT_CLASSLESS_ROUTE: + setOptionClasslessRoute(reply, dhcpInfo); + break; + default: + LOG.debug("DHCP Option code {} not supported yet", paramList[i]); + break; + } + } + } + private void setOptionClasslessRoute(DHCP reply, DhcpInfo dhcpInfo) { + List hostRoutes = dhcpInfo.getHostRoutes(); + if(hostRoutes == null) { + //we can't set this option, so return + return; + } + ByteArrayOutputStream result = new ByteArrayOutputStream(); + Iterator iter = hostRoutes.iterator(); + while(iter.hasNext()) { + HostRoutes hostRoute = iter.next(); + String router = hostRoute.getNexthop().toString(); + String dest = hostRoute.getDestination().toString(); + try { + result.write(convertToClasslessRouteOption(dest, router)); + } catch (IOException | NullPointerException e) { + LOG.debug("Exception {}",e.getMessage()); + } + } + if (result.size() > 0) { + reply.setOptionBytes(DHCPConstants.OPT_CLASSLESS_ROUTE , result.toByteArray()); + } + } + + protected byte[] convertToClasslessRouteOption(String dest, String router) { + ByteArrayOutputStream bArr = new ByteArrayOutputStream(); + if((dest == null || + router == null)) { + return null; + } + + //get prefix + Short prefix = null; + String[] parts = dest.split("/"); + if (parts.length < 2) { + prefix = new Short((short)0); + } else { + prefix = Short.valueOf(parts[1]); + } + + bArr.write(prefix.byteValue()); + SubnetUtils util = new SubnetUtils(dest); + SubnetInfo info = util.getInfo(); + String strNetAddr = info.getNetworkAddress(); + try { + byte[] netAddr = InetAddress.getByName(strNetAddr).getAddress(); + //Strip any trailing 0s from netAddr + for(int i = 0; i < netAddr.length;i++) { + if(netAddr[i] != 0) { + bArr.write(netAddr,i,1); + } + } + bArr.write(InetAddress.getByName(router).getAddress()); + } catch (IOException e) { + return null; + } + return bArr.toByteArray(); + } + + private boolean isPktInReasonSendtoCtrl(Class pktInReason) { + return (pktInReason == SendToController.class); } @Override public void close() throws Exception { // TODO Auto-generated method stub - + } + + public void setPacketProcessingService(PacketProcessingService packetService) { + this.pktService = packetService; } } diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpProvider.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpProvider.java index 7c086c23..ce1a0a11 100644 --- a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpProvider.java +++ b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpProvider.java @@ -7,8 +7,10 @@ */ package org.opendaylight.vpnservice.dhcpservice; -import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import java.math.BigInteger; +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService; import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext; @@ -24,15 +26,22 @@ public class DhcpProvider implements BindingAwareProvider, AutoCloseable { private DhcpPktHandler dhcpPktHandler; private Registration packetListener = null; private NotificationProviderService notificationService; + private DhcpManager dhcpManager; + private NodeListener dhcpNodeListener; @Override public void onSessionInitiated(ProviderContext session) { LOG.info("DhcpProvider Session Initiated"); try { - final DataBroker dataBroker = session.getSALService(DataBroker.class); - dhcpPktHandler = new DhcpPktHandler(dataBroker); + final DataBroker dataBroker = session.getSALService(DataBroker.class); + final PacketProcessingService pktProcessingService = session.getRpcService(PacketProcessingService.class); + dhcpManager = new DhcpManager(dataBroker); + dhcpManager.setMdsalManager(mdsalManager); + dhcpPktHandler = new DhcpPktHandler(dataBroker, dhcpManager); + dhcpPktHandler.setPacketProcessingService(pktProcessingService); packetListener = notificationService.registerNotificationListener(dhcpPktHandler); - } catch (Exception e) { + dhcpNodeListener = new NodeListener(dataBroker, dhcpManager); + } catch (Exception e) { LOG.error("Error initializing services", e); } } @@ -50,6 +59,9 @@ public class DhcpProvider implements BindingAwareProvider, AutoCloseable { if(dhcpPktHandler != null) { dhcpPktHandler.close(); } + if(dhcpNodeListener != null) { + dhcpNodeListener.close(); + } LOG.info("DhcpProvider closed"); } diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/NodeListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/NodeListener.java new file mode 100644 index 00000000..8cb8a7ad --- /dev/null +++ b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/NodeListener.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. 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.vpnservice.dhcpservice; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants; +import org.opendaylight.vpnservice.mdsalutil.*; +import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager; +import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +public class NodeListener extends AbstractDataChangeListener implements AutoCloseable { + + private static final Logger LOG = LoggerFactory.getLogger(NodeListener.class); + + private IMdsalApiManager mdsalManager; + private ListenerRegistration listenerRegistration; + private final DataBroker broker; + private DhcpManager dhcpManager; + + public NodeListener(final DataBroker db, final DhcpManager dhcpMgr) { + super(Node.class); + broker = db; + dhcpManager = dhcpMgr; + registerListener(db); + } + + private void registerListener(final DataBroker db) { + try { + listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + getWildCardPath(), NodeListener.this, AsyncDataBroker.DataChangeScope.SUBTREE); + } catch (final Exception e) { + LOG.error("NodeListener: DataChange listener registration fail!", e); + throw new IllegalStateException("NodeListener: registration Listener failed.", e); + } + } + + private InstanceIdentifier getWildCardPath() { + return InstanceIdentifier.create(Nodes.class).child(Node.class); + } + + + @Override + protected void remove(InstanceIdentifier identifier, Node del) { + + } + + @Override + protected void update(InstanceIdentifier identifier, Node original, Node update) { + + } + + @Override + protected void add(InstanceIdentifier identifier, Node add) { + NodeId nodeId = add.getId(); + String[] node = nodeId.getValue().split(":"); + BigInteger dpId = new BigInteger(node[1]); + dhcpManager.installDhcpEntries(dpId); + } + + @Override + public void close() throws Exception { + if (listenerRegistration != null) { + try { + listenerRegistration.close(); + } catch (final Exception e) { + LOG.error("Error when cleaning up NodeListener.", e); + } + listenerRegistration = null; + //ToDo: Should we delete DHCP flows when we are closed? + } + LOG.debug("Node Listener Closed"); + } +} diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/dhcpservice/impl/rev150710/DhcpServiceImplModule.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/dhcpservice/impl/rev150710/DhcpServiceImplModule.java index 9fbd12c8..bf453d42 100644 --- a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/dhcpservice/impl/rev150710/DhcpServiceImplModule.java +++ b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/dhcpservice/impl/rev150710/DhcpServiceImplModule.java @@ -20,6 +20,7 @@ public class DhcpServiceImplModule extends org.opendaylight.yang.gen.v1.urn.open public java.lang.AutoCloseable createInstance() { DhcpProvider dhcpProvider = new DhcpProvider(); dhcpProvider.setNotificationProviderService(getNotificationServiceDependency()); + dhcpProvider.setMdsalManager(getMdsalutilDependency()); getBrokerDependency().registerProvider(dhcpProvider); return dhcpProvider; } diff --git a/features/pom.xml b/features/pom.xml index 7ddc5bc0..80effa8f 100644 --- a/features/pom.xml +++ b/features/pom.xml @@ -29,6 +29,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL 0.2.0-SNAPSHOT 1.2.1-SNAPSHOT 0.10.0-SNAPSHOT + 0.6.0-SNAPSHOT ${vpnservices.version} ${vpnservices.version} ${vpnservices.version} @@ -107,6 +108,19 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL xml runtime + + org.opendaylight.neutron + features-neutron + features + ${neutron.version} + xml + runtime + + + org.opendaylight.neutron + dummyprovider + ${neutron.version} + ${project.groupId} vpnmanager-impl @@ -321,5 +335,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL libthrift 0.9.1 + + commons-net + commons-net + ${commons.net.version} + diff --git a/features/src/main/features/features.xml b/features/src/main/features/features.xml index c9c41ec8..fa5145bd 100644 --- a/features/src/main/features/features.xml +++ b/features/src/main/features/features.xml @@ -16,14 +16,17 @@ and is available at http://www.eclipse.org/legal/epl-v10.html mvn:org.opendaylight.openflowplugin/features-openflowplugin/${openflowplugin.version}/xml/features mvn:org.opendaylight.netconf/features-restconf/${restconf.version}/xml/features mvn:org.opendaylight.ovsdb/features-ovsdb/${ovsdb.version}/xml/features + mvn:org.opendaylight.neutron/features-neutron/${neutron.version}/xml/features odl-mdsal-broker odl-mdsal-models odl-openflowplugin-nsf-model mvn:org.opendaylight.controller/liblldp/${liblldp.version} + mvn:org.opendaylight.neutron/model/${neutron.version} mvn:org.opendaylight.vpnservice/model-bgp/{{VERSION}} mvn:org.opendaylight.vpnservice/lockmanager-api/${lockmanager.version} mvn:org.opendaylight.vpnservice/idmanager-api/${idmanager.version} + mvn:org.opendaylight.vpnservice/mdsalutil-api/${vpnservices.version} mvn:org.opendaylight.vpnservice/arputil-api/${arputil.version} mvn:org.opendaylight.vpnservice/alivenessmonitor-api/${vpnservices.version} mvn:org.opendaylight.vpnservice/vpnmanager-api/${vpnmanager.version} @@ -38,14 +41,15 @@ and is available at http://www.eclipse.org/legal/epl-v10.html odl-vpnservice-api odl-openflowplugin-southbound odl-openflowplugin-flow-services + mvn:commons-net/commons-net/${commons.net.version} mvn:org.opendaylight.vpnservice/lockmanager-impl/${lockmanager.version} mvn:org.opendaylight.vpnservice/idmanager-impl/${idmanager.version} mvn:org.opendaylight.vpnservice/bgpmanager-api/${vpnservices.version} mvn:org.opendaylight.vpnservice/bgpmanager-impl/${vpnservices.version} - mvn:org.opendaylight.vpnservice/mdsalutil-api/${interfacemgr.version} + mvn:org.opendaylight.vpnservice/mdsalutil-api/${vpnservices.version} mvn:org.opendaylight.vpnservice/arputil-impl/${arputil.version} mvn:org.opendaylight.vpnservice/alivenessmonitor-impl/${vpnservices.version} - mvn:org.opendaylight.vpnservice/mdsalutil-impl/${interfacemgr.version} + mvn:org.opendaylight.vpnservice/mdsalutil-impl/${vpnservices.version} mvn:org.opendaylight.vpnservice/interfacemgr-api/${interfacemgr.version} mvn:org.opendaylight.vpnservice/interfacemgr-impl/${interfacemgr.version} mvn:org.opendaylight.vpnservice/vpnmanager-impl/${vpnmanager.version} @@ -61,7 +65,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html mvn:org.opendaylight.vpnservice/idmanager-impl/${idmanager.version}/xml/config mvn:org.opendaylight.vpnservice/idmanager-impl/${idmanager.version}/xml/config mvn:org.opendaylight.vpnservice/bgpmanager-impl/${vpnservices.version}/xml/config - mvn:org.opendaylight.vpnservice/mdsalutil-impl/${interfacemgr.version}/xml/config + mvn:org.opendaylight.vpnservice/mdsalutil-impl/${vpnservices.version}/xml/config mvn:org.opendaylight.vpnservice/interfacemgr-impl/${interfacemgr.version}/xml/config mvn:org.opendaylight.vpnservice/arputil-impl/${arputil.version}/xml/config mvn:org.opendaylight.vpnservice/alivenessmonitor-impl/${vpnservices.version}/xml/config @@ -81,6 +85,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html odl-mdsal-xsql + odl-neutron-service + mvn:org.opendaylight.neutron/dummyprovider/${neutron.version} odl-vpnservice-impl-ui diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ARP.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ARP.java index 5f502d07..be7501ea 100644 --- a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ARP.java +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ARP.java @@ -67,10 +67,6 @@ public class ARP extends Packet { hdrFieldsMap = fieldValues; } - /** - * Constructor that sets the access level for the packet and - * creates and sets the HashMap - */ public ARP(boolean writeAccess) { super(writeAccess); fieldValues = new HashMap(); diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/Ethernet.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/Ethernet.java index 5fce3de1..da9c61c2 100644 --- a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/Ethernet.java +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/Ethernet.java @@ -35,6 +35,8 @@ public class Ethernet extends Packet { static { etherTypeClassMap = new HashMap>(); etherTypeClassMap.put(EtherTypes.ARP.shortValue(), ARP.class); + etherTypeClassMap.put(EtherTypes.LLDP.shortValue(), LLDP.class); + etherTypeClassMap.put(EtherTypes.IPv4.shortValue(), IPv4.class); // TODO: Add support for more classes here // etherTypeClassMap.put(EtherTypes.VLANTAGGED.shortValue(), IEEE8021Q.class); // etherTypeClassMap.put(EtherTypes.OLDQINQ.shortValue(), IEEE8021Q.class); @@ -64,6 +66,7 @@ public class Ethernet extends Packet { /** * Constructor that sets the access level for the packet and * creates and sets the HashMap + * @param writeAccess boolean */ public Ethernet(boolean writeAccess) { super(writeAccess); diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ICMP.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ICMP.java new file mode 100644 index 00000000..792ab47f --- /dev/null +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ICMP.java @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2013 - 2015 Cisco Systems, Inc. and others. 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.vpnservice.mdsalutil.packet; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.opendaylight.controller.liblldp.BitBufferHelper; +import org.opendaylight.controller.liblldp.BufferException; +import org.opendaylight.controller.liblldp.NetUtils; +import org.opendaylight.controller.liblldp.Packet; +import org.opendaylight.controller.liblldp.PacketException; + +/** + * Class that represents the ICMP packet objects + */ + +public class ICMP extends Packet { + private static final String TYPE = "Type"; + private static final String CODE = "Code"; + private static final String CHECKSUM = "Checksum"; + private static final String IDENTIFIER = "Identifier"; + private static final String SEQNUMBER = "SequenceNumber"; + + private static Map> fieldCoordinates = new LinkedHashMap>() { + private static final long serialVersionUID = 1L; + { + put(TYPE, new ImmutablePair(0, 8)); + put(CODE, new ImmutablePair(8, 8)); + put(CHECKSUM, new ImmutablePair(16, 16)); + put(IDENTIFIER, new ImmutablePair(32, 16)); + put(SEQNUMBER, new ImmutablePair(48, 16)); + } + }; + + /** + * Default constructor that creates and sets the hash map values + */ + public ICMP() { + super(); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + } + + /** + * Constructor that sets the access level for the packet + * @param writeAccess - boolean + */ + public ICMP(boolean writeAccess) { + super(writeAccess); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + } + + private final Map fieldValues; + + @Override + public void setHeaderField(String headerField, byte[] readValue) { + hdrFieldsMap.put(headerField, readValue); + } + + /** + * Sets the type for the current ICMP message + * + * @param type + * The ICMP message type + * @return This ICMP object + */ + public ICMP setType(byte type) { + byte[] icmpType = BitBufferHelper.toByteArray(type); + fieldValues.put(TYPE, icmpType); + return this; + } + + /** + * Returns the type field of the current ICMP packet + * + * @return The type code of the current ICMP packet + */ + public byte getType() { + return BitBufferHelper.getByte(fieldValues.get(TYPE)); + } + + /** + * Sets the ICMP code (type subtype) for the current ICMP object instance + * + * @param code + * The ICMP message type subtype + * @return This ICMP object + */ + public ICMP setCode(byte code) { + byte[] icmpCode = BitBufferHelper.toByteArray(code); + fieldValues.put(CODE, icmpCode); + return this; + } + + /** + * Gets the ICMP code (type subtype) for the current ICMP object instance + * + * @return The ICMP message type subtype + */ + public byte getCode() { + return BitBufferHelper.getByte(fieldValues.get(CODE)); + } + + /** + * Sets the ICMP checksum for the current ICMP object instance + * @param checksum - short + * @return ICMP + */ + public ICMP setChecksum(short checksum) { + byte[] icmpChecksum = BitBufferHelper.toByteArray(checksum); + fieldValues.put(CHECKSUM, icmpChecksum); + return this; + } + + /** + * Sets the ICMP identifier for the current ICMP object instance + * @param identifier - short + * @return ICMP + */ + public ICMP setIdentifier(short identifier) { + byte[] icmpIdentifier = BitBufferHelper.toByteArray(identifier); + fieldValues.put(IDENTIFIER, icmpIdentifier); + return this; + } + + /** + * Gets the ICMP identifier of the current ICMP object instance + * + * @return short - identifier + */ + + public short getIdentifier() { + return BitBufferHelper.getShort(fieldValues.get(IDENTIFIER)); + } + + /** + * Sets the ICMP sequence number for the current ICMP object instance + * @param seqNumber-short + * @return ICMP + */ + public ICMP setSequenceNumber(short seqNumber) { + byte[] icmpSeqNumber = BitBufferHelper.toByteArray(seqNumber); + fieldValues.put(SEQNUMBER, icmpSeqNumber); + return this; + } + + /** + * Gets the ICMP sequence number of the current ICMP object instance + * + * @return short - seqNumber + */ + + public short getSequenceNumber() { + return BitBufferHelper.getShort(fieldValues.get(SEQNUMBER)); + } + + /** + * Gets the header size in bits + * @return The ICMP header size in bits + */ + @Override + public int getHeaderSize() { + return 64; + } + + /** + * Computes the ICMP checksum on the serialized ICMP message + * + * @param data + * The serialized data stream + * @param start + * The byte index on the data stream from which the ICMP packet + * starts + * @return The checksum + */ + short computeChecksum(byte[] data, int start) { + int sum = 0, carry = 0, finalSum = 0; + int wordData; + int end = start + this.getHeaderSize() / NetUtils.NumBitsInAByte; + if (rawPayload != null) { + end += rawPayload.length; + } + int checksumStartByte = start + getfieldOffset(CHECKSUM) / NetUtils.NumBitsInAByte; + int even = end & ~1; + + for (int i = start; i < even; i = i + 2) { + // Skip, if the current bytes are checkSum bytes + if (i == checksumStartByte) { + continue; + } + wordData = ((data[i] << 8) & 0xFF00) + (data[i + 1] & 0xFF); + sum = sum + wordData; + } + if (even < end) { + // Add the last octet with zero padding. + wordData = (data[even] << 8) & 0xFF00; + sum = sum + wordData; + } + + carry = sum >>> 16; + finalSum = (sum & 0xFFFF) + carry; + return (short) ~((short) finalSum & 0xFFFF); + } + + @Override + protected void postSerializeCustomOperation(byte[] serializedBytes) + throws PacketException { + byte[] checkSum = BitBufferHelper + .toByteArray(computeChecksum(serializedBytes, 0)); + try { + BitBufferHelper.setBytes(serializedBytes, checkSum, + getfieldOffset(CHECKSUM), getfieldnumBits(CHECKSUM)); + } catch (BufferException e) { + throw new PacketException(e.getMessage()); + } + } + + @Override + protected void postDeserializeCustomOperation(byte[] data, int endBitOffset) { + short computedChecksum = computeChecksum(data, endBitOffset / NetUtils.NumBitsInAByte); + short actualChecksum = BitBufferHelper.getShort(fieldValues.get(CHECKSUM)); + + if (computedChecksum != actualChecksum) { + corrupted = true; + } + } + + /** + * Gets the checksum value stored + * @return the checksum + */ + public short getChecksum() { + return (BitBufferHelper.getShort(fieldValues.get(CHECKSUM))); + } +} diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IPProtocols.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IPProtocols.java new file mode 100644 index 00000000..5a02b70b --- /dev/null +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IPProtocols.java @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2013, 2015 Cisco Systems, Inc. and others. 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.vpnservice.mdsalutil.packet; + +import java.util.ArrayList; +import java.util.List; + +/** + * Enum represents the most common IP protocols numbers It provides the binding + * between IP protocol names and numbers and provides APIs to read and parse + * them in either of the two forms + * + * NOTE: Openflow 1.0 supports the IP Proto match only for ICMP, TCP and UDP + * + * references: + * http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml + */ +public enum IPProtocols { + ANY("any", -1), + HOPOPT("HOPOPT",0), + ICMP("ICMP", 1), + IGMP("IGMP",2), + GGP("GGP",3), + IPV4("IPv4",4), + ST("ST",5), + TCP("TCP", 6), + CBT("CBT",7), + EGP("EGP",8), + IGP("IGP",9), + BBNRCCMON("BBN-RCC-MON",10), + NVPII("NVP-II",11), + PUP("PUP",12), + ARGUS("ARGUS",13), + EMCON("EMCON",14), + XNET("XNET",15), + CHAOS("CHAOS",16), + UDP("UDP", 17), + MUX("MUX",18), + DCNMEAS("DCN-MEAS",19), + HMP("HMP",20), + PRM("PRM",21), + XNSIDP("XNS-IDP",22), + TRUNK1("TRUNK-1",23), + TRUNK2("TRUNK-2",24), + LEAF1("LEAF-1",25), + LEAF2("LEAF-2",26), + RDP("RDP",27), + IRTP("IRTP",28), + ISOTP4("ISO-TP4",29), + NETBLT("NETBLT",30), + MFENSP("MFE-NSP",31), + MERITINP("MERIT-INP",32), + DCCP("DCCP",33), + THREEPC("3PC",34), + IDPR("IDPR",35), + XTP("XTP",36), + DDP("DDP",37), + IDPRCMTP("IDPR-CMTP",38), + TPPLUSPLUS("TP++",39), + IL("IL",40), + IPV6("IPv6",41), + SDRP("SDRP",42), + IPV6Route("IPv6-Route",43), + IPV6Frag("IPv6-Frag",44), + IDRP("IDRP",45), + RSVP("RSVP",46), + GRE("GRE",47), + DSR("DSR",48), + BNA("BNA",49), + ESP("ESP",50), + AH("AH",51), + INLSP("I-NLSP",52), + SWIPE("SWIPE",53), + NARP("NARP",54), + MOBILE("MOBILE",55), + TLSP("TLSP",56), + SKIP("SKIP",57), + IPV6ICMP("IPv6-ICMP", 58), + IPV6NoNxt("IPv6-NoNxt",59), + IPV6Opts("IPv6-Opts",60), + ANYHOST("ANY-HOST",61), + CFTP("CFTP",62), + ANYNETWORK("ANY-NETWORK",63), + SATEXPAK("SAT-EXPAK",64), + KRYPTOLAN("KRYPTOLAN",65), + RVD("RVD",66), + IPPC("IPPC",67), + ANYDISTFS("ANY-DIST-FS",68), + SATMON("SAT-MON",69), + VISA("VISA",70), + IPCV("IPCV",71), + CPNX("CPNX",72), + CPHB("CPHB",73), + WSN("WSN",74), + PVP("PVP",75), + BRSATMON("BR-SAT-MON",76), + SUNND("SUN-ND",77), + WBMON("WB-MON",78), + WBEXPAK("WB-EXPAK",79), + ISOIP("ISO-IP",80), + VMTP("VMTP",81), + SECUREVMTP("SECURE-VMTP",82), + VINES("VINES",83), + TTP("TTP",84), + IPTM("IPTM",84), + NSFNETIGP("NSFNET-IGP",85), + DGP("DGP",86), + TCF("TCF",87), + EIGRP("EIGRP",88), + OSPFIGP("OSPFIGP",89), + SPRITERPC("Sprite-RPC",90), + LARP("LARP",91), + MTP("MTP",92), + AX25("AX.25",93), + IPIP("IPIP",94), + MICP("MICP",95), + SCCSP("SCC-SP",96), + ETHERIP("ETHERIP",97), + ENCAP("ENCAP",98), + ANYENC("ANY-ENC",99), + GMTP("GMTP",100), + IFMP("IFMP",101), + PNNI("PNNI",102), + PIM("PIM",103), + ARIS("ARIS",104), + SCPS("SCPS",105), + QNX("QNX",106), + AN("A/N",107), + IPComp("IPComp",108), + SNP("SNP",109), + COMPAQPEER("Compaq-Peer",110), + IPXINIP("IPX-in-IP",111), + VRRP("VRRP",112), + PGM("PGM",113), + ANY0HOP("ANY-0-HOP",114), + L2TP("L2TP",115), + DDX("DDX",116), + IATP("IATP",117), + STP("STP",118), + SRP("SRP",119), + UTI("UTI",120), + SMP("SMP",121), + SM("SM",122), + PTP("PTP",123), + ISIS("ISIS",124), + FIRE("FIRE",125), + CRTP("CRTP",126), + CRUDP("CRUDP",127), + SSCOPMCE("SSCOPMCE",128), + IPLT("IPLT",129), + SPS("SPS",130), + PIPE("PIPE",131), + SCTP("SCTP",132), + FC("FC",133), + RSVPE2EIGNORE("RSVP-E2E-IGNORE",134), + MOBILITYHEADER("Mobility Header",135), + UDPLITE("UDPLite",136), + MPLSINIP("MPLS-in-IP",137), + MANET("MANET",138), + HIP("HIP",139), + SHIM6("Shim6",140), + WESP("WESP",141), + ROHC("ROHC",142), + /*143-252 Unassigned by IANA*/ + + //Experimebtal protocol numbers (http://tools.ietf.org/html/rfc3692) + EXP1("Experimental1", 253), + EXP2("Experimental2", 254), + + RESERVED("RESERVED",255); + + private String protocolName; + private int protocolNumber; + + private IPProtocols(String name, int number) { + protocolName = name; + protocolNumber = number; + } + + public int intValue() { + return protocolNumber; + } + + public short shortValue() { + return ((Integer) protocolNumber).shortValue(); + } + + public byte byteValue() { + return ((Integer) protocolNumber).byteValue(); + } + + @Override + public String toString() { + return protocolName; + } + + public static String getProtocolName(int number) { + return getProtocolNameInternal(number); + } + + public static String getProtocolName(short number) { + return getProtocolNameInternal(number & 0xffff); + } + + public static String getProtocolName(byte number) { + return getProtocolNameInternal(number & 0xff); + } + + private static String getProtocolNameInternal(int number) { + for (IPProtocols proto : IPProtocols.values()) { + if (proto.protocolNumber == number) { + return proto.toString(); + } + } + //TODO: this is for backwards compatibility + return "0x" + Integer.toHexString(number); + } + + public static short getProtocolNumberShort(String name) { + IPProtocols p = fromString(name); + if (p != null) { + return p.shortValue(); + } + //This method should be called after validation only + throw new IllegalArgumentException("Illegal IP protocol value: " + name); + } + + public static int getProtocolNumberInt(String name) { + IPProtocols p = fromString(name); + if (p != null) { + return p.intValue(); + } + //This method should be called after validation only + throw new IllegalArgumentException("Illegal IP protocol value: " + name); + } + + public static byte getProtocolNumberByte(String name) { + IPProtocols p = fromString(name); + if (p != null) { + return p.byteValue(); + } + //This method should be called after validation only + throw new IllegalArgumentException("Illegal IP protocol value: " + name); + } + + public static List getProtocolNameList() { + List protoList = new ArrayList(); + for (IPProtocols proto : IPProtocols.values()) { + protoList.add(proto.toString()); + } + return protoList; + } + + /** + * Method to parse an IPProtocol from a numeric string + * + * @param s + * The IP protocol string to be parsed + * @return The IP protocol Enum, or null if invalid protocol string is passed + */ + public static IPProtocols fromString(String s) { + // null/empty/any/* evaluates to ANY + if (s == null || s.isEmpty() || s.equalsIgnoreCase("any") || s.equals("*")) { + return IPProtocols.ANY; + } + + // Try parsing numeric and find the related ENUM + try { + int protoNum = Integer.decode(s); + for (IPProtocols protoEnum : IPProtocols.values()) { + if (protoEnum.protocolNumber == protoNum) { + return protoEnum; + } + } + // At this point it's an invalid number (i.e. out of range or not a valid proto num) + return null; + } catch (NumberFormatException nfe) { + // numeric failed try by NAME + try { + return valueOf(s); + } catch(IllegalArgumentException e) { + // Neither numeric nor enum NAME, attempt human readable name + for (IPProtocols protoEnum : IPProtocols.values()) { + if (protoEnum.toString().equalsIgnoreCase(s)) { + return protoEnum; + } + } + //couldn't parse, signifies an invalid proto field! + return null; + } + + } + } +} diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IPv4.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IPv4.java new file mode 100644 index 00000000..2bc29a84 --- /dev/null +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IPv4.java @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2013 - 2015 Cisco Systems, Inc. and others. 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.vpnservice.mdsalutil.packet; + +import java.net.InetAddress; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Random; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.opendaylight.controller.liblldp.BitBufferHelper; +import org.opendaylight.controller.liblldp.BufferException; +import org.opendaylight.controller.liblldp.NetUtils; +import org.opendaylight.controller.liblldp.Packet; +import org.opendaylight.controller.liblldp.PacketException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class that represents the IPv4 packet objects + */ + +public class IPv4 extends Packet { + protected static final Logger logger = LoggerFactory + .getLogger(IPv4.class); + private static final String VERSION = "Version"; + private static final String HEADERLENGTH = "HeaderLength"; + private static final String DIFFSERV = "DiffServ"; + private static final String ECN = "ECN"; + private static final String TOTLENGTH = "TotalLength"; + private static final String IDENTIFICATION = "Identification"; + private static final String FLAGS = "Flags"; + private static final String FRAGOFFSET = "FragmentOffset"; + private static final String TTL = "TTL"; + private static final String PROTOCOL = "Protocol"; + private static final String CHECKSUM = "Checksum"; + private static final String SIP = "SourceIPAddress"; + private static final String DIP = "DestinationIPAddress"; + private static final String OPTIONS = "Options"; + + private static final int UNIT_SIZE_SHIFT = 2; + private static final int UNIT_SIZE = (1 << UNIT_SIZE_SHIFT); + private static final int MIN_HEADER_SIZE = 20; + + public static final Map> protocolClassMap; + static { + protocolClassMap = new HashMap>(); + protocolClassMap.put(IPProtocols.ICMP.byteValue(), ICMP.class); + protocolClassMap.put(IPProtocols.UDP.byteValue(), UDP.class); + protocolClassMap.put(IPProtocols.TCP.byteValue(), TCP.class); + } + private static Map> fieldCoordinates = new LinkedHashMap>() { + private static final long serialVersionUID = 1L; + { + put(VERSION, new ImmutablePair(0, 4)); + put(HEADERLENGTH, new ImmutablePair(4, 4)); + put(DIFFSERV, new ImmutablePair(8, 6)); + put(ECN, new ImmutablePair(14, 2)); + put(TOTLENGTH, new ImmutablePair(16, 16)); + put(IDENTIFICATION, new ImmutablePair(32, 16)); + put(FLAGS, new ImmutablePair(48, 3)); + put(FRAGOFFSET, new ImmutablePair(51, 13)); + put(TTL, new ImmutablePair(64, 8)); + put(PROTOCOL, new ImmutablePair(72, 8)); + put(CHECKSUM, new ImmutablePair(80, 16)); + put(SIP, new ImmutablePair(96, 32)); + put(DIP, new ImmutablePair(128, 32)); + put(OPTIONS, new ImmutablePair(160, 0)); + } + }; + + private final Map fieldValues; + + + /** + * Default constructor that sets the version to 4, headerLength to 5, + * and flags to 2. The default value for the identification is set to a + * random number and the remaining fields are set to 0. + */ + public IPv4() { + super(); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + corrupted = false; + + setVersion((byte) 4); + setHeaderLength((byte) 5); + setDiffServ((byte) 0); + setECN((byte) 0); + setIdentification(generateId()); + setFlags((byte) 2); + setFragmentOffset((short) 0); + } + + /** + * The write access to the packet is set in this constructor. + * Constructor that sets the version to 4, headerLength to 5, + * and flags to 2. The default value for the identification is set to a + * random number and the remaining fields are set to 0. + * @param writeAccess - boolean + */ + public IPv4(boolean writeAccess) { + super(writeAccess); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + corrupted = false; + + setVersion((byte) 4); + setHeaderLength((byte) 5); + setDiffServ((byte) 0); + setECN((byte) 0); + setIdentification(generateId()); + setFlags((byte) 2); + setFragmentOffset((short) 0); + } + + /** + * Gets the IP version stored + * @return the version + */ + public byte getVersion() { + return (BitBufferHelper.getByte(fieldValues.get(VERSION))); + } + + /** + * Gets the IP header length stored + * @return the headerLength in bytes + */ + public int getHeaderLen() { + return (4 * BitBufferHelper.getByte(fieldValues.get(HEADERLENGTH))); + } + + /** + * Gets the header size in bits + * @return The number of bits constituting the header + */ + @Override + public int getHeaderSize() { + int headerLen = this.getHeaderLen(); + if (headerLen == 0) { + headerLen = MIN_HEADER_SIZE; + } + + return headerLen * NetUtils.NumBitsInAByte; + } + + /** + * Gets the differential services value stored + * @return the diffServ + */ + public byte getDiffServ() { + return BitBufferHelper.getByte(fieldValues.get(DIFFSERV)); + } + + /** + * Gets the ecn bits stored + * @return the ecn bits + */ + public byte getECN() { + return BitBufferHelper.getByte(fieldValues.get(ECN)); + } + + /** + * Gets the total length of the IP header in bytes + * @return the totalLength + */ + public short getTotalLength() { + return (BitBufferHelper.getShort(fieldValues.get(TOTLENGTH))); + } + + /** + * Gets the identification value stored + * @return the identification + */ + public short getIdentification() { + return (BitBufferHelper.getShort(fieldValues.get(IDENTIFICATION))); + } + + /** + * Gets the flag values stored + * @return the flags + */ + public byte getFlags() { + return (BitBufferHelper.getByte(fieldValues.get(FLAGS))); + } + + /** + * Gets the TTL value stored + * @return the ttl + */ + public byte getTtl() { + return (BitBufferHelper.getByte(fieldValues.get(TTL))); + } + + /** + * Gets the protocol value stored + * @return the protocol + */ + public byte getProtocol() { + return (BitBufferHelper.getByte(fieldValues.get(PROTOCOL))); + } + + /** + * Gets the checksum value stored + * @return the checksum + */ + public short getChecksum() { + return (BitBufferHelper.getShort(fieldValues.get(CHECKSUM))); + } + + /** + * Gets the fragment offset stored + * @return the fragmentOffset + */ + public short getFragmentOffset() { + return (BitBufferHelper.getShort(fieldValues.get(FRAGOFFSET))); + } + + /** + * Gets the source IP address stored + * @return the sourceAddress + */ + public int getSourceAddress() { + return (BitBufferHelper.getInt(fieldValues.get(SIP))); + } + + /** + * Gets the destination IP address stored + * @return the destinationAddress + */ + public int getDestinationAddress() { + return (BitBufferHelper.getInt(fieldValues.get(DIP))); + } + + /** + * gets the Options stored + * @return the options + */ + public byte[] getOptions() { + return (fieldValues.get(OPTIONS)); + } + + @Override + /** + * Stores the value of fields read from data stream + * Variable header value like payload protocol, is stored here + * @param headerField + * @param readValue + */ + public void setHeaderField(String headerField, byte[] readValue) { + if (headerField.equals(PROTOCOL)) { + // Don't set payloadClass if framgment offset is not zero. + byte[] fragoff = hdrFieldsMap.get(FRAGOFFSET); + if (fragoff == null || BitBufferHelper.getShort(fragoff) == 0) { + payloadClass = protocolClassMap.get(readValue[0]); + } + } else if (headerField.equals(FRAGOFFSET)) { + if (readValue != null && BitBufferHelper.getShort(readValue) != 0) { + // Clear payloadClass because protocol header is not present + // in this packet. + payloadClass = null; + } + } else if (headerField.equals(OPTIONS) && + (readValue == null || readValue.length == 0)) { + hdrFieldsMap.remove(headerField); + return; + } + hdrFieldsMap.put(headerField, readValue); + } + + /** + * Stores the IP version from the header + * @param ipVersion the version to set + * @return IPv4 + */ + public IPv4 setVersion(byte ipVersion) { + byte[] version = BitBufferHelper.toByteArray(ipVersion); + fieldValues.put(VERSION, version); + return this; + } + + /** + * Stores the length of IP header in words (4 bytes) + * @param ipheaderLength the headerLength to set + * @return IPv4 + */ + public IPv4 setHeaderLength(byte ipheaderLength) { + byte[] headerLength = BitBufferHelper.toByteArray(ipheaderLength); + fieldValues.put(HEADERLENGTH, headerLength); + return this; + } + + /** + * Stores the differential services value from the IP header + * @param ipdiffServ the diffServ to set + * @return IPv4 + */ + public IPv4 setDiffServ(byte ipdiffServ) { + byte[] diffServ = BitBufferHelper.toByteArray(ipdiffServ); + fieldValues.put(DIFFSERV, diffServ); + return this; + } + + /** + * Stores the ECN bits from the header + * @param ecn ECN bits to set + * @return IPv4 + */ + public IPv4 setECN(byte ecn) { + byte[] ecnbytes = BitBufferHelper.toByteArray(ecn); + fieldValues.put(ECN, ecnbytes); + return this; + } + + /** + * Stores the total length of IP header in bytes + * @param iptotalLength the totalLength to set + * @return IPv4 + */ + public IPv4 setTotalLength(short iptotalLength) { + byte[] totalLength = BitBufferHelper.toByteArray(iptotalLength); + fieldValues.put(TOTLENGTH, totalLength); + return this; + } + + /** + * Stores the identification number from the header + * @param ipIdentification the identification to set + * @return IPv4 + */ + public IPv4 setIdentification(short ipIdentification) { + byte[] identification = BitBufferHelper.toByteArray(ipIdentification); + fieldValues.put(IDENTIFICATION, identification); + return this; + } + + /** + * Stores the IP flags value + * @param ipFlags the flags to set + * @return IPv4 + */ + public IPv4 setFlags(byte ipFlags) { + byte[] flags = { ipFlags }; + fieldValues.put(FLAGS, flags); + return this; + } + + /** + * Stores the IP fragmentation offset value + * @param ipFragmentOffset the fragmentOffset to set + * @return IPv4 + */ + public IPv4 setFragmentOffset(short ipFragmentOffset) { + byte[] fragmentOffset = BitBufferHelper.toByteArray(ipFragmentOffset); + fieldValues.put(FRAGOFFSET, fragmentOffset); + return this; + } + + /** + * Stores the TTL value + * @param ipTtl the ttl to set + * @return IPv4 + */ + public IPv4 setTtl(byte ipTtl) { + byte[] ttl = BitBufferHelper.toByteArray(ipTtl); + fieldValues.put(TTL, ttl); + return this; + } + + /** + * Stores the protocol value of the IP payload + * @param ipProtocol the protocol to set + * @return IPv4 + */ + public IPv4 setProtocol(byte ipProtocol) { + byte[] protocol = BitBufferHelper.toByteArray(ipProtocol); + fieldValues.put(PROTOCOL, protocol); + return this; + } + + /** + * @param checksum the checksum to set + */ + /*public IPv4 setChecksum() { + short ipChecksum = computeChecksum(); + byte[] checksum = BitBufferHelper.toByteArray(ipChecksum); + fieldValues.put(CHECKSUM, checksum); + return this; + }*/ + + /** + * Stores the IP source address from the header + * @param ipSourceAddress the sourceAddress to set + * @return IPv4 + */ + public IPv4 setSourceAddress(InetAddress ipSourceAddress) { + byte[] sourceAddress = ipSourceAddress.getAddress(); + fieldValues.put(SIP, sourceAddress); + return this; + } + + /** + * Stores the IP destination address from the header + * @param ipDestinationAddress the destination Address to set + * @return IPv4 + */ + public IPv4 setDestinationAddress(InetAddress ipDestinationAddress) { + byte[] sourceAddress = ipDestinationAddress.getAddress(); + fieldValues.put(DIP, sourceAddress); + return this; + } + + /** + * Stores the IP destination address from the header + * @param ipDestinationAddress the destinationAddress to set + * @return IPv4 + */ + public IPv4 setDestinationAddress(int ipDestinationAddress) { + byte[] destinationAddress = BitBufferHelper + .toByteArray(ipDestinationAddress); + fieldValues.put(DIP, destinationAddress); + return this; + } + + /** + * Generate a random number to set the Identification field + * in IPv4 Header + * @return short + */ + private short generateId() { + Random randomgen = new Random(); + return (short) (randomgen.nextInt(Short.MAX_VALUE + 1)); + } + + /** + * Store the options from IP header + * @param options - byte[] + * @return IPv4 + */ + public IPv4 setOptions(byte[] options) { + byte newIHL = (byte)(MIN_HEADER_SIZE >>> UNIT_SIZE_SHIFT); + if (options == null || options.length == 0) { + fieldValues.remove(OPTIONS); + } else { + int len = options.length; + int rlen = (len + (UNIT_SIZE - 1)) & ~(UNIT_SIZE - 1); + if (rlen > len) { + // Padding is required. + byte[] newopt = new byte[rlen]; + System.arraycopy(options, 0, newopt, 0, len); + options = newopt; + len = rlen; + } + fieldValues.put(OPTIONS, options); + newIHL += (len >>> UNIT_SIZE_SHIFT); + } + + setHeaderLength(newIHL); + + return this; + } + + /** + * Computes the IPv4 header checksum on the passed stream of bytes + * representing the packet + * + * @param data + * The byte stream + * @param offset + * The byte offset from where the IPv4 packet starts + * @return The computed checksum + */ + short computeChecksum(byte[] data, int start) { + int end = start + getHeaderLen(); + short checkSum = (short) 0; + int sum = 0, carry = 0, finalSum = 0; + int wordData; + int checksumStart = start + + (getfieldOffset(CHECKSUM) / NetUtils.NumBitsInAByte); + + for (int i = start; i <= (end - 1); i = i + 2) { + // Skip, if the current bytes are checkSum bytes + if (i == checksumStart) { + continue; + } + wordData = ((data[i] << 8) & 0xFF00) + (data[i + 1] & 0xFF); + sum = sum + wordData; + } + carry = (sum >> 16) & 0xFF; + finalSum = (sum & 0xFFFF) + carry; + checkSum = (short) ~((short) finalSum & 0xFFFF); + + return checkSum; + } + + @Override + /** + * Gets the number of bits for the fieldname specified + * If the fieldname has variable length like "Options", then this value is computed using the header length + * @param fieldname - String + * @return number of bits for fieldname - int + */ + public int getfieldnumBits(String fieldName) { + if (fieldName.equals(OPTIONS)) { + return (getHeaderLen() - MIN_HEADER_SIZE) * NetUtils.NumBitsInAByte; + } + return hdrFieldCoordMap.get(fieldName).getRight(); + } + + @Override + /** + * Method to perform post serialization - like computation of checksum of serialized header + * @param data + * @return void + * @Exception throws PacketException + */ + protected void postSerializeCustomOperation(byte[] data) + throws PacketException { + + // Recompute the total length field here + byte[] totalLength = BitBufferHelper.toByteArray((short) data.length); + try { + BitBufferHelper.setBytes(data, totalLength, getfieldOffset(TOTLENGTH), + getfieldnumBits(TOTLENGTH)); + } catch (BufferException e) { + throw new PacketException(e.getMessage()); + } + + // Now compute the Header Checksum + byte[] checkSum = BitBufferHelper.toByteArray(computeChecksum(data, 0)); + + try { + BitBufferHelper.setBytes(data, checkSum, getfieldOffset(CHECKSUM), + getfieldnumBits(CHECKSUM)); + } catch (BufferException e) { + throw new PacketException(e.getMessage()); + } + } + + @Override + /** + * Stores the payload of IP, serializes it and stores the length of serialized payload + * bytes in Total Length + * @param payload - Packet + */ + /** + * Set the total length field in the IPv4 Object + * Note: this field will get overwritten during serialization phase. + */ + public void setPayload(Packet payload) { + this.payload = payload; + /* + * Deriving the Total Length here + */ + int payloadLength = 0; + if (payload != null) { + try { + payloadLength = payload.serialize().length; + } catch (PacketException e) { + logger.error("", e); + } + } + + this.setTotalLength((short) (this.getHeaderLen() + payloadLength)); + } + + + /** + * Method to perform post deserialization - like compare computed checksum with + * the one obtained from IP header + */ + @Override + protected void postDeserializeCustomOperation(byte[] data, int startBitOffset) { + int start = startBitOffset / NetUtils.NumBitsInAByte; + short computedChecksum = computeChecksum(data, start); + short actualChecksum = BitBufferHelper.getShort(fieldValues.get(CHECKSUM)); + if (computedChecksum != actualChecksum) { + corrupted = true; + } + } + +} diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/TCP.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/TCP.java new file mode 100644 index 00000000..1d582da7 --- /dev/null +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/TCP.java @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2013 - 2015 Cisco Systems, Inc. and others. 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.vpnservice.mdsalutil.packet; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.opendaylight.controller.liblldp.BitBufferHelper; +import org.opendaylight.controller.liblldp.Packet; + +/** + * Class that represents the TCP segment objects + */ +public class TCP extends Packet { + + public static final String SRCPORT = "SourcePort"; + public static final String DESTPORT = "DestinationPort"; + public static final String SEQNUMBER = "SequenceNumber"; + public static final String ACKNUMBER = "AcknowledgementNumber"; + public static final String DATAOFFSET = "DataOffset"; + public static final String RESERVED = "Reserved"; + public static final String HEADERLENFLAGS = "HeaderLenFlags"; + public static final String WINDOWSIZE = "WindowSize"; + public static final String CHECKSUM = "Checksum"; + public static final String URGENTPOINTER = "UrgentPointer"; + + private static Map> fieldCoordinates = new LinkedHashMap>() { + private static final long serialVersionUID = 1L; + { + put(SRCPORT, new ImmutablePair(0, 16)); + put(DESTPORT, new ImmutablePair(16, 16)); + put(SEQNUMBER, new ImmutablePair(32, 32)); + put(ACKNUMBER, new ImmutablePair(64, 32)); + put(DATAOFFSET, new ImmutablePair(96, 4)); + put(RESERVED, new ImmutablePair(100, 3)); + put(HEADERLENFLAGS, new ImmutablePair(103, 9)); + put(WINDOWSIZE, new ImmutablePair(112, 16)); + put(CHECKSUM, new ImmutablePair(128, 16)); + put(URGENTPOINTER, new ImmutablePair(144, 16)); + } + }; + + private final Map fieldValues; + + /** + * Default constructor that sets all the header fields to zero + */ + public TCP() { + super(); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + /* Setting all remaining header field values to + * default value of 0. These maybe changed as needed + */ + setSourcePort((short) 0); + setDestinationPort((short) 0); + setSequenceNumber(0); + setAckNumber(0); + setDataOffset((byte) 0); + setReserved((byte) 0); + setWindowSize((short) 0); + setUrgentPointer((short) 0); + setChecksum((short) 0); + } + + /** + * Constructor that sets the access level for the packet and + * sets all the header fields to zero. + * @param writeAccess - boolean + */ + public TCP(boolean writeAccess) { + super(writeAccess); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + /* Setting all remaining header field values to + * default value of 0. These maybe changed as needed + */ + setSourcePort((short) 0); + setDestinationPort((short) 0); + setSequenceNumber(0); + setAckNumber(0); + setDataOffset((byte) 0); + setReserved((byte) 0); + setWindowSize((short) 0); + setUrgentPointer((short) 0); + setChecksum((short) 0); + } + + @Override + /** + * Stores the value read from data stream + * @param headerField - String + * @param readValue - byte[] + */ + public void setHeaderField(String headerField, byte[] readValue) { + hdrFieldsMap.put(headerField, readValue); + } + + /** + * Sets the TCP source port for the current TCP object instance + * @param tcpSourcePort short + * @return TCP + */ + public TCP setSourcePort(short tcpSourcePort) { + byte[] sourcePort = BitBufferHelper.toByteArray(tcpSourcePort); + fieldValues.put(SRCPORT, sourcePort); + return this; + } + + /** + * Sets the TCP destination port for the current TCP object instance + * @param tcpDestinationPort short + * @return TCP + */ + public TCP setDestinationPort(short tcpDestinationPort) { + byte[] destinationPort = BitBufferHelper + .toByteArray(tcpDestinationPort); + fieldValues.put(DESTPORT, destinationPort); + return this; + } + + /** + * Sets the TCP sequence number for the current TCP object instance + * @param tcpSequenceNumber - int + * @return TCP + */ + public TCP setSequenceNumber(int tcpSequenceNumber) { + byte[] sequenceNumber = BitBufferHelper.toByteArray(tcpSequenceNumber); + fieldValues.put(SEQNUMBER, sequenceNumber); + return this; + } + + /** + * Sets the TCP data offset for the current TCP object instance + * @param tcpDataOffset - byte + * @return TCP + */ + public TCP setDataOffset(byte tcpDataOffset) { + byte[] offset = BitBufferHelper.toByteArray(tcpDataOffset); + fieldValues.put("DataOffset", offset); + return this; + } + + /** + * Sets the TCP reserved bits for the current TCP object instance + * @param tcpReserved byte + * @return TCP + */ + public TCP setReserved(byte tcpReserved) { + byte[] reserved = BitBufferHelper.toByteArray(tcpReserved); + fieldValues.put("Reserved", reserved); + return this; + } + + /** + * Sets the TCP Ack number for the current TCP object instance + * @param tcpAckNumber int + * @return TCP + */ + public TCP setAckNumber(int tcpAckNumber) { + byte[] ackNumber = BitBufferHelper.toByteArray(tcpAckNumber); + fieldValues.put(ACKNUMBER, ackNumber); + return this; + } + + /** + * Sets the TCP flags for the current TCP object instance + * @param tcpFlags short + * @return TCP + */ + public TCP setHeaderLenFlags(short tcpFlags) { + byte[] headerLenFlags = BitBufferHelper.toByteArray(tcpFlags); + fieldValues.put(HEADERLENFLAGS, headerLenFlags); + return this; + } + + /** + * Sets the TCP window size for the current TCP object instance + * @param tcpWsize short + * @return TCP + */ + public TCP setWindowSize(short tcpWsize) { + byte[] wsize = BitBufferHelper.toByteArray(tcpWsize); + fieldValues.put(WINDOWSIZE, wsize); + return this; + } + + /** + * Sets the TCP checksum for the current TCP object instance + * @param tcpChecksum short + * @return TCP + */ + public TCP setChecksum(short tcpChecksum) { + byte[] checksum = BitBufferHelper.toByteArray(tcpChecksum); + fieldValues.put(CHECKSUM, checksum); + return this; + } + + /** + * Sets the TCP Urgent Pointer for the current TCP object instance + * @param tcpUrgentPointer short + * @return TCP + */ + public TCP setUrgentPointer(short tcpUrgentPointer) { + byte[] urgentPointer = BitBufferHelper.toByteArray(tcpUrgentPointer); + fieldValues.put(URGENTPOINTER, urgentPointer); + return this; + } + + /** + * Gets the stored source port value of TCP header + * @return the sourcePort + */ + public short getSourcePort() { + return (BitBufferHelper.getShort(fieldValues.get(SRCPORT))); + } + + /** + * Gets the stored destination port value of TCP header + * @return the destinationPort + */ + public short getDestinationPort() { + return (BitBufferHelper.getShort(fieldValues.get(DESTPORT))); + } + + /** + * Get the stored checksum value of the TCP header + * @return short - the checksum + */ + public short getChecksum() { + return (BitBufferHelper.getShort(fieldValues.get(CHECKSUM))); + } + +} diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/UDP.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/UDP.java new file mode 100644 index 00000000..b8c7367f --- /dev/null +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/UDP.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2013 - 2015 Cisco Systems, Inc. and others. 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.vpnservice.mdsalutil.packet; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.opendaylight.controller.liblldp.BitBufferHelper; +import org.opendaylight.controller.liblldp.Packet; + +/** + * Class that represents the UDP datagram objects + */ + +public class UDP extends Packet { + + private static final String SRCPORT = "SourcePort"; + private static final String DESTPORT = "DestinationPort"; + private static final String LENGTH = "Length"; + private static final String CHECKSUM = "Checksum"; + + private static Map> fieldCoordinates = new LinkedHashMap>() { + private static final long serialVersionUID = 1L; + { + put(SRCPORT, new ImmutablePair(0, 16)); + put(DESTPORT, new ImmutablePair(16, 16)); + put(LENGTH, new ImmutablePair(32, 16)); + put(CHECKSUM, new ImmutablePair(48, 16)); + } + }; + + public UDP() { + super(); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + /* Setting all remaining header field values to + * default value of 0. These maybe changed as needed + */ + setSourcePort((short) 0); + setDestinationPort((short) 0); + setChecksum((short) 0); + } + + public UDP(boolean writeAccess) { + super(writeAccess); + fieldValues = new HashMap(); + hdrFieldCoordMap = fieldCoordinates; + hdrFieldsMap = fieldValues; + /* Setting all remaining header field values to + * default value of 0. These maybe changed as needed + */ + setSourcePort((short) 0); + setDestinationPort((short) 0); + setChecksum((short) 0); + } + + private final Map fieldValues; + + /* public static Map> decodeMap; + + static { + decodeMap = new HashMap>(); + UDP.decodeMap.put((short)67, DHCP.class); + UDP.decodeMap.put((short)68, DHCP.class); + }*/ + /** + * Get the stored source port + * @return short - the sourcePort + */ + public short getSourcePort() { + return (BitBufferHelper.getShort(fieldValues.get(SRCPORT))); + } + + /** + * Get the stored destination port + * @return short - the destinationPort + */ + public short getDestinationPort() { + return (BitBufferHelper.getShort(fieldValues.get(DESTPORT))); + } + + /** + * Gets the stored length of UDP header + * @return short - the length + */ + public short getLength() { + return (BitBufferHelper.getShort(fieldValues.get(LENGTH))); + } + + /** + * Get the stored checksum value of the UDP header + * @return short - the checksum + */ + public short getChecksum() { + return (BitBufferHelper.getShort(fieldValues.get(CHECKSUM))); + } + + @Override + /** + * Store the value read from data stream in hdrFieldMap + */ + public void setHeaderField(String headerField, byte[] readValue) { + hdrFieldsMap.put(headerField, readValue); + } + + /** + * Sets the sourcePort value for the current UDP object instance + * @param udpSourcePort short source port to set + * @return UDP + */ + public UDP setSourcePort(short udpSourcePort) { + byte[] sourcePort = BitBufferHelper.toByteArray(udpSourcePort); + fieldValues.put(SRCPORT, sourcePort); + return this; + } + + /** + * Sets the destinationPort value for the current UDP object instance + * @param udpDestinationPort short destination port to set + * @return UDP + */ + public UDP setDestinationPort(short udpDestinationPort) { + byte[] destinationPort = BitBufferHelper + .toByteArray(udpDestinationPort); + fieldValues.put(DESTPORT, destinationPort); + return this; + } + + /** + * Set the UDP header length value for the current UDP object instance + * @param udpLength - short - the length to set + * @return UDP + */ + public UDP setLength(short udpLength) { + byte[] length = BitBufferHelper.toByteArray(udpLength); + fieldValues.put(LENGTH, length); + return this; + } + + /** + * Set the checksum for the current UDP object instance + * @param udpChecksum - short - the checksum to set + * @return UDP + */ + public UDP setChecksum(short udpChecksum) { + byte[] checksum = BitBufferHelper.toByteArray(udpChecksum); + fieldValues.put(CHECKSUM, checksum); + return this; + } + +} -- 2.36.6