update charts
diff --git a/charts/metallb/templates/NOTES.txt b/charts/metallb/templates/NOTES.txt
new file mode 100644
index 0000000..23d1d5b
--- /dev/null
+++ b/charts/metallb/templates/NOTES.txt
@@ -0,0 +1,4 @@
+MetalLB is now running in the cluster.
+
+Now you can configure it via its CRs. Please refer to the metallb official docs
+on how to use the CRs.
diff --git a/charts/metallb/templates/_helpers.tpl b/charts/metallb/templates/_helpers.tpl
new file mode 100644
index 0000000..53d9528
--- /dev/null
+++ b/charts/metallb/templates/_helpers.tpl
@@ -0,0 +1,113 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "metallb.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "metallb.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "metallb.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "metallb.labels" -}}
+helm.sh/chart: {{ include "metallb.chart" . }}
+{{ include "metallb.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "metallb.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "metallb.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the controller service account to use
+*/}}
+{{- define "metallb.controller.serviceAccountName" -}}
+{{- if .Values.controller.serviceAccount.create }}
+{{- default (printf "%s-controller" (include "metallb.fullname" .)) .Values.controller.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.controller.serviceAccount.name }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create the name of the speaker service account to use
+*/}}
+{{- define "metallb.speaker.serviceAccountName" -}}
+{{- if .Values.speaker.serviceAccount.create }}
+{{- default (printf "%s-speaker" (include "metallb.fullname" .)) .Values.speaker.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.speaker.serviceAccount.name }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create the name of the settings Secret to use.
+*/}}
+{{- define "metallb.secretName" -}}
+    {{ default ( printf "%s-memberlist" (include "metallb.fullname" .)) .Values.speaker.secretName | trunc 63 | trimSuffix "-" }}
+{{- end -}}
+
+{{- define "metrics.exposedportname" -}}
+{{- if .Values.prometheus.secureMetricsPort -}}
+"metricshttps"
+{{- else -}}
+"metrics"
+{{- end -}}
+{{- end -}}
+
+{{- define "metrics.exposedfrrportname" -}}
+{{- if .Values.speaker.frr.secureMetricsPort -}}
+"frrmetricshttps"
+{{- else -}}
+"frrmetrics"
+{{- end }}
+{{- end }}
+
+{{- define "metrics.exposedport" -}}
+{{- if .Values.prometheus.secureMetricsPort -}}
+{{ .Values.prometheus.secureMetricsPort }}
+{{- else -}}
+{{ .Values.prometheus.metricsPort }}
+{{- end -}}
+{{- end }}
+
+{{- define "metrics.exposedfrrport" -}}
+{{- if .Values.speaker.frr.secureMetricsPort -}}
+{{ .Values.speaker.frr.secureMetricsPort }}
+{{- else -}}
+{{ .Values.speaker.frr.metricsPort }}
+{{- end }}
+{{- end }}
diff --git a/charts/metallb/templates/controller.yaml b/charts/metallb/templates/controller.yaml
new file mode 100644
index 0000000..2b522d1
--- /dev/null
+++ b/charts/metallb/templates/controller.yaml
@@ -0,0 +1,182 @@
+{{- if .Values.controller.enabled }}
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ template "metallb.fullname" . }}-controller
+  namespace: {{ .Release.Namespace | quote }}
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+    app.kubernetes.io/component: controller
+    {{- range $key, $value := .Values.controller.labels }}
+    {{ $key }}: {{ $value | quote }}
+    {{- end }}
+spec:
+  {{- if .Values.controller.strategy }}
+  strategy: {{- toYaml .Values.controller.strategy | nindent 4 }}
+  {{- end }}
+  selector:
+    matchLabels:
+      {{- include "metallb.selectorLabels" . | nindent 6 }}
+      app.kubernetes.io/component: controller
+  template:
+    metadata:
+      {{- if or .Values.prometheus.scrapeAnnotations .Values.controller.podAnnotations }}
+      annotations:
+        {{- if .Values.prometheus.scrapeAnnotations }}
+        prometheus.io/scrape: "true"
+        prometheus.io/port: "{{ .Values.prometheus.metricsPort }}"
+        {{- end }}
+        {{- with .Values.controller.podAnnotations }}
+          {{- toYaml . | nindent 8 }}
+        {{- end }}
+      {{- end }}
+      labels:
+        {{- include "metallb.selectorLabels" . | nindent 8 }}
+        app.kubernetes.io/component: controller
+        {{- range $key, $value := .Values.controller.labels }}
+        {{ $key }}: {{ $value | quote }}
+        {{- end }}
+    spec:
+      {{- with .Values.controller.runtimeClassName }}
+      runtimeClassName: {{ . | quote }}
+      {{- end }}
+      {{- with .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      serviceAccountName: {{ template "metallb.controller.serviceAccountName" . }}
+      terminationGracePeriodSeconds: 0
+{{- if .Values.controller.securityContext }}
+      securityContext:
+{{ toYaml .Values.controller.securityContext | indent 8 }}
+{{- end }}
+      containers:
+      - name: controller
+        image: {{ .Values.controller.image.repository }}:{{ .Values.controller.image.tag | default .Chart.AppVersion }}
+        {{- if .Values.controller.image.pullPolicy }}
+        imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
+        {{- end }}
+        {{- if .Values.controller.command }}
+        command:
+          - {{ .Values.controller.command }}
+        {{- end }}
+        args:
+        - --port={{ .Values.prometheus.metricsPort }}
+        {{- with .Values.controller.logLevel }}
+        - --log-level={{ . }}
+        {{- end }}
+        - --cert-service-name=metallb-webhook-service
+        {{- if .Values.loadBalancerClass }}
+        - --lb-class={{ .Values.loadBalancerClass }}
+        {{- end }}
+        {{- if .Values.controller.webhookMode }}
+        - --webhook-mode={{ .Values.controller.webhookMode }}
+        {{- end }}
+        env:
+        {{- if and .Values.speaker.enabled .Values.speaker.memberlist.enabled }}
+        - name: METALLB_ML_SECRET_NAME
+          value: {{ include "metallb.secretName" . }}
+        - name: METALLB_DEPLOYMENT
+          value: {{ template "metallb.fullname" . }}-controller
+        {{- end }}
+        {{- if .Values.speaker.frr.enabled }}
+        - name: METALLB_BGP_TYPE
+          value: frr
+        {{- end }}
+        ports:
+        - name: monitoring
+          containerPort: {{ .Values.prometheus.metricsPort }}
+        - containerPort: 9443
+          name: webhook-server
+          protocol: TCP
+        volumeMounts:
+        - mountPath: /tmp/k8s-webhook-server/serving-certs
+          name: cert
+          readOnly: true
+        {{- if .Values.controller.livenessProbe.enabled }}
+        livenessProbe:
+          httpGet:
+            path: /metrics
+            port: monitoring
+          initialDelaySeconds: {{ .Values.controller.livenessProbe.initialDelaySeconds }}
+          periodSeconds: {{ .Values.controller.livenessProbe.periodSeconds }}
+          timeoutSeconds: {{ .Values.controller.livenessProbe.timeoutSeconds }}
+          successThreshold: {{ .Values.controller.livenessProbe.successThreshold }}
+          failureThreshold: {{ .Values.controller.livenessProbe.failureThreshold }}
+        {{- end }}
+        {{- if .Values.controller.readinessProbe.enabled }}
+        readinessProbe:
+          httpGet:
+            path: /metrics
+            port: monitoring
+          initialDelaySeconds: {{ .Values.controller.readinessProbe.initialDelaySeconds }}
+          periodSeconds: {{ .Values.controller.readinessProbe.periodSeconds }}
+          timeoutSeconds: {{ .Values.controller.readinessProbe.timeoutSeconds }}
+          successThreshold: {{ .Values.controller.readinessProbe.successThreshold }}
+          failureThreshold: {{ .Values.controller.readinessProbe.failureThreshold }}
+        {{- end }}
+        {{- with .Values.controller.resources }}
+        resources:
+          {{- toYaml . | nindent 10 }}
+        {{- end }}
+        securityContext:
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
+          capabilities:
+            drop:
+            - ALL
+      {{- if .Values.prometheus.secureMetricsPort }}
+      - name: kube-rbac-proxy
+        image: {{ .Values.prometheus.rbacProxy.repository }}:{{ .Values.prometheus.rbacProxy.tag }}
+        imagePullPolicy: {{ .Values.prometheus.rbacProxy.pullPolicy }}
+        args:
+          - --logtostderr
+          - --secure-listen-address=:{{ .Values.prometheus.secureMetricsPort }}
+          - --upstream=http://127.0.0.1:{{ .Values.prometheus.metricsPort }}/
+          - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+        {{- if .Values.prometheus.controllerMetricsTLSSecret }}
+          - --tls-private-key-file=/etc/metrics/tls.key
+          - --tls-cert-file=/etc/metrics/tls.crt
+        {{- end }}
+        ports:
+          - containerPort: {{ .Values.prometheus.secureMetricsPort }}
+            name: metricshttps
+        resources:
+          requests:
+            cpu: 10m
+            memory: 20Mi
+        terminationMessagePolicy: FallbackToLogsOnError
+        {{- if .Values.prometheus.controllerMetricsTLSSecret }}
+        volumeMounts:
+          - name: metrics-certs
+            mountPath: /etc/metrics
+            readOnly: true
+        {{- end }}
+      {{ end }}
+      nodeSelector:
+        "kubernetes.io/os": linux
+        {{- with .Values.controller.nodeSelector }}
+          {{- toYaml . | nindent 8 }}
+        {{- end }}
+      {{- with .Values.controller.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.controller.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 6 }}
+      {{- end }}
+      {{- with .Values.controller.priorityClassName }}
+      priorityClassName: {{ . | quote }}
+      {{- end }}
+      volumes:
+      - name: cert
+        secret:
+          defaultMode: 420
+          secretName: webhook-server-cert
+      {{- if .Values.prometheus.controllerMetricsTLSSecret }}
+      - name: metrics-certs
+        secret:
+          secretName: {{ .Values.prometheus.controllerMetricsTLSSecret }}
+      {{- end }}
+{{- end }}
diff --git a/charts/metallb/templates/deprecated_configInline.yaml b/charts/metallb/templates/deprecated_configInline.yaml
new file mode 100644
index 0000000..8a1a551
--- /dev/null
+++ b/charts/metallb/templates/deprecated_configInline.yaml
@@ -0,0 +1,3 @@
+{{- if .Values.configInline }}
+{{- fail "Starting from v0.13.0 configInline is no longer supported. Please see https://metallb.universe.tf/#backward-compatibility" }}
+{{- end }}
diff --git a/charts/metallb/templates/exclude-l2-config.yaml b/charts/metallb/templates/exclude-l2-config.yaml
new file mode 100644
index 0000000..cacea8f
--- /dev/null
+++ b/charts/metallb/templates/exclude-l2-config.yaml
@@ -0,0 +1,23 @@
+{{- if .Values.speaker.excludeInterfaces.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: metallb-excludel2
+  namespace: {{ .Release.Namespace | quote }}
+data:
+  excludel2.yaml: |
+    announcedInterfacesToExclude:
+    - ^docker.*
+    - ^cbr.*
+    - ^dummy.*
+    - ^virbr.*
+    - ^lxcbr.*
+    - ^veth.*
+    - ^lo$
+    - ^cali.*
+    - ^tunl.*
+    - ^flannel.*
+    - ^kube-ipvs.*
+    - ^cni.*
+    - ^nodelocaldns.*
+{{- end }}
\ No newline at end of file
diff --git a/charts/metallb/templates/manifest.yaml b/charts/metallb/templates/manifest.yaml
deleted file mode 100644
index 537ab7f..0000000
--- a/charts/metallb/templates/manifest.yaml
+++ /dev/null
@@ -1,2033 +0,0 @@
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
-  creationTimestamp: null
-  name: addresspools.metallb.io
-spec:
-  conversion:
-    strategy: Webhook
-    webhook:
-      clientConfig:
-        caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlGWlRDQ0EwMmdBd0lCQWdJVU5GRW1XcTM3MVpKdGkrMmlSQzk1WmpBV1MxZ3dEUVlKS29aSWh2Y05BUUVMDQpCUUF3UWpFTE1Ba0dBMVVFQmhNQ1dGZ3hGVEFUQmdOVkJBY01ERVJsWm1GMWJIUWdRMmwwZVRFY01Cb0dBMVVFDQpDZ3dUUkdWbVlYVnNkQ0JEYjIxd1lXNTVJRXgwWkRBZUZ3MHlNakEzTVRrd09UTXlNek5hRncweU1qQTRNVGd3DQpPVE15TXpOYU1FSXhDekFKQmdOVkJBWVRBbGhZTVJVd0V3WURWUVFIREF4RVpXWmhkV3gwSUVOcGRIa3hIREFhDQpCZ05WQkFvTUUwUmxabUYxYkhRZ1EyOXRjR0Z1ZVNCTWRHUXdnZ0lpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElDDQpEd0F3Z2dJS0FvSUNBUUNxVFpxMWZRcC9vYkdlenhES0o3OVB3Ny94azJwellualNzMlkzb1ZYSm5sRmM4YjVlDQpma2ZZQnY2bndscW1keW5PL2phWFBaQmRQSS82aFdOUDBkdVhadEtWU0NCUUpyZzEyOGNXb3F0MGNTN3pLb1VpDQpvcU1tQ0QvRXVBeFFNZjhRZDF2c1gvVllkZ0poVTZBRXJLZEpIaXpFOUJtUkNkTDBGMW1OVW55Rk82UnRtWFZUDQpidkxsTDVYeTc2R0FaQVBLOFB4aVlDa0NtbDdxN0VnTWNiOXlLWldCYmlxQ3VkTXE5TGJLNmdKNzF6YkZnSXV4DQo1L1pXK2JraTB2RlplWk9ZODUxb1psckFUNzJvMDI4NHNTWW9uN0pHZVZkY3NoUnh5R1VpSFpSTzdkaXZVTDVTDQpmM2JmSDFYbWY1ZDQzT0NWTWRuUUV2NWVaOG8zeWVLa3ZrbkZQUGVJMU9BbjdGbDlFRVNNR2dhOGFaSG1URSttDQpsLzlMSmdDYjBnQmtPT0M0WnV4bWh2aERKV1EzWnJCS3pMQlNUZXN0NWlLNVlwcXRWVVk2THRyRW9FelVTK1lsDQpwWndXY2VQWHlHeHM5ZURsR3lNVmQraW15Y3NTU1UvVno2Mmx6MnZCS21NTXBkYldDQWhud0RsRTVqU2dyMjRRDQp0eGNXLys2N3d5KzhuQlI3UXdqVTFITndVRjBzeERWdEwrZ1NHVERnSEVZSlhZelYvT05zMy94TkpoVFNPSkxNDQpoeXNVdyttaGdackdhbUdXcHVIVU1DUitvTWJzMTc1UkcrQjJnUFFHVytPTjJnUTRyOXN2b0ZBNHBBQm8xd1dLDQpRYjRhY3pmeVVscElBOVFoSmFsZEY3S3dPSHVlV3gwRUNrNXg0T2tvVDBvWVp0dzFiR0JjRGtaSmF3SURBUUFCDQpvMU13VVRBZEJnTlZIUTRFRmdRVW90UlNIUm9IWTEyRFZ4R0NCdEhpb1g2ZmVFQXdId1lEVlIwakJCZ3dGb0FVDQpvdFJTSFJvSFkxMkRWeEdDQnRIaW9YNmZlRUF3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFOQmdrcWhraUc5dzBCDQpBUXNGQUFPQ0FnRUFSbkpsWWRjMTFHd0VxWnh6RDF2R3BDR2pDN2VWTlQ3aVY1d3IybXlybHdPYi9aUWFEa0xYDQpvVStaOVVXT1VlSXJTdzUydDdmQUpvVVAwSm5iYkMveVIrU1lqUGhvUXNiVHduOTc2ZldBWTduM3FMOXhCd1Y0DQphek41OXNjeUp0dlhMeUtOL2N5ak1ReDRLajBIMFg0bWJ6bzVZNUtzWWtYVU0vOEFPdWZMcEd0S1NGVGgrSEFDDQpab1Q5YnZHS25adnNHd0tYZFF0Wnh0akhaUjVqK3U3ZGtQOTJBT051RFNabS8rWVV4b2tBK09JbzdSR3BwSHNXDQo1ZTdNY0FTVXRtb1FORXd6dVFoVkJaRWQ1OGtKYjUrV0VWbGNzanlXNnRTbzErZ25tTWNqR1BsMWgxR2hVbjV4DQpFY0lWRnBIWXM5YWo1NmpBSjk1MVQvZjhMaWxmTlVnanBLQ0c1bnl0SUt3emxhOHNtdGlPdm1UNEpYbXBwSkI2DQo4bmdHRVluVjUrUTYwWFJ2OEhSSGp1VG9CRHVhaERrVDA2R1JGODU1d09FR2V4bkZpMXZYWUxLVllWb1V2MXRKDQo4dVdUR1pwNllDSVJldlBqbzg5ZytWTlJSaVFYUThJd0dybXE5c0RoVTlqTjA0SjdVL1RvRDFpNHE3VnlsRUc5DQorV1VGNkNLaEdBeTJIaEhwVncyTGFoOS9lUzdZMUZ1YURrWmhPZG1laG1BOCtqdHNZamJadnR5Mm1SWlF0UUZzDQpUU1VUUjREbUR2bVVPRVRmeStpRHdzK2RkWXVNTnJGeVVYV2dkMnpBQU4ydVl1UHFGY2pRcFNPODFzVTJTU3R3DQoxVzAyeUtYOGJEYmZFdjBzbUh3UzliQnFlSGo5NEM1Mjg0YXpsdTBmaUdpTm1OUEM4ckJLRmhBPQ0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
-        service:
-          name: webhook-service
-          namespace: metallb-system
-          path: /convert
-      conversionReviewVersions:
-      - v1alpha1
-      - v1beta1
-  group: metallb.io
-  names:
-    kind: AddressPool
-    listKind: AddressPoolList
-    plural: addresspools
-    singular: addresspool
-  scope: Namespaced
-  versions:
-  - deprecated: true
-    deprecationWarning: metallb.io v1alpha1 AddressPool is deprecated
-    name: v1alpha1
-    schema:
-      openAPIV3Schema:
-        description: AddressPool is the Schema for the addresspools API.
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: AddressPoolSpec defines the desired state of AddressPool.
-            properties:
-              addresses:
-                description: A list of IP address ranges over which MetalLB has authority.
-                  You can list multiple ranges in a single pool, they will all share
-                  the same settings. Each range can be either a CIDR prefix, or an
-                  explicit start-end range of IPs.
-                items:
-                  type: string
-                type: array
-              autoAssign:
-                default: true
-                description: AutoAssign flag used to prevent MetallB from automatic
-                  allocation for a pool.
-                type: boolean
-              bgpAdvertisements:
-                description: When an IP is allocated from this pool, how should it
-                  be translated into BGP announcements?
-                items:
-                  properties:
-                    aggregationLength:
-                      default: 32
-                      description: The aggregation-length advertisement option lets
-                        you “roll up” the /32s into a larger prefix.
-                      format: int32
-                      minimum: 1
-                      type: integer
-                    aggregationLengthV6:
-                      default: 128
-                      description: Optional, defaults to 128 (i.e. no aggregation)
-                        if not specified.
-                      format: int32
-                      type: integer
-                    communities:
-                      description: BGP communities
-                      items:
-                        type: string
-                      type: array
-                    localPref:
-                      description: BGP LOCAL_PREF attribute which is used by BGP best
-                        path algorithm, Path with higher localpref is preferred over
-                        one with lower localpref.
-                      format: int32
-                      type: integer
-                  type: object
-                type: array
-              protocol:
-                description: Protocol can be used to select how the announcement is
-                  done.
-                enum:
-                - layer2
-                - bgp
-                type: string
-            required:
-            - addresses
-            - protocol
-            type: object
-          status:
-            description: AddressPoolStatus defines the observed state of AddressPool.
-            type: object
-        required:
-        - spec
-        type: object
-    served: true
-    storage: false
-    subresources:
-      status: {}
-  - deprecated: true
-    deprecationWarning: metallb.io v1beta1 AddressPool is deprecated, consider using
-      IPAddressPool
-    name: v1beta1
-    schema:
-      openAPIV3Schema:
-        description: AddressPool represents a pool of IP addresses that can be allocated
-          to LoadBalancer services. AddressPool is deprecated and being replaced by
-          IPAddressPool.
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: AddressPoolSpec defines the desired state of AddressPool.
-            properties:
-              addresses:
-                description: A list of IP address ranges over which MetalLB has authority.
-                  You can list multiple ranges in a single pool, they will all share
-                  the same settings. Each range can be either a CIDR prefix, or an
-                  explicit start-end range of IPs.
-                items:
-                  type: string
-                type: array
-              autoAssign:
-                default: true
-                description: AutoAssign flag used to prevent MetallB from automatic
-                  allocation for a pool.
-                type: boolean
-              bgpAdvertisements:
-                description: Drives how an IP allocated from this pool should translated
-                  into BGP announcements.
-                items:
-                  properties:
-                    aggregationLength:
-                      default: 32
-                      description: The aggregation-length advertisement option lets
-                        you “roll up” the /32s into a larger prefix.
-                      format: int32
-                      minimum: 1
-                      type: integer
-                    aggregationLengthV6:
-                      default: 128
-                      description: Optional, defaults to 128 (i.e. no aggregation)
-                        if not specified.
-                      format: int32
-                      type: integer
-                    communities:
-                      description: BGP communities to be associated with the given
-                        advertisement.
-                      items:
-                        type: string
-                      type: array
-                    localPref:
-                      description: BGP LOCAL_PREF attribute which is used by BGP best
-                        path algorithm, Path with higher localpref is preferred over
-                        one with lower localpref.
-                      format: int32
-                      type: integer
-                  type: object
-                type: array
-              protocol:
-                description: Protocol can be used to select how the announcement is
-                  done.
-                enum:
-                - layer2
-                - bgp
-                type: string
-            required:
-            - addresses
-            - protocol
-            type: object
-          status:
-            description: AddressPoolStatus defines the observed state of AddressPool.
-            type: object
-        required:
-        - spec
-        type: object
-    served: true
-    storage: true
-    subresources:
-      status: {}
----
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
-  creationTimestamp: null
-  name: bfdprofiles.metallb.io
-spec:
-  group: metallb.io
-  names:
-    kind: BFDProfile
-    listKind: BFDProfileList
-    plural: bfdprofiles
-    singular: bfdprofile
-  scope: Namespaced
-  versions:
-  - additionalPrinterColumns:
-    - jsonPath: .spec.passiveMode
-      name: Passive Mode
-      type: boolean
-    - jsonPath: .spec.transmitInterval
-      name: Transmit Interval
-      type: integer
-    - jsonPath: .spec.receiveInterval
-      name: Receive Interval
-      type: integer
-    - jsonPath: .spec.detectMultiplier
-      name: Multiplier
-      type: integer
-    name: v1beta1
-    schema:
-      openAPIV3Schema:
-        description: BFDProfile represents the settings of the bfd session that can
-          be optionally associated with a BGP session.
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: BFDProfileSpec defines the desired state of BFDProfile.
-            properties:
-              detectMultiplier:
-                description: Configures the detection multiplier to determine packet
-                  loss. The remote transmission interval will be multiplied by this
-                  value to determine the connection loss detection timer.
-                format: int32
-                maximum: 255
-                minimum: 2
-                type: integer
-              echoInterval:
-                description: Configures the minimal echo receive transmission interval
-                  that this system is capable of handling in milliseconds. Defaults
-                  to 50ms
-                format: int32
-                maximum: 60000
-                minimum: 10
-                type: integer
-              echoMode:
-                description: Enables or disables the echo transmission mode. This
-                  mode is disabled by default, and not supported on multi hops setups.
-                type: boolean
-              minimumTtl:
-                description: 'For multi hop sessions only: configure the minimum expected
-                  TTL for an incoming BFD control packet.'
-                format: int32
-                maximum: 254
-                minimum: 1
-                type: integer
-              passiveMode:
-                description: 'Mark session as passive: a passive session will not
-                  attempt to start the connection and will wait for control packets
-                  from peer before it begins replying.'
-                type: boolean
-              receiveInterval:
-                description: The minimum interval that this system is capable of receiving
-                  control packets in milliseconds. Defaults to 300ms.
-                format: int32
-                maximum: 60000
-                minimum: 10
-                type: integer
-              transmitInterval:
-                description: The minimum transmission interval (less jitter) that
-                  this system wants to use to send BFD control packets in milliseconds.
-                  Defaults to 300ms
-                format: int32
-                maximum: 60000
-                minimum: 10
-                type: integer
-            type: object
-          status:
-            description: BFDProfileStatus defines the observed state of BFDProfile.
-            type: object
-        type: object
-    served: true
-    storage: true
-    subresources:
-      status: {}
----
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
-  creationTimestamp: null
-  name: bgpadvertisements.metallb.io
-spec:
-  group: metallb.io
-  names:
-    kind: BGPAdvertisement
-    listKind: BGPAdvertisementList
-    plural: bgpadvertisements
-    singular: bgpadvertisement
-  scope: Namespaced
-  versions:
-  - additionalPrinterColumns:
-    - jsonPath: .spec.ipAddressPools
-      name: IPAddressPools
-      type: string
-    - jsonPath: .spec.ipAddressPoolSelectors
-      name: IPAddressPool Selectors
-      type: string
-    - jsonPath: .spec.peers
-      name: Peers
-      type: string
-    - jsonPath: .spec.nodeSelectors
-      name: Node Selectors
-      priority: 10
-      type: string
-    name: v1beta1
-    schema:
-      openAPIV3Schema:
-        description: BGPAdvertisement allows to advertise the IPs coming from the
-          selected IPAddressPools via BGP, setting the parameters of the BGP Advertisement.
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: BGPAdvertisementSpec defines the desired state of BGPAdvertisement.
-            properties:
-              aggregationLength:
-                default: 32
-                description: The aggregation-length advertisement option lets you
-                  “roll up” the /32s into a larger prefix. Defaults to 32. Works for
-                  IPv4 addresses.
-                format: int32
-                minimum: 1
-                type: integer
-              aggregationLengthV6:
-                default: 128
-                description: The aggregation-length advertisement option lets you
-                  “roll up” the /128s into a larger prefix. Defaults to 128. Works
-                  for IPv6 addresses.
-                format: int32
-                type: integer
-              communities:
-                description: The BGP communities to be associated with the announcement.
-                  Each item can be a standard community of the form 1234:1234, a large
-                  community of the form large:1234:1234:1234 or the name of an alias
-                  defined in the Community CRD.
-                items:
-                  type: string
-                type: array
-              ipAddressPoolSelectors:
-                description: A selector for the IPAddressPools which would get advertised
-                  via this advertisement. If no IPAddressPool is selected by this
-                  or by the list, the advertisement is applied to all the IPAddressPools.
-                items:
-                  description: A label selector is a label query over a set of resources.
-                    The result of matchLabels and matchExpressions are ANDed. An empty
-                    label selector matches all objects. A null label selector matches
-                    no objects.
-                  properties:
-                    matchExpressions:
-                      description: matchExpressions is a list of label selector requirements.
-                        The requirements are ANDed.
-                      items:
-                        description: A label selector requirement is a selector that
-                          contains values, a key, and an operator that relates the
-                          key and values.
-                        properties:
-                          key:
-                            description: key is the label key that the selector applies
-                              to.
-                            type: string
-                          operator:
-                            description: operator represents a key's relationship
-                              to a set of values. Valid operators are In, NotIn, Exists
-                              and DoesNotExist.
-                            type: string
-                          values:
-                            description: values is an array of string values. If the
-                              operator is In or NotIn, the values array must be non-empty.
-                              If the operator is Exists or DoesNotExist, the values
-                              array must be empty. This array is replaced during a
-                              strategic merge patch.
-                            items:
-                              type: string
-                            type: array
-                        required:
-                        - key
-                        - operator
-                        type: object
-                      type: array
-                    matchLabels:
-                      additionalProperties:
-                        type: string
-                      description: matchLabels is a map of {key,value} pairs. A single
-                        {key,value} in the matchLabels map is equivalent to an element
-                        of matchExpressions, whose key field is "key", the operator
-                        is "In", and the values array contains only "value". The requirements
-                        are ANDed.
-                      type: object
-                  type: object
-                  x-kubernetes-map-type: atomic
-                type: array
-              ipAddressPools:
-                description: The list of IPAddressPools to advertise via this advertisement,
-                  selected by name.
-                items:
-                  type: string
-                type: array
-              localPref:
-                description: The BGP LOCAL_PREF attribute which is used by BGP best
-                  path algorithm, Path with higher localpref is preferred over one
-                  with lower localpref.
-                format: int32
-                type: integer
-              nodeSelectors:
-                description: NodeSelectors allows to limit the nodes to announce as
-                  next hops for the LoadBalancer IP. When empty, all the nodes having  are
-                  announced as next hops.
-                items:
-                  description: A label selector is a label query over a set of resources.
-                    The result of matchLabels and matchExpressions are ANDed. An empty
-                    label selector matches all objects. A null label selector matches
-                    no objects.
-                  properties:
-                    matchExpressions:
-                      description: matchExpressions is a list of label selector requirements.
-                        The requirements are ANDed.
-                      items:
-                        description: A label selector requirement is a selector that
-                          contains values, a key, and an operator that relates the
-                          key and values.
-                        properties:
-                          key:
-                            description: key is the label key that the selector applies
-                              to.
-                            type: string
-                          operator:
-                            description: operator represents a key's relationship
-                              to a set of values. Valid operators are In, NotIn, Exists
-                              and DoesNotExist.
-                            type: string
-                          values:
-                            description: values is an array of string values. If the
-                              operator is In or NotIn, the values array must be non-empty.
-                              If the operator is Exists or DoesNotExist, the values
-                              array must be empty. This array is replaced during a
-                              strategic merge patch.
-                            items:
-                              type: string
-                            type: array
-                        required:
-                        - key
-                        - operator
-                        type: object
-                      type: array
-                    matchLabels:
-                      additionalProperties:
-                        type: string
-                      description: matchLabels is a map of {key,value} pairs. A single
-                        {key,value} in the matchLabels map is equivalent to an element
-                        of matchExpressions, whose key field is "key", the operator
-                        is "In", and the values array contains only "value". The requirements
-                        are ANDed.
-                      type: object
-                  type: object
-                  x-kubernetes-map-type: atomic
-                type: array
-              peers:
-                description: Peers limits the bgppeer to advertise the ips of the
-                  selected pools to. When empty, the loadbalancer IP is announced
-                  to all the BGPPeers configured.
-                items:
-                  type: string
-                type: array
-            type: object
-          status:
-            description: BGPAdvertisementStatus defines the observed state of BGPAdvertisement.
-            type: object
-        type: object
-    served: true
-    storage: true
-    subresources:
-      status: {}
----
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
-  creationTimestamp: null
-  name: bgppeers.metallb.io
-spec:
-  conversion:
-    strategy: Webhook
-    webhook:
-      clientConfig:
-        caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlGWlRDQ0EwMmdBd0lCQWdJVU5GRW1XcTM3MVpKdGkrMmlSQzk1WmpBV1MxZ3dEUVlKS29aSWh2Y05BUUVMDQpCUUF3UWpFTE1Ba0dBMVVFQmhNQ1dGZ3hGVEFUQmdOVkJBY01ERVJsWm1GMWJIUWdRMmwwZVRFY01Cb0dBMVVFDQpDZ3dUUkdWbVlYVnNkQ0JEYjIxd1lXNTVJRXgwWkRBZUZ3MHlNakEzTVRrd09UTXlNek5hRncweU1qQTRNVGd3DQpPVE15TXpOYU1FSXhDekFKQmdOVkJBWVRBbGhZTVJVd0V3WURWUVFIREF4RVpXWmhkV3gwSUVOcGRIa3hIREFhDQpCZ05WQkFvTUUwUmxabUYxYkhRZ1EyOXRjR0Z1ZVNCTWRHUXdnZ0lpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElDDQpEd0F3Z2dJS0FvSUNBUUNxVFpxMWZRcC9vYkdlenhES0o3OVB3Ny94azJwellualNzMlkzb1ZYSm5sRmM4YjVlDQpma2ZZQnY2bndscW1keW5PL2phWFBaQmRQSS82aFdOUDBkdVhadEtWU0NCUUpyZzEyOGNXb3F0MGNTN3pLb1VpDQpvcU1tQ0QvRXVBeFFNZjhRZDF2c1gvVllkZ0poVTZBRXJLZEpIaXpFOUJtUkNkTDBGMW1OVW55Rk82UnRtWFZUDQpidkxsTDVYeTc2R0FaQVBLOFB4aVlDa0NtbDdxN0VnTWNiOXlLWldCYmlxQ3VkTXE5TGJLNmdKNzF6YkZnSXV4DQo1L1pXK2JraTB2RlplWk9ZODUxb1psckFUNzJvMDI4NHNTWW9uN0pHZVZkY3NoUnh5R1VpSFpSTzdkaXZVTDVTDQpmM2JmSDFYbWY1ZDQzT0NWTWRuUUV2NWVaOG8zeWVLa3ZrbkZQUGVJMU9BbjdGbDlFRVNNR2dhOGFaSG1URSttDQpsLzlMSmdDYjBnQmtPT0M0WnV4bWh2aERKV1EzWnJCS3pMQlNUZXN0NWlLNVlwcXRWVVk2THRyRW9FelVTK1lsDQpwWndXY2VQWHlHeHM5ZURsR3lNVmQraW15Y3NTU1UvVno2Mmx6MnZCS21NTXBkYldDQWhud0RsRTVqU2dyMjRRDQp0eGNXLys2N3d5KzhuQlI3UXdqVTFITndVRjBzeERWdEwrZ1NHVERnSEVZSlhZelYvT05zMy94TkpoVFNPSkxNDQpoeXNVdyttaGdackdhbUdXcHVIVU1DUitvTWJzMTc1UkcrQjJnUFFHVytPTjJnUTRyOXN2b0ZBNHBBQm8xd1dLDQpRYjRhY3pmeVVscElBOVFoSmFsZEY3S3dPSHVlV3gwRUNrNXg0T2tvVDBvWVp0dzFiR0JjRGtaSmF3SURBUUFCDQpvMU13VVRBZEJnTlZIUTRFRmdRVW90UlNIUm9IWTEyRFZ4R0NCdEhpb1g2ZmVFQXdId1lEVlIwakJCZ3dGb0FVDQpvdFJTSFJvSFkxMkRWeEdDQnRIaW9YNmZlRUF3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFOQmdrcWhraUc5dzBCDQpBUXNGQUFPQ0FnRUFSbkpsWWRjMTFHd0VxWnh6RDF2R3BDR2pDN2VWTlQ3aVY1d3IybXlybHdPYi9aUWFEa0xYDQpvVStaOVVXT1VlSXJTdzUydDdmQUpvVVAwSm5iYkMveVIrU1lqUGhvUXNiVHduOTc2ZldBWTduM3FMOXhCd1Y0DQphek41OXNjeUp0dlhMeUtOL2N5ak1ReDRLajBIMFg0bWJ6bzVZNUtzWWtYVU0vOEFPdWZMcEd0S1NGVGgrSEFDDQpab1Q5YnZHS25adnNHd0tYZFF0Wnh0akhaUjVqK3U3ZGtQOTJBT051RFNabS8rWVV4b2tBK09JbzdSR3BwSHNXDQo1ZTdNY0FTVXRtb1FORXd6dVFoVkJaRWQ1OGtKYjUrV0VWbGNzanlXNnRTbzErZ25tTWNqR1BsMWgxR2hVbjV4DQpFY0lWRnBIWXM5YWo1NmpBSjk1MVQvZjhMaWxmTlVnanBLQ0c1bnl0SUt3emxhOHNtdGlPdm1UNEpYbXBwSkI2DQo4bmdHRVluVjUrUTYwWFJ2OEhSSGp1VG9CRHVhaERrVDA2R1JGODU1d09FR2V4bkZpMXZYWUxLVllWb1V2MXRKDQo4dVdUR1pwNllDSVJldlBqbzg5ZytWTlJSaVFYUThJd0dybXE5c0RoVTlqTjA0SjdVL1RvRDFpNHE3VnlsRUc5DQorV1VGNkNLaEdBeTJIaEhwVncyTGFoOS9lUzdZMUZ1YURrWmhPZG1laG1BOCtqdHNZamJadnR5Mm1SWlF0UUZzDQpUU1VUUjREbUR2bVVPRVRmeStpRHdzK2RkWXVNTnJGeVVYV2dkMnpBQU4ydVl1UHFGY2pRcFNPODFzVTJTU3R3DQoxVzAyeUtYOGJEYmZFdjBzbUh3UzliQnFlSGo5NEM1Mjg0YXpsdTBmaUdpTm1OUEM4ckJLRmhBPQ0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQ==
-        service:
-          name: webhook-service
-          namespace: metallb-system
-          path: /convert
-      conversionReviewVersions:
-      - v1beta1
-      - v1beta2
-  group: metallb.io
-  names:
-    kind: BGPPeer
-    listKind: BGPPeerList
-    plural: bgppeers
-    singular: bgppeer
-  scope: Namespaced
-  versions:
-  - additionalPrinterColumns:
-    - jsonPath: .spec.peerAddress
-      name: Address
-      type: string
-    - jsonPath: .spec.peerASN
-      name: ASN
-      type: string
-    - jsonPath: .spec.bfdProfile
-      name: BFD Profile
-      type: string
-    - jsonPath: .spec.ebgpMultiHop
-      name: Multi Hops
-      type: string
-    name: v1beta1
-    schema:
-      openAPIV3Schema:
-        description: BGPPeer is the Schema for the peers API.
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: BGPPeerSpec defines the desired state of Peer.
-            properties:
-              bfdProfile:
-                type: string
-              ebgpMultiHop:
-                description: EBGP peer is multi-hops away
-                type: boolean
-              holdTime:
-                description: Requested BGP hold time, per RFC4271.
-                type: string
-              keepaliveTime:
-                description: Requested BGP keepalive time, per RFC4271.
-                type: string
-              myASN:
-                description: AS number to use for the local end of the session.
-                format: int32
-                maximum: 4294967295
-                minimum: 0
-                type: integer
-              nodeSelectors:
-                description: Only connect to this peer on nodes that match one of
-                  these selectors.
-                items:
-                  properties:
-                    matchExpressions:
-                      items:
-                        properties:
-                          key:
-                            type: string
-                          operator:
-                            type: string
-                          values:
-                            items:
-                              type: string
-                            minItems: 1
-                            type: array
-                        required:
-                        - key
-                        - operator
-                        - values
-                        type: object
-                      type: array
-                    matchLabels:
-                      additionalProperties:
-                        type: string
-                      type: object
-                  type: object
-                type: array
-              password:
-                description: Authentication password for routers enforcing TCP MD5
-                  authenticated sessions
-                type: string
-              peerASN:
-                description: AS number to expect from the remote end of the session.
-                format: int32
-                maximum: 4294967295
-                minimum: 0
-                type: integer
-              peerAddress:
-                description: Address to dial when establishing the session.
-                type: string
-              peerPort:
-                description: Port to dial when establishing the session.
-                maximum: 16384
-                minimum: 0
-                type: integer
-              routerID:
-                description: BGP router ID to advertise to the peer
-                type: string
-              sourceAddress:
-                description: Source address to use when establishing the session.
-                type: string
-            required:
-            - myASN
-            - peerASN
-            - peerAddress
-            type: object
-          status:
-            description: BGPPeerStatus defines the observed state of Peer.
-            type: object
-        type: object
-    served: true
-    storage: false
-    subresources:
-      status: {}
-  - additionalPrinterColumns:
-    - jsonPath: .spec.peerAddress
-      name: Address
-      type: string
-    - jsonPath: .spec.peerASN
-      name: ASN
-      type: string
-    - jsonPath: .spec.bfdProfile
-      name: BFD Profile
-      type: string
-    - jsonPath: .spec.ebgpMultiHop
-      name: Multi Hops
-      type: string
-    name: v1beta2
-    schema:
-      openAPIV3Schema:
-        description: BGPPeer is the Schema for the peers API.
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: BGPPeerSpec defines the desired state of Peer.
-            properties:
-              bfdProfile:
-                description: The name of the BFD Profile to be used for the BFD session
-                  associated to the BGP session. If not set, the BFD session won't
-                  be set up.
-                type: string
-              ebgpMultiHop:
-                description: To set if the BGPPeer is multi-hops away. Needed for
-                  FRR mode only.
-                type: boolean
-              holdTime:
-                description: Requested BGP hold time, per RFC4271.
-                type: string
-              keepaliveTime:
-                description: Requested BGP keepalive time, per RFC4271.
-                type: string
-              myASN:
-                description: AS number to use for the local end of the session.
-                format: int32
-                maximum: 4294967295
-                minimum: 0
-                type: integer
-              nodeSelectors:
-                description: Only connect to this peer on nodes that match one of
-                  these selectors.
-                items:
-                  description: A label selector is a label query over a set of resources.
-                    The result of matchLabels and matchExpressions are ANDed. An empty
-                    label selector matches all objects. A null label selector matches
-                    no objects.
-                  properties:
-                    matchExpressions:
-                      description: matchExpressions is a list of label selector requirements.
-                        The requirements are ANDed.
-                      items:
-                        description: A label selector requirement is a selector that
-                          contains values, a key, and an operator that relates the
-                          key and values.
-                        properties:
-                          key:
-                            description: key is the label key that the selector applies
-                              to.
-                            type: string
-                          operator:
-                            description: operator represents a key's relationship
-                              to a set of values. Valid operators are In, NotIn, Exists
-                              and DoesNotExist.
-                            type: string
-                          values:
-                            description: values is an array of string values. If the
-                              operator is In or NotIn, the values array must be non-empty.
-                              If the operator is Exists or DoesNotExist, the values
-                              array must be empty. This array is replaced during a
-                              strategic merge patch.
-                            items:
-                              type: string
-                            type: array
-                        required:
-                        - key
-                        - operator
-                        type: object
-                      type: array
-                    matchLabels:
-                      additionalProperties:
-                        type: string
-                      description: matchLabels is a map of {key,value} pairs. A single
-                        {key,value} in the matchLabels map is equivalent to an element
-                        of matchExpressions, whose key field is "key", the operator
-                        is "In", and the values array contains only "value". The requirements
-                        are ANDed.
-                      type: object
-                  type: object
-                  x-kubernetes-map-type: atomic
-                type: array
-              password:
-                description: Authentication password for routers enforcing TCP MD5
-                  authenticated sessions
-                type: string
-              passwordSecret:
-                description: passwordSecret is name of the authentication secret for
-                  BGP Peer. the secret must be of type "kubernetes.io/basic-auth",
-                  and created in the same namespace as the MetalLB deployment. The
-                  password is stored in the secret as the key "password".
-                properties:
-                  name:
-                    description: name is unique within a namespace to reference a
-                      secret resource.
-                    type: string
-                  namespace:
-                    description: namespace defines the space within which the secret
-                      name must be unique.
-                    type: string
-                type: object
-                x-kubernetes-map-type: atomic
-              peerASN:
-                description: AS number to expect from the remote end of the session.
-                format: int32
-                maximum: 4294967295
-                minimum: 0
-                type: integer
-              peerAddress:
-                description: Address to dial when establishing the session.
-                type: string
-              peerPort:
-                default: 179
-                description: Port to dial when establishing the session.
-                maximum: 16384
-                minimum: 0
-                type: integer
-              routerID:
-                description: BGP router ID to advertise to the peer
-                type: string
-              sourceAddress:
-                description: Source address to use when establishing the session.
-                type: string
-              vrf:
-                description: To set if we want to peer with the BGPPeer using an interface
-                  belonging to a host vrf
-                type: string
-            required:
-            - myASN
-            - peerASN
-            - peerAddress
-            type: object
-          status:
-            description: BGPPeerStatus defines the observed state of Peer.
-            type: object
-        type: object
-    served: true
-    storage: true
-    subresources:
-      status: {}
----
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
-  creationTimestamp: null
-  name: communities.metallb.io
-spec:
-  group: metallb.io
-  names:
-    kind: Community
-    listKind: CommunityList
-    plural: communities
-    singular: community
-  scope: Namespaced
-  versions:
-  - name: v1beta1
-    schema:
-      openAPIV3Schema:
-        description: Community is a collection of aliases for communities. Users can
-          define named aliases to be used in the BGPPeer CRD.
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: CommunitySpec defines the desired state of Community.
-            properties:
-              communities:
-                items:
-                  properties:
-                    name:
-                      description: The name of the alias for the community.
-                      type: string
-                    value:
-                      description: The BGP community value corresponding to the given
-                        name. Can be a standard community of the form 1234:1234 or
-                        a large community of the form large:1234:1234:1234.
-                      type: string
-                  type: object
-                type: array
-            type: object
-          status:
-            description: CommunityStatus defines the observed state of Community.
-            type: object
-        type: object
-    served: true
-    storage: true
-    subresources:
-      status: {}
----
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
-  creationTimestamp: null
-  name: ipaddresspools.metallb.io
-spec:
-  group: metallb.io
-  names:
-    kind: IPAddressPool
-    listKind: IPAddressPoolList
-    plural: ipaddresspools
-    singular: ipaddresspool
-  scope: Namespaced
-  versions:
-  - additionalPrinterColumns:
-    - jsonPath: .spec.autoAssign
-      name: Auto Assign
-      type: boolean
-    - jsonPath: .spec.avoidBuggyIPs
-      name: Avoid Buggy IPs
-      type: boolean
-    - jsonPath: .spec.addresses
-      name: Addresses
-      type: string
-    name: v1beta1
-    schema:
-      openAPIV3Schema:
-        description: IPAddressPool represents a pool of IP addresses that can be allocated
-          to LoadBalancer services.
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: IPAddressPoolSpec defines the desired state of IPAddressPool.
-            properties:
-              addresses:
-                description: A list of IP address ranges over which MetalLB has authority.
-                  You can list multiple ranges in a single pool, they will all share
-                  the same settings. Each range can be either a CIDR prefix, or an
-                  explicit start-end range of IPs.
-                items:
-                  type: string
-                type: array
-              autoAssign:
-                default: true
-                description: AutoAssign flag used to prevent MetallB from automatic
-                  allocation for a pool.
-                type: boolean
-              avoidBuggyIPs:
-                default: false
-                description: AvoidBuggyIPs prevents addresses ending with .0 and .255
-                  to be used by a pool.
-                type: boolean
-              serviceAllocation:
-                description: AllocateTo makes ip pool allocation to specific namespace
-                  and/or service. The controller will use the pool with lowest value
-                  of priority in case of multiple matches. A pool with no priority
-                  set will be used only if the pools with priority can't be used.
-                  If multiple matching IPAddressPools are available it will check
-                  for the availability of IPs sorting the matching IPAddressPools
-                  by priority, starting from the highest to the lowest. If multiple
-                  IPAddressPools have the same priority, choice will be random.
-                properties:
-                  namespaceSelectors:
-                    description: NamespaceSelectors list of label selectors to select
-                      namespace(s) for ip pool, an alternative to using namespace
-                      list.
-                    items:
-                      description: A label selector is a label query over a set of
-                        resources. The result of matchLabels and matchExpressions
-                        are ANDed. An empty label selector matches all objects. A
-                        null label selector matches no objects.
-                      properties:
-                        matchExpressions:
-                          description: matchExpressions is a list of label selector
-                            requirements. The requirements are ANDed.
-                          items:
-                            description: A label selector requirement is a selector
-                              that contains values, a key, and an operator that relates
-                              the key and values.
-                            properties:
-                              key:
-                                description: key is the label key that the selector
-                                  applies to.
-                                type: string
-                              operator:
-                                description: operator represents a key's relationship
-                                  to a set of values. Valid operators are In, NotIn,
-                                  Exists and DoesNotExist.
-                                type: string
-                              values:
-                                description: values is an array of string values.
-                                  If the operator is In or NotIn, the values array
-                                  must be non-empty. If the operator is Exists or
-                                  DoesNotExist, the values array must be empty. This
-                                  array is replaced during a strategic merge patch.
-                                items:
-                                  type: string
-                                type: array
-                            required:
-                            - key
-                            - operator
-                            type: object
-                          type: array
-                        matchLabels:
-                          additionalProperties:
-                            type: string
-                          description: matchLabels is a map of {key,value} pairs.
-                            A single {key,value} in the matchLabels map is equivalent
-                            to an element of matchExpressions, whose key field is
-                            "key", the operator is "In", and the values array contains
-                            only "value". The requirements are ANDed.
-                          type: object
-                      type: object
-                      x-kubernetes-map-type: atomic
-                    type: array
-                  namespaces:
-                    description: Namespaces list of namespace(s) on which ip pool
-                      can be attached.
-                    items:
-                      type: string
-                    type: array
-                  priority:
-                    description: Priority priority given for ip pool while ip allocation
-                      on a service.
-                    type: integer
-                  serviceSelectors:
-                    description: ServiceSelectors list of label selector to select
-                      service(s) for which ip pool can be used for ip allocation.
-                    items:
-                      description: A label selector is a label query over a set of
-                        resources. The result of matchLabels and matchExpressions
-                        are ANDed. An empty label selector matches all objects. A
-                        null label selector matches no objects.
-                      properties:
-                        matchExpressions:
-                          description: matchExpressions is a list of label selector
-                            requirements. The requirements are ANDed.
-                          items:
-                            description: A label selector requirement is a selector
-                              that contains values, a key, and an operator that relates
-                              the key and values.
-                            properties:
-                              key:
-                                description: key is the label key that the selector
-                                  applies to.
-                                type: string
-                              operator:
-                                description: operator represents a key's relationship
-                                  to a set of values. Valid operators are In, NotIn,
-                                  Exists and DoesNotExist.
-                                type: string
-                              values:
-                                description: values is an array of string values.
-                                  If the operator is In or NotIn, the values array
-                                  must be non-empty. If the operator is Exists or
-                                  DoesNotExist, the values array must be empty. This
-                                  array is replaced during a strategic merge patch.
-                                items:
-                                  type: string
-                                type: array
-                            required:
-                            - key
-                            - operator
-                            type: object
-                          type: array
-                        matchLabels:
-                          additionalProperties:
-                            type: string
-                          description: matchLabels is a map of {key,value} pairs.
-                            A single {key,value} in the matchLabels map is equivalent
-                            to an element of matchExpressions, whose key field is
-                            "key", the operator is "In", and the values array contains
-                            only "value". The requirements are ANDed.
-                          type: object
-                      type: object
-                      x-kubernetes-map-type: atomic
-                    type: array
-                type: object
-            required:
-            - addresses
-            type: object
-          status:
-            description: IPAddressPoolStatus defines the observed state of IPAddressPool.
-            type: object
-        required:
-        - spec
-        type: object
-    served: true
-    storage: true
-    subresources:
-      status: {}
----
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
-  annotations:
-    controller-gen.kubebuilder.io/version: v0.11.1
-  creationTimestamp: null
-  name: l2advertisements.metallb.io
-spec:
-  group: metallb.io
-  names:
-    kind: L2Advertisement
-    listKind: L2AdvertisementList
-    plural: l2advertisements
-    singular: l2advertisement
-  scope: Namespaced
-  versions:
-  - additionalPrinterColumns:
-    - jsonPath: .spec.ipAddressPools
-      name: IPAddressPools
-      type: string
-    - jsonPath: .spec.ipAddressPoolSelectors
-      name: IPAddressPool Selectors
-      type: string
-    - jsonPath: .spec.interfaces
-      name: Interfaces
-      type: string
-    - jsonPath: .spec.nodeSelectors
-      name: Node Selectors
-      priority: 10
-      type: string
-    name: v1beta1
-    schema:
-      openAPIV3Schema:
-        description: L2Advertisement allows to advertise the LoadBalancer IPs provided
-          by the selected pools via L2.
-        properties:
-          apiVersion:
-            description: 'APIVersion defines the versioned schema of this representation
-              of an object. Servers should convert recognized schemas to the latest
-              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
-            type: string
-          kind:
-            description: 'Kind is a string value representing the REST resource this
-              object represents. Servers may infer this from the endpoint the client
-              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
-            type: string
-          metadata:
-            type: object
-          spec:
-            description: L2AdvertisementSpec defines the desired state of L2Advertisement.
-            properties:
-              interfaces:
-                description: A list of interfaces to announce from. The LB IP will
-                  be announced only from these interfaces. If the field is not set,
-                  we advertise from all the interfaces on the host.
-                items:
-                  type: string
-                type: array
-              ipAddressPoolSelectors:
-                description: A selector for the IPAddressPools which would get advertised
-                  via this advertisement. If no IPAddressPool is selected by this
-                  or by the list, the advertisement is applied to all the IPAddressPools.
-                items:
-                  description: A label selector is a label query over a set of resources.
-                    The result of matchLabels and matchExpressions are ANDed. An empty
-                    label selector matches all objects. A null label selector matches
-                    no objects.
-                  properties:
-                    matchExpressions:
-                      description: matchExpressions is a list of label selector requirements.
-                        The requirements are ANDed.
-                      items:
-                        description: A label selector requirement is a selector that
-                          contains values, a key, and an operator that relates the
-                          key and values.
-                        properties:
-                          key:
-                            description: key is the label key that the selector applies
-                              to.
-                            type: string
-                          operator:
-                            description: operator represents a key's relationship
-                              to a set of values. Valid operators are In, NotIn, Exists
-                              and DoesNotExist.
-                            type: string
-                          values:
-                            description: values is an array of string values. If the
-                              operator is In or NotIn, the values array must be non-empty.
-                              If the operator is Exists or DoesNotExist, the values
-                              array must be empty. This array is replaced during a
-                              strategic merge patch.
-                            items:
-                              type: string
-                            type: array
-                        required:
-                        - key
-                        - operator
-                        type: object
-                      type: array
-                    matchLabels:
-                      additionalProperties:
-                        type: string
-                      description: matchLabels is a map of {key,value} pairs. A single
-                        {key,value} in the matchLabels map is equivalent to an element
-                        of matchExpressions, whose key field is "key", the operator
-                        is "In", and the values array contains only "value". The requirements
-                        are ANDed.
-                      type: object
-                  type: object
-                  x-kubernetes-map-type: atomic
-                type: array
-              ipAddressPools:
-                description: The list of IPAddressPools to advertise via this advertisement,
-                  selected by name.
-                items:
-                  type: string
-                type: array
-              nodeSelectors:
-                description: NodeSelectors allows to limit the nodes to announce as
-                  next hops for the LoadBalancer IP. When empty, all the nodes having  are
-                  announced as next hops.
-                items:
-                  description: A label selector is a label query over a set of resources.
-                    The result of matchLabels and matchExpressions are ANDed. An empty
-                    label selector matches all objects. A null label selector matches
-                    no objects.
-                  properties:
-                    matchExpressions:
-                      description: matchExpressions is a list of label selector requirements.
-                        The requirements are ANDed.
-                      items:
-                        description: A label selector requirement is a selector that
-                          contains values, a key, and an operator that relates the
-                          key and values.
-                        properties:
-                          key:
-                            description: key is the label key that the selector applies
-                              to.
-                            type: string
-                          operator:
-                            description: operator represents a key's relationship
-                              to a set of values. Valid operators are In, NotIn, Exists
-                              and DoesNotExist.
-                            type: string
-                          values:
-                            description: values is an array of string values. If the
-                              operator is In or NotIn, the values array must be non-empty.
-                              If the operator is Exists or DoesNotExist, the values
-                              array must be empty. This array is replaced during a
-                              strategic merge patch.
-                            items:
-                              type: string
-                            type: array
-                        required:
-                        - key
-                        - operator
-                        type: object
-                      type: array
-                    matchLabels:
-                      additionalProperties:
-                        type: string
-                      description: matchLabels is a map of {key,value} pairs. A single
-                        {key,value} in the matchLabels map is equivalent to an element
-                        of matchExpressions, whose key field is "key", the operator
-                        is "In", and the values array contains only "value". The requirements
-                        are ANDed.
-                      type: object
-                  type: object
-                  x-kubernetes-map-type: atomic
-                type: array
-            type: object
-          status:
-            description: L2AdvertisementStatus defines the observed state of L2Advertisement.
-            type: object
-        type: object
-    served: true
-    storage: true
-    subresources:
-      status: {}
----
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  labels:
-    app: metallb
-  name: controller
-  namespace: metallb-system
----
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  labels:
-    app: metallb
-  name: speaker
-  namespace: metallb-system
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: Role
-metadata:
-  labels:
-    app: metallb
-  name: controller
-  namespace: metallb-system
-rules:
-- apiGroups:
-  - ""
-  resources:
-  - secrets
-  verbs:
-  - create
-  - delete
-  - get
-  - list
-  - patch
-  - update
-  - watch
-- apiGroups:
-  - ""
-  resourceNames:
-  - memberlist
-  resources:
-  - secrets
-  verbs:
-  - list
-- apiGroups:
-  - apps
-  resourceNames:
-  - controller
-  resources:
-  - deployments
-  verbs:
-  - get
-- apiGroups:
-  - metallb.io
-  resources:
-  - bgppeers
-  verbs:
-  - get
-  - list
-- apiGroups:
-  - metallb.io
-  resources:
-  - addresspools
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - metallb.io
-  resources:
-  - bfdprofiles
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - metallb.io
-  resources:
-  - ipaddresspools
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - metallb.io
-  resources:
-  - bgpadvertisements
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - metallb.io
-  resources:
-  - l2advertisements
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - metallb.io
-  resources:
-  - communities
-  verbs:
-  - get
-  - list
-  - watch
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: Role
-metadata:
-  labels:
-    app: metallb
-  name: pod-lister
-  namespace: metallb-system
-rules:
-- apiGroups:
-  - ""
-  resources:
-  - pods
-  verbs:
-  - list
-- apiGroups:
-  - ""
-  resources:
-  - secrets
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - ""
-  resources:
-  - configmaps
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - metallb.io
-  resources:
-  - addresspools
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - metallb.io
-  resources:
-  - bfdprofiles
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - metallb.io
-  resources:
-  - bgppeers
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - metallb.io
-  resources:
-  - l2advertisements
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - metallb.io
-  resources:
-  - bgpadvertisements
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - metallb.io
-  resources:
-  - ipaddresspools
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - metallb.io
-  resources:
-  - communities
-  verbs:
-  - get
-  - list
-  - watch
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
-  labels:
-    app: metallb
-  name: metallb-system:controller
-rules:
-- apiGroups:
-  - ""
-  resources:
-  - services
-  - namespaces
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - ""
-  resources:
-  - nodes
-  verbs:
-  - list
-- apiGroups:
-  - ""
-  resources:
-  - services/status
-  verbs:
-  - update
-- apiGroups:
-  - ""
-  resources:
-  - events
-  verbs:
-  - create
-  - patch
-- apiGroups:
-  - policy
-  resourceNames:
-  - controller
-  resources:
-  - podsecuritypolicies
-  verbs:
-  - use
-- apiGroups:
-  - admissionregistration.k8s.io
-  resourceNames:
-  - metallb-webhook-configuration
-  resources:
-  - validatingwebhookconfigurations
-  - mutatingwebhookconfigurations
-  verbs:
-  - create
-  - delete
-  - get
-  - list
-  - patch
-  - update
-  - watch
-- apiGroups:
-  - admissionregistration.k8s.io
-  resources:
-  - validatingwebhookconfigurations
-  - mutatingwebhookconfigurations
-  verbs:
-  - list
-  - watch
-- apiGroups:
-  - apiextensions.k8s.io
-  resourceNames:
-  - addresspools.metallb.io
-  - bfdprofiles.metallb.io
-  - bgpadvertisements.metallb.io
-  - bgppeers.metallb.io
-  - ipaddresspools.metallb.io
-  - l2advertisements.metallb.io
-  - communities.metallb.io
-  resources:
-  - customresourcedefinitions
-  verbs:
-  - create
-  - delete
-  - get
-  - list
-  - patch
-  - update
-  - watch
-- apiGroups:
-  - apiextensions.k8s.io
-  resources:
-  - customresourcedefinitions
-  verbs:
-  - list
-  - watch
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
-  labels:
-    app: metallb
-  name: metallb-system:speaker
-rules:
-- apiGroups:
-  - ""
-  resources:
-  - services
-  - endpoints
-  - nodes
-  - namespaces
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - discovery.k8s.io
-  resources:
-  - endpointslices
-  verbs:
-  - get
-  - list
-  - watch
-- apiGroups:
-  - ""
-  resources:
-  - events
-  verbs:
-  - create
-  - patch
-- apiGroups:
-  - policy
-  resourceNames:
-  - speaker
-  resources:
-  - podsecuritypolicies
-  verbs:
-  - use
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: RoleBinding
-metadata:
-  labels:
-    app: metallb
-  name: controller
-  namespace: metallb-system
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: Role
-  name: controller
-subjects:
-- kind: ServiceAccount
-  name: controller
-  namespace: metallb-system
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: RoleBinding
-metadata:
-  labels:
-    app: metallb
-  name: pod-lister
-  namespace: metallb-system
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: Role
-  name: pod-lister
-subjects:
-- kind: ServiceAccount
-  name: speaker
-  namespace: metallb-system
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
-  labels:
-    app: metallb
-  name: metallb-system:controller
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: ClusterRole
-  name: metallb-system:controller
-subjects:
-- kind: ServiceAccount
-  name: controller
-  namespace: metallb-system
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
-  labels:
-    app: metallb
-  name: metallb-system:speaker
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: ClusterRole
-  name: metallb-system:speaker
-subjects:
-- kind: ServiceAccount
-  name: speaker
-  namespace: metallb-system
----
-apiVersion: v1
-data:
-  excludel2.yaml: |
-    announcedInterfacesToExclude: ["docker.*", "cbr.*", "dummy.*", "virbr.*", "lxcbr.*", "veth.*", "lo", "^cali.*", "^tunl.*", "flannel.*", "kube-ipvs.*", "cni.*", "^nodelocaldns.*"]
-kind: ConfigMap
-metadata:
-  name: metallb-excludel2
-  namespace: metallb-system
----
-apiVersion: v1
-kind: Secret
-metadata:
-  name: webhook-server-cert
-  namespace: metallb-system
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: webhook-service
-  namespace: metallb-system
-spec:
-  ports:
-  - port: 443
-    targetPort: 9443
-  selector:
-    component: controller
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  labels:
-    app: metallb
-    component: controller
-  name: controller
-  namespace: metallb-system
-spec:
-  revisionHistoryLimit: 3
-  selector:
-    matchLabels:
-      app: metallb
-      component: controller
-  template:
-    metadata:
-      annotations:
-        prometheus.io/port: "7472"
-        prometheus.io/scrape: "true"
-      labels:
-        app: metallb
-        component: controller
-    spec:
-      containers:
-      - args:
-        - --port=7472
-        - --log-level=info
-        env:
-        - name: METALLB_ML_SECRET_NAME
-          value: memberlist
-        - name: METALLB_DEPLOYMENT
-          value: controller
-        image: quay.io/metallb/controller:v0.13.10
-        livenessProbe:
-          failureThreshold: 3
-          httpGet:
-            path: /metrics
-            port: monitoring
-          initialDelaySeconds: 10
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 1
-        name: controller
-        ports:
-        - containerPort: 7472
-          name: monitoring
-        - containerPort: 9443
-          name: webhook-server
-          protocol: TCP
-        readinessProbe:
-          failureThreshold: 3
-          httpGet:
-            path: /metrics
-            port: monitoring
-          initialDelaySeconds: 10
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 1
-        securityContext:
-          allowPrivilegeEscalation: false
-          capabilities:
-            drop:
-            - all
-          readOnlyRootFilesystem: true
-        volumeMounts:
-        - mountPath: /tmp/k8s-webhook-server/serving-certs
-          name: cert
-          readOnly: true
-      nodeSelector:
-        kubernetes.io/os: linux
-      securityContext:
-        fsGroup: 65534
-        runAsNonRoot: true
-        runAsUser: 65534
-      serviceAccountName: controller
-      terminationGracePeriodSeconds: 0
-      volumes:
-      - name: cert
-        secret:
-          defaultMode: 420
-          secretName: webhook-server-cert
----
-apiVersion: apps/v1
-kind: DaemonSet
-metadata:
-  labels:
-    app: metallb
-    component: speaker
-  name: speaker
-  namespace: metallb-system
-spec:
-  selector:
-    matchLabels:
-      app: metallb
-      component: speaker
-  template:
-    metadata:
-      annotations:
-        prometheus.io/port: "7472"
-        prometheus.io/scrape: "true"
-      labels:
-        app: metallb
-        component: speaker
-    spec:
-      containers:
-      - args:
-        - --port=7472
-        - --log-level=info
-        env:
-        - name: METALLB_NODE_NAME
-          valueFrom:
-            fieldRef:
-              fieldPath: spec.nodeName
-        - name: METALLB_HOST
-          valueFrom:
-            fieldRef:
-              fieldPath: status.hostIP
-        - name: METALLB_ML_BIND_ADDR
-          valueFrom:
-            fieldRef:
-              fieldPath: status.podIP
-        - name: METALLB_ML_LABELS
-          value: app=metallb,component=speaker
-        - name: METALLB_ML_SECRET_KEY_PATH
-          value: /etc/ml_secret_key
-        image: quay.io/metallb/speaker:v0.13.10
-        livenessProbe:
-          failureThreshold: 3
-          httpGet:
-            path: /metrics
-            port: monitoring
-          initialDelaySeconds: 10
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 1
-        name: speaker
-        ports:
-        - containerPort: 7472
-          name: monitoring
-        - containerPort: 7946
-          name: memberlist-tcp
-        - containerPort: 7946
-          name: memberlist-udp
-          protocol: UDP
-        readinessProbe:
-          failureThreshold: 3
-          httpGet:
-            path: /metrics
-            port: monitoring
-          initialDelaySeconds: 10
-          periodSeconds: 10
-          successThreshold: 1
-          timeoutSeconds: 1
-        securityContext:
-          allowPrivilegeEscalation: false
-          capabilities:
-            add:
-            - NET_RAW
-            drop:
-            - ALL
-          readOnlyRootFilesystem: true
-        volumeMounts:
-        - mountPath: /etc/ml_secret_key
-          name: memberlist
-          readOnly: true
-        - mountPath: /etc/metallb
-          name: metallb-excludel2
-          readOnly: true
-      hostNetwork: true
-      nodeSelector:
-        kubernetes.io/os: linux
-      serviceAccountName: speaker
-      terminationGracePeriodSeconds: 2
-      tolerations:
-      - effect: NoSchedule
-        key: node-role.kubernetes.io/master
-        operator: Exists
-      - effect: NoSchedule
-        key: node-role.kubernetes.io/control-plane
-        operator: Exists
-      volumes:
-      - name: memberlist
-        secret:
-          defaultMode: 420
-          secretName: memberlist
-      - configMap:
-          defaultMode: 256
-          name: metallb-excludel2
-        name: metallb-excludel2
----
-apiVersion: admissionregistration.k8s.io/v1
-kind: ValidatingWebhookConfiguration
-metadata:
-  creationTimestamp: null
-  name: metallb-webhook-configuration
-webhooks:
-- admissionReviewVersions:
-  - v1
-  clientConfig:
-    service:
-      name: webhook-service
-      namespace: metallb-system
-      path: /validate-metallb-io-v1beta2-bgppeer
-  failurePolicy: Fail
-  name: bgppeersvalidationwebhook.metallb.io
-  rules:
-  - apiGroups:
-    - metallb.io
-    apiVersions:
-    - v1beta2
-    operations:
-    - CREATE
-    - UPDATE
-    resources:
-    - bgppeers
-  sideEffects: None
-- admissionReviewVersions:
-  - v1
-  clientConfig:
-    service:
-      name: webhook-service
-      namespace: metallb-system
-      path: /validate-metallb-io-v1beta1-addresspool
-  failurePolicy: Fail
-  name: addresspoolvalidationwebhook.metallb.io
-  rules:
-  - apiGroups:
-    - metallb.io
-    apiVersions:
-    - v1beta1
-    operations:
-    - CREATE
-    - UPDATE
-    resources:
-    - addresspools
-  sideEffects: None
-- admissionReviewVersions:
-  - v1
-  clientConfig:
-    service:
-      name: webhook-service
-      namespace: metallb-system
-      path: /validate-metallb-io-v1beta1-bfdprofile
-  failurePolicy: Fail
-  name: bfdprofilevalidationwebhook.metallb.io
-  rules:
-  - apiGroups:
-    - metallb.io
-    apiVersions:
-    - v1beta1
-    operations:
-    - CREATE
-    - DELETE
-    resources:
-    - bfdprofiles
-  sideEffects: None
-- admissionReviewVersions:
-  - v1
-  clientConfig:
-    service:
-      name: webhook-service
-      namespace: metallb-system
-      path: /validate-metallb-io-v1beta1-bgpadvertisement
-  failurePolicy: Fail
-  name: bgpadvertisementvalidationwebhook.metallb.io
-  rules:
-  - apiGroups:
-    - metallb.io
-    apiVersions:
-    - v1beta1
-    operations:
-    - CREATE
-    - UPDATE
-    resources:
-    - bgpadvertisements
-  sideEffects: None
-- admissionReviewVersions:
-  - v1
-  clientConfig:
-    service:
-      name: webhook-service
-      namespace: metallb-system
-      path: /validate-metallb-io-v1beta1-community
-  failurePolicy: Fail
-  name: communityvalidationwebhook.metallb.io
-  rules:
-  - apiGroups:
-    - metallb.io
-    apiVersions:
-    - v1beta1
-    operations:
-    - CREATE
-    - UPDATE
-    resources:
-    - communities
-  sideEffects: None
-- admissionReviewVersions:
-  - v1
-  clientConfig:
-    service:
-      name: webhook-service
-      namespace: metallb-system
-      path: /validate-metallb-io-v1beta1-ipaddresspool
-  failurePolicy: Fail
-  name: ipaddresspoolvalidationwebhook.metallb.io
-  rules:
-  - apiGroups:
-    - metallb.io
-    apiVersions:
-    - v1beta1
-    operations:
-    - CREATE
-    - UPDATE
-    resources:
-    - ipaddresspools
-  sideEffects: None
-- admissionReviewVersions:
-  - v1
-  clientConfig:
-    service:
-      name: webhook-service
-      namespace: metallb-system
-      path: /validate-metallb-io-v1beta1-l2advertisement
-  failurePolicy: Fail
-  name: l2advertisementvalidationwebhook.metallb.io
-  rules:
-  - apiGroups:
-    - metallb.io
-    apiVersions:
-    - v1beta1
-    operations:
-    - CREATE
-    - UPDATE
-    resources:
-    - l2advertisements
-  sideEffects: None
diff --git a/charts/metallb/templates/podmonitor.yaml b/charts/metallb/templates/podmonitor.yaml
new file mode 100644
index 0000000..93a7fd6
--- /dev/null
+++ b/charts/metallb/templates/podmonitor.yaml
@@ -0,0 +1,106 @@
+{{- if .Values.prometheus.podMonitor.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: PodMonitor
+metadata:
+  name: {{ template "metallb.fullname" . }}-controller
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+    app.kubernetes.io/component: controller
+    {{- if .Values.prometheus.podMonitor.additionalLabels }}
+{{ toYaml .Values.prometheus.podMonitor.additionalLabels | indent 4 }}
+    {{- end }}
+  {{- if .Values.prometheus.podMonitor.annotations }}
+  annotations:
+{{ toYaml .Values.prometheus.podMonitor.annotations | indent 4 }}
+  {{- end }}
+spec:
+  jobLabel: {{ .Values.prometheus.podMonitor.jobLabel | quote }}
+  selector:
+    matchLabels:
+      {{- include "metallb.selectorLabels" . | nindent 6 }}
+      app.kubernetes.io/component: controller
+  namespaceSelector:
+    matchNames:
+    - {{ .Release.Namespace }}
+  podMetricsEndpoints:
+  - port: monitoring
+    path: /metrics
+    {{- if .Values.prometheus.podMonitor.interval }}
+    interval: {{ .Values.prometheus.podMonitor.interval }}
+    {{- end }}
+{{- if .Values.prometheus.podMonitor.metricRelabelings }}
+    metricRelabelings:
+{{- toYaml .Values.prometheus.podMonitor.metricRelabelings | nindent 4 }}
+{{- end }}
+{{- if .Values.prometheus.podMonitor.relabelings }}
+    relabelings:
+{{- toYaml .Values.prometheus.podMonitor.relabelings | nindent 4 }}
+{{- end }}
+---
+apiVersion: monitoring.coreos.com/v1
+kind: PodMonitor
+metadata:
+  name: {{ template "metallb.fullname" . }}-speaker
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+    app.kubernetes.io/component: speaker
+    {{- if .Values.prometheus.podMonitor.additionalLabels }}
+{{ toYaml .Values.prometheus.podMonitor.additionalLabels | indent 4 }}
+    {{- end }}
+  {{- if .Values.prometheus.podMonitor.annotations }}
+  annotations:
+{{ toYaml .Values.prometheus.podMonitor.annotations | indent 4 }}
+  {{- end }}
+spec:
+  jobLabel: {{ .Values.prometheus.podMonitor.jobLabel | quote }}
+  selector:
+    matchLabels:
+      {{- include "metallb.selectorLabels" . | nindent 6 }}
+      app.kubernetes.io/component: speaker
+  namespaceSelector:
+    matchNames:
+    - {{ .Release.Namespace }}
+  podMetricsEndpoints:
+  - port: monitoring
+    path: /metrics
+    {{- if .Values.prometheus.podMonitor.interval }}
+    interval: {{ .Values.prometheus.podMonitor.interval }}
+    {{- end }}
+{{- if .Values.prometheus.podMonitor.metricRelabelings }}
+    metricRelabelings:
+{{- toYaml .Values.prometheus.podMonitor.metricRelabelings | nindent 4 }}
+{{- end }}
+{{- if .Values.prometheus.podMonitor.relabelings }}
+    relabelings:
+{{- toYaml .Values.prometheus.podMonitor.relabelings | nindent 4 }}
+{{- end }}
+---
+{{- if .Values.prometheus.rbacPrometheus }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: {{ template "metallb.fullname" . }}-prometheus
+rules:
+  - apiGroups:
+      - ""
+    resources:
+      - pods
+    verbs:
+      - get
+      - list
+      - watch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: {{ template "metallb.fullname" . }}-prometheus
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: {{ template "metallb.fullname" . }}-prometheus
+subjects:
+  - kind: ServiceAccount
+    name: {{ required ".Values.prometheus.serviceAccount must be defined when .Values.prometheus.podMonitor.enabled == true" .Values.prometheus.serviceAccount }}
+    namespace: {{ required ".Values.prometheus.namespace must be defined when .Values.prometheus.podMonitor.enabled == true" .Values.prometheus.namespace }}
+{{- end }}
+{{- end }}
diff --git a/charts/metallb/templates/prometheusrules.yaml b/charts/metallb/templates/prometheusrules.yaml
new file mode 100644
index 0000000..463aaca
--- /dev/null
+++ b/charts/metallb/templates/prometheusrules.yaml
@@ -0,0 +1,84 @@
+{{- if .Values.prometheus.prometheusRule.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+  name: {{ template "metallb.fullname" . }}
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+    {{- if .Values.prometheus.prometheusRule.additionalLabels }}
+{{ toYaml .Values.prometheus.prometheusRule.additionalLabels | indent 4 }}
+    {{- end }}
+  {{- if .Values.prometheus.prometheusRule.annotations }}
+  annotations:
+{{ toYaml .Values.prometheus.prometheusRule.annotations | indent 4 }}
+  {{- end }}
+spec:
+  groups:
+  - name: {{ template "metallb.fullname" . }}.rules
+    rules:
+    {{- if .Values.prometheus.prometheusRule.staleConfig.enabled }}
+    - alert: MetalLBStaleConfig
+      annotations:
+        message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod
+          }} has a stale config for > 1 minute'`}}
+      expr: metallb_k8s_client_config_stale_bool{job="{{ include "metallb.name" . }}"} == 1
+      for: 1m
+      {{- with .Values.prometheus.prometheusRule.staleConfig.labels }}
+      labels:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+    {{- end }}
+    {{- if .Values.prometheus.prometheusRule.configNotLoaded.enabled }}
+    - alert: MetalLBConfigNotLoaded
+      annotations:
+        message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod
+          }} has not loaded for > 1 minute'`}}
+      expr: metallb_k8s_client_config_loaded_bool{job="{{ include "metallb.name" . }}"} == 0
+      for: 1m
+      {{- with .Values.prometheus.prometheusRule.configNotLoaded.labels }}
+      labels:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+    {{- end }}
+    {{- if .Values.prometheus.prometheusRule.addressPoolExhausted.enabled }}
+    - alert: MetalLBAddressPoolExhausted
+      annotations:
+        message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod
+          }} has exhausted address pool {{ $labels.pool }} for > 1 minute'`}}
+      expr: metallb_allocator_addresses_in_use_total >= on(pool) metallb_allocator_addresses_total
+      for: 1m
+      {{- with .Values.prometheus.prometheusRule.addressPoolExhausted.labels }}
+      labels:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+    {{- end }}
+
+    {{- if .Values.prometheus.prometheusRule.addressPoolUsage.enabled }}
+    {{- range .Values.prometheus.prometheusRule.addressPoolUsage.thresholds }}
+    - alert: MetalLBAddressPoolUsage{{ .percent }}Percent
+      annotations:
+        message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod
+          }} has address pool {{ $labels.pool }} past `}}{{ .percent }}{{`% usage for > 1 minute'`}}
+      expr: ( metallb_allocator_addresses_in_use_total / on(pool) metallb_allocator_addresses_total ) * 100 > {{ .percent }}
+      {{- with .labels }}
+      labels:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+    {{- end }}
+    {{- end }}
+    {{- if .Values.prometheus.prometheusRule.bgpSessionDown.enabled }}
+    - alert: MetalLBBGPSessionDown
+      annotations:
+        message: {{`'{{ $labels.job }} - MetalLB {{ $labels.container }} on {{ $labels.pod
+          }} has BGP session {{ $labels.peer }} down for > 1 minute'`}}
+      expr: metallb_bgp_session_up{job="{{ include "metallb.name" . }}"} == 0
+      for: 1m
+      {{- with .Values.prometheus.prometheusRule.bgpSessionDown.labels }}
+      labels:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+    {{- end }}
+    {{- with .Values.prometheus.prometheusRule.extraAlerts }}
+    {{- toYaml . | nindent 4 }}
+    {{- end}}
+{{- end }}
diff --git a/charts/metallb/templates/rbac.yaml b/charts/metallb/templates/rbac.yaml
new file mode 100644
index 0000000..ed6b826
--- /dev/null
+++ b/charts/metallb/templates/rbac.yaml
@@ -0,0 +1,210 @@
+{{- if .Values.rbac.create -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: {{ template "metallb.fullname" . }}:controller
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+rules:
+- apiGroups: [""]
+  resources: ["services", "namespaces"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: [""]
+  resources: ["nodes"]
+  verbs: ["list"]
+- apiGroups: [""]
+  resources: ["services/status"]
+  verbs: ["update"]
+- apiGroups: [""]
+  resources: ["events"]
+  verbs: ["create", "patch"]
+- apiGroups: ["admissionregistration.k8s.io"]
+  resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"]
+  resourceNames: ["metallb-webhook-configuration"]
+  verbs: ["create", "delete", "get", "list", "patch", "update", "watch"]
+- apiGroups: ["admissionregistration.k8s.io"]
+  resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"]
+  verbs: ["list", "watch"]
+- apiGroups: ["apiextensions.k8s.io"]
+  resources: ["customresourcedefinitions"]
+  resourceNames: ["addresspools.metallb.io","bfdprofiles.metallb.io","bgpadvertisements.metallb.io",
+    "bgppeers.metallb.io","ipaddresspools.metallb.io","l2advertisements.metallb.io","communities.metallb.io"]
+  verbs: ["create", "delete", "get", "list", "patch", "update", "watch"]
+- apiGroups: ["apiextensions.k8s.io"]
+  resources: ["customresourcedefinitions"]
+  verbs: ["list", "watch"]
+{{- if .Values.prometheus.secureMetricsPort }}
+- apiGroups: ["authentication.k8s.io"]
+  resources: ["tokenreviews"]
+  verbs: ["create"]
+- apiGroups: ["authorization.k8s.io"]
+  resources: ["subjectaccessreviews"]
+  verbs: ["create"]
+{{- end }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: {{ template "metallb.fullname" . }}:speaker
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+rules:
+- apiGroups: [""]
+  resources: ["services", "endpoints", "nodes", "namespaces"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: ["discovery.k8s.io"]
+  resources: ["endpointslices"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: [""]
+  resources: ["events"]
+  verbs: ["create", "patch"]
+{{- if .Values.prometheus.secureMetricsPort }}
+- apiGroups: ["authentication.k8s.io"]
+  resources: ["tokenreviews"]
+  verbs: ["create"]
+- apiGroups: ["authorization.k8s.io"]
+  resources: ["subjectaccessreviews"]
+  verbs: ["create"]
+{{- end }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: {{ include "metallb.fullname" . }}-pod-lister
+  namespace: {{ .Release.Namespace | quote }}
+  labels: {{- include "metallb.labels" . | nindent 4 }}
+rules:
+- apiGroups: [""]
+  resources: ["pods"]
+  verbs: ["list"]
+- apiGroups: [""]
+  resources: ["secrets"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: [""]
+  resources: ["configmaps"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: ["metallb.io"]
+  resources: ["addresspools"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: ["metallb.io"]
+  resources: ["bfdprofiles"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: ["metallb.io"]
+  resources: ["bgppeers"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: ["metallb.io"]
+  resources: ["l2advertisements"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: ["metallb.io"]
+  resources: ["bgpadvertisements"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: ["metallb.io"]
+  resources: ["ipaddresspools"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: ["metallb.io"]
+  resources: ["communities"]
+  verbs: ["get", "list", "watch"]
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: {{ include "metallb.fullname" . }}-controller
+  namespace: {{ .Release.Namespace | quote }}
+  labels: {{- include "metallb.labels" . | nindent 4 }}
+rules:
+{{- if .Values.speaker.memberlist.enabled }}
+- apiGroups: [""]
+  resources: ["secrets"]
+  verbs: ["create", "get", "list", "watch"]
+- apiGroups: [""]
+  resources: ["secrets"]
+  resourceNames: [{{ include "metallb.secretName" . | quote }}]
+  verbs: ["list"]
+- apiGroups: ["apps"]
+  resources: ["deployments"]
+  resourceNames: ["{{ template "metallb.fullname" . }}-controller"]
+  verbs: ["get"]
+{{- end }}
+- apiGroups: [""]
+  resources: ["secrets"]
+  verbs: ["create", "delete", "get", "list", "patch", "update", "watch"]
+- apiGroups: ["metallb.io"]
+  resources: ["addresspools"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: ["metallb.io"]
+  resources: ["ipaddresspools"]
+  verbs: ["get", "list", "watch"]
+- apiGroups: ["metallb.io"]
+  resources: ["bgppeers"]
+  verbs: ["get", "list"]
+- apiGroups: ["metallb.io"]
+  resources: ["bgpadvertisements"]
+  verbs: ["get", "list"]
+- apiGroups: ["metallb.io"]
+  resources: ["l2advertisements"]
+  verbs: ["get", "list"]
+- apiGroups: ["metallb.io"]
+  resources: ["communities"]
+  verbs: ["get", "list","watch"]
+- apiGroups: ["metallb.io"]
+  resources: ["bfdprofiles"]
+  verbs: ["get", "list","watch"]
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: {{ template "metallb.fullname" . }}:controller
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+subjects:
+- kind: ServiceAccount
+  name: {{ template "metallb.controller.serviceAccountName" . }}
+  namespace: {{ .Release.Namespace }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: {{ template "metallb.fullname" . }}:controller
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: {{ template "metallb.fullname" . }}:speaker
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+subjects:
+- kind: ServiceAccount
+  name: {{ template "metallb.speaker.serviceAccountName" . }}
+  namespace: {{ .Release.Namespace }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: {{ template "metallb.fullname" . }}:speaker
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: {{ include "metallb.fullname" . }}-pod-lister
+  namespace: {{ .Release.Namespace | quote }}
+  labels: {{- include "metallb.labels" . | nindent 4 }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: {{ include "metallb.fullname" . }}-pod-lister
+subjects:
+- kind: ServiceAccount
+  name: {{ include "metallb.speaker.serviceAccountName" . }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: {{ include "metallb.fullname" . }}-controller
+  namespace: {{ .Release.Namespace | quote }}
+  labels: {{- include "metallb.labels" . | nindent 4 }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: {{ include "metallb.fullname" . }}-controller
+subjects:
+- kind: ServiceAccount
+  name: {{ include "metallb.controller.serviceAccountName" . }}
+{{- end -}}
diff --git a/charts/metallb/templates/service-accounts.yaml b/charts/metallb/templates/service-accounts.yaml
new file mode 100644
index 0000000..9615acf
--- /dev/null
+++ b/charts/metallb/templates/service-accounts.yaml
@@ -0,0 +1,30 @@
+{{- if .Values.controller.serviceAccount.create }}
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ template "metallb.controller.serviceAccountName" . }}
+  namespace: {{ .Release.Namespace | quote }}
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+    app.kubernetes.io/component: controller
+  {{- with .Values.controller.serviceAccount.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+{{- end }}
+{{- if .Values.speaker.serviceAccount.create }}
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ template "metallb.speaker.serviceAccountName" . }}
+  namespace: {{ .Release.Namespace | quote }}
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+    app.kubernetes.io/component: speaker
+  {{- with .Values.speaker.serviceAccount.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+{{- end }}
diff --git a/charts/metallb/templates/servicemonitor.yaml b/charts/metallb/templates/servicemonitor.yaml
new file mode 100644
index 0000000..1cfc0c4
--- /dev/null
+++ b/charts/metallb/templates/servicemonitor.yaml
@@ -0,0 +1,193 @@
+{{- if .Values.prometheus.serviceMonitor.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+  name: {{ template "metallb.fullname" . }}-speaker-monitor
+  namespace: {{ .Release.Namespace | quote }}
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+    app.kubernetes.io/component: speaker
+    {{- if .Values.prometheus.serviceMonitor.speaker.additionalLabels }}
+{{ toYaml .Values.prometheus.serviceMonitor.speaker.additionalLabels | indent 4 }}
+    {{- end }}
+  {{- if .Values.prometheus.serviceMonitor.speaker.annotations }}
+  annotations:
+{{ toYaml .Values.prometheus.serviceMonitor.speaker.annotations | indent 4 }}
+  {{- end }}
+spec:
+  endpoints:
+    - port: {{ template "metrics.exposedportname" . }}
+      honorLabels: true
+      {{- if .Values.prometheus.serviceMonitor.metricRelabelings }}
+      metricRelabelings:
+      {{- toYaml .Values.prometheus.serviceMonitor.metricRelabelings | nindent 8 }}
+      {{- end -}}
+      {{- if .Values.prometheus.serviceMonitor.relabelings }}
+      relabelings:
+      {{- toYaml .Values.prometheus.serviceMonitor.relabelings | nindent 8 }}
+      {{- end }}
+      {{- if .Values.prometheus.serviceMonitor.interval }}
+      interval: {{ .Values.prometheus.serviceMonitor.interval }}
+      {{- end -}}
+{{ if .Values.prometheus.secureMetricsPort }}
+      bearerTokenFile: "/var/run/secrets/kubernetes.io/serviceaccount/token"
+      scheme: "https"
+{{- if .Values.prometheus.serviceMonitor.speaker.tlsConfig }}
+      tlsConfig:
+{{ toYaml .Values.prometheus.serviceMonitor.speaker.tlsConfig | indent 8 }}      
+{{- end }}
+{{ end }}
+{{- if .Values.speaker.frr.enabled }}
+    - port: {{ template "metrics.exposedfrrportname" . }}
+      honorLabels: true
+{{ if .Values.speaker.frr.secureMetricsPort }}
+      {{- if .Values.prometheus.serviceMonitor.interval }}
+      interval: {{ .Values.prometheus.serviceMonitor.interval }}
+      {{- end }}
+      bearerTokenFile: "/var/run/secrets/kubernetes.io/serviceaccount/token"
+      scheme: "https"
+{{- if .Values.prometheus.serviceMonitor.speaker.tlsConfig }}
+      tlsConfig:
+{{ toYaml .Values.prometheus.serviceMonitor.speaker.tlsConfig | indent 8 }}      
+{{- end }}
+{{- end }}
+{{- end }}
+  jobLabel: {{ .Values.prometheus.serviceMonitor.jobLabel | quote }}
+  namespaceSelector:
+    matchNames:
+      - {{ .Release.Namespace }}
+  selector:
+    matchLabels:
+      name: {{ template "metallb.fullname" . }}-speaker-monitor-service
+---
+apiVersion: v1
+kind: Service
+metadata:
+  annotations:
+    prometheus.io/scrape: "true"
+  {{- if .Values.prometheus.serviceMonitor.speaker.annotations }}
+{{ toYaml .Values.prometheus.serviceMonitor.speaker.annotations | indent 4 }}
+  {{- end }}
+  labels:
+    name: {{ template "metallb.fullname" . }}-speaker-monitor-service
+  name: {{ template "metallb.fullname" . }}-speaker-monitor-service
+  namespace: {{ .Release.Namespace | quote }}
+spec:
+  selector:
+    {{- include "metallb.selectorLabels" . | nindent 4 }}
+    app.kubernetes.io/component: speaker
+  clusterIP: None
+  ports:
+    - name: {{ template "metrics.exposedportname" . }}
+      port: {{ template "metrics.exposedport" . }}
+      targetPort: {{ template "metrics.exposedport" . }}
+{{- if .Values.speaker.frr.enabled }}
+    - name: {{ template "metrics.exposedfrrportname" . }}
+      port: {{ template "metrics.exposedfrrport" . }}
+      targetPort: {{ template "metrics.exposedfrrport" . }}
+{{- end }}
+  sessionAffinity: None
+  type: ClusterIP
+---
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+  name: {{ template "metallb.fullname" . }}-controller-monitor
+  namespace: {{ .Release.Namespace | quote }}
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+    app.kubernetes.io/component: speaker
+    {{- if .Values.prometheus.serviceMonitor.controller.additionalLabels }}
+{{ toYaml .Values.prometheus.serviceMonitor.controller.additionalLabels | indent 4 }}
+    {{- end }}
+  {{- if .Values.prometheus.serviceMonitor.controller.annotations }}
+  annotations:
+{{ toYaml .Values.prometheus.serviceMonitor.controller.annotations | indent 4 }}
+  {{- end }}
+spec:
+  endpoints:
+    - port: {{ template "metrics.exposedportname" . }}
+      {{- if .Values.prometheus.serviceMonitor.metricRelabelings }}
+      metricRelabelings:
+      {{- toYaml .Values.prometheus.serviceMonitor.metricRelabelings | nindent 8 }}
+      {{- end -}}
+      {{- if .Values.prometheus.serviceMonitor.relabelings }}
+      relabelings:
+      {{- toYaml .Values.prometheus.serviceMonitor.relabelings | nindent 8 }}
+      {{- end }}
+      {{- if .Values.prometheus.serviceMonitor.interval }}
+      interval: {{ .Values.prometheus.serviceMonitor.interval }}
+      {{- end }}
+      honorLabels: true
+{{- if .Values.prometheus.secureMetricsPort }}
+      bearerTokenFile: "/var/run/secrets/kubernetes.io/serviceaccount/token"
+      scheme: "https"
+{{- if .Values.prometheus.serviceMonitor.controller.tlsConfig }}
+      tlsConfig:
+{{ toYaml .Values.prometheus.serviceMonitor.controller.tlsConfig | indent 8 }}      
+{{- end }}
+{{- end }}
+  jobLabel: {{ .Values.prometheus.serviceMonitor.jobLabel | quote }}
+  namespaceSelector:
+    matchNames:
+      - {{ .Release.Namespace }}
+  selector:
+    matchLabels:
+      name: {{ template "metallb.fullname" . }}-controller-monitor-service
+---
+apiVersion: v1
+kind: Service
+metadata:
+  annotations:
+    prometheus.io/scrape: "true"
+  {{- if .Values.prometheus.serviceMonitor.controller.annotations }}
+{{ toYaml .Values.prometheus.serviceMonitor.controller.annotations | indent 4 }}
+  {{- end }}
+  labels:
+    name: {{ template "metallb.fullname" . }}-controller-monitor-service
+  name: {{ template "metallb.fullname" . }}-controller-monitor-service
+spec:
+  selector:
+    {{- include "metallb.selectorLabels" . | nindent 4 }}
+    app.kubernetes.io/component: controller
+  clusterIP: None
+  ports:
+    - name: {{ template "metrics.exposedportname" . }}
+      port: {{ template "metrics.exposedport" . }}
+      targetPort: {{ template "metrics.exposedport" . }}
+  sessionAffinity: None
+  type: ClusterIP
+---
+{{- if .Values.prometheus.rbacPrometheus }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: {{ template "metallb.fullname" . }}-prometheus
+  namespace: {{ .Release.Namespace | quote }}
+rules:
+  - apiGroups:
+      - ""
+    resources:
+      - pods
+      - services
+      - endpoints
+    verbs:
+      - get
+      - list
+      - watch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: {{ template "metallb.fullname" . }}-prometheus
+  namespace: {{ .Release.Namespace | quote }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: {{ template "metallb.fullname" . }}-prometheus
+subjects:
+  - kind: ServiceAccount
+    name: {{ required ".Values.prometheus.serviceAccount must be defined when .Values.prometheus.serviceMonitor.enabled == true" .Values.prometheus.serviceAccount }}
+    namespace: {{ required ".Values.prometheus.namespace must be defined when .Values.prometheus.serviceMonitor.enabled == true" .Values.prometheus.namespace }}
+{{- end }}
+{{- end }}
diff --git a/charts/metallb/templates/speaker.yaml b/charts/metallb/templates/speaker.yaml
new file mode 100644
index 0000000..1a4c7b2
--- /dev/null
+++ b/charts/metallb/templates/speaker.yaml
@@ -0,0 +1,510 @@
+{{- if .Values.speaker.frr.enabled }}
+# FRR expects to have these files owned by frr:frr on startup.
+# Having them in a ConfigMap allows us to modify behaviors: for example enabling more daemons on startup.
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ template "metallb.fullname" . }}-frr-startup
+  namespace: {{ .Release.Namespace | quote }}
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+    app.kubernetes.io/component: speaker
+data:
+  daemons: |
+    # This file tells the frr package which daemons to start.
+    #
+    # Sample configurations for these daemons can be found in
+    # /usr/share/doc/frr/examples/.
+    #
+    # ATTENTION:
+    #
+    # When activating a daemon for the first time, a config file, even if it is
+    # empty, has to be present *and* be owned by the user and group "frr", else
+    # the daemon will not be started by /etc/init.d/frr. The permissions should
+    # be u=rw,g=r,o=.
+    # When using "vtysh" such a config file is also needed. It should be owned by
+    # group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too.
+    #
+    # The watchfrr and zebra daemons are always started.
+    #
+    bgpd=yes
+    ospfd=no
+    ospf6d=no
+    ripd=no
+    ripngd=no
+    isisd=no
+    pimd=no
+    ldpd=no
+    nhrpd=no
+    eigrpd=no
+    babeld=no
+    sharpd=no
+    pbrd=no
+    bfdd=yes
+    fabricd=no
+    vrrpd=no
+
+    #
+    # If this option is set the /etc/init.d/frr script automatically loads
+    # the config via "vtysh -b" when the servers are started.
+    # Check /etc/pam.d/frr if you intend to use "vtysh"!
+    #
+    vtysh_enable=yes
+    zebra_options="  -A 127.0.0.1 -s 90000000"
+    bgpd_options="   -A 127.0.0.1 -p 0"
+    ospfd_options="  -A 127.0.0.1"
+    ospf6d_options=" -A ::1"
+    ripd_options="   -A 127.0.0.1"
+    ripngd_options=" -A ::1"
+    isisd_options="  -A 127.0.0.1"
+    pimd_options="   -A 127.0.0.1"
+    ldpd_options="   -A 127.0.0.1"
+    nhrpd_options="  -A 127.0.0.1"
+    eigrpd_options=" -A 127.0.0.1"
+    babeld_options=" -A 127.0.0.1"
+    sharpd_options=" -A 127.0.0.1"
+    pbrd_options="   -A 127.0.0.1"
+    staticd_options="-A 127.0.0.1"
+    bfdd_options="   -A 127.0.0.1"
+    fabricd_options="-A 127.0.0.1"
+    vrrpd_options="  -A 127.0.0.1"
+
+    # configuration profile
+    #
+    #frr_profile="traditional"
+    #frr_profile="datacenter"
+
+    #
+    # This is the maximum number of FD's that will be available.
+    # Upon startup this is read by the control files and ulimit
+    # is called. Uncomment and use a reasonable value for your
+    # setup if you are expecting a large number of peers in
+    # say BGP.
+    #MAX_FDS=1024
+
+    # The list of daemons to watch is automatically generated by the init script.
+    #watchfrr_options=""
+
+    # for debugging purposes, you can specify a "wrap" command to start instead
+    # of starting the daemon directly, e.g. to use valgrind on ospfd:
+    #   ospfd_wrap="/usr/bin/valgrind"
+    # or you can use "all_wrap" for all daemons, e.g. to use perf record:
+    #   all_wrap="/usr/bin/perf record --call-graph -"
+    # the normal daemon command is added to this at the end.
+  vtysh.conf: |+
+    service integrated-vtysh-config
+  frr.conf: |+
+    ! This file gets overriden the first time the speaker renders a config.
+    ! So anything configured here is only temporary.
+    frr version 7.5.1
+    frr defaults traditional
+    hostname Router
+    line vty
+    log file /etc/frr/frr.log informational
+{{- end }}
+---
+{{- if .Values.speaker.enabled }}
+apiVersion: apps/v1
+kind: DaemonSet
+metadata:
+  name: {{ template "metallb.fullname" . }}-speaker
+  namespace: {{ .Release.Namespace | quote }}
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+    app.kubernetes.io/component: speaker
+    {{- range $key, $value := .Values.speaker.labels }}
+    {{ $key }}: {{ $value | quote }}
+    {{- end }}
+spec:
+  {{- if .Values.speaker.updateStrategy }}
+  updateStrategy: {{- toYaml .Values.speaker.updateStrategy | nindent 4 }}
+  {{- end }}
+  selector:
+    matchLabels:
+      {{- include "metallb.selectorLabels" . | nindent 6 }}
+      app.kubernetes.io/component: speaker
+  template:
+    metadata:
+      {{- if or .Values.prometheus.scrapeAnnotations .Values.speaker.podAnnotations }}
+      annotations:
+        {{- if .Values.prometheus.scrapeAnnotations }}
+        prometheus.io/scrape: "true"
+        {{- if not .Values.speaker.frr.enabled }}
+        prometheus.io/port: "{{ .Values.prometheus.metricsPort }}"
+        {{- end }}
+        {{- end }}
+        {{- with .Values.speaker.podAnnotations }}
+          {{- toYaml . | nindent 8 }}
+        {{- end }}
+      {{- end }}
+      labels:
+        {{- include "metallb.selectorLabels" . | nindent 8 }}
+        app.kubernetes.io/component: speaker
+        {{- range $key, $value := .Values.speaker.labels }}
+        {{ $key }}: {{ $value | quote }}
+        {{- end }}
+    spec:
+      {{- if .Values.speaker.runtimeClassName }}
+      runtimeClassName: {{ .Values.speaker.runtimeClassName }}
+      {{- end }}
+      {{- with .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      serviceAccountName: {{ template "metallb.speaker.serviceAccountName" . }}
+      terminationGracePeriodSeconds: 0
+      hostNetwork: true
+      volumes:
+      {{- if .Values.speaker.memberlist.enabled }}
+        - name: memberlist
+          secret:
+            secretName: {{ include "metallb.secretName" . }}
+            defaultMode: 420
+      {{- end }}
+      {{- if .Values.speaker.excludeInterfaces.enabled }}
+        - name: metallb-excludel2
+          configMap:
+            defaultMode: 256
+            name: metallb-excludel2
+      {{- end }}
+      {{- if .Values.speaker.frr.enabled }}
+        - name: frr-sockets
+          emptyDir: {}
+        - name: frr-startup
+          configMap:
+            name: {{ template "metallb.fullname" . }}-frr-startup
+        - name: frr-conf
+          emptyDir: {}
+        - name: reloader
+          emptyDir: {}
+        - name: metrics
+          emptyDir: {}
+      {{- if .Values.prometheus.speakerMetricsTLSSecret }}
+        - name: metrics-certs
+          secret:
+            secretName: {{ .Values.prometheus.speakerMetricsTLSSecret }}
+      {{- end }}
+      initContainers:
+        # Copies the initial config files with the right permissions to the shared volume.
+        - name: cp-frr-files
+          image: {{ .Values.speaker.frr.image.repository }}:{{ .Values.speaker.frr.image.tag | default .Chart.AppVersion }}
+          securityContext:
+            runAsUser: 100
+            runAsGroup: 101
+          command: ["/bin/sh", "-c", "cp -rLf /tmp/frr/* /etc/frr/"]
+          volumeMounts:
+            - name: frr-startup
+              mountPath: /tmp/frr
+            - name: frr-conf
+              mountPath: /etc/frr
+        # Copies the reloader to the shared volume between the speaker and reloader.
+        - name: cp-reloader
+          image: {{ .Values.speaker.image.repository }}:{{ .Values.speaker.image.tag | default .Chart.AppVersion }}
+          command: ["/bin/sh", "-c", "cp -f /frr-reloader.sh /etc/frr_reloader/"]
+          volumeMounts:
+            - name: reloader
+              mountPath: /etc/frr_reloader
+        # Copies the metrics exporter
+        - name: cp-metrics
+          image: {{ .Values.speaker.image.repository }}:{{ .Values.speaker.image.tag | default .Chart.AppVersion }}
+          command: ["/bin/sh", "-c", "cp -f /frr-metrics /etc/frr_metrics/"]
+          volumeMounts:
+            - name: metrics
+              mountPath: /etc/frr_metrics
+      shareProcessNamespace: true
+      {{- end }}
+      containers:
+      - name: speaker
+        image: {{ .Values.speaker.image.repository }}:{{ .Values.speaker.image.tag | default .Chart.AppVersion }}
+        {{- if .Values.speaker.image.pullPolicy }}
+        imagePullPolicy: {{ .Values.speaker.image.pullPolicy }}
+        {{- end }}
+        {{- if .Values.speaker.command }}
+        command:
+          - {{ .Values.speaker.command }}
+        {{- end }}
+        args:
+        - --port={{ .Values.prometheus.metricsPort }}
+        {{- with .Values.speaker.logLevel }}
+        - --log-level={{ . }}
+        {{- end }}
+        {{- if .Values.loadBalancerClass }}
+        - --lb-class={{ .Values.loadBalancerClass }}
+        {{- end }}
+        env:
+        - name: METALLB_NODE_NAME
+          valueFrom:
+            fieldRef:
+              fieldPath: spec.nodeName
+        - name: METALLB_HOST
+          valueFrom:
+            fieldRef:
+              fieldPath: status.hostIP
+        {{- if .Values.speaker.memberlist.enabled }}
+        - name: METALLB_ML_BIND_ADDR
+          valueFrom:
+            fieldRef:
+              fieldPath: status.podIP
+        - name: METALLB_ML_LABELS
+          value: "app.kubernetes.io/name={{ include "metallb.name" . }},app.kubernetes.io/component=speaker"
+        - name: METALLB_ML_BIND_PORT
+          value: "{{ .Values.speaker.memberlist.mlBindPort }}"
+        - name: METALLB_ML_SECRET_KEY_PATH
+          value: "{{ .Values.speaker.memberlist.mlSecretKeyPath }}"
+        {{- end }}
+        {{- if .Values.speaker.frr.enabled }}
+        - name: FRR_CONFIG_FILE
+          value: /etc/frr_reloader/frr.conf
+        - name: FRR_RELOADER_PID_FILE
+          value: /etc/frr_reloader/reloader.pid
+        - name: METALLB_BGP_TYPE
+          value: frr
+        {{- end }}
+        ports:
+        - name: monitoring
+          containerPort: {{ .Values.prometheus.metricsPort }}
+        {{- if .Values.speaker.memberlist.enabled }}
+        - name: memberlist-tcp
+          containerPort: {{ .Values.speaker.memberlist.mlBindPort }}
+          protocol: TCP
+        - name: memberlist-udp
+          containerPort: {{ .Values.speaker.memberlist.mlBindPort }}
+          protocol: UDP
+        {{- end }}
+        {{- if .Values.speaker.livenessProbe.enabled }}
+        livenessProbe:
+          httpGet:
+            path: /metrics
+            port: monitoring
+          initialDelaySeconds: {{ .Values.speaker.livenessProbe.initialDelaySeconds }}
+          periodSeconds: {{ .Values.speaker.livenessProbe.periodSeconds }}
+          timeoutSeconds: {{ .Values.speaker.livenessProbe.timeoutSeconds }}
+          successThreshold: {{ .Values.speaker.livenessProbe.successThreshold }}
+          failureThreshold: {{ .Values.speaker.livenessProbe.failureThreshold }}
+        {{- end }}
+        {{- if .Values.speaker.readinessProbe.enabled }}
+        readinessProbe:
+          httpGet:
+            path: /metrics
+            port: monitoring
+          initialDelaySeconds: {{ .Values.speaker.readinessProbe.initialDelaySeconds }}
+          periodSeconds: {{ .Values.speaker.readinessProbe.periodSeconds }}
+          timeoutSeconds: {{ .Values.speaker.readinessProbe.timeoutSeconds }}
+          successThreshold: {{ .Values.speaker.readinessProbe.successThreshold }}
+          failureThreshold: {{ .Values.speaker.readinessProbe.failureThreshold }}
+        {{- end }}
+        {{- with .Values.speaker.resources }}
+        resources:
+          {{- toYaml . | nindent 10 }}
+        {{- end }}
+        securityContext:
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
+          capabilities:
+            drop:
+            - ALL
+            add:
+            - NET_RAW
+        {{- if or .Values.speaker.frr.enabled .Values.speaker.memberlist.enabled .Values.speaker.excludeInterfaces.enabled }}
+        volumeMounts:
+          {{- if .Values.speaker.memberlist.enabled }}
+          - name: memberlist 
+            mountPath: {{ .Values.speaker.memberlist.mlSecretKeyPath }}
+          {{- end }}
+          {{- if .Values.speaker.frr.enabled }}
+          - name: reloader
+            mountPath: /etc/frr_reloader
+          {{- end }}
+          {{- if .Values.speaker.excludeInterfaces.enabled }}
+          - name: metallb-excludel2
+            mountPath: /etc/metallb
+          {{- end }}
+        {{- end }}
+      {{- if .Values.speaker.frr.enabled }}
+      - name: frr
+        securityContext:
+          capabilities:
+            add:
+            - NET_ADMIN
+            - NET_RAW
+            - SYS_ADMIN
+            - NET_BIND_SERVICE
+        image: {{ .Values.speaker.frr.image.repository }}:{{ .Values.speaker.frr.image.tag | default .Chart.AppVersion }}
+        {{- if .Values.speaker.frr.image.pullPolicy }}
+        imagePullPolicy: {{ .Values.speaker.frr.image.pullPolicy }}
+        {{- end }}
+        env:
+          - name: TINI_SUBREAPER
+            value: "true"
+        volumeMounts:
+          - name: frr-sockets
+            mountPath: /var/run/frr
+          - name: frr-conf
+            mountPath: /etc/frr
+        # The command is FRR's default entrypoint & waiting for the log file to appear and tailing it.
+        # If the log file isn't created in 60 seconds the tail fails and the container is restarted.
+        # This workaround is needed to have the frr logs as part of kubectl logs -c frr < speaker_pod_name >.
+        command:
+          - /bin/sh
+          - -c
+          - |
+            /sbin/tini -- /usr/lib/frr/docker-start &
+            attempts=0
+            until [[ -f /etc/frr/frr.log || $attempts -eq 60 ]]; do
+              sleep 1
+              attempts=$(( $attempts + 1 ))
+            done
+            tail -f /etc/frr/frr.log
+        {{- with .Values.speaker.frr.resources }}
+        resources:
+          {{- toYaml . | nindent 12 }}
+        {{- end }}
+        {{- if .Values.speaker.livenessProbe.enabled }}
+        livenessProbe:
+          httpGet:
+            path: /livez
+            port: {{ .Values.speaker.frr.metricsPort }}
+          initialDelaySeconds: {{ .Values.speaker.livenessProbe.initialDelaySeconds }}
+          periodSeconds: {{ .Values.speaker.livenessProbe.periodSeconds }}
+          timeoutSeconds: {{ .Values.speaker.livenessProbe.timeoutSeconds }}
+          successThreshold: {{ .Values.speaker.livenessProbe.successThreshold }}
+          failureThreshold: {{ .Values.speaker.livenessProbe.failureThreshold }}
+        {{- end }}
+        {{- if .Values.speaker.startupProbe.enabled }}
+        startupProbe:
+          httpGet:
+            path: /livez
+            port: {{ .Values.speaker.frr.metricsPort }}
+          failureThreshold: {{ .Values.speaker.startupProbe.failureThreshold }}
+          periodSeconds: {{ .Values.speaker.startupProbe.periodSeconds }}
+        {{- end }}
+      - name: reloader
+        image: {{ .Values.speaker.frr.image.repository }}:{{ .Values.speaker.frr.image.tag | default .Chart.AppVersion }}
+        {{- if .Values.speaker.frr.image.pullPolicy }}
+        imagePullPolicy: {{ .Values.speaker.frr.image.pullPolicy }}
+        {{- end }}
+        command: ["/etc/frr_reloader/frr-reloader.sh"]
+        volumeMounts:
+          - name: frr-sockets
+            mountPath: /var/run/frr
+          - name: frr-conf
+            mountPath: /etc/frr
+          - name: reloader
+            mountPath: /etc/frr_reloader
+        {{- with .Values.speaker.reloader.resources }}
+        resources:
+          {{- toYaml . | nindent 12 }}
+        {{- end }}
+      - name: frr-metrics
+        image: {{ .Values.speaker.frr.image.repository }}:{{ .Values.speaker.frr.image.tag | default .Chart.AppVersion }}
+        command: ["/etc/frr_metrics/frr-metrics"]
+        args:
+          - --metrics-port={{ .Values.speaker.frr.metricsPort }}
+        ports:
+          - containerPort: {{ .Values.speaker.frr.metricsPort }}
+            name: monitoring
+        volumeMounts:
+          - name: frr-sockets
+            mountPath: /var/run/frr
+          - name: frr-conf
+            mountPath: /etc/frr
+          - name: metrics
+            mountPath: /etc/frr_metrics
+        {{- with .Values.speaker.frrMetrics.resources }}
+        resources:
+          {{- toYaml . | nindent 12 }}
+        {{- end }}
+      {{- end }}
+      {{- if .Values.prometheus.secureMetricsPort }}
+      - name: kube-rbac-proxy
+        image: {{ .Values.prometheus.rbacProxy.repository }}:{{ .Values.prometheus.rbacProxy.tag }}
+        imagePullPolicy: {{ .Values.prometheus.rbacProxy.pullPolicy }}
+        args:
+          - --logtostderr
+          - --secure-listen-address=:{{ .Values.prometheus.secureMetricsPort }}
+          - --upstream=http://$(METALLB_HOST):{{ .Values.prometheus.metricsPort }}/
+          - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+        {{- if .Values.prometheus.speakerMetricsTLSSecret }}
+          - --tls-private-key-file=/etc/metrics/tls.key
+          - --tls-cert-file=/etc/metrics/tls.crt
+        {{- end }}
+        ports:
+          - containerPort: {{ .Values.prometheus.secureMetricsPort }}
+            name: metricshttps
+        env:
+          - name: METALLB_HOST
+            valueFrom:
+              fieldRef:
+                fieldPath: status.hostIP
+        resources:
+          requests:
+            cpu: 10m
+            memory: 20Mi
+        terminationMessagePolicy: FallbackToLogsOnError
+        {{- if .Values.prometheus.speakerMetricsTLSSecret }}
+        volumeMounts:
+          - name: metrics-certs
+            mountPath: /etc/metrics
+            readOnly: true
+        {{- end }}
+      {{ end }}
+      {{- if .Values.speaker.frr.secureMetricsPort }}
+      - name: kube-rbac-proxy-frr
+        image: {{ .Values.prometheus.rbacProxy.repository }}:{{ .Values.prometheus.rbacProxy.tag | default .Chart.AppVersion }}
+        imagePullPolicy: {{ .Values.prometheus.rbacProxy.pullPolicy }}
+        args:
+          - --logtostderr
+          - --secure-listen-address=:{{ .Values.speaker.frr.secureMetricsPort }}
+          - --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+          - --upstream=http://$(METALLB_HOST):{{ .Values.speaker.frr.metricsPort }}/
+        {{- if .Values.prometheus.speakerMetricsTLSSecret }}
+          - --tls-private-key-file=/etc/metrics/tls.key
+          - --tls-cert-file=/etc/metrics/tls.crt
+        {{- end }}
+        ports:
+          - containerPort: {{ .Values.speaker.frr.secureMetricsPort }}
+            name: metricshttps
+        env:
+          - name: METALLB_HOST
+            valueFrom:
+              fieldRef:
+                fieldPath: status.hostIP
+        resources:
+          requests:
+            cpu: 10m
+            memory: 20Mi
+        terminationMessagePolicy: FallbackToLogsOnError
+        {{- if .Values.prometheus.speakerMetricsTLSSecret }}
+        volumeMounts:
+          - name: metrics-certs
+            mountPath: /etc/metrics
+            readOnly: true
+        {{- end }}
+      {{ end }}
+      nodeSelector:
+        "kubernetes.io/os": linux
+        {{- with .Values.speaker.nodeSelector }}
+          {{- toYaml . | nindent 8 }}
+        {{- end }}
+      {{- with .Values.speaker.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- if or .Values.speaker.tolerateMaster .Values.speaker.tolerations }}
+      tolerations:
+      {{- if .Values.speaker.tolerateMaster }}
+      - key: node-role.kubernetes.io/master
+        effect: NoSchedule
+        operator: Exists
+      - key: node-role.kubernetes.io/control-plane
+        effect: NoSchedule
+        operator: Exists        
+      {{- end }}
+      {{- with .Values.speaker.tolerations }}
+        {{- toYaml . | nindent 6 }}
+      {{- end }}
+      {{- end }}
+      {{- with .Values.speaker.priorityClassName }}
+      priorityClassName: {{ . | quote }}
+      {{- end }}
+{{- end }}
diff --git a/charts/metallb/templates/webhooks.yaml b/charts/metallb/templates/webhooks.yaml
new file mode 100644
index 0000000..3b587a4
--- /dev/null
+++ b/charts/metallb/templates/webhooks.yaml
@@ -0,0 +1,170 @@
+apiVersion: admissionregistration.k8s.io/v1
+kind: ValidatingWebhookConfiguration
+metadata:
+  name: metallb-webhook-configuration
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+webhooks:
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: metallb-webhook-service
+      namespace: {{ .Release.Namespace }}
+      path: /validate-metallb-io-v1beta1-addresspool
+  failurePolicy: {{ .Values.crds.validationFailurePolicy }}
+  name: addresspoolvalidationwebhook.metallb.io
+  rules:
+  - apiGroups:
+    - metallb.io
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - addresspools
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: metallb-webhook-service
+      namespace: {{ .Release.Namespace }}
+      path: /validate-metallb-io-v1beta2-bgppeer
+  failurePolicy: {{ .Values.crds.validationFailurePolicy }}
+  name: bgppeervalidationwebhook.metallb.io
+  rules:
+  - apiGroups:
+    - metallb.io
+    apiVersions:
+    - v1beta2
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - bgppeers
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: metallb-webhook-service
+      namespace: {{ .Release.Namespace }}
+      path: /validate-metallb-io-v1beta1-ipaddresspool
+  failurePolicy: {{ .Values.crds.validationFailurePolicy }}
+  name: ipaddresspoolvalidationwebhook.metallb.io
+  rules:
+  - apiGroups:
+    - metallb.io
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - ipaddresspools
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: metallb-webhook-service
+      namespace: {{ .Release.Namespace }}
+      path: /validate-metallb-io-v1beta1-bgpadvertisement
+  failurePolicy: {{ .Values.crds.validationFailurePolicy }}
+  name: bgpadvertisementvalidationwebhook.metallb.io
+  rules:
+  - apiGroups:
+    - metallb.io
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - bgpadvertisements
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: metallb-webhook-service
+      namespace: {{ .Release.Namespace }}
+      path: /validate-metallb-io-v1beta1-community
+  failurePolicy: {{ .Values.crds.validationFailurePolicy }}
+  name: communityvalidationwebhook.metallb.io
+  rules:
+  - apiGroups:
+    - metallb.io
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - communities
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: metallb-webhook-service
+      namespace: {{ .Release.Namespace }}
+      path: /validate-metallb-io-v1beta1-bfdprofile
+  failurePolicy: {{ .Values.crds.validationFailurePolicy }}
+  name: bfdprofilevalidationwebhook.metallb.io
+  rules:
+  - apiGroups:
+    - metallb.io
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - DELETE
+    resources:
+    - bfdprofiles
+  sideEffects: None
+- admissionReviewVersions:
+  - v1
+  clientConfig:
+    service:
+      name: metallb-webhook-service
+      namespace: {{ .Release.Namespace }}
+      path: /validate-metallb-io-v1beta1-l2advertisement
+  failurePolicy: {{ .Values.crds.validationFailurePolicy }}
+  name: l2advertisementvalidationwebhook.metallb.io
+  rules:
+  - apiGroups:
+    - metallb.io
+    apiVersions:
+    - v1beta1
+    operations:
+    - CREATE
+    - UPDATE
+    resources:
+    - l2advertisements
+  sideEffects: None
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: metallb-webhook-service
+  namespace: {{ .Release.Namespace | quote }}
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}
+spec:
+  ports:
+  - port: 443
+    targetPort: 9443
+  selector:
+    {{- include "metallb.selectorLabels" . | nindent 4 }}
+    app.kubernetes.io/component: controller
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: webhook-server-cert
+  namespace: {{ .Release.Namespace | quote }}
+  labels:
+    {{- include "metallb.labels" . | nindent 4 }}