Skip to main content
An allowed address pair binds an extra IP address — or a CIDR range — to a Virtual Machine’s network interface. By default, each port enforces a strict MAC-to-IP binding, so only traffic addressed to the port’s own IP is accepted. Adding an entry to the allowed address pairs list lifts that restriction for the specified address, making the machine accessible on both its original IP and the additional one. A common use case is distributing a virtual IP address across multiple VMs using Keepalived — each VM’s port must allow the shared VIP address.
A permanent API token is required, along with a project ID and region ID.
Set these environment variables before running the examples:
export GCORE_API_KEY="{YOUR_API_KEY}"
export GCORE_CLOUD_PROJECT_ID="{YOUR_PROJECT_ID}"
export GCORE_CLOUD_REGION_ID="{YOUR_REGION_ID}"
export INSTANCE_ID="{YOUR_INSTANCE_ID}"
export PORT_ID="{YOUR_PORT_ID}"
To find the values for each variable:
  • INSTANCE_ID: the UUID of the virtual machine whose port you want to configure. To create a VM or find its ID, see Create a virtual machine.
  • PORT_ID: the UUID of the VM’s private network interface port. The external (public) interface does not support allowed address pairs. See the Find the port ID section below for how to retrieve it.

Find the port ID

Each VM network interface has a port_id. Allowed address pairs are applied per port, and only ports on private (non-external) networks support this feature.
import os
import requests

session = requests.Session()
session.headers.update({"Authorization": f"APIKey {os.environ['GCORE_API_KEY']}"})

resp = session.get(
    f"https://api.gcore.com/cloud/v1/instances"
    f"/{os.environ['GCORE_CLOUD_PROJECT_ID']}/{os.environ['GCORE_CLOUD_REGION_ID']}"
    f"/{os.environ['INSTANCE_ID']}/interfaces"
)
resp.raise_for_status()
for iface in resp.json()["results"]:
    print(f"port_id={iface['port_id']}  ip={iface['ip_assignments'][0]['ip_address']}")
Save the port_id of the private interface (the one with a private IP range such as 10.x.x.x or 192.168.x.x) as PORT_ID. The external interface with a public IP does not support allowed address pairs. The same endpoint also shows allowed_address_pairs on each interface, so you can use it to verify the result after setting pairs.

Set allowed address pairs

The PUT request replaces the entire list of allowed address pairs for the port. To add one pair without losing existing ones, include all current pairs in the request body alongside the new entry.
ParameterRequiredDescription
ip_addressYesIP address or CIDR range to allow (e.g. 192.168.1.10 or 10.0.0.0/24)
mac_addressNoMAC address to associate; defaults to the port’s own MAC when omitted
Up to 10 pairs are allowed per port.
import os
import time
import requests

session = requests.Session()
session.headers.update({"Authorization": f"APIKey {os.environ['GCORE_API_KEY']}"})
base = "https://api.gcore.com/cloud"

resp = session.put(
    f"{base}/v2/ports"
    f"/{os.environ['GCORE_CLOUD_PROJECT_ID']}/{os.environ['GCORE_CLOUD_REGION_ID']}"
    f"/{os.environ['PORT_ID']}/allow_address_pairs",
    json={
        "allowed_address_pairs": [
            {"ip_address": "192.168.123.20", "mac_address": "00:16:3e:f2:87:16"},
            {"ip_address": "192.168.0.0/24"},
        ]
    },
)
resp.raise_for_status()
task_id = resp.json()["tasks"][0]

while True:
    state = session.get(f"{base}/v1/tasks/{task_id}").json()["state"]
    if state == "FINISHED":
        break
    time.sleep(5)
print("Pairs applied.")
When mac_address is omitted, the API assigns the port’s default MAC address to that entry automatically.

Remove allowed address pairs

To remove all allowed address pairs from a port, send the same PUT request with an empty allowed_address_pairs array. The operation is asynchronous — poll the returned task until state is FINISHED.
import os
import time
import requests

session = requests.Session()
session.headers.update({"Authorization": f"APIKey {os.environ['GCORE_API_KEY']}"})
base = "https://api.gcore.com/cloud"

resp = session.put(
    f"{base}/v2/ports"
    f"/{os.environ['GCORE_CLOUD_PROJECT_ID']}/{os.environ['GCORE_CLOUD_REGION_ID']}"
    f"/{os.environ['PORT_ID']}/allow_address_pairs",
    json={"allowed_address_pairs": []},
)
resp.raise_for_status()
task_id = resp.json()["tasks"][0]

while True:
    state = session.get(f"{base}/v1/tasks/{task_id}").json()["state"]
    if state == "FINISHED":
        break
    time.sleep(5)
print("Pairs removed.")
To remove individual pairs rather than all of them, omit only the entries to remove and include the rest in the request body.