Add pkt handling to DHCPService 01/31201/4
authorVishal Thapar <vishal.thapar@ericsson.com>
Fri, 11 Dec 2015 12:01:25 +0000 (17:31 +0530)
committerVishal Thapar <vishal.thapar@ericsson.com>
Mon, 14 Dec 2015 15:27:37 +0000 (20:57 +0530)
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 <vishal.thapar@ericsson.com>
18 files changed:
dhcpservice/dhcpservice-api/pom.xml
dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCP.java [new file with mode: 0644]
dhcpservice/dhcpservice-api/src/main/java/org/opendaylight/vpnservice/dhcpservice/api/DHCPOptions.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInfo.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpManager.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpPktHandler.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpProvider.java
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/NodeListener.java [new file with mode: 0644]
dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/dhcpservice/impl/rev150710/DhcpServiceImplModule.java
features/pom.xml
features/src/main/features/features.xml
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ARP.java
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/Ethernet.java
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/ICMP.java [new file with mode: 0644]
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IPProtocols.java [new file with mode: 0644]
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/IPv4.java [new file with mode: 0644]
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/TCP.java [new file with mode: 0644]
mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/mdsalutil/packet/UDP.java [new file with mode: 0644]

index f40230dcfd04266f51b189f9c96999b2d74ba488..e725c3d36c0902689d2cedc798791235664efc99 100644 (file)
@@ -19,5 +19,23 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   <artifactId>dhcpservice-api</artifactId>
   <version>${vpnservices.version}</version>
   <packaging>bundle</packaging>
-
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.mdsal</groupId>
+      <artifactId>yang-binding</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>yang-ext</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.mdsal.model</groupId>
+      <artifactId>iana-if-type-2014-05-08</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>mdsalutil-api</artifactId>
+      <version>${vpnservices.version}</version>
+    </dependency>
+  </dependencies>
 </project>
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 (file)
index 0000000..a226771
--- /dev/null
@@ -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<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
+        private static final long serialVersionUID = 1L;
+        {
+            put(OP, new ImmutablePair<Integer, Integer>(0, 8));
+            put(HTYPE, new ImmutablePair<Integer, Integer>(8, 8));
+            put(HLEN, new ImmutablePair<Integer, Integer>(16, 8));
+            put(HOPS, new ImmutablePair<Integer, Integer>(24, 8));
+            put(XID, new ImmutablePair<Integer, Integer>(32, 32));
+            put(SECS, new ImmutablePair<Integer, Integer>(64, 16));
+            put(FLAGS, new ImmutablePair<Integer, Integer>(80, 16));
+            put(CIADDR, new ImmutablePair<Integer, Integer>(96, 32));
+            put(YIADDR, new ImmutablePair<Integer, Integer>(128, 32));
+            put(SIADDR, new ImmutablePair<Integer, Integer>(160, 32));
+            put(GIADDR, new ImmutablePair<Integer, Integer>(192, 32));
+            put(CHADDR, new ImmutablePair<Integer, Integer>(224, 128));
+            put(SNAME, new ImmutablePair<Integer, Integer>(352, 512));
+            put(FILE, new ImmutablePair<Integer, Integer>(864, 1024));
+            put(MCOOKIE, new ImmutablePair<Integer, Integer>(1888, 32));
+            put(OPTIONS, new ImmutablePair<Integer, Integer>(1920, 0));
+        }
+    };
+
+    private final Map<String, byte[]> fieldValues;
+
+    public DHCP() {
+        this(false);
+    }
+
+    public DHCP(boolean writeAccess) {
+        super(writeAccess);
+        fieldValues = new HashMap<String, byte[]>();
+        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<String, Pair<Integer, Integer>> 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<String> 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 (file)
index 0000000..47d3ed7
--- /dev/null
@@ -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<Byte, DhcpOption> options;
+
+    public DHCPOptions() {
+        options = new LinkedHashMap<Byte, DhcpOption>();
+    }
+
+    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<String> 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 (file)
index 0000000..dfb4046
--- /dev/null
@@ -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<String> _dnsServers;
+    private List<HostRoutes> _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 = hostRoutes;
+        return this;
+    }
+
+    protected DhcpInfo setDnsServers(List<String> dnsServers) {
+        _dnsServers = dnsServers;
+        return this;
+    }
+
+    protected DhcpInfo setDnsServersIpAddrs(List<IpAddress> dnsServers) {
+        for (IpAddress ipAddr: dnsServers) {
+            addDnsServer(ipAddr.getIpv4Address().getValue());
+        }
+        return this;
+    }
+
+    protected DhcpInfo addDnsServer(String dnsServerIp) {
+        if(_dnsServers == null) {
+            _dnsServers = new ArrayList<String>();
+        }
+        _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<String> getDnsServers() {
+        return _dnsServers;
+    }
+
+    protected List<HostRoutes> 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 (file)
index 0000000..458ad96
--- /dev/null
@@ -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<Void> DEFAULT_CALLBACK =
+        new FutureCallback<Void>() {
+            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<MatchInfo> matches = new ArrayList<MatchInfo>();
+
+        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<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
+        List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
+
+        // 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<Subnet> sIid =
+                            InstanceIdentifier.create(Neutron.class).child(Subnets.class)
+                                .child(Subnet.class, new SubnetKey(nPort.getFixedIps().get(0).getSubnetId()));
+            Optional<Subnet> 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<Ports> pIid = InstanceIdentifier.create(Neutron.class).child(Ports.class);
+        Optional<Ports> 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;
+    }
+
+}
index 16a2dc19d53302196e0e10dd96120db54f537371..3d10fa420b53edd9acf77a1233efc722c528194c 100644 (file)
  */
 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<? extends PacketInReason> 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<Node> 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<Node> 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<IpAddress> 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<NodeConnector> ncId = inNcRef.getValue().firstIdentifierOf(NodeConnector.class);
+        Optional<NodeConnector> 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<String> 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> hostRoutes = dhcpInfo.getHostRoutes();
+        if(hostRoutes == null) {
+            //we can't set this option, so return
+            return;
+        }
+        ByteArrayOutputStream result = new ByteArrayOutputStream();
+        Iterator<HostRoutes> 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<? extends PacketInReason> pktInReason) {
+        return (pktInReason == SendToController.class);
     }
 
     @Override
     public void close() throws Exception {
         // TODO Auto-generated method stub
-        
+    }
+
+    public void setPacketProcessingService(PacketProcessingService packetService) {
+        this.pktService = packetService;
     }
 
 }
index 7c086c23fe739dbc689f94e7a89638f0fff3b284..ce1a0a11c227c06c31555ab69aa5699841b2f8a0 100644 (file)
@@ -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 (file)
index 0000000..8cb8a7a
--- /dev/null
@@ -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<Node> implements AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NodeListener.class);
+
+    private IMdsalApiManager mdsalManager;
+    private ListenerRegistration<DataChangeListener> 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<Node> getWildCardPath() {
+        return InstanceIdentifier.create(Nodes.class).child(Node.class);
+    }
+
+
+    @Override
+    protected void remove(InstanceIdentifier<Node> identifier, Node del) {
+
+    }
+
+    @Override
+    protected void update(InstanceIdentifier<Node> identifier, Node original, Node update) {
+
+    }
+
+    @Override
+    protected void add(InstanceIdentifier<Node> 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");
+    }
+}
index 9fbd12c880aaadfab3623a0dd62f689d71917bea..bf453d425700d35ddc1799eb78109c5443edc767 100644 (file)
@@ -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;
     }
index 7ddc5bc08b261d7208511fed358af1f68c21f3f4..80effa8f6cc9f30924dc4a5f8222dfdc4996ff05 100644 (file)
@@ -29,6 +29,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
     <vpnservices.version>0.2.0-SNAPSHOT</vpnservices.version>
     <ovsdb.version>1.2.1-SNAPSHOT</ovsdb.version>
     <liblldp.version>0.10.0-SNAPSHOT</liblldp.version>
+    <neutron.version>0.6.0-SNAPSHOT</neutron.version>
     <arputil.version>${vpnservices.version}</arputil.version>
     <mdsalutil.version>${vpnservices.version}</mdsalutil.version>
     <vpnmanager.version>${vpnservices.version}</vpnmanager.version>
@@ -107,6 +108,19 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.neutron</groupId>
+      <artifactId>features-neutron</artifactId>
+      <classifier>features</classifier>
+      <version>${neutron.version}</version>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.neutron</groupId>
+      <artifactId>dummyprovider</artifactId>
+      <version>${neutron.version}</version>
+    </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>vpnmanager-impl</artifactId>
@@ -321,5 +335,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <artifactId>libthrift</artifactId>
       <version>0.9.1</version>
     </dependency>
+    <dependency>
+      <groupId>commons-net</groupId>
+      <artifactId>commons-net</artifactId>
+      <version>${commons.net.version}</version>
+    </dependency>
   </dependencies>
 </project>
index c9c41ec861798e82bc2c569f997e45e519633457..fa5145bde394f2c9113cfb67a0bf1cadf8488164 100644 (file)
@@ -16,14 +16,17 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
   <repository>mvn:org.opendaylight.openflowplugin/features-openflowplugin/${openflowplugin.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.netconf/features-restconf/${restconf.version}/xml/features</repository>
   <repository>mvn:org.opendaylight.ovsdb/features-ovsdb/${ovsdb.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.neutron/features-neutron/${neutron.version}/xml/features</repository>
   <feature name='odl-vpnservice-api' version='${project.version}' description='OpenDaylight :: vpnservice :: api '>
     <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
     <feature version='${mdsal.model.version}'>odl-mdsal-models</feature>
     <feature version='${openflowplugin.version}'>odl-openflowplugin-nsf-model</feature>
     <bundle>mvn:org.opendaylight.controller/liblldp/${liblldp.version}</bundle>
+    <bundle>mvn:org.opendaylight.neutron/model/${neutron.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/model-bgp/{{VERSION}}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/lockmanager-api/${lockmanager.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/idmanager-api/${idmanager.version}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/mdsalutil-api/${vpnservices.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/arputil-api/${arputil.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/alivenessmonitor-api/${vpnservices.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/vpnmanager-api/${vpnmanager.version}</bundle>
@@ -38,14 +41,15 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <feature version='${project.version}'>odl-vpnservice-api</feature>
     <feature version="${openflowplugin.version}">odl-openflowplugin-southbound</feature>
     <feature version="${openflowplugin.version}">odl-openflowplugin-flow-services</feature>
+    <bundle>mvn:commons-net/commons-net/${commons.net.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/lockmanager-impl/${lockmanager.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/idmanager-impl/${idmanager.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/bgpmanager-api/${vpnservices.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/bgpmanager-impl/${vpnservices.version}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/mdsalutil-api/${interfacemgr.version}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/mdsalutil-api/${vpnservices.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/arputil-impl/${arputil.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/alivenessmonitor-impl/${vpnservices.version}</bundle>
-    <bundle>mvn:org.opendaylight.vpnservice/mdsalutil-impl/${interfacemgr.version}</bundle>
+    <bundle>mvn:org.opendaylight.vpnservice/mdsalutil-impl/${vpnservices.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/interfacemgr-api/${interfacemgr.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/interfacemgr-impl/${interfacemgr.version}</bundle>
     <bundle>mvn:org.opendaylight.vpnservice/vpnmanager-impl/${vpnmanager.version}</bundle>
@@ -61,7 +65,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <configfile finalname="idmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/idmanager-impl/${idmanager.version}/xml/config</configfile>
     <configfile finalname="idmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/idmanager-impl/${idmanager.version}/xml/config</configfile>
     <configfile finalname="bgpmanager-impl-default-config.xml">mvn:org.opendaylight.vpnservice/bgpmanager-impl/${vpnservices.version}/xml/config</configfile>
-    <configfile finalname="mdsalutil-impl-default-config.xml">mvn:org.opendaylight.vpnservice/mdsalutil-impl/${interfacemgr.version}/xml/config</configfile>
+    <configfile finalname="mdsalutil-impl-default-config.xml">mvn:org.opendaylight.vpnservice/mdsalutil-impl/${vpnservices.version}/xml/config</configfile>
     <configfile finalname="interfacemgr-impl-default-config.xml">mvn:org.opendaylight.vpnservice/interfacemgr-impl/${interfacemgr.version}/xml/config</configfile>
     <configfile finalname="arputil-impl-default-config.xml">mvn:org.opendaylight.vpnservice/arputil-impl/${arputil.version}/xml/config</configfile>
     <configfile finalname="alivenessmonitor-impl-default-config.xml">mvn:org.opendaylight.vpnservice/alivenessmonitor-impl/${vpnservices.version}/xml/config</configfile>
@@ -81,6 +85,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
     <feature version="${mdsal.version}">odl-mdsal-xsql</feature>
   </feature>
   <feature name='odl-vpnservice-core' version='${project.version}' description='OpenDaylight :: vpnservice :: core'>
+    <feature version="${neutron.version}">odl-neutron-service</feature>
+    <bundle>mvn:org.opendaylight.neutron/dummyprovider/${neutron.version}</bundle>
     <feature version="${project.version}">odl-vpnservice-impl-ui</feature>
   </feature>
   <feature name='odl-vpnservice-openstack' version='${project.version}' description='OpenDaylight :: vpnservice :: impl :: REST '>
index 5f502d07ea28e4f8bbb890dd2e16fd2d0e6589c2..be7501ea47023c045eb10c01e3012b33357e6f66 100644 (file)
@@ -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<String, byte[]>();
index 5fce3de15a62ea7a29b090f4d1ea683f9d43ed34..da9c61c28ba67909fbc2644522f318405142a686 100644 (file)
@@ -35,6 +35,8 @@ public class Ethernet extends Packet {
     static {
         etherTypeClassMap = new HashMap<Short, Class<? extends Packet>>();
         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 (file)
index 0000000..792ab47
--- /dev/null
@@ -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<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
+        private static final long serialVersionUID = 1L;
+        {
+            put(TYPE, new ImmutablePair<Integer, Integer>(0, 8));
+            put(CODE, new ImmutablePair<Integer, Integer>(8, 8));
+            put(CHECKSUM, new ImmutablePair<Integer, Integer>(16, 16));
+            put(IDENTIFIER, new ImmutablePair<Integer, Integer>(32, 16));
+            put(SEQNUMBER, new ImmutablePair<Integer, Integer>(48, 16));
+        }
+    };
+
+    /**
+     * Default constructor that creates and sets the hash map values
+     */
+    public ICMP() {
+        super();
+        fieldValues = new HashMap<String, byte[]>();
+        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<String, byte[]>();
+        hdrFieldCoordMap = fieldCoordinates;
+        hdrFieldsMap = fieldValues;
+    }
+
+    private final Map<String, byte[]> 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 (file)
index 0000000..5a02b70
--- /dev/null
@@ -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<String> getProtocolNameList() {
+        List<String> protoList = new ArrayList<String>();
+        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 (file)
index 0000000..2bc29a8
--- /dev/null
@@ -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<Byte, Class<? extends Packet>> protocolClassMap;
+    static {
+        protocolClassMap = new HashMap<Byte, Class<? extends Packet>>();
+        protocolClassMap.put(IPProtocols.ICMP.byteValue(), ICMP.class);
+        protocolClassMap.put(IPProtocols.UDP.byteValue(), UDP.class);
+        protocolClassMap.put(IPProtocols.TCP.byteValue(), TCP.class);
+    }
+    private static Map<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
+        private static final long serialVersionUID = 1L;
+        {
+            put(VERSION, new ImmutablePair<Integer, Integer>(0, 4));
+            put(HEADERLENGTH, new ImmutablePair<Integer, Integer>(4, 4));
+            put(DIFFSERV, new ImmutablePair<Integer, Integer>(8, 6));
+            put(ECN, new ImmutablePair<Integer, Integer>(14, 2));
+            put(TOTLENGTH, new ImmutablePair<Integer, Integer>(16, 16));
+            put(IDENTIFICATION, new ImmutablePair<Integer, Integer>(32, 16));
+            put(FLAGS, new ImmutablePair<Integer, Integer>(48, 3));
+            put(FRAGOFFSET, new ImmutablePair<Integer, Integer>(51, 13));
+            put(TTL, new ImmutablePair<Integer, Integer>(64, 8));
+            put(PROTOCOL, new ImmutablePair<Integer, Integer>(72, 8));
+            put(CHECKSUM, new ImmutablePair<Integer, Integer>(80, 16));
+            put(SIP, new ImmutablePair<Integer, Integer>(96, 32));
+            put(DIP, new ImmutablePair<Integer, Integer>(128, 32));
+            put(OPTIONS, new ImmutablePair<Integer, Integer>(160, 0));
+        }
+    };
+
+    private final Map<String, byte[]> 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<String, byte[]>();
+        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<String, byte[]>();
+        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 (file)
index 0000000..1d582da
--- /dev/null
@@ -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<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
+        private static final long serialVersionUID = 1L;
+        {
+            put(SRCPORT, new ImmutablePair<Integer, Integer>(0, 16));
+            put(DESTPORT, new ImmutablePair<Integer, Integer>(16, 16));
+            put(SEQNUMBER, new ImmutablePair<Integer, Integer>(32, 32));
+            put(ACKNUMBER, new ImmutablePair<Integer, Integer>(64, 32));
+            put(DATAOFFSET, new ImmutablePair<Integer, Integer>(96, 4));
+            put(RESERVED, new ImmutablePair<Integer, Integer>(100, 3));
+            put(HEADERLENFLAGS, new ImmutablePair<Integer, Integer>(103, 9));
+            put(WINDOWSIZE, new ImmutablePair<Integer, Integer>(112, 16));
+            put(CHECKSUM, new ImmutablePair<Integer, Integer>(128, 16));
+            put(URGENTPOINTER, new ImmutablePair<Integer, Integer>(144, 16));
+        }
+    };
+
+    private final Map<String, byte[]> fieldValues;
+
+    /**
+     * Default constructor that sets all the header fields to zero
+     */
+    public TCP() {
+        super();
+        fieldValues = new HashMap<String, byte[]>();
+        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<String, byte[]>();
+        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 (file)
index 0000000..b8c7367
--- /dev/null
@@ -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<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
+        private static final long serialVersionUID = 1L;
+        {
+            put(SRCPORT, new ImmutablePair<Integer, Integer>(0, 16));
+            put(DESTPORT, new ImmutablePair<Integer, Integer>(16, 16));
+            put(LENGTH, new ImmutablePair<Integer, Integer>(32, 16));
+            put(CHECKSUM, new ImmutablePair<Integer, Integer>(48, 16));
+        }
+    };
+
+    public UDP() {
+        super();
+        fieldValues = new HashMap<String, byte[]>();
+        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<String, byte[]>();
+        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<String, byte[]> fieldValues;
+
+    /* public static Map<Short, Class<? extends Packet>> decodeMap;
+
+      static {
+          decodeMap = new HashMap<Short, Class<? extends Packet>>();
+          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;
+    }
+
+}