Skip to content

Commit beb75a4

Browse files
JanScheurichzoltanbalogheth
authored andcommitted
userspace: Switching of L3 packets in L2 pipeline
Ports have a new layer3 attribute if they send/receive L3 packets. The packet_type included in structs dp_packet and flow is considered in ofproto-dpif. The classical L2 match fields (dl_src, dl_dst, dl_type, and vlan_tci, vlan_vid, vlan_pcp) now have Ethernet as pre-requisite. A dummy ethernet header is pushed to L3 packets received from L3 ports before the the pipeline processing starts. The ethernet header is popped before sending a packet to a L3 port. For datapath ports that can receive L2 or L3 packets, the packet_type becomes part of the flow key for datapath flows and is handled appropriately in dpif-netdev. In the 'else' branch in flow_put_on_pmd() function, the additional check flow_equal(&match.flow, &netdev_flow->flow) was removed, as a) the dpcls lookup is sufficient to uniquely identify a flow and b) it caused false negatives because the flow in netdev->flow may not properly masked. In dpif_netdev_flow_put() we now use the same method for constructing the netdev_flow_key as the one used when adding the flow to the dplcs to make sure these always match. The function netdev_flow_key_from_flow() used so far was not only inefficient but sometimes caused mismatches and subsequent flow update failures. The kernel datapath does not support the packet_type match field. Instead it encodes the packet type implictly by the presence or absence of the Ethernet attribute in the flow key and mask. This patch filters the PACKET_TYPE attribute out of netlink flow key and mask to be sent to the kernel datapath. Signed-off-by: Lorand Jakab <lojakab@cisco.com> Signed-off-by: Simon Horman <simon.horman@netronome.com> Signed-off-by: Jiri Benc <jbenc@redhat.com> Signed-off-by: Yi Yang <yi.y.yang@intel.com> Signed-off-by: Jan Scheurich <jan.scheurich@ericsson.com> Co-authored-by: Zoltan Balogh <zoltan.balogh@ericsson.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
1 parent 5978c2e commit beb75a4

23 files changed

Lines changed: 337 additions & 119 deletions

‎build-aux/extract-ofp-fields‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ FORMATTING = {"decimal": ("MFS_DECIMAL", 1, 8),
3939
"TCP flags": ("MFS_TCP_FLAGS", 2, 2)}
4040

4141
PREREQS = {"none": "MFP_NONE",
42+
"Ethernet": "MFP_ETHERNET",
4243
"ARP": "MFP_ARP",
4344
"VLAN VID": "MFP_VLAN_VID",
4445
"IPv4": "MFP_IPV4",

‎datapath/linux/compat/include/linux/openvswitch.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,8 @@ enum ovs_key_attr {
363363
/* Only used within kernel data path. */
364364
OVS_KEY_ATTR_TUNNEL_INFO, /* struct ovs_tunnel_info */
365365
#endif
366+
367+
OVS_KEY_ATTR_PACKET_TYPE, /* be32 packet type */
366368
__OVS_KEY_ATTR_MAX
367369
};
368370

‎include/openvswitch/match.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ void match_set_ct_ipv6_dst(struct match *, const struct in6_addr *);
116116
void match_set_ct_ipv6_dst_masked(struct match *, const struct in6_addr *,
117117
const struct in6_addr *);
118118

119+
void match_set_packet_type(struct match *, ovs_be32 packet_type);
119120
void match_set_skb_priority(struct match *, uint32_t skb_priority);
120121
void match_set_dl_type(struct match *, ovs_be16);
121122
void match_set_dl_src(struct match *, const struct eth_addr );

‎include/openvswitch/meta-flow.h‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,7 @@ enum OVS_PACKED_ENUM mf_field_id {
986986
* Type: MAC.
987987
* Maskable: bitwise.
988988
* Formatting: Ethernet.
989-
* Prerequisites: none.
989+
* Prerequisites: Ethernet.
990990
* Access: read/write.
991991
* NXM: NXM_OF_ETH_SRC(2) since v1.1.
992992
* OXM: OXM_OF_ETH_SRC(4) since OF1.2 and v1.7.
@@ -1002,7 +1002,7 @@ enum OVS_PACKED_ENUM mf_field_id {
10021002
* Type: MAC.
10031003
* Maskable: bitwise.
10041004
* Formatting: Ethernet.
1005-
* Prerequisites: none.
1005+
* Prerequisites: Ethernet.
10061006
* Access: read/write.
10071007
* NXM: NXM_OF_ETH_DST(1) since v1.1.
10081008
* OXM: OXM_OF_ETH_DST(3) since OF1.2 and v1.7.
@@ -1021,7 +1021,7 @@ enum OVS_PACKED_ENUM mf_field_id {
10211021
* Type: be16.
10221022
* Maskable: no.
10231023
* Formatting: hexadecimal.
1024-
* Prerequisites: none.
1024+
* Prerequisites: Ethernet.
10251025
* Access: read-only.
10261026
* NXM: NXM_OF_ETH_TYPE(3) since v1.1.
10271027
* OXM: OXM_OF_ETH_TYPE(5) since OF1.2 and v1.7.
@@ -1051,7 +1051,7 @@ enum OVS_PACKED_ENUM mf_field_id {
10511051
* Type: be16.
10521052
* Maskable: bitwise.
10531053
* Formatting: hexadecimal.
1054-
* Prerequisites: none.
1054+
* Prerequisites: Ethernet.
10551055
* Access: read/write.
10561056
* NXM: NXM_OF_VLAN_TCI(4) since v1.1.
10571057
* OXM: none.
@@ -1067,7 +1067,7 @@ enum OVS_PACKED_ENUM mf_field_id {
10671067
* Type: be16 (low 12 bits).
10681068
* Maskable: no.
10691069
* Formatting: decimal.
1070-
* Prerequisites: none.
1070+
* Prerequisites: Ethernet.
10711071
* Access: read/write.
10721072
* NXM: none.
10731073
* OXM: none.
@@ -1085,7 +1085,7 @@ enum OVS_PACKED_ENUM mf_field_id {
10851085
* Type: be16 (low 12 bits).
10861086
* Maskable: bitwise.
10871087
* Formatting: decimal.
1088-
* Prerequisites: none.
1088+
* Prerequisites: Ethernet.
10891089
* Access: read/write.
10901090
* NXM: none.
10911091
* OXM: OXM_OF_VLAN_VID(6) since OF1.2 and v1.7.
@@ -1101,7 +1101,7 @@ enum OVS_PACKED_ENUM mf_field_id {
11011101
* Type: u8 (low 3 bits).
11021102
* Maskable: no.
11031103
* Formatting: decimal.
1104-
* Prerequisites: none.
1104+
* Prerequisites: Ethernet.
11051105
* Access: read/write.
11061106
* NXM: none.
11071107
* OXM: none.
@@ -1809,6 +1809,7 @@ enum OVS_PACKED_ENUM mf_prereqs {
18091809
MFP_NONE,
18101810

18111811
/* L2 requirements. */
1812+
MFP_ETHERNET,
18121813
MFP_ARP,
18131814
MFP_VLAN_VID,
18141815
MFP_IPV4,

‎lib/dpif-netdev.c‎

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1918,24 +1918,6 @@ netdev_flow_key_clone(struct netdev_flow_key *dst,
19181918
offsetof(struct netdev_flow_key, mf) + src->len);
19191919
}
19201920

1921-
/* Slow. */
1922-
static void
1923-
netdev_flow_key_from_flow(struct netdev_flow_key *dst,
1924-
const struct flow *src)
1925-
{
1926-
struct dp_packet packet;
1927-
uint64_t buf_stub[512 / 8];
1928-
1929-
dp_packet_use_stub(&packet, buf_stub, sizeof buf_stub);
1930-
pkt_metadata_from_flow(&packet.md, src);
1931-
flow_compose(&packet, src);
1932-
miniflow_extract(&packet, &dst->mf);
1933-
dp_packet_uninit(&packet);
1934-
1935-
dst->len = netdev_flow_key_size(miniflow_n_values(&dst->mf));
1936-
dst->hash = 0; /* Not computed yet. */
1937-
}
1938-
19391921
/* Initialize a netdev_flow_key 'mask' from 'match'. */
19401922
static inline void
19411923
netdev_flow_mask_init(struct netdev_flow_key *mask,
@@ -2411,7 +2393,7 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd,
24112393
cmap_insert(&pmd->flow_table, CONST_CAST(struct cmap_node *, &flow->node),
24122394
dp_netdev_flow_hash(&flow->ufid));
24132395

2414-
if (OVS_UNLIKELY(VLOG_IS_DBG_ENABLED())) {
2396+
if (OVS_UNLIKELY(!VLOG_DROP_DBG((&upcall_rl)))) {
24152397
struct ds ds = DS_EMPTY_INITIALIZER;
24162398
struct ofpbuf key_buf, mask_buf;
24172399
struct odp_flow_key_parms odp_parms = {
@@ -2436,10 +2418,21 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd,
24362418
ds_put_cstr(&ds, ", actions:");
24372419
format_odp_actions(&ds, actions, actions_len);
24382420

2439-
VLOG_DBG_RL(&upcall_rl, "%s", ds_cstr(&ds));
2421+
VLOG_DBG("%s", ds_cstr(&ds));
24402422

24412423
ofpbuf_uninit(&key_buf);
24422424
ofpbuf_uninit(&mask_buf);
2425+
2426+
/* Add a printout of the actual match installed. */
2427+
struct match m;
2428+
ds_clear(&ds);
2429+
ds_put_cstr(&ds, "flow match: ");
2430+
miniflow_expand(&flow->cr.flow.mf, &m.flow);
2431+
miniflow_expand(&flow->cr.mask->mf, &m.wc.masks);
2432+
match_format(&m, NULL, &ds, OFP_DEFAULT_PRIORITY);
2433+
2434+
VLOG_DBG("%s", ds_cstr(&ds));
2435+
24432436
ds_destroy(&ds);
24442437
}
24452438

@@ -2476,8 +2469,7 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd,
24762469
error = ENOENT;
24772470
}
24782471
} else {
2479-
if (put->flags & DPIF_FP_MODIFY
2480-
&& flow_equal(&match->flow, &netdev_flow->flow)) {
2472+
if (put->flags & DPIF_FP_MODIFY) {
24812473
struct dp_netdev_actions *new_actions;
24822474
struct dp_netdev_actions *old_actions;
24832475

@@ -2519,7 +2511,7 @@ static int
25192511
dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
25202512
{
25212513
struct dp_netdev *dp = get_dp_netdev(dpif);
2522-
struct netdev_flow_key key;
2514+
struct netdev_flow_key key, mask;
25232515
struct dp_netdev_pmd_thread *pmd;
25242516
struct match match;
25252517
ovs_u128 ufid;
@@ -2548,9 +2540,10 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
25482540
}
25492541

25502542
/* Must produce a netdev_flow_key for lookup.
2551-
* This interface is no longer performance critical, since it is not used
2552-
* for upcall processing any more. */
2553-
netdev_flow_key_from_flow(&key, &match.flow);
2543+
* Use the same method as employed to create the key when adding
2544+
* the flow to the dplcs to make sure they match. */
2545+
netdev_flow_mask_init(&mask, &match);
2546+
netdev_flow_key_init_masked(&key, &match.flow, &mask);
25542547

25552548
if (put->pmd_id == PMD_ID_NULL) {
25562549
if (cmap_count(&dp->poll_threads) == 0) {

‎lib/dpif-netlink.c‎

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,7 +1636,7 @@ dpif_netlink_encode_execute(int dp_ifindex, const struct dpif_execute *d_exec,
16361636
dp_packet_size(d_exec->packet));
16371637

16381638
key_ofs = nl_msg_start_nested(buf, OVS_PACKET_ATTR_KEY);
1639-
odp_key_from_pkt_metadata(buf, &d_exec->packet->md);
1639+
odp_key_from_dp_packet(buf, d_exec->packet);
16401640
nl_msg_end_nested(buf, key_ofs);
16411641

16421642
nl_msg_put_unspec(buf, OVS_PACKET_ATTR_ACTIONS,
@@ -2984,6 +2984,38 @@ dpif_netlink_flow_from_ofpbuf(struct dpif_netlink_flow *flow,
29842984
return 0;
29852985
}
29862986

2987+
2988+
/*
2989+
* If PACKET_TYPE attribute is present in 'data', it filters PACKET_TYPE out,
2990+
* then puts 'data' to 'buf'.
2991+
*/
2992+
static void
2993+
put_exclude_packet_type(struct ofpbuf *buf, uint16_t type,
2994+
const struct nlattr *data, uint16_t data_len)
2995+
{
2996+
const struct nlattr *packet_type;
2997+
2998+
packet_type = nl_attr_find__(data, data_len, OVS_KEY_ATTR_PACKET_TYPE);
2999+
3000+
if (packet_type) {
3001+
/* exclude PACKET_TYPE Netlink attribute. */
3002+
ovs_assert(NLA_ALIGN(packet_type->nla_len) == NL_A_U32_SIZE);
3003+
size_t packet_type_len = NL_A_U32_SIZE;
3004+
size_t first_chunk_size = (uint8_t *)packet_type - (uint8_t *)data;
3005+
size_t second_chunk_size = data_len - first_chunk_size
3006+
- packet_type_len;
3007+
uint8_t *first_attr = NULL;
3008+
struct nlattr *next_attr = nl_attr_next(packet_type);
3009+
3010+
first_attr = nl_msg_put_unspec_uninit(buf, type,
3011+
data_len - packet_type_len);
3012+
memcpy(first_attr, data, first_chunk_size);
3013+
memcpy(first_attr + first_chunk_size, next_attr, second_chunk_size);
3014+
} else {
3015+
nl_msg_put_unspec(buf, type, data, data_len);
3016+
}
3017+
}
3018+
29873019
/* Appends to 'buf' (which must initially be empty) a "struct ovs_header"
29883020
* followed by Netlink attributes corresponding to 'flow'. */
29893021
static void
@@ -3010,13 +3042,12 @@ dpif_netlink_flow_to_ofpbuf(const struct dpif_netlink_flow *flow,
30103042
}
30113043
if (!flow->ufid_terse || !flow->ufid_present) {
30123044
if (flow->key_len) {
3013-
nl_msg_put_unspec(buf, OVS_FLOW_ATTR_KEY,
3014-
flow->key, flow->key_len);
3045+
put_exclude_packet_type(buf, OVS_FLOW_ATTR_KEY, flow->key,
3046+
flow->key_len);
30153047
}
3016-
30173048
if (flow->mask_len) {
3018-
nl_msg_put_unspec(buf, OVS_FLOW_ATTR_MASK,
3019-
flow->mask, flow->mask_len);
3049+
put_exclude_packet_type(buf, OVS_FLOW_ATTR_MASK, flow->mask,
3050+
flow->mask_len);
30203051
}
30213052
if (flow->actions || flow->actions_len) {
30223053
nl_msg_put_unspec(buf, OVS_FLOW_ATTR_ACTIONS,

‎lib/dpif.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1765,7 +1765,7 @@ log_execute_message(struct dpif *dpif, const struct dpif_execute *execute,
17651765
packet = ofp_packet_to_string(dp_packet_data(execute->packet),
17661766
dp_packet_size(execute->packet),
17671767
execute->packet->packet_type);
1768-
odp_key_from_pkt_metadata(&md, &execute->packet->md);
1768+
odp_key_from_dp_packet(&md, execute->packet);
17691769
ds_put_format(&ds, "%s: %sexecute ",
17701770
dpif_name(dpif),
17711771
(subexecute ? "sub-"

‎lib/match.c‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,13 @@ match_set_ct_ipv6_dst_masked(struct match *match, const struct in6_addr *dst,
476476
match->wc.masks.ct_ipv6_dst = *mask;
477477
}
478478

479+
void
480+
match_set_packet_type(struct match *match, ovs_be32 packet_type)
481+
{
482+
match->flow.packet_type = packet_type;
483+
match->wc.masks.packet_type = OVS_BE32_MAX;
484+
}
485+
479486
void
480487
match_set_dl_type(struct match *match, ovs_be16 dl_type)
481488
{
@@ -1249,6 +1256,22 @@ match_format(const struct match *match,
12491256
format_be16_masked(s, "ct_tp_dst", f->ct_tp_dst, wc->masks.ct_tp_dst);
12501257
}
12511258

1259+
if (wc->masks.packet_type) {
1260+
if (pt_ns_type_be(wc->masks.packet_type) == 0) {
1261+
ds_put_format(s, "packet_type=(%u,*),",
1262+
pt_ns(f->packet_type));
1263+
} else if (pt_ns_type_be(wc->masks.packet_type) == OVS_BE16_MAX) {
1264+
ds_put_format(s, "packet_type=(%u,%#"PRIx16"),",
1265+
pt_ns(f->packet_type),
1266+
pt_ns_type(f->packet_type));
1267+
} else {
1268+
ds_put_format(s, "packet_type=(%u,%#"PRIx16"/%#"PRIx16"),",
1269+
pt_ns(f->packet_type),
1270+
pt_ns_type(f->packet_type),
1271+
pt_ns_type(wc->masks.packet_type));
1272+
}
1273+
}
1274+
12521275
if (wc->masks.dl_type) {
12531276
skip_type = true;
12541277
if (f->dl_type == htons(ETH_TYPE_IP)) {
@@ -1361,8 +1384,10 @@ match_format(const struct match *match,
13611384
ntohs(wc->masks.vlans[i].tci));
13621385
}
13631386
}
1387+
13641388
format_eth_masked(s, "dl_src", f->dl_src, wc->masks.dl_src);
13651389
format_eth_masked(s, "dl_dst", f->dl_dst, wc->masks.dl_dst);
1390+
13661391
if (!skip_type && wc->masks.dl_type) {
13671392
ds_put_format(s, "%sdl_type=%s0x%04"PRIx16",",
13681393
colors.param, colors.end, ntohs(f->dl_type));

‎lib/meta-flow.c‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,8 @@ mf_are_prereqs_ok__(const struct mf_field *mf, const struct flow *flow,
404404
switch (mf->prereqs) {
405405
case MFP_NONE:
406406
return true;
407+
case MFP_ETHERNET:
408+
return is_ethernet(flow, wc);
407409
case MFP_ARP:
408410
return (flow->dl_type == htons(ETH_TYPE_ARP) ||
409411
flow->dl_type == htons(ETH_TYPE_RARP));

‎lib/netdev-vport.c‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,13 @@ netdev_vport_is_patch(const struct netdev *netdev)
9797
bool
9898
netdev_vport_is_layer3(const struct netdev *dev)
9999
{
100-
const char *type = netdev_get_type(dev);
100+
if (is_vport_class(netdev_get_class(dev))) {
101+
struct netdev_vport *vport = netdev_vport_cast(dev);
102+
103+
return vport->tnl_cfg.is_layer3;
104+
}
101105

102-
return (!strcmp("lisp", type));
106+
return false;
103107
}
104108

105109
static bool

0 commit comments

Comments
 (0)