On Thu, Jan 30, 2025 at 02:31:52PM +0100, Eelco Chaudron wrote:
>
>
> On 17 Jan 2025, at 15:25, Adrian Moreno wrote:
>
> > The upcall_cost.py script has a useful port mapping cache that can be
> > very useful for other scripts.
> >
> > Move it into a library file (usdt_lib.py). While we're at it, refactor
> > it into a class since setting attributes to functions and having it
> > return different types depending on input is not very clean.
> >
> > This patch should not introduce any functional change.
> >
> > Signed-off-by: Adrian Moreno <[email protected]>
>
> In general, this looks good to me. Some small comments below.
>
> //Eelco
>
> > ---
> > utilities/automake.mk | 7 ++-
> > utilities/usdt-scripts/upcall_cost.py | 72 ++++-----------------------
> > utilities/usdt-scripts/usdt_lib.py | 70 ++++++++++++++++++++++++++
> > 3 files changed, 86 insertions(+), 63 deletions(-)
> > create mode 100644 utilities/usdt-scripts/usdt_lib.py
> >
> > diff --git a/utilities/automake.mk b/utilities/automake.mk
> > index 22260b254..fcd353109 100644
> > --- a/utilities/automake.mk
> > +++ b/utilities/automake.mk
> > @@ -28,7 +28,8 @@ usdt_SCRIPTS += \
> > utilities/usdt-scripts/kernel_delay.rst \
> > utilities/usdt-scripts/reval_monitor.py \
> > utilities/usdt-scripts/upcall_cost.py \
> > - utilities/usdt-scripts/upcall_monitor.py
> > + utilities/usdt-scripts/upcall_monitor.py \
> > + utilities/usdt-scripts/usdt_lib.py
> >
> > completion_SCRIPTS += \
> > utilities/ovs-appctl-bashcomp.bash \
> > @@ -78,7 +79,9 @@ EXTRA_DIST += \
> > utilities/usdt-scripts/kernel_delay.rst \
> > utilities/usdt-scripts/reval_monitor.py \
> > utilities/usdt-scripts/upcall_cost.py \
> > - utilities/usdt-scripts/upcall_monitor.py
> > + utilities/usdt-scripts/upcall_monitor.py \
> > + utilities/usdt-scripts/usdt_lib.py
> > +
> > MAN_ROOTS += \
> > utilities/ovs-testcontroller.8.in \
> > utilities/ovs-dpctl.8.in \
> > diff --git a/utilities/usdt-scripts/upcall_cost.py
> > b/utilities/usdt-scripts/upcall_cost.py
> > index 765669585..47a1e30a6 100755
> > --- a/utilities/usdt-scripts/upcall_cost.py
> > +++ b/utilities/usdt-scripts/upcall_cost.py
> > @@ -58,12 +58,13 @@ from strenum import StrEnum
> > from text_histogram3 import histogram
> > from time import process_time
> >
> > +from usdt_lib import DpPortMapping
> > +
> > import argparse
> > import ast
> > import psutil
> > import re
> > import struct
> > -import subprocess
> > import sys
> > import time
> >
> > @@ -353,7 +354,7 @@ class DpUpcall(Event):
> > pkt_frag_len):
> > super(DpUpcall, self).__init__(ts, pid, comm, cpu,
> > EventType.DP_UPCALL)
> > self.dpif_name = dpif_name
> > - self.dp_port = get_dp_mapping(dpif_name, port)
> > + self.dp_port = dp_map.get(dpif_name, port)
> > if self.dp_port is None:
> > #
> > # As we only identify interfaces at startup, new interfaces
> > could
> > @@ -446,13 +447,8 @@ class RecvUpcall(Event):
> > self.pkt_len)
> >
> > def get_system_dp_port(dpif_name):
> > - dp_map = get_dp_mapping(dpif_name, "ovs-system", return_map=True)
> > - if dpif_name not in dp_map:
> > - return None
> > - try:
> > - return dp_map[dpif_name]["ovs-system"]
> > - except KeyError:
> > - return None
> > + dp_map = dp_map.get_map()
>
> This looks confusing, as dp_map local is the same as the global variable.
> Maybe rename it.
>
Ack
> > + return dp_map.get(dpif_name, {}).get("ovs-system", None)
> >
> > def decode_nlm(msg, indent=4, dump=True):
> > bytes_left = len(msg)
> > @@ -621,54 +617,6 @@ class OpFlowExecute(Event):
> > return event
> >
> >
> > -#
> > -# get_dp_mapping()
> > -#
> > -def get_dp_mapping(dp, port, return_map=False, dp_map=None):
> > - if options.unit_test:
> > - return port
> > -
> > - if dp_map is not None:
> > - get_dp_mapping.dp_port_map_cache = dp_map
> > -
> > - #
> > - # Build a cache, so we do not have to execue the ovs command each time.
> > - #
> > - if not hasattr(get_dp_mapping, "dp_port_map_cache"):
> > - try:
> > - output = subprocess.check_output(['ovs-appctl', 'dpctl/show'],
> > - encoding='utf8').split("\n")
> > - except subprocess.CalledProcessError:
> > - output = ""
> > - pass
> > -
> > - current_dp = None
> > - get_dp_mapping.dp_port_map_cache = {}
> > -
> > - for line in output:
> > - match = re.match("^system@(.*):$", line)
> > - if match is not None:
> > - current_dp = match.group(1)
> > -
> > - match = re.match("^ port ([0-9]+): ([^ /]*)", line)
> > - if match is not None and current_dp is not None:
> > - try:
> > - get_dp_mapping.dp_port_map_cache[
> > - current_dp][match.group(2)] = int(match.group(1))
> > - except KeyError:
> > - get_dp_mapping.dp_port_map_cache[current_dp] = \
> > - {match.group(2): int(match.group(1))}
> > -
> > - if return_map:
> > - return get_dp_mapping.dp_port_map_cache
> > -
> > - if dp not in get_dp_mapping.dp_port_map_cache or \
> > - port not in get_dp_mapping.dp_port_map_cache[dp]:
> > - return None
> > -
> > - return get_dp_mapping.dp_port_map_cache[dp][port]
> > -
> > -
> > #
> > # event_to_dict()
> > #
> > @@ -1429,6 +1377,9 @@ def main():
> > global events_received
> > global event_count
> > global export_file
> > + global dp_map
> > +
> > + dp_map = DpPortMapping()
> >
> > #
> > # Argument parsing
> > @@ -1531,9 +1482,9 @@ def main():
> > event_count = {'total': {}, 'valid': {}, 'miss': {}}
> > if options.read_events is None:
> > #
> > - # Call get_dp_mapping() to prepare the cache
> > + # Prepare the datapath port mapping cache
> > #
> > - dp_port_map = get_dp_mapping("ovs-system", "eth0", return_map=True)
> > + dp_port_map = dp_map.get_map()
> > if export_file is not None:
> > export_file.write("dp_port_map = {}\n".format(dp_port_map))
> >
> > @@ -1643,8 +1594,7 @@ def main():
> > if entry.startswith('dp_port_map = {'):
> > if not dp_port_mapping_valid:
> > dp_port_mapping_valid = True
> > - get_dp_mapping("", "",
> > -
> > dp_map=ast.literal_eval(entry[14:]))
> > + dp_map.set_map(ast.literal_eval(entry[14:]))
> > elif (entry.startswith('event = {') and
> > dp_port_mapping_valid):
> > event = ast.literal_eval(entry[8:])
> > diff --git a/utilities/usdt-scripts/usdt_lib.py
> > b/utilities/usdt-scripts/usdt_lib.py
> > new file mode 100644
> > index 000000000..da3fab2bf
> > --- /dev/null
> > +++ b/utilities/usdt-scripts/usdt_lib.py
> > @@ -0,0 +1,70 @@
> > +# Copyright (c) 2025 Red Hat, Inc.
>
> As some of this code is copied from the 2021 licensed file, I think, this
> should also be 2021.
>
Right! Thanks.
> > +#
> > +# Licensed under the Apache License, Version 2.0 (the "License");
> > +# you may not use this file except in compliance with the License.
> > +# You may obtain a copy of the License at:
> > +#
> > +# http://www.apache.org/licenses/LICENSE-2.0
> > +#
> > +# Unless required by applicable law or agreed to in writing, software
> > +# distributed under the License is distributed on an "AS IS" BASIS,
> > +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> > +# See the License for the specific language governing permissions and
> > +# limitations under the License.
> > +
> > +import re
> > +import subprocess
> > +
> > +
> > +class DpPortMapping:
> > + """Class used to retrieve and cache datapath port numbers to port
> > names."""
> > +
> > + def __init__(self):
> > + self.cache_map = None
> > +
> > + def get_map(self):
> > + """Get the cache map."""
> > + if not self.cache_map:
> > + self._get_mapping()
> > +
> > + return self.cache_map
> > +
> > + def set_map(self, cache_map):
> > + """Override the internal cache map."""
> > + self.cache_map = cache_map
> > +
> > + def get(self, dp, port_no):
> > + """Get the portname from a port number."""
> > + if self.cache_map is None:
> > + self._get_mapping()
> > +
> > + return self.cache_map.get(dp, {}).get(port_no, None)
> > +
> > + def _get_mapping(self):
> > + """Get the datapath port mapping from the running OVS."""
> > + try:
> > + output = subprocess.check_output(
> > + ["ovs-appctl", "dpctl/show"], encoding="utf8"
> > + ).split("\n")
> > + except subprocess.CalledProcessError:
> > + output = ""
> > + return
> > +
> > + current_dp = None
> > + self.cache_map = {}
> > +
> > + for line in output:
> > + match = re.match("^system@(.*):$", line)
> > + if match:
> > + current_dp = match.group(1)
> > +
> > + match = re.match("^ port ([0-9]+): ([^ /]*)", line)
> > + if match and current_dp:
> > + try:
> > + self.cache_map[current_dp][match.group(2)] = int(
> > + match.group(1)
> > + )
> > + except KeyError:
> > + self.cache_map[current_dp] = {
> > + match.group(2): int(match.group(1))
> > + }
> > --
> > 2.48.1
> >
> > _______________________________________________
> > dev mailing list
> > [email protected]
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev