X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fdatapath.c;h=4d40ac3bde253c1d6d34c2778c96fa4e7e0a82f7;hb=0f4d9dce8150fced85070149e0820707d55ee252;hp=454f96cc20bcc85e725441fd5d38d7804cacbdfa;hpb=d9065a90b6b955aa38586c952e8804ca7a22547e;p=openvswitch diff --git a/datapath/datapath.c b/datapath/datapath.c index 454f96cc..4d40ac3b 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -49,8 +49,8 @@ #include "datapath.h" #include "actions.h" #include "flow.h" -#include "table.h" #include "vlan.h" +#include "tunnel.h" #include "vport-internal_dev.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) || \ @@ -84,7 +84,7 @@ EXPORT_SYMBOL(dp_ioctl_hook); static LIST_HEAD(dps); static struct vport *new_vport(const struct vport_parms *); -static int queue_userspace_packets(struct datapath *, struct sk_buff *, +static int queue_userspace_packets(struct datapath *, u32 pid, struct sk_buff *, const struct dp_upcall_info *); /* Must be called with rcu_read_lock, genl_mutex, or RTNL lock. */ @@ -107,7 +107,7 @@ struct datapath *get_dp(int dp_ifindex) EXPORT_SYMBOL_GPL(get_dp); /* Must be called with genl_mutex. */ -static struct tbl *get_table_protected(struct datapath *dp) +static struct flow_table *get_table_protected(struct datapath *dp) { return rcu_dereference_protected(dp->table, lockdep_genl_is_held()); } @@ -124,6 +124,24 @@ const char *dp_name(const struct datapath *dp) return vport_get_name(rcu_dereference_rtnl(dp->ports[OVSP_LOCAL])); } +static int get_dpifindex(struct datapath *dp) +{ + struct vport *local; + int ifindex; + + rcu_read_lock(); + + local = get_vport_protected(dp, OVSP_LOCAL); + if (local) + ifindex = vport_get_ifindex(local); + else + ifindex = 0; + + rcu_read_unlock(); + + return ifindex; +} + static inline size_t br_nlmsg_size(void) { return NLMSG_ALIGN(sizeof(struct ifinfomsg)) @@ -160,8 +178,7 @@ static int dp_fill_ifinfo(struct sk_buff *skb, hdr->ifi_change = 0; NLA_PUT_STRING(skb, IFLA_IFNAME, vport_get_name(port)); - NLA_PUT_U32(skb, IFLA_MASTER, - vport_get_ifindex(get_vport_protected(dp, OVSP_LOCAL))); + NLA_PUT_U32(skb, IFLA_MASTER, get_dpifindex(dp)); NLA_PUT_U32(skb, IFLA_MTU, vport_get_mtu(port)); #ifdef IFLA_OPERSTATE NLA_PUT_U8(skb, IFLA_OPERSTATE, @@ -217,7 +234,7 @@ static void destroy_dp_rcu(struct rcu_head *rcu) { struct datapath *dp = container_of(rcu, struct datapath, rcu); - tbl_destroy((struct tbl __force *)dp->table, flow_free_tbl); + flow_tbl_destroy(dp->table); free_percpu(dp->stats_percpu); kobject_put(&dp->ifobj); } @@ -241,7 +258,7 @@ static struct vport *new_vport(const struct vport_parms *parms) } /* Called with RTNL lock. */ -int dp_detach_port(struct vport *p) +void dp_detach_port(struct vport *p) { ASSERT_RTNL(); @@ -254,13 +271,14 @@ int dp_detach_port(struct vport *p) rcu_assign_pointer(p->dp->ports[p->port_no], NULL); /* Then destroy it. */ - return vport_del(p); + vport_del(p); } /* Must be called with rcu_read_lock. */ void dp_process_received_packet(struct vport *p, struct sk_buff *skb) { struct datapath *dp = p->dp; + struct sw_flow *flow; struct dp_stats_percpu *stats; int stats_counter_off; int error; @@ -269,7 +287,6 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb) if (!OVS_CB(skb)->flow) { struct sw_flow_key key; - struct tbl_node *flow_node; int key_len; bool is_frag; @@ -287,9 +304,8 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb) } /* Look up flow. */ - flow_node = tbl_lookup(rcu_dereference(dp->table), &key, key_len, - flow_hash(&key, key_len), flow_cmp); - if (unlikely(!flow_node)) { + flow = flow_tbl_lookup(rcu_dereference(dp->table), &key, key_len); + if (unlikely(!flow)) { struct dp_upcall_info upcall; upcall.cmd = OVS_PACKET_CMD_MISS; @@ -303,7 +319,7 @@ void dp_process_received_packet(struct vport *p, struct sk_buff *skb) goto out; } - OVS_CB(skb)->flow = flow_cast(flow_node); + OVS_CB(skb)->flow = flow; } stats_counter_off = offsetof(struct dp_stats_percpu, n_hit); @@ -345,51 +361,22 @@ static struct genl_family dp_packet_genl_family = { .maxattr = OVS_PACKET_ATTR_MAX }; -/* Generic Netlink multicast groups for upcalls. - * - * We really want three unique multicast groups per datapath, but we can't even - * get one, because genl_register_mc_group() takes genl_lock, which is also - * held during Generic Netlink message processing, so trying to acquire - * multicast groups during OVS_DP_NEW processing deadlocks. Instead, we - * preallocate a few groups and use them round-robin for datapaths. Collision - * isn't fatal--multicast listeners should check that the family is the one - * that they want and discard others--but it wastes time and memory to receive - * unwanted messages. - */ -#define PACKET_N_MC_GROUPS 16 -static struct genl_multicast_group packet_mc_groups[PACKET_N_MC_GROUPS]; - -static u32 packet_mc_group(struct datapath *dp, u8 cmd) -{ - u32 idx; - BUILD_BUG_ON_NOT_POWER_OF_2(PACKET_N_MC_GROUPS); - - idx = jhash_2words(dp->dp_ifindex, cmd, 0) & (PACKET_N_MC_GROUPS - 1); - return packet_mc_groups[idx].id; -} - -static int packet_register_mc_groups(void) -{ - int i; - - for (i = 0; i < PACKET_N_MC_GROUPS; i++) { - struct genl_multicast_group *group = &packet_mc_groups[i]; - int error; - - sprintf(group->name, "packet%d", i); - error = genl_register_mc_group(&dp_packet_genl_family, group); - if (error) - return error; - } - return 0; -} - int dp_upcall(struct datapath *dp, struct sk_buff *skb, const struct dp_upcall_info *upcall_info) { struct dp_stats_percpu *stats; + u32 pid; int err; - WARN_ON_ONCE(skb_shared(skb)); + if (OVS_CB(skb)->flow) + pid = OVS_CB(skb)->flow->upcall_pid; + else + pid = OVS_CB(skb)->vport->upcall_pid; + + if (pid == 0) { + err = -ENOTCONN; + kfree_skb(skb); + goto err; + } forward_ip_summed(skb, true); @@ -407,7 +394,7 @@ int dp_upcall(struct datapath *dp, struct sk_buff *skb, const struct dp_upcall_i skb = nskb; } - err = queue_userspace_packets(dp, skb, upcall_info); + err = queue_userspace_packets(dp, pid, skb, upcall_info); if (err) goto err; @@ -430,13 +417,21 @@ err: * 'upcall_info'. There will be only one packet unless we broke up a GSO * packet. */ -static int queue_userspace_packets(struct datapath *dp, struct sk_buff *skb, - const struct dp_upcall_info *upcall_info) +static int queue_userspace_packets(struct datapath *dp, u32 pid, + struct sk_buff *skb, + const struct dp_upcall_info *upcall_info) { - u32 group = packet_mc_group(dp, upcall_info->cmd); + int dp_ifindex; struct sk_buff *nskb; int err; + dp_ifindex = get_dpifindex(dp); + if (!dp_ifindex) { + err = -ENODEV; + nskb = skb->next; + goto err_kfree_skbs; + } + do { struct ovs_header *upcall; struct sk_buff *user_skb; /* to be queued to userspace */ @@ -450,8 +445,10 @@ static int queue_userspace_packets(struct datapath *dp, struct sk_buff *skb, if (unlikely(err)) goto err_kfree_skbs; - if (nla_attr_size(skb->len) > USHRT_MAX) + if (nla_attr_size(skb->len) > USHRT_MAX) { + err = -EFBIG; goto err_kfree_skbs; + } len = sizeof(struct ovs_header); len += nla_total_size(skb->len); @@ -465,12 +462,12 @@ static int queue_userspace_packets(struct datapath *dp, struct sk_buff *skb, user_skb = genlmsg_new(len, GFP_ATOMIC); if (!user_skb) { - netlink_set_err(INIT_NET_GENL_SOCK, 0, group, -ENOBUFS); + err = -ENOMEM; goto err_kfree_skbs; } upcall = genlmsg_put(user_skb, 0, 0, &dp_packet_genl_family, 0, upcall_info->cmd); - upcall->dp_ifindex = dp->dp_ifindex; + upcall->dp_ifindex = dp_ifindex; nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY); flow_to_nlattrs(upcall_info->key, user_skb); @@ -495,7 +492,7 @@ static int queue_userspace_packets(struct datapath *dp, struct sk_buff *skb, else skb_copy_bits(skb, 0, nla_data(nla), skb->len); - err = genlmsg_multicast(user_skb, 0, group, GFP_ATOMIC); + err = genlmsg_unicast(&init_net, user_skb, pid); if (err) goto err_kfree_skbs; @@ -516,8 +513,8 @@ err_kfree_skbs: /* Called with genl_mutex. */ static int flush_flows(int dp_ifindex) { - struct tbl *old_table; - struct tbl *new_table; + struct flow_table *old_table; + struct flow_table *new_table; struct datapath *dp; dp = get_dp(dp_ifindex); @@ -525,14 +522,13 @@ static int flush_flows(int dp_ifindex) return -ENODEV; old_table = get_table_protected(dp); - new_table = tbl_create(TBL_MIN_BUCKETS); + new_table = flow_tbl_alloc(TBL_MIN_BUCKETS); if (!new_table) return -ENOMEM; rcu_assign_pointer(dp->table, new_table); - tbl_deferred_destroy(old_table, flow_free_tbl); - + flow_tbl_deferred_destroy(old_table); return 0; } @@ -614,24 +610,6 @@ static void clear_stats(struct sw_flow *flow) flow->byte_count = 0; } -/* Called with genl_mutex. */ -static int expand_table(struct datapath *dp) -{ - struct tbl *old_table = get_table_protected(dp); - struct tbl *new_table; - - new_table = tbl_expand(old_table); - if (IS_ERR(new_table)) { - if (PTR_ERR(new_table) != -ENOSPC) - return PTR_ERR(new_table); - } else { - rcu_assign_pointer(dp->table, new_table); - tbl_deferred_destroy(old_table, NULL); - } - - return 0; -} - static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) { struct ovs_header *ovs_header = info->userhdr; @@ -692,7 +670,12 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) if (err) goto err_flow_put; - flow->tbl_node.hash = flow_hash(&flow->key, key_len); + flow->hash = flow_hash(&flow->key, key_len); + + if (a[OVS_PACKET_ATTR_UPCALL_PID]) + flow->upcall_pid = nla_get_u32(a[OVS_PACKET_ATTR_UPCALL_PID]); + else + flow->upcall_pid = NETLINK_CB(skb).pid; acts = flow_actions_alloc(a[OVS_PACKET_ATTR_ACTIONS]); err = PTR_ERR(acts); @@ -707,6 +690,11 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) err = -ENODEV; if (!dp) goto err_unlock; + + if (flow->key.eth.in_port < DP_MAX_PORTS) + OVS_CB(packet)->vport = get_vport_protected(dp, + flow->key.eth.in_port); + err = execute_actions(dp, packet); rcu_read_unlock(); @@ -727,6 +715,7 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = { [OVS_PACKET_ATTR_PACKET] = { .type = NLA_UNSPEC }, [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED }, [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED }, + [OVS_PACKET_ATTR_UPCALL_PID] = { .type = NLA_U32 }, }; static struct genl_ops dp_packet_genl_ops[] = { @@ -740,9 +729,9 @@ static struct genl_ops dp_packet_genl_ops[] = { static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats) { int i; - struct tbl *table = get_table_protected(dp); + struct flow_table *table = get_table_protected(dp); - stats->n_flows = tbl_count(table); + stats->n_flows = flow_tbl_count(table); stats->n_frags = stats->n_hit = stats->n_missed = stats->n_lost = 0; for_each_possible_cpu(i) { @@ -764,54 +753,9 @@ static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats) } } -/* MTU of the dp pseudo-device: ETH_DATA_LEN or the minimum of the ports. - * Called with RTNL lock. - */ -int dp_min_mtu(const struct datapath *dp) -{ - struct vport *p; - int mtu = 0; - - ASSERT_RTNL(); - - list_for_each_entry (p, &dp->port_list, node) { - int dev_mtu; - - /* Skip any internal ports, since that's what we're trying to - * set. */ - if (is_internal_vport(p)) - continue; - - dev_mtu = vport_get_mtu(p); - if (!dev_mtu) - continue; - if (!mtu || dev_mtu < mtu) - mtu = dev_mtu; - } - - return mtu ? mtu : ETH_DATA_LEN; -} - -/* Sets the MTU of all datapath devices to the minimum of the ports - * Called with RTNL lock. - */ -void set_internal_devs_mtu(const struct datapath *dp) -{ - struct vport *p; - int mtu; - - ASSERT_RTNL(); - - mtu = dp_min_mtu(dp); - - list_for_each_entry (p, &dp->port_list, node) { - if (is_internal_vport(p)) - vport_set_mtu(p, mtu); - } -} - static const struct nla_policy flow_policy[OVS_FLOW_ATTR_MAX + 1] = { [OVS_FLOW_ATTR_KEY] = { .type = NLA_NESTED }, + [OVS_FLOW_ATTR_UPCALL_PID] = { .type = NLA_U32 }, [OVS_FLOW_ATTR_ACTIONS] = { .type = NLA_NESTED }, [OVS_FLOW_ATTR_CLEAR] = { .type = NLA_FLAG }, }; @@ -848,7 +792,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, if (!ovs_header) return -EMSGSIZE; - ovs_header->dp_ifindex = dp->dp_ifindex; + ovs_header->dp_ifindex = get_dpifindex(dp); nla = nla_nest_start(skb, OVS_FLOW_ATTR_KEY); if (!nla) @@ -858,6 +802,8 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp, goto error; nla_nest_end(skb, nla); + NLA_PUT_U32(skb, OVS_FLOW_ATTR_UPCALL_PID, flow->upcall_pid); + spin_lock_bh(&flow->lock); used = flow->used; stats.n_packets = flow->packet_count; @@ -933,13 +879,11 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) { struct nlattr **a = info->attrs; struct ovs_header *ovs_header = info->userhdr; - struct tbl_node *flow_node; struct sw_flow_key key; struct sw_flow *flow; struct sk_buff *reply; struct datapath *dp; - struct tbl *table; - u32 hash; + struct flow_table *table; int error; int key_len; @@ -966,10 +910,9 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) if (!dp) goto error; - hash = flow_hash(&key, key_len); table = get_table_protected(dp); - flow_node = tbl_lookup(table, &key, key_len, hash, flow_cmp); - if (!flow_node) { + flow = flow_tbl_lookup(table, &key, key_len); + if (!flow) { struct sw_flow_actions *acts; /* Bail out if we're not allowed to create a new flow. */ @@ -978,11 +921,15 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) goto error; /* Expand table, if necessary, to make room. */ - if (tbl_count(table) >= tbl_n_buckets(table)) { - error = expand_table(dp); - if (error) - goto error; - table = get_table_protected(dp); + if (flow_tbl_need_to_expand(table)) { + struct flow_table *new_table; + + new_table = flow_tbl_expand(table); + if (!IS_ERR(new_table)) { + rcu_assign_pointer(dp->table, new_table); + flow_tbl_deferred_destroy(table); + table = get_table_protected(dp); + } } /* Allocate flow. */ @@ -994,6 +941,11 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) flow->key = key; clear_stats(flow); + if (a[OVS_FLOW_ATTR_UPCALL_PID]) + flow->upcall_pid = nla_get_u32(a[OVS_FLOW_ATTR_UPCALL_PID]); + else + flow->upcall_pid = NETLINK_CB(skb).pid; + /* Obtain actions. */ acts = flow_actions_alloc(a[OVS_FLOW_ATTR_ACTIONS]); error = PTR_ERR(acts); @@ -1002,9 +954,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) rcu_assign_pointer(flow->sf_acts, acts); /* Put flow in bucket. */ - error = tbl_insert(table, &flow->tbl_node, hash); - if (error) - goto error_free_flow; + flow->hash = flow_hash(&key, key_len); + flow_tbl_insert(table, flow); reply = ovs_flow_cmd_build_info(flow, dp, info->snd_pid, info->snd_seq, OVS_FLOW_CMD_NEW); @@ -1024,7 +975,6 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) goto error; /* Update actions. */ - flow = flow_cast(flow_node); old_acts = rcu_dereference_protected(flow->sf_acts, lockdep_genl_is_held()); if (a[OVS_FLOW_ATTR_ACTIONS] && @@ -1045,6 +995,9 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) reply = ovs_flow_cmd_build_info(flow, dp, info->snd_pid, info->snd_seq, OVS_FLOW_CMD_NEW); + if (a[OVS_FLOW_ATTR_UPCALL_PID]) + flow->upcall_pid = nla_get_u32(a[OVS_FLOW_ATTR_UPCALL_PID]); + /* Clear stats. */ if (a[OVS_FLOW_ATTR_CLEAR]) { spin_lock_bh(&flow->lock); @@ -1072,11 +1025,10 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) struct nlattr **a = info->attrs; struct ovs_header *ovs_header = info->userhdr; struct sw_flow_key key; - struct tbl_node *flow_node; struct sk_buff *reply; struct sw_flow *flow; struct datapath *dp; - struct tbl *table; + struct flow_table *table; int err; int key_len; @@ -1091,12 +1043,10 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) return -ENODEV; table = get_table_protected(dp); - flow_node = tbl_lookup(table, &key, key_len, flow_hash(&key, key_len), - flow_cmp); - if (!flow_node) + flow = flow_tbl_lookup(table, &key, key_len); + if (!flow) return -ENOENT; - flow = flow_cast(flow_node); reply = ovs_flow_cmd_build_info(flow, dp, info->snd_pid, info->snd_seq, OVS_FLOW_CMD_NEW); if (IS_ERR(reply)) return PTR_ERR(reply); @@ -1109,11 +1059,10 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) struct nlattr **a = info->attrs; struct ovs_header *ovs_header = info->userhdr; struct sw_flow_key key; - struct tbl_node *flow_node; struct sk_buff *reply; struct sw_flow *flow; struct datapath *dp; - struct tbl *table; + struct flow_table *table; int err; int key_len; @@ -1128,21 +1077,15 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) return -ENODEV; table = get_table_protected(dp); - flow_node = tbl_lookup(table, &key, key_len, flow_hash(&key, key_len), - flow_cmp); - if (!flow_node) + flow = flow_tbl_lookup(table, &key, key_len); + if (!flow) return -ENOENT; - flow = flow_cast(flow_node); reply = ovs_flow_cmd_alloc_info(flow); if (!reply) return -ENOMEM; - err = tbl_remove(table, flow_node); - if (err) { - kfree_skb(reply); - return err; - } + flow_tbl_remove(table, flow); err = ovs_flow_cmd_fill_info(flow, dp, reply, info->snd_pid, info->snd_seq, 0, OVS_FLOW_CMD_DEL); @@ -1165,17 +1108,15 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb) return -ENODEV; for (;;) { - struct tbl_node *flow_node; struct sw_flow *flow; u32 bucket, obj; bucket = cb->args[0]; obj = cb->args[1]; - flow_node = tbl_next(get_table_protected(dp), &bucket, &obj); - if (!flow_node) + flow = flow_tbl_next(get_table_protected(dp), &bucket, &obj); + if (!flow) break; - flow = flow_cast(flow_node); if (ovs_flow_cmd_fill_info(flow, dp, skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLM_F_MULTI, OVS_FLOW_CMD_NEW) < 0) @@ -1215,6 +1156,7 @@ static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = { #ifdef HAVE_NLA_NUL_STRING [OVS_DP_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, #endif + [OVS_DP_ATTR_UPCALL_PID] = { .type = NLA_U32 }, [OVS_DP_ATTR_IPV4_FRAGS] = { .type = NLA_U32 }, [OVS_DP_ATTR_SAMPLING] = { .type = NLA_U32 }, }; @@ -1243,7 +1185,7 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb, if (!ovs_header) goto error; - ovs_header->dp_ifindex = dp->dp_ifindex; + ovs_header->dp_ifindex = get_dpifindex(dp); rcu_read_lock(); err = nla_put_string(skb, OVS_DP_ATTR_NAME, dp_name(dp)); @@ -1262,14 +1204,6 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb, if (dp->sflow_probability) NLA_PUT_U32(skb, OVS_DP_ATTR_SAMPLING, dp->sflow_probability); - nla = nla_nest_start(skb, OVS_DP_ATTR_MCGROUPS); - if (!nla) - goto nla_put_failure; - NLA_PUT_U32(skb, OVS_PACKET_CMD_MISS, packet_mc_group(dp, OVS_PACKET_CMD_MISS)); - NLA_PUT_U32(skb, OVS_PACKET_CMD_ACTION, packet_mc_group(dp, OVS_PACKET_CMD_ACTION)); - NLA_PUT_U32(skb, OVS_PACKET_CMD_SAMPLE, packet_mc_group(dp, OVS_PACKET_CMD_SAMPLE)); - nla_nest_end(skb, nla); - return genlmsg_end(skb, ovs_header); nla_put_failure: @@ -1370,35 +1304,39 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) /* Allocate table. */ err = -ENOMEM; - rcu_assign_pointer(dp->table, tbl_create(TBL_MIN_BUCKETS)); + rcu_assign_pointer(dp->table, flow_tbl_alloc(TBL_MIN_BUCKETS)); if (!dp->table) goto err_free_dp; + dp->drop_frags = 0; + dp->stats_percpu = alloc_percpu(struct dp_stats_percpu); + if (!dp->stats_percpu) { + err = -ENOMEM; + goto err_destroy_table; + } + + change_datapath(dp, a); + /* Set up our datapath device. */ parms.name = nla_data(a[OVS_DP_ATTR_NAME]); parms.type = OVS_VPORT_TYPE_INTERNAL; parms.options = NULL; parms.dp = dp; parms.port_no = OVSP_LOCAL; + if (a[OVS_DP_ATTR_UPCALL_PID]) + parms.upcall_pid = nla_get_u32(a[OVS_DP_ATTR_UPCALL_PID]); + else + parms.upcall_pid = NETLINK_CB(skb).pid; + vport = new_vport(&parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); if (err == -EBUSY) err = -EEXIST; - goto err_destroy_table; - } - dp->dp_ifindex = vport_get_ifindex(vport); - - dp->drop_frags = 0; - dp->stats_percpu = alloc_percpu(struct dp_stats_percpu); - if (!dp->stats_percpu) { - err = -ENOMEM; - goto err_destroy_local_port; + goto err_destroy_percpu; } - change_datapath(dp, a); - reply = ovs_dp_cmd_build_info(dp, info->snd_pid, info->snd_seq, OVS_DP_CMD_NEW); err = PTR_ERR(reply); if (IS_ERR(reply)) @@ -1415,8 +1353,10 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info) err_destroy_local_port: dp_detach_port(get_vport_protected(dp, OVSP_LOCAL)); +err_destroy_percpu: + free_percpu(dp->stats_percpu); err_destroy_table: - tbl_destroy(get_table_protected(dp), NULL); + flow_tbl_destroy(get_table_protected(dp)); err_free_dp: kfree(dp); err_put_module: @@ -1576,15 +1516,15 @@ static struct genl_ops dp_datapath_genl_ops[] = { static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = { #ifdef HAVE_NLA_NUL_STRING [OVS_VPORT_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, - [OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 }, - [OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 }, - [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct rtnl_link_stats64) }, + [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) }, [OVS_VPORT_ATTR_ADDRESS] = { .len = ETH_ALEN }, #else - [OVS_VPORT_ATTR_STATS] = { .minlen = sizeof(struct rtnl_link_stats64) }, + [OVS_VPORT_ATTR_STATS] = { .minlen = sizeof(struct ovs_vport_stats) }, [OVS_VPORT_ATTR_ADDRESS] = { .minlen = ETH_ALEN }, #endif - [OVS_VPORT_ATTR_MTU] = { .type = NLA_U32 }, + [OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 }, + [OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 }, + [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_U32 }, [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, }; @@ -1607,7 +1547,6 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, struct ovs_header *ovs_header; struct nlattr *nla; int ifindex; - int mtu; int err; ovs_header = genlmsg_put(skb, pid, seq, &dp_vport_genl_family, @@ -1615,23 +1554,20 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, if (!ovs_header) return -EMSGSIZE; - ovs_header->dp_ifindex = vport->dp->dp_ifindex; + ovs_header->dp_ifindex = get_dpifindex(vport->dp); NLA_PUT_U32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no); NLA_PUT_U32(skb, OVS_VPORT_ATTR_TYPE, vport_get_type(vport)); NLA_PUT_STRING(skb, OVS_VPORT_ATTR_NAME, vport_get_name(vport)); + NLA_PUT_U32(skb, OVS_VPORT_ATTR_UPCALL_PID, vport->upcall_pid); - nla = nla_reserve(skb, OVS_VPORT_ATTR_STATS, sizeof(struct rtnl_link_stats64)); + nla = nla_reserve(skb, OVS_VPORT_ATTR_STATS, sizeof(struct ovs_vport_stats)); if (!nla) goto nla_put_failure; - if (vport_get_stats(vport, nla_data(nla))) - __skb_trim(skb, skb->len - nla->nla_len); - NLA_PUT(skb, OVS_VPORT_ATTR_ADDRESS, ETH_ALEN, vport_get_addr(vport)); + vport_get_stats(vport, nla_data(nla)); - mtu = vport_get_mtu(vport); - if (mtu) - NLA_PUT_U32(skb, OVS_VPORT_ATTR_MTU, mtu); + NLA_PUT(skb, OVS_VPORT_ATTR_ADDRESS, ETH_ALEN, vport_get_addr(vport)); err = vport_get_options(vport, skb); if (err == -EMSGSIZE) @@ -1708,12 +1644,13 @@ static struct vport *lookup_vport(struct ovs_header *ovs_header, static int change_vport(struct vport *vport, struct nlattr *a[OVS_VPORT_ATTR_MAX + 1]) { int err = 0; + if (a[OVS_VPORT_ATTR_STATS]) - err = vport_set_stats(vport, nla_data(a[OVS_VPORT_ATTR_STATS])); - if (!err && a[OVS_VPORT_ATTR_ADDRESS]) + vport_set_stats(vport, nla_data(a[OVS_VPORT_ATTR_STATS])); + + if (a[OVS_VPORT_ATTR_ADDRESS]) err = vport_set_addr(vport, nla_data(a[OVS_VPORT_ATTR_ADDRESS])); - if (!err && a[OVS_VPORT_ATTR_MTU]) - err = vport_set_mtu(vport, nla_get_u32(a[OVS_VPORT_ATTR_MTU])); + return err; } @@ -1770,13 +1707,16 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info) parms.options = a[OVS_VPORT_ATTR_OPTIONS]; parms.dp = dp; parms.port_no = port_no; + if (a[OVS_VPORT_ATTR_UPCALL_PID]) + parms.upcall_pid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]); + else + parms.upcall_pid = NETLINK_CB(skb).pid; vport = new_vport(&parms); err = PTR_ERR(vport); if (IS_ERR(vport)) goto exit_unlock; - set_internal_devs_mtu(dp); dp_sysfs_add_if(vport); err = change_vport(vport, a); @@ -1822,6 +1762,8 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info) err = vport_set_options(vport, a[OVS_VPORT_ATTR_OPTIONS]); if (!err) err = change_vport(vport, a); + if (!err && a[OVS_VPORT_ATTR_UPCALL_PID]) + vport->upcall_pid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]); reply = ovs_vport_cmd_build_info(vport, info->snd_pid, info->snd_seq, OVS_VPORT_CMD_NEW); @@ -1869,7 +1811,7 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info) if (IS_ERR(reply)) goto exit_unlock; - err = dp_detach_port(vport); + dp_detach_port(vport); genl_notify(reply, genl_info_net(info), info->snd_pid, dp_vport_multicast_group.id, info->nlhdr, GFP_KERNEL); @@ -2023,9 +1965,6 @@ static int dp_register_genl(void) } } - err = packet_register_mc_groups(); - if (err) - goto error; return 0; error: @@ -2042,10 +1981,14 @@ static int __init dp_init(void) printk("Open vSwitch %s, built "__DATE__" "__TIME__"\n", VERSION BUILDNR); - err = flow_init(); + err = tnl_init(); if (err) goto error; + err = flow_init(); + if (err) + goto error_tnl_exit; + err = vport_init(); if (err) goto error_flow_exit; @@ -2066,6 +2009,8 @@ error_vport_exit: vport_exit(); error_flow_exit: flow_exit(); +error_tnl_exit: + tnl_exit(); error: return err; } @@ -2077,6 +2022,7 @@ static void dp_cleanup(void) unregister_netdevice_notifier(&dp_device_notifier); vport_exit(); flow_exit(); + tnl_exit(); } module_init(dp_init);