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
a507c346
Commit
a507c346
authored
Feb 09, 2017
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'openvswitch-Conntrack-integration-improvements'
parents
9878f602
316d4d78
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
420 additions
and
113 deletions
+420
-113
include/uapi/linux/openvswitch.h
include/uapi/linux/openvswitch.h
+30
-3
net/openvswitch/actions.c
net/openvswitch/actions.c
+2
-0
net/openvswitch/conntrack.c
net/openvswitch/conntrack.c
+232
-64
net/openvswitch/conntrack.h
net/openvswitch/conntrack.h
+10
-4
net/openvswitch/flow.c
net/openvswitch/flow.c
+29
-5
net/openvswitch/flow.h
net/openvswitch/flow.h
+42
-13
net/openvswitch/flow_netlink.c
net/openvswitch/flow_netlink.c
+70
-22
net/openvswitch/flow_netlink.h
net/openvswitch/flow_netlink.h
+5
-2
No files found.
include/uapi/linux/openvswitch.h
View file @
a507c346
/*
* Copyright (c) 2007-201
3
Nicira, Inc.
* Copyright (c) 2007-201
7
Nicira, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
...
...
@@ -331,6 +331,8 @@ enum ovs_key_attr {
OVS_KEY_ATTR_CT_ZONE
,
/* u16 connection tracking zone. */
OVS_KEY_ATTR_CT_MARK
,
/* u32 connection tracking mark */
OVS_KEY_ATTR_CT_LABELS
,
/* 16-octet connection tracking label */
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4
,
/* struct ovs_key_ct_tuple_ipv4 */
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6
,
/* struct ovs_key_ct_tuple_ipv6 */
#ifdef __KERNEL__
OVS_KEY_ATTR_TUNNEL_INFO
,
/* struct ip_tunnel_info */
...
...
@@ -446,9 +448,13 @@ struct ovs_key_nd {
__u8
nd_tll
[
ETH_ALEN
];
};
#define OVS_CT_LABELS_LEN 16
#define OVS_CT_LABELS_LEN_32 4
#define OVS_CT_LABELS_LEN (OVS_CT_LABELS_LEN_32 * sizeof(__u32))
struct
ovs_key_ct_labels
{
__u8
ct_labels
[
OVS_CT_LABELS_LEN
];
union
{
__u8
ct_labels
[
OVS_CT_LABELS_LEN
];
__u32
ct_labels_32
[
OVS_CT_LABELS_LEN_32
];
};
};
/* OVS_KEY_ATTR_CT_STATE flags */
...
...
@@ -468,6 +474,22 @@ struct ovs_key_ct_labels {
#define OVS_CS_F_NAT_MASK (OVS_CS_F_SRC_NAT | OVS_CS_F_DST_NAT)
struct
ovs_key_ct_tuple_ipv4
{
__be32
ipv4_src
;
__be32
ipv4_dst
;
__be16
src_port
;
__be16
dst_port
;
__u8
ipv4_proto
;
};
struct
ovs_key_ct_tuple_ipv6
{
__be32
ipv6_src
[
4
];
__be32
ipv6_dst
[
4
];
__be16
src_port
;
__be16
dst_port
;
__u8
ipv6_proto
;
};
/**
* enum ovs_flow_attr - attributes for %OVS_FLOW_* commands.
* @OVS_FLOW_ATTR_KEY: Nested %OVS_KEY_ATTR_* attributes specifying the flow
...
...
@@ -652,6 +674,10 @@ struct ovs_action_hash {
* @OVS_CT_ATTR_HELPER: variable length string defining conntrack ALG.
* @OVS_CT_ATTR_NAT: Nested OVS_NAT_ATTR_* for performing L3 network address
* translation (NAT) on the packet.
* @OVS_CT_ATTR_FORCE_COMMIT: Like %OVS_CT_ATTR_COMMIT, but instead of doing
* nothing if the connection is already committed will check that the current
* packet is in conntrack entry's original direction. If directionality does
* not match, will delete the existing conntrack entry and commit a new one.
*/
enum
ovs_ct_attr
{
OVS_CT_ATTR_UNSPEC
,
...
...
@@ -662,6 +688,7 @@ enum ovs_ct_attr {
OVS_CT_ATTR_HELPER
,
/* netlink helper to assist detection of
related connections. */
OVS_CT_ATTR_NAT
,
/* Nested OVS_NAT_ATTR_* */
OVS_CT_ATTR_FORCE_COMMIT
,
/* No argument */
__OVS_CT_ATTR_MAX
};
...
...
net/openvswitch/actions.c
View file @
a507c346
...
...
@@ -1074,6 +1074,8 @@ static int execute_masked_set_action(struct sk_buff *skb,
case
OVS_KEY_ATTR_CT_ZONE
:
case
OVS_KEY_ATTR_CT_MARK
:
case
OVS_KEY_ATTR_CT_LABELS
:
case
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4
:
case
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6
:
err
=
-
EINVAL
;
break
;
}
...
...
net/openvswitch/conntrack.c
View file @
a507c346
...
...
@@ -65,6 +65,7 @@ struct ovs_conntrack_info {
struct
nf_conn
*
ct
;
u8
commit
:
1
;
u8
nat
:
3
;
/* enum ovs_ct_nat */
u8
force
:
1
;
u16
family
;
struct
md_mark
mark
;
struct
md_labels
labels
;
...
...
@@ -73,6 +74,8 @@ struct ovs_conntrack_info {
#endif
};
static
bool
labels_nonzero
(
const
struct
ovs_key_ct_labels
*
labels
);
static
void
__ovs_ct_free_action
(
struct
ovs_conntrack_info
*
ct_info
);
static
u16
key_to_nfproto
(
const
struct
sw_flow_key
*
key
)
...
...
@@ -129,21 +132,33 @@ static u32 ovs_ct_get_mark(const struct nf_conn *ct)
#endif
}
/* Guard against conntrack labels max size shrinking below 128 bits. */
#if NF_CT_LABELS_MAX_SIZE < 16
#error NF_CT_LABELS_MAX_SIZE must be at least 16 bytes
#endif
static
void
ovs_ct_get_labels
(
const
struct
nf_conn
*
ct
,
struct
ovs_key_ct_labels
*
labels
)
{
struct
nf_conn_labels
*
cl
=
ct
?
nf_ct_labels_find
(
ct
)
:
NULL
;
if
(
cl
)
{
size_t
len
=
sizeof
(
cl
->
bits
);
if
(
cl
)
memcpy
(
labels
,
cl
->
bits
,
OVS_CT_LABELS_LEN
);
else
memset
(
labels
,
0
,
OVS_CT_LABELS_LEN
);
}
if
(
len
>
OVS_CT_LABELS_LEN
)
len
=
OVS_CT_LABELS_LEN
;
else
if
(
len
<
OVS_CT_LABELS_LEN
)
memset
(
labels
,
0
,
OVS_CT_LABELS_LEN
);
memcpy
(
labels
,
cl
->
bits
,
len
);
static
void
__ovs_ct_update_key_orig_tp
(
struct
sw_flow_key
*
key
,
const
struct
nf_conntrack_tuple
*
orig
,
u8
icmp_proto
)
{
key
->
ct_orig_proto
=
orig
->
dst
.
protonum
;
if
(
orig
->
dst
.
protonum
==
icmp_proto
)
{
key
->
ct
.
orig_tp
.
src
=
htons
(
orig
->
dst
.
u
.
icmp
.
type
);
key
->
ct
.
orig_tp
.
dst
=
htons
(
orig
->
dst
.
u
.
icmp
.
code
);
}
else
{
memset
(
labels
,
0
,
OVS_CT_LABELS_LEN
);
key
->
ct
.
orig_tp
.
src
=
orig
->
src
.
u
.
all
;
key
->
ct
.
orig_tp
.
dst
=
orig
->
dst
.
u
.
all
;
}
}
...
...
@@ -151,13 +166,42 @@ static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state,
const
struct
nf_conntrack_zone
*
zone
,
const
struct
nf_conn
*
ct
)
{
key
->
ct
.
state
=
state
;
key
->
ct
.
zone
=
zone
->
id
;
key
->
ct
_
state
=
state
;
key
->
ct
_
zone
=
zone
->
id
;
key
->
ct
.
mark
=
ovs_ct_get_mark
(
ct
);
ovs_ct_get_labels
(
ct
,
&
key
->
ct
.
labels
);
if
(
ct
)
{
const
struct
nf_conntrack_tuple
*
orig
;
/* Use the master if we have one. */
if
(
ct
->
master
)
ct
=
ct
->
master
;
orig
=
&
ct
->
tuplehash
[
IP_CT_DIR_ORIGINAL
].
tuple
;
/* IP version must match with the master connection. */
if
(
key
->
eth
.
type
==
htons
(
ETH_P_IP
)
&&
nf_ct_l3num
(
ct
)
==
NFPROTO_IPV4
)
{
key
->
ipv4
.
ct_orig
.
src
=
orig
->
src
.
u3
.
ip
;
key
->
ipv4
.
ct_orig
.
dst
=
orig
->
dst
.
u3
.
ip
;
__ovs_ct_update_key_orig_tp
(
key
,
orig
,
IPPROTO_ICMP
);
return
;
}
else
if
(
key
->
eth
.
type
==
htons
(
ETH_P_IPV6
)
&&
!
sw_flow_key_is_nd
(
key
)
&&
nf_ct_l3num
(
ct
)
==
NFPROTO_IPV6
)
{
key
->
ipv6
.
ct_orig
.
src
=
orig
->
src
.
u3
.
in6
;
key
->
ipv6
.
ct_orig
.
dst
=
orig
->
dst
.
u3
.
in6
;
__ovs_ct_update_key_orig_tp
(
key
,
orig
,
NEXTHDR_ICMP
);
return
;
}
}
/* Clear 'ct_orig_proto' to mark the non-existence of conntrack
* original direction key fields.
*/
key
->
ct_orig_proto
=
0
;
}
/* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has
/* Update 'key' based on skb->
_
nfct. If 'post_ct' is true, then OVS has
* previously sent the packet to conntrack via the ct action. If
* 'keep_nat_flags' is true, the existing NAT flags retained, else they are
* initialized from the connection status.
...
...
@@ -184,7 +228,7 @@ static void ovs_ct_update_key(const struct sk_buff *skb,
if
(
ct
->
master
)
state
|=
OVS_CS_F_RELATED
;
if
(
keep_nat_flags
)
{
state
|=
key
->
ct
.
state
&
OVS_CS_F_NAT_MASK
;
state
|=
key
->
ct
_
state
&
OVS_CS_F_NAT_MASK
;
}
else
{
if
(
ct
->
status
&
IPS_SRC_NAT
)
state
|=
OVS_CS_F_SRC_NAT
;
...
...
@@ -208,44 +252,69 @@ void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key)
ovs_ct_update_key
(
skb
,
NULL
,
key
,
false
,
false
);
}
int
ovs_ct_put_key
(
const
struct
sw_flow_key
*
key
,
struct
sk_buff
*
skb
)
#define IN6_ADDR_INITIALIZER(ADDR) \
{ (ADDR).s6_addr32[0], (ADDR).s6_addr32[1], \
(ADDR).s6_addr32[2], (ADDR).s6_addr32[3] }
int
ovs_ct_put_key
(
const
struct
sw_flow_key
*
swkey
,
const
struct
sw_flow_key
*
output
,
struct
sk_buff
*
skb
)
{
if
(
nla_put_u32
(
skb
,
OVS_KEY_ATTR_CT_STATE
,
key
->
ct
.
state
))
if
(
nla_put_u32
(
skb
,
OVS_KEY_ATTR_CT_STATE
,
output
->
ct_
state
))
return
-
EMSGSIZE
;
if
(
IS_ENABLED
(
CONFIG_NF_CONNTRACK_ZONES
)
&&
nla_put_u16
(
skb
,
OVS_KEY_ATTR_CT_ZONE
,
key
->
ct
.
zone
))
nla_put_u16
(
skb
,
OVS_KEY_ATTR_CT_ZONE
,
output
->
ct_
zone
))
return
-
EMSGSIZE
;
if
(
IS_ENABLED
(
CONFIG_NF_CONNTRACK_MARK
)
&&
nla_put_u32
(
skb
,
OVS_KEY_ATTR_CT_MARK
,
key
->
ct
.
mark
))
nla_put_u32
(
skb
,
OVS_KEY_ATTR_CT_MARK
,
output
->
ct
.
mark
))
return
-
EMSGSIZE
;
if
(
IS_ENABLED
(
CONFIG_NF_CONNTRACK_LABELS
)
&&
nla_put
(
skb
,
OVS_KEY_ATTR_CT_LABELS
,
sizeof
(
key
->
ct
.
labels
),
&
key
->
ct
.
labels
))
nla_put
(
skb
,
OVS_KEY_ATTR_CT_LABELS
,
sizeof
(
output
->
ct
.
labels
),
&
output
->
ct
.
labels
))
return
-
EMSGSIZE
;
if
(
swkey
->
ct_orig_proto
)
{
if
(
swkey
->
eth
.
type
==
htons
(
ETH_P_IP
))
{
struct
ovs_key_ct_tuple_ipv4
orig
=
{
output
->
ipv4
.
ct_orig
.
src
,
output
->
ipv4
.
ct_orig
.
dst
,
output
->
ct
.
orig_tp
.
src
,
output
->
ct
.
orig_tp
.
dst
,
output
->
ct_orig_proto
,
};
if
(
nla_put
(
skb
,
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4
,
sizeof
(
orig
),
&
orig
))
return
-
EMSGSIZE
;
}
else
if
(
swkey
->
eth
.
type
==
htons
(
ETH_P_IPV6
))
{
struct
ovs_key_ct_tuple_ipv6
orig
=
{
IN6_ADDR_INITIALIZER
(
output
->
ipv6
.
ct_orig
.
src
),
IN6_ADDR_INITIALIZER
(
output
->
ipv6
.
ct_orig
.
dst
),
output
->
ct
.
orig_tp
.
src
,
output
->
ct
.
orig_tp
.
dst
,
output
->
ct_orig_proto
,
};
if
(
nla_put
(
skb
,
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6
,
sizeof
(
orig
),
&
orig
))
return
-
EMSGSIZE
;
}
}
return
0
;
}
static
int
ovs_ct_set_mark
(
struct
sk_buff
*
skb
,
struct
sw_flow_key
*
key
,
static
int
ovs_ct_set_mark
(
struct
nf_conn
*
ct
,
struct
sw_flow_key
*
key
,
u32
ct_mark
,
u32
mask
)
{
#if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)
enum
ip_conntrack_info
ctinfo
;
struct
nf_conn
*
ct
;
u32
new_mark
;
/* The connection could be invalid, in which case set_mark is no-op. */
ct
=
nf_ct_get
(
skb
,
&
ctinfo
);
if
(
!
ct
)
return
0
;
new_mark
=
ct_mark
|
(
ct
->
mark
&
~
(
mask
));
if
(
ct
->
mark
!=
new_mark
)
{
ct
->
mark
=
new_mark
;
nf_conntrack_event_cache
(
IPCT_MARK
,
ct
);
if
(
nf_ct_is_confirmed
(
ct
))
nf_conntrack_event_cache
(
IPCT_MARK
,
ct
);
key
->
ct
.
mark
=
new_mark
;
}
...
...
@@ -255,34 +324,80 @@ static int ovs_ct_set_mark(struct sk_buff *skb, struct sw_flow_key *key,
#endif
}
static
int
ovs_ct_set_labels
(
struct
sk_buff
*
skb
,
struct
sw_flow_key
*
key
,
const
struct
ovs_key_ct_labels
*
labels
,
const
struct
ovs_key_ct_labels
*
mask
)
static
struct
nf_conn_labels
*
ovs_ct_get_conn_labels
(
struct
nf_conn
*
ct
)
{
enum
ip_conntrack_info
ctinfo
;
struct
nf_conn_labels
*
cl
;
struct
nf_conn
*
ct
;
int
err
;
/* The connection could be invalid, in which case set_label is no-op.*/
ct
=
nf_ct_get
(
skb
,
&
ctinfo
);
if
(
!
ct
)
return
0
;
cl
=
nf_ct_labels_find
(
ct
);
if
(
!
cl
)
{
nf_ct_labels_ext_add
(
ct
);
cl
=
nf_ct_labels_find
(
ct
);
}
if
(
!
cl
||
sizeof
(
cl
->
bits
)
<
OVS_CT_LABELS_LEN
)
return
cl
;
}
/* Initialize labels for a new, yet to be committed conntrack entry. Note that
* since the new connection is not yet confirmed, and thus no-one else has
* access to it's labels, we simply write them over. Also, we refrain from
* triggering events, as receiving change events before the create event would
* be confusing.
*/
static
int
ovs_ct_init_labels
(
struct
nf_conn
*
ct
,
struct
sw_flow_key
*
key
,
const
struct
ovs_key_ct_labels
*
labels
,
const
struct
ovs_key_ct_labels
*
mask
)
{
struct
nf_conn_labels
*
cl
,
*
master_cl
;
bool
have_mask
=
labels_nonzero
(
mask
);
/* Inherit master's labels to the related connection? */
master_cl
=
ct
->
master
?
nf_ct_labels_find
(
ct
->
master
)
:
NULL
;
if
(
!
master_cl
&&
!
have_mask
)
return
0
;
/* Nothing to do. */
cl
=
ovs_ct_get_conn_labels
(
ct
);
if
(
!
cl
)
return
-
ENOSPC
;
/* Inherit the master's labels, if any. */
if
(
master_cl
)
*
cl
=
*
master_cl
;
if
(
have_mask
)
{
u32
*
dst
=
(
u32
*
)
cl
->
bits
;
int
i
;
for
(
i
=
0
;
i
<
OVS_CT_LABELS_LEN_32
;
i
++
)
dst
[
i
]
=
(
dst
[
i
]
&
~
mask
->
ct_labels_32
[
i
])
|
(
labels
->
ct_labels_32
[
i
]
&
mask
->
ct_labels_32
[
i
]);
}
memcpy
(
&
key
->
ct
.
labels
,
cl
->
bits
,
OVS_CT_LABELS_LEN
);
return
0
;
}
static
int
ovs_ct_set_labels
(
struct
nf_conn
*
ct
,
struct
sw_flow_key
*
key
,
const
struct
ovs_key_ct_labels
*
labels
,
const
struct
ovs_key_ct_labels
*
mask
)
{
struct
nf_conn_labels
*
cl
;
int
err
;
cl
=
ovs_ct_get_conn_labels
(
ct
);
if
(
!
cl
)
return
-
ENOSPC
;
err
=
nf_connlabels_replace
(
ct
,
(
u32
*
)
labels
,
(
u32
*
)
mask
,
OVS_CT_LABELS_LEN
/
sizeof
(
u32
));
err
=
nf_connlabels_replace
(
ct
,
labels
->
ct_labels_32
,
mask
->
ct_labels_32
,
OVS_CT_LABELS_LEN_32
);
if
(
err
)
return
err
;
ovs_ct_get_labels
(
ct
,
&
key
->
ct
.
labels
);
memcpy
(
&
key
->
ct
.
labels
,
cl
->
bits
,
OVS_CT_LABELS_LEN
);
return
0
;
}
...
...
@@ -421,16 +536,16 @@ ovs_ct_get_info(const struct nf_conntrack_tuple_hash *h)
/* Find an existing connection which this packet belongs to without
* re-attributing statistics or modifying the connection state. This allows an
* skb->nfct lost due to an upcall to be recovered during actions execution.
* skb->
_
nfct lost due to an upcall to be recovered during actions execution.
*
* Must be called with rcu_read_lock.
*
* On success, populates skb->
nfct and skb->nfctinfo, and returns the
*
connection. Returns NULL
if there is no existing entry.
* On success, populates skb->
_nfct and returns the connection. Returns NULL
* if there is no existing entry.
*/
static
struct
nf_conn
*
ovs_ct_find_existing
(
struct
net
*
net
,
const
struct
nf_conntrack_zone
*
zone
,
u8
l3num
,
struct
sk_buff
*
skb
)
u8
l3num
,
struct
sk_buff
*
skb
,
bool
natted
)
{
struct
nf_conntrack_l3proto
*
l3proto
;
struct
nf_conntrack_l4proto
*
l4proto
;
...
...
@@ -453,6 +568,17 @@ ovs_ct_find_existing(struct net *net, const struct nf_conntrack_zone *zone,
return
NULL
;
}
/* Must invert the tuple if skb has been transformed by NAT. */
if
(
natted
)
{
struct
nf_conntrack_tuple
inverse
;
if
(
!
nf_ct_invert_tuple
(
&
inverse
,
&
tuple
,
l3proto
,
l4proto
))
{
pr_debug
(
"ovs_ct_find_existing: Inversion failed!
\n
"
);
return
NULL
;
}
tuple
=
inverse
;
}
/* look for tuple match */
h
=
nf_conntrack_find_get
(
net
,
zone
,
&
tuple
);
if
(
!
h
)
...
...
@@ -460,11 +586,18 @@ ovs_ct_find_existing(struct net *net, const struct nf_conntrack_zone *zone,
ct
=
nf_ct_tuplehash_to_ctrack
(
h
);
/* Inverted packet tuple matches the reverse direction conntrack tuple,
* select the other tuplehash to get the right 'ctinfo' bits for this
* packet.
*/
if
(
natted
)
h
=
&
ct
->
tuplehash
[
!
h
->
tuple
.
dst
.
dir
];
nf_ct_set
(
skb
,
ct
,
ovs_ct_get_info
(
h
));
return
ct
;
}
/* Determine whether skb->nfct is equal to the result of conntrack lookup. */
/* Determine whether skb->
_
nfct is equal to the result of conntrack lookup. */
static
bool
skb_nfct_cached
(
struct
net
*
net
,
const
struct
sw_flow_key
*
key
,
const
struct
ovs_conntrack_info
*
info
,
...
...
@@ -475,14 +608,19 @@ static bool skb_nfct_cached(struct net *net,
ct
=
nf_ct_get
(
skb
,
&
ctinfo
);
/* If no ct, check if we have evidence that an existing conntrack entry
* might be found for this skb. This happens when we lose a skb->nfct
* might be found for this skb. This happens when we lose a skb->
_
nfct
* due to an upcall. If the connection was not confirmed, it is not
* cached and needs to be run through conntrack again.
*/
if
(
!
ct
&&
key
->
ct
.
state
&
OVS_CS_F_TRACKED
&&
!
(
key
->
ct
.
state
&
OVS_CS_F_INVALID
)
&&
key
->
ct
.
zone
==
info
->
zone
.
id
)
ct
=
ovs_ct_find_existing
(
net
,
&
info
->
zone
,
info
->
family
,
skb
);
if
(
!
ct
&&
key
->
ct_state
&
OVS_CS_F_TRACKED
&&
!
(
key
->
ct_state
&
OVS_CS_F_INVALID
)
&&
key
->
ct_zone
==
info
->
zone
.
id
)
{
ct
=
ovs_ct_find_existing
(
net
,
&
info
->
zone
,
info
->
family
,
skb
,
!!
(
key
->
ct_state
&
OVS_CS_F_NAT_MASK
));
if
(
ct
)
nf_ct_get
(
skb
,
&
ctinfo
);
}
if
(
!
ct
)
return
false
;
if
(
!
net_eq
(
net
,
read_pnet
(
&
ct
->
ct_net
)))
...
...
@@ -496,6 +634,18 @@ static bool skb_nfct_cached(struct net *net,
if
(
help
&&
rcu_access_pointer
(
help
->
helper
)
!=
info
->
helper
)
return
false
;
}
/* Force conntrack entry direction to the current packet? */
if
(
info
->
force
&&
CTINFO2DIR
(
ctinfo
)
!=
IP_CT_DIR_ORIGINAL
)
{
/* Delete the conntrack entry if confirmed, else just release
* the reference.
*/
if
(
nf_ct_is_confirmed
(
ct
))
nf_ct_delete
(
ct
,
0
,
0
);
else
nf_conntrack_put
(
&
ct
->
ct_general
);
nf_ct_set
(
skb
,
NULL
,
0
);
return
false
;
}
return
true
;
}
...
...
@@ -590,7 +740,7 @@ static void ovs_nat_update_key(struct sw_flow_key *key,
if
(
maniptype
==
NF_NAT_MANIP_SRC
)
{
__be16
src
;
key
->
ct
.
state
|=
OVS_CS_F_SRC_NAT
;
key
->
ct
_
state
|=
OVS_CS_F_SRC_NAT
;
if
(
key
->
eth
.
type
==
htons
(
ETH_P_IP
))
key
->
ipv4
.
addr
.
src
=
ip_hdr
(
skb
)
->
saddr
;
else
if
(
key
->
eth
.
type
==
htons
(
ETH_P_IPV6
))
...
...
@@ -612,7 +762,7 @@ static void ovs_nat_update_key(struct sw_flow_key *key,
}
else
{
__be16
dst
;
key
->
ct
.
state
|=
OVS_CS_F_DST_NAT
;
key
->
ct
_
state
|=
OVS_CS_F_DST_NAT
;
if
(
key
->
eth
.
type
==
htons
(
ETH_P_IP
))
key
->
ipv4
.
addr
.
dst
=
ip_hdr
(
skb
)
->
daddr
;
else
if
(
key
->
eth
.
type
==
htons
(
ETH_P_IPV6
))
...
...
@@ -699,7 +849,7 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key,
/* Pass 'skb' through conntrack in 'net', using zone configured in 'info', if
* not done already. Update key with new CT state after passing the packet
* through conntrack.
* Note that if the packet is deemed invalid by conntrack, skb->nfct will be
* Note that if the packet is deemed invalid by conntrack, skb->
_
nfct will be
* set to NULL and 0 will be returned.
*/
static
int
__ovs_ct_lookup
(
struct
net
*
net
,
struct
sw_flow_key
*
key
,
...
...
@@ -736,7 +886,7 @@ static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
* NAT after the nf_conntrack_in() call. We can actually clear
* the whole state, as it will be re-initialized below.
*/
key
->
ct
.
state
=
0
;
key
->
ct
_
state
=
0
;
/* Update the key, but keep the NAT flags. */
ovs_ct_update_key
(
skb
,
info
,
key
,
true
,
true
);
...
...
@@ -752,9 +902,9 @@ static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
*
* NAT will be done only if the CT action has NAT, and only
* once per packet (per zone), as guarded by the NAT bits in
* the key->ct
.
state.
* the key->ct
_
state.
*/
if
(
info
->
nat
&&
!
(
key
->
ct
.
state
&
OVS_CS_F_NAT_MASK
)
&&
if
(
info
->
nat
&&
!
(
key
->
ct
_
state
&
OVS_CS_F_NAT_MASK
)
&&
(
nf_ct_is_confirmed
(
ct
)
||
info
->
commit
)
&&
ovs_ct_nat
(
net
,
key
,
info
,
skb
,
ct
,
ctinfo
)
!=
NF_ACCEPT
)
{
return
-
EINVAL
;
...
...
@@ -830,8 +980,8 @@ static bool labels_nonzero(const struct ovs_key_ct_labels *labels)
{
size_t
i
;
for
(
i
=
0
;
i
<
sizeof
(
*
labels
)
;
i
++
)
if
(
labels
->
ct_labels
[
i
])
for
(
i
=
0
;
i
<
OVS_CT_LABELS_LEN_32
;
i
++
)
if
(
labels
->
ct_labels
_32
[
i
])
return
true
;
return
false
;
...
...
@@ -842,24 +992,36 @@ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key,
const
struct
ovs_conntrack_info
*
info
,
struct
sk_buff
*
skb
)
{
enum
ip_conntrack_info
ctinfo
;
struct
nf_conn
*
ct
;
int
err
;
err
=
__ovs_ct_lookup
(
net
,
key
,
info
,
skb
);
if
(
err
)
return
err
;
/* The connection could be invalid, in which case this is a no-op.*/
ct
=
nf_ct_get
(
skb
,
&
ctinfo
);
if
(
!
ct
)
return
0
;
/* Apply changes before confirming the connection so that the initial
* conntrack NEW netlink event carries the values given in the CT
* action.
*/
if
(
info
->
mark
.
mask
)
{
err
=
ovs_ct_set_mark
(
skb
,
key
,
info
->
mark
.
value
,
err
=
ovs_ct_set_mark
(
ct
,
key
,
info
->
mark
.
value
,
info
->
mark
.
mask
);
if
(
err
)
return
err
;
}
if
(
labels_nonzero
(
&
info
->
labels
.
mask
))
{
err
=
ovs_ct_set_labels
(
skb
,
key
,
&
info
->
labels
.
value
,
if
(
!
nf_ct_is_confirmed
(
ct
))
{
err
=
ovs_ct_init_labels
(
ct
,
key
,
&
info
->
labels
.
value
,
&
info
->
labels
.
mask
);
if
(
err
)
return
err
;
}
else
if
(
labels_nonzero
(
&
info
->
labels
.
mask
))
{
err
=
ovs_ct_set_labels
(
ct
,
key
,
&
info
->
labels
.
value
,
&
info
->
labels
.
mask
);
if
(
err
)
return
err
;
...
...
@@ -1061,6 +1223,7 @@ static int parse_nat(const struct nlattr *attr,
static
const
struct
ovs_ct_len_tbl
ovs_ct_attr_lens
[
OVS_CT_ATTR_MAX
+
1
]
=
{
[
OVS_CT_ATTR_COMMIT
]
=
{
.
minlen
=
0
,
.
maxlen
=
0
},
[
OVS_CT_ATTR_FORCE_COMMIT
]
=
{
.
minlen
=
0
,
.
maxlen
=
0
},
[
OVS_CT_ATTR_ZONE
]
=
{
.
minlen
=
sizeof
(
u16
),
.
maxlen
=
sizeof
(
u16
)
},
[
OVS_CT_ATTR_MARK
]
=
{
.
minlen
=
sizeof
(
struct
md_mark
),
...
...
@@ -1100,6 +1263,9 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
}
switch
(
type
)
{
case
OVS_CT_ATTR_FORCE_COMMIT
:
info
->
force
=
true
;
/* fall through. */
case
OVS_CT_ATTR_COMMIT
:
info
->
commit
=
true
;
break
;
...
...
@@ -1326,7 +1492,9 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info,
if
(
!
start
)
return
-
EMSGSIZE
;
if
(
ct_info
->
commit
&&
nla_put_flag
(
skb
,
OVS_CT_ATTR_COMMIT
))
if
(
ct_info
->
commit
&&
nla_put_flag
(
skb
,
ct_info
->
force
?
OVS_CT_ATTR_FORCE_COMMIT
:
OVS_CT_ATTR_COMMIT
))
return
-
EMSGSIZE
;
if
(
IS_ENABLED
(
CONFIG_NF_CONNTRACK_ZONES
)
&&
nla_put_u16
(
skb
,
OVS_CT_ATTR_ZONE
,
ct_info
->
zone
.
id
))
...
...
net/openvswitch/conntrack.h
View file @
a507c346
...
...
@@ -32,7 +32,8 @@ int ovs_ct_execute(struct net *, struct sk_buff *, struct sw_flow_key *,
const
struct
ovs_conntrack_info
*
);
void
ovs_ct_fill_key
(
const
struct
sk_buff
*
skb
,
struct
sw_flow_key
*
key
);
int
ovs_ct_put_key
(
const
struct
sw_flow_key
*
key
,
struct
sk_buff
*
skb
);
int
ovs_ct_put_key
(
const
struct
sw_flow_key
*
swkey
,
const
struct
sw_flow_key
*
output
,
struct
sk_buff
*
skb
);
void
ovs_ct_free_action
(
const
struct
nlattr
*
a
);
#define CT_SUPPORTED_MASK (OVS_CS_F_NEW | OVS_CS_F_ESTABLISHED | \
...
...
@@ -75,13 +76,18 @@ static inline int ovs_ct_execute(struct net *net, struct sk_buff *skb,
static
inline
void
ovs_ct_fill_key
(
const
struct
sk_buff
*
skb
,
struct
sw_flow_key
*
key
)
{
key
->
ct
.
state
=
0
;
key
->
ct
.
zone
=
0
;
key
->
ct
_
state
=
0
;
key
->
ct
_
zone
=
0
;
key
->
ct
.
mark
=
0
;
memset
(
&
key
->
ct
.
labels
,
0
,
sizeof
(
key
->
ct
.
labels
));
/* Clear 'ct_orig_proto' to mark the non-existence of original
* direction key fields.
*/
key
->
ct_orig_proto
=
0
;
}
static
inline
int
ovs_ct_put_key
(
const
struct
sw_flow_key
*
key
,
static
inline
int
ovs_ct_put_key
(
const
struct
sw_flow_key
*
swkey
,
const
struct
sw_flow_key
*
output
,
struct
sk_buff
*
skb
)
{
return
0
;
...
...
net/openvswitch/flow.c
View file @
a507c346
...
...
@@ -765,7 +765,7 @@ static int key_extract_mac_proto(struct sk_buff *skb)
int
ovs_flow_key_extract
(
const
struct
ip_tunnel_info
*
tun_info
,
struct
sk_buff
*
skb
,
struct
sw_flow_key
*
key
)
{
int
res
;
int
res
,
err
;
/* Extract metadata from packet. */
if
(
tun_info
)
{
...
...
@@ -792,7 +792,6 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
key
->
phy
.
priority
=
skb
->
priority
;
key
->
phy
.
in_port
=
OVS_CB
(
skb
)
->
input_vport
->
port_no
;
key
->
phy
.
skb_mark
=
skb
->
mark
;
ovs_ct_fill_key
(
skb
,
key
);
key
->
ovs_flow_hash
=
0
;
res
=
key_extract_mac_proto
(
skb
);
if
(
res
<
0
)
...
...
@@ -800,17 +799,26 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info,
key
->
mac_proto
=
res
;
key
->
recirc_id
=
0
;
return
key_extract
(
skb
,
key
);
err
=
key_extract
(
skb
,
key
);
if
(
!
err
)
ovs_ct_fill_key
(
skb
,
key
);
/* Must be after key_extract(). */
return
err
;
}
int
ovs_flow_key_extract_userspace
(
struct
net
*
net
,
const
struct
nlattr
*
attr
,
struct
sk_buff
*
skb
,
struct
sw_flow_key
*
key
,
bool
log
)
{
const
struct
nlattr
*
a
[
OVS_KEY_ATTR_MAX
+
1
];
u64
attrs
=
0
;
int
err
;
err
=
parse_flow_nlattrs
(
attr
,
a
,
&
attrs
,
log
);
if
(
err
)
return
-
EINVAL
;
/* Extract metadata from netlink attributes. */
err
=
ovs_nla_get_flow_metadata
(
net
,
a
ttr
,
key
,
log
);
err
=
ovs_nla_get_flow_metadata
(
net
,
a
,
attrs
,
key
,
log
);
if
(
err
)
return
err
;
...
...
@@ -824,5 +832,21 @@ int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr,
*/
skb
->
protocol
=
key
->
eth
.
type
;
return
key_extract
(
skb
,
key
);
err
=
key_extract
(
skb
,
key
);
if
(
err
)
return
err
;
/* Check that we have conntrack original direction tuple metadata only
* for packets for which it makes sense. Otherwise the key may be
* corrupted due to overlapping key fields.
*/
if
(
attrs
&
(
1
<<
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4
)
&&
key
->
eth
.
type
!=
htons
(
ETH_P_IP
))
return
-
EINVAL
;
if
(
attrs
&
(
1
<<
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6
)
&&
(
key
->
eth
.
type
!=
htons
(
ETH_P_IPV6
)
||
sw_flow_key_is_nd
(
key
)))
return
-
EINVAL
;
return
0
;
}
net/openvswitch/flow.h
View file @
a507c346
/*
* Copyright (c) 2007-201
4
Nicira, Inc.
* Copyright (c) 2007-201
7
Nicira, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
...
...
@@ -85,6 +85,11 @@ struct sw_flow_key {
struct
vlan_head
cvlan
;
__be16
type
;
/* Ethernet frame type. */
}
eth
;
/* Filling a hole of two bytes. */
u8
ct_state
;
u8
ct_orig_proto
;
/* CT original direction tuple IP
* protocol.
*/
union
{
struct
{
__be32
top_lse
;
/* top label stack entry */
...
...
@@ -96,6 +101,7 @@ struct sw_flow_key {
u8
frag
;
/* One of OVS_FRAG_TYPE_*. */
}
ip
;
};
u16
ct_zone
;
/* Conntrack zone. */
struct
{
__be16
src
;
/* TCP/UDP/SCTP source port. */
__be16
dst
;
/* TCP/UDP/SCTP destination port. */
...
...
@@ -107,10 +113,16 @@ struct sw_flow_key {
__be32
src
;
/* IP source address. */
__be32
dst
;
/* IP destination address. */
}
addr
;
struct
{
u8
sha
[
ETH_ALEN
];
/* ARP source hardware address. */
u8
tha
[
ETH_ALEN
];
/* ARP target hardware address. */
}
arp
;
union
{
struct
{
__be32
src
;
__be32
dst
;
}
ct_orig
;
/* Conntrack original direction fields. */
struct
{
u8
sha
[
ETH_ALEN
];
/* ARP source hardware address. */
u8
tha
[
ETH_ALEN
];
/* ARP target hardware address. */
}
arp
;
};
}
ipv4
;
struct
{
struct
{
...
...
@@ -118,23 +130,40 @@ struct sw_flow_key {
struct
in6_addr
dst
;
/* IPv6 destination address. */
}
addr
;
__be32
label
;
/* IPv6 flow label. */
struct
{
struct
in6_addr
target
;
/* ND target address. */
u8
sll
[
ETH_ALEN
];
/* ND source link layer address. */
u8
tll
[
ETH_ALEN
];
/* ND target link layer address. */
}
nd
;
union
{
struct
{
struct
in6_addr
src
;
struct
in6_addr
dst
;
}
ct_orig
;
/* Conntrack original direction fields. */
struct
{
struct
in6_addr
target
;
/* ND target address. */
u8
sll
[
ETH_ALEN
];
/* ND source link layer address. */
u8
tll
[
ETH_ALEN
];
/* ND target link layer address. */
}
nd
;
};
}
ipv6
;
};
struct
{
/* Connection tracking fields. */
u16
zone
;
/* Connection tracking fields not packed above. */
struct
{
__be16
src
;
/* CT orig tuple tp src port. */
__be16
dst
;
/* CT orig tuple tp dst port. */
}
orig_tp
;
u32
mark
;
u8
state
;
struct
ovs_key_ct_labels
labels
;
}
ct
;
}
__aligned
(
BITS_PER_LONG
/
8
);
/* Ensure that we can do comparisons as longs. */
static
inline
bool
sw_flow_key_is_nd
(
const
struct
sw_flow_key
*
key
)
{
return
key
->
eth
.
type
==
htons
(
ETH_P_IPV6
)
&&
key
->
ip
.
proto
==
NEXTHDR_ICMP
&&
key
->
tp
.
dst
==
0
&&
(
key
->
tp
.
src
==
htons
(
NDISC_NEIGHBOUR_SOLICITATION
)
||
key
->
tp
.
src
==
htons
(
NDISC_NEIGHBOUR_ADVERTISEMENT
));
}
struct
sw_flow_key_range
{
unsigned
short
int
start
;
unsigned
short
int
end
;
...
...
net/openvswitch/flow_netlink.c
View file @
a507c346
...
...
@@ -129,7 +129,9 @@ static bool match_validate(const struct sw_flow_match *match,
/* The following mask attributes allowed only if they
* pass the validation tests. */
mask_allowed
&=
~
((
1
<<
OVS_KEY_ATTR_IPV4
)
|
(
1
<<
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4
)
|
(
1
<<
OVS_KEY_ATTR_IPV6
)
|
(
1
<<
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6
)
|
(
1
<<
OVS_KEY_ATTR_TCP
)
|
(
1
<<
OVS_KEY_ATTR_TCP_FLAGS
)
|
(
1
<<
OVS_KEY_ATTR_UDP
)
...
...
@@ -161,8 +163,10 @@ static bool match_validate(const struct sw_flow_match *match,
if
(
match
->
key
->
eth
.
type
==
htons
(
ETH_P_IP
))
{
key_expected
|=
1
<<
OVS_KEY_ATTR_IPV4
;
if
(
match
->
mask
&&
(
match
->
mask
->
key
.
eth
.
type
==
htons
(
0xffff
)))
if
(
match
->
mask
&&
match
->
mask
->
key
.
eth
.
type
==
htons
(
0xffff
))
{
mask_allowed
|=
1
<<
OVS_KEY_ATTR_IPV4
;
mask_allowed
|=
1
<<
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4
;
}
if
(
match
->
key
->
ip
.
frag
!=
OVS_FRAG_TYPE_LATER
)
{
if
(
match
->
key
->
ip
.
proto
==
IPPROTO_UDP
)
{
...
...
@@ -196,8 +200,10 @@ static bool match_validate(const struct sw_flow_match *match,
if
(
match
->
key
->
eth
.
type
==
htons
(
ETH_P_IPV6
))
{
key_expected
|=
1
<<
OVS_KEY_ATTR_IPV6
;
if
(
match
->
mask
&&
(
match
->
mask
->
key
.
eth
.
type
==
htons
(
0xffff
)))
if
(
match
->
mask
&&
match
->
mask
->
key
.
eth
.
type
==
htons
(
0xffff
))
{
mask_allowed
|=
1
<<
OVS_KEY_ATTR_IPV6
;
mask_allowed
|=
1
<<
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6
;
}
if
(
match
->
key
->
ip
.
frag
!=
OVS_FRAG_TYPE_LATER
)
{
if
(
match
->
key
->
ip
.
proto
==
IPPROTO_UDP
)
{
...
...
@@ -230,6 +236,12 @@ static bool match_validate(const struct sw_flow_match *match,
htons
(
NDISC_NEIGHBOUR_SOLICITATION
)
||
match
->
key
->
tp
.
src
==
htons
(
NDISC_NEIGHBOUR_ADVERTISEMENT
))
{
key_expected
|=
1
<<
OVS_KEY_ATTR_ND
;
/* Original direction conntrack tuple
* uses the same space as the ND fields
* in the key, so both are not allowed
* at the same time.
*/
mask_allowed
&=
~
(
1ULL
<<
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6
);
if
(
match
->
mask
&&
(
match
->
mask
->
key
.
tp
.
src
==
htons
(
0xff
)))
mask_allowed
|=
1
<<
OVS_KEY_ATTR_ND
;
}
...
...
@@ -282,7 +294,7 @@ size_t ovs_key_attr_size(void)
/* Whenever adding new OVS_KEY_ FIELDS, we should consider
* updating this function.
*/
BUILD_BUG_ON
(
OVS_KEY_ATTR_TUNNEL_INFO
!=
2
6
);
BUILD_BUG_ON
(
OVS_KEY_ATTR_TUNNEL_INFO
!=
2
8
);
return
nla_total_size
(
4
)
/* OVS_KEY_ATTR_PRIORITY */
+
nla_total_size
(
0
)
/* OVS_KEY_ATTR_TUNNEL */
...
...
@@ -295,6 +307,7 @@ size_t ovs_key_attr_size(void)
+
nla_total_size
(
2
)
/* OVS_KEY_ATTR_CT_ZONE */
+
nla_total_size
(
4
)
/* OVS_KEY_ATTR_CT_MARK */
+
nla_total_size
(
16
)
/* OVS_KEY_ATTR_CT_LABELS */
+
nla_total_size
(
40
)
/* OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6 */
+
nla_total_size
(
12
)
/* OVS_KEY_ATTR_ETHERNET */
+
nla_total_size
(
2
)
/* OVS_KEY_ATTR_ETHERTYPE */
+
nla_total_size
(
4
)
/* OVS_KEY_ATTR_VLAN */
...
...
@@ -355,6 +368,10 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
[
OVS_KEY_ATTR_CT_ZONE
]
=
{
.
len
=
sizeof
(
u16
)
},
[
OVS_KEY_ATTR_CT_MARK
]
=
{
.
len
=
sizeof
(
u32
)
},
[
OVS_KEY_ATTR_CT_LABELS
]
=
{
.
len
=
sizeof
(
struct
ovs_key_ct_labels
)
},
[
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4
]
=
{
.
len
=
sizeof
(
struct
ovs_key_ct_tuple_ipv4
)
},
[
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6
]
=
{
.
len
=
sizeof
(
struct
ovs_key_ct_tuple_ipv6
)
},
};
static
bool
check_attr_len
(
unsigned
int
attr_len
,
unsigned
int
expected_len
)
...
...
@@ -430,9 +447,8 @@ static int parse_flow_mask_nlattrs(const struct nlattr *attr,
return
__parse_flow_nlattrs
(
attr
,
a
,
attrsp
,
log
,
true
);
}
static
int
parse_flow_nlattrs
(
const
struct
nlattr
*
attr
,
const
struct
nlattr
*
a
[],
u64
*
attrsp
,
bool
log
)
int
parse_flow_nlattrs
(
const
struct
nlattr
*
attr
,
const
struct
nlattr
*
a
[],
u64
*
attrsp
,
bool
log
)
{
return
__parse_flow_nlattrs
(
attr
,
a
,
attrsp
,
log
,
false
);
}
...
...
@@ -1056,14 +1072,14 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
return
-
EINVAL
;
}
SW_FLOW_KEY_PUT
(
match
,
ct
.
state
,
ct_state
,
is_mask
);
SW_FLOW_KEY_PUT
(
match
,
ct
_
state
,
ct_state
,
is_mask
);
*
attrs
&=
~
(
1ULL
<<
OVS_KEY_ATTR_CT_STATE
);
}
if
(
*
attrs
&
(
1
<<
OVS_KEY_ATTR_CT_ZONE
)
&&
ovs_ct_verify
(
net
,
OVS_KEY_ATTR_CT_ZONE
))
{
u16
ct_zone
=
nla_get_u16
(
a
[
OVS_KEY_ATTR_CT_ZONE
]);
SW_FLOW_KEY_PUT
(
match
,
ct
.
zone
,
ct_zone
,
is_mask
);
SW_FLOW_KEY_PUT
(
match
,
ct
_
zone
,
ct_zone
,
is_mask
);
*
attrs
&=
~
(
1ULL
<<
OVS_KEY_ATTR_CT_ZONE
);
}
if
(
*
attrs
&
(
1
<<
OVS_KEY_ATTR_CT_MARK
)
&&
...
...
@@ -1082,6 +1098,34 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
sizeof
(
*
cl
),
is_mask
);
*
attrs
&=
~
(
1ULL
<<
OVS_KEY_ATTR_CT_LABELS
);
}
if
(
*
attrs
&
(
1ULL
<<
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4
))
{
const
struct
ovs_key_ct_tuple_ipv4
*
ct
;
ct
=
nla_data
(
a
[
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4
]);
SW_FLOW_KEY_PUT
(
match
,
ipv4
.
ct_orig
.
src
,
ct
->
ipv4_src
,
is_mask
);
SW_FLOW_KEY_PUT
(
match
,
ipv4
.
ct_orig
.
dst
,
ct
->
ipv4_dst
,
is_mask
);
SW_FLOW_KEY_PUT
(
match
,
ct
.
orig_tp
.
src
,
ct
->
src_port
,
is_mask
);
SW_FLOW_KEY_PUT
(
match
,
ct
.
orig_tp
.
dst
,
ct
->
dst_port
,
is_mask
);
SW_FLOW_KEY_PUT
(
match
,
ct_orig_proto
,
ct
->
ipv4_proto
,
is_mask
);
*
attrs
&=
~
(
1ULL
<<
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV4
);
}
if
(
*
attrs
&
(
1ULL
<<
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6
))
{
const
struct
ovs_key_ct_tuple_ipv6
*
ct
;
ct
=
nla_data
(
a
[
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6
]);
SW_FLOW_KEY_MEMCPY
(
match
,
ipv6
.
ct_orig
.
src
,
&
ct
->
ipv6_src
,
sizeof
(
match
->
key
->
ipv6
.
ct_orig
.
src
),
is_mask
);
SW_FLOW_KEY_MEMCPY
(
match
,
ipv6
.
ct_orig
.
dst
,
&
ct
->
ipv6_dst
,
sizeof
(
match
->
key
->
ipv6
.
ct_orig
.
dst
),
is_mask
);
SW_FLOW_KEY_PUT
(
match
,
ct
.
orig_tp
.
src
,
ct
->
src_port
,
is_mask
);
SW_FLOW_KEY_PUT
(
match
,
ct
.
orig_tp
.
dst
,
ct
->
dst_port
,
is_mask
);
SW_FLOW_KEY_PUT
(
match
,
ct_orig_proto
,
ct
->
ipv6_proto
,
is_mask
);
*
attrs
&=
~
(
1ULL
<<
OVS_KEY_ATTR_CT_ORIG_TUPLE_IPV6
);
}
/* For layer 3 packets the Ethernet type is provided
* and treated as metadata but no MAC addresses are provided.
...
...
@@ -1493,9 +1537,12 @@ u32 ovs_nla_get_ufid_flags(const struct nlattr *attr)
/**
* ovs_nla_get_flow_metadata - parses Netlink attributes into a flow key.
* @key: Receives extracted in_port, priority, tun_key and skb_mark.
* @attr: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute
* sequence.
* @net: Network namespace.
* @key: Receives extracted in_port, priority, tun_key, skb_mark and conntrack
* metadata.
* @a: Array of netlink attributes holding parsed %OVS_KEY_ATTR_* Netlink
* attributes.
* @attrs: Bit mask for the netlink attributes included in @a.
* @log: Boolean to allow kernel error logging. Normally true, but when
* probing for feature compatibility this should be passed in as false to
* suppress unnecessary error logging.
...
...
@@ -1504,25 +1551,26 @@ u32 ovs_nla_get_ufid_flags(const struct nlattr *attr)
* take the same form accepted by flow_from_nlattrs(), but only enough of it to
* get the metadata, that is, the parts of the flow key that cannot be
* extracted from the packet itself.
*
* This must be called before the packet key fields are filled in 'key'.
*/
int
ovs_nla_get_flow_metadata
(
struct
net
*
net
,
const
struct
nlattr
*
attr
,
struct
sw_flow_key
*
key
,
bool
log
)
int
ovs_nla_get_flow_metadata
(
struct
net
*
net
,
const
struct
nlattr
*
a
[
OVS_KEY_ATTR_MAX
+
1
]
,
u64
attrs
,
struct
sw_flow_key
*
key
,
bool
log
)
{
const
struct
nlattr
*
a
[
OVS_KEY_ATTR_MAX
+
1
];
struct
sw_flow_match
match
;
u64
attrs
=
0
;
int
err
;
err
=
parse_flow_nlattrs
(
attr
,
a
,
&
attrs
,
log
);
if
(
err
)
return
-
EINVAL
;
memset
(
&
match
,
0
,
sizeof
(
match
));
match
.
key
=
key
;
key
->
ct_state
=
0
;
key
->
ct_zone
=
0
;
key
->
ct_orig_proto
=
0
;
memset
(
&
key
->
ct
,
0
,
sizeof
(
key
->
ct
));
memset
(
&
key
->
ipv4
.
ct_orig
,
0
,
sizeof
(
key
->
ipv4
.
ct_orig
));
memset
(
&
key
->
ipv6
.
ct_orig
,
0
,
sizeof
(
key
->
ipv6
.
ct_orig
));
key
->
phy
.
in_port
=
DP_MAX_PORTS
;
return
metadata_from_nlattrs
(
net
,
&
match
,
&
attrs
,
a
,
false
,
log
);
...
...
@@ -1584,7 +1632,7 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey,
if
(
nla_put_u32
(
skb
,
OVS_KEY_ATTR_SKB_MARK
,
output
->
phy
.
skb_mark
))
goto
nla_put_failure
;
if
(
ovs_ct_put_key
(
output
,
skb
))
if
(
ovs_ct_put_key
(
swkey
,
output
,
skb
))
goto
nla_put_failure
;
if
(
ovs_key_mac_proto
(
swkey
)
==
MAC_PROTO_ETHERNET
)
{
...
...
net/openvswitch/flow_netlink.h
View file @
a507c346
...
...
@@ -46,8 +46,11 @@ void ovs_match_init(struct sw_flow_match *match,
int
ovs_nla_put_key
(
const
struct
sw_flow_key
*
,
const
struct
sw_flow_key
*
,
int
attr
,
bool
is_mask
,
struct
sk_buff
*
);
int
ovs_nla_get_flow_metadata
(
struct
net
*
,
const
struct
nlattr
*
,
struct
sw_flow_key
*
,
bool
log
);
int
parse_flow_nlattrs
(
const
struct
nlattr
*
attr
,
const
struct
nlattr
*
a
[],
u64
*
attrsp
,
bool
log
);
int
ovs_nla_get_flow_metadata
(
struct
net
*
net
,
const
struct
nlattr
*
a
[
OVS_KEY_ATTR_MAX
+
1
],
u64
attrs
,
struct
sw_flow_key
*
key
,
bool
log
);
int
ovs_nla_put_identifier
(
const
struct
sw_flow
*
flow
,
struct
sk_buff
*
skb
);
int
ovs_nla_put_masked_key
(
const
struct
sw_flow
*
flow
,
struct
sk_buff
*
skb
);
...
...
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