diff mbox series

[ovs-dev,v4,3/3] controller: add memory accounting for local_datapath

Message ID a939b63a793e31c5bebbe158113971984ded823a.1634222132.git.lorenzo.bianconi@redhat.com
State Changes Requested
Headers show
Series add memory accounting for if_status_mgr module | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed
ovsrobot/github-robot-_ovn-kubernetes success github build: passed

Commit Message

Lorenzo Bianconi Oct. 14, 2021, 3:17 p.m. UTC
Similar to if-status-mgr, track memory allocated for local_datapath.

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
---
 controller/binding.c        |  6 ++--
 controller/local_data.c     | 66 +++++++++++++++++++++++++++++++++++++
 controller/local_data.h     |  7 ++++
 controller/ovn-controller.c |  1 +
 4 files changed, 77 insertions(+), 3 deletions(-)

Comments

Dumitru Ceara Oct. 18, 2021, 11:36 a.m. UTC | #1
On 10/14/21 5:17 PM, Lorenzo Bianconi wrote:
> Similar to if-status-mgr, track memory allocated for local_datapath.
> 
> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
> ---
>  controller/binding.c        |  6 ++--
>  controller/local_data.c     | 66 +++++++++++++++++++++++++++++++++++++
>  controller/local_data.h     |  7 ++++
>  controller/ovn-controller.c |  1 +
>  4 files changed, 77 insertions(+), 3 deletions(-)
> 
> diff --git a/controller/binding.c b/controller/binding.c
> index c037b2352..329d0d12b 100644
> --- a/controller/binding.c
> +++ b/controller/binding.c
> @@ -374,8 +374,8 @@ update_ld_external_ports(const struct sbrec_port_binding *binding_rec,
>      struct local_datapath *ld = get_local_datapath(
>          local_datapaths, binding_rec->datapath->tunnel_key);
>      if (ld) {
> -        shash_replace(&ld->external_ports, binding_rec->logical_port,
> -                      binding_rec);
> +        add_local_datapath_external_port(ld, binding_rec->logical_port,
> +                                         binding_rec);
>      }
>  }
>  
> @@ -1756,7 +1756,7 @@ remove_pb_from_local_datapath(const struct sbrec_port_binding *pb,
>              ld->localnet_port = NULL;
>          }
>      } else if (!strcmp(pb->type, "external")) {
> -        shash_find_and_delete(&ld->external_ports, pb->logical_port);
> +        remove_local_datapath_external_port(ld, pb->logical_port);
>      }
>  }
>  
> diff --git a/controller/local_data.c b/controller/local_data.c
> index 6efed2de0..48e6958b7 100644
> --- a/controller/local_data.c
> +++ b/controller/local_data.c
> @@ -47,6 +47,30 @@ static struct tracked_datapath *tracked_datapath_create(
>      enum en_tracked_resource_type tracked_type,
>      struct hmap *tracked_datapaths);
>  
> +static uint64_t local_datapath_usage;
> +
> +static void
> +local_datapath_peer_ports_mem_add(struct local_datapath *ld,
> +                                  size_t n_peer_ports)
> +{
> +    /* memory accounting - peer_ports. */
> +    local_datapath_usage +=
> +        (ld->n_allocated_peer_ports - n_peer_ports) * sizeof *ld->peer_ports;
> +}
> +
> +static void
> +local_datapath_ext_port_mem_update(struct local_datapath *ld, const char *name,
> +                                   bool erase)
> +{
> +    struct shash_node *node = shash_find(&ld->external_ports, name);
> +
> +    if (!node && !erase) { /* add a new element */
> +        local_datapath_usage += (sizeof *node + strlen(name));
> +    } else if (node && erase) { /* remove an element */
> +        local_datapath_usage -= (sizeof *node + strlen(name));
> +    }
> +}
> +
>  struct local_datapath *
>  get_local_datapath(const struct hmap *local_datapaths, uint32_t tunnel_key)
>  {
> @@ -63,6 +87,9 @@ local_datapath_alloc(const struct sbrec_datapath_binding *dp)
>      ld->datapath = dp;
>      ld->is_switch = datapath_is_switch(dp);
>      shash_init(&ld->external_ports);
> +    /* memory accounting - common part. */
> +    local_datapath_usage += sizeof *ld;
> +
>      return ld;
>  }
>  
> @@ -80,6 +107,16 @@ local_datapaths_destroy(struct hmap *local_datapaths)
>  void
>  local_datapath_destroy(struct local_datapath *ld)
>  {
> +    /* memory accounting. */
> +    struct shash_node *node;
> +    SHASH_FOR_EACH (node, &ld->external_ports) {
> +        local_datapath_usage -= strlen(node->name);
> +    }
> +    local_datapath_usage -= shash_count(&ld->external_ports) * sizeof *node;
> +    local_datapath_usage -= sizeof *ld;
> +    local_datapath_usage -=
> +        ld->n_allocated_peer_ports * sizeof *ld->peer_ports;
> +
>      free(ld->peer_ports);
>      shash_destroy(&ld->external_ports);
>      free(ld);
> @@ -175,10 +212,12 @@ add_local_datapath_peer_port(
>      if (!present) {
>          ld->n_peer_ports++;
>          if (ld->n_peer_ports > ld->n_allocated_peer_ports) {
> +            size_t n_peer_ports = ld->n_allocated_peer_ports;
>              ld->peer_ports =
>                  x2nrealloc(ld->peer_ports,
>                             &ld->n_allocated_peer_ports,
>                             sizeof *ld->peer_ports);
> +            local_datapath_peer_ports_mem_add(ld, n_peer_ports);
>          }
>          ld->peer_ports[ld->n_peer_ports - 1].local = pb;
>          ld->peer_ports[ld->n_peer_ports - 1].remote = peer;
> @@ -204,10 +243,12 @@ add_local_datapath_peer_port(
>  
>      peer_ld->n_peer_ports++;
>      if (peer_ld->n_peer_ports > peer_ld->n_allocated_peer_ports) {
> +        size_t n_peer_ports = peer_ld->n_allocated_peer_ports;
>          peer_ld->peer_ports =
>              x2nrealloc(peer_ld->peer_ports,
>                          &peer_ld->n_allocated_peer_ports,
>                          sizeof *peer_ld->peer_ports);
> +            local_datapath_peer_ports_mem_add(peer_ld, n_peer_ports);
>      }
>      peer_ld->peer_ports[peer_ld->n_peer_ports - 1].local = peer;
>      peer_ld->peer_ports[peer_ld->n_peer_ports - 1].remote = pb;
> @@ -248,6 +289,22 @@ remove_local_datapath_peer_port(const struct sbrec_port_binding *pb,
>      }
>  }
>  
> +void
> +add_local_datapath_external_port(struct local_datapath *ld,
> +                                 char *logical_port, const void *data)
> +{
> +    local_datapath_ext_port_mem_update(ld, logical_port, false);
> +    shash_replace(&ld->external_ports, logical_port, data);


We can simplify this and remove local_datapath_ext_port_mem_update()
if we rewrite it like:

if (!shash_replace(&ld->external_ports, logical_port, data)) {
    local_datapath_usage += sizeof(struct shash_node) + strlen(logical_port);
}

> +}
> +
> +void
> +remove_local_datapath_external_port(struct local_datapath *ld,
> +                                    char *logical_port)
> +{
> +    local_datapath_ext_port_mem_update(ld, logical_port, true);
> +    shash_find_and_delete(&ld->external_ports, logical_port);

Here too:

if (shash_find_and_delete(&ld->external_ports, logical_port)) {
    local_datapath_usage -= sizeof(struct shash_node) + strlen(logical_port);
}

> +}
> +
>  /* track datapath functions. */
>  struct tracked_datapath *
>  tracked_datapath_add(const struct sbrec_datapath_binding *dp,
> @@ -537,10 +594,12 @@ add_local_datapath__(struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
>                      }
>                      ld->n_peer_ports++;
>                      if (ld->n_peer_ports > ld->n_allocated_peer_ports) {
> +                        size_t n_peer_ports = ld->n_allocated_peer_ports;
>                          ld->peer_ports =
>                              x2nrealloc(ld->peer_ports,
>                                         &ld->n_allocated_peer_ports,
>                                         sizeof *ld->peer_ports);
> +                        local_datapath_peer_ports_mem_add(ld, n_peer_ports);

There's quite some code duplication when adding a new datapath peer port
(3 different places), we can probably refactor it and also include
memory accounting directly in there if we add a new function:

static void
local_datapath_peer_port_add(struct local_datapath *ld,
                             const struct sbrec_port_binding *local,
                             const struct sbrec_port_binding *remote)
{
    ld->n_peer_ports++;
    if (ld->n_peer_ports > ld->n_allocated_peer_ports) {
        size_t old_n_ports = ld->n_allocated_peer_ports;
        ld->peer_ports =
            x2nrealloc(ld->peer_ports,
                       &ld->n_allocated_peer_ports,
                       sizeof *ld->peer_ports);
        local_datapath_usage +=
            (ld->n_allocated_peer_ports - old_n_ports) *
            sizeof *ld->peer_ports;
    }
    ld->peer_ports[ld->n_peer_ports - 1].local = local;
    ld->peer_ports[ld->n_peer_ports - 1].remote = remote;
}

What do you think?

Thanks,
Dumitru
Dumitru Ceara Oct. 18, 2021, 11:53 a.m. UTC | #2
On 10/14/21 5:17 PM, Lorenzo Bianconi wrote:

[...]

> diff --git a/controller/local_data.h b/controller/local_data.h
> index f6317e9ca..3defa9925 100644
> --- a/controller/local_data.h
> +++ b/controller/local_data.h
> @@ -154,5 +154,12 @@ bool get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels,
>                                 ofp_port_t *ofport);
>  
>  void chassis_tunnels_destroy(struct hmap *chassis_tunnels);
> +void local_datapath_memory_usage(struct simap *usage);
> +void
> +add_local_datapath_external_port(struct local_datapath *ld,
> +                                 char *logical_port, const void *data);

Probably best to change this to 'const char *logical_port'.  When
reviewing I was in doubt about whether we should free the shash_node's
data when removing external_ports.  Changing the type to const would
make it explicit, as free works only on non-const pointers.

> +void
> +remove_local_datapath_external_port(struct local_datapath *ld,
> +                                    char *logical_port);

Same here.

Thanks!
Lorenzo Bianconi Oct. 21, 2021, 9:14 a.m. UTC | #3
On Oct 18, Dumitru Ceara wrote:
> On 10/14/21 5:17 PM, Lorenzo Bianconi wrote:
> > Similar to if-status-mgr, track memory allocated for local_datapath.
> > 
> > Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
> > ---
> >  controller/binding.c        |  6 ++--
> >  controller/local_data.c     | 66 +++++++++++++++++++++++++++++++++++++
> >  controller/local_data.h     |  7 ++++
> >  controller/ovn-controller.c |  1 +
> >  4 files changed, 77 insertions(+), 3 deletions(-)
> > 
> > diff --git a/controller/binding.c b/controller/binding.c
> > index c037b2352..329d0d12b 100644
> > --- a/controller/binding.c
> > +++ b/controller/binding.c
> > @@ -374,8 +374,8 @@ update_ld_external_ports(const struct sbrec_port_binding *binding_rec,
> >      struct local_datapath *ld = get_local_datapath(
> >          local_datapaths, binding_rec->datapath->tunnel_key);
> >      if (ld) {
> > -        shash_replace(&ld->external_ports, binding_rec->logical_port,
> > -                      binding_rec);
> > +        add_local_datapath_external_port(ld, binding_rec->logical_port,
> > +                                         binding_rec);
> >      }
> >  }
> >  
> > @@ -1756,7 +1756,7 @@ remove_pb_from_local_datapath(const struct sbrec_port_binding *pb,
> >              ld->localnet_port = NULL;
> >          }
> >      } else if (!strcmp(pb->type, "external")) {
> > -        shash_find_and_delete(&ld->external_ports, pb->logical_port);
> > +        remove_local_datapath_external_port(ld, pb->logical_port);
> >      }
> >  }
> >  
> > diff --git a/controller/local_data.c b/controller/local_data.c
> > index 6efed2de0..48e6958b7 100644
> > --- a/controller/local_data.c
> > +++ b/controller/local_data.c
> > @@ -47,6 +47,30 @@ static struct tracked_datapath *tracked_datapath_create(
> >      enum en_tracked_resource_type tracked_type,
> >      struct hmap *tracked_datapaths);
> >  
> > +static uint64_t local_datapath_usage;
> > +
> > +static void
> > +local_datapath_peer_ports_mem_add(struct local_datapath *ld,
> > +                                  size_t n_peer_ports)
> > +{
> > +    /* memory accounting - peer_ports. */
> > +    local_datapath_usage +=
> > +        (ld->n_allocated_peer_ports - n_peer_ports) * sizeof *ld->peer_ports;
> > +}
> > +
> > +static void
> > +local_datapath_ext_port_mem_update(struct local_datapath *ld, const char *name,
> > +                                   bool erase)
> > +{
> > +    struct shash_node *node = shash_find(&ld->external_ports, name);
> > +
> > +    if (!node && !erase) { /* add a new element */
> > +        local_datapath_usage += (sizeof *node + strlen(name));
> > +    } else if (node && erase) { /* remove an element */
> > +        local_datapath_usage -= (sizeof *node + strlen(name));
> > +    }
> > +}
> > +
> >  struct local_datapath *
> >  get_local_datapath(const struct hmap *local_datapaths, uint32_t tunnel_key)
> >  {
> > @@ -63,6 +87,9 @@ local_datapath_alloc(const struct sbrec_datapath_binding *dp)
> >      ld->datapath = dp;
> >      ld->is_switch = datapath_is_switch(dp);
> >      shash_init(&ld->external_ports);
> > +    /* memory accounting - common part. */
> > +    local_datapath_usage += sizeof *ld;
> > +
> >      return ld;
> >  }
> >  
> > @@ -80,6 +107,16 @@ local_datapaths_destroy(struct hmap *local_datapaths)
> >  void
> >  local_datapath_destroy(struct local_datapath *ld)
> >  {
> > +    /* memory accounting. */
> > +    struct shash_node *node;
> > +    SHASH_FOR_EACH (node, &ld->external_ports) {
> > +        local_datapath_usage -= strlen(node->name);
> > +    }
> > +    local_datapath_usage -= shash_count(&ld->external_ports) * sizeof *node;
> > +    local_datapath_usage -= sizeof *ld;
> > +    local_datapath_usage -=
> > +        ld->n_allocated_peer_ports * sizeof *ld->peer_ports;
> > +
> >      free(ld->peer_ports);
> >      shash_destroy(&ld->external_ports);
> >      free(ld);
> > @@ -175,10 +212,12 @@ add_local_datapath_peer_port(
> >      if (!present) {
> >          ld->n_peer_ports++;
> >          if (ld->n_peer_ports > ld->n_allocated_peer_ports) {
> > +            size_t n_peer_ports = ld->n_allocated_peer_ports;
> >              ld->peer_ports =
> >                  x2nrealloc(ld->peer_ports,
> >                             &ld->n_allocated_peer_ports,
> >                             sizeof *ld->peer_ports);
> > +            local_datapath_peer_ports_mem_add(ld, n_peer_ports);
> >          }
> >          ld->peer_ports[ld->n_peer_ports - 1].local = pb;
> >          ld->peer_ports[ld->n_peer_ports - 1].remote = peer;
> > @@ -204,10 +243,12 @@ add_local_datapath_peer_port(
> >  
> >      peer_ld->n_peer_ports++;
> >      if (peer_ld->n_peer_ports > peer_ld->n_allocated_peer_ports) {
> > +        size_t n_peer_ports = peer_ld->n_allocated_peer_ports;
> >          peer_ld->peer_ports =
> >              x2nrealloc(peer_ld->peer_ports,
> >                          &peer_ld->n_allocated_peer_ports,
> >                          sizeof *peer_ld->peer_ports);
> > +            local_datapath_peer_ports_mem_add(peer_ld, n_peer_ports);
> >      }
> >      peer_ld->peer_ports[peer_ld->n_peer_ports - 1].local = peer;
> >      peer_ld->peer_ports[peer_ld->n_peer_ports - 1].remote = pb;
> > @@ -248,6 +289,22 @@ remove_local_datapath_peer_port(const struct sbrec_port_binding *pb,
> >      }
> >  }
> >  
> > +void
> > +add_local_datapath_external_port(struct local_datapath *ld,
> > +                                 char *logical_port, const void *data)
> > +{
> > +    local_datapath_ext_port_mem_update(ld, logical_port, false);
> > +    shash_replace(&ld->external_ports, logical_port, data);
> 
> 
> We can simplify this and remove local_datapath_ext_port_mem_update()
> if we rewrite it like:
> 
> if (!shash_replace(&ld->external_ports, logical_port, data)) {
>     local_datapath_usage += sizeof(struct shash_node) + strlen(logical_port);

ack, I will fix it in v5

> }
> 
> > +}
> > +
> > +void
> > +remove_local_datapath_external_port(struct local_datapath *ld,
> > +                                    char *logical_port)
> > +{
> > +    local_datapath_ext_port_mem_update(ld, logical_port, true);
> > +    shash_find_and_delete(&ld->external_ports, logical_port);
> 
> Here too:
> 
> if (shash_find_and_delete(&ld->external_ports, logical_port)) {
>     local_datapath_usage -= sizeof(struct shash_node) + strlen(logical_port);

ditto

> }
> 
> > +}
> > +
> >  /* track datapath functions. */
> >  struct tracked_datapath *
> >  tracked_datapath_add(const struct sbrec_datapath_binding *dp,
> > @@ -537,10 +594,12 @@ add_local_datapath__(struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
> >                      }
> >                      ld->n_peer_ports++;
> >                      if (ld->n_peer_ports > ld->n_allocated_peer_ports) {
> > +                        size_t n_peer_ports = ld->n_allocated_peer_ports;
> >                          ld->peer_ports =
> >                              x2nrealloc(ld->peer_ports,
> >                                         &ld->n_allocated_peer_ports,
> >                                         sizeof *ld->peer_ports);
> > +                        local_datapath_peer_ports_mem_add(ld, n_peer_ports);
> 
> There's quite some code duplication when adding a new datapath peer port
> (3 different places), we can probably refactor it and also include
> memory accounting directly in there if we add a new function:
> 
> static void
> local_datapath_peer_port_add(struct local_datapath *ld,
>                              const struct sbrec_port_binding *local,
>                              const struct sbrec_port_binding *remote)
> {
>     ld->n_peer_ports++;
>     if (ld->n_peer_ports > ld->n_allocated_peer_ports) {
>         size_t old_n_ports = ld->n_allocated_peer_ports;
>         ld->peer_ports =
>             x2nrealloc(ld->peer_ports,
>                        &ld->n_allocated_peer_ports,
>                        sizeof *ld->peer_ports);
>         local_datapath_usage +=
>             (ld->n_allocated_peer_ports - old_n_ports) *
>             sizeof *ld->peer_ports;
>     }
>     ld->peer_ports[ld->n_peer_ports - 1].local = local;
>     ld->peer_ports[ld->n_peer_ports - 1].remote = remote;
> }
> 
> What do you think?

ack, right. I will add it to v5.

Regards,
Lorenzo

> 
> Thanks,
> Dumitru
>
diff mbox series

Patch

diff --git a/controller/binding.c b/controller/binding.c
index c037b2352..329d0d12b 100644
--- a/controller/binding.c
+++ b/controller/binding.c
@@ -374,8 +374,8 @@  update_ld_external_ports(const struct sbrec_port_binding *binding_rec,
     struct local_datapath *ld = get_local_datapath(
         local_datapaths, binding_rec->datapath->tunnel_key);
     if (ld) {
-        shash_replace(&ld->external_ports, binding_rec->logical_port,
-                      binding_rec);
+        add_local_datapath_external_port(ld, binding_rec->logical_port,
+                                         binding_rec);
     }
 }
 
@@ -1756,7 +1756,7 @@  remove_pb_from_local_datapath(const struct sbrec_port_binding *pb,
             ld->localnet_port = NULL;
         }
     } else if (!strcmp(pb->type, "external")) {
-        shash_find_and_delete(&ld->external_ports, pb->logical_port);
+        remove_local_datapath_external_port(ld, pb->logical_port);
     }
 }
 
diff --git a/controller/local_data.c b/controller/local_data.c
index 6efed2de0..48e6958b7 100644
--- a/controller/local_data.c
+++ b/controller/local_data.c
@@ -47,6 +47,30 @@  static struct tracked_datapath *tracked_datapath_create(
     enum en_tracked_resource_type tracked_type,
     struct hmap *tracked_datapaths);
 
+static uint64_t local_datapath_usage;
+
+static void
+local_datapath_peer_ports_mem_add(struct local_datapath *ld,
+                                  size_t n_peer_ports)
+{
+    /* memory accounting - peer_ports. */
+    local_datapath_usage +=
+        (ld->n_allocated_peer_ports - n_peer_ports) * sizeof *ld->peer_ports;
+}
+
+static void
+local_datapath_ext_port_mem_update(struct local_datapath *ld, const char *name,
+                                   bool erase)
+{
+    struct shash_node *node = shash_find(&ld->external_ports, name);
+
+    if (!node && !erase) { /* add a new element */
+        local_datapath_usage += (sizeof *node + strlen(name));
+    } else if (node && erase) { /* remove an element */
+        local_datapath_usage -= (sizeof *node + strlen(name));
+    }
+}
+
 struct local_datapath *
 get_local_datapath(const struct hmap *local_datapaths, uint32_t tunnel_key)
 {
@@ -63,6 +87,9 @@  local_datapath_alloc(const struct sbrec_datapath_binding *dp)
     ld->datapath = dp;
     ld->is_switch = datapath_is_switch(dp);
     shash_init(&ld->external_ports);
+    /* memory accounting - common part. */
+    local_datapath_usage += sizeof *ld;
+
     return ld;
 }
 
@@ -80,6 +107,16 @@  local_datapaths_destroy(struct hmap *local_datapaths)
 void
 local_datapath_destroy(struct local_datapath *ld)
 {
+    /* memory accounting. */
+    struct shash_node *node;
+    SHASH_FOR_EACH (node, &ld->external_ports) {
+        local_datapath_usage -= strlen(node->name);
+    }
+    local_datapath_usage -= shash_count(&ld->external_ports) * sizeof *node;
+    local_datapath_usage -= sizeof *ld;
+    local_datapath_usage -=
+        ld->n_allocated_peer_ports * sizeof *ld->peer_ports;
+
     free(ld->peer_ports);
     shash_destroy(&ld->external_ports);
     free(ld);
@@ -175,10 +212,12 @@  add_local_datapath_peer_port(
     if (!present) {
         ld->n_peer_ports++;
         if (ld->n_peer_ports > ld->n_allocated_peer_ports) {
+            size_t n_peer_ports = ld->n_allocated_peer_ports;
             ld->peer_ports =
                 x2nrealloc(ld->peer_ports,
                            &ld->n_allocated_peer_ports,
                            sizeof *ld->peer_ports);
+            local_datapath_peer_ports_mem_add(ld, n_peer_ports);
         }
         ld->peer_ports[ld->n_peer_ports - 1].local = pb;
         ld->peer_ports[ld->n_peer_ports - 1].remote = peer;
@@ -204,10 +243,12 @@  add_local_datapath_peer_port(
 
     peer_ld->n_peer_ports++;
     if (peer_ld->n_peer_ports > peer_ld->n_allocated_peer_ports) {
+        size_t n_peer_ports = peer_ld->n_allocated_peer_ports;
         peer_ld->peer_ports =
             x2nrealloc(peer_ld->peer_ports,
                         &peer_ld->n_allocated_peer_ports,
                         sizeof *peer_ld->peer_ports);
+            local_datapath_peer_ports_mem_add(peer_ld, n_peer_ports);
     }
     peer_ld->peer_ports[peer_ld->n_peer_ports - 1].local = peer;
     peer_ld->peer_ports[peer_ld->n_peer_ports - 1].remote = pb;
@@ -248,6 +289,22 @@  remove_local_datapath_peer_port(const struct sbrec_port_binding *pb,
     }
 }
 
+void
+add_local_datapath_external_port(struct local_datapath *ld,
+                                 char *logical_port, const void *data)
+{
+    local_datapath_ext_port_mem_update(ld, logical_port, false);
+    shash_replace(&ld->external_ports, logical_port, data);
+}
+
+void
+remove_local_datapath_external_port(struct local_datapath *ld,
+                                    char *logical_port)
+{
+    local_datapath_ext_port_mem_update(ld, logical_port, true);
+    shash_find_and_delete(&ld->external_ports, logical_port);
+}
+
 /* track datapath functions. */
 struct tracked_datapath *
 tracked_datapath_add(const struct sbrec_datapath_binding *dp,
@@ -537,10 +594,12 @@  add_local_datapath__(struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
                     }
                     ld->n_peer_ports++;
                     if (ld->n_peer_ports > ld->n_allocated_peer_ports) {
+                        size_t n_peer_ports = ld->n_allocated_peer_ports;
                         ld->peer_ports =
                             x2nrealloc(ld->peer_ports,
                                        &ld->n_allocated_peer_ports,
                                        sizeof *ld->peer_ports);
+                        local_datapath_peer_ports_mem_add(ld, n_peer_ports);
                     }
                     ld->peer_ports[ld->n_peer_ports - 1].local = pb;
                     ld->peer_ports[ld->n_peer_ports - 1].remote = peer;
@@ -563,3 +622,10 @@  tracked_datapath_create(const struct sbrec_datapath_binding *dp,
     hmap_insert(tracked_datapaths, &t_dp->node, uuid_hash(&dp->header_.uuid));
     return t_dp;
 }
+
+void
+local_datapath_memory_usage(struct simap *usage)
+{
+    simap_increase(usage, "local_datapath_usage-KB",
+                   ROUND_UP(local_datapath_usage, 1024) / 1024);
+}
diff --git a/controller/local_data.h b/controller/local_data.h
index f6317e9ca..3defa9925 100644
--- a/controller/local_data.h
+++ b/controller/local_data.h
@@ -154,5 +154,12 @@  bool get_chassis_tunnel_ofport(const struct hmap *chassis_tunnels,
                                ofp_port_t *ofport);
 
 void chassis_tunnels_destroy(struct hmap *chassis_tunnels);
+void local_datapath_memory_usage(struct simap *usage);
+void
+add_local_datapath_external_port(struct local_datapath *ld,
+                                 char *logical_port, const void *data);
+void
+remove_local_datapath_external_port(struct local_datapath *ld,
+                                    char *logical_port);
 
 #endif /* controller/local_data.h */
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index e0fb0988f..a8e252e9c 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -3464,6 +3464,7 @@  main(int argc, char *argv[])
             lflow_cache_get_memory_usage(ctrl_engine_ctx.lflow_cache, &usage);
             ofctrl_get_memory_usage(&usage);
             if_status_mgr_get_memory_usage(if_mgr, &usage);
+            local_datapath_memory_usage(&usage);
             memory_report(&usage);
             simap_destroy(&usage);
         }