/* * 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.sal.flowprogrammer; import java.io.Serializable; import java.net.Inet6Address; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import org.opendaylight.controller.sal.action.Action; import org.opendaylight.controller.sal.action.ActionType; import org.opendaylight.controller.sal.action.SetDlType; import org.opendaylight.controller.sal.action.SetNwDst; import org.opendaylight.controller.sal.action.SetNwSrc; import org.opendaylight.controller.sal.match.Match; import org.opendaylight.controller.sal.utils.EtherTypes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Represent a flow: match + actions + flow specific properties * */ @XmlRootElement @XmlAccessorType(XmlAccessType.NONE) public class Flow implements Cloneable, Serializable { protected static final Logger logger = LoggerFactory .getLogger(Flow.class); private static final long serialVersionUID = 1L; @XmlElement private Match match; @XmlElement private List actions; @XmlElement private short priority; @XmlElement private short idleTimeout; @XmlElement private short hardTimeout; @XmlElement private long id; // unique identifier for this flow public Flow() { match = null; actions = null; } public Flow(Match match, List actions) { if (match.isIPv4() && actionsAreIPv6()) { try { throw new Exception("Conflicting Match and Action list"); } catch (Exception e) { logger.error("",e); } } else { this.match = match; this.actions = actions; } } /** * Return a copy of the Match configured on this flow * * @return */ public Match getMatch() { return match.clone(); } /** * Set the Match for this flow * This operation will overwrite an existing Match if present * * @param match */ public void setMatch(Match match) { this.match = match; } /** * Returns a copy of the actions list of this flow * @return */ public List getActions() { return (actions == null) ? null : new ArrayList(actions); } /** * Set the actions list for this flow * If a list is already present, it will be * replaced with the passed one. During * addition, only the valid actions will be added * It is a no op if the passed actions is null * An empty actions is a vlaid input * * @param actions */ public void setActions(List actions) { if (actions == null) { return; } this.actions = new ArrayList(actions.size()); for (Action action : actions) { if (action.isValid()) { this.actions.add(action); } } } /** * Returns whether the Flow is for IPv4 or IPv6 * Information is derived from match and actions list * * @return */ public boolean isIPv6() { return (match.isIPv6()) ? true : actionsAreIPv6(); } /** * Returns true if it finds at least one action which is for IPv6 * in the list of actions for this Flow * * @return */ private boolean actionsAreIPv6() { if (this.actions != null) { for (Action action : actions) { switch (action.getType()) { case SET_NW_SRC: if (((SetNwSrc) action).getAddress() instanceof Inet6Address) { return true; } break; case SET_NW_DST: if (((SetNwDst) action).getAddress() instanceof Inet6Address) { return true; } break; case SET_DL_TYPE: if (((SetDlType) action).getDlType() == EtherTypes.IPv6 .intValue()) { return true; } break; default: } } } return false; } @Override public Flow clone() { Flow cloned = null; try { cloned = (Flow) super.clone(); cloned.match = this.getMatch(); cloned.actions = this.getActions(); } catch (CloneNotSupportedException e) { logger.error("",e); } return cloned; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((actions == null) ? 0 : actions.hashCode()); result = prime * result + hardTimeout; result = prime * result + (int) (id ^ (id >>> 32)); result = prime * result + idleTimeout; result = prime * result + ((match == null) ? 0 : match.hashCode()); result = prime * result + priority; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Flow other = (Flow) obj; if (actions == null) { if (other.actions != null) return false; } else if (!actions.equals(other.actions)) return false; if (hardTimeout != other.hardTimeout) return false; if (id != other.id) return false; if (idleTimeout != other.idleTimeout) return false; if (match == null) { if (other.match != null) return false; } else if (!match.equals(other.match)) return false; if (priority != other.priority) return false; return true; } @Override public String toString() { return "Flow[match = " + match + ", actions = " + actions + ", priority = " + priority + ", id = " + id + ", idleTimeout = " + idleTimeout + ", hardTimeout = " + hardTimeout + "]"; } public short getPriority() { return priority; } public void setPriority(short priority) { this.priority = priority; } public short getIdleTimeout() { return idleTimeout; } public void setIdleTimeout(short idleTimeout) { this.idleTimeout = idleTimeout; } public short getHardTimeout() { return hardTimeout; } public void setHardTimeout(short hardTimeout) { this.hardTimeout = hardTimeout; } public long getId() { return id; } public void setId(long id) { this.id = id; } /** * Adds the specified action to the list of action of this flow * * @param action * @return false if the passed action is null or not valid or if it fails to add it */ public boolean addAction(Action action) { if (action == null || !action.isValid()) { return false; } return actions.add(action); } public boolean removeAction(Action action) { if (action == null) { return false; } return actions.remove(action); } /** * remove ALL actions of type actionType from the list of actions of this flow * * @param actionType * @return false if an action of that type is present and it fails to remove it */ public boolean removeAction(ActionType actionType) { Iterator actionIter = this.getActions().iterator(); while (actionIter.hasNext()) { Action action = actionIter.next(); if (action.getType() == actionType) { if (!this.removeAction(action)) return false; } } return true; } }