Make the OFPP_LOCAL port work in the kernel OpenFlow implementation.
This commit is contained in:
+79
-88
@@ -33,6 +33,7 @@
|
||||
#include "datapath.h"
|
||||
#include "table.h"
|
||||
#include "chain.h"
|
||||
#include "dp_dev.h"
|
||||
#include "forward.h"
|
||||
#include "flow.h"
|
||||
#include "datapath_t.h"
|
||||
@@ -60,8 +61,6 @@ struct net_bridge_port {
|
||||
static struct genl_family dp_genl_family;
|
||||
static struct genl_multicast_group mc_group;
|
||||
|
||||
int dp_dev_setup(struct net_device *dev);
|
||||
|
||||
/* It's hard to imagine wanting more than one datapath, but... */
|
||||
#define DP_MAX 32
|
||||
|
||||
@@ -78,6 +77,9 @@ static DEFINE_MUTEX(dp_mutex);
|
||||
static int dp_maint_func(void *data);
|
||||
static int send_port_status(struct net_bridge_port *p, uint8_t status);
|
||||
static int dp_genl_openflow_done(struct netlink_callback *);
|
||||
static struct net_bridge_port *new_nbp(struct datapath *,
|
||||
struct net_device *, int port_no);
|
||||
static int del_switch_port(struct net_bridge_port *);
|
||||
|
||||
/* nla_shrink - reduce amount of space reserved by nla_reserve
|
||||
* @skb: socket buffer from which to recover room
|
||||
@@ -270,35 +272,42 @@ static int new_dp(int dp_idx)
|
||||
if (dp == NULL)
|
||||
goto err_unlock;
|
||||
|
||||
/* Setup our "of" device */
|
||||
err = dp_dev_setup(dp);
|
||||
if (err)
|
||||
goto err_free_dp;
|
||||
|
||||
dp->dp_idx = dp_idx;
|
||||
dp->id = gen_datapath_id(dp_idx);
|
||||
dp->chain = chain_create(dp);
|
||||
if (dp->chain == NULL)
|
||||
goto err_free_dp;
|
||||
goto err_destroy_dp_dev;
|
||||
INIT_LIST_HEAD(&dp->port_list);
|
||||
|
||||
#if 0
|
||||
/* Setup our "of" device */
|
||||
dp->dev.priv = dp;
|
||||
rtnl_lock();
|
||||
err = dp_dev_setup(&dp->dev);
|
||||
rtnl_unlock();
|
||||
if (err != 0)
|
||||
printk("datapath: problem setting up 'of' device\n");
|
||||
#endif
|
||||
dp->local_port = new_nbp(dp, dp->netdev, OFPP_LOCAL);
|
||||
if (IS_ERR(dp->local_port)) {
|
||||
err = PTR_ERR(dp->local_port);
|
||||
goto err_destroy_local_port;
|
||||
}
|
||||
|
||||
dp->flags = 0;
|
||||
dp->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN;
|
||||
|
||||
dp->dp_task = kthread_run(dp_maint_func, dp, "dp%d", dp_idx);
|
||||
if (IS_ERR(dp->dp_task))
|
||||
goto err_free_dp;
|
||||
goto err_destroy_chain;
|
||||
|
||||
rcu_assign_pointer(dps[dp_idx], dp);
|
||||
mutex_unlock(&dp_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
err_destroy_local_port:
|
||||
del_switch_port(dp->local_port);
|
||||
err_destroy_chain:
|
||||
chain_destroy(dp->chain);
|
||||
err_destroy_dp_dev:
|
||||
dp_dev_destroy(dp);
|
||||
err_free_dp:
|
||||
kfree(dp);
|
||||
err_unlock:
|
||||
@@ -318,23 +327,29 @@ static int find_portno(struct datapath *dp)
|
||||
}
|
||||
|
||||
static struct net_bridge_port *new_nbp(struct datapath *dp,
|
||||
struct net_device *dev)
|
||||
struct net_device *dev, int port_no)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
int port_no;
|
||||
|
||||
port_no = find_portno(dp);
|
||||
if (port_no < 0)
|
||||
return ERR_PTR(port_no);
|
||||
if (dev->br_port != NULL)
|
||||
return ERR_PTR(-EBUSY);
|
||||
|
||||
p = kzalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (p == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
p->dp = dp;
|
||||
rtnl_lock();
|
||||
dev_set_promiscuity(dev, 1);
|
||||
rtnl_unlock();
|
||||
dev_hold(dev);
|
||||
p->dp = dp;
|
||||
p->dev = dev;
|
||||
p->port_no = port_no;
|
||||
if (port_no != OFPP_LOCAL)
|
||||
rcu_assign_pointer(dev->br_port, p);
|
||||
if (port_no < OFPP_MAX)
|
||||
rcu_assign_pointer(dp->ports[port_no], p);
|
||||
list_add_rcu(&p->node, &dp->port_list);
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -343,26 +358,20 @@ static struct net_bridge_port *new_nbp(struct datapath *dp,
|
||||
int add_switch_port(struct datapath *dp, struct net_device *dev)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
int port_no;
|
||||
|
||||
if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER)
|
||||
if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER
|
||||
|| is_dp_dev(dev))
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->br_port != NULL)
|
||||
return -EBUSY;
|
||||
port_no = find_portno(dp);
|
||||
if (port_no < 0)
|
||||
return port_no;
|
||||
|
||||
p = new_nbp(dp, dev);
|
||||
p = new_nbp(dp, dev, port_no);
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
|
||||
dev_hold(dev);
|
||||
rcu_assign_pointer(dev->br_port, p);
|
||||
rtnl_lock();
|
||||
dev_set_promiscuity(dev, 1);
|
||||
rtnl_unlock();
|
||||
|
||||
rcu_assign_pointer(dp->ports[p->port_no], p);
|
||||
list_add_rcu(&p->node, &dp->port_list);
|
||||
|
||||
/* Notify the ctlpath that this port has been added */
|
||||
send_port_status(p, OFPPR_ADD);
|
||||
|
||||
@@ -396,19 +405,13 @@ static int del_switch_port(struct net_bridge_port *p)
|
||||
/* Called with dp_mutex. */
|
||||
static void del_dp(struct datapath *dp)
|
||||
{
|
||||
struct net_bridge_port *p, *n;
|
||||
|
||||
#if 0
|
||||
/* Unregister the "of" device of this dp */
|
||||
rtnl_lock();
|
||||
unregister_netdevice(&dp->dev);
|
||||
rtnl_unlock();
|
||||
#endif
|
||||
struct net_bridge_port *p;
|
||||
|
||||
dp_dev_destroy(dp);
|
||||
kthread_stop(dp->dp_task);
|
||||
|
||||
/* Drop references to DP. */
|
||||
list_for_each_entry_safe (p, n, &dp->port_list, node)
|
||||
list_for_each_entry_rcu (p, &dp->port_list, node)
|
||||
del_switch_port(p);
|
||||
rcu_assign_pointer(dps[dp->dp_idx], NULL);
|
||||
|
||||
@@ -479,21 +482,6 @@ static void dp_frame_hook(struct sk_buff *skb)
|
||||
/* Forwarding output path.
|
||||
* Based on net/bridge/br_forward.c. */
|
||||
|
||||
/* Don't forward packets to originating port. If we're flooding,
|
||||
* then don't send out ports with flooding disabled.
|
||||
*/
|
||||
static inline int should_deliver(const struct net_bridge_port *p,
|
||||
const struct sk_buff *skb, int flood)
|
||||
{
|
||||
if (skb->dev == p->dev)
|
||||
return 0;
|
||||
|
||||
if (flood && (p->flags & BRIDGE_PORT_NO_FLOOD))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline unsigned packet_length(const struct sk_buff *skb)
|
||||
{
|
||||
int length = skb->len - ETH_HLEN;
|
||||
@@ -508,12 +496,12 @@ static inline unsigned packet_length(const struct sk_buff *skb)
|
||||
static int
|
||||
output_all(struct datapath *dp, struct sk_buff *skb, int flood)
|
||||
{
|
||||
u32 disable = flood ? BRIDGE_PORT_NO_FLOOD : 0;
|
||||
struct net_bridge_port *p;
|
||||
int prev_port;
|
||||
int prev_port = -1;
|
||||
|
||||
prev_port = -1;
|
||||
list_for_each_entry_rcu (p, &dp->port_list, node) {
|
||||
if (!should_deliver(p, skb, flood))
|
||||
if (skb->dev == p->dev || p->flags & disable)
|
||||
continue;
|
||||
if (prev_port != -1) {
|
||||
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
|
||||
@@ -538,8 +526,11 @@ output_all(struct datapath *dp, struct sk_buff *skb, int flood)
|
||||
int dp_set_origin(struct datapath *dp, uint16_t in_port,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
if (in_port < OFPP_MAX && dp->ports[in_port]) {
|
||||
skb->dev = dp->ports[in_port]->dev;
|
||||
struct net_bridge_port *p = (in_port < OFPP_MAX ? dp->ports[in_port]
|
||||
: in_port == OFPP_LOCAL ? dp->local_port
|
||||
: NULL);
|
||||
if (p) {
|
||||
skb->dev = p->dev;
|
||||
return 0;
|
||||
}
|
||||
return -ENOENT;
|
||||
@@ -549,9 +540,6 @@ int dp_set_origin(struct datapath *dp, uint16_t in_port,
|
||||
*/
|
||||
int dp_output_port(struct datapath *dp, struct sk_buff *skb, int out_port)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
int len = skb->len;
|
||||
|
||||
BUG_ON(!skb);
|
||||
if (out_port == OFPP_FLOOD)
|
||||
return output_all(dp, skb, 1);
|
||||
@@ -561,10 +549,11 @@ int dp_output_port(struct datapath *dp, struct sk_buff *skb, int out_port)
|
||||
return dp_output_control(dp, skb, fwd_save_skb(skb), 0,
|
||||
OFPR_ACTION);
|
||||
else if (out_port == OFPP_TABLE) {
|
||||
struct net_bridge_port *p = skb->dev->br_port;
|
||||
struct sw_flow_key key;
|
||||
struct sw_flow *flow;
|
||||
|
||||
flow_extract(skb, skb->dev->br_port->port_no, &key);
|
||||
flow_extract(skb, p ? p->port_no : OFPP_LOCAL, &key);
|
||||
flow = chain_lookup(dp->chain, &key);
|
||||
if (likely(flow != NULL)) {
|
||||
flow_used(flow, skb);
|
||||
@@ -572,25 +561,27 @@ int dp_output_port(struct datapath *dp, struct sk_buff *skb, int out_port)
|
||||
return 0;
|
||||
}
|
||||
return -ESRCH;
|
||||
} else if (out_port >= OFPP_MAX)
|
||||
goto bad_port;
|
||||
} else if (out_port == OFPP_LOCAL) {
|
||||
struct net_device *dev = dp->netdev;
|
||||
return dev ? dp_dev_recv(dev, skb) : -ESRCH;
|
||||
} else if (out_port >= 0 && out_port < OFPP_MAX) {
|
||||
struct net_bridge_port *p = dp->ports[out_port];
|
||||
int len = skb->len;
|
||||
if (p == NULL)
|
||||
goto bad_port;
|
||||
skb->dev = p->dev;
|
||||
if (packet_length(skb) > skb->dev->mtu) {
|
||||
printk("dropped over-mtu packet: %d > %d\n",
|
||||
packet_length(skb), skb->dev->mtu);
|
||||
kfree_skb(skb);
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
p = dp->ports[out_port];
|
||||
if (p == NULL)
|
||||
goto bad_port;
|
||||
dev_queue_xmit(skb);
|
||||
|
||||
skb->dev = p->dev;
|
||||
if (packet_length(skb) > skb->dev->mtu) {
|
||||
printk("dropped over-mtu packet: %d > %d\n",
|
||||
packet_length(skb), skb->dev->mtu);
|
||||
kfree_skb(skb);
|
||||
return -E2BIG;
|
||||
return len;
|
||||
}
|
||||
|
||||
dev_queue_xmit(skb);
|
||||
|
||||
return len;
|
||||
|
||||
bad_port:
|
||||
kfree_skb(skb);
|
||||
if (net_ratelimit())
|
||||
@@ -612,6 +603,7 @@ dp_output_control(struct datapath *dp, struct sk_buff *skb,
|
||||
* forward the whole packet? */
|
||||
struct sk_buff *f_skb;
|
||||
struct ofp_packet_in *opi;
|
||||
struct net_bridge_port *p;
|
||||
size_t fwd_len, opi_len;
|
||||
int err;
|
||||
|
||||
@@ -627,7 +619,8 @@ dp_output_control(struct datapath *dp, struct sk_buff *skb,
|
||||
}
|
||||
opi->buffer_id = htonl(buffer_id);
|
||||
opi->total_len = htons(skb->len);
|
||||
opi->in_port = htons(skb->dev->br_port->port_no);
|
||||
p = skb->dev->br_port;
|
||||
opi->in_port = htons(p ? p->port_no : OFPP_LOCAL);
|
||||
opi->reason = reason;
|
||||
opi->pad = 0;
|
||||
memcpy(opi->data, skb_mac_header(skb), fwd_len);
|
||||
@@ -744,16 +737,14 @@ dp_send_config_reply(struct datapath *dp, const struct sender *sender)
|
||||
int
|
||||
dp_update_port_flags(struct datapath *dp, const struct ofp_phy_port *opp)
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
|
||||
p = dp->ports[htons(opp->port_no)];
|
||||
|
||||
int port_no = ntohs(opp->port_no);
|
||||
struct net_bridge_port *p = (port_no < OFPP_MAX ? dp->ports[port_no]
|
||||
: port_no == OFPP_LOCAL ? dp->local_port
|
||||
: NULL);
|
||||
/* Make sure the port id hasn't changed since this was sent */
|
||||
if (!p || memcmp(opp->hw_addr, p->dev->dev_addr, ETH_ALEN) != 0)
|
||||
if (!p || memcmp(opp->hw_addr, p->dev->dev_addr, ETH_ALEN))
|
||||
return -1;
|
||||
|
||||
p->flags = htonl(opp->flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -45,8 +45,7 @@ struct datapath {
|
||||
struct task_struct *dp_task; /* Kernel thread for maintenance. */
|
||||
|
||||
/* Data related to the "of" device of this datapath */
|
||||
struct net_device dev;
|
||||
struct net_device_stats stats;
|
||||
struct net_device *netdev;
|
||||
|
||||
/* Configuration set from controller */
|
||||
uint16_t flags;
|
||||
@@ -54,7 +53,8 @@ struct datapath {
|
||||
|
||||
/* Switch ports. */
|
||||
struct net_bridge_port *ports[OFPP_MAX];
|
||||
struct list_head port_list; /* List of ports, for flooding. */
|
||||
struct net_bridge_port *local_port; /* OFPP_LOCAL port. */
|
||||
struct list_head port_list; /* All ports, including local_port. */
|
||||
};
|
||||
|
||||
/* Information necessary to reply to the sender of an OpenFlow message. */
|
||||
|
||||
+104
-48
@@ -6,73 +6,129 @@
|
||||
#include "datapath.h"
|
||||
#include "forward.h"
|
||||
|
||||
static int dp_dev_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||
struct dp_dev {
|
||||
struct net_device_stats stats;
|
||||
struct datapath *dp;
|
||||
};
|
||||
|
||||
static struct dp_dev *dp_dev_priv(struct net_device *netdev)
|
||||
{
|
||||
printk("xxx_do_ioctl called\n");
|
||||
return netdev_priv(netdev);
|
||||
}
|
||||
|
||||
static struct net_device_stats *dp_dev_get_stats(struct net_device *netdev)
|
||||
{
|
||||
struct dp_dev *dp_dev = dp_dev_priv(netdev);
|
||||
return &dp_dev->stats;
|
||||
}
|
||||
|
||||
int dp_dev_recv(struct net_device *netdev, struct sk_buff *skb)
|
||||
{
|
||||
int len = skb->len;
|
||||
struct dp_dev *dp_dev = dp_dev_priv(netdev);
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
skb->protocol = eth_type_trans(skb, netdev);
|
||||
netif_rx(skb);
|
||||
netdev->last_rx = jiffies;
|
||||
dp_dev->stats.rx_packets++;
|
||||
dp_dev->stats.rx_bytes += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static int dp_dev_mac_addr(struct net_device *dev, void *p)
|
||||
{
|
||||
struct sockaddr *addr = p;
|
||||
|
||||
if (netif_running(dev))
|
||||
return -EBUSY;
|
||||
if (!is_valid_ether_addr(addr->sa_data))
|
||||
return -EADDRNOTAVAIL;
|
||||
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct net_device_stats *dp_dev_get_stats(struct net_device *dev)
|
||||
static int dp_dev_xmit(struct sk_buff *skb, struct net_device *netdev)
|
||||
{
|
||||
struct datapath *dp = netdev_priv(dev);
|
||||
return &dp->stats;
|
||||
}
|
||||
|
||||
int dp_dev_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct datapath *dp = netdev_priv(dev);
|
||||
|
||||
printk("xxx dp_dev_xmit not implemented yet!\n");
|
||||
return 0;
|
||||
|
||||
printk("xxx_xmit called send to dp_frame_hook\n");
|
||||
|
||||
rcu_read_lock(); /* xxx Only for 2.4 kernels? */
|
||||
fwd_port_input(dp->chain, skb, OFPP_LOCAL);
|
||||
rcu_read_unlock(); /* xxx Only for 2.4 kernels? */
|
||||
|
||||
struct dp_dev *dp_dev = dp_dev_priv(netdev);
|
||||
struct datapath *dp;
|
||||
rcu_read_lock();
|
||||
dp = dp_dev->dp;
|
||||
if (likely(dp != NULL)) {
|
||||
dp_dev->stats.tx_packets++;
|
||||
dp_dev->stats.tx_bytes += skb->len;
|
||||
skb_reset_mac_header(skb);
|
||||
fwd_port_input(dp->chain, skb, OFPP_LOCAL);
|
||||
} else {
|
||||
dp_dev->stats.tx_dropped++;
|
||||
kfree_skb(skb);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_dev_open(struct net_device *dev)
|
||||
static int dp_dev_open(struct net_device *netdev)
|
||||
{
|
||||
netif_start_queue(dev);
|
||||
netif_start_queue(netdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dp_dev_set_multicast_list(struct net_device *dev)
|
||||
static int dp_dev_stop(struct net_device *netdev)
|
||||
{
|
||||
printk("xxx_set_multi called\n");
|
||||
}
|
||||
|
||||
static int dp_dev_stop(struct net_device *dev)
|
||||
{
|
||||
netif_stop_queue(dev);
|
||||
netif_stop_queue(netdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dp_dev_setup(struct net_device *dev)
|
||||
static void
|
||||
do_setup(struct net_device *netdev)
|
||||
{
|
||||
ether_setup(netdev);
|
||||
|
||||
netdev->get_stats = dp_dev_get_stats;
|
||||
netdev->hard_start_xmit = dp_dev_xmit;
|
||||
netdev->open = dp_dev_open;
|
||||
netdev->stop = dp_dev_stop;
|
||||
netdev->tx_queue_len = 0;
|
||||
netdev->set_mac_address = dp_dev_mac_addr;
|
||||
|
||||
netdev->flags = IFF_BROADCAST | IFF_MULTICAST;
|
||||
|
||||
random_ether_addr(netdev->dev_addr);
|
||||
}
|
||||
|
||||
|
||||
int dp_dev_setup(struct datapath *dp)
|
||||
{
|
||||
struct dp_dev *dp_dev;
|
||||
struct net_device *netdev;
|
||||
char of_name[8];
|
||||
int err;
|
||||
|
||||
strncpy(dev->name, "of%d", IFNAMSIZ);
|
||||
err = dev_alloc_name(dev, dev->name);
|
||||
if (err < 0)
|
||||
snprintf(of_name, sizeof of_name, "of%d", dp->dp_idx);
|
||||
netdev = alloc_netdev(sizeof(struct dp_dev), of_name, do_setup);
|
||||
if (!netdev)
|
||||
return -ENOMEM;
|
||||
|
||||
err = register_netdev(netdev);
|
||||
if (err) {
|
||||
free_netdev(netdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
dev->do_ioctl = dp_dev_do_ioctl;
|
||||
dev->get_stats = dp_dev_get_stats;
|
||||
dev->hard_start_xmit = dp_dev_xmit;
|
||||
dev->open = dp_dev_open;
|
||||
dev->set_multicast_list = dp_dev_set_multicast_list;
|
||||
dev->stop = dp_dev_stop;
|
||||
dev->tx_queue_len = 0;
|
||||
dev->set_mac_address = NULL;
|
||||
|
||||
dev->flags = IFF_BROADCAST | IFF_NOARP | IFF_MULTICAST;
|
||||
|
||||
random_ether_addr(dev->dev_addr);
|
||||
|
||||
ether_setup(dev);
|
||||
return register_netdevice(dev);
|
||||
dp_dev = dp_dev_priv(netdev);
|
||||
dp_dev->dp = dp;
|
||||
dp->netdev = netdev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dp_dev_destroy(struct datapath *dp)
|
||||
{
|
||||
struct dp_dev *dp_dev = dp_dev_priv(dp->netdev);
|
||||
dp_dev->dp = NULL;
|
||||
synchronize_net();
|
||||
unregister_netdev(dp->netdev);
|
||||
}
|
||||
|
||||
int is_dp_dev(struct net_device *netdev)
|
||||
{
|
||||
return netdev->open == dp_dev_open;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef DP_DEV_H
|
||||
#define DP_DEV_H 1
|
||||
|
||||
int dp_dev_setup(struct datapath *);
|
||||
void dp_dev_destroy(struct datapath *);
|
||||
int dp_dev_recv(struct net_device *, struct sk_buff *);
|
||||
int is_dp_dev(struct net_device *);
|
||||
|
||||
#endif /* dp_dev.h */
|
||||
@@ -2,6 +2,8 @@
|
||||
#define __LINUX_NETDEVICE_WRAPPER_H 1
|
||||
|
||||
#include_next <linux/netdevice.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* In 2.6.24, a namespace argument became required for dev_get_by_name.
|
||||
@@ -28,4 +30,10 @@ static inline void *netdev_priv(struct net_device *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Synchronize with packet receive processing. */
|
||||
static inline void synchronize_net(void)
|
||||
{
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ enum ofp_port {
|
||||
those disabled by STP. */
|
||||
OFPP_ALL = 0xfffc, /* All physical ports except input port. */
|
||||
OFPP_CONTROLLER = 0xfffd, /* Send to controller. */
|
||||
OFPP_LOCAL = 0xfffe, /* Local openflow "port". */ /* xxx Want?! */
|
||||
OFPP_LOCAL = 0xfffe, /* Local openflow "port". */
|
||||
OFPP_NONE = 0xffff /* Not associated with a physical port. */
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user