Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
cefd81cf
Commit
cefd81cf
authored
Sep 04, 2012
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
git://git.kernel.org/pub/scm/linux/kernel/git/jesse/openvswitch
parents
3731a334
15eac2a7
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
317 additions
and
171 deletions
+317
-171
net/openvswitch/actions.c
net/openvswitch/actions.c
+1
-1
net/openvswitch/datapath.c
net/openvswitch/datapath.c
+237
-138
net/openvswitch/datapath.h
net/openvswitch/datapath.h
+42
-8
net/openvswitch/dp_notify.c
net/openvswitch/dp_notify.c
+5
-3
net/openvswitch/flow.c
net/openvswitch/flow.c
+4
-7
net/openvswitch/flow.h
net/openvswitch/flow.h
+2
-1
net/openvswitch/vport-internal_dev.c
net/openvswitch/vport-internal_dev.c
+6
-1
net/openvswitch/vport-netdev.c
net/openvswitch/vport-netdev.c
+1
-1
net/openvswitch/vport.c
net/openvswitch/vport.c
+15
-8
net/openvswitch/vport.h
net/openvswitch/vport.h
+4
-3
No files found.
net/openvswitch/actions.c
View file @
cefd81cf
...
...
@@ -266,7 +266,7 @@ static int do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
if
(
unlikely
(
!
skb
))
return
-
ENOMEM
;
vport
=
rcu_dereference
(
dp
->
ports
[
out_port
]
);
vport
=
ovs_vport_rcu
(
dp
,
out_port
);
if
(
unlikely
(
!
vport
))
{
kfree_skb
(
skb
);
return
-
ENODEV
;
...
...
net/openvswitch/datapath.c
View file @
cefd81cf
...
...
@@ -49,11 +49,28 @@
#include <linux/dmi.h>
#include <linux/workqueue.h>
#include <net/genetlink.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include "datapath.h"
#include "flow.h"
#include "vport-internal_dev.h"
/**
* struct ovs_net - Per net-namespace data for ovs.
* @dps: List of datapaths to enable dumping them all out.
* Protected by genl_mutex.
*/
struct
ovs_net
{
struct
list_head
dps
;
};
static
int
ovs_net_id
__read_mostly
;
#define REHASH_FLOW_INTERVAL (10 * 60 * HZ)
static
void
rehash_flow_table
(
struct
work_struct
*
work
);
static
DECLARE_DELAYED_WORK
(
rehash_flow_wq
,
rehash_flow_table
);
/**
* DOC: Locking:
*
...
...
@@ -71,29 +88,21 @@
* each other.
*/
/* Global list of datapaths to enable dumping them all out.
* Protected by genl_mutex.
*/
static
LIST_HEAD
(
dps
);
#define REHASH_FLOW_INTERVAL (10 * 60 * HZ)
static
void
rehash_flow_table
(
struct
work_struct
*
work
);
static
DECLARE_DELAYED_WORK
(
rehash_flow_wq
,
rehash_flow_table
);
static
struct
vport
*
new_vport
(
const
struct
vport_parms
*
);
static
int
queue_gso_packets
(
int
dp_ifindex
,
struct
sk_buff
*
,
static
int
queue_gso_packets
(
struct
net
*
,
int
dp_ifindex
,
struct
sk_buff
*
,
const
struct
dp_upcall_info
*
);
static
int
queue_userspace_packet
(
int
dp_ifindex
,
struct
sk_buff
*
,
static
int
queue_userspace_packet
(
struct
net
*
,
int
dp_ifindex
,
struct
sk_buff
*
,
const
struct
dp_upcall_info
*
);
/* Must be called with rcu_read_lock, genl_mutex, or RTNL lock. */
static
struct
datapath
*
get_dp
(
int
dp_ifindex
)
static
struct
datapath
*
get_dp
(
struct
net
*
net
,
int
dp_ifindex
)
{
struct
datapath
*
dp
=
NULL
;
struct
net_device
*
dev
;
rcu_read_lock
();
dev
=
dev_get_by_index_rcu
(
&
init_
net
,
dp_ifindex
);
dev
=
dev_get_by_index_rcu
(
net
,
dp_ifindex
);
if
(
dev
)
{
struct
vport
*
vport
=
ovs_internal_dev_get_vport
(
dev
);
if
(
vport
)
...
...
@@ -107,7 +116,7 @@ static struct datapath *get_dp(int dp_ifindex)
/* Must be called with rcu_read_lock or RTNL lock. */
const
char
*
ovs_dp_name
(
const
struct
datapath
*
dp
)
{
struct
vport
*
vport
=
rcu_dereference_rtnl
(
dp
->
ports
[
OVSP_LOCAL
]
);
struct
vport
*
vport
=
ovs_vport_rtnl_rcu
(
dp
,
OVSP_LOCAL
);
return
vport
->
ops
->
get_name
(
vport
);
}
...
...
@@ -118,7 +127,7 @@ static int get_dpifindex(struct datapath *dp)
rcu_read_lock
();
local
=
rcu_dereference
(
dp
->
ports
[
OVSP_LOCAL
]
);
local
=
ovs_vport_rcu
(
dp
,
OVSP_LOCAL
);
if
(
local
)
ifindex
=
local
->
ops
->
get_ifindex
(
local
);
else
...
...
@@ -135,9 +144,31 @@ static void destroy_dp_rcu(struct rcu_head *rcu)
ovs_flow_tbl_destroy
((
__force
struct
flow_table
*
)
dp
->
table
);
free_percpu
(
dp
->
stats_percpu
);
release_net
(
ovs_dp_get_net
(
dp
));
kfree
(
dp
->
ports
);
kfree
(
dp
);
}
static
struct
hlist_head
*
vport_hash_bucket
(
const
struct
datapath
*
dp
,
u16
port_no
)
{
return
&
dp
->
ports
[
port_no
&
(
DP_VPORT_HASH_BUCKETS
-
1
)];
}
struct
vport
*
ovs_lookup_vport
(
const
struct
datapath
*
dp
,
u16
port_no
)
{
struct
vport
*
vport
;
struct
hlist_node
*
n
;
struct
hlist_head
*
head
;
head
=
vport_hash_bucket
(
dp
,
port_no
);
hlist_for_each_entry_rcu
(
vport
,
n
,
head
,
dp_hash_node
)
{
if
(
vport
->
port_no
==
port_no
)
return
vport
;
}
return
NULL
;
}
/* Called with RTNL lock and genl_lock. */
static
struct
vport
*
new_vport
(
const
struct
vport_parms
*
parms
)
{
...
...
@@ -146,9 +177,9 @@ static struct vport *new_vport(const struct vport_parms *parms)
vport
=
ovs_vport_add
(
parms
);
if
(
!
IS_ERR
(
vport
))
{
struct
datapath
*
dp
=
parms
->
dp
;
struct
hlist_head
*
head
=
vport_hash_bucket
(
dp
,
vport
->
port_no
);
rcu_assign_pointer
(
dp
->
ports
[
parms
->
port_no
],
vport
);
list_add
(
&
vport
->
node
,
&
dp
->
port_list
);
hlist_add_head_rcu
(
&
vport
->
dp_hash_node
,
head
);
}
return
vport
;
...
...
@@ -160,8 +191,7 @@ void ovs_dp_detach_port(struct vport *p)
ASSERT_RTNL
();
/* First drop references to device. */
list_del
(
&
p
->
node
);
rcu_assign_pointer
(
p
->
dp
->
ports
[
p
->
port_no
],
NULL
);
hlist_del_rcu
(
&
p
->
dp_hash_node
);
/* Then destroy it. */
ovs_vport_del
(
p
);
...
...
@@ -220,11 +250,12 @@ static struct genl_family dp_packet_genl_family = {
.
hdrsize
=
sizeof
(
struct
ovs_header
),
.
name
=
OVS_PACKET_FAMILY
,
.
version
=
OVS_PACKET_VERSION
,
.
maxattr
=
OVS_PACKET_ATTR_MAX
.
maxattr
=
OVS_PACKET_ATTR_MAX
,
.
netnsok
=
true
};
int
ovs_dp_upcall
(
struct
datapath
*
dp
,
struct
sk_buff
*
skb
,
const
struct
dp_upcall_info
*
upcall_info
)
const
struct
dp_upcall_info
*
upcall_info
)
{
struct
dp_stats_percpu
*
stats
;
int
dp_ifindex
;
...
...
@@ -242,9 +273,9 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
}
if
(
!
skb_is_gso
(
skb
))
err
=
queue_userspace_packet
(
dp_ifindex
,
skb
,
upcall_info
);
err
=
queue_userspace_packet
(
ovs_dp_get_net
(
dp
),
dp_ifindex
,
skb
,
upcall_info
);
else
err
=
queue_gso_packets
(
dp_ifindex
,
skb
,
upcall_info
);
err
=
queue_gso_packets
(
ovs_dp_get_net
(
dp
),
dp_ifindex
,
skb
,
upcall_info
);
if
(
err
)
goto
err
;
...
...
@@ -260,7 +291,8 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
return
err
;
}
static
int
queue_gso_packets
(
int
dp_ifindex
,
struct
sk_buff
*
skb
,
static
int
queue_gso_packets
(
struct
net
*
net
,
int
dp_ifindex
,
struct
sk_buff
*
skb
,
const
struct
dp_upcall_info
*
upcall_info
)
{
unsigned
short
gso_type
=
skb_shinfo
(
skb
)
->
gso_type
;
...
...
@@ -276,7 +308,7 @@ static int queue_gso_packets(int dp_ifindex, struct sk_buff *skb,
/* Queue all of the segments. */
skb
=
segs
;
do
{
err
=
queue_userspace_packet
(
dp_ifindex
,
skb
,
upcall_info
);
err
=
queue_userspace_packet
(
net
,
dp_ifindex
,
skb
,
upcall_info
);
if
(
err
)
break
;
...
...
@@ -306,7 +338,8 @@ static int queue_gso_packets(int dp_ifindex, struct sk_buff *skb,
return
err
;
}
static
int
queue_userspace_packet
(
int
dp_ifindex
,
struct
sk_buff
*
skb
,
static
int
queue_userspace_packet
(
struct
net
*
net
,
int
dp_ifindex
,
struct
sk_buff
*
skb
,
const
struct
dp_upcall_info
*
upcall_info
)
{
struct
ovs_header
*
upcall
;
...
...
@@ -362,7 +395,7 @@ static int queue_userspace_packet(int dp_ifindex, struct sk_buff *skb,
skb_copy_and_csum_dev
(
skb
,
nla_data
(
nla
));
err
=
genlmsg_unicast
(
&
init_
net
,
user_skb
,
upcall_info
->
pid
);
err
=
genlmsg_unicast
(
net
,
user_skb
,
upcall_info
->
pid
);
out:
kfree_skb
(
nskb
);
...
...
@@ -370,15 +403,10 @@ static int queue_userspace_packet(int dp_ifindex, struct sk_buff *skb,
}
/* Called with genl_mutex. */
static
int
flush_flows
(
int
dp_ifindex
)
static
int
flush_flows
(
struct
datapath
*
dp
)
{
struct
flow_table
*
old_table
;
struct
flow_table
*
new_table
;
struct
datapath
*
dp
;
dp
=
get_dp
(
dp_ifindex
);
if
(
!
dp
)
return
-
ENODEV
;
old_table
=
genl_dereference
(
dp
->
table
);
new_table
=
ovs_flow_tbl_alloc
(
TBL_MIN_BUCKETS
);
...
...
@@ -668,7 +696,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
packet
->
priority
=
flow
->
key
.
phy
.
priority
;
rcu_read_lock
();
dp
=
get_dp
(
ovs_header
->
dp_ifindex
);
dp
=
get_dp
(
sock_net
(
skb
->
sk
),
ovs_header
->
dp_ifindex
);
err
=
-
ENODEV
;
if
(
!
dp
)
goto
err_unlock
;
...
...
@@ -742,7 +770,8 @@ static struct genl_family dp_flow_genl_family = {
.
hdrsize
=
sizeof
(
struct
ovs_header
),
.
name
=
OVS_FLOW_FAMILY
,
.
version
=
OVS_FLOW_VERSION
,
.
maxattr
=
OVS_FLOW_ATTR_MAX
.
maxattr
=
OVS_FLOW_ATTR_MAX
,
.
netnsok
=
true
};
static
struct
genl_multicast_group
ovs_dp_flow_multicast_group
=
{
...
...
@@ -894,7 +923,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
goto
error
;
}
dp
=
get_dp
(
ovs_header
->
dp_ifindex
);
dp
=
get_dp
(
sock_net
(
skb
->
sk
),
ovs_header
->
dp_ifindex
);
error
=
-
ENODEV
;
if
(
!
dp
)
goto
error
;
...
...
@@ -995,7 +1024,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
ovs_dp_flow_multicast_group
.
id
,
info
->
nlhdr
,
GFP_KERNEL
);
else
netlink_set_err
(
init_net
.
genl_sock
,
0
,
netlink_set_err
(
sock_net
(
skb
->
sk
)
->
genl_sock
,
0
,
ovs_dp_flow_multicast_group
.
id
,
PTR_ERR
(
reply
));
return
0
;
...
...
@@ -1023,7 +1052,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
if
(
err
)
return
err
;
dp
=
get_dp
(
ovs_header
->
dp_ifindex
);
dp
=
get_dp
(
sock_net
(
skb
->
sk
),
ovs_header
->
dp_ifindex
);
if
(
!
dp
)
return
-
ENODEV
;
...
...
@@ -1052,16 +1081,17 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
int
err
;
int
key_len
;
dp
=
get_dp
(
sock_net
(
skb
->
sk
),
ovs_header
->
dp_ifindex
);
if
(
!
dp
)
return
-
ENODEV
;
if
(
!
a
[
OVS_FLOW_ATTR_KEY
])
return
flush_flows
(
ovs_header
->
dp_ifindex
);
return
flush_flows
(
dp
);
err
=
ovs_flow_from_nlattrs
(
&
key
,
&
key_len
,
a
[
OVS_FLOW_ATTR_KEY
]);
if
(
err
)
return
err
;
dp
=
get_dp
(
ovs_header
->
dp_ifindex
);
if
(
!
dp
)
return
-
ENODEV
;
table
=
genl_dereference
(
dp
->
table
);
flow
=
ovs_flow_tbl_lookup
(
table
,
&
key
,
key_len
);
if
(
!
flow
)
...
...
@@ -1090,7 +1120,7 @@ static int ovs_flow_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
struct
datapath
*
dp
;
struct
flow_table
*
table
;
dp
=
get_dp
(
ovs_header
->
dp_ifindex
);
dp
=
get_dp
(
sock_net
(
skb
->
sk
),
ovs_header
->
dp_ifindex
);
if
(
!
dp
)
return
-
ENODEV
;
...
...
@@ -1152,7 +1182,8 @@ static struct genl_family dp_datapath_genl_family = {
.
hdrsize
=
sizeof
(
struct
ovs_header
),
.
name
=
OVS_DATAPATH_FAMILY
,
.
version
=
OVS_DATAPATH_VERSION
,
.
maxattr
=
OVS_DP_ATTR_MAX
.
maxattr
=
OVS_DP_ATTR_MAX
,
.
netnsok
=
true
};
static
struct
genl_multicast_group
ovs_dp_datapath_multicast_group
=
{
...
...
@@ -1210,18 +1241,19 @@ static struct sk_buff *ovs_dp_cmd_build_info(struct datapath *dp, u32 pid,
}
/* Called with genl_mutex and optionally with RTNL lock also. */
static
struct
datapath
*
lookup_datapath
(
struct
ovs_header
*
ovs_header
,
static
struct
datapath
*
lookup_datapath
(
struct
net
*
net
,
struct
ovs_header
*
ovs_header
,
struct
nlattr
*
a
[
OVS_DP_ATTR_MAX
+
1
])
{
struct
datapath
*
dp
;
if
(
!
a
[
OVS_DP_ATTR_NAME
])
dp
=
get_dp
(
ovs_header
->
dp_ifindex
);
dp
=
get_dp
(
net
,
ovs_header
->
dp_ifindex
);
else
{
struct
vport
*
vport
;
rcu_read_lock
();
vport
=
ovs_vport_locate
(
nla_data
(
a
[
OVS_DP_ATTR_NAME
]));
vport
=
ovs_vport_locate
(
n
et
,
n
la_data
(
a
[
OVS_DP_ATTR_NAME
]));
dp
=
vport
&&
vport
->
port_no
==
OVSP_LOCAL
?
vport
->
dp
:
NULL
;
rcu_read_unlock
();
}
...
...
@@ -1235,22 +1267,21 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
struct
sk_buff
*
reply
;
struct
datapath
*
dp
;
struct
vport
*
vport
;
int
err
;
struct
ovs_net
*
ovs_net
;
int
err
,
i
;
err
=
-
EINVAL
;
if
(
!
a
[
OVS_DP_ATTR_NAME
]
||
!
a
[
OVS_DP_ATTR_UPCALL_PID
])
goto
err
;
rtnl_lock
();
err
=
-
ENODEV
;
if
(
!
try_module_get
(
THIS_MODULE
))
goto
err_unlock_rtnl
;
err
=
-
ENOMEM
;
dp
=
kzalloc
(
sizeof
(
*
dp
),
GFP_KERNEL
);
if
(
dp
==
NULL
)
goto
err_put_module
;
INIT_LIST_HEAD
(
&
dp
->
port_list
);
goto
err_unlock_rtnl
;
ovs_dp_set_net
(
dp
,
hold_net
(
sock_net
(
skb
->
sk
)));
/* Allocate table. */
err
=
-
ENOMEM
;
...
...
@@ -1264,6 +1295,16 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
goto
err_destroy_table
;
}
dp
->
ports
=
kmalloc
(
DP_VPORT_HASH_BUCKETS
*
sizeof
(
struct
hlist_head
),
GFP_KERNEL
);
if
(
!
dp
->
ports
)
{
err
=
-
ENOMEM
;
goto
err_destroy_percpu
;
}
for
(
i
=
0
;
i
<
DP_VPORT_HASH_BUCKETS
;
i
++
)
INIT_HLIST_HEAD
(
&
dp
->
ports
[
i
]);
/* Set up our datapath device. */
parms
.
name
=
nla_data
(
a
[
OVS_DP_ATTR_NAME
]);
parms
.
type
=
OVS_VPORT_TYPE_INTERNAL
;
...
...
@@ -1278,7 +1319,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
if
(
err
==
-
EBUSY
)
err
=
-
EEXIST
;
goto
err_destroy_p
ercpu
;
goto
err_destroy_p
orts_array
;
}
reply
=
ovs_dp_cmd_build_info
(
dp
,
info
->
snd_pid
,
...
...
@@ -1287,7 +1328,8 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
if
(
IS_ERR
(
reply
))
goto
err_destroy_local_port
;
list_add_tail
(
&
dp
->
list_node
,
&
dps
);
ovs_net
=
net_generic
(
ovs_dp_get_net
(
dp
),
ovs_net_id
);
list_add_tail
(
&
dp
->
list_node
,
&
ovs_net
->
dps
);
rtnl_unlock
();
genl_notify
(
reply
,
genl_info_net
(
info
),
info
->
snd_pid
,
...
...
@@ -1296,46 +1338,40 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
return
0
;
err_destroy_local_port:
ovs_dp_detach_port
(
rtnl_dereference
(
dp
->
ports
[
OVSP_LOCAL
]));
ovs_dp_detach_port
(
ovs_vport_rtnl
(
dp
,
OVSP_LOCAL
));
err_destroy_ports_array:
kfree
(
dp
->
ports
);
err_destroy_percpu:
free_percpu
(
dp
->
stats_percpu
);
err_destroy_table:
ovs_flow_tbl_destroy
(
genl_dereference
(
dp
->
table
));
err_free_dp:
release_net
(
ovs_dp_get_net
(
dp
));
kfree
(
dp
);
err_put_module:
module_put
(
THIS_MODULE
);
err_unlock_rtnl:
rtnl_unlock
();
err:
return
err
;
}
static
int
ovs_dp_cmd_del
(
struct
sk_buff
*
skb
,
struct
genl_info
*
info
)
/* Called with genl_mutex. */
static
void
__dp_destroy
(
struct
datapath
*
dp
)
{
struct
vport
*
vport
,
*
next_vport
;
struct
sk_buff
*
reply
;
struct
datapath
*
dp
;
int
err
;
int
i
;
rtnl_lock
();
dp
=
lookup_datapath
(
info
->
userhdr
,
info
->
attrs
);
err
=
PTR_ERR
(
dp
);
if
(
IS_ERR
(
dp
))
goto
exit_unlock
;
reply
=
ovs_dp_cmd_build_info
(
dp
,
info
->
snd_pid
,
info
->
snd_seq
,
OVS_DP_CMD_DEL
);
err
=
PTR_ERR
(
reply
);
if
(
IS_ERR
(
reply
))
goto
exit_unlock
;
for
(
i
=
0
;
i
<
DP_VPORT_HASH_BUCKETS
;
i
++
)
{
struct
vport
*
vport
;
struct
hlist_node
*
node
,
*
n
;
list_for_each_entry_safe
(
vport
,
next_vport
,
&
dp
->
port_list
,
node
)
if
(
vport
->
port_no
!=
OVSP_LOCAL
)
ovs_dp_detach_port
(
vport
);
hlist_for_each_entry_safe
(
vport
,
node
,
n
,
&
dp
->
ports
[
i
],
dp_hash_node
)
if
(
vport
->
port_no
!=
OVSP_LOCAL
)
ovs_dp_detach_port
(
vport
);
}
list_del
(
&
dp
->
list_node
);
ovs_dp_detach_port
(
rtnl_dereference
(
dp
->
ports
[
OVSP_LOCAL
]
));
ovs_dp_detach_port
(
ovs_vport_rtnl
(
dp
,
OVSP_LOCAL
));
/* rtnl_unlock() will wait until all the references to devices that
* are pending unregistration have been dropped. We do it here to
...
...
@@ -1345,17 +1381,32 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
rtnl_unlock
();
call_rcu
(
&
dp
->
rcu
,
destroy_dp_rcu
);
module_put
(
THIS_MODULE
);
}
static
int
ovs_dp_cmd_del
(
struct
sk_buff
*
skb
,
struct
genl_info
*
info
)
{
struct
sk_buff
*
reply
;
struct
datapath
*
dp
;
int
err
;
dp
=
lookup_datapath
(
sock_net
(
skb
->
sk
),
info
->
userhdr
,
info
->
attrs
);
err
=
PTR_ERR
(
dp
);
if
(
IS_ERR
(
dp
))
return
err
;
reply
=
ovs_dp_cmd_build_info
(
dp
,
info
->
snd_pid
,
info
->
snd_seq
,
OVS_DP_CMD_DEL
);
err
=
PTR_ERR
(
reply
);
if
(
IS_ERR
(
reply
))
return
err
;
__dp_destroy
(
dp
);
genl_notify
(
reply
,
genl_info_net
(
info
),
info
->
snd_pid
,
ovs_dp_datapath_multicast_group
.
id
,
info
->
nlhdr
,
GFP_KERNEL
);
return
0
;
exit_unlock:
rtnl_unlock
();
return
err
;
}
static
int
ovs_dp_cmd_set
(
struct
sk_buff
*
skb
,
struct
genl_info
*
info
)
...
...
@@ -1364,7 +1415,7 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
struct
datapath
*
dp
;
int
err
;
dp
=
lookup_datapath
(
info
->
userhdr
,
info
->
attrs
);
dp
=
lookup_datapath
(
sock_net
(
skb
->
sk
),
info
->
userhdr
,
info
->
attrs
);
if
(
IS_ERR
(
dp
))
return
PTR_ERR
(
dp
);
...
...
@@ -1372,7 +1423,7 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
info
->
snd_seq
,
OVS_DP_CMD_NEW
);
if
(
IS_ERR
(
reply
))
{
err
=
PTR_ERR
(
reply
);
netlink_set_err
(
init_net
.
genl_sock
,
0
,
netlink_set_err
(
sock_net
(
skb
->
sk
)
->
genl_sock
,
0
,
ovs_dp_datapath_multicast_group
.
id
,
err
);
return
0
;
}
...
...
@@ -1389,7 +1440,7 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
struct
sk_buff
*
reply
;
struct
datapath
*
dp
;
dp
=
lookup_datapath
(
info
->
userhdr
,
info
->
attrs
);
dp
=
lookup_datapath
(
sock_net
(
skb
->
sk
),
info
->
userhdr
,
info
->
attrs
);
if
(
IS_ERR
(
dp
))
return
PTR_ERR
(
dp
);
...
...
@@ -1403,11 +1454,12 @@ static int ovs_dp_cmd_get(struct sk_buff *skb, struct genl_info *info)
static
int
ovs_dp_cmd_dump
(
struct
sk_buff
*
skb
,
struct
netlink_callback
*
cb
)
{
struct
ovs_net
*
ovs_net
=
net_generic
(
sock_net
(
skb
->
sk
),
ovs_net_id
);
struct
datapath
*
dp
;
int
skip
=
cb
->
args
[
0
];
int
i
=
0
;
list_for_each_entry
(
dp
,
&
dps
,
list_node
)
{
list_for_each_entry
(
dp
,
&
ovs_net
->
dps
,
list_node
)
{
if
(
i
>=
skip
&&
ovs_dp_cmd_fill_info
(
dp
,
skb
,
NETLINK_CB
(
cb
->
skb
).
pid
,
cb
->
nlh
->
nlmsg_seq
,
NLM_F_MULTI
,
...
...
@@ -1459,7 +1511,8 @@ static struct genl_family dp_vport_genl_family = {
.
hdrsize
=
sizeof
(
struct
ovs_header
),
.
name
=
OVS_VPORT_FAMILY
,
.
version
=
OVS_VPORT_VERSION
,
.
maxattr
=
OVS_VPORT_ATTR_MAX
.
maxattr
=
OVS_VPORT_ATTR_MAX
,
.
netnsok
=
true
};
struct
genl_multicast_group
ovs_dp_vport_multicast_group
=
{
...
...
@@ -1525,14 +1578,15 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 pid,
}
/* Called with RTNL lock or RCU read lock. */
static
struct
vport
*
lookup_vport
(
struct
ovs_header
*
ovs_header
,
static
struct
vport
*
lookup_vport
(
struct
net
*
net
,
struct
ovs_header
*
ovs_header
,
struct
nlattr
*
a
[
OVS_VPORT_ATTR_MAX
+
1
])
{
struct
datapath
*
dp
;
struct
vport
*
vport
;
if
(
a
[
OVS_VPORT_ATTR_NAME
])
{
vport
=
ovs_vport_locate
(
nla_data
(
a
[
OVS_VPORT_ATTR_NAME
]));
vport
=
ovs_vport_locate
(
n
et
,
n
la_data
(
a
[
OVS_VPORT_ATTR_NAME
]));
if
(
!
vport
)
return
ERR_PTR
(
-
ENODEV
);
if
(
ovs_header
->
dp_ifindex
&&
...
...
@@ -1545,11 +1599,11 @@ static struct vport *lookup_vport(struct ovs_header *ovs_header,
if
(
port_no
>=
DP_MAX_PORTS
)
return
ERR_PTR
(
-
EFBIG
);
dp
=
get_dp
(
ovs_header
->
dp_ifindex
);
dp
=
get_dp
(
net
,
ovs_header
->
dp_ifindex
);
if
(
!
dp
)
return
ERR_PTR
(
-
ENODEV
);
vport
=
rcu_dereference_rtnl
(
dp
->
ports
[
port_no
]
);
vport
=
ovs_vport_rtnl_rcu
(
dp
,
port_no
);
if
(
!
vport
)
return
ERR_PTR
(
-
ENOENT
);
return
vport
;
...
...
@@ -1574,7 +1628,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
goto
exit
;
rtnl_lock
();
dp
=
get_dp
(
ovs_header
->
dp_ifindex
);
dp
=
get_dp
(
sock_net
(
skb
->
sk
),
ovs_header
->
dp_ifindex
);
err
=
-
ENODEV
;
if
(
!
dp
)
goto
exit_unlock
;
...
...
@@ -1586,7 +1640,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
if
(
port_no
>=
DP_MAX_PORTS
)
goto
exit_unlock
;
vport
=
rtnl_dereference
(
dp
->
ports
[
port_no
]
);
vport
=
ovs_vport_rtnl_rcu
(
dp
,
port_no
);
err
=
-
EBUSY
;
if
(
vport
)
goto
exit_unlock
;
...
...
@@ -1596,7 +1650,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
err
=
-
EFBIG
;
goto
exit_unlock
;
}
vport
=
rtnl_dereference
(
dp
->
ports
[
port_no
]
);
vport
=
ovs_vport_rtnl
(
dp
,
port_no
);
if
(
!
vport
)
break
;
}
...
...
@@ -1638,7 +1692,7 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
int
err
;
rtnl_lock
();
vport
=
lookup_vport
(
info
->
userhdr
,
a
);
vport
=
lookup_vport
(
sock_net
(
skb
->
sk
),
info
->
userhdr
,
a
);
err
=
PTR_ERR
(
vport
);
if
(
IS_ERR
(
vport
))
goto
exit_unlock
;
...
...
@@ -1658,7 +1712,7 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
reply
=
ovs_vport_cmd_build_info
(
vport
,
info
->
snd_pid
,
info
->
snd_seq
,
OVS_VPORT_CMD_NEW
);
if
(
IS_ERR
(
reply
))
{
netlink_set_err
(
init_net
.
genl_sock
,
0
,
netlink_set_err
(
sock_net
(
skb
->
sk
)
->
genl_sock
,
0
,
ovs_dp_vport_multicast_group
.
id
,
PTR_ERR
(
reply
));
goto
exit_unlock
;
}
...
...
@@ -1679,7 +1733,7 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
int
err
;
rtnl_lock
();
vport
=
lookup_vport
(
info
->
userhdr
,
a
);
vport
=
lookup_vport
(
sock_net
(
skb
->
sk
),
info
->
userhdr
,
a
);
err
=
PTR_ERR
(
vport
);
if
(
IS_ERR
(
vport
))
goto
exit_unlock
;
...
...
@@ -1714,7 +1768,7 @@ static int ovs_vport_cmd_get(struct sk_buff *skb, struct genl_info *info)
int
err
;
rcu_read_lock
();
vport
=
lookup_vport
(
ovs_header
,
a
);
vport
=
lookup_vport
(
sock_net
(
skb
->
sk
),
ovs_header
,
a
);
err
=
PTR_ERR
(
vport
);
if
(
IS_ERR
(
vport
))
goto
exit_unlock
;
...
...
@@ -1738,54 +1792,39 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
struct
ovs_header
*
ovs_header
=
genlmsg_data
(
nlmsg_data
(
cb
->
nlh
));
struct
datapath
*
dp
;
u32
port_no
;
int
retval
;
int
bucket
=
cb
->
args
[
0
],
skip
=
cb
->
args
[
1
]
;
int
i
,
j
=
0
;
dp
=
get_dp
(
ovs_header
->
dp_ifindex
);
dp
=
get_dp
(
sock_net
(
skb
->
sk
),
ovs_header
->
dp_ifindex
);
if
(
!
dp
)
return
-
ENODEV
;
rcu_read_lock
();
for
(
port_no
=
cb
->
args
[
0
];
port_no
<
DP_MAX_PORTS
;
port_no
++
)
{
for
(
i
=
bucket
;
i
<
DP_VPORT_HASH_BUCKETS
;
i
++
)
{
struct
vport
*
vport
;
vport
=
rcu_dereference
(
dp
->
ports
[
port_no
]);
if
(
!
vport
)
continue
;
if
(
ovs_vport_cmd_fill_info
(
vport
,
skb
,
NETLINK_CB
(
cb
->
skb
).
pid
,
cb
->
nlh
->
nlmsg_seq
,
NLM_F_MULTI
,
OVS_VPORT_CMD_NEW
)
<
0
)
break
;
}
rcu_read_unlock
();
cb
->
args
[
0
]
=
port_no
;
retval
=
skb
->
len
;
return
retval
;
}
static
void
rehash_flow_table
(
struct
work_struct
*
work
)
{
struct
datapath
*
dp
;
genl_lock
();
list_for_each_entry
(
dp
,
&
dps
,
list_node
)
{
struct
flow_table
*
old_table
=
genl_dereference
(
dp
->
table
);
struct
flow_table
*
new_table
;
new_table
=
ovs_flow_tbl_rehash
(
old_table
);
if
(
!
IS_ERR
(
new_table
))
{
rcu_assign_pointer
(
dp
->
table
,
new_table
);
ovs_flow_tbl_deferred_destroy
(
old_table
);
struct
hlist_node
*
n
;
j
=
0
;
hlist_for_each_entry_rcu
(
vport
,
n
,
&
dp
->
ports
[
i
],
dp_hash_node
)
{
if
(
j
>=
skip
&&
ovs_vport_cmd_fill_info
(
vport
,
skb
,
NETLINK_CB
(
cb
->
skb
).
pid
,
cb
->
nlh
->
nlmsg_seq
,
NLM_F_MULTI
,
OVS_VPORT_CMD_NEW
)
<
0
)
goto
out
;
j
++
;
}
skip
=
0
;
}
out:
rcu_read_unlock
();
genl_unlock
();
cb
->
args
[
0
]
=
i
;
cb
->
args
[
1
]
=
j
;
schedule_delayed_work
(
&
rehash_flow_wq
,
REHASH_FLOW_INTERVAL
)
;
return
skb
->
len
;
}
static
struct
genl_ops
dp_vport_genl_ops
[]
=
{
...
...
@@ -1872,6 +1911,59 @@ static int dp_register_genl(void)
return
err
;
}
static
void
rehash_flow_table
(
struct
work_struct
*
work
)
{
struct
datapath
*
dp
;
struct
net
*
net
;
genl_lock
();
rtnl_lock
();
for_each_net
(
net
)
{
struct
ovs_net
*
ovs_net
=
net_generic
(
net
,
ovs_net_id
);
list_for_each_entry
(
dp
,
&
ovs_net
->
dps
,
list_node
)
{
struct
flow_table
*
old_table
=
genl_dereference
(
dp
->
table
);
struct
flow_table
*
new_table
;
new_table
=
ovs_flow_tbl_rehash
(
old_table
);
if
(
!
IS_ERR
(
new_table
))
{
rcu_assign_pointer
(
dp
->
table
,
new_table
);
ovs_flow_tbl_deferred_destroy
(
old_table
);
}
}
}
rtnl_unlock
();
genl_unlock
();
schedule_delayed_work
(
&
rehash_flow_wq
,
REHASH_FLOW_INTERVAL
);
}
static
int
__net_init
ovs_init_net
(
struct
net
*
net
)
{
struct
ovs_net
*
ovs_net
=
net_generic
(
net
,
ovs_net_id
);
INIT_LIST_HEAD
(
&
ovs_net
->
dps
);
return
0
;
}
static
void
__net_exit
ovs_exit_net
(
struct
net
*
net
)
{
struct
ovs_net
*
ovs_net
=
net_generic
(
net
,
ovs_net_id
);
struct
datapath
*
dp
,
*
dp_next
;
genl_lock
();
list_for_each_entry_safe
(
dp
,
dp_next
,
&
ovs_net
->
dps
,
list_node
)
__dp_destroy
(
dp
);
genl_unlock
();
}
static
struct
pernet_operations
ovs_net_ops
=
{
.
init
=
ovs_init_net
,
.
exit
=
ovs_exit_net
,
.
id
=
&
ovs_net_id
,
.
size
=
sizeof
(
struct
ovs_net
),
};
static
int
__init
dp_init
(
void
)
{
struct
sk_buff
*
dummy_skb
;
...
...
@@ -1889,10 +1981,14 @@ static int __init dp_init(void)
if
(
err
)
goto
error_flow_exit
;
err
=
register_
netdevice_notifier
(
&
ovs_dp_device_notifier
);
err
=
register_
pernet_device
(
&
ovs_net_ops
);
if
(
err
)
goto
error_vport_exit
;
err
=
register_netdevice_notifier
(
&
ovs_dp_device_notifier
);
if
(
err
)
goto
error_netns_exit
;
err
=
dp_register_genl
();
if
(
err
<
0
)
goto
error_unreg_notifier
;
...
...
@@ -1903,6 +1999,8 @@ static int __init dp_init(void)
error_unreg_notifier:
unregister_netdevice_notifier
(
&
ovs_dp_device_notifier
);
error_netns_exit:
unregister_pernet_device
(
&
ovs_net_ops
);
error_vport_exit:
ovs_vport_exit
();
error_flow_exit:
...
...
@@ -1914,9 +2012,10 @@ static int __init dp_init(void)
static
void
dp_cleanup
(
void
)
{
cancel_delayed_work_sync
(
&
rehash_flow_wq
);
rcu_barrier
();
dp_unregister_genl
(
ARRAY_SIZE
(
dp_genl_families
));
unregister_netdevice_notifier
(
&
ovs_dp_device_notifier
);
unregister_pernet_device
(
&
ovs_net_ops
);
rcu_barrier
();
ovs_vport_exit
();
ovs_flow_exit
();
}
...
...
net/openvswitch/datapath.h
View file @
cefd81cf
...
...
@@ -27,10 +27,11 @@
#include <linux/u64_stats_sync.h>
#include "flow.h"
#include "vport.h"
struct
vport
;
#define DP_MAX_PORTS USHRT_MAX
#define DP_VPORT_HASH_BUCKETS 1024
#define DP_MAX_PORTS 1024
#define SAMPLE_ACTION_DEPTH 3
/**
...
...
@@ -58,11 +59,10 @@ struct dp_stats_percpu {
* @list_node: Element in global 'dps' list.
* @n_flows: Number of flows currently in flow table.
* @table: Current flow table. Protected by genl_lock and RCU.
* @ports: Map from port number to &struct vport. %OVSP_LOCAL port
* always exists, other ports may be %NULL. Protected by RTNL and RCU.
* @port_list: List of all ports in @ports in arbitrary order. RTNL required
* to iterate or modify.
* @ports: Hash table for ports. %OVSP_LOCAL port always exists. Protected by
* RTNL and RCU.
* @stats_percpu: Per-CPU datapath statistics.
* @net: Reference to net namespace.
*
* Context: See the comment on locking at the top of datapath.c for additional
* locking information.
...
...
@@ -75,13 +75,37 @@ struct datapath {
struct
flow_table
__rcu
*
table
;
/* Switch ports. */
struct
vport
__rcu
*
ports
[
DP_MAX_PORTS
];
struct
list_head
port_list
;
struct
hlist_head
*
ports
;
/* Stats. */
struct
dp_stats_percpu
__percpu
*
stats_percpu
;
#ifdef CONFIG_NET_NS
/* Network namespace ref. */
struct
net
*
net
;
#endif
};
struct
vport
*
ovs_lookup_vport
(
const
struct
datapath
*
dp
,
u16
port_no
);
static
inline
struct
vport
*
ovs_vport_rcu
(
const
struct
datapath
*
dp
,
int
port_no
)
{
WARN_ON_ONCE
(
!
rcu_read_lock_held
());
return
ovs_lookup_vport
(
dp
,
port_no
);
}
static
inline
struct
vport
*
ovs_vport_rtnl_rcu
(
const
struct
datapath
*
dp
,
int
port_no
)
{
WARN_ON_ONCE
(
!
rcu_read_lock_held
()
&&
!
rtnl_is_locked
());
return
ovs_lookup_vport
(
dp
,
port_no
);
}
static
inline
struct
vport
*
ovs_vport_rtnl
(
const
struct
datapath
*
dp
,
int
port_no
)
{
ASSERT_RTNL
();
return
ovs_lookup_vport
(
dp
,
port_no
);
}
/**
* struct ovs_skb_cb - OVS data in skb CB
* @flow: The flow associated with this packet. May be %NULL if no flow.
...
...
@@ -108,6 +132,16 @@ struct dp_upcall_info {
u32
pid
;
};
static
inline
struct
net
*
ovs_dp_get_net
(
struct
datapath
*
dp
)
{
return
read_pnet
(
&
dp
->
net
);
}
static
inline
void
ovs_dp_set_net
(
struct
datapath
*
dp
,
struct
net
*
net
)
{
write_pnet
(
&
dp
->
net
,
net
);
}
extern
struct
notifier_block
ovs_dp_device_notifier
;
extern
struct
genl_multicast_group
ovs_dp_vport_multicast_group
;
...
...
net/openvswitch/dp_notify.c
View file @
cefd81cf
...
...
@@ -41,19 +41,21 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event,
case
NETDEV_UNREGISTER
:
if
(
!
ovs_is_internal_dev
(
dev
))
{
struct
sk_buff
*
notify
;
struct
datapath
*
dp
=
vport
->
dp
;
notify
=
ovs_vport_cmd_build_info
(
vport
,
0
,
0
,
OVS_VPORT_CMD_DEL
);
ovs_dp_detach_port
(
vport
);
if
(
IS_ERR
(
notify
))
{
netlink_set_err
(
init_net
.
genl_sock
,
0
,
netlink_set_err
(
ovs_dp_get_net
(
dp
)
->
genl_sock
,
0
,
ovs_dp_vport_multicast_group
.
id
,
PTR_ERR
(
notify
));
break
;
}
genlmsg_multicast
(
notify
,
0
,
ovs_dp_vport_multicast_group
.
id
,
GFP_KERNEL
);
genlmsg_multicast_netns
(
ovs_dp_get_net
(
dp
),
notify
,
0
,
ovs_dp_vport_multicast_group
.
id
,
GFP_KERNEL
);
}
break
;
}
...
...
net/openvswitch/flow.c
View file @
cefd81cf
...
...
@@ -203,10 +203,7 @@ struct sw_flow_actions *ovs_flow_actions_alloc(const struct nlattr *actions)
int
actions_len
=
nla_len
(
actions
);
struct
sw_flow_actions
*
sfa
;
/* At least DP_MAX_PORTS actions are required to be able to flood a
* packet to every port. Factor of 2 allows for setting VLAN tags,
* etc. */
if
(
actions_len
>
2
*
DP_MAX_PORTS
*
nla_total_size
(
4
))
if
(
actions_len
>
MAX_ACTIONS_BUFSIZE
)
return
ERR_PTR
(
-
EINVAL
);
sfa
=
kmalloc
(
sizeof
(
*
sfa
)
+
actions_len
,
GFP_KERNEL
);
...
...
@@ -992,7 +989,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
swkey
->
phy
.
in_port
=
in_port
;
attrs
&=
~
(
1
<<
OVS_KEY_ATTR_IN_PORT
);
}
else
{
swkey
->
phy
.
in_port
=
USHRT_MAX
;
swkey
->
phy
.
in_port
=
DP_MAX_PORTS
;
}
/* Data attributes. */
...
...
@@ -1135,7 +1132,7 @@ int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port,
const
struct
nlattr
*
nla
;
int
rem
;
*
in_port
=
USHRT_MAX
;
*
in_port
=
DP_MAX_PORTS
;
*
priority
=
0
;
nla_for_each_nested
(
nla
,
attr
,
rem
)
{
...
...
@@ -1172,7 +1169,7 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
nla_put_u32
(
skb
,
OVS_KEY_ATTR_PRIORITY
,
swkey
->
phy
.
priority
))
goto
nla_put_failure
;
if
(
swkey
->
phy
.
in_port
!=
USHRT_MAX
&&
if
(
swkey
->
phy
.
in_port
!=
DP_MAX_PORTS
&&
nla_put_u32
(
skb
,
OVS_KEY_ATTR_IN_PORT
,
swkey
->
phy
.
in_port
))
goto
nla_put_failure
;
...
...
net/openvswitch/flow.h
View file @
cefd81cf
...
...
@@ -43,7 +43,7 @@ struct sw_flow_actions {
struct
sw_flow_key
{
struct
{
u32
priority
;
/* Packet QoS priority. */
u16
in_port
;
/* Input switch port (or
USHRT_MAX
). */
u16
in_port
;
/* Input switch port (or
DP_MAX_PORTS
). */
}
phy
;
struct
{
u8
src
[
ETH_ALEN
];
/* Ethernet source address. */
...
...
@@ -161,6 +161,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
int
ovs_flow_metadata_from_nlattrs
(
u32
*
priority
,
u16
*
in_port
,
const
struct
nlattr
*
);
#define MAX_ACTIONS_BUFSIZE (16 * 1024)
#define TBL_MIN_BUCKETS 1024
struct
flow_table
{
...
...
net/openvswitch/vport-internal_dev.c
View file @
cefd81cf
...
...
@@ -144,7 +144,7 @@ static void do_setup(struct net_device *netdev)
netdev
->
tx_queue_len
=
0
;
netdev
->
features
=
NETIF_F_LLTX
|
NETIF_F_SG
|
NETIF_F_FRAGLIST
|
NETIF_F_HIGHDMA
|
NETIF_F_HW_CSUM
|
NETIF_F_TSO
;
NETIF_F_HIGHDMA
|
NETIF_F_HW_CSUM
|
NETIF_F_TSO
;
netdev
->
vlan_features
=
netdev
->
features
;
netdev
->
features
|=
NETIF_F_HW_VLAN_TX
;
...
...
@@ -175,9 +175,14 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
goto
error_free_vport
;
}
dev_net_set
(
netdev_vport
->
dev
,
ovs_dp_get_net
(
vport
->
dp
));
internal_dev
=
internal_dev_priv
(
netdev_vport
->
dev
);
internal_dev
->
vport
=
vport
;
/* Restrict bridge port to current netns. */
if
(
vport
->
port_no
==
OVSP_LOCAL
)
netdev_vport
->
dev
->
features
|=
NETIF_F_NETNS_LOCAL
;
err
=
register_netdevice
(
netdev_vport
->
dev
);
if
(
err
)
goto
error_free_netdev
;
...
...
net/openvswitch/vport-netdev.c
View file @
cefd81cf
...
...
@@ -83,7 +83,7 @@ static struct vport *netdev_create(const struct vport_parms *parms)
netdev_vport
=
netdev_vport_priv
(
vport
);
netdev_vport
->
dev
=
dev_get_by_name
(
&
init_net
,
parms
->
name
);
netdev_vport
->
dev
=
dev_get_by_name
(
ovs_dp_get_net
(
vport
->
dp
)
,
parms
->
name
);
if
(
!
netdev_vport
->
dev
)
{
err
=
-
ENODEV
;
goto
error_free_vport
;
...
...
net/openvswitch/vport.c
View file @
cefd81cf
...
...
@@ -16,10 +16,10 @@
* 02110-1301, USA
*/
#include <linux/dcache.h>
#include <linux/etherdevice.h>
#include <linux/if.h>
#include <linux/if_vlan.h>
#include <linux/jhash.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/mutex.h>
...
...
@@ -27,7 +27,9 @@
#include <linux/rcupdate.h>
#include <linux/rtnetlink.h>
#include <linux/compat.h>
#include <net/net_namespace.h>
#include "datapath.h"
#include "vport.h"
#include "vport-internal_dev.h"
...
...
@@ -67,9 +69,9 @@ void ovs_vport_exit(void)
kfree
(
dev_table
);
}
static
struct
hlist_head
*
hash_bucket
(
const
char
*
name
)
static
struct
hlist_head
*
hash_bucket
(
struct
net
*
net
,
const
char
*
name
)
{
unsigned
int
hash
=
full_name_hash
(
name
,
strlen
(
name
)
);
unsigned
int
hash
=
jhash
(
name
,
strlen
(
name
),
(
unsigned
long
)
net
);
return
&
dev_table
[
hash
&
(
VPORT_HASH_BUCKETS
-
1
)];
}
...
...
@@ -80,14 +82,15 @@ static struct hlist_head *hash_bucket(const char *name)
*
* Must be called with RTNL or RCU read lock.
*/
struct
vport
*
ovs_vport_locate
(
const
char
*
name
)
struct
vport
*
ovs_vport_locate
(
struct
net
*
net
,
const
char
*
name
)
{
struct
hlist_head
*
bucket
=
hash_bucket
(
name
);
struct
hlist_head
*
bucket
=
hash_bucket
(
n
et
,
n
ame
);
struct
vport
*
vport
;
struct
hlist_node
*
node
;
hlist_for_each_entry_rcu
(
vport
,
node
,
bucket
,
hash_node
)
if
(
!
strcmp
(
name
,
vport
->
ops
->
get_name
(
vport
)))
if
(
!
strcmp
(
name
,
vport
->
ops
->
get_name
(
vport
))
&&
net_eq
(
ovs_dp_get_net
(
vport
->
dp
),
net
))
return
vport
;
return
NULL
;
...
...
@@ -124,6 +127,7 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
vport
->
port_no
=
parms
->
port_no
;
vport
->
upcall_pid
=
parms
->
upcall_pid
;
vport
->
ops
=
ops
;
INIT_HLIST_NODE
(
&
vport
->
dp_hash_node
);
vport
->
percpu_stats
=
alloc_percpu
(
struct
vport_percpu_stats
);
if
(
!
vport
->
percpu_stats
)
{
...
...
@@ -170,14 +174,17 @@ struct vport *ovs_vport_add(const struct vport_parms *parms)
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
vport_ops_list
);
i
++
)
{
if
(
vport_ops_list
[
i
]
->
type
==
parms
->
type
)
{
struct
hlist_head
*
bucket
;
vport
=
vport_ops_list
[
i
]
->
create
(
parms
);
if
(
IS_ERR
(
vport
))
{
err
=
PTR_ERR
(
vport
);
goto
out
;
}
hlist_add_head_rcu
(
&
vport
->
hash_node
,
hash_bucket
(
vport
->
ops
->
get_name
(
vport
)));
bucket
=
hash_bucket
(
ovs_dp_get_net
(
vport
->
dp
),
vport
->
ops
->
get_name
(
vport
));
hlist_add_head_rcu
(
&
vport
->
hash_node
,
bucket
);
return
vport
;
}
}
...
...
net/openvswitch/vport.h
View file @
cefd81cf
...
...
@@ -20,6 +20,7 @@
#define VPORT_H 1
#include <linux/list.h>
#include <linux/netlink.h>
#include <linux/openvswitch.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
...
...
@@ -38,7 +39,7 @@ void ovs_vport_exit(void);
struct
vport
*
ovs_vport_add
(
const
struct
vport_parms
*
);
void
ovs_vport_del
(
struct
vport
*
);
struct
vport
*
ovs_vport_locate
(
const
char
*
name
);
struct
vport
*
ovs_vport_locate
(
struct
net
*
net
,
const
char
*
name
);
void
ovs_vport_get_stats
(
struct
vport
*
,
struct
ovs_vport_stats
*
);
...
...
@@ -69,10 +70,10 @@ struct vport_err_stats {
* @rcu: RCU callback head for deferred destruction.
* @port_no: Index into @dp's @ports array.
* @dp: Datapath to which this port belongs.
* @node: Element in @dp's @port_list.
* @upcall_pid: The Netlink port to use for packets received on this port that
* miss the flow table.
* @hash_node: Element in @dev_table hash table in vport.c.
* @dp_hash_node: Element in @datapath->ports hash table in datapath.c.
* @ops: Class structure.
* @percpu_stats: Points to per-CPU statistics used and maintained by vport
* @stats_lock: Protects @err_stats;
...
...
@@ -82,10 +83,10 @@ struct vport {
struct
rcu_head
rcu
;
u16
port_no
;
struct
datapath
*
dp
;
struct
list_head
node
;
u32
upcall_pid
;
struct
hlist_node
hash_node
;
struct
hlist_node
dp_hash_node
;
const
struct
vport_ops
*
ops
;
struct
vport_percpu_stats
__percpu
*
percpu_stats
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment