Port Profile
A Port Profile is a named network configuration template that can be applied to switch ports. Each profile carries one or more Roles (NetBox Config Contexts) and Interface Mappings that bind logical interface names to VRFs and — optionally — to a set of VLANs scoped by a VLAN Group.
Models
PortProfile
Extends NetBoxModel.
| Field | Type | Editable via API | Description |
|---|---|---|---|
id |
integer | — | Auto-generated primary key |
name |
string (max 100) | ✅ | Unique identifier across all port profiles |
config_contexts |
M2M → extras.ConfigContext |
✅ (role_ids) |
Config contexts that define the role of this profile. Exposed as role (read) and role_ids (write) in the API. Labelled Roles in the UI. |
tags |
array | ✅ | Standard NetBox tags |
custom_fields |
object | ✅ | Standard NetBox custom fields |
created |
datetime | — | Record creation timestamp |
last_updated |
datetime | — | Last DB write timestamp |
PortProfileInterfaceMapping
Extends models.Model.
| Field | Type | Editable via API | Description |
|---|---|---|---|
id |
integer | — | Auto-generated primary key |
port_profile |
FK → PortProfile |
✅ | Parent port profile. Cascade-deleted when the profile is deleted. |
interface_name |
string (max 100) | ✅ | Logical interface name |
vrfs |
M2M → ipam.VRF |
✅ (vrf_ids) |
VRFs associated with this interface |
vlan_group |
FK → ipam.VLANGroup |
✅ (vlan_group_id) |
Optional VLAN group used to scope VLAN selection. Nullable — SET NULL when the group is deleted. Exposed as vlan_group (read, nested) and vlan_group_id (write, PK) in the API. |
vlans |
M2M → ipam.VLAN |
✅ (vlan_ids) |
VLANs assigned to this interface mapping. Exposed as vlans (read, nested array) and vlan_ids (write, list of PKs) in the API. |
Constraints
- Unique name:
PortProfile.namemust be unique across all port profiles. - Cascade delete: deleting a Port Profile automatically deletes all of its Interface Mappings. Referenced Config Contexts, VLANs, and VRFs are never deleted.
- VLAN Group nullability: deleting a VLANGroup sets
vlan_grouptonullon any Interface Mapping that referenced it — the mapping and its VLAN assignments are otherwise unaffected. - VLAN Group scoping: there is no server-side enforcement that selected VLANs belong to the specified
vlan_group. The group is purely a UI scoping aid.
UI
Port Profile is accessible from the Plugins → Network → Port Profiles menu.
List View
Displays all port profiles in a filterable, sortable table.
| Column | Description |
|---|---|
| Name | Hyperlink to the detail view. Sortable. |
| Roles | Up to 2 config-context badge pills shown inline. When more than 2 are assigned, a blue +N more badge appears — hover it to see the full list as a tooltip. |
| Interface Mappings | Count of child mappings for the profile. |
Interface Mapping List View
Displays all interface mappings in a filterable, sortable table.
| Column | Description |
|---|---|
| Port Profile | Hyperlink to the parent Port Profile detail page. |
| Interface Name | Logical interface name. Hyperlink to the mapping detail view. |
| VRFs | Badge pills for each assigned VRF. |
| VLAN Group | Badge link to the VLANGroup detail page. Shows — when no group is assigned. |
| VLANs | Up to 2 VLAN badge pills (<vid> <name>) shown inline. When more than 2 are assigned, a blue +N more badge appears — hover it to see the full list as a tooltip. Shows — when no VLANs are assigned. |
Detail View
The detail page is split into two columns.
Left column
- Port Profile card — Name attribute row.
- Tags panel.
Right column
- Roles card — badge grid of all assigned config contexts. The card header shows the total count. Each badge links to the Config Context detail page and shows its description on hover.
- Custom Fields panel.
Tabs: Port Profile (default) · Interface Mappings (badge shows count) · Journal · Changelog
Interface Mapping Detail View
The interface mapping detail page shows:
- Interface Mapping card — Port Profile, Interface Name, and VLAN Group attribute rows.
- VLANs card — badge grid of all assigned VLANs (
<vid> – <name>). The card header shows the total count. Each badge links to the VLAN detail page. Shows "None" when no VLANs are assigned. - VRFs card — assigned VRFs.
Add / Edit View — Port Profile
Path: Plugins → Network → Port Profiles → + Add
The form is organised into two fieldsets:
Port Profile
| Field | Required | Validation |
|---|---|---|
| Name | Yes | Unique. Max 100 characters. Duplicate names are rejected on save with an inline error. |
| Roles | No | Dynamic multi-select over existing NetBox Config Contexts. Zero or more may be selected. Help text: "Config contexts assigned as the role for this port profile." |
Tags
| Field | Required | Validation |
|---|---|---|
| Tags | No | Standard NetBox tag picker. |
Add / Edit View — Interface Mapping
Path: Plugins → Network → Port Profile Interface Mappings → + Add — or — Port Profile detail page → Interface Mappings tab → + Add
The form is organised into two fieldsets:
Interface Mapping
| Field | Required | Validation |
|---|---|---|
| Port Profile | Yes | Must reference an existing Port Profile. |
| Interface Name | Yes | Max 100 characters. Not required to be unique across profiles. |
| VRFs | No | Dynamic multi-select over IPAM VRFs. |
VLANs
| Field | Required | Validation |
|---|---|---|
| VLAN Group | No | Dynamic single-select over IPAM VLANGroups. Selecting a group automatically scopes the VLANs dropdown to only VLANs belonging to that group. Help text: "Optionally scope VLAN selection to a specific VLAN group." |
| VLANs | No | Dynamic multi-select over IPAM VLANs. When a VLAN Group is selected above, the list is filtered to that group's VLANs. Zero or more may be selected. Help text: "VLANs assigned to this interface mapping." |
Delete
- Single delete: Delete button on the detail page.
- Bulk delete: check one or more rows on the list → Delete Selected. Cascade-deletes all child interface mappings when deleting a Port Profile.
Filter Drawer — Port Profiles
Click the funnel icon on the Port Profile list view to open the filter panel.
| Filter field | Query param | Behaviour |
|---|---|---|
| Search | q |
Case-insensitive substring match across name and assigned config-context names. Results are deduplicated. |
| Name | name |
Case-insensitive contains match on profile name. |
| Role | config_context_id |
Dynamic multi-select. Filters to profiles that have any of the selected config contexts assigned. |
Filter Drawer — Interface Mappings
Click the funnel icon on the Interface Mapping list view to open the filter panel.
| Filter field | Query param | Behaviour |
|---|---|---|
| Search | q |
Case-insensitive substring match across interface_name, parent port profile name, VLAN group name, VLAN names, and VLAN IDs. Results are deduplicated. |
| Port Profile | port_profile |
Dynamic single-select. Filters to mappings belonging to the selected profile. |
| Interface Name | interface_name |
Case-insensitive contains match on interface name. |
| VLAN Group | vlan_group_id |
Dynamic multi-select. Filters to mappings whose vlan_group matches any of the selected groups. |
| VLAN | vlan_id |
Dynamic multi-select, scoped by the selected VLAN Group above. Filters to mappings that have any of the selected VLANs assigned. |
API
Base URL: /api/plugins/ibm-netbox-plugins/
Interactive docs: /api/docs/ → ibm-netbox-plugins section.
Authentication: Authorization: Token <token>
All responses are JSON. Paginated list responses use the standard NetBox envelope:
{
"count": <int>,
"next": "<url | null>",
"previous": "<url | null>",
"results": [...]
}
Read field vs write field for Roles
The API exposes two separate fields for roles:
role(read-only) — returned in every GET response as a list of nested Config Context objects.role_ids(write-only) — accepted in POST, PUT, and PATCH request bodies as a list of Config Context PKs. Sendingrole_idsreplaces the full role set. To clear all roles send"role_ids": []. Omittingrole_idsleaves existing roles unchanged.
Read field vs write field for VLAN Group and VLANs (Interface Mapping)
Both VLAN-related fields on the Interface Mapping resource follow the same read/write split pattern:
vlan_group(read-only) — returned in GET responses as a nested VLANGroup object (ornull).vlan_group_id(write-only) — accepted in POST, PUT, and PATCH as a VLANGroup PK. Sendnullto clear.vlans(read-only) — returned in GET responses as a list of nested VLAN objects.vlan_ids(write-only) — accepted in POST, PUT, and PATCH as a list of VLAN PKs. Sendingvlan_idsreplaces the full VLAN set. Send[]to clear all VLANs. Omittingvlan_idsleaves existing VLANs unchanged.
There is no server-side enforcement that selected VLANs belong to the specified vlan_group. The group is purely a UI scoping aid.
Port Profile endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /port-profiles/ |
List all port profiles (paginated) |
| POST | /port-profiles/ |
Create a port profile |
| GET | /port-profiles/{id}/ |
Retrieve a single port profile |
| PUT | /port-profiles/{id}/ |
Full replacement update |
| PATCH | /port-profiles/{id}/ |
Partial update |
| DELETE | /port-profiles/{id}/ |
Delete (cascades to interface mappings) |
Interface Mapping endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /port-profile-interface-mappings/ |
List all mappings (paginated) |
| POST | /port-profile-interface-mappings/ |
Create a mapping |
| GET | /port-profile-interface-mappings/{id}/ |
Retrieve a single mapping |
| PUT | /port-profile-interface-mappings/{id}/ |
Full replacement update |
| PATCH | /port-profile-interface-mappings/{id}/ |
Partial update |
| DELETE | /port-profile-interface-mappings/{id}/ |
Delete |
API Query Parameters — Port Profiles
| Parameter | Type | Description |
|---|---|---|
q |
string | Free-text search across name and config-context names (icontains). Results deduplicated. |
name |
string | Case-insensitive contains match on profile name. |
config_context_id |
integer (repeatable) | Filter by Config Context PK. Repeat for OR semantics: ?config_context_id=1&config_context_id=2 |
config_context |
string (repeatable) | Filter by Config Context name (exact match). Repeat for OR. |
limit |
integer | Results per page (default 50, max 1000). |
offset |
integer | Results to skip for pagination. |
brief |
flag | Return {id, url, display, name} only — no nested relations. |
API Query Parameters — Interface Mappings
| Parameter | Type | Description |
|---|---|---|
q |
string | Free-text search across interface_name, port profile name, VLAN group name, VLAN names, and VLAN IDs (icontains). Results deduplicated. |
port_profile |
integer | Filter by Port Profile PK. |
interface_name |
string | Case-insensitive contains match on interface name. |
vlan_group_id |
integer (repeatable) | Filter by VLANGroup PK. Repeat for OR semantics. |
vlan_group |
string (repeatable) | Filter by VLANGroup name (exact match). Repeat for OR. |
vlan_id |
integer (repeatable) | Filter by VLAN PK. Repeat for OR semantics. |
vlan |
string (repeatable) | Filter by VLAN name (exact match). Repeat for OR. |
limit |
integer | Results per page (default 50, max 1000). |
offset |
integer | Results to skip for pagination. |
POST — Create a Port Profile
POST /api/plugins/ibm-netbox-plugins/port-profiles/
curl -X 'POST' \
'http://<netbox>/api/plugins/ibm-netbox-plugins/port-profiles/' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Token <your-token>' \
-d '{
"name": "dal10_sr01_nb_1",
"role_ids": [5, 12],
"tags": []
}'
Sample response — 201 Created
{
"id": 3,
"url": "http://<netbox>/api/plugins/ibm-netbox-plugins/port-profiles/3/",
"display_url": "http://<netbox>/plugins/ibm-netbox-plugins/port-profiles/3/",
"display": "dal10_sr01_nb_1",
"name": "dal10_sr01_nb_1",
"role": [
{
"id": 5,
"url": "http://<netbox>/api/extras/config-contexts/5/",
"display": "cos_lb",
"name": "cos_lb",
"description": "COS load-balancer context",
"is_active": true
},
{
"id": 12,
"url": "http://<netbox>/api/extras/config-contexts/12/",
"display": "ncs_testing_bgp",
"name": "ncs_testing_bgp",
"description": "",
"is_active": true
}
],
"interface_mappings": [],
"tags": [],
"custom_fields": {},
"created": "2026-09-02T06:00:00Z",
"last_updated": "2026-09-02T06:00:00Z"
}
GET — List Port Profiles
GET /api/plugins/ibm-netbox-plugins/port-profiles/?limit=1
curl -X 'GET' \
'http://<netbox>/api/plugins/ibm-netbox-plugins/port-profiles/?limit=1' \
-H 'accept: application/json' \
-H 'Authorization: Token <your-token>'
Sample response — 200 OK
{
"count": 12,
"next": "http://<netbox>/api/plugins/ibm-netbox-plugins/port-profiles/?limit=1&offset=1",
"previous": null,
"results": [
{
"id": 2,
"url": "http://<netbox>/api/plugins/ibm-netbox-plugins/port-profiles/2/",
"display_url": "http://<netbox>/plugins/ibm-netbox-plugins/port-profiles/2/",
"display": "dal09_sr09_nb_2",
"name": "dal09_sr09_nb_2",
"role": [
{
"id": 5,
"url": "http://<netbox>/api/extras/config-contexts/5/",
"display": "cos_lb",
"name": "cos_lb",
"description": "COS load-balancer context",
"is_active": true
}
],
"interface_mappings": [
{
"id": 5,
"interface_name": "int3",
"vrfs": [
{
"id": 1,
"url": "http://<netbox>/api/ipam/vrfs/1/",
"display": "mgmt",
"name": "mgmt",
"rd": "65000:1"
}
],
"vlan_group": {
"id": 3,
"url": "http://<netbox>/api/ipam/vlan-groups/3/",
"display": "DAL09-VLANs",
"name": "DAL09-VLANs"
},
"vlans": [
{
"id": 101,
"url": "http://<netbox>/api/ipam/vlans/101/",
"display": "101 (mgmt)",
"vid": 101,
"name": "mgmt"
}
]
}
],
"tags": [],
"custom_fields": {},
"created": "2026-08-28T04:55:00Z",
"last_updated": "2026-09-02T05:55:00Z"
}
]
}
GET — Retrieve a Port Profile
GET /api/plugins/ibm-netbox-plugins/port-profiles/{id}/
curl -X 'GET' \
'http://<netbox>/api/plugins/ibm-netbox-plugins/port-profiles/2/' \
-H 'accept: application/json' \
-H 'Authorization: Token <your-token>'
Returns the same object shape as a single item in the list response above.
PATCH — Update a Port Profile
Updates only the fields provided.
PATCH /api/plugins/ibm-netbox-plugins/port-profiles/{id}/
curl -X 'PATCH' \
'http://<netbox>/api/plugins/ibm-netbox-plugins/port-profiles/2/' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Token <your-token>' \
-d '{
"role_ids": [5, 7]
}'
Sample response — 200 OK
Returns the full updated port profile object.
PUT — Full Update
Replaces the full record. name is required.
PUT /api/plugins/ibm-netbox-plugins/port-profiles/{id}/
curl -X 'PUT' \
'http://<netbox>/api/plugins/ibm-netbox-plugins/port-profiles/2/' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Token <your-token>' \
-d '{
"name": "dal09_sr09_nb_2",
"role_ids": [5],
"tags": []
}'
DELETE — Remove a Port Profile
Permanently deletes the port profile and all of its Interface Mappings. Config Contexts are not affected.
DELETE /api/plugins/ibm-netbox-plugins/port-profiles/{id}/
curl -X 'DELETE' \
'http://<netbox>/api/plugins/ibm-netbox-plugins/port-profiles/2/' \
-H 'Authorization: Token <your-token>'
Response — 204 No Content (empty body on success).
POST — Create an Interface Mapping
POST /api/plugins/ibm-netbox-plugins/port-profile-interface-mappings/
curl -X 'POST' \
'http://<netbox>/api/plugins/ibm-netbox-plugins/port-profile-interface-mappings/' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Token <your-token>' \
-d '{
"port_profile": 2,
"interface_name": "eth0",
"vrfs": [1, 3],
"vlan_group_id": 3,
"vlan_ids": [101, 102]
}'
Sample response — 201 Created
{
"id": 7,
"interface_name": "eth0",
"vrfs": [
{
"id": 1,
"url": "http://<netbox>/api/ipam/vrfs/1/",
"display": "mgmt",
"name": "mgmt",
"rd": "65000:1"
},
{
"id": 3,
"url": "http://<netbox>/api/ipam/vrfs/3/",
"display": "prod",
"name": "prod",
"rd": "65000:3"
}
],
"vlan_group": {
"id": 3,
"url": "http://<netbox>/api/ipam/vlan-groups/3/",
"display": "DAL10-VLANs",
"name": "DAL10-VLANs"
},
"vlans": [
{
"id": 101,
"url": "http://<netbox>/api/ipam/vlans/101/",
"display": "101 (mgmt)",
"vid": 101,
"name": "mgmt"
},
{
"id": 102,
"url": "http://<netbox>/api/ipam/vlans/102/",
"display": "102 (storage)",
"vid": 102,
"name": "storage"
}
]
}
PATCH — Update an Interface Mapping
Updates only the fields provided. Use this to add, replace, or clear VLANs without touching other fields.
PATCH /api/plugins/ibm-netbox-plugins/port-profile-interface-mappings/{id}/
# Assign a VLAN group and replace the VLAN set
curl -X 'PATCH' \
'http://<netbox>/api/plugins/ibm-netbox-plugins/port-profile-interface-mappings/7/' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Token <your-token>' \
-d '{
"vlan_group_id": 4,
"vlan_ids": [110, 120]
}'
# Clear all VLANs and remove the VLAN group
curl -X 'PATCH' \
'http://<netbox>/api/plugins/ibm-netbox-plugins/port-profile-interface-mappings/7/' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Token <your-token>' \
-d '{
"vlan_group_id": null,
"vlan_ids": []
}'
Sample response — 200 OK
Returns the full updated interface mapping object.
Response Field Reference
Port Profile fields
| Field | Description |
|---|---|
role[] |
Array of Config Context objects. Each entry includes id, url, display, name, description, and is_active. Empty array means no roles assigned. |
role_ids |
Write-only. List of Config Context PKs. Replaces the full role set on every write. Send [] to clear all roles. |
interface_mappings[] |
Inline array of child mappings. Each entry has interface_name, vrfs[], vlan_group, and vlans[]. |
display_url |
Browser URL for the UI detail page. Use this to link to the port profile from external tooling. |
count |
Total matching records across all pages — not just the current page. |
next / previous |
Pagination cursor URLs. null when on the last or first page. Follow next sequentially or jump using ?offset=N&limit=M. |
Interface Mapping fields
| Field | Description |
|---|---|
vrfs[] |
Array of VRF objects. Each entry includes id, url, display, name, and rd. Empty array means no VRFs assigned. |
vrfs[].rd |
Route distinguisher of the VRF. May be null if not configured. |
vlan_group |
Nested VLANGroup object (id, url, display, name), or null when no group is assigned. |
vlan_group_id |
Write-only. VLANGroup PK. Send null to clear. |
vlans[] |
Array of VLAN objects. Each entry includes id, url, display, vid, and name. Empty array means no VLANs assigned. |
vlan_ids |
Write-only. List of VLAN PKs. Replaces the full VLAN set on every write. Send [] to clear all VLANs. |
Validation Messages
| Scenario | HTTP Status | Field | Message |
|---|---|---|---|
name already in use |
400 |
name |
port profile with this name already exists. |
name exceeds 100 characters |
400 |
name |
Ensure this field has no more than 100 characters. |
role_ids contains a non-existent Config Context PK |
400 |
role_ids |
Invalid pk "<id>" - object does not exist. |
vlan_group_id references a non-existent VLANGroup |
400 |
vlan_group_id |
Invalid pk "<id>" - object does not exist. |
vlan_ids contains a non-existent VLAN PK |
400 |
vlan_ids |
Invalid pk "<id>" - object does not exist. |
port_profile FK missing on Interface Mapping create |
400 |
port_profile |
This field is required. |
interface_name missing on Interface Mapping create |
400 |
interface_name |
This field is required. |
Performance Notes
The list and retrieve endpoints for Port Profiles use
prefetch_related('interface_mappings__vrfs', 'config_contexts', 'tags') — a fixed
number of queries regardless of result-set size.
The list and retrieve endpoints for Interface Mappings use
select_related('vlan_group') and prefetch_related('vlans') to avoid N+1 queries.
For large result sets use ?limit=100&offset=N pagination rather than fetching all records at once.