#include "dp_dev.h"
#include "forward.h"
#include "flow.h"
-#include "datapath_t.h"
#include "compat.h"
static int
send_openflow_skb(struct sk_buff *skb, const struct sender *sender)
{
- int err = (sender
- ? genlmsg_unicast(skb, sender->pid)
- : genlmsg_multicast(skb, 0, mc_group.id, GFP_ATOMIC));
- if (err && net_ratelimit())
- printk(KERN_WARNING "send_openflow_skb: send failed: %d\n",
- err);
- return err;
+ return (sender
+ ? genlmsg_unicast(skb, sender->pid)
+ : genlmsg_multicast(skb, 0, mc_group.id, GFP_ATOMIC));
}
/* Generates a unique datapath id. It incorporates the datapath index
/* Called with dp_mutex. */
static void del_dp(struct datapath *dp)
{
- struct net_bridge_port *p;
+ struct net_bridge_port *p, *n;
- dp_dev_destroy(dp);
kthread_stop(dp->dp_task);
/* Drop references to DP. */
- list_for_each_entry_rcu (p, &dp->port_list, node)
+ list_for_each_entry_safe (p, n, &dp->port_list, node)
del_switch_port(p);
rcu_assign_pointer(dps[dp->dp_idx], NULL);
+ /* Kill off local_port dev references from buffered packets that have
+ * associated dst entries. */
+ synchronize_rcu();
+ fwd_discard_all();
+
+ /* Destroy dp->netdev. (Must follow deleting switch ports since
+ * dp->local_port has a reference to it.) */
+ dp_dev_destroy(dp);
+
/* Wait until no longer in use, then destroy it. */
synchronize_rcu();
chain_destroy(dp->chain);
do_port_input(struct net_bridge_port *p, struct sk_buff *skb)
{
/* Push the Ethernet header back on. */
- if (skb->protocol == htons(ETH_P_8021Q))
- skb_push(skb, VLAN_ETH_HLEN);
- else
- skb_push(skb, ETH_HLEN);
+ skb_push(skb, ETH_HLEN);
fwd_port_input(p->dp->chain, skb, p->port_no);
}
return send_openflow_skb(skb, sender);
}
+int
+dp_send_echo_reply(struct datapath *dp, const struct sender *sender,
+ const struct ofp_header *rq)
+{
+ struct sk_buff *skb;
+ struct ofp_header *reply;
+
+ reply = alloc_openflow_skb(dp, ntohs(rq->length), OFPT_ECHO_REPLY,
+ sender, &skb);
+ if (!reply)
+ return -ENOMEM;
+
+ memcpy(reply + 1, rq + 1, ntohs(rq->length) - sizeof *rq);
+ return send_openflow_skb(skb, sender);
+}
+
/* Generic Netlink interface.
*
* See netlink(7) for an introduction to netlink. See
.dumpit = dp_genl_openflow_dumpit,
};
-static struct nla_policy dp_genl_benchmark_policy[DP_GENL_A_MAX + 1] = {
- [DP_GENL_A_DP_IDX] = { .type = NLA_U32 },
- [DP_GENL_A_NPACKETS] = { .type = NLA_U32 },
- [DP_GENL_A_PSIZE] = { .type = NLA_U32 },
-};
-
-static struct genl_ops dp_genl_ops_benchmark_nl = {
- .cmd = DP_GENL_C_BENCHMARK_NL,
- .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privilege. */
- .policy = dp_genl_benchmark_policy,
- .doit = dp_genl_benchmark_nl,
- .dumpit = NULL,
-};
-
static struct genl_ops *dp_genl_all_ops[] = {
/* Keep this operation first. Generic Netlink dispatching
* looks up operations with linear search, so we want it at the
&dp_genl_ops_query_dp,
&dp_genl_ops_add_port,
&dp_genl_ops_del_port,
- &dp_genl_ops_benchmark_nl,
};
static int dp_init_netlink(void)