Note that flow filter feature is not yet implemented.
Currently all flow filter REST APIs do nothing.
Change-Id: Ic6a3e65355e8162b8e19df6320008cecab209d0f
Signed-off-by: Shigeru Yasuda <s-yasuda@da.jp.nec.com>
org.opendaylight.vtn.manager,
org.opendaylight.vtn.manager.flow,
org.opendaylight.vtn.manager.flow.action,
- org.opendaylight.vtn.manager.flow.cond
+ org.opendaylight.vtn.manager.flow.cond,
+ org.opendaylight.vtn.manager.flow.filter
</Export-Package>
<Import-Package>
org.opendaylight.controller.hosttracker.hostAware,
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager;
+
+import org.opendaylight.controller.sal.core.UpdateType;
+
+/**
+ * {@code ErrorVNodePath} class is used to indicate that an invalid
+ * virtual node path is specified.
+ *
+ * <p>
+ * This class is provided only for internal use.
+ * Java application must not use this class.
+ * </p>
+ *
+ * @since Helium
+ */
+public final class ErrorVNodePath extends VNodePath
+ implements VInterfacePath {
+ /**
+ * Version number for serialization.
+ */
+ private static final long serialVersionUID = 2748579569569933516L;
+
+ /**
+ * A string which represents type type of this node path.
+ */
+ private static final String NODETYPE_ERROR = "*** ERROR ***";
+
+ /**
+ * Construct a new instance.
+ *
+ * @param msg An error message.
+ */
+ ErrorVNodePath(String msg) {
+ super(msg, null);
+ }
+
+ /**
+ * Return an error message configured in this instance.
+ *
+ * @return An error message.
+ */
+ public String getError() {
+ return getTenantName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getNodeType() {
+ return NODETYPE_ERROR;
+ }
+
+ /**
+ * This method should never be called.
+ *
+ * @return Never returns.
+ * @throws IllegalStateException Always thrown.
+ */
+ @Override
+ public VNodeLocation toVNodeLocation() {
+ throw unexpected();
+ }
+
+ /**
+ * Create an {@link IllegalStateException} that indicates unexpected method
+ * is called.
+ *
+ * @return An exception.
+ */
+ private IllegalStateException unexpected() {
+ return new IllegalStateException("Should never be called.");
+ }
+
+ // VInterfacePath
+
+ /**
+ * This method should never be called.
+ *
+ * @return Never returns.
+ * @throws IllegalStateException Always thrown.
+ */
+ @Override
+ public String getInterfaceName() {
+ throw unexpected();
+ }
+
+ /**
+ * This method should never be called.
+ *
+ * @param listener Unused.
+ * @param viface Unused.
+ * @param type Unused.
+ * @throws IllegalStateException Always thrown.
+ */
+ @Override
+ public void vInterfaceChanged(IVTNManagerAware listener, VInterface viface,
+ UpdateType type) {
+ throw unexpected();
+ }
+
+ /**
+ * This method should never be called.
+ *
+ * @param listener Unused.
+ * @param pmap Unused.
+ * @param type Unused.
+ * @throws IllegalStateException Always thrown.
+ */
+ @Override
+ public void portMapChanged(IVTNManagerAware listener, PortMap pmap,
+ UpdateType type) {
+ throw unexpected();
+ }
+}
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 3530008424797872881L;
+ private static final long serialVersionUID = -4792520332881436474L;
/**
* A string which represents that the node type is vBridge interface.
return components;
}
+ /**
+ * Convert this instance into a {@link VNodeLocation} instance.
+ *
+ * @return A {@link VNodeLocation} instance.
+ */
+ @Override
+ public VNodeLocation toVNodeLocation() {
+ return new VNodeLocation(this);
+ }
+
/**
* Return the hash code of this object.
*
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = -2598911916422555753L;
+ private static final long serialVersionUID = -2918772111159548106L;
/**
* A string which represents that the node type is vBridge.
public String getNodeType() {
return NODETYPE_VBRIDGE;
}
+
+ /**
+ * Convert this instance into a {@link VNodeLocation} instance.
+ *
+ * @return A {@link VNodeLocation} instance.
+ */
+ @Override
+ public VNodeLocation toVNodeLocation() {
+ return new VNodeLocation(this);
+ }
}
*/
String getNodeType();
+ /**
+ * Convert this instance into a {@link VNodeLocation} instance.
+ *
+ * @return A {@link VNodeLocation} instance.
+ */
+ VNodeLocation toVNodeLocation();
+
/**
* Call method that listens the change of the virtual interface.
*
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+/**
+ * This class is used to establish JAXB mapping between {@link VInterfacePath}
+ * and {@link VNodeLocation}.
+ *
+ * @since Helium
+ */
+public class VInterfacePathAdapter
+ extends XmlAdapter<VNodeLocation, VInterfacePath> {
+ /**
+ * Construct a new instance.
+ */
+ public VInterfacePathAdapter() {
+ }
+
+ /**
+ * Convert an instance of {@link VNodeLocation} into
+ * {@link VInterfacePath}.
+ *
+ * @param loc A {@link VNodeLocation} instance to be converted.
+ * @return A {@link VInterfacePath} instance.
+ * {@code null} is returned if the specified {@link VNodeLocation}
+ * does not point any virtual interface.
+ */
+ @Override
+ public VInterfacePath unmarshal(VNodeLocation loc) {
+ if (loc == null) {
+ return null;
+ }
+
+ String tname = loc.getTenantName();
+ String ifname = loc.getInterfaceName();
+ if (ifname == null) {
+ return new ErrorVNodePath("Interface name is not specified: " +
+ loc);
+ }
+
+ String bname = loc.getBridgeName();
+ if (bname != null) {
+ return new VBridgeIfPath(tname, bname, ifname);
+ }
+
+ String tmname = loc.getTerminalName();
+ if (tmname != null) {
+ return new VTerminalIfPath(tname, tmname, ifname);
+ }
+
+ return new ErrorVNodePath("Unexpected interface location: " + loc);
+ }
+
+ /**
+ * Convert an instance of {@link VInterfacePath} into an instance of
+ * {@link VNodeLocation}.
+ *
+ * @param path A {@link VInterfacePath} instance to be converted.
+ * @return A {@link VNodeLocation} instance.
+ * {@code null} is returned a value passed to {@code path} is
+ * {@code null} or an instance of unexpected class.
+ */
+ @Override
+ public VNodeLocation marshal(VInterfacePath path) {
+ return (path == null) ? null : path.toVNodeLocation();
+ }
+}
package org.opendaylight.vtn.manager;
import java.io.Serializable;
+import java.util.Objects;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 8688432687151988512L;
+ private static final long serialVersionUID = 1379126227527453095L;
/**
* The name of the VTN.
public String getInterfaceName() {
return interfaceName;
}
+
+ /**
+ * Determine whether the given object is identical to this object.
+ *
+ * @param o An object to be compared.
+ * @return {@code true} if identical. Otherwise {@code false}.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o == null || !getClass().equals(o.getClass())) {
+ return false;
+ }
+
+ VNodeLocation loc = (VNodeLocation)o;
+ return (Objects.equals(tenantName, loc.tenantName) &&
+ Objects.equals(bridgeName, loc.bridgeName) &&
+ Objects.equals(routerName, loc.routerName) &&
+ Objects.equals(terminalName, loc.terminalName) &&
+ Objects.equals(interfaceName, loc.interfaceName));
+ }
+
+ /**
+ * Return the hash code of this object.
+ *
+ * @return The hash code.
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(tenantName, bridgeName, routerName, terminalName,
+ interfaceName);
+ }
}
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = -3691447682025580103L;
+ private static final long serialVersionUID = 569227328812607675L;
/**
* The name of the virtual node inside the VTN.
* @param tenantName The name of the VTN.
* @param name The name of the virtual node inside the VTN.
*/
- protected VNodePath(String tenantName, String name) {
+ VNodePath(String tenantName, String name) {
super(tenantName);
tenantNodeName = name;
}
* @param name The name of the virtual node.
* @throws NullPointerException {@code tenantPath} is {@code null}.
*/
- protected VNodePath(VTenantPath tenantPath, String name) {
+ VNodePath(VTenantPath tenantPath, String name) {
this(tenantPath.getTenantName(), name);
}
return tenantNodeName;
}
+ /**
+ * Convert this instance into a {@link VNodeLocation} instance.
+ *
+ * @return A {@link VNodeLocation} instance.
+ */
+ public abstract VNodeLocation toVNodeLocation();
+
/**
* {@inheritDoc}
*/
import javax.xml.bind.annotation.adapters.XmlAdapter;
/**
- * This class is used to establish JAXB mapping between {@code VNodePath} and
+ * This class is used to establish JAXB mapping between {@link VNodePath} and
* {@link VNodeLocation}.
*
* @since Helium
}
String tname = loc.getTenantName();
- if (tname == null) {
- return null;
- }
-
String ifname = loc.getInterfaceName();
String bname = loc.getBridgeName();
if (bname != null) {
: new VTerminalIfPath(tname, tmname, ifname);
}
- return null;
+ return new ErrorVNodePath("Unexpected node location: " + loc);
}
/**
- * Convert an instance of {@link VNodePath} into {@link VNodeLocation}.
+ * Convert an instance of {@link VNodePath} into an instance of
+ * {@link VNodeLocation}.
*
* @param path A {@link VNodePath} instance to be converted.
* @return A {@link VNodeLocation} instance.
- * {@code null} is returned a value passed to {@code path} is
- * {@code null} or an instance of unexpected class.
+ * {@code null} is returned if {@code null} is passed to
+ * {@code path}.
*/
@Override
public VNodeLocation marshal(VNodePath path) {
- if (path instanceof VBridgeIfPath) {
- return new VNodeLocation((VBridgeIfPath)path);
- }
- if (path instanceof VTerminalIfPath) {
- return new VNodeLocation((VTerminalIfPath)path);
- }
- if (path instanceof VBridgePath) {
- return new VNodeLocation((VBridgePath)path);
- }
- if (path instanceof VTerminalPath) {
- return new VNodeLocation((VTerminalPath)path);
- }
-
- return null;
+ return (path == null) ? null : path.toVNodeLocation();
}
}
*
* @see <a href="package-summary.html#VTN">VTN</a>
*/
-public class VTenantPath implements Serializable, Comparable<VTenantPath> {
+public class VTenantPath
+ implements Serializable, Comparable<VTenantPath>, Cloneable {
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 8776060135426029534L;
+ private static final long serialVersionUID = -3796118278733925106L;
/**
* A string which represents that the node type is VTN.
/**
* The name of the {@linkplain <a href="package-summary.html#VTN">VTN</a>}.
*/
- private final String tenantName;
+ private String tenantName;
/**
* Construct a new object which represents the position of the
return NODETYPE_VTN;
}
+ /**
+ * Create a shallow copy of this instance, and replace the tenant name
+ * with the specified name.
+ *
+ * @param tenantName The name of the VTN to be configured into a new
+ * instance.
+ * @return A constructed instance.
+ * @since Helium
+ */
+ public final VTenantPath replaceTenantName(String tenantName) {
+ try {
+ VTenantPath path = (VTenantPath)super.clone();
+ path.tenantName = tenantName;
+ return path;
+ } catch (CloneNotSupportedException e) {
+ // This should never happen.
+ throw new IllegalStateException("clone() failed", e);
+ }
+ }
+
/**
* Return a {@link StringBuilder} object which contains a string
* representation of this object.
return ret;
}
+
+ // Cloneable
+
+ /**
+ * Create a shallow copy of this instance.
+ *
+ * @return A shallow copy of this instance.
+ */
+ public VTenantPath clone() {
+ try {
+ return (VTenantPath)super.clone();
+ } catch (CloneNotSupportedException e) {
+ // This should never happen.
+ throw new IllegalStateException("clone() failed", e);
+ }
+ }
}
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = 627513994821323718L;
+ private static final long serialVersionUID = -7165865505431233649L;
/**
* A string which represents that the node type is vTerminal interface.
return components;
}
+ /**
+ * Convert this instance into a {@link VNodeLocation} instance.
+ *
+ * @return A {@link VNodeLocation} instance.
+ */
+ @Override
+ public VNodeLocation toVNodeLocation() {
+ return new VNodeLocation(this);
+ }
+
/**
* Return the hash code of this object.
*
/**
* Version number for serialization.
*/
- private static final long serialVersionUID = -8111755848677458802L;
+ private static final long serialVersionUID = -4095702145474291746L;
/**
* A string which represents that the node type is vTerminal.
public String getNodeType() {
return NODETYPE_VTERMINAL;
}
+
+ /**
+ * Convert this instance into a {@link VNodeLocation} instance.
+ *
+ * @return A {@link VNodeLocation} instance.
+ */
+ @Override
+ public VNodeLocation toVNodeLocation() {
+ return new VNodeLocation(this);
+ }
}
* This package provides public APIs for flow condition, which tests whether
* the packet satisfies the specified conditions.
*
+ * <p>
+ * A flow condition is a named list of flow match conditions, and it is
+ * used to select packets. Each flow match condition must have a match index,
+ * which is an unique index in a flow condition. When a flow condition
+ * tests a packet, flow match conditions in a flow condition are evaluated
+ * in ascending order of match indices. A packet is selected if at least one
+ * flow match condition matches the packet.
+ * </p>
+ * <p>
+ * Flow conditions configured in the container is shared with all VTNs
+ * in the container.
+ * </p>
+ *
* @since Helium
*/
package org.opendaylight.vtn.manager.flow.cond;
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.flow.filter;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+/**
+ * {@code DropFilter} class describes the DROP flow filter which discards
+ * the specified packets.
+ *
+ * <h4>Example JSON</h4>
+ * <pre class="prettyprint lang-json">{}</pre>
+ *
+ * @since Helium
+ */
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@XmlRootElement(name = "drop")
+@XmlAccessorType(XmlAccessType.NONE)
+public final class DropFilter extends FilterType {
+ /**
+ * Version number for serialization.
+ */
+ private static final long serialVersionUID = 7396754685166202723L;
+
+ /**
+ * Construct a new instance.
+ */
+ public DropFilter() {
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.flow.filter;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSeeAlso;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+/**
+ * {@code FilterType} is an abstract class that describes the type of
+ * flow filter.
+ *
+ * @since Helium
+ */
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@XmlRootElement(name = "filtertype")
+@XmlAccessorType(XmlAccessType.NONE)
+@XmlSeeAlso({
+ PassFilter.class,
+ DropFilter.class,
+ RedirectFilter.class
+})
+public abstract class FilterType implements Serializable {
+ /**
+ * Version number for serialization.
+ */
+ private static final long serialVersionUID = -4140830853020675751L;
+
+ /**
+ * Construct a new instance.
+ */
+ FilterType() {
+ }
+
+ /**
+ * Determine whether the given object is identical to this object.
+ *
+ * @param o An object to be compared.
+ * @return {@code true} if identical. Otherwise {@code false}.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ return (o != null && getClass().equals(o.getClass()));
+ }
+
+ /**
+ * Return the hash code of this object.
+ *
+ * @return The hash code.
+ */
+ @Override
+ public int hashCode() {
+ return getClass().getName().hashCode();
+ }
+
+ /**
+ * Return a string representation of this object.
+ *
+ * @return A string representation of this object.
+ */
+ @Override
+ public String toString() {
+ return getClass().getSimpleName();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.flow.filter;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import org.opendaylight.vtn.manager.flow.action.FlowAction;
+import org.opendaylight.vtn.manager.flow.action.SetDlDstAction;
+import org.opendaylight.vtn.manager.flow.action.SetDlSrcAction;
+import org.opendaylight.vtn.manager.flow.action.SetDscpAction;
+import org.opendaylight.vtn.manager.flow.action.SetIcmpCodeAction;
+import org.opendaylight.vtn.manager.flow.action.SetIcmpTypeAction;
+import org.opendaylight.vtn.manager.flow.action.SetInet4DstAction;
+import org.opendaylight.vtn.manager.flow.action.SetInet4SrcAction;
+import org.opendaylight.vtn.manager.flow.action.SetTpDstAction;
+import org.opendaylight.vtn.manager.flow.action.SetTpSrcAction;
+import org.opendaylight.vtn.manager.flow.action.SetVlanPcpAction;
+
+/**
+ * {@code FlowFilter} class describes configuration information about
+ * flow filter.
+ *
+ * <p>
+ * An instance of this class represents a rule of a packet filter applied
+ * to packets forwarded in the VTN. If a flow condition configured in
+ * a flow filter matches a packet, actions configured in that flow filter
+ * are applied to the packet.
+ * </p>
+ *
+ * <h4>Example JSON</h4>
+ * <pre class="prettyprint lang-json">
+ * {
+ * "index": 10,
+ * "condition": "flowcond_1",
+ * "filterType": {
+ * "redirect": {
+ * "destination": {
+ * "bridge": "vbridge_1",
+ * "interface": "if_2"
+ * },
+ * "output": false
+ * }
+ * },
+ * "actions": [
+ * {"dlsrc": {"address": "f0:f1:f2:f3:f4:f5"}},
+ * {"vlanpcp": {"priority": 7}}
+ * ]
+ * }</pre>
+ *
+ * @since Helium
+ */
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@XmlRootElement(name = "flowfilter")
+@XmlAccessorType(XmlAccessType.NONE)
+public final class FlowFilter implements Serializable {
+ /**
+ * Version number for serialization.
+ */
+ private static final long serialVersionUID = -2789802133918528483L;
+
+ /**
+ * An index value assigned to this flow filter.
+ *
+ * <ul>
+ * <li>
+ * The range of value that can be specified is from
+ * <strong>1</strong> to <strong>65535</strong>.
+ * </li>
+ * <li>
+ * This value is used to determine order of evaluation.
+ * Flow filters in the same list are evaluated against packet
+ * in ascending order of indices assigned to
+ * <strong>flowfilter</strong> elements, and only the first matched
+ * flow filter is applied to the packet.
+ * </li>
+ * </ul>
+ */
+ @XmlAttribute(name = "index")
+ private Integer index;
+
+ /**
+ * The name of the flow condition that selects packets.
+ *
+ * <ul>
+ * <li>
+ * This flow filter will be applied to the packet if the packet is
+ * selected by the flow condition specified by this attribute.
+ * </li>
+ * <li>
+ * This flow filter is invalidated if the flow condition specified by
+ * this attribute does not exist.
+ * </li>
+ * </ul>
+ */
+ @XmlAttribute(required = true)
+ private String condition;
+
+ /**
+ * The type of this flow filter.
+ *
+ * <p>
+ * The flow filter type determines action to be applied to the packet
+ * when it matches the condition specified by the
+ * <strong>condition</strong> attribute.
+ * One of the following elements can be specified.
+ * </p>
+ * <dl style="margin-left: 1em;">
+ * <dt>pass
+ * <dd style="margin-left: 1.5em;">
+ * Let the matched packet through the virtual node.
+ * The type of this element must be {@link PassFilter}.
+ *
+ * <dt>drop
+ * <dd style="margin-left: 1.5em;">
+ * Discard the matched packet.
+ * The type of this element must be {@link DropFilter}.
+ *
+ * <dt>redirect
+ * <dd style="margin-left: 1.5em;">
+ * Forward the matched packet to another virtual interface in the
+ * same VTN.
+ * The type of this element must be {@link RedirectFilter}.
+ * </dl>
+ *
+ * <ul>
+ * <li>
+ * If omitted, it will be treated as if <strong>pass</strong> is
+ * specified.
+ * </li>
+ * <li>
+ * In JSON notation, this element must be wrapped by a
+ * <strong>filterType</strong> element.
+ * </li>
+ * </ul>
+ */
+ @XmlElements({
+ @XmlElement(name = "pass", type = PassFilter.class),
+ @XmlElement(name = "drop", type = DropFilter.class),
+ @XmlElement(name = "redirect", type = RedirectFilter.class)
+ })
+ private FilterType filterType;
+
+ /**
+ * A list of {@link FlowAction} instances that modifies the packet
+ * when this flow filter is applied to the packet.
+ *
+ * <ul>
+ * <li>
+ * If omitted or an empty list is specified, this flow filter is
+ * applied to the packet without modifying the packet.
+ * </li>
+ * <li>
+ * Note that the VLAN ID of the packet cannot be specified
+ * because it is always determined by the virtual mapping configuration
+ * such as port mapping.
+ * </li>
+ * <li>
+ * This element is ignored if a <strong>drop</strong> element is
+ * configured in this instance.
+ * </li>
+ * </ul>
+ * <p>
+ * One or more of the following elements can be specified.
+ * </p>
+ * <dl style="margin-left: 1em;">
+ * <dt>dlsrc
+ * <dd style="margin-left: 1.5em;">
+ * Specifies the action that sets the source MAC address in
+ * Ethernet header.
+ * <ul>
+ * <li>The type of this element must be {@link SetDlSrcAction}.</li>
+ * <li>
+ * The source MAC address cannot be changed to the following
+ * addresses.
+ * <ul>
+ * <li>Zero <code>00:00:00:00:00:00</code></li>
+ * <li>Broadcast address <code>ff:ff:ff:ff:ff:ff</code></li>
+ * <li>Multicast address</li>
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * <dt>dldst
+ * <dd style="margin-left: 1.5em;">
+ * Specifies the action that sets the destination MAC address in
+ * Ethernet header.
+ * <ul>
+ * <li>The type of this element must be {@link SetDlDstAction}.</li>
+ * <li>
+ * The destination MAC address cannot be changed to the following
+ * addresses.
+ * <ul>
+ * <li>Zero <code>00:00:00:00:00:00</code></li>
+ * <li>Broadcast address <code>ff:ff:ff:ff:ff:ff</code></li>
+ * <li>Multicast address</li>
+ * </ul>
+ * </li>
+ * </ul>
+ *
+ * <dt>vlanpcp
+ * <dd style="margin-left: 1.5em;">
+ * Specifies the action that sets the VLAN priority in Ethernet
+ * header.
+ * <ul>
+ * <li>The type of this element must be {@link SetVlanPcpAction}.</li>
+ * <li>This element does not affect packets without VLAN tag.</li>
+ * </ul>
+ *
+ * <dt>inet4src
+ * <dd style="margin-left: 1.5em;">
+ * Specifies the action that sets the source IP address in IPv4
+ * header.
+ * <ul>
+ * <li>
+ * The type of this element must be {@link SetInet4SrcAction}.
+ * </li>
+ * <li>This element does not affect packets without IPv4 header.</li>
+ * <li>
+ * <strong>This element is not yet supported.</strong>
+ * </li>
+ * </ul>
+ *
+ * <dt>inet4dst
+ * <dd style="margin-left: 1.5em;">
+ * Specifies the action that sets the destination IP address in IPv4
+ * header.
+ * <ul>
+ * <li>
+ * The type of this element must be {@link SetInet4DstAction}.
+ * </li>
+ * <li>This element does not affect packets without IPv4 header.</li>
+ * <li>
+ * <strong>This element is not yet supported.</strong>
+ * </li>
+ * </ul>
+ *
+ * <dt>dscp
+ * <dd style="margin-left: 1.5em;">
+ * Specifies the action that sets the DSCP value in IP header.
+ * The type of this element must be {@link SetDscpAction}.
+ * <ul>
+ * <li>
+ * The type of this element must be {@link SetDscpAction}.
+ * </li>
+ * <li>This element does not affect packets without IP header.</li>
+ * </ul>
+ *
+ * <dt>tpsrc
+ * <dd style="margin-left: 1.5em;">
+ * Specifies the action that sets the source port number in TCP or
+ * UDP header.
+ * <ul>
+ * <li>
+ * The type of this element must be {@link SetTpSrcAction}.
+ * </li>
+ * <li>
+ * This element does not affect packets without TCP or UDP header.
+ * </li>
+ * <li>
+ * <strong>This element is not yet supported.</strong>
+ * </li>
+ * </ul>
+ *
+ * <dt>tpdst
+ * <dd style="margin-left: 1.5em;">
+ * Specifies the action that sets the destination port number in TCP or
+ * UDP header.
+ * <ul>
+ * <li>
+ * The type of this element must be {@link SetTpDstAction}.
+ * </li>
+ * <li>
+ * This element does not affect packets without TCP or UDP header.
+ * </li>
+ * <li>
+ * <strong>This element is not yet supported.</strong>
+ * </li>
+ * </ul>
+ *
+ * <dt>icmptype
+ * <dd style="margin-left: 1.5em;">
+ * Specifies the action that sets the ICMP type in ICMPv4 header.
+ * <ul>
+ * <li>
+ * The type of this element must be {@link SetIcmpTypeAction}.
+ * </li>
+ * <li>
+ * This element does not affect packets without ICMPv4 header.
+ * </li>
+ * </ul>
+ *
+ * <dt>icmpcode
+ * <dd style="margin-left: 1.5em;">
+ * Specifies the action that sets the ICMP code in ICMPv4 header.
+ * <ul>
+ * <li>
+ * The type of this element must be {@link SetIcmpCodeAction}.
+ * </li>
+ * <li>
+ * This element does not affect packets without ICMPv4 header.
+ * </li>
+ * </ul>
+ * </dl>
+ */
+ @XmlElementWrapper
+ @XmlElements({
+ @XmlElement(name = "dlsrc", type = SetDlSrcAction.class),
+ @XmlElement(name = "dldst", type = SetDlDstAction.class),
+ @XmlElement(name = "vlanpcp", type = SetVlanPcpAction.class),
+ @XmlElement(name = "inet4src", type = SetInet4SrcAction.class),
+ @XmlElement(name = "inet4dst", type = SetInet4DstAction.class),
+ @XmlElement(name = "dscp", type = SetDscpAction.class),
+ @XmlElement(name = "tpsrc", type = SetTpSrcAction.class),
+ @XmlElement(name = "tpdst", type = SetTpDstAction.class),
+ @XmlElement(name = "icmptype", type = SetIcmpTypeAction.class),
+ @XmlElement(name = "icmpcode", type = SetIcmpCodeAction.class)
+ })
+ private List<FlowAction> actions;
+
+ /**
+ * Private constructor only for JAXB.
+ */
+ private FlowFilter() {
+ }
+
+ /**
+ * Construct a new flow filter configuration.
+ *
+ * @param idx An {@link Integer} instance which represents the filter
+ * index.
+ * @param cond The name of the flow condition.
+ * @param type The type of the flow filter.
+ * {@code null} cannot be specified.
+ * @param acts A list of {@link FlowAction} instances to be applied to
+ * packets.
+ */
+ private FlowFilter(Integer idx, String cond, FilterType type,
+ List<FlowAction> acts) {
+ index = idx;
+ condition = cond;
+ filterType = type;
+ if (acts != null && !acts.isEmpty()) {
+ actions = new ArrayList(acts);
+ }
+ }
+
+ /**
+ * Construct a new flow filter configuration without specifying
+ * filter index.
+ *
+ * @param cond The name of the flow condition.
+ * {@code null} cannot be specified.
+ * @param type The type of the flow filter.
+ * {@code null} cannot be specified.
+ * @param acts A list of {@link FlowAction} instances to be applied to
+ * packets.
+ */
+ public FlowFilter(String cond, FilterType type, List<FlowAction> acts) {
+ this(null, cond, type, acts);
+ }
+
+ /**
+ * Construct a new flow filter configuration.
+ *
+ * @param idx The index value to be assigned to the flow filter.
+ * The range of value that can be specified is from
+ * <strong>1</strong> to <strong>65535</strong>.
+ * @param cond The name of the flow condition.
+ * {@code null} cannot be specified.
+ * @param type The type of the flow filter.
+ * {@code null} cannot be specified.
+ * @param acts A list of {@link FlowAction} instances to be applied to
+ * packets.
+ */
+ public FlowFilter(int idx, String cond, FilterType type,
+ List<FlowAction> acts) {
+ this(Integer.valueOf(idx), cond, type, acts);
+ }
+
+ /**
+ * Return an index value assigned to this instance.
+ *
+ * @return An {@link Integer} instance which represents an index value
+ * assigned to this instance.
+ * {@code null} is returned if no index is assigned.
+ */
+ public Integer getIndex() {
+ return index;
+ }
+
+ /**
+ * Return the name of the flow condition configured in this instance.
+ *
+ * @return The name of the flow condition.
+ */
+ public String getFlowConditionName() {
+ return condition;
+ }
+
+ /**
+ * Return a {@link FilterType} instance which represents the type of
+ * this flow filter.
+ *
+ * @return A {@link FilterType} instance.
+ * {@code null} is returned if no filter type is configured.
+ */
+ public FilterType getFilterType() {
+ return filterType;
+ }
+
+ /**
+ * Return a list of {@link FlowAction} instances to be applied to the
+ * packet when this flow filter is applied.
+ *
+ * @return A list of {@link FlowAction} instances.
+ * {@code null} is returned if no flow action is configured.
+ */
+ public List<FlowAction> getActions() {
+ return (actions == null)
+ ? null
+ : new ArrayList<FlowAction>(actions);
+ }
+
+ /**
+ * Determine whether the given object is identical to this object.
+ *
+ * @param o An object to be compared.
+ * @return {@code true} if identical. Otherwise {@code false}.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o == null || !getClass().equals(o.getClass())) {
+ return false;
+ }
+
+ FlowFilter ff = (FlowFilter)o;
+ return (Objects.equals(index, ff.index) &&
+ Objects.equals(condition, ff.condition) &&
+ Objects.equals(filterType, ff.filterType) &&
+ Objects.equals(actions, ff.actions));
+ }
+
+ /**
+ * Return the hash code of this object.
+ *
+ * @return The hash code.
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(index, condition, filterType, actions);
+ }
+
+ /**
+ * Return a string representation of this object.
+ *
+ * @return A string representation of this object.
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("FlowFilter[");
+ String sep = "";
+ if (index != null) {
+ builder.append("index=").append(index.toString());
+ sep = ",";
+ }
+ if (condition != null) {
+ builder.append(sep).append("cond=").append(condition);
+ sep = ",";
+ }
+ if (filterType != null) {
+ builder.append(sep).append("type=").append(filterType);
+ sep = ",";
+ }
+ if (actions != null) {
+ builder.append(sep).append("actions=").append(actions);
+ }
+
+ return builder.append(']').toString();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.flow.filter;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+/**
+ * {@code PassFilter} class describes the PASS flow filter which lets the
+ * specified packets through the virtual node in the VTN.
+ *
+ * <h4>Example JSON</h4>
+ * <pre class="prettyprint lang-json">{}</pre>
+ *
+ * @since Helium
+ */
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@XmlRootElement(name = "pass")
+@XmlAccessorType(XmlAccessType.NONE)
+public final class PassFilter extends FilterType {
+ /**
+ * Version number for serialization.
+ */
+ private static final long serialVersionUID = 1295310703141555376L;
+
+ /**
+ * Construct a new instance.
+ */
+ public PassFilter() {
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.flow.filter;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import org.opendaylight.vtn.manager.VBridgeIfPath;
+import org.opendaylight.vtn.manager.VInterfacePath;
+import org.opendaylight.vtn.manager.VInterfacePathAdapter;
+import org.opendaylight.vtn.manager.VTerminalIfPath;
+
+/**
+ * {@code RedirectFilter} class describes the REDIRECT flow filter which
+ * forwards the specified packets to another virtual interface in the VTN.
+ *
+ * <h4>Example JSON</h4>
+ * <pre class="prettyprint lang-json">
+ * {
+ * "destination": {
+ * "bridge": "vbridge_1",
+ * "interface": "if0",
+ * },
+ * "output": true
+ * }</pre>
+ *
+ * @since Helium
+ */
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@XmlRootElement(name = "redirect")
+@XmlAccessorType(XmlAccessType.NONE)
+public final class RedirectFilter extends FilterType {
+ /**
+ * Version number for serialization.
+ */
+ private static final long serialVersionUID = 2299914147430572837L;
+
+ /**
+ * The path to the virtual interface where the specified packets are
+ * forwarded.
+ *
+ * <ul>
+ * <li>
+ * The VTN name configured in the <strong>tenant</strong> attribute is
+ * always ignored. The VTN name is always determined by the location
+ * of the virtual node that contains the flow filter.
+ * </li>
+ * <li>
+ * The location of the virtual interface that contains this
+ * flow filter can not be specified.
+ * </li>
+ * <li>
+ * Note that every packet redirected by the flow filter is discarded
+ * if the virtual interface specified by this element does not exist
+ * in the VTN.
+ * </li>
+ * </ul>
+ * <p>
+ * Packet redirection should be configured not to cause the packet loop.
+ * The number of virtual node hops per a flow (the number of packet
+ * redirections) is limited to <strong>100</strong>.
+ * If the number of virtual node hops exceeds the limit, it is treated
+ * as the packet loop and then the packet is discarded.
+ * </p>
+ */
+ @XmlJavaTypeAdapter(VInterfacePathAdapter.class)
+ @XmlElement(required = true)
+ private VInterfacePath destination;
+
+ /**
+ * Determine the direction of the packet redirection.
+ *
+ * <ul>
+ * <li>
+ * If <strong>true</strong> is specified, the packet is redirected
+ * as outgoing packet.
+ * <ul>
+ * <li>
+ * The redirected packet will be treated as if it is transmitted
+ * from the virtual interface specified by the
+ * <strong>destination</strong> element.
+ * </li>
+ * <li>
+ * A list of flow filters for outgoing packets configured in the
+ * virtual interface specified by <strong>destination</strong>
+ * will be evaluated against the redirected packet.
+ * If the packet is passed by the flow filter, it is transmitted
+ * to the physical network mapped to the virtual interface by
+ * port mapping. The packet will be discarded if port mapping
+ * is not configured to the virtual interface.
+ * </li>
+ * </ul>
+ * </li>
+ * <li>
+ * If <strong>false</strong> is specified, the packet is redirected
+ * as incoming packet.
+ * <ul>
+ * <li>
+ * The redirected packet will be treated as if it is received from
+ * the virtual interface specified by the
+ * <strong>destination</strong> element.
+ * The packet is redirected even if no physical network is mapped
+ * to the destination virtual interface by port mapping.
+ * </li>
+ * <li>
+ * A list of flow filters for incoming packets configured in the
+ * virtual interface specified by <strong>destination</strong>
+ * will be evaluated against the redirected packet.
+ * If the packet is passed by the flow filter, it is forwarded to
+ * the virtual node that contains the virtual interface.
+ * </li>
+ * </ul>
+ * </li>
+ * <li>
+ * If omitted, it will be treated as if <strong>false</strong> is
+ * specified.
+ * </li>
+ * </ul>
+ */
+ @XmlAttribute
+ private boolean output;
+
+ /**
+ * Private constructor only for JAXB.
+ */
+ private RedirectFilter() {
+ }
+
+ /**
+ * Construct a new instance that specifies the packet redirection to be
+ * done by a flow filter.
+ *
+ * @param path
+ * The path to the vBridge interface where the specified packets should
+ * be redirected.
+ * <ul>
+ * <li>{@code null} can not be specified.</li>
+ * <li>
+ * The VTN name configured in {@code path} is always ignored.
+ * The VTN name is always determined by the location of the virtual
+ * node that contains the flow filter.
+ * </li>
+ * </ul>
+ * @param out {@code true} means the redirected packet should be
+ * treated as outgoing packet.
+ * {@code false} means the redirected packet should be
+ * treated as incoming packet.
+ */
+ public RedirectFilter(VBridgeIfPath path, boolean out) {
+ destination = path;
+ output = out;
+ }
+
+ /**
+ * Construct a new instance that specifies the packet redirection to be
+ * done by a flow filter.
+ *
+ * @param path
+ * The path to the vTerminal interface where the specified packets should
+ * be redirected.
+ * <ul>
+ * <li>{@code null} can not be specified.</li>
+ * <li>
+ * The VTN name configured in {@code path} is always ignored.
+ * The VTN name is always determined by the location of the virtual
+ * node that contains the flow filter.
+ * </li>
+ * </ul>
+ * @param out {@code true} means the redirected packet should be
+ * treated as outgoing packet.
+ * {@code false} means the redirected packet should be
+ * treated as incoming packet.
+ */
+ public RedirectFilter(VTerminalIfPath path, boolean out) {
+ destination = path;
+ output = out;
+ }
+
+ /**
+ * Return the location of the virtual interface where the packet should
+ * be redirected.
+ *
+ * @return A {@link VInterfacePath} instance.
+ */
+ public VInterfacePath getDestination() {
+ return destination;
+ }
+
+ /**
+ * Determine whether the direction of packet redirection.
+ *
+ * @return {@code true} is returned if the redirected packet should be
+ * treated as outgoing packet.
+ * {@code false} is returned if the redirected packet should be
+ * treated as incoming packet.
+ */
+ public boolean isOutput() {
+ return output;
+ }
+
+ /**
+ * Determine whether the given object is identical to this object.
+ *
+ * @param o An object to be compared.
+ * @return {@code true} if identical. Otherwise {@code false}.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+
+ RedirectFilter rf = (RedirectFilter)o;
+ if (output != rf.output) {
+ return false;
+ }
+
+ if (destination == null) {
+ return (rf.destination == null);
+ }
+
+ return destination.equals(rf.destination);
+ }
+
+ /**
+ * Return the hash code of this object.
+ *
+ * @return The hash code.
+ */
+ @Override
+ public int hashCode() {
+ int h = super.hashCode();
+ if (output) {
+ h++;
+ }
+ if (destination != null) {
+ h += (destination.hashCode() * 17);
+ }
+
+ return h;
+ }
+
+ /**
+ * Return a string representation of this object.
+ *
+ * @return A string representation of this object.
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("RedirectFilter[");
+ if (destination != null) {
+ builder.append("destination=").append(destination).append(',');
+ }
+ return builder.append("output=").append(output).append(']').toString();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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
+ */
+
+/**
+ * This package provides public APIs related to flow filter.
+ *
+ * <h2 id="function-overview" style="border-bottom: 4px double #aaaaaa; padding-top: 0.5em;">
+ * Function overview
+ * </h2>
+ *
+ * <div style="margin-left: 1em;">
+ * <p>
+ * Flow filter provides packet filtering feature for packets forwarded
+ * in <a href="../../package-summary.html#VTN">VTN</a>.
+ * Flow filter can not only filter out the specified packets but also
+ * modify the specified packets.
+ * </p>
+ * <p>
+ * Each flow filter must specify a
+ * <a href="../cond/package-summary.html">flow condition</a> by name.
+ * If a packet matches the condition described by the flow condition in a
+ * flow filter, then actions configured in the same flow filter is applied
+ * to that packet.
+ * </p>
+ * </div>
+ *
+ * <h3 id="type" style="border-bottom: 2px solid #aaaaaa;">
+ * Type of flow filter
+ * </h3>
+ * <div style="margin-left: 1em;">
+ * <p>
+ * There are three types of flow filter as follows.
+ * </p>
+ * <dl style="margin-left: 1em;">
+ * <dt id="type.PASS" style="font-weight: bold; margin-top: 0.5em;">PASS
+ * <dd style="margin-left: 2em;">
+ * Let the packet through the virtual node if the packet matches the
+ * flow condition configured in a flow filter.
+ * This type of flow filter can be used to modify the specified packets.
+ *
+ * <dt id="type.DROP" style="font-weight: bold; margin-top: 0.5em;">DROP
+ * <dd style="margin-left: 2em;">
+ * Discard the packet if the packet matches the flow condition configured
+ * in a flow filter.
+ *
+ * <dt id="type.REDIRECT" style="font-weight: bold; margin-top: 0.5em;">REDIRECT
+ * <dd style="margin-left: 2em;">
+ * Forward the packet to another virtual interface in the same VTN if the
+ * packet matches the flow condition configured in a flow filter.
+ * This type of flow filter also can modify the matched packet.
+ * See description about <a href="#redirect">packet redirection</a> for
+ * more details.
+ * </dl>
+ * </div>
+ *
+ * <h3 id="actions" style="border-bottom: 2px solid #aaaaaa;">
+ * Flow action list
+ * </h3>
+ * <div style="margin-left: 1em;">
+ * <p>
+ * <strong>Flow action list</strong> is a list of rules to modify packet.
+ * </p>
+ * <ul>
+ * <li>
+ * When a <a href="#type.PASS">PASS</a> or a
+ * <a href="#type.REDIRECT">REDIRECT</a> flow filter is applied to
+ * a packet, flow actions configured in the same flow filter are applied
+ * to the packet in order.
+ * </li>
+ * <li>
+ * Although a <a href="#type.DROP">DROP</a> flow filter can have
+ * flow actions, they will be always ignored.
+ * </li>
+ * </ul>
+ *
+ * <p>
+ * Note that modification done by flow actions in a flow filter is visible
+ * to succeeding evaluation of flow filters.
+ * </p>
+ * </div>
+ *
+ * <h3 id="place" style="border-bottom: 2px solid #aaaaaa;">
+ * Place to configure flow filter
+ * </h3>
+ * <div style="margin-left: 1em;">
+ * <p>
+ * One or more flow filters can be configured in virtual node in VTN as a
+ * list, and it is evaluated when a packet is forwarded to the
+ * virtual node. Each flow filter has a unique index in the list, and
+ * they are evaluated in ascending order of indices, and only the first
+ * matched flow filter is applied to the packet.
+ * If none of flow filter in the list matches the packet, then the
+ * VTN Manager lets the packet through the virtual node without modifying
+ * the packet.
+ * </p>
+ * <p>
+ * Flow filter can be configured in the following places.
+ * </p>
+ * <dl style="margin-left: 1em;">
+ * <dt id="place.VTN" style="font-weight: bold; margin-top: 0.5em;">VTN
+ * <dd style="margin-left: 2em;">
+ * <p>
+ * Flow filters in this list are evaluated when an incoming packet is
+ * mapped to the VTN. Note that the VTN flow filter list is evaluated
+ * only once before other flow filter lists are evaluated.
+ * </p>
+ *
+ * <dt id="place.vBridge.in" style="font-weight: bold; margin-top: 0.5em;">vBridge (input)
+ * <dd style="margin-left: 2em;">
+ * <p>
+ * Flow filters in this list are evaluated when a packet is forwarded
+ * to the specified
+ * <a href="../../package-summary.html#vBridge">vBridge</a>.
+ * This list is evaluated at the following instances.
+ * </p>
+ * <ul>
+ * <li>
+ * When a packet is forwarded from the virtual interface to the
+ * vBridge.
+ * </li>
+ * <li>
+ * When an incoming packet is mapped to the vBridge by
+ * <a href="../../package-summary.html#VLAN-map">VLAN mapping</a> or
+ * <a href="../../package-summary.html#MAC-map">MAC mapping</a>.
+ * </li>
+ * </ul>
+ *
+ * <dt id="place.vBridge.out" style="font-weight: bold; margin-top: 0.5em;">vBridge (output)
+ * <dd style="margin-left: 2em;">
+ * <p>
+ * Flow filters in this list are evaluated when a packet is going to be
+ * transmitted to the physical network mapped to the
+ * <a href="../../package-summary.html#vBridge">vBridge</a> by
+ * <a href="../../package-summary.html#VLAN-map">VLAN mapping</a> or
+ * <a href="../../package-summary.html#MAC-map">MAC mapping</a>.
+ * Note that this list is not evaluated when a packet is forwarded to
+ * the virtual interface in the same vBridge.
+ * </p>
+ *
+ * <dt id="place.vBridge.vif.in" style="font-weight: bold; margin-top: 0.5em;">vBridge interface (input)
+ * <dd style="margin-left: 2em;">
+ * <p>
+ * Flow filters in this list are evaluated when a packet is forwarded to
+ * the specified
+ * <a href="../../package-summary.html#vInterface">virtual interface</a>
+ * in the <a href="../../package-summary.html#vBridge">vBridge</a>.
+ * This list is evaluated at the following instances.
+ * </p>
+ * <ul>
+ * <li>
+ * When an incoming packet is mapped to the vBridge interface by
+ * <a href="../../package-summary.html#port-map">port mapping</a>.
+ * </li>
+ * <li>
+ * When a packet is redirected by another flow filter to the
+ * vBridge interface as an incoming packet.
+ * </li>
+ * </ul>
+ *
+ * <dt id="place.vBridge.vif.out" style="font-weight: bold; margin-top: 0.5em;">vBridge interface (output)
+ * <dd style="margin-left: 2em;">
+ * <p>
+ * Flow filters in this list are evaluated when a packet is going to be
+ * transmitted to the physical network mapped to the
+ * <a href="../../package-summary.html#vInterface">virtual interface</a>
+ * in the <a href="../../package-summary.html#vBridge">vBridge</a>.
+ * This list is evaluated at the following instances.
+ * </p>
+ * <ul>
+ * <li>
+ * When a packet is forwarded from the vBridge to the virtual
+ * interface.
+ * </li>
+ * <li>
+ * When a packet is redirected by another flow filter to the
+ * vBridge interface as an outgoing packet.
+ * </li>
+ * </ul>
+ *
+ * <dt id="place.vTerminal.vif.in" style="font-weight: bold; margin-top: 0.5em;">vTerminal interface (input)
+ * <dd style="margin-left: 2em;">
+ * <p>
+ * Flow filters in this list are evaluated when a packet is forwarded
+ * to the specified
+ * <a href="../../package-summary.html#vInterface">virtual interface</a>
+ * in the <a href="../../package-summary.html#vTerminal">vTerminal</a>.
+ * This list is evaluated at the following instances.
+ * </p>
+ * <ul>
+ * <li>
+ * When an incoming packet is mapped to the vTerminal interface by
+ * <a href="../../package-summary.html#port-map">port mapping</a>.
+ * </li>
+ * <li>
+ * When a packet is redirected by another flow filter to the
+ * vTerminal interface as an incoming packet.
+ * </li>
+ * </ul>
+ * <p>
+ * vTerminal is an isolated input/output terminal.
+ * So an incoming packet is always discarded unless it is redirected
+ * to another virtual interface by the flow filter.
+ * </p>
+ *
+ * <dt id="place.vTerminal.vif.out" style="font-weight: bold; margin-top: 0.5em;">vTerminal interface (output)
+ * <dd style="margin-left: 2em;">
+ * <p>
+ * Flow filters in this list are evaluated when a packet is going to
+ * be transmitted to the physical network mapped to the
+ * <a href="../../package-summary.html#vInterface">virtual interface</a>
+ * in the <a href="../../package-summary.html#vTerminal">vTerminal</a>.
+ * </p>
+ * <p>
+ * This list is evaluated only when a packet is redirected by another
+ * flow filter to the vTerminal interface as an outgoing packet.
+ * </p>
+ * </dl>
+ * </div>
+ *
+ * <h3 id="redirect" style="border-bottom: 2px solid #aaaaaa;">
+ * Packet redirection
+ * </h3>
+ * <div style="margin-left: 1em;">
+ * <p>
+ * A <a href="#type.REDIRECT">REDIRECT</a> flow filter forwards the packet
+ * to another
+ * <a href="../../package-summary.html#vInterface">virtual interface</a>
+ * in the same <a href="../../package-summary.html#VTN">VTN</a>.
+ * A REDIRECT flow filter has the following configurations.
+ * </p>
+ * <dl style="margin-left: 1em;">
+ * <dt id="redirect.destination" style="font-weight: bold; margin-top: 0.5em;">Destination virtual interface
+ * <dd style="margin-left: 2em;">
+ * <p>
+ * The location of the destination virtual interface must be configured
+ * in every REDIRECT flow filter.
+ * </p>
+ * <ul>
+ * <li>
+ * Self-redirection (specifying the virtual interface that contains
+ * the REDIRECT flow filter itself as the destination) is always
+ * forbidden.
+ * </li>
+ * <li>
+ * If the specified destination node does not exist, every packets
+ * matched to that REDIRECT flow filter will be discarded.
+ * </li>
+ * </ul>
+ *
+ * <dt id="redirect.destination" style="font-weight: bold; margin-top: 0.5em;">Direction
+ * <dd style="margin-left: 2em;">
+ * <p>
+ * Every REDIRECT flow filter must choose the direction of the packet
+ * redirection, <strong>input</strong> or <strong>output</strong>.
+ * </p>
+ * <ul>
+ * <li>
+ * <p>
+ * <strong>input</strong> means that a redirected packet should be
+ * treated as an incoming packet as if it is forwarded or mapped
+ * to the specified virtual interface.
+ * </p>
+ * <p>
+ * A list of flow filters for incoming packets configured in the
+ * destination virtual interface is evaluated against the
+ * redirected packet. If the flow filter passes the packet,
+ * the packet is forwarded to the virtual node which contains the
+ * destination virtual interface.
+ * <ul>
+ * <li>
+ * If the destination virtual interface is attached to the
+ * <a href="../../package-summary.html#vBridge">vBridge</a>,
+ * then the packet is routed according to the vBridge
+ * configuration.
+ * Note that the source MAC address of the redirected packet
+ * is never learned into the
+ * <a href="../../package-summary.html#macTable">MAC address table</a>
+ * in the vBridge.
+ * </li>
+ * <li>
+ * If the destination virtual interface is attached to the
+ * <a href="../../package-summary.html#vTerminal">vTerminal</a>,
+ * then the packet is always discarded. In other words, the
+ * packet is always discarded unless the packet is redirected
+ * to another interface by the flow filter configured in the
+ * destination virtual interface.
+ * </li>
+ * </ul>
+ * <p>
+ * </li>
+ * <li>
+ * <p>
+ * <strong>output</strong> means that a redirected packet should be
+ * treated as an outgoing packet as if it is going to be
+ * transmitted to the physical network mapped to the specified
+ * virtual interface.
+ * </p>
+ * <p>
+ * A list of flow filters for outgoing packets configured in the
+ * destination virtual interface is evaluated against the
+ * redirected packet. If the flow filter passes the packet,
+ * the packet is transmitted to the physical network mapped to the
+ * virtual interface by
+ * <a href="../../package-summary.html#port-map">port mapping</a>.
+ * Note that the packet is discarded if the port mapping is not
+ * configured in the virtual interface.
+ * </p>
+ * </li>
+ * </ul>
+ * </dl>
+ *
+ * <h4 id="redirect.loop" style="border-bottom: 1px dashed #aaaaaa;">
+ * Packet loop detection
+ * </h4>
+ * <div style="margin-left: 1em;">
+ * <p>
+ * <a href="#type.REDIRECT">REDIRECT</a> flow filter should be configured
+ * not to cause the packet loop. The number of virtual node hops per a
+ * flow (the number of packet redirections per a flow) is limited to
+ * <strong>100</strong>. If the number of virtual node hops exceeds the
+ * limit, it is treated as the packet loop and then the packet is
+ * discarded.
+ * </p>
+ * </div>
+ * </div>
+ *
+ * <h3 style="border-bottom: 2px solid #aaaaaa;">
+ * Limitations
+ * </h3>
+ * <div style="margin-left: 1em;">
+ * <h4 id="multicast" style="border-bottom: 1px dashed #aaaaaa;">
+ * Broadcast/Multicast packet
+ * </h4>
+ * <div style="margin-left: 1em;">
+ * <p>
+ * Basically, flow filter can be applied to unicast packets.
+ * So flow filter ignores broadcast and multicast packets except for
+ * <a href="#type.DROP">DROP</a> flow filter.
+ * </p>
+ * <p>
+ * For example, a broadcast packet is mapped to the VTN, flow filters
+ * in the <a href="#place.VTN">VTN flow filter</a> are evaluated as
+ * follows.
+ * </p>
+ * <ul>
+ * <li>
+ * A flow filter is ignored if its type is <a href="#type.PASS">PASS</a>
+ * or <a href="#type.REDIRECT">REDIRECT</a>.
+ * </li>
+ * <li>
+ * A flow filter is evaluated if its type is
+ * <a href="#type.DROP">DROP</a>. It the broadcast packet matches that
+ * flow filter, then the packet is discarded.
+ * </li>
+ * </ul>
+ * </div>
+ * </div>
+ *
+ * @since Helium
+ */
+package org.opendaylight.vtn.manager.flow.filter;
import org.opendaylight.vtn.manager.flow.action.SetTpSrcAction;
import org.opendaylight.vtn.manager.flow.action.SetVlanIdAction;
import org.opendaylight.vtn.manager.flow.action.SetVlanPcpAction;
+import org.opendaylight.vtn.manager.flow.filter.DropFilter;
+import org.opendaylight.vtn.manager.flow.filter.FilterType;
+import org.opendaylight.vtn.manager.flow.filter.PassFilter;
+import org.opendaylight.vtn.manager.flow.filter.RedirectFilter;
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.core.NodeConnector;
return null;
}
+ /**
+ * Create a copy of the specified {@link FilterType} instance.
+ *
+ * @param type A {@link FilterType} instance to be copied.
+ * @return A copied {@link FilterType} instance.
+ */
+ protected static FilterType copy(FilterType type) {
+ if (type == null) {
+ return null;
+ }
+ if (type instanceof PassFilter) {
+ return new PassFilter();
+ }
+ if (type instanceof DropFilter) {
+ return new DropFilter();
+ }
+ if (type instanceof RedirectFilter) {
+ RedirectFilter rf = (RedirectFilter)type;
+ VInterfacePath path = rf.getDestination();
+ boolean output = rf.isOutput();
+ if (path instanceof VBridgeIfPath) {
+ VBridgeIfPath ipath = new VBridgeIfPath(
+ copy(path.getTenantName()),
+ copy(path.getTenantNodeName()),
+ copy(path.getInterfaceName()));
+ return new RedirectFilter(ipath, output);
+ } else {
+ VTerminalIfPath ipath = new VTerminalIfPath(
+ copy(path.getTenantName()),
+ copy(path.getTenantNodeName()),
+ copy(path.getInterfaceName()));
+ return new RedirectFilter(ipath, output);
+ }
+ }
+
+ fail("Unexpected filter type: " + type);
+ return null;
+ }
+
/**
* Create a deep copy of the specified set.
*
dst.add(copy((MacAddressEntry)elem));
} else if (elem instanceof FlowAction) {
dst.add(copy((FlowAction)elem));
+ } else if (elem instanceof FilterType) {
+ dst.add(copy((FilterType)elem));
} else {
fail("Unexpected instanse in the collection: " + elem);
}
assertEquals(bname, path.getBridgeName());
assertEquals(iname, path.getInterfaceName());
assertEquals("vBridge-IF", path.getNodeType());
+
+ VTenantPath clone = path.clone();
+ assertNotSame(clone, path);
+ assertEquals(clone, path);
+
+ String name = tname + "_new";
+ VBridgeIfPath path1 =
+ (VBridgeIfPath)path.replaceTenantName(name);
+ assertEquals(name, path1.getTenantName());
+ assertEquals(bname, path1.getBridgeName());
+ assertEquals(iname, path1.getInterfaceName());
+ assertEquals("vBridge-IF", path1.getNodeType());
+ assertEquals(VBridgeIfPath.class, path1.getClass());
}
}
}
assertEquals(tname, path.getTenantName());
assertEquals(bname, path.getBridgeName());
assertEquals("vBridge", path.getNodeType());
+
+ VTenantPath clone = path.clone();
+ assertNotSame(clone, path);
+ assertEquals(clone, path);
+
+ String name = tname + "_new";
+ VBridgePath path1 = (VBridgePath)path.replaceTenantName(name);
+ assertEquals(name, path1.getTenantName());
+ assertEquals(bname, path1.getBridgeName());
+ assertEquals("vBridge", path1.getNodeType());
+ assertEquals(VBridgePath.class, path1.getClass());
}
}
}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager;
+
+import org.junit.Test;
+
+/**
+ * JUnit test for {@link VInterfacePathAdapter}.
+ */
+public class VInterfacePathAdapterTest extends TestBase {
+ /**
+ * Test case for {@link VInterfacePathAdapter#marshal(VInterfacePath)} and
+ * {@link VInterfacePathAdapter#unmarshal(VNodeLocation)}.
+ */
+ @Test
+ public void testMarshal() {
+ VInterfacePathAdapter adapter = new VInterfacePathAdapter();
+ assertEquals(null, adapter.marshal(null));
+ assertEquals(null, adapter.unmarshal(null));
+
+ for (String tname: createStrings("tenant")) {
+ for (String bname: createStrings("bridge", false)) {
+ VBridgePath bpath = new VBridgePath(tname, bname);
+ VTerminalPath vtpath = new VTerminalPath(tname, bname);
+ for (String iname: createStrings("ifname", false)) {
+ VBridgeIfPath bipath = new VBridgeIfPath(bpath, iname);
+ VNodeLocation loc = new VNodeLocation(bipath);
+ assertEquals(bipath, adapter.unmarshal(loc));
+ assertEquals(loc, adapter.marshal(bipath));
+
+ VTerminalIfPath vipath =
+ new VTerminalIfPath(vtpath, iname);
+ loc = new VNodeLocation(vipath);
+ assertEquals(vipath, adapter.unmarshal(loc));
+ assertEquals(loc, adapter.marshal(vipath));
+ }
+ }
+ }
+
+ // Specifying invalid path.
+ VInterfacePath path = new VBridgeIfPath("vtn", null, "if_1");
+ VNodeLocation loc = path.toVNodeLocation();
+ VInterfacePath invalid = adapter.unmarshal(loc);
+ assertEquals(ErrorVNodePath.class, invalid.getClass());
+ assertEquals("Unexpected interface location: " + loc,
+ ((ErrorVNodePath)invalid).getError());
+
+ path = new VBridgeIfPath("vtn", "vbridge", null);
+ loc = path.toVNodeLocation();
+ invalid = adapter.unmarshal(loc);
+ assertEquals(ErrorVNodePath.class, invalid.getClass());
+ assertEquals("Interface name is not specified: " + loc,
+ ((ErrorVNodePath)invalid).getError());
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager;
+
+import org.junit.Test;
+
+/**
+ * JUnit test for {@link VNodePathAdapter}.
+ */
+public class VNodePathAdapterTest extends TestBase {
+ /**
+ * Test case for {@link VNodePathAdapter#marshal(VNodePath)} and
+ * {@link VNodePathAdapter#unmarshal(VNodeLocation)}.
+ */
+ @Test
+ public void testMarshal() {
+ VNodePathAdapter adapter = new VNodePathAdapter();
+ assertEquals(null, adapter.marshal(null));
+ assertEquals(null, adapter.unmarshal(null));
+
+ for (String tname: createStrings("tenant")) {
+ for (String bname: createStrings("bridge", false)) {
+ VBridgePath bpath = new VBridgePath(tname, bname);
+ VNodeLocation loc = new VNodeLocation(bpath);
+ assertEquals(bpath, adapter.unmarshal(loc));
+ assertEquals(loc, adapter.marshal(bpath));
+
+ VTerminalPath vtpath = new VTerminalPath(tname, bname);
+ loc = new VNodeLocation(vtpath);
+ assertEquals(vtpath, adapter.unmarshal(loc));
+ assertEquals(loc, adapter.marshal(vtpath));
+
+ for (String iname: createStrings("ifname", false)) {
+ VBridgeIfPath bipath = new VBridgeIfPath(bpath, iname);
+ loc = new VNodeLocation(bipath);
+ assertEquals(bipath, adapter.unmarshal(loc));
+ assertEquals(loc, adapter.marshal(bipath));
+
+ VTerminalIfPath vipath =
+ new VTerminalIfPath(vtpath, iname);
+ loc = new VNodeLocation(vipath);
+ assertEquals(vipath, adapter.unmarshal(loc));
+ assertEquals(loc, adapter.marshal(vipath));
+ }
+ }
+ }
+
+ // Specifying invalid path.
+ VNodePath path = new VBridgePath("vtn", null);
+ VNodeLocation loc = path.toVNodeLocation();
+ VNodePath invalid = adapter.unmarshal(loc);
+ assertEquals(ErrorVNodePath.class, invalid.getClass());
+ assertEquals("Unexpected node location: " + loc,
+ ((ErrorVNodePath)invalid).getError());
+
+ path = new VBridgeIfPath("vtn", null, "if_1");
+ loc = path.toVNodeLocation();
+ invalid = adapter.unmarshal(loc);
+ assertEquals(ErrorVNodePath.class, invalid.getClass());
+ assertEquals("Unexpected node location: " + loc,
+ ((ErrorVNodePath)invalid).getError());
+ }
+}
VTenantPath path = new VTenantPath(tname);
assertEquals(tname, path.getTenantName());
assertEquals("VTN", path.getNodeType());
+
+ VTenantPath clone = path.clone();
+ assertNotSame(clone, path);
+ assertEquals(clone, path);
+
+ String name = tname + "_new";
+ VTenantPath path1 = path.replaceTenantName(name);
+ assertEquals(name, path1.getTenantName());
+ assertEquals("VTN", path1.getNodeType());
+ assertEquals(VTenantPath.class, path1.getClass());
}
}
assertEquals(vtname, path.getTerminalName());
assertEquals(iname, path.getInterfaceName());
assertEquals("vTerminal-IF", path.getNodeType());
+
+ VTenantPath clone = path.clone();
+ assertNotSame(clone, path);
+ assertEquals(clone, path);
+
+ String name = tname + "_new";
+ VTerminalIfPath path1 =
+ (VTerminalIfPath)path.replaceTenantName(name);
+ assertEquals(name, path1.getTenantName());
+ assertEquals(vtname, path1.getTerminalName());
+ assertEquals(iname, path1.getInterfaceName());
+ assertEquals("vTerminal-IF", path1.getNodeType());
+ assertEquals(VTerminalIfPath.class, path1.getClass());
}
}
}
assertEquals(tname, path.getTenantName());
assertEquals(mname, path.getTerminalName());
assertEquals("vTerminal", path.getNodeType());
+
+ VTenantPath clone = path.clone();
+ assertNotSame(clone, path);
+ assertEquals(clone, path);
+
+ String name = tname + "_new";
+ VTerminalPath path1 =
+ (VTerminalPath)path.replaceTenantName(name);
+ assertEquals(name, path1.getTenantName());
+ assertEquals(mname, path1.getTerminalName());
+ assertEquals("vTerminal", path1.getNodeType());
+ assertEquals(VTerminalPath.class, path1.getClass());
}
}
}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.flow.filter;
+
+import java.util.HashSet;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.VBridgeIfPath;
+
+import org.opendaylight.vtn.manager.TestBase;
+
+/**
+ * JUnit test for {@link DropFilter}.
+ */
+public class DropFilterTest extends TestBase {
+ /**
+ * Test case for {@link DropFilter#equals(Object)} and
+ * {@link DropFilter#hashCode()}.
+ */
+ @Test
+ public void testEquals() {
+ HashSet<Object> set = new HashSet<Object>();
+ testEquals(set, new DropFilter(), new DropFilter());
+ for (int i = 0; i < 10; i++) {
+ assertFalse(set.add(new DropFilter()));
+ }
+
+ assertEquals(1, set.size());
+ assertTrue(set.add(new PassFilter()));
+
+ VBridgeIfPath path = new VBridgeIfPath("vtn", "vbr", "if");
+ assertTrue(set.add(new RedirectFilter(path, true)));
+ assertEquals(3, set.size());
+ }
+
+ /**
+ * Test case for {@link DropFilter#toString()}.
+ */
+ @Test
+ public void testToString() {
+ for (int i = 0; i < 10; i++) {
+ DropFilter pf = new DropFilter();
+ assertEquals("DropFilter", pf.toString());
+ }
+ }
+
+ /**
+ * Ensure that {@link DropFilter} is serializable.
+ */
+ @Test
+ public void testSerialize() {
+ for (int i = 0; i < 10; i++) {
+ serializeTest(new DropFilter());
+ }
+ }
+
+ /**
+ * Ensure that {@link DropFilter} is mapped to XML root element.
+ */
+ @Test
+ public void testJAXB() {
+ for (int i = 0; i < 10; i++) {
+ jaxbTest(new DropFilter(), "drop");
+ }
+ }
+
+ /**
+ * Ensure that {@link DropFilter} is mapped to JSON object.
+ */
+ @Test
+ public void testJSON() {
+ for (int i = 0; i < 10; i++) {
+ jsonTest(new DropFilter());
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.flow.filter;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.VBridgeIfPath;
+import org.opendaylight.vtn.manager.VTerminalIfPath;
+import org.opendaylight.vtn.manager.flow.action.FlowAction;
+import org.opendaylight.vtn.manager.flow.action.SetDlDstAction;
+import org.opendaylight.vtn.manager.flow.action.SetDlSrcAction;
+import org.opendaylight.vtn.manager.flow.action.SetDscpAction;
+import org.opendaylight.vtn.manager.flow.action.SetIcmpCodeAction;
+import org.opendaylight.vtn.manager.flow.action.SetIcmpTypeAction;
+import org.opendaylight.vtn.manager.flow.action.SetInet4DstAction;
+import org.opendaylight.vtn.manager.flow.action.SetInet4SrcAction;
+import org.opendaylight.vtn.manager.flow.action.SetTpDstAction;
+import org.opendaylight.vtn.manager.flow.action.SetTpSrcAction;
+import org.opendaylight.vtn.manager.flow.action.SetVlanPcpAction;
+
+import org.opendaylight.vtn.manager.TestBase;
+
+/**
+ * JUnit test for {@link FlowFilter}.
+ */
+public class FlowFilterTest extends TestBase {
+ /**
+ * A list of {@link FilterType} instances for test.
+ */
+ private List<FilterType> filterTypes;
+
+ /**
+ * A list of {@link FlowAction} instance lists for test.
+ */
+ private List<List<FlowAction>> actionLists;
+
+ /**
+ * Test case for getter methods.
+ */
+ @Test
+ public void testGetter() {
+ int[] indices = {1, 100, 1000, 65535};
+ for (int index: indices) {
+ for (String cond: createStrings("cnd")) {
+ for (FilterType type: createFilterTypes()) {
+ for (List<FlowAction> actions: createActionLists()) {
+ FlowFilter ff = new FlowFilter(cond, type, actions);
+ List<FlowAction> exacts = actions;
+ if (exacts != null && exacts.isEmpty()) {
+ exacts = null;
+ }
+ assertEquals(null, ff.getIndex());
+ assertEquals(cond, ff.getFlowConditionName());
+ assertEquals(type, ff.getFilterType());
+ assertEquals(exacts, ff.getActions());
+
+ ff = new FlowFilter(index, cond, type, actions);
+ assertEquals(Integer.valueOf(index), ff.getIndex());
+ assertEquals(cond, ff.getFlowConditionName());
+ assertEquals(type, ff.getFilterType());
+
+ List<FlowAction> list = ff.getActions();
+ assertEquals(exacts, list);
+
+ // Ensure that a copy of action list is returned.
+ if (list != null) {
+ list.clear();
+ assertEquals(exacts, ff.getActions());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Test case for {@link FlowFilter#equals(Object)} and
+ * {@link FlowFilter#hashCode()}.
+ */
+ @Test
+ public void testEquals() {
+ HashSet<Object> set = new HashSet<Object>();
+ int[] indices = {0, 1, 65535};
+ List<String> conditions = createStrings("cnd");
+ List<FilterType> types = createFilterTypes();
+ List<List<FlowAction>> actLists = createActionLists();
+ for (Iterator<List<FlowAction>> it = actLists.iterator();
+ it.hasNext();) {
+ List<FlowAction> act = it.next();
+ if (act == null) {
+ it.remove();
+ break;
+ }
+ }
+
+ for (int index: indices) {
+ for (String cond: conditions) {
+ for (FilterType type: types) {
+ for (List<FlowAction> actions: actLists) {
+ FlowFilter ff1, ff2;
+
+ if (index == 0) {
+ ff1 = new FlowFilter(cond, type, actions);
+ ff2 = new FlowFilter(copy(cond), copy(type),
+ copy(actions));
+ } else {
+ ff1 = new FlowFilter(index, cond, type, actions);
+ ff2 = new FlowFilter(index, copy(cond), copy(type),
+ copy(actions));
+ }
+ testEquals(set, ff1, ff2);
+ }
+ }
+ }
+ }
+
+ int required = indices.length * conditions.size() * types.size() *
+ actLists.size();
+ assertEquals(required, set.size());
+ }
+
+ /**
+ * Test case for {@link FlowFilter#toString()}.
+ */
+ @Test
+ public void testToString() {
+ String prefix = "FlowFilter[";
+ String suffix = "]";
+ int[] indices = {0, 1, 1000, 65535};
+ for (int index: indices) {
+ for (String cond: createStrings("cnd")) {
+ for (FilterType type: createFilterTypes()) {
+ for (List<FlowAction> actions: createActionLists()) {
+ FlowFilter ff = (index == 0)
+ ? new FlowFilter(cond, type, actions)
+ : new FlowFilter(index, cond, type, actions);
+ String i = (index == 0)
+ ? null : "index=" + index;
+ String c = (cond == null) ? null : "cond=" + cond;
+ String t = (type == null) ? null : "type=" + type;
+ String a = (actions == null || actions.isEmpty())
+ ? null : "actions=" + actions;
+ String required = joinStrings(prefix, suffix, ",",
+ i, c, t, a);
+ assertEquals(required, ff.toString());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Ensure that {@link FlowFilter} is serializable.
+ */
+ @Test
+ public void testSerialize() {
+ int[] indices = {0, 100, 65535};
+ for (int index: indices) {
+ for (String cond: createStrings("cnd")) {
+ for (FilterType type: createFilterTypes()) {
+ for (List<FlowAction> actions: createActionLists()) {
+ FlowFilter ff = (index == 0)
+ ? new FlowFilter(cond, type, actions)
+ : new FlowFilter(index, cond, type, actions);
+ serializeTest(ff);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Ensure that {@link FlowFilter} is mapped to XML root element.
+ */
+ @Test
+ public void testJAXB() {
+ int[] indices = {0, 100, 65535};
+ for (int index: indices) {
+ for (String cond: createStrings("cnd")) {
+ for (FilterType type: createFilterTypes()) {
+ for (List<FlowAction> actions: createActionLists()) {
+ FlowFilter ff = (index == 0)
+ ? new FlowFilter(cond, type, actions)
+ : new FlowFilter(index, cond, type, actions);
+ jaxbTest(ff, "flowfilter");
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Ensure that {@link FlowFilter} is mapped to JSON object.
+ */
+ @Test
+ public void testJSON() {
+ int[] indices = {0, 100, 65535};
+ for (int index: indices) {
+ for (String cond: createStrings("cnd")) {
+ for (FilterType type: createFilterTypes()) {
+ for (List<FlowAction> actions: createActionLists()) {
+ FlowFilter ff = (index == 0)
+ ? new FlowFilter(cond, type, actions)
+ : new FlowFilter(index, cond, type, actions);
+ jsonTest(ff);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Create a list of {@link FilterType} instances.
+ *
+ * @return A list of {@link FilterType} instances.
+ */
+ private List<FilterType> createFilterTypes() {
+ List<FilterType> list = filterTypes;
+ if (list == null) {
+ list = new ArrayList<FilterType>();
+ list.add(null);
+ list.add(new PassFilter());
+ list.add(new DropFilter());
+ list.add(new RedirectFilter(
+ new VBridgeIfPath(null, "bname", "if1"), true));
+ list.add(new RedirectFilter(
+ new VTerminalIfPath("vtn", "vtname", "if2"), false));
+ filterTypes = list;
+ }
+
+ return list;
+ }
+
+ /**
+ * Create lists of {@link FlowAction} instances.
+ *
+ * @return A list of {@link FlowAction} instance lists.
+ */
+ private List<List<FlowAction>> createActionLists() {
+ List<List<FlowAction>> list = actionLists;
+ if (list == null) {
+ list = new ArrayList<List<FlowAction>>();
+ byte[] mac1 = {
+ (byte)0x00, (byte)0x01, (byte)0x02,
+ (byte)0x03, (byte)0x04, (byte)0x05,
+ };
+ byte[] mac2 = {
+ (byte)0x10, (byte)0x20, (byte)0x30,
+ (byte)0x40, (byte)0x50, (byte)0x60,
+ };
+ byte[] mac3 = {
+ (byte)0xa0, (byte)0xbb, (byte)0xcc,
+ (byte)0xdd, (byte)0xee, (byte)0xff,
+ };
+ byte[] mac4 = {
+ (byte)0xfa, (byte)0xf0, (byte)0xf1,
+ (byte)0xfa, (byte)0xfb, (byte)0xfc,
+ };
+
+ InetAddress addr1, addr2;
+ try {
+ addr1 = InetAddress.getByName("192.168.100.1");
+ addr2 = InetAddress.getByName("192.168.200.123");
+ } catch (Exception e) {
+ unexpected(e);
+ return null;
+ }
+
+ list.add(null);
+ list.add(new ArrayList<FlowAction>());
+ list.add(createActions(new SetDscpAction((byte)63)));
+ list.add(createActions(new SetDlSrcAction(mac1),
+ new SetDlDstAction(mac2),
+ new SetVlanPcpAction((byte)3)));
+
+ // Create all-in-one list.
+ list.add(createActions(new SetVlanPcpAction((byte)7),
+ new SetDscpAction((byte)4),
+ new SetTpSrcAction(65535),
+ new SetTpDstAction(0),
+ new SetDlSrcAction(mac3),
+ new SetDlDstAction(mac4),
+ new SetIcmpTypeAction((short)255),
+ new SetIcmpCodeAction((short)128),
+ new SetInet4SrcAction(addr1),
+ new SetInet4DstAction(addr2)));
+
+ actionLists = list;
+ }
+
+ return list;
+ }
+
+ /**
+ * Create a list of {@link FlowAction} instances.
+ *
+ * @param actions An array of {@link FlowAction} instances to be added
+ * to the list.
+ * @return A list of {@link FlowAction} instances.
+ */
+ private List<FlowAction> createActions(FlowAction ... actions) {
+ List<FlowAction> list = new ArrayList<FlowAction>();
+ for (FlowAction act: actions) {
+ list.add(act);
+ }
+
+ return list;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.flow.filter;
+
+import java.util.HashSet;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.VTerminalIfPath;
+
+import org.opendaylight.vtn.manager.TestBase;
+
+/**
+ * JUnit test for {@link PassFilter}.
+ */
+public class PassFilterTest extends TestBase {
+ /**
+ * Test case for {@link PassFilter#equals(Object)} and
+ * {@link PassFilter#hashCode()}.
+ */
+ @Test
+ public void testEquals() {
+ HashSet<Object> set = new HashSet<Object>();
+ testEquals(set, new PassFilter(), new PassFilter());
+ for (int i = 0; i < 10; i++) {
+ assertFalse(set.add(new PassFilter()));
+ }
+
+ assertEquals(1, set.size());
+ assertTrue(set.add(new DropFilter()));
+
+ VTerminalIfPath path = new VTerminalIfPath("vtn", "vtm", "if");
+ assertTrue(set.add(new RedirectFilter(path, false)));
+ assertEquals(3, set.size());
+ }
+
+ /**
+ * Test case for {@link PassFilter#toString()}.
+ */
+ @Test
+ public void testToString() {
+ for (int i = 0; i < 10; i++) {
+ PassFilter pf = new PassFilter();
+ assertEquals("PassFilter", pf.toString());
+ }
+ }
+
+ /**
+ * Ensure that {@link PassFilter} is serializable.
+ */
+ @Test
+ public void testSerialize() {
+ for (int i = 0; i < 10; i++) {
+ serializeTest(new PassFilter());
+ }
+ }
+
+ /**
+ * Ensure that {@link PassFilter} is mapped to XML root element.
+ */
+ @Test
+ public void testJAXB() {
+ for (int i = 0; i < 10; i++) {
+ jaxbTest(new PassFilter(), "pass");
+ }
+ }
+
+ /**
+ * Ensure that {@link PassFilter} is mapped to JSON object.
+ */
+ @Test
+ public void testJSON() {
+ for (int i = 0; i < 10; i++) {
+ jsonTest(new PassFilter());
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.flow.filter;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.codehaus.jettison.json.JSONObject;
+
+import org.opendaylight.vtn.manager.ErrorVNodePath;
+import org.opendaylight.vtn.manager.VBridgeIfPath;
+import org.opendaylight.vtn.manager.VBridgePath;
+import org.opendaylight.vtn.manager.VInterfacePath;
+import org.opendaylight.vtn.manager.VNodeLocation;
+import org.opendaylight.vtn.manager.VNodePath;
+import org.opendaylight.vtn.manager.VTenantPath;
+import org.opendaylight.vtn.manager.VTerminalIfPath;
+import org.opendaylight.vtn.manager.VTerminalPath;
+
+import org.opendaylight.vtn.manager.TestBase;
+
+/**
+ * JUnit test for {@link RedirectFilter}.
+ */
+public class RedirectFilterTest extends TestBase {
+ /**
+ * A list of {@link VInterfacePath} instances for test.
+ */
+ private List<VInterfacePath> interfaces;
+
+ /**
+ * Test case for getter methods.
+ */
+ @Test
+ public void testGetter() {
+ boolean[] bools = {true, false};
+ for (VInterfacePath path: createPaths()) {
+ for (boolean output: bools) {
+ RedirectFilter rf = (path instanceof VBridgeIfPath)
+ ? new RedirectFilter((VBridgeIfPath)path, output)
+ : new RedirectFilter((VTerminalIfPath)path, output);
+ assertEquals(path, rf.getDestination());
+ assertEquals(output, rf.isOutput());
+ }
+ }
+ }
+
+ /**
+ * Test case for {@link RedirectFilter#equals(Object)} and
+ * {@link RedirectFilter#hashCode()}.
+ */
+ @Test
+ public void testEquals() {
+ HashSet<Object> set = new HashSet<Object>();
+ List<VInterfacePath> paths = createPaths();
+ boolean[] bools = {true, false};
+ for (VInterfacePath path: createPaths()) {
+ for (boolean output: bools) {
+ RedirectFilter rf1 = (path instanceof VBridgeIfPath)
+ ? new RedirectFilter((VBridgeIfPath)path, output)
+ : new RedirectFilter((VTerminalIfPath)path, output);
+ VTenantPath dest = (path == null)
+ ? null
+ : ((VNodePath)path).clone();
+ RedirectFilter rf2 = (dest instanceof VBridgeIfPath)
+ ? new RedirectFilter((VBridgeIfPath)dest, output)
+ : new RedirectFilter((VTerminalIfPath)dest, output);
+ testEquals(set, rf1, rf2);
+ }
+ }
+
+ assertEquals(paths.size() * bools.length, set.size());
+ }
+
+ /**
+ * Test case for {@link RedirectFilter#toString()}.
+ */
+ @Test
+ public void testToString() {
+ String prefix = "RedirectFilter[";
+ String suffix = "]";
+ boolean[] bools = {true, false};
+ for (VInterfacePath path: createPaths()) {
+ for (boolean output: bools) {
+ RedirectFilter rf = (path instanceof VBridgeIfPath)
+ ? new RedirectFilter((VBridgeIfPath)path, output)
+ : new RedirectFilter((VTerminalIfPath)path, output);
+ String p = (path == null) ? null : "destination=" + path;
+ String o = "output=" + output;
+ String required = joinStrings(prefix, suffix, ",", p, o);
+ assertEquals(required, rf.toString());
+ }
+ }
+ }
+
+ /**
+ * Ensure that {@link RedirectFilter} is serializable.
+ */
+ @Test
+ public void testSerialize() {
+ boolean[] bools = {true, false};
+ for (VInterfacePath path: createPaths()) {
+ for (boolean output: bools) {
+ RedirectFilter rf = (path instanceof VBridgeIfPath)
+ ? new RedirectFilter((VBridgeIfPath)path, output)
+ : new RedirectFilter((VTerminalIfPath)path, output);
+ serializeTest(rf);
+ }
+ }
+ }
+
+ /**
+ * Ensure that {@link RedirectFilter} is mapped to XML root element.
+ */
+ @Test
+ public void testJAXB() {
+ boolean[] bools = {true, false};
+ for (VInterfacePath path: createPaths()) {
+ for (boolean output: bools) {
+ RedirectFilter rf = (path instanceof VBridgeIfPath)
+ ? new RedirectFilter((VBridgeIfPath)path, output)
+ : new RedirectFilter((VTerminalIfPath)path, output);
+ jaxbTest(rf, "redirect");
+ }
+ }
+ }
+
+ /**
+ * Ensure that {@link RedirectFilter} is mapped to JSON object.
+ */
+ @Test
+ public void testJSON() {
+ boolean[] bools = {true, false};
+ for (VInterfacePath path: createPaths()) {
+ for (boolean output: bools) {
+ RedirectFilter rf = (path instanceof VBridgeIfPath)
+ ? new RedirectFilter((VBridgeIfPath)path, output)
+ : new RedirectFilter((VTerminalIfPath)path, output);
+ jsonTest(rf);
+ }
+ }
+
+ // Error detection test: Virtual node name is not specified.
+ ObjectMapper mapper = getJsonObjectMapper();
+ try {
+ JSONObject json = new JSONObject();
+ JSONObject dest = new JSONObject();
+ dest.put("interface", "if_1");
+ json.put("destination", dest);
+
+ RedirectFilter rf =
+ mapper.readValue(json.toString(), RedirectFilter.class);
+ VInterfacePath path = rf.getDestination();
+ assertEquals(ErrorVNodePath.class, path.getClass());
+ ErrorVNodePath err = (ErrorVNodePath)path;
+ VNodeLocation loc =
+ new VNodeLocation(new VBridgeIfPath(null, null, "if_1"));
+ assertEquals("Unexpected interface location: " + loc,
+ err.getError());
+ } catch (Exception e) {
+ unexpected(e);
+ }
+
+ // Error detection test: Interface name is not specified.
+ VNodePath[] paths = {
+ new VBridgePath((String)null, "node1"),
+ new VTerminalPath((String)null, "node2"),
+ };
+ for (VNodePath vnpath: paths) {
+ try {
+ JSONObject json = new JSONObject();
+ JSONObject dest = new JSONObject();
+ String key = (vnpath instanceof VBridgePath)
+ ? "bridge" : "terminal";
+ dest.put(key, vnpath.getTenantNodeName());
+ json.put("destination", dest);
+
+ RedirectFilter rf =
+ mapper.readValue(json.toString(), RedirectFilter.class);
+ VInterfacePath path = rf.getDestination();
+ assertEquals(ErrorVNodePath.class, path.getClass());
+ ErrorVNodePath err = (ErrorVNodePath)path;
+ VNodeLocation loc = (vnpath instanceof VBridgePath)
+ ? new VNodeLocation((VBridgePath)vnpath)
+ : new VNodeLocation((VTerminalPath)vnpath);
+ assertEquals("Interface name is not specified: " + loc,
+ err.getError());
+ } catch (Exception e) {
+ unexpected(e);
+ }
+ }
+ }
+
+ /**
+ * Create a list of {@link VInterfacePath} instances.
+ *
+ * @return A list of {@link VInterfacePath} instances.
+ */
+ private List<VInterfacePath> createPaths() {
+ List<VInterfacePath> list = interfaces;
+ if (list == null) {
+ list = new ArrayList<VInterfacePath>();
+ list.add(null);
+ for (String tname: createStrings("tenant")) {
+ for (String bname: createStrings("vbr", false)) {
+ for (String iname: createStrings("iface", false)) {
+ list.add(new VBridgeIfPath(tname, bname, iname));
+ list.add(new VTerminalIfPath(tname, bname, iname));
+ }
+ }
+ }
+ interfaces = list;
+ }
+
+ return list;
+ }
+}
org.opendaylight.vtn.manager.flow,
org.opendaylight.vtn.manager.flow.action,
org.opendaylight.vtn.manager.flow.cond,
+ org.opendaylight.vtn.manager.flow.filter,
org.apache.felix.dm,
org.slf4j,
org.osgi.framework
org.opendaylight.vtn.manager.flow,
org.opendaylight.vtn.manager.flow.action,
org.opendaylight.vtn.manager.flow.cond,
+ org.opendaylight.vtn.manager.flow.filter,
com.fasterxml.jackson.databind.annotation,
com.sun.jersey.spi.container.servlet,
javax.ws.rs,
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.northbound;
+
+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 com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+import org.opendaylight.vtn.manager.flow.filter.FlowFilter;
+
+/**
+ * {@code FlowFilterList} class describes a list of flow filter information.
+ *
+ * <p>
+ * This class is used to return a list of flow filter information to
+ * REST client.
+ * </p>
+ *
+ * <h4>Example JSON</h4>
+ * <pre class="prettyprint lang-json">
+ * {
+ * "flowfilter": [
+ * {
+ * "index": 10,
+ * "condition": "flowcond_1",
+ * "filterType": {
+ * "redirect": {
+ * "destination": {
+ * "bridge": "vbridge_1",
+ * "interface": "if_2"
+ * },
+ * "output": false
+ * }
+ * },
+ * "actions": [
+ * {"dlsrc": {"address": "f0:f1:f2:f3:f4:f5"}},
+ * {"vlanpcp": {"priority": 7}}
+ * ]
+ * },
+ * {
+ * "index": 20,
+ * "condition": "flowcond_2",
+ * "filterType": {
+ * "pass": {}
+ * },
+ * "actions": [
+ * {"dscp": {"dscp": 10}}
+ * ]
+ * }
+ * ]
+ * }</pre>
+ *
+ * @since Helium
+ */
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+@XmlRootElement(name = "flowfilters")
+@XmlAccessorType(XmlAccessType.NONE)
+public class FlowFilterList {
+ /**
+ * A list of {@link FlowFilter} instances.
+ *
+ * <ul>
+ * <li>
+ * This element contains 0 or more {@link FlowFilter} instances
+ * which represent flow filter information.
+ * </li>
+ * </ul>
+ */
+ @XmlElement(name = "flowfilter")
+ private List<FlowFilter> filters;
+
+ /**
+ * Default constructor.
+ */
+ public FlowFilterList() {
+ }
+
+ /**
+ * Construct a list of flow filters.
+ *
+ * @param list A list of flow filter information.
+ */
+ public FlowFilterList(List<FlowFilter> list) {
+ filters = list;
+ }
+
+ /**
+ * Return a list of flow filter information.
+ *
+ * @return A list of flow filter information.
+ */
+ List<FlowFilter> getFilters() {
+ return filters;
+ }
+
+ /**
+ * Determine whether the given object is identical to this object.
+ *
+ * @param o An object to be compared.
+ * @return {@code true} if identical. Otherwise {@code false}.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof FlowFilterList)) {
+ return false;
+ }
+
+ List<FlowFilter> list = ((FlowFilterList)o).filters;
+ if (filters == null || filters.isEmpty()) {
+ return (list == null || list.isEmpty());
+ }
+
+ return filters.equals(list);
+ }
+
+ /**
+ * Return the hash code of this object.
+ *
+ * @return The hash code.
+ */
+ @Override
+ public int hashCode() {
+ int h = 0;
+ if (filters != null && !filters.isEmpty()) {
+ h ^= filters.hashCode();
+ }
+
+ return h;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.northbound;
+
+import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
+import static java.net.HttpURLConnection.HTTP_CREATED;
+import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
+import static java.net.HttpURLConnection.HTTP_NOT_ACCEPTABLE;
+import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
+import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
+import static java.net.HttpURLConnection.HTTP_OK;
+import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
+import static java.net.HttpURLConnection.HTTP_UNAVAILABLE;
+import static java.net.HttpURLConnection.HTTP_UNSUPPORTED_TYPE;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.ResponseHeader;
+import org.codehaus.enunciate.jaxrs.ResponseHeaders;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.codehaus.enunciate.jaxrs.TypeHint;
+
+import org.opendaylight.vtn.manager.flow.filter.FlowFilter;
+
+import org.opendaylight.controller.sal.authorization.Privilege;
+
+/**
+ * This class provides Northbound REST APIs to handle flow filter in the
+ * vBridge.
+ *
+ * <p>
+ * Each vBridge has two flow filter lists.
+ * </p>
+ * <dl style="margin-left: 1em;">
+ * <dt>Input flow filter list
+ * <dd style="margin-left: 1.5em">
+ * <p>
+ * Flow filters in this list are evaluated when a packet is forwarded
+ * to the vBridge. This list is evaluated at the following instances.
+ * </p>
+ * <ul>
+ * <li>
+ * When a packet is forwarded from the virtual interface to the
+ * vBridge.
+ * </li>
+ * <li>
+ * When an incoming packet is mapped to the vBridge by VLAN mapping or
+ * MAC mapping.
+ * </li>
+ * </ul>
+ *
+ * <dt>Output flow filter list
+ * <dd style="margin-left: 1.5em">
+ * <p>
+ * Flow filters in this list are evaluated when a packet is going to be
+ * transmitted to the physical network mapped to the vBridge by
+ * VLAN mapping or MAC mapping.
+ * Note that this list is not evaluated when a packet is forwarded to
+ * the virtual interface in the same vBridge.
+ * </p>
+ * </dl>
+ *
+ * @since Helium
+ */
+@Path("/{containerName}/vtns/{tenantName}/vbridges/{bridgeName}/flowfilters")
+public class VBridgeFlowFilterNorthbound extends VTNNorthBoundBase {
+ /**
+ * Return information about flow filters configured in the specified
+ * vBridge flow filter list.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param bridgeName The name of the vBridge.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vBridge.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vBridge.
+ * </dl>
+ * @return
+ * <strong>flowfilters</strong> element contains information about the
+ * vBridge flow filter list specified by the requested URI.
+ */
+ @Path("{listType}")
+ @GET
+ @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @TypeHint(FlowFilterList.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Operation completed successfully."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "Invalid value is passed to " +
+ "<u>{listType}</u>."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vBridge does not exist.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public FlowFilterList getFlowFilters(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("bridgeName") String bridgeName,
+ @PathParam("listType") String listType) {
+ checkPrivilege(containerName, Privilege.READ);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Delete all flow filters in the specified vBridge flow filter list.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param bridgeName The name of the vBridge.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vBridge.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vBridge.
+ * </dl>
+ * @return Response as dictated by the HTTP Response Status code.
+ */
+ @Path("{listType}")
+ @DELETE
+ @TypeHint(TypeHint.NO_CONTENT.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Flow filters were deleted successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "No flow filter was configured in the " +
+ "specified vBridge flow filter list."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "Invalid value is passed to " +
+ "<u>{listType}</u>."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vBridge does not exist.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_NOT_ACCEPTABLE,
+ condition = "\"default\" is specified to " +
+ "<u>{containerName}</u> and a container other than " +
+ "the default container is present."),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public Response deleteFlowFilters(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("bridgeName") String bridgeName,
+ @PathParam("listType") String listType) {
+ checkPrivilege(containerName, Privilege.WRITE);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Return information about the flow filter specified by the flow filter
+ * index in the vBridge flow filter list.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param bridgeName The name of the vBridge.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vBridge.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vBridge.
+ * </dl>
+ * @param index
+ * The index value which specifies the flow filter in the vBridge
+ * flow filter list. A string representation of an integer value must be
+ * specified.
+ * @return <strong>flowfilter</strong> element contains information
+ * about the flow filter specified by the requested URI.
+ */
+ @Path("{listType}/{index}")
+ @GET
+ @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @TypeHint(FlowFilter.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Operation completed successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "The specified flow filter does not exist " +
+ "in the specified vBridge."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "Invalid value is passed to " +
+ "<u>{listType}</u>."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vBridge does not exist.</li>" +
+ "<li>A string passed to <u>{index}</u> can not be " +
+ "converted into an integer.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public FlowFilter getFlowFilter(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("bridgeName") String bridgeName,
+ @PathParam("listType") String listType,
+ @PathParam("index") int index) {
+ checkPrivilege(containerName, Privilege.READ);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Create or modify the flow filter specified by the index number in the
+ * vBridge flow filter list.
+ *
+ * <ul>
+ * <li>
+ * If the flow filter specified by
+ * <span style="text-decoration: underline;">{index}</span> does not
+ * exist in the vBridge flow filter list specified by
+ * <span style="text-decoration: underline;">{listType}</span>,
+ * a new flow filter will be associated with
+ * <span style="text-decoration: underline;">{index}</span> in the
+ * specified vBridge flow filter list.
+ * </li>
+ * <li>
+ * If the flow filter specified by
+ * <span style="text-decoration: underline;">{index}</span> already
+ * exists in the vBridge flow filter list specified by
+ * <span style="text-decoration: underline;">{listType}</span>,
+ * it will be modified as specified by <strong>flowfilter</strong>
+ * element.
+ * </li>
+ * </ul>
+ *
+ * @param uriInfo Requested URI information.
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param bridgeName The name of the vBridge.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vBridge.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vBridge.
+ * </dl>
+ * @param index
+ * The index value which specifies the flow filter in the vBridge
+ * flow filter list.
+ * <ul>
+ * <li>
+ * A string representation of an integer value must be specified.
+ * </li>
+ * <li>
+ * The range of value that can be specified is from
+ * <strong>1</strong> to <strong>65535</strong>.
+ * </li>
+ * <li>
+ * This value is also used to determine the order of flow filter
+ * evaluation. Flow filters in the list are evaluated in ascending
+ * order of indices, and only the first matched flow filter is
+ * applied to the packet.
+ * </li>
+ * </ul>
+ * @param ff
+ * <strong>flowfilter</strong> element specifies the configuration of the
+ * flow filter.
+ * <ul>
+ * <li>
+ * The <strong>index</strong> attribute in the
+ * <strong>flowfilter</strong> element is always ignored.
+ * The index number is determined by the
+ * <span style="text-decoration: underline;">{index}</span>
+ * parameter.
+ * </li>
+ * <li>
+ * Note that this API does not check whether the flow condition
+ * specified by the <strong>condition</strong> attribute in
+ * the <strong>flowfilter</strong> element actually exists or not.
+ * The flow filter will be invalidated if the specified
+ * flow condition does not exist.
+ * </li>
+ * <li>
+ * Note that this API does not check whether the destination
+ * virtual interface of the packet redirection, which is configured
+ * in the <strong>redirect</strong> element in the
+ * <strong>flowfilter</strong> element, actually exists or not.
+ * The packet will be discarded if the destination virtual interface
+ * is not found when the packet is going to be redirected by the
+ * flow filter.
+ * </li>
+ * </ul>
+ * @return Response as dictated by the HTTP Response Status code.
+ */
+ @Path("{listType}/{index}")
+ @PUT
+ @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @TypeHint(TypeHint.NO_CONTENT.class)
+ @ResponseHeaders({
+ @ResponseHeader(name = "Location",
+ description = "URI corresponding to the newly " +
+ "created flow filter, which is the same URI " +
+ "specified in request. This header is set only if " +
+ "CREATED(201) is returned as response code.")})
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Existing flow filter was modified " +
+ "successfully."),
+ @ResponseCode(code = HTTP_CREATED,
+ condition = "Flow filter was newly created " +
+ "successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "Flow filter was not changed."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "<ul>" +
+ "<li>Incorrect XML or JSON data is specified " +
+ "in Request body.</li>" +
+ "<li>Invalid value is passed to <u>{listType}</u>." +
+ "<li>Index number specified by <u>{index}</u> " +
+ "parameter is out of valid range.</li>" +
+ "<li>Incorrect value is configured in " +
+ "<strong>flowfilter</strong>.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vBridge does not exist.</li>" +
+ "<li>A string passed to <u>{index}</u> can not be " +
+ "converted into an integer.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_NOT_ACCEPTABLE,
+ condition = "\"default\" is specified to " +
+ "<u>{containerName}</u> and a container other than " +
+ "the default container is present."),
+ @ResponseCode(code = HTTP_UNSUPPORTED_TYPE,
+ condition = "Unsupported data type is specified in " +
+ "<strong>Content-Type</strong> header."),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public Response putFlowFilter(
+ @Context UriInfo uriInfo,
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("bridgeName") String bridgeName,
+ @PathParam("listType") String listType,
+ @PathParam("index") int index,
+ @TypeHint(FlowFilter.class) FlowFilter ff) {
+ checkPrivilege(containerName, Privilege.WRITE);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Delete the flow filter specified by the index number in the
+ * vBridge flow filter list.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param bridgeName The name of the vBridge.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vBridge.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vBridge.
+ * </dl>
+ * @param index
+ * The index value which specifies the flow filter in the vBridge
+ * flow filter list. A string representation of an integer value must be
+ * specified.
+ * @return Response as dictated by the HTTP Response Status code.
+ */
+ @Path("{listType}/{index}")
+ @DELETE
+ @TypeHint(TypeHint.NO_CONTENT.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Flow filter was deleted successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "The specified flow filter does not exist " +
+ "in the specified vBridge."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "Invalid value is passed to " +
+ "<u>{listType}</u>."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vBridge does not exist.</li>" +
+ "<li>A string passed to <u>{index}</u> can not be " +
+ "converted into an integer.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_NOT_ACCEPTABLE,
+ condition = "\"default\" is specified to " +
+ "<u>{containerName}</u> and a container other than " +
+ "the default container is present."),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public Response deleteFlowFilter(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("bridgeName") String bridgeName,
+ @PathParam("listType") String listType,
+ @PathParam("index") int index) {
+ checkPrivilege(containerName, Privilege.WRITE);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.northbound;
+
+import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
+import static java.net.HttpURLConnection.HTTP_CREATED;
+import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
+import static java.net.HttpURLConnection.HTTP_NOT_ACCEPTABLE;
+import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
+import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
+import static java.net.HttpURLConnection.HTTP_OK;
+import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
+import static java.net.HttpURLConnection.HTTP_UNAVAILABLE;
+import static java.net.HttpURLConnection.HTTP_UNSUPPORTED_TYPE;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.ResponseHeader;
+import org.codehaus.enunciate.jaxrs.ResponseHeaders;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.codehaus.enunciate.jaxrs.TypeHint;
+
+import org.opendaylight.vtn.manager.flow.filter.FlowFilter;
+
+import org.opendaylight.controller.sal.authorization.Privilege;
+
+/**
+ * This class provides Northbound REST APIs to handle flow filter in the
+ * vBridge interface.
+ *
+ * <p>
+ * Each vBridge interface has two flow filter lists.
+ * </p>
+ * <dl style="margin-left: 1em;">
+ * <dt>Input flow filter list
+ * <dd style="margin-left: 1.5em">
+ * <p>
+ * Flow filters in this list are evaluated when a packet is forwarded to
+ * the vBridge interface. This list is evaluated at the following
+ * instances.
+ * </p>
+ * <ul>
+ * <li>
+ * When an incoming packet is mapped to the vBridge interface by
+ * port mapping.
+ * </li>
+ * <li>
+ * When a packet is redirected by another flow filter to the
+ * vBridge interface as an incoming packet.
+ * </li>
+ * </ul>
+ *
+ * <dt>Output flow filter list
+ * <dd style="margin-left: 1.5em">
+ * <p>
+ * Flow filters in this list are evaluated when a packet is going to be
+ * transmitted to the physical network mapped to the vBridge interface.
+ * This list is evaluated at the following instances.
+ * </p>
+ * <ul>
+ * <li>
+ * When a packet is forwarded from the vBridge to the virtual
+ * interface.
+ * </li>
+ * <li>
+ * When a packet is redirected by another flow filter to the
+ * vBridge interface as an outgoing packet.
+ * </li>
+ * </ul>
+ * </dl>
+ *
+ * @since Helium
+ */
+@Path("/{containerName}/vtns/{tenantName}/vbridges/{bridgeName}/interfaces/{ifName}/flowfilters")
+public class VBridgeIfFlowFilterNorthbound extends VTNNorthBoundBase {
+ /**
+ * Return information about flow filters configured in the specified
+ * vBridge interface.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param bridgeName The name of the vBridge.
+ * @param ifName The name of the vBridge interface.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vBridge interface.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vBridge interface.
+ * </dl>
+ * @return
+ * <strong>flowfilters</strong> element contains information about the
+ * vBridge interface flow filter list specified by the requested URI.
+ */
+ @Path("{listType}")
+ @GET
+ @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @TypeHint(FlowFilterList.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Operation completed successfully."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "Invalid value is passed to " +
+ "<u>{listType}</u>."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vBridge does not exist.</li>" +
+ "<li>The specified vBridge interface does not " +
+ "exist.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public FlowFilterList getFlowFilters(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("bridgeName") String bridgeName,
+ @PathParam("ifName") String ifName,
+ @PathParam("listType") String listType) {
+ checkPrivilege(containerName, Privilege.READ);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Delete all flow filters in the specified vBridge interface flow filter
+ * list.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param bridgeName The name of the vBridge.
+ * @param ifName The name of the vBridge interface.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vBridge interface.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vBridge interface.
+ * </dl>
+ * @return Response as dictated by the HTTP Response Status code.
+ */
+ @Path("{listType}")
+ @DELETE
+ @TypeHint(TypeHint.NO_CONTENT.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Flow filters were deleted successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "No flow filter was configured in the " +
+ "specified vBridge interface flow filter list."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "Invalid value is passed to " +
+ "<u>{listType}</u>."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vBridge does not exist.</li>" +
+ "<li>The specified vBridge interface does not " +
+ "exist.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_NOT_ACCEPTABLE,
+ condition = "\"default\" is specified to " +
+ "<u>{containerName}</u> and a container other than " +
+ "the default container is present."),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public Response deleteFlowFilters(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("bridgeName") String bridgeName,
+ @PathParam("ifName") String ifName,
+ @PathParam("listType") String listType) {
+ checkPrivilege(containerName, Privilege.WRITE);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Return information about the flow filter specified by
+ * the flow filter index in the vBridge interface flow filter list.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param bridgeName The name of the vBridge.
+ * @param ifName The name of the vBridge interface.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vBridge interface.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vBridge interface.
+ * </dl>
+ * @param index
+ * The index value which specifies the flow filter in the vBridge
+ * interface flow filter list. A string representation of an integer
+ * value must be specified.
+ * @return <strong>flowfilter</strong> element contains information
+ * about the flow filter specified by the requested URI.
+ */
+ @Path("{listType}/{index}")
+ @GET
+ @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @TypeHint(FlowFilter.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Operation completed successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "The specified flow filter does not exist " +
+ "in the specified vBridge."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "Invalid value is passed to " +
+ "<u>{listType}</u>."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vBridge does not exist.</li>" +
+ "<li>The specified vBridge interface does not " +
+ "exist.</li>" +
+ "<li>A string passed to <u>{index}</u> can not be " +
+ "converted into an integer.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public FlowFilter getFlowFilter(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("bridgeName") String bridgeName,
+ @PathParam("ifName") String ifName,
+ @PathParam("listType") String listType,
+ @PathParam("index") int index) {
+ checkPrivilege(containerName, Privilege.READ);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Create or modify the flow filter specified by the index number in the
+ * vBridge interface flow filter list.
+ *
+ * <ul>
+ * <li>
+ * If the flow filter specified by
+ * <span style="text-decoration: underline;">{index}</span> does not
+ * exist in the vBridge interface flow filter list specified by
+ * <span style="text-decoration: underline;">{listType}</span>,
+ * a new flow filter will be associated with
+ * <span style="text-decoration: underline;">{index}</span> in the
+ * specified vBridge interface flow filter list.
+ * </li>
+ * <li>
+ * If the flow filter specified by
+ * <span style="text-decoration: underline;">{index}</span> already
+ * exists in the vBridge interface flow filter list specified by
+ * <span style="text-decoration: underline;">{listType}</span>,
+ * it will be modified as specified by <strong>flowfilter</strong>
+ * element.
+ * </li>
+ * </ul>
+ *
+ * @param uriInfo Requested URI information.
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param bridgeName The name of the vBridge.
+ * @param ifName The name of the vBridge interface.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vBridge interface.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vBridge interface.
+ * </dl>
+ * @param index
+ * The index value which specifies the flow filter in the vBridge
+ * interface flow filter list.
+ * <ul>
+ * <li>
+ * A string representation of an integer value must be specified.
+ * </li>
+ * <li>
+ * The range of value that can be specified is from
+ * <strong>1</strong> to <strong>65535</strong>.
+ * </li>
+ * <li>
+ * This value is also used to determine the order of flow filter
+ * evaluation. Flow filters in the list are evaluated in ascending
+ * order of indices, and only the first matched flow filter is
+ * applied to the packet.
+ * </li>
+ * </ul>
+ * @param ff
+ * <strong>flowfilter</strong> element specifies the configuration of the
+ * flow filter.
+ * <ul>
+ * <li>
+ * The <strong>index</strong> attribute in the
+ * <strong>flowfilter</strong> element is always ignored.
+ * The index number is determined by the
+ * <span style="text-decoration: underline;">{index}</span>
+ * parameter.
+ * </li>
+ * <li>
+ * Note that this API does not check whether the flow condition
+ * specified by the <strong>condition</strong> attribute in
+ * the <strong>flowfilter</strong> element actually exists or not.
+ * The flow filter will be invalidated if the specified
+ * flow condition does not exist.
+ * </li>
+ * <li>
+ * Note that this API does not check whether the destination
+ * virtual interface of the packet redirection, which is configured
+ * in the <strong>redirect</strong> element in the
+ * <strong>flowfilter</strong> element, actually exists or not.
+ * The packet will be discarded if the destination virtual interface
+ * is not found when the packet is going to be redirected by the
+ * flow filter.
+ * </li>
+ * </ul>
+ * @return Response as dictated by the HTTP Response Status code.
+ */
+ @Path("{listType}/{index}")
+ @PUT
+ @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @TypeHint(TypeHint.NO_CONTENT.class)
+ @ResponseHeaders({
+ @ResponseHeader(name = "Location",
+ description = "URI corresponding to the newly " +
+ "created flow filter, which is the same URI " +
+ "specified in request. This header is set only if " +
+ "CREATED(201) is returned as response code.")})
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Existing flow filter was modified " +
+ "successfully."),
+ @ResponseCode(code = HTTP_CREATED,
+ condition = "Flow filter was newly created " +
+ "successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "Flow filter was not changed."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "<ul>" +
+ "<li>Incorrect XML or JSON data is specified " +
+ "in Request body.</li>" +
+ "<li>Invalid value is passed to <u>{listType}</u>." +
+ "<li>Index number specified by <u>{index}</u> " +
+ "parameter is out of valid range.</li>" +
+ "<li>Incorrect value is configured in " +
+ "<strong>flowfilter</strong>.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vBridge does not exist.</li>" +
+ "<li>The specified vBridge interface does not " +
+ "exist.</li>" +
+ "<li>A string passed to <u>{index}</u> can not be " +
+ "converted into an integer.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_NOT_ACCEPTABLE,
+ condition = "\"default\" is specified to " +
+ "<u>{containerName}</u> and a container other than " +
+ "the default container is present."),
+ @ResponseCode(code = HTTP_UNSUPPORTED_TYPE,
+ condition = "Unsupported data type is specified in " +
+ "<strong>Content-Type</strong> header."),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public Response putFlowFilter(
+ @Context UriInfo uriInfo,
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("bridgeName") String bridgeName,
+ @PathParam("ifName") String ifName,
+ @PathParam("listType") String listType,
+ @PathParam("index") int index,
+ @TypeHint(FlowFilter.class) FlowFilter ff) {
+ checkPrivilege(containerName, Privilege.WRITE);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Delete the flow filter specified by the index number in the
+ * specified vBridge interface flow filter list.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param bridgeName The name of the vBridge.
+ * @param ifName The name of the vBridge interface.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vBridge interface.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vBridge interface.
+ * </dl>
+ * @param index
+ * The index value which specifies the flow filter in the vBridge
+ * interface flow filter list. A string representation of an integer
+ * value must be specified.
+ * @return Response as dictated by the HTTP Response Status code.
+ */
+ @Path("{listType}/{index}")
+ @DELETE
+ @TypeHint(TypeHint.NO_CONTENT.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Flow filter was deleted successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "The specified flow filter does not exist " +
+ "in the specified vBridge."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "Invalid value is passed to " +
+ "<u>{listType}</u>."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vBridge does not exist.</li>" +
+ "<li>The specified vBridge interface does not " +
+ "exist.</li>" +
+ "<li>A string passed to <u>{index}</u> can not be " +
+ "converted into an integer.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_NOT_ACCEPTABLE,
+ condition = "\"default\" is specified to " +
+ "<u>{containerName}</u> and a container other than " +
+ "the default container is present."),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public Response deleteFlowFilter(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("bridgeName") String bridgeName,
+ @PathParam("ifName") String ifName,
+ @PathParam("listType") String listType,
+ @PathParam("index") int index) {
+ checkPrivilege(containerName, Privilege.WRITE);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.northbound;
+
+import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
+import static java.net.HttpURLConnection.HTTP_CREATED;
+import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
+import static java.net.HttpURLConnection.HTTP_NOT_ACCEPTABLE;
+import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
+import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
+import static java.net.HttpURLConnection.HTTP_OK;
+import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
+import static java.net.HttpURLConnection.HTTP_UNAVAILABLE;
+import static java.net.HttpURLConnection.HTTP_UNSUPPORTED_TYPE;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.ResponseHeader;
+import org.codehaus.enunciate.jaxrs.ResponseHeaders;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.codehaus.enunciate.jaxrs.TypeHint;
+
+import org.opendaylight.vtn.manager.flow.filter.FlowFilter;
+
+import org.opendaylight.controller.sal.authorization.Privilege;
+
+/**
+ * This class provides Northbound REST APIs to handle flow filter in the
+ * VTN.
+ *
+ * <p>
+ * Each VTN has a list of flow filters. Flow filters in the VTN flow filter
+ * list are evaluated when an incoming packet is mapped to the VTN.
+ * Note that the VTN flow filter list is evaluated only once before other
+ * flow filter lists are evaluated.
+ * </p>
+ *
+ * @since Helium
+ */
+@Path("/{containerName}/vtns/{tenantName}/flowfilters")
+public class VTenantFlowFilterNorthbound extends VTNNorthBoundBase {
+ /**
+ * Return information about flow filters configured in the specified VTN.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @return
+ * <strong>flowfilters</strong> element contains information about the
+ * VTN flow filter list specified by the requested URI.
+ */
+ @GET
+ @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @TypeHint(FlowFilterList.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Operation completed successfully."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public FlowFilterList getFlowFilters(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName) {
+ checkPrivilege(containerName, Privilege.READ);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+
+ /**
+ * Delete all flow filters in the VTN flow filter list.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @return Response as dictated by the HTTP Response Status code.
+ */
+ @DELETE
+ @TypeHint(TypeHint.NO_CONTENT.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Flow filters were deleted successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "No flow filter was configured in the " +
+ "specified VTN."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_NOT_ACCEPTABLE,
+ condition = "\"default\" is specified to " +
+ "<u>{containerName}</u> and a container other than " +
+ "the default container is present."),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public Response deleteFlowFilters(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName) {
+ checkPrivilege(containerName, Privilege.WRITE);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Return information about the flow filter specified by the
+ * flow filter index in the VTN flow filter list.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param index
+ * The index value which specifies the flow filter in the VTN flow filter
+ * list. A string representation of an integer value must be specified.
+ * @return
+ * <strong>flowfilter</strong> element contains information about the
+ * flow filter specified by the requested URI.
+ */
+ @Path("{index}")
+ @GET
+ @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @TypeHint(FlowFilter.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Operation completed successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "The specified flow filter does not exist " +
+ "in the specified VTN."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>A string passed to <u>{index}</u> can not be " +
+ "converted into an integer.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public FlowFilter getFlowFilter(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("index") int index) {
+ checkPrivilege(containerName, Privilege.READ);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Create or modify the flow filter specified by the index number in the
+ * VTN flow filter list.
+ *
+ * <ul>
+ * <li>
+ * If the flow filter specified by
+ * <span style="text-decoration: underline;">{index}</span> does not
+ * exist, a new flow filter will be associated with
+ * <span style="text-decoration: underline;">{index}</span> in the
+ * VTN flow filter list.
+ * </li>
+ * <li>
+ * If the flow filter specified by
+ * <span style="text-decoration: underline;">{index}</span> already
+ * exists, it will be modified as specified by
+ * <strong>flowfilter</strong> element.
+ * </li>
+ * </ul>
+ *
+ * @param uriInfo Requested URI information.
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param index
+ * The index value which specifies the flow filter in the VTN flow filter
+ * list.
+ * <ul>
+ * <li>
+ * A string representation of an integer value must be specified.
+ * </li>
+ * <li>
+ * The range of value that can be specified is from
+ * <strong>1</strong> to <strong>65535</strong>.
+ * </li>
+ * <li>
+ * This value is also used to determine the order of flow filter
+ * evaluation. Flow filters in the list are evaluated in ascending
+ * order of indices, and only the first matched flow filter is
+ * applied to the packet.
+ * </li>
+ * </ul>
+ * @param ff
+ * <strong>flowfilter</strong> element specifies the configuration of the
+ * flow filter.
+ * <ul>
+ * <li>
+ * The <strong>index</strong> attribute in the
+ * <strong>flowfilter</strong> element is always ignored.
+ * The index number is determined by the
+ * <span style="text-decoration: underline;">{index}</span>
+ * parameter.
+ * </li>
+ * <li>
+ * Note that this API does not check whether the flow condition
+ * specified by the <strong>condition</strong> attribute in
+ * the <strong>flowfilter</strong> element actually exists or not.
+ * The flow filter will be invalidated if the specified
+ * flow condition does not exist.
+ * </li>
+ * <li>
+ * Note that this API does not check whether the destination
+ * virtual interface of the packet redirection, which is configured
+ * in the <strong>redirect</strong> element in the
+ * <strong>flowfilter</strong> element, actually exists or not.
+ * The packet will be discarded if the destination virtual interface
+ * is not found when the packet is going to be redirected by the
+ * flow filter.
+ * </li>
+ * </ul>
+ * @return Response as dictated by the HTTP Response Status code.
+ */
+ @Path("{index}")
+ @PUT
+ @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @TypeHint(TypeHint.NO_CONTENT.class)
+ @ResponseHeaders({
+ @ResponseHeader(name = "Location",
+ description = "URI corresponding to the newly " +
+ "created flow filter, which is the same URI " +
+ "specified in request. This header is set only if " +
+ "CREATED(201) is returned as response code.")})
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Existing flow filter was modified " +
+ "successfully."),
+ @ResponseCode(code = HTTP_CREATED,
+ condition = "Flow filter was newly created " +
+ "successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "Flow filter was not changed."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "<ul>" +
+ "<li>Incorrect XML or JSON data is specified " +
+ "in Request body.</li>" +
+ "<li>Index number specified by <u>{index}</u> " +
+ "parameter is out of valid range.</li>" +
+ "<li>Incorrect value is configured in " +
+ "<strong>flowfilter</strong>.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>A string passed to <u>{index}</u> can not be " +
+ "converted into an integer.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_NOT_ACCEPTABLE,
+ condition = "\"default\" is specified to " +
+ "<u>{containerName}</u> and a container other than " +
+ "the default container is present."),
+ @ResponseCode(code = HTTP_UNSUPPORTED_TYPE,
+ condition = "Unsupported data type is specified in " +
+ "<strong>Content-Type</strong> header."),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public Response putFlowFilter(
+ @Context UriInfo uriInfo,
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("index") int index,
+ @TypeHint(FlowFilter.class) FlowFilter ff) {
+ checkPrivilege(containerName, Privilege.WRITE);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Delete the flow filter specified by the index number in the VTN
+ * flow filter list.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param index
+ * The index value which specifies the flow filter in the VTN flow filter
+ * list. A string representation of an integer value must be specified.
+ * @return Response as dictated by the HTTP Response Status code.
+ */
+ @Path("{index}")
+ @DELETE
+ @TypeHint(TypeHint.NO_CONTENT.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Flow filter was deleted successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "The specified flow filter does not exist " +
+ "in the specified VTN."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>A string passed to <u>{index}</u> can not be " +
+ "converted into an integer.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_NOT_ACCEPTABLE,
+ condition = "\"default\" is specified to " +
+ "<u>{containerName}</u> and a container other than " +
+ "the default container is present."),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public Response deleteFlowFilter(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("index") int index) {
+ checkPrivilege(containerName, Privilege.WRITE);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.northbound;
+
+import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
+import static java.net.HttpURLConnection.HTTP_CREATED;
+import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
+import static java.net.HttpURLConnection.HTTP_NOT_ACCEPTABLE;
+import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
+import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
+import static java.net.HttpURLConnection.HTTP_OK;
+import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
+import static java.net.HttpURLConnection.HTTP_UNAVAILABLE;
+import static java.net.HttpURLConnection.HTTP_UNSUPPORTED_TYPE;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.ResponseHeader;
+import org.codehaus.enunciate.jaxrs.ResponseHeaders;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.codehaus.enunciate.jaxrs.TypeHint;
+
+import org.opendaylight.vtn.manager.flow.filter.FlowFilter;
+
+import org.opendaylight.controller.sal.authorization.Privilege;
+
+/**
+ * This class provides Northbound REST APIs to handle flow filter in the
+ * vTerminal interface.
+ *
+ * <p>
+ * Each vTerminal interface has two flow filter lists.
+ * </p>
+ * <dl style="margin-left: 1em;">
+ * <dt>Input flow filter list
+ * <dd style="margin-left: 1.5em">
+ * <p>
+ * Flow filters in this list are evaluated when a packet is forwarded
+ * to the vTerminal interface.
+ * This list is evaluated at the following instances.
+ * </p>
+ * <ul>
+ * <li>
+ * When an incoming packet is mapped to the vTerminal interface by
+ * port mapping.
+ * </li>
+ * <li>
+ * When a packet is redirected by another flow filter to the
+ * vTerminal interface as an incoming packet.
+ * </li>
+ * </ul>
+ * <p>
+ * vTerminal is an isolated input/output terminal.
+ * So an incoming packet is always discarded unless it is redirected
+ * to another virtual interface by the flow filter.
+ * </p>
+ *
+ * <dt>Output flow filter list
+ * <dd style="margin-left: 1.5em">
+ * <p>
+ * Flow filters in this list are evaluated when a packet is going to be
+ * transmitted to the physical network mapped to the vTerminal interface.
+ * This list is evaluated at the following instances.
+ * </p>
+ * <p>
+ * This list is evaluated only when a packet is redirected by another
+ * flow filter to the vTerminal interface as an outgoing packet.
+ * </p>
+ * </dl>
+ *
+ * @since Helium
+ */
+@Path("/{containerName}/vtns/{tenantName}/vterminals/{termName}/interfaces/{ifName}/flowfilters")
+public class VTerminalIfFlowFilterNorthbound extends VTNNorthBoundBase {
+ /**
+ * Return information about flow filters configured in the specified
+ * vTerminal interface.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param termName The name of the vTerminal.
+ * @param ifName The name of the vTerminal interface.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vTerminal interface.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vTerminal interface.
+ * </dl>
+ * @return
+ * <strong>flowfilters</strong> element contains information about the
+ * vTerminal interface flow filter list specified by the requested URI.
+ */
+ @Path("{listType}")
+ @GET
+ @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @TypeHint(FlowFilterList.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Operation completed successfully."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "Invalid value is passed to " +
+ "<u>{listType}</u>."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vTerminal does not exist.</li>" +
+ "<li>The specified vTerminal interface does not " +
+ "exist.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public FlowFilterList getFlowFilters(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("termName") String termName,
+ @PathParam("ifName") String ifName,
+ @PathParam("listType") String listType) {
+ checkPrivilege(containerName, Privilege.READ);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Delete all flow filters in the specified vTerminal interface flow filter
+ * list.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param termName The name of the vTerminal.
+ * @param ifName The name of the vTerminal interface.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vTerminal interface.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vTerminal interface.
+ * </dl>
+ * @return Response as dictated by the HTTP Response Status code.
+ */
+ @Path("{listType}")
+ @DELETE
+ @TypeHint(TypeHint.NO_CONTENT.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Flow filters were deleted successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "No flow filter was configured in the " +
+ "specified vTerminal interface flow filter list."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "Invalid value is passed to " +
+ "<u>{listType}</u>."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vTerminal does not exist.</li>" +
+ "<li>The specified vTerminal interface does not " +
+ "exist.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_NOT_ACCEPTABLE,
+ condition = "\"default\" is specified to " +
+ "<u>{containerName}</u> and a container other than " +
+ "the default container is present."),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public Response deleteFlowFilters(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("termame") String termName,
+ @PathParam("ifName") String ifName,
+ @PathParam("listType") String listType) {
+ checkPrivilege(containerName, Privilege.WRITE);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Return information about the flow filter specified by
+ * the flow filter index in the vTerminal interface flow filter list.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param termName The name of the vTerminal.
+ * @param ifName The name of the vTerminal interface.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vTerminal interface.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vTerminal interface.
+ * </dl>
+ * @param index
+ * The index value which specifies the flow filter in the vTerminal
+ * interface flow filter list. A string representation of an integer
+ * value must be specified.
+ * @return <strong>flowfilter</strong> element contains information
+ * about the flow filter specified by the requested URI.
+ */
+ @Path("{listType}/{index}")
+ @GET
+ @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @TypeHint(FlowFilter.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Operation completed successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "The specified flow filter does not exist " +
+ "in the specified vTerminal."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "Invalid value is passed to " +
+ "<u>{listType}</u>."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vTerminal does not exist.</li>" +
+ "<li>The specified vTerminal interface does not " +
+ "exist.</li>" +
+ "<li>A string passed to <u>{index}</u> can not be " +
+ "converted into an integer.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public FlowFilter getFlowFilter(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("termName") String termName,
+ @PathParam("ifName") String ifName,
+ @PathParam("listType") String listType,
+ @PathParam("index") int index) {
+ checkPrivilege(containerName, Privilege.READ);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Create or modify the flow filter specified by the index number in the
+ * vTerminal interface flow filter list.
+ *
+ * <ul>
+ * <li>
+ * If the flow filter specified by
+ * <span style="text-decoration: underline;">{index}</span> does not
+ * exist in the vTerminal interface flow filter list specified by
+ * <span style="text-decoration: underline;">{listType}</span>,
+ * a new flow filter will be associated with
+ * <span style="text-decoration: underline;">{index}</span> in the
+ * specified vTerminal interface flow filter list.
+ * </li>
+ * <li>
+ * If the flow filter specified by
+ * <span style="text-decoration: underline;">{index}</span> already
+ * exists in the vTerminal interface flow filter list specified by
+ * <span style="text-decoration: underline;">{listType}</span>,
+ * it will be modified as specified by <strong>flowfilter</strong>
+ * element.
+ * </li>
+ * </ul>
+ *
+ * @param uriInfo Requested URI information.
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param termName The name of the vTerminal.
+ * @param ifName The name of the vTerminal interface.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vTerminal interface.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vTerminal interface.
+ * </dl>
+ * @param index
+ * The index value which specifies the flow filter in the vTerminal
+ * interface flow filter list.
+ * <ul>
+ * <li>
+ * A string representation of an integer value must be specified.
+ * </li>
+ * <li>
+ * The range of value that can be specified is from
+ * <strong>1</strong> to <strong>65535</strong>.
+ * </li>
+ * <li>
+ * This value is also used to determine the order of flow filter
+ * evaluation. Flow filters in the list are evaluated in ascending
+ * order of indices, and only the first matched flow filter is
+ * applied to the packet.
+ * </li>
+ * </ul>
+ * @param ff
+ * <strong>flowfilter</strong> element specifies the configuration of the
+ * flow filter.
+ * <ul>
+ * <li>
+ * The <strong>index</strong> attribute in the
+ * <strong>flowfilter</strong> element is always ignored.
+ * The index number is determined by the
+ * <span style="text-decoration: underline;">{index}</span>
+ * parameter.
+ * </li>
+ * <li>
+ * Note that this API does not check whether the flow condition
+ * specified by the <strong>condition</strong> attribute in
+ * the <strong>flowfilter</strong> element actually exists or not.
+ * The flow filter will be invalidated if the specified
+ * flow condition does not exist.
+ * </li>
+ * <li>
+ * Note that this API does not check whether the destination
+ * virtual interface of the packet redirection, which is configured
+ * in the <strong>redirect</strong> element in the
+ * <strong>flowfilter</strong> element, actually exists or not.
+ * The packet will be discarded if the destination virtual interface
+ * is not found when the packet is going to be redirected by the
+ * flow filter.
+ * </li>
+ * </ul>
+ * @return Response as dictated by the HTTP Response Status code.
+ */
+ @Path("{listType}/{index}")
+ @PUT
+ @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @TypeHint(TypeHint.NO_CONTENT.class)
+ @ResponseHeaders({
+ @ResponseHeader(name = "Location",
+ description = "URI corresponding to the newly " +
+ "created flow filter, which is the same URI " +
+ "specified in request. This header is set only if " +
+ "CREATED(201) is returned as response code.")})
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Existing flow filter was modified " +
+ "successfully."),
+ @ResponseCode(code = HTTP_CREATED,
+ condition = "Flow filter was newly created " +
+ "successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "Flow filter was not changed."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "<ul>" +
+ "<li>Incorrect XML or JSON data is specified " +
+ "in Request body.</li>" +
+ "<li>Invalid value is passed to <u>{listType}</u>." +
+ "<li>Index number specified by <u>{index}</u> " +
+ "parameter is out of valid range.</li>" +
+ "<li>Incorrect value is configured in " +
+ "<strong>flowfilter</strong>.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vTerminal does not exist.</li>" +
+ "<li>The specified vTerminal interface does not " +
+ "exist.</li>" +
+ "<li>A string passed to <u>{index}</u> can not be " +
+ "converted into an integer.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_NOT_ACCEPTABLE,
+ condition = "\"default\" is specified to " +
+ "<u>{containerName}</u> and a container other than " +
+ "the default container is present."),
+ @ResponseCode(code = HTTP_UNSUPPORTED_TYPE,
+ condition = "Unsupported data type is specified in " +
+ "<strong>Content-Type</strong> header."),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public Response putFlowFilter(
+ @Context UriInfo uriInfo,
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("termName") String termName,
+ @PathParam("ifName") String ifName,
+ @PathParam("listType") String listType,
+ @PathParam("index") int index,
+ @TypeHint(FlowFilter.class) FlowFilter ff) {
+ checkPrivilege(containerName, Privilege.WRITE);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+
+ /**
+ * Delete the flow filter specified by the index number in the
+ * specified vTerminal interface flow filter list.
+ *
+ * @param containerName The name of the container.
+ * @param tenantName The name of the VTN.
+ * @param termName The name of the vTerminal.
+ * @param ifName The name of the vTerminal interface.
+ * @param listType
+ * The type of the flow filter list (case insensitive).
+ * <dl style="margin-left: 1em;">
+ * <dt>in
+ * <dd style="margin-left: 1.5em">
+ * Indicates the input flow filter list, which is evaluated when a
+ * packet is forwarded to the vTerminal interface.
+ *
+ * <dt>out
+ * <dd style="margin-left: 1.5em">
+ * Indicates the output flow filter list, which is evaluated when a
+ * packet is going to be transmitted to the physical network mapped
+ * to the vTerminal interface.
+ * </dl>
+ * @param index
+ * The index value which specifies the flow filter in the vTerminal
+ * interface flow filter list. A string representation of an integer
+ * value must be specified.
+ * @return Response as dictated by the HTTP Response Status code.
+ */
+ @Path("{listType}/{index}")
+ @DELETE
+ @TypeHint(TypeHint.NO_CONTENT.class)
+ @StatusCodes({
+ @ResponseCode(code = HTTP_OK,
+ condition = "Flow filter was deleted successfully."),
+ @ResponseCode(code = HTTP_NO_CONTENT,
+ condition = "The specified flow filter does not exist " +
+ "in the specified vTerminal."),
+ @ResponseCode(code = HTTP_BAD_REQUEST,
+ condition = "Invalid value is passed to " +
+ "<u>{listType}</u>."),
+ @ResponseCode(code = HTTP_UNAUTHORIZED,
+ condition = "User is not authorized to perform this " +
+ "operation."),
+ @ResponseCode(code = HTTP_NOT_FOUND,
+ condition = "<ul>" +
+ "<li>The specified container does not exist.</li>" +
+ "<li>The specified VTN does not exist.</li>" +
+ "<li>The specified vTerminal does not exist.</li>" +
+ "<li>The specified vTerminal interface does not " +
+ "exist.</li>" +
+ "<li>A string passed to <u>{index}</u> can not be " +
+ "converted into an integer.</li>" +
+ "</ul>"),
+ @ResponseCode(code = HTTP_NOT_ACCEPTABLE,
+ condition = "\"default\" is specified to " +
+ "<u>{containerName}</u> and a container other than " +
+ "the default container is present."),
+ @ResponseCode(code = HTTP_INTERNAL_ERROR,
+ condition = "Fatal internal error occurred in the " +
+ "VTN Manager."),
+ @ResponseCode(code = HTTP_UNAVAILABLE,
+ condition = "One or more of mandatory controller " +
+ "services, such as the VTN Manager, are unavailable.")})
+ public Response deleteFlowFilter(
+ @PathParam("containerName") String containerName,
+ @PathParam("tenantName") String tenantName,
+ @PathParam("termName") String termName,
+ @PathParam("ifName") String ifName,
+ @PathParam("listType") String listType,
+ @PathParam("index") int index) {
+ checkPrivilege(containerName, Privilege.WRITE);
+
+ // REVISIT: Not yet.
+ return null;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 NEC Corporation
+ * 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.vtn.manager.northbound;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.VBridgeIfPath;
+import org.opendaylight.vtn.manager.VTerminalIfPath;
+import org.opendaylight.vtn.manager.flow.action.FlowAction;
+import org.opendaylight.vtn.manager.flow.action.SetDlDstAction;
+import org.opendaylight.vtn.manager.flow.action.SetDlSrcAction;
+import org.opendaylight.vtn.manager.flow.action.SetDscpAction;
+import org.opendaylight.vtn.manager.flow.action.SetIcmpCodeAction;
+import org.opendaylight.vtn.manager.flow.action.SetIcmpTypeAction;
+import org.opendaylight.vtn.manager.flow.action.SetInet4DstAction;
+import org.opendaylight.vtn.manager.flow.action.SetInet4SrcAction;
+import org.opendaylight.vtn.manager.flow.action.SetTpDstAction;
+import org.opendaylight.vtn.manager.flow.action.SetTpSrcAction;
+import org.opendaylight.vtn.manager.flow.action.SetVlanPcpAction;
+import org.opendaylight.vtn.manager.flow.filter.DropFilter;
+import org.opendaylight.vtn.manager.flow.filter.FilterType;
+import org.opendaylight.vtn.manager.flow.filter.FlowFilter;
+import org.opendaylight.vtn.manager.flow.filter.PassFilter;
+import org.opendaylight.vtn.manager.flow.filter.RedirectFilter;
+
+/**
+ * JUnit test for {@link FlowFilterList}.
+ */
+public class FlowFilterListTest extends TestBase {
+ /**
+ * A list of {@link FilterType} instances for test.
+ */
+ private List<FilterType> filterTypes;
+
+ /**
+ * A list of {@link FlowAction} instance lists for test.
+ */
+ private List<List<FlowAction>> actionLists;
+
+ /**
+ * Test case for getter methods.
+ */
+ @Test
+ public void testGetter() {
+ // Null list.
+ FlowFilterList nullList = new FlowFilterList(null);
+ assertNull(nullList.getFilters());
+
+ // Empty list.
+ List<FlowFilter> filters = new ArrayList<FlowFilter>();
+ FlowFilterList emptyList = new FlowFilterList(filters);
+ assertEquals(filters, emptyList.getFilters());
+
+ int[] indices = {0, 1, 65535};
+ for (int index: indices) {
+ for (String cond: createStrings("cnd")) {
+ for (FilterType type: createFilterTypes()) {
+ for (List<FlowAction> actions: createActionLists()) {
+ FlowFilter ff = (index == 0)
+ ? new FlowFilter(cond, type, actions)
+ : new FlowFilter(index, cond, type, actions);
+ filters.add(ff);
+
+ List<FlowFilter> list =
+ new ArrayList<FlowFilter>(filters);
+ FlowFilterList fl = new FlowFilterList(list);
+ assertEquals(list, fl.getFilters());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Test case for {@link FlowFilterList#equals(Object)} and
+ * {@link FlowFilterList#hashCode()}.
+ */
+ @Test
+ public void testEquals() {
+ HashSet<Object> set = new HashSet<Object>();
+
+ // Null list.
+ FlowFilterList nullList = new FlowFilterList(null);
+ testEquals(set, nullList, new FlowFilterList(null));
+
+ // Empty list should be treated as null list.
+ List<FlowFilter> filters1 = new ArrayList<FlowFilter>();
+ List<FlowFilter> filters2 = new ArrayList<FlowFilter>();
+ FlowFilterList emptyList = new FlowFilterList(filters1);
+ assertEquals(nullList, emptyList);
+ assertEquals(nullList.hashCode(), emptyList.hashCode());
+ assertFalse(set.add(emptyList));
+
+ int[] indices = {0, 1, 65535};
+ String[] conditions = {null, "condition"};
+ List<FilterType> types = createFilterTypes();
+ List<List<FlowAction>> actLists = createActionLists();
+ for (Iterator<List<FlowAction>> it = actLists.iterator();
+ it.hasNext();) {
+ List<FlowAction> act = it.next();
+ if (act == null) {
+ it.remove();
+ break;
+ }
+ }
+
+ for (int index: indices) {
+ for (String cond: conditions) {
+ for (FilterType type: types) {
+ for (List<FlowAction> actions: actLists) {
+ FlowFilter ff1, ff2;
+ List<FlowAction> alist =
+ new ArrayList<FlowAction>(actions);
+ if (index == 0) {
+ ff1 = new FlowFilter(cond, type, actions);
+ ff2 = new FlowFilter(copy(cond), type, alist);
+ } else {
+ ff1 = new FlowFilter(index, cond, type, actions);
+ ff2 = new FlowFilter(index, copy(cond), type,
+ alist);
+ }
+
+ filters1.add(ff1);
+ filters2.add(ff2);
+ List<FlowFilter> list1 =
+ new ArrayList<FlowFilter>(filters1);
+ List<FlowFilter> list2 =
+ new ArrayList<FlowFilter>(filters2);
+ FlowFilterList fl1 = new FlowFilterList(list1);
+ FlowFilterList fl2 = new FlowFilterList(list2);
+ testEquals(set, fl1, fl2);
+ }
+ }
+ }
+ }
+
+ int required = indices.length * conditions.length * types.size() *
+ actLists.size() + 1;
+ assertEquals(required, set.size());
+ }
+
+ /**
+ * Ensure that {@link FlowFilterList} is mapped to XML root element.
+ */
+ @Test
+ public void testJAXB() {
+ // Null list.
+ FlowFilterList fl = new FlowFilterList(null);
+ String rootName = "flowfilters";
+ jaxbTest(fl, rootName);
+
+ // Empty list.
+ List<FlowFilter> filters = new ArrayList<FlowFilter>();
+ fl = new FlowFilterList(filters);
+ jaxbTest(fl, rootName);
+
+ int[] indices = {0, 1, 65535};
+ String[] conditions = {null, "condition"};
+ for (int index: indices) {
+ for (String cond: conditions) {
+ for (FilterType type: createFilterTypes()) {
+ for (List<FlowAction> actions: createActionLists()) {
+ FlowFilter ff = (index == 0)
+ ? new FlowFilter(cond, type, actions)
+ : new FlowFilter(index, cond, type, actions);
+ filters.add(ff);
+
+ List<FlowFilter> list =
+ new ArrayList<FlowFilter>(filters);
+ fl = new FlowFilterList(list);
+ jaxbTest(fl, rootName);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Ensure that {@link FlowFilterList} is mapped to JSON object.
+ */
+ @Test
+ public void testJSON() {
+ // Null list.
+ FlowFilterList fl = new FlowFilterList(null);
+ String rootName = "flowfilters";
+ jaxbTest(fl, rootName);
+
+ // Empty list.
+ List<FlowFilter> filters = new ArrayList<FlowFilter>();
+ fl = new FlowFilterList(filters);
+ jaxbTest(fl, rootName);
+
+ int[] indices = {0, 1, 65535};
+ String[] conditions = {null, "condition"};
+ for (int index: indices) {
+ for (String cond: conditions) {
+ for (FilterType type: createFilterTypes()) {
+ for (List<FlowAction> actions: createActionLists()) {
+ FlowFilter ff = (index == 0)
+ ? new FlowFilter(cond, type, actions)
+ : new FlowFilter(index, cond, type, actions);
+ filters.add(ff);
+
+ List<FlowFilter> list =
+ new ArrayList<FlowFilter>(filters);
+ fl = new FlowFilterList(list);
+ jsonTest(fl);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Create a list of {@link FilterType} instances.
+ *
+ * @return A list of {@link FilterType} instances.
+ */
+ private List<FilterType> createFilterTypes() {
+ List<FilterType> list = filterTypes;
+ if (list == null) {
+ list = new ArrayList<FilterType>();
+ list.add(null);
+ list.add(new PassFilter());
+ list.add(new DropFilter());
+ list.add(new RedirectFilter(
+ new VBridgeIfPath(null, "bname", "if1"), true));
+ list.add(new RedirectFilter(
+ new VTerminalIfPath("vtn", "vtname", "if2"), false));
+ filterTypes = list;
+ }
+
+ return list;
+ }
+
+ /**
+ * Create lists of {@link FlowAction} instances.
+ *
+ * @return A list of {@link FlowAction} instance lists.
+ */
+ private List<List<FlowAction>> createActionLists() {
+ List<List<FlowAction>> list = actionLists;
+ if (list == null) {
+ list = new ArrayList<List<FlowAction>>();
+ byte[] mac1 = {
+ (byte)0x00, (byte)0x01, (byte)0x02,
+ (byte)0x03, (byte)0x04, (byte)0x05,
+ };
+ byte[] mac2 = {
+ (byte)0x10, (byte)0x20, (byte)0x30,
+ (byte)0x40, (byte)0x50, (byte)0x60,
+ };
+ byte[] mac3 = {
+ (byte)0xa0, (byte)0xbb, (byte)0xcc,
+ (byte)0xdd, (byte)0xee, (byte)0xff,
+ };
+ byte[] mac4 = {
+ (byte)0xfa, (byte)0xf0, (byte)0xf1,
+ (byte)0xfa, (byte)0xfb, (byte)0xfc,
+ };
+
+ InetAddress addr1, addr2;
+ try {
+ addr1 = InetAddress.getByName("192.168.100.1");
+ addr2 = InetAddress.getByName("192.168.200.123");
+ } catch (Exception e) {
+ unexpected(e);
+ return null;
+ }
+
+ list.add(null);
+ list.add(new ArrayList<FlowAction>());
+ list.add(createActions(new SetDscpAction((byte)63),
+ new SetDlSrcAction(mac1),
+ new SetDlDstAction(mac2),
+ new SetVlanPcpAction((byte)3)));
+
+ // Create all-in-one list.
+ list.add(createActions(new SetVlanPcpAction((byte)7),
+ new SetDscpAction((byte)4),
+ new SetTpSrcAction(65535),
+ new SetTpDstAction(0),
+ new SetDlSrcAction(mac3),
+ new SetDlDstAction(mac4),
+ new SetIcmpTypeAction((short)255),
+ new SetIcmpCodeAction((short)128),
+ new SetInet4SrcAction(addr1),
+ new SetInet4DstAction(addr2)));
+
+ actionLists = list;
+ }
+
+ return list;
+ }
+
+ /**
+ * Create a list of {@link FlowAction} instances.
+ *
+ * @param actions An array of {@link FlowAction} instances to be added
+ * to the list.
+ * @return A list of {@link FlowAction} instances.
+ */
+ private List<FlowAction> createActions(FlowAction ... actions) {
+ List<FlowAction> list = new ArrayList<FlowAction>();
+ for (FlowAction act: actions) {
+ list.add(act);
+ }
+
+ return list;
+ }
+}
import javax.xml.bind.JAXB;
import javax.xml.bind.annotation.XmlRootElement;
+import com.fasterxml.jackson.databind.AnnotationIntrospector;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
+import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
+
import org.opendaylight.vtn.manager.EthernetHost;
import org.opendaylight.vtn.manager.MacAddressEntry;
import org.opendaylight.vtn.manager.SwitchPort;
*
* @param o An object to be tested.
* @param rootName The name of expected root element.
+ * @return Deserialized object.
*/
- protected static void jaxbTest(Object o, String rootName) {
+ protected static Object jaxbTest(Object o, String rootName) {
// Ensure that the class of the given class has XmlRootElement
// annotation.
Class<?> cl = o.getClass();
assertNotSame(o, newobj);
assertEquals(o, newobj);
+
+ return newobj;
+ }
+
+ /**
+ * Ensure that the given object is mapped to JSON object.
+ *
+ * @param o An object to be tested.
+ * @param <T> The type of the given object.
+ * @return Deserialized object.
+ */
+ protected static <T> T jsonTest(T o) {
+ ObjectMapper mapper = getJsonObjectMapper();
+
+ try {
+ // Marshal the given object into JSON.
+ String json = mapper.writeValueAsString(o);
+ assertNotNull(json);
+ assertTrue(json.length() != 0);
+
+ // Unmarshal the JSON notation.
+ T newobj = mapper.readValue(json, (Class<T>)o.getClass());
+ assertNotSame(o, newobj);
+ assertEquals(o, newobj);
+ return newobj;
+ } catch (Exception e) {
+ unexpected(e);
+ }
+
+ return null;
+ }
+
+ /**
+ * Create Jackson's {@code ObjectMapper} instance.
+ *
+ * @return A {@code ObjectMapper} instance.
+ */
+ protected static ObjectMapper getJsonObjectMapper() {
+ // Create Jackson object mapper with enabling JAXB annotations.
+ ObjectMapper mapper = new ObjectMapper();
+ AnnotationIntrospector introspector =
+ AnnotationIntrospector.pair(new JacksonAnnotationIntrospector(),
+ new JaxbAnnotationIntrospector());
+ mapper.setAnnotationIntrospector(introspector);
+
+ return mapper;
}
}