---
title: Monitoring MetalLB configuration status
---

# Monitoring MetalLB configuration status {id="monitoring-metallb-status""} {#monitoring-metallb-configuration-status-idmonitoring-metallb-status}

As an OpenShift Container Platform system administrator, you can monitor the operational status of your MetalLB deployment by examining its custom resources (CRs). These status fields provide information about IP address allocations, BGP peer announcements, and session states, which are important for effective monitoring and troubleshooting.

## Understanding MetalLB status custom resources {#nw-metallb-status-reporting_monitor-metallb-config-status}

MetalLB provides a scalable framework for monitoring the health of network traffic and IP addresses. Use status fields in MetalLB custom resources to track session status and troubleshoot configuration.

MetalLB exposes status information for several key components, providing a comprehensive view of its configuration and operation.

**MetalLB status resources**

| Resource | Description | Troubleshooting command |
| --- | --- | --- |
| **`IPAddressPool` (status field)** | Shows the cluster-wide allocation and availability of IP addresses within a defined pool, including the number of assigned and available addresses for both IPv4 and IPv6. | `oc get ipaddresspool _<IPAddressPool-name>_ -n metallb-system -o yaml` |
| **`ServiceBGPStatus`** | Shows which service IP addresses the system announces to specific BGP peers across the network infrastructure. | `oc get servicebgpstatus -n metallb-system` |
| **`BGPSessionStatus`** | Shows the real-time operational state of the border gateway protocol (BGP) and bidirectional forwarding detection (BFD) sessions between a specific cluster node and a BGP peer, indicating if the channel is `Established` or `Up` based on routing stack feedback. | `oc get bgpsessionstatus -o wide` |
| **`ConfigurationState`** | Shows whether the MetalLB controller and speakers have successfully validated and applied the current configuration. MetalLB creates one resource for the controller and one for each speaker node. Reports errors when custom resources are incompatible. | `oc get configurationstates -n metallb-system` |

The MetalLB controller, typically deployed as `metallb-system/controller`, is responsible for managing IP address assignments and updating the `IPAddressPool` status. When a service requests a `LoadBalancer` IP, the controller allocates an IP from an appropriate `IPAddressPool` and updates the status fields to reflect the current number of assigned and available IP addresses.

## Viewing the `IPAddressPool` status {#nw-metallb-configure-address-pool_monitor-metallb-config-status}

Check IP address allocation from your MetalLB pools by viewing the `IPAddressPool` status. This status shows the number of addresses assigned to services and the number remaining available for assignment.

As a cluster administrator, you can add address pools to your cluster to control the IP addresses that MetalLB can assign to load-balancer services. This example shows how to create an `IPAddressPool` custom resource (CR) and view its status. The configuration sets the advertisement mode to Layer 2 (L2).

**Prerequisites**

- You have an OpenShift Container Platform cluster with the MetalLB Operator installed.
- You have deployed a MetalLB instance.

**Procedure**

1. Create an IP address pool.

   1. Create a file, named for example `ipaddresspool.yaml`, with content such as the following:

      ```yaml
      apiVersion: metallb.io/v1beta1
      kind: IPAddressPool
      metadata:
        name: doc-example-l2
        namespace: metallb-system
      spec:
        addresses:
        - 192.168.122.200-192.168.122.220
        autoAssign: true
        avoidBuggyIPs: false
      ```
   2. Apply the configuration for the IP address pool:

      ```terminal
      $ oc apply -f ipaddresspool.yaml
      ```
2. View the status of the IP address pool by running the following command:

   ```terminal
   $ oc get ipaddresspool doc-example-l2 -n metallb-system -o yaml
   ```

   The output is similar to the following:

   ```yaml
   apiVersion: metallb.io/v1beta1
   kind: IPAddressPool
   metadata:
     annotations:
       kubectl.kubernetes.io/last-applied-configuration: |
         {"apiVersion":"metallb.io/v1beta1","kind":"IPAddressPool","metadata":{"annotations":{},"name":"doc-example-l2","namespace":"metallb-system"},"spec":{"addresses":["192.168.122.200-192.168.122.220"],"autoAssign":true,"avoidBuggyIPs":false}}
     creationTimestamp: "2025-07-17T10:13:37Z"
     generation: 1
     name: doc-example-l2
     namespace: metallb-system
     resourceVersion: "29080"
     uid: 8df1c303-03ac-4d31-8970-6dacdb173dc2
   spec:
     addresses:
     - 192.168.122.200-192.168.122.220
     autoAssign: true
     avoidBuggyIPs: false
   status:
     assignedIPv4: 0
     assignedIPv6: 0
     availableIPv4: 21
     availableIPv6: 0
   ```

   - `assignedIPv4` represents the total number of IPv4 addresses that MetalLB has successfully assigned from this pool to `LoadBalancer` services.
   - `assignedIPv6` represents the total number of IPv6 addresses that MetalLB has successfully assigned from this pool to `LoadBalancer` services.
   - `availableIPv4` indicates the total number of IPv4 addresses remaining and available for assignment within this pool. MetalLB calculates this value by subtracting `assignedIPv4` from the total theoretical IPv4 addresses in the `spec.addresses` ranges, potentially accounting for `avoidBuggyIPs` if enabled.
   - `availableIPv6` indicates the total number of IPv6 addresses remaining and available for assignment within this pool. The system calculates this value similarly to `availableIPv4`, using the total theoretical IPv6 addresses in the `spec.addresses` ranges.
3. Create an `L2Advertisement` CR for Layer 2 mode with the following sample YAML:

   ```yaml
   apiVersion: metallb.io/v1beta1
   kind: L2Advertisement
   metadata:
     name: l2advertisement
     namespace: metallb-system
   spec:
     ipAddressPools:
     - doc-example-l2
   ```

   1. Apply the configuration for the L2 advertisement by running the following command:

      ```terminal
      $ oc apply -f l2advertisement.yaml
      ```
4. Deploy an application and expose it with a `LoadBalancer` service.

   1. Create a file, like `nginx.yaml`, with the following content to deploy an Nginx application:

      ```yaml
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: nginx-deployment
        labels:
          app: nginx
      spec:
        replicas: 2
        selector:
          matchLabels:
            app: nginx
        template:
          metadata:
            labels:
              app: nginx
          spec:
            containers:
            - name: nginx
              image: quay.io/openshifttest/hello-openshift:multiarch
              ports:
              - containerPort: 8080
      ```
   2. Apply the configuration by running the following command:

      ```terminal
      $ oc apply -f nginx.yaml
      ```
   3. Expose the deployment as a `LoadBalancer` service by creating a file, such as `nginx-service.yaml`, with content like the following:

      ```yaml
      apiVersion: v1
      kind: Service
      metadata:
        name: nginx-service
        namespace: default
        annotations:
          metallb.universe.tf/address-pool: doc-example-l2
      spec:
        selector:
          app: nginx
        ports:
          - protocol: TCP
            port: 80
            targetPort: 8080
        type: LoadBalancer
      ```

      > [!IMPORTANT]
      > The service must be in the same namespace as your application deployment. The `metallb.universe.tf/address-pool` annotation tells MetalLB which `IPAddressPool` to use for IP allocation.
   4. Apply the service configuration by running the following command:

      ```terminal
      $ oc apply -f nginx-service.yaml
      ```
5. View the updated `IPAddressPool` status to see the assigned and available IP addresses by running the following command:

   ```terminal
   $ oc get ipaddresspool doc-example-l2 -n metallb-system -o yaml
   ```

   The output is similar to the following:

   ```yaml
   apiVersion: metallb.io/v1beta1
   kind: IPAddressPool
   metadata:
     annotations:
       kubectl.kubernetes.io/last-applied-configuration: |
         {"apiVersion":"metallb.io/v1beta1","kind":"IPAddressPool","metadata":{"annotations":{},"name":"doc-example-l2","namespace":"metallb-system"},"spec":{"addresses":["192.168.122.200-192.168.122.220"],"autoAssign":true,"avoidBuggyIPs":false}}
     creationTimestamp: "2025-07-17T10:13:37Z"
     generation: 1
     name: doc-example-l2
     namespace: metallb-system
     resourceVersion: "30250"
     uid: 8df1c303-03ac-4d31-8970-6dacdb173dc2
   spec:
     addresses:
     - 192.168.122.200-192.168.122.220
     autoAssign: true
     avoidBuggyIPs: false
   status:
     assignedIPv4: 1
     assignedIPv6: 0
     availableIPv4: 20
     availableIPv6: 0
   ```

   The `assignedIPv4` value of `1` indicates that one IPv4 address from this pool has been successfully assigned by MetalLB to your `nginx-service` `LoadBalancer`.

## Viewing the ServiceBGPStatus custom resource {#nw-viewing-service-bgp-status_monitor-metallb-config-status}

You can verify border gateway protocol (BGP) advertisement status for your services by viewing the `ServiceBGPStatus` custom resource, which shows which BGP peers receive advertisements from each node. This is essential for debugging connectivity in telco environments.

The `ServiceBGPStatus` CR reports the BGP peering status for a service, detailing which neighbors are receiving updates from a specific node.

> [!NOTE]
> `ServiceBGPStatus` resources are created in the `metallb-system` namespace, not in the namespace where your `LoadBalancer` service is deployed. Always query these resources with `-n metallb-system`.

**Prerequisites**

- You have an OpenShift Container Platform cluster with the MetalLB Operator installed.
- You have deployed a MetalLB instance.

This example shows how to configure MetalLB for BGP mode, deploy a service, and view the `ServiceBGPStatus` to verify BGP advertisements.

**Procedure**

1. Create an `IPAddressPool` CR for BGP, like the following example, and save it as `ipaddresspool.yaml`:

   ```yaml
   apiVersion: metallb.io/v1beta1
   kind: IPAddressPool
   metadata:
     name: bgp-pool
     namespace: metallb-system
   spec:
     addresses:
     - 192.168.122.210-192.168.122.220
     autoAssign: true
   ```
2. Run the following command to create the `IPAddressPool` configuration:

   ```terminal
   $ oc apply -f ipaddresspool.yaml
   ```
3. To configure a BGP peer, create a file named `bgppeer.yaml` with the following content:

   ```yaml
   apiVersion: metallb.io/v1beta2
   kind: BGPPeer
   metadata:
     name: bgp-peer
     namespace: metallb-system
   spec:
     myASN: 64501
     peerASN: 64500
     peerAddress: 192.168.1.1
   ```

   - Set the `spec:peerAddress` field to the IP address of your BGP router.
4. Apply the BGPPeer configuration by running the following command:

   ```terminal
   $ oc apply -f bgppeer.yaml
   ```
5. To create a BGP advertisement to advertise the pool, create a file named `bgpadvertisement.yaml` with the following content:

   ```yaml
   apiVersion: metallb.io/v1beta1
   kind: BGPAdvertisement
   metadata:
     name: bgp-advertisement
     namespace: metallb-system
   spec:
     ipAddressPools:
     - bgp-pool
   ```
6. Apply the BGPAdvertisement configuration by running the following command:

   ```terminal
   $ oc apply -f bgpadvertisement.yaml
   ```
7. Deploy an application and expose it with a `LoadBalancer` service. For this example, create a simple test application named for example `test-app` by creating a file named `deployment.yaml` with the following content:

   ```yaml
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: test-app
     namespace: default
   spec:
     replicas: 2
     selector:
       matchLabels:
         app: test-app
     template:
       metadata:
         labels:
           app: test-app
       spec:
         containers:
         - name: test-app
           image: quay.io/openshifttest/hello-openshift:multiarch
           ports:
           - containerPort: 8080
   ```
8. Apply the deployment:

   ```terminal
   $ oc apply -f deployment.yaml
   ```
9. Create a `LoadBalancer` service for the application:

   ```yaml
   apiVersion: v1
   kind: Service
   metadata:
     name: test-service
     namespace: default
   spec:
     selector:
       app: test-app
     ports:
       - protocol: TCP
         port: 80
         targetPort: 8080
     type: LoadBalancer
   ```

   > [!IMPORTANT]
   > The system creates `ServiceBGPStatus` resources automatically only when the service has at least one ready endpoint (running pod). Ensure your application pods are running before checking for `ServiceBGPStatus` resources.
10. Apply the service configuration by running the following command:

    ```terminal
    $ oc apply -f service.yaml
    ```
11. Verify the service received an external IP by running the following command:

    ```terminal
    $ oc get svc test-service -n default
    ```

    The output is similar to the following:

    ```terminal
    NAME           TYPE           CLUSTER-IP       EXTERNAL-IP       PORT(S)        AGE
    test-service   LoadBalancer   172.30.116.108   192.168.122.210   80:32431/TCP   2m
    ```
12. View the `ServiceBGPStatus` resources by running the following command:

    ```terminal
    $ oc get servicebgpstatus -n metallb-system
    ```

    The output is similar to the following:

    ```terminal
    NAME                  NODE       SERVICE NAME   SERVICE NAMESPACE
    bgp-xxxxx             worker0    test-service   default
    ```

    > [!NOTE]
    > `ServiceBGPStatus` resources are created with generated names. Use labels to find the status for your service:
    >
    > ```terminal
    > $ oc get servicebgpstatus -n metallb-system -l metallb.io/service-name=test-service
    > ```
13. View the details of the `ServiceBGPStatus` CR for your service:

    ```terminal
    $ oc get servicebgpstatus bgp-xxxxx -n metallb-system -o yaml
    ```

    The output is similar to the following:

    ```yaml
    apiVersion: metallb.io/v1beta1
    kind: ServiceBGPStatus
    metadata:
      name: bgp-xxxxx
      namespace: metallb-system
      labels:
        metallb.io/node: worker0
        metallb.io/service-name: test-service
        metallb.io/service-namespace: default
    status:
      node: worker0
      peers:
      - bgp-peer
      serviceName: test-service
      serviceNamespace: default
    ```

    - `metadata.labels.metallb.io/node` indicates the node that is advertising the service via BGP.
    - `metadata.labels.metallb.io/service-name` identifies the service being advertised.
    - `metadata.labels.metallb.io/service-namespace` identifies the namespace of the service being advertised.
    - `status.node` confirms the name of the node advertising the service.
    - `status.peers` lists the names of the BGPPeer resources to which the service is being advertised. This is useful for confirming that the advertisement is reaching the intended peers.
    - `status.serviceName` indicates the name of the service being advertised.
    - `status.serviceNamespace` indicates the namespace of the service being advertised.

## Verifying BGP session state {#nw-metallb-verifying-bgp-session_monitor-metallb-config-status}

Once you configure MetalLB for border gateway protocol (BGP) mode, you can verify that the system has established BGP sessions and is advertising routes. You can examine the `BGPSessionState` custom resource (CR) and the `FRRNodeState` CR to troubleshoot BGP connectivity and confirm proper route advertisement.

> [!NOTE]
> The `BGPSessionState` CR is updated at a regular poll interval of 2 minutes. It can take up to 2 minutes for the CR to reflect the actual BGP state.

**Prerequisites**

- You have an OpenShift Container Platform cluster with the MetalLB Operator installed.
- You have configured MetalLB for BGP mode with:

  - An `IPAddressPool`
  - A `BGPPeer` configuration
  - A `BGPAdvertisement`
- You have deployed at least one `LoadBalancer` service.

**Procedure**

1. Check BGP session status by running the following command:

   ```terminal
   $ oc get bgpsessionstates.frrk8s.metallb.io -A -o wide
   ```

   This example output shows the BGP session status between each node and its configured BGP peers. Look for the `BGP` column to confirm that the session is `Established`.

   ```terminal
   NAMESPACE           NAME               NODE       PEER         VRF   BGP           BFD
   openshift-frr-k8s   worker-2gjfq       worker     10.89.0.64         Active        N/A
   openshift-frr-k8s   worker-9gtnb       worker     10.89.0.63         Established   N/A
   openshift-frr-k8s   worker2-rknga      worker2    10.89.0.66         Established   Up
   openshift-frr-k8s   worker2-t7bfc      worker2    172.30.0.2         Established   Down
   ```
2. Check `FRRNodeState` to see the BGP configuration on each node by running the following command:

   ```terminal
   $ oc get frrnodestate -n metallb-system
   ```

   The example output lists the `FRRNodeState` resources for each node where the MetalLB speaker is running.

   ```terminal
   NAME                 AGE
   worker0.example.com  5m
   ```
3. View the detailed BGP configuration and running state by running the following command for a specific node:

   ```terminal
   $ oc get frrnodestate worker0.example.com -n metallb-system -o yaml
   ```

   The `status.runningConfig` field shows the FRR BGP configuration including configured BGP neighbors, route advertisements, and prefix lists.
4. Verify that the system is advertising routes by checking the `FRRNodeState` resource for the relevant node with this command:

   ```terminal
   $ oc get frrnodestate _<node-name>_ -n metallb-system -o jsonpath='{.status.runningConfig}' | grep "network"
   ```

   The output displays the network prefixes that BGP advertises. For example:

   ```terminal
    address-family ipv4 unicast
     network 192.168.122.210/32
   ```

   This confirms that BGP is advertising the service IP.

## Checking MetalLB configuration status {#nw-metallb-checking-configuration-status_monitor-metallb-config-status}

You can verify that the MetalLB controller and speakers have successfully applied the current configuration by viewing the `ConfigurationState` custom resource (CR). MetalLB creates a `ConfigurationState` resource for the controller and one for each speaker node. These resources report whether the configuration is valid and surface error details when validation fails, such as incompatible custom resources.

**Prerequisites**

- You have an OpenShift Container Platform cluster with the MetalLB Operator installed.
- You have deployed a MetalLB instance.
- You have configured MetalLB resources such as `IPAddressPool`, `BGPPeer`, `BFDProfile`, `Community`, or `FRRConfiguration`.

**Procedure**

1. List the `ConfigurationState` resources by running the following command:

   ```terminal
   $ oc get configurationstates -n metallb-system
   ```

   ```terminal {title="Example output"}
   NAME                         RESULT   ERRORSUMMARY   AGE
   controller                   Valid                   75m
   speaker-mysno-sno.demo.lab   Valid                   28m
   ```

   The `controller` resource shows the status for the MetalLB controller. Each `speaker-<node-name>` resource shows the status for the speaker on that node.
2. Verify that the controller has a valid configuration by inspecting the `ConfigurationState` details. Run the following command:

   ```terminal
   $ oc get configurationstates controller -n metallb-system -o yaml
   ```

   ```yaml {title="Example output"}
   apiVersion: metallb.io/v1beta1
   kind: ConfigurationState
   metadata:
     creationTimestamp: "2026-04-21T09:46:47Z"
     generation: 1
     labels:
       metallb.io/component-type: controller
     name: controller
     namespace: metallb-system
     resourceVersion: "28268"
     uid: 23f5c492-4d5c-4893-84ea-77904c006404
   status:
     conditions:
     - lastTransitionTime: "2026-04-21T09:54:00Z"
       message: ""
       reason: Reconciled
       status: "True"
       type: poolReconcilerValid
     result: Valid
   ```

   Confirm that the output has the following values:

   - `result: Valid` indicates that all configured resources are compatible and active. If this value is `Invalid`, check the `errorSummary` field for aggregated error messages that identify which part of the configuration has failed.
   - `message: Describes any configuration problem that occurs.  Here, `""\` confirms that no errors were reported.
   - `reason: Reconciled` with `status: "True"` confirms that the reconciler has successfully processed the configuration. If the `reason` is `ReconciliationFailed` and `status` is `"False"`, the `message` field contains details about the failure.

     > [!NOTE]
     > The controller does not validate peer-level settings. Errors such as a missing `BFDProfile`, undefined `Community`, or missing authentication secret are reported only by the speakers. A `Valid` controller with one or more `Invalid` speakers is expected in these cases. Always check both controller and speaker `ConfigurationState` resources.

     If the configuration is invalid, the output is similar to the following example:

     ```yaml
     apiVersion: metallb.io/v1beta1
     kind: ConfigurationState
     metadata:
       creationTimestamp: "2026-04-21T09:51:17Z"
       generation: 1
       labels:
         metallb.io/component-type: speaker
         metallb.io/node-name: mysno-sno.demo.lab
       name: speaker-mysno-sno.demo.lab
       namespace: metallb-system
       resourceVersion: "31161"
       uid: 339781bf-ec9a-4ba9-aaba-0a9ac8ebce78
     status:
       conditions:
       - lastTransitionTime: "2026-04-21T10:09:34Z"
         message: 'configuration error: peer peer1 referencing non existing bfd profile
           my-bfd-profile'
         reason: ConfigurationError
         status: "False"
         type: configReconcilerValid
       errorSummary: 'configuration error: peer peer1 referencing non existing bfd profile
         my-bfd-profile'
       result: Invalid
     ```

     Confirm that the output has the following values to identify the problem:
   - `result: Invalid` indicates that one or more configured resources are incompatible. The `errorSummary` field provides an aggregated description of the problem.
   - `reason: ConfigurationError` with `status: "False"` indicates that the reconciler failed to process the configuration. The `message` field describes the specific error.
   - In this example, the `BGPPeer` resource `peer1` references a `BFDProfile` named `my-bfd-profile` that does not exist. To resolve this error, either create the missing `BFDProfile` resource or update the `BGPPeer` to reference an existing `BFDProfile`.

     > [!NOTE]
     > The `ConfigurationState` resource does not report errors that arise when the configuration applied by the speaker to the `frr-k8s` daemon conflicts with other external configurations within that daemon.
3. After correcting the configuration, verify that the status shows a valid configuration by running the following command:

   ```terminal
   $ oc get configurationstates -n metallb-system -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.result}{"\n"}{end}'
   ```

   A return value of `Valid` for all entries confirms that the MetalLB controller and speakers are operating with a valid configuration.

**Additional resources**
{._additional-resources}

- [About MetalLB and the MetalLB Operator](/openshift-docs-markdown/networking/networking_operators/metallb-operator/about-metallb#about-metallb)
