diff --git a/lib/dpctl.c b/lib/dpctl.c index 90ea62efd87..4f1e443f266 100644 --- a/lib/dpctl.c +++ b/lib/dpctl.c @@ -771,7 +771,7 @@ dpctl_dump_dps(int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, static void format_dpif_flow(struct ds *ds, const struct dpif_flow *f, struct hmap *ports, - char *type, struct dpctl_params *dpctl_p) + struct dpctl_params *dpctl_p) { if (dpctl_p->verbosity && f->ufid_present) { odp_format_ufid(&f->ufid, ds); @@ -782,9 +782,12 @@ format_dpif_flow(struct ds *ds, const struct dpif_flow *f, struct hmap *ports, ds_put_cstr(ds, ", "); dpif_flow_stats_format(&f->stats, ds); - if (dpctl_p->verbosity && !type && f->offloaded) { + if (dpctl_p->verbosity && f->attrs.offloaded) { ds_put_cstr(ds, ", offloaded:yes"); } + if (dpctl_p->verbosity && f->attrs.dp_layer) { + ds_put_format(ds, ", dp:%s", f->attrs.dp_layer); + } ds_put_cstr(ds, ", actions:"); format_odp_actions(ds, f->actions, f->actions_len, ports); } @@ -794,6 +797,15 @@ static char *supported_dump_types[] = { "ovs", }; +static bool +flow_passes_type_filter(const struct dpif_flow *f, char *type) +{ + if (!strcmp(type, "offloaded")) { + return f->attrs.offloaded; + } + return true; +} + static struct hmap * dpctl_get_portno_names(struct dpif *dpif, const struct dpctl_params *dpctl_p) { @@ -938,9 +950,10 @@ dpctl_dump_flows(int argc, const char *argv[], struct dpctl_params *dpctl_p) } pmd_id = f.pmd_id; } - format_dpif_flow(&ds, &f, portno_names, type, dpctl_p); - - dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds)); + if (!type || flow_passes_type_filter(&f, type)) { + format_dpif_flow(&ds, &f, portno_names, dpctl_p); + dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds)); + } } dpif_flow_dump_thread_destroy(flow_dump_thread); error = dpif_flow_dump_destroy(flow_dump); @@ -1102,7 +1115,7 @@ dpctl_get_flow(int argc, const char *argv[], struct dpctl_params *dpctl_p) } ds_init(&ds); - format_dpif_flow(&ds, &flow, portno_names, NULL, dpctl_p); + format_dpif_flow(&ds, &flow, portno_names, dpctl_p); dpctl_print(dpctl_p, "%s\n", ds_cstr(&ds)); ds_destroy(&ds); diff --git a/lib/dpctl.man b/lib/dpctl.man index a6917bd0b29..5d987e62daa 100644 --- a/lib/dpctl.man +++ b/lib/dpctl.man @@ -119,9 +119,9 @@ flow. As an example, \fBfilter='tcp,tp_src=100'\fR will match the datapath flow containing '\fBtcp(src=80/0xff00,dst=8080/0xff)\fR'. .IP If \fBtype=\fItype\fR is specified, only displays flows of a specific type. -\fItype\fR can be \fBoffloaded\fR to display only offloaded rules or \fBovs\fR -to display only non-offloaded rules. -By default both offloaded and non-offloaded rules are displayed. +\fItype\fR can be \fBoffloaded\fR to display only rules offloaded to the HW +or \fBovs\fR to display only rules from the OVS tables. +By default all rules are displayed. . .IP "\*(DX\fBadd\-flow\fR [\fIdp\fR] \fIflow actions\fR" .TP diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 1bd10a6ea90..aa9bbd9463a 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -1463,13 +1463,13 @@ dpif_netlink_init_flow_del(struct dpif_netlink *dpif, } enum { - DUMP_OVS_FLOWS_BIT = 0, - DUMP_OFFLOADED_FLOWS_BIT = 1, + DUMP_OVS_FLOWS_BIT = 0, + DUMP_NETDEV_FLOWS_BIT = 1, }; enum { - DUMP_OVS_FLOWS = (1 << DUMP_OVS_FLOWS_BIT), - DUMP_OFFLOADED_FLOWS = (1 << DUMP_OFFLOADED_FLOWS_BIT), + DUMP_OVS_FLOWS = (1 << DUMP_OVS_FLOWS_BIT), + DUMP_NETDEV_FLOWS = (1 << DUMP_NETDEV_FLOWS_BIT), }; struct dpif_netlink_flow_dump { @@ -1495,7 +1495,7 @@ start_netdev_dump(const struct dpif *dpif_, { ovs_mutex_init(&dump->netdev_lock); - if (!(dump->type & DUMP_OFFLOADED_FLOWS)) { + if (!(dump->type & DUMP_NETDEV_FLOWS)) { dump->netdev_dumps_num = 0; dump->netdev_dumps = NULL; return; @@ -1518,7 +1518,7 @@ dpif_netlink_get_dump_type(char *str) { } if ((netdev_is_flow_api_enabled() && !str) || (str && (!strcmp(str, "offloaded") || !strcmp(str, "dpctl")))) { - type |= DUMP_OFFLOADED_FLOWS; + type |= DUMP_NETDEV_FLOWS; } return type; @@ -1656,7 +1656,8 @@ dpif_netlink_flow_to_dpif_flow(struct dpif *dpif, struct dpif_flow *dpif_flow, &dpif_flow->ufid); } dpif_netlink_flow_get_stats(datapath_flow, &dpif_flow->stats); - dpif_flow->offloaded = false; + dpif_flow->attrs.offloaded = false; + dpif_flow->attrs.dp_layer = "ovs"; } /* The design is such that all threads are working together on the first dump @@ -1698,6 +1699,7 @@ dpif_netlink_netdev_match_to_dpif_flow(struct match *match, struct ofpbuf *mask_buf, struct nlattr *actions, struct dpif_flow_stats *stats, + struct dpif_flow_attrs *attrs, ovs_u128 *ufid, struct dpif_flow *flow, bool terse OVS_UNUSED) @@ -1740,7 +1742,7 @@ dpif_netlink_netdev_match_to_dpif_flow(struct match *match, flow->pmd_id = PMD_ID_NULL; - flow->offloaded = true; + memcpy(&flow->attrs, attrs, sizeof *attrs); return 0; } @@ -1772,6 +1774,7 @@ dpif_netlink_flow_dump_next(struct dpif_flow_dump_thread *thread_, struct match match; struct nlattr *actions; struct dpif_flow_stats stats; + struct dpif_flow_attrs attrs; ovs_u128 ufid; bool has_next; @@ -1779,7 +1782,7 @@ dpif_netlink_flow_dump_next(struct dpif_flow_dump_thread *thread_, ofpbuf_use_stack(&act, actbuf, sizeof *actbuf); ofpbuf_use_stack(&mask, maskbuf, sizeof *maskbuf); has_next = netdev_flow_dump_next(netdev_dump, &match, - &actions, &stats, + &actions, &stats, &attrs, &ufid, &thread->nl_flows, &act); @@ -1788,6 +1791,7 @@ dpif_netlink_flow_dump_next(struct dpif_flow_dump_thread *thread_, &key, &mask, actions, &stats, + &attrs, &ufid, f, dump->up.terse); @@ -2055,6 +2059,7 @@ parse_flow_get(struct dpif_netlink *dpif, struct dpif_flow_get *get) struct match match; struct nlattr *actions; struct dpif_flow_stats stats; + struct dpif_flow_attrs attrs; struct ofpbuf buf; uint64_t act_buf[1024 / 8]; struct odputil_keybuf maskbuf; @@ -2065,7 +2070,7 @@ parse_flow_get(struct dpif_netlink *dpif, struct dpif_flow_get *get) ofpbuf_use_stack(&buf, &act_buf, sizeof act_buf); err = netdev_ports_flow_get(dpif->dpif.dpif_class, &match, - &actions, get->ufid, &stats, &buf); + &actions, get->ufid, &stats, &attrs, &buf); if (err) { return err; } @@ -2076,7 +2081,7 @@ parse_flow_get(struct dpif_netlink *dpif, struct dpif_flow_get *get) ofpbuf_use_stack(&act, &actbuf, sizeof actbuf); ofpbuf_use_stack(&mask, &maskbuf, sizeof maskbuf); dpif_netlink_netdev_match_to_dpif_flow(&match, &key, &mask, actions, - &stats, + &stats, &attrs, (ovs_u128 *) get->ufid, dpif_flow, false); diff --git a/lib/dpif.h b/lib/dpif.h index 0534651363b..33d2d0bec33 100644 --- a/lib/dpif.h +++ b/lib/dpif.h @@ -507,6 +507,11 @@ struct dpif_flow_stats { uint16_t tcp_flags; }; +struct dpif_flow_attrs { + bool offloaded; /* True if flow is offloaded to HW. */ + const char *dp_layer; /* DP layer the flow is handled in. */ +}; + void dpif_flow_stats_extract(const struct flow *, const struct dp_packet *packet, long long int used, struct dpif_flow_stats *); void dpif_flow_stats_format(const struct dpif_flow_stats *, struct ds *); @@ -589,7 +594,7 @@ struct dpif_flow { bool ufid_present; /* True if 'ufid' was provided by datapath.*/ unsigned pmd_id; /* Datapath poll mode driver id. */ struct dpif_flow_stats stats; /* Flow statistics. */ - bool offloaded; /* True if flow is offloaded */ + struct dpif_flow_attrs attrs; /* Flow attributes. */ }; int dpif_flow_dump_next(struct dpif_flow_dump_thread *, struct dpif_flow *flows, int max_flows); diff --git a/lib/flow.h b/lib/flow.h index 9de94b2e1c9..5b6585f11d9 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -33,6 +33,7 @@ #include "util.h" struct dpif_flow_stats; +struct dpif_flow_attrs; struct ds; struct flow_wildcards; struct minimask; diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index 5503b79c72d..4da579c1b5e 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -837,7 +837,8 @@ struct netdev_class { * to be pre allocated by the caller. */ bool (*flow_dump_next)(struct netdev_flow_dump *, struct match *, struct nlattr **actions, - struct dpif_flow_stats *stats, ovs_u128 *ufid, + struct dpif_flow_stats *stats, + struct dpif_flow_attrs *attrs, ovs_u128 *ufid, struct ofpbuf *rbuffer, struct ofpbuf *wbuffer); /* Offload the given flow on netdev. @@ -857,7 +858,7 @@ struct netdev_class { * Return 0 if successful, otherwise returns a positive errno value. */ int (*flow_get)(struct netdev *, struct match *, struct nlattr **actions, const ovs_u128 *ufid, struct dpif_flow_stats *, - struct ofpbuf *wbuffer); + struct dpif_flow_attrs *, struct ofpbuf *wbuffer); /* Delete a flow specified by ufid from netdev. * 'stats' is populated according to the rules set out in the description diff --git a/lib/netdev-tc-offloads.c b/lib/netdev-tc-offloads.c index 69d6533e4b3..0d8cc2c82e8 100644 --- a/lib/netdev-tc-offloads.c +++ b/lib/netdev-tc-offloads.c @@ -398,6 +398,7 @@ parse_tc_flower_to_match(struct tc_flower *flower, struct match *match, struct nlattr **actions, struct dpif_flow_stats *stats, + struct dpif_flow_attrs *attrs, struct ofpbuf *buf) { size_t act_off; @@ -565,6 +566,10 @@ parse_tc_flower_to_match(struct tc_flower *flower, stats->used = flower->lastused; } + attrs->offloaded = (flower->offloaded_state == TC_OFFLOADED_STATE_IN_HW) + || (flower->offloaded_state == TC_OFFLOADED_STATE_UNDEFINED); + attrs->dp_layer = "tc"; + return 0; } @@ -573,6 +578,7 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump, struct match *match, struct nlattr **actions, struct dpif_flow_stats *stats, + struct dpif_flow_attrs *attrs, ovs_u128 *ufid, struct ofpbuf *rbuffer, struct ofpbuf *wbuffer) @@ -587,7 +593,7 @@ netdev_tc_flow_dump_next(struct netdev_flow_dump *dump, continue; } - if (parse_tc_flower_to_match(&flower, match, actions, stats, + if (parse_tc_flower_to_match(&flower, match, actions, stats, attrs, wbuffer)) { continue; } @@ -1119,6 +1125,7 @@ netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED, struct nlattr **actions, const ovs_u128 *ufid, struct dpif_flow_stats *stats, + struct dpif_flow_attrs *attrs, struct ofpbuf *buf) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); @@ -1154,7 +1161,7 @@ netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED, } in_port = netdev_ifindex_to_odp_port(ifindex); - parse_tc_flower_to_match(&flower, match, actions, stats, buf); + parse_tc_flower_to_match(&flower, match, actions, stats, attrs, buf); match->wc.masks.in_port.odp_port = u32_to_odp(UINT32_MAX); match->flow.in_port.odp_port = in_port; diff --git a/lib/netdev-tc-offloads.h b/lib/netdev-tc-offloads.h index 317347e2670..ebd8ca88499 100644 --- a/lib/netdev-tc-offloads.h +++ b/lib/netdev-tc-offloads.h @@ -25,6 +25,7 @@ int netdev_tc_flow_dump_destroy(struct netdev_flow_dump *); bool netdev_tc_flow_dump_next(struct netdev_flow_dump *, struct match *, struct nlattr **actions, struct dpif_flow_stats *, + struct dpif_flow_attrs *, ovs_u128 *ufid, struct ofpbuf *rbuffer, struct ofpbuf *wbuffer); @@ -34,7 +35,8 @@ int netdev_tc_flow_put(struct netdev *, struct match *, struct dpif_flow_stats *); int netdev_tc_flow_get(struct netdev *, struct match *, struct nlattr **actions, const ovs_u128 *, - struct dpif_flow_stats *, struct ofpbuf *); + struct dpif_flow_stats *, + struct dpif_flow_attrs *, struct ofpbuf *); int netdev_tc_flow_del(struct netdev *, const ovs_u128 *, struct dpif_flow_stats *); int netdev_tc_init_flow_api(struct netdev *); diff --git a/lib/netdev.c b/lib/netdev.c index dec35de25d3..83614f560e8 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -2162,14 +2162,14 @@ netdev_flow_dump_destroy(struct netdev_flow_dump *dump) bool netdev_flow_dump_next(struct netdev_flow_dump *dump, struct match *match, struct nlattr **actions, struct dpif_flow_stats *stats, - ovs_u128 *ufid, struct ofpbuf *rbuffer, - struct ofpbuf *wbuffer) + struct dpif_flow_attrs *attrs, ovs_u128 *ufid, + struct ofpbuf *rbuffer, struct ofpbuf *wbuffer) { const struct netdev_class *class = dump->netdev->netdev_class; return (class->flow_dump_next - ? class->flow_dump_next(dump, match, actions, stats, ufid, - rbuffer, wbuffer) + ? class->flow_dump_next(dump, match, actions, stats, attrs, + ufid, rbuffer, wbuffer) : false); } @@ -2190,12 +2190,13 @@ netdev_flow_put(struct netdev *netdev, struct match *match, int netdev_flow_get(struct netdev *netdev, struct match *match, struct nlattr **actions, const ovs_u128 *ufid, - struct dpif_flow_stats *stats, struct ofpbuf *buf) + struct dpif_flow_stats *stats, + struct dpif_flow_attrs *attrs, struct ofpbuf *buf) { const struct netdev_class *class = netdev->netdev_class; return (class->flow_get - ? class->flow_get(netdev, match, actions, ufid, stats, buf) + ? class->flow_get(netdev, match, actions, ufid, stats, attrs, buf) : EOPNOTSUPP); } @@ -2430,7 +2431,8 @@ netdev_ports_flow_del(const struct dpif_class *dpif_class, int netdev_ports_flow_get(const struct dpif_class *dpif_class, struct match *match, struct nlattr **actions, const ovs_u128 *ufid, - struct dpif_flow_stats *stats, struct ofpbuf *buf) + struct dpif_flow_stats *stats, + struct dpif_flow_attrs *attrs, struct ofpbuf *buf) { struct port_to_netdev_data *data; @@ -2438,7 +2440,7 @@ netdev_ports_flow_get(const struct dpif_class *dpif_class, struct match *match, HMAP_FOR_EACH (data, portno_node, &port_to_netdev) { if (data->dpif_class == dpif_class && !netdev_flow_get(data->netdev, match, actions, - ufid, stats, buf)) { + ufid, stats, attrs, buf)) { ovs_mutex_unlock(&netdev_hmap_mutex); return 0; } diff --git a/lib/netdev.h b/lib/netdev.h index 71ffdab63ec..490b34662aa 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -209,14 +209,14 @@ int netdev_flow_dump_create(struct netdev *, struct netdev_flow_dump **dump); int netdev_flow_dump_destroy(struct netdev_flow_dump *); bool netdev_flow_dump_next(struct netdev_flow_dump *, struct match *, struct nlattr **actions, struct dpif_flow_stats *, - ovs_u128 *ufid, struct ofpbuf *rbuffer, - struct ofpbuf *wbuffer); + struct dpif_flow_attrs *, ovs_u128 *ufid, + struct ofpbuf *rbuffer, struct ofpbuf *wbuffer); int netdev_flow_put(struct netdev *, struct match *, struct nlattr *actions, size_t actions_len, const ovs_u128 *, struct offload_info *, struct dpif_flow_stats *); int netdev_flow_get(struct netdev *, struct match *, struct nlattr **actions, const ovs_u128 *, struct dpif_flow_stats *, - struct ofpbuf *wbuffer); + struct dpif_flow_attrs *, struct ofpbuf *wbuffer); int netdev_flow_del(struct netdev *, const ovs_u128 *, struct dpif_flow_stats *); int netdev_init_flow_api(struct netdev *); @@ -239,6 +239,7 @@ int netdev_ports_flow_get(const struct dpif_class *, struct match *match, struct nlattr **actions, const ovs_u128 *ufid, struct dpif_flow_stats *stats, + struct dpif_flow_attrs *attrs, struct ofpbuf *buf); /* native tunnel APIs */ diff --git a/lib/tc.c b/lib/tc.c index 8e7d10341ff..71334866d8d 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -458,6 +458,28 @@ nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) { } } +static enum tc_offloaded_state +nl_get_flower_offloaded_state(struct nlattr **attrs) +{ + uint32_t flower_flags = 0; + + if (attrs[TCA_FLOWER_FLAGS]) { + flower_flags = nl_attr_get_u32(attrs[TCA_FLOWER_FLAGS]); + if (flower_flags & TCA_CLS_FLAGS_NOT_IN_HW) { + return TC_OFFLOADED_STATE_NOT_IN_HW; + } else if (flower_flags & TCA_CLS_FLAGS_IN_HW) { + return TC_OFFLOADED_STATE_IN_HW; + } + } + return TC_OFFLOADED_STATE_UNDEFINED; +} + +static void +nl_parse_flower_flags(struct nlattr **attrs, struct tc_flower *flower) +{ + flower->offloaded_state = nl_get_flower_offloaded_state(attrs); +} + static const struct nl_policy pedit_policy[] = { [TCA_PEDIT_PARMS_EX] = { .type = NL_A_UNSPEC, .min_len = sizeof(struct tc_pedit), @@ -942,6 +964,7 @@ nl_parse_flower_options(struct nlattr *nl_options, struct tc_flower *flower) nl_parse_flower_vlan(attrs, flower); nl_parse_flower_ip(attrs, flower); nl_parse_flower_tunnel(attrs, flower); + nl_parse_flower_flags(attrs, flower); return nl_parse_flower_actions(attrs, flower); } diff --git a/lib/tc.h b/lib/tc.h index 963db54dc67..cc193748e12 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -141,6 +141,12 @@ struct tc_action { enum tc_action_type type; }; +enum tc_offloaded_state { + TC_OFFLOADED_STATE_UNDEFINED, + TC_OFFLOADED_STATE_IN_HW, + TC_OFFLOADED_STATE_NOT_IN_HW, +}; + struct tc_flower { uint32_t handle; uint32_t prio; @@ -180,6 +186,8 @@ struct tc_flower { struct tc_cookie act_cookie; bool needs_full_ip_proto_mask; + + enum tc_offloaded_state offloaded_state; }; /* assert that if we overflow with a masked write of uint32_t to the last byte