You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit e04e45c
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: docs/design-guide/neutron-networking.md
+43Lines changed: 43 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -499,6 +499,49 @@ Neutron based on certain data provided to port creation and update API calls.
499
499
- the port has a binding host
500
500
- the port is either unbound or has previously failed to bind
501
501
502
+
### Port Representations
503
+
504
+
Neutron exposes a port in three different shapes and you will see all of them
505
+
in the Neutron source and in our drivers:
506
+
507
+
| Representation | How you get it | Notes |
508
+
| -------------- | -------------- | ----- |
509
+
| Dict |`core_plugin.get_port()`, `PortContext.current`| API-shaped. Binding fields appear flattened as `binding:vif_type`, `binding:vnic_type`, `binding:host_id`, etc. |
510
+
| OVO |`neutron.objects.ports.Port.get_object()`| Typed versioned object. Bindings are in `port.bindings`, binding levels in `port.binding_levels`. |
511
+
| SQLAlchemy model |`payload.metadata["port_db"]`, `ml2.db.get_port()`| ML2 internal. Bindings are in `port.port_bindings`. Don't go looking for these; use them when Neutron hands one to you. |
512
+
513
+
Use the representation that matches where the port came from, and don't
514
+
re-fetch a port just to change its shape:
515
+
516
+
- If Neutron hands you a dict (`PortContext.current`) or a SQLAlchemy model
517
+
(for example `payload.metadata["port_db"]` in a registry callback), work with
518
+
that directly.
519
+
- When we have only a port ID, as with a trunk's parent port, fetch the **OVO**
520
+
with `utils.fetch_port_object()`. It is typed, and it is what Neutron's own
521
+
newer code uses when it needs binding details. We don't use `get_port()` for
522
+
this.
523
+
524
+
#### Selecting a binding
525
+
526
+
A port can have several bindings (one `ACTIVE`, any number of `INACTIVE` ones
527
+
during live migration), so never index with `port.bindings[0]`. Select the
528
+
binding with `get_port_binding_by_status_and_host()` from
529
+
`neutron_lib.plugins.utils`, then read `vif_type`, `vnic_type`, `profile` and
530
+
`host` from the result. For an OVO port, `utils.active_port_binding()` wraps
531
+
this and returns the `ACTIVE` binding, or `None` if there isn't one:
532
+
533
+
```python
534
+
binding = utils.active_port_binding(port)
535
+
if binding and binding.vnic_type == portbindings.VNIC_BAREMETAL:
536
+
...
537
+
```
538
+
539
+
For a SQLAlchemy model, call the neutron-lib helper directly with
540
+
`port.port_bindings` (the model's attribute name) instead of `port.bindings`.
541
+
The helper only subscripts each binding (`binding["status"]`,
542
+
`binding["host"]`), so it works on either. Pass `raise_if_not_found=True` to get
543
+
`PortBindingNotFound` instead of `None`.
544
+
502
545
### Router Interface Lifecycle
503
546
504
547
When a subnet is attached to a router, the understack ML2 driver sets up a path
0 commit comments