+
+/*
+ * Copyright (c) 2013 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.controller.forwarding.staticrouting;
+
+import java.io.Serializable;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.controller.sal.core.NodeConnector;
+import org.opendaylight.controller.sal.packet.BitBufferHelper;
+import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
+import org.opendaylight.controller.sal.utils.NodeCreator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class defines a static route object.
+ */
+public class StaticRoute implements Serializable{
+ private static final long serialVersionUID = 1L;
+ protected static final Logger logger = LoggerFactory
+ .getLogger(StaticRoute.class);
+
+ /**
+ * This Enum defines the possible types for the next hop address.
+ */
+ public enum NextHopType implements Serializable {
+ IPADDRESS("nexthop-ip"), SWITCHPORT("nexthop-interface");
+ private NextHopType(String name) {
+ this.name = name;
+ }
+
+ private String name;
+
+ public String toString() {
+ return name;
+ }
+
+ public static NextHopType fromString(String str) {
+ if (str == null)
+ return IPADDRESS;
+ if (str.equals(IPADDRESS.toString()))
+ return IPADDRESS;
+ if (str.equals(SWITCHPORT.toString()))
+ return SWITCHPORT;
+ return IPADDRESS;
+ }
+ }
+
+ InetAddress networkAddress;
+ InetAddress mask;
+ NextHopType type;
+ InetAddress nextHopAddress;
+ Node node;
+ NodeConnector port;
+ HostNodeConnector host;
+
+ /**
+ * Create a static route object with no specific information.
+ */
+ public StaticRoute() {
+
+ }
+
+ /**
+ * Create a static route object from the StaticRouteConfig.
+ * @param: config: StaticRouteConfig
+ */
+ public StaticRoute(StaticRouteConfig config) {
+ networkAddress = config.getStaticRouteIP();
+ mask = StaticRoute.getV4AddressMaskFromDecimal(config
+ .getStaticRouteMask());
+ type = NextHopType.fromString(config.getNextHopType());
+ nextHopAddress = config.getNextHopIP();
+ Map<Long, Short> switchPort = config.getNextHopSwitchPorts();
+ if ((switchPort != null) && (switchPort.size() == 1)) {
+ node = NodeCreator.createOFNode((Long) switchPort.keySet()
+ .toArray()[0]);
+ port = NodeConnectorCreator.createOFNodeConnector(
+ (Short) switchPort.values().toArray()[0], node);
+ }
+ }
+
+ /**
+ * Get the IP address portion of the sub-network of the static route.
+ * @return InetAddress: the IP address portion of the sub-network of the static route
+ */
+ public InetAddress getNetworkAddress() {
+ return networkAddress;
+ }
+
+ /**
+ * Set the IP address portion of the sub-network of the static route.
+ * @param networkAddress The IP address (InetAddress) to be set
+ */
+ public void setNetworkAddress(InetAddress networkAddress) {
+ this.networkAddress = networkAddress;
+ }
+
+ /**
+ * Get the mask of the sub-network of the static route.
+ * @return mask: the mask (InetAddress) of the sub-network of the static route
+ */
+ public InetAddress getMask() {
+ return mask;
+ }
+
+ /**
+ * Set the sub-network's mask of the static route.
+ * @param mask The mask (InetAddress) to be set
+ */
+ public void setMask(InetAddress mask) {
+ this.mask = mask;
+ }
+
+ /**
+ * Get the NextHopeType of the static route.
+ * @return type: NextHopeType
+ */
+ public NextHopType getType() {
+ return type;
+ }
+
+ /**
+ * Set the nextHopType.
+ * @param type The NextHopType to be set
+ */
+ public void setType(NextHopType type) {
+ this.type = type;
+ }
+
+ /**
+ * Get the next hop IP address.
+ * @return: nextHopAddress (InetAddress)
+ */
+ public InetAddress getNextHopAddress() {
+ return nextHopAddress;
+ }
+
+ /**
+ * Set the next hop IP address.
+ * @param nextHopAddress The IP address (InetAddress) to be set
+ */
+ public void setNextHopAddress(InetAddress nextHopAddress) {
+ this.nextHopAddress = nextHopAddress;
+ }
+
+ /**
+ * Get the Node associated with the static route.
+ * @return: Node
+ */
+ public Node getNode() {
+ return node;
+ }
+
+ /**
+ * Set the node associated to the static route.
+ * @param node: The node to be set
+ */
+ public void setNode(Node node) {
+ this.node = node;
+ }
+
+ /**
+ * Set the port associated to the static route.
+ * @param port The port (NodeConnector) to be set
+ */
+ public void setPort(NodeConnector port) {
+ this.port = port;
+ }
+
+ /**
+ * Get the port associated to the static route.
+ * @return port: The port (NodeConnector)
+ */
+ public NodeConnector getPort() {
+ return port;
+ }
+
+ /**
+ * Get the Host associated to static route.
+ * @return host: The host (HostNodeConnector)
+ */
+ public HostNodeConnector getHost() {
+ return host;
+ }
+
+ /**
+ * Set the host associated to the static route.
+ * @param host: (HostNodeConnector) to be set
+ */
+ public void setHost(HostNodeConnector host) {
+ this.host = host;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((host == null) ? 0 : host.hashCode());
+ result = prime * result + ((mask == null) ? 0 : mask.hashCode());
+ result = prime * result
+ + ((networkAddress == null) ? 0 : networkAddress.hashCode());
+ result = prime * result
+ + ((nextHopAddress == null) ? 0 : nextHopAddress.hashCode());
+ result = prime * result + ((port == null) ? 0 : port.hashCode());
+ result = prime * result + ((node == null) ? 0 : node.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "StaticRoute [networkAddress=" + networkAddress + ", mask="
+ + mask + ", type=" + type.toString() + ", nextHopAddress="
+ + nextHopAddress + ", swid=" + node + ", port=" + port
+ + ", host=" + host + "]";
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ StaticRoute other = (StaticRoute) obj;
+ if (!networkAddress.equals(other.networkAddress))
+ return false;
+ if (!mask.equals(other.mask))
+ return false;
+ return true;
+ }
+
+ private static InetAddress getV4AddressMaskFromDecimal(int mask) {
+ int netmask = 0;
+ for (int i = 0; i < mask; i++) {
+ netmask |= (1 << 31 - i);
+ }
+
+ try {
+ return InetAddress.getByAddress(BitBufferHelper
+ .toByteArray(netmask));
+ } catch (Exception e) {
+ logger.error("",e);
+ return null;
+ }
+ }
+
+ private void applyV4MaskOnByteBuffer(ByteBuffer bb, ByteBuffer bbMask) {
+ for (int i = 0; i < bb.array().length; i++) {
+ bb.put(i, (byte) (bb.get(i) & bbMask.get(i)));
+ }
+ }
+
+ /**
+ * Compute and return the IP address with longest prefix match from the static route based on the
+ * destNetworkAddress. Currently it only take IPv4 address format (Inet4Address)
+ * @param destNetworkAddress: the IP address to be based on
+ * @return: InetAddress: the IPv4 address with the longest prefix matching the static route.
+ * If the destNetworkkAddress is not IPv4 format, it will return null.
+ */
+ public InetAddress longestPrefixMatch(InetAddress destNetworkAddress) {
+ if (destNetworkAddress instanceof Inet4Address) {
+ ByteBuffer bbdest = ByteBuffer
+ .wrap(destNetworkAddress.getAddress());
+ ByteBuffer bbself = ByteBuffer.wrap(networkAddress.getAddress());
+
+ ByteBuffer bbMask = ByteBuffer.wrap(mask.getAddress());
+
+ applyV4MaskOnByteBuffer(bbdest, bbMask);
+ applyV4MaskOnByteBuffer(bbself, bbMask);
+
+ if (bbdest.equals(bbself)) {
+ try {
+ return InetAddress.getByAddress(bbself.array());
+ } catch (Exception e) {
+ logger.error("",e);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Compare the static route with another static route. It only handles(for now) IPv4Address.
+ * @param s: the other StaticRoute
+ * @return: 0 if they are the same
+ */
+ public int compareTo(StaticRoute s) {
+ if (s == null)
+ return 1;
+ if ((networkAddress instanceof Inet6Address)
+ || (s.getNetworkAddress() instanceof Inet6Address)) {
+ // HANDLE IPv6 Later
+ return 1;
+ }
+
+ ByteBuffer bbchallenger = ByteBuffer.wrap(s.getNetworkAddress()
+ .getAddress());
+ ByteBuffer bbself = ByteBuffer.wrap(networkAddress.getAddress());
+ ByteBuffer bbChallengerMask = ByteBuffer.wrap(s.getMask().getAddress());
+ ByteBuffer bbSelfMask = ByteBuffer.wrap(getMask().getAddress());
+
+ applyV4MaskOnByteBuffer(bbchallenger, bbChallengerMask);
+ applyV4MaskOnByteBuffer(bbself, bbSelfMask);
+ return bbself.compareTo(bbchallenger);
+ }
+}
\ No newline at end of file