Skip to content

Conversation

@s3rj1k
Copy link

@s3rj1k s3rj1k commented Jan 20, 2026

Add support for converting OpenStack network_data.json "linux_bridge" link type to cloud-init network config v1 bridge type. This enables guest-side Linux bridge configuration through the OpenStack metadata service and config drive.

Related-To: https://review.opendev.org/c/openstack/nova/+/973924

@holmanb
Copy link
Member

holmanb commented Jan 21, 2026

Thanks for this @s3rj1k. Please include a sample network_data.json from the metadata service and a cloud-init.log and cloud-init-output.log from an instance that was booted using this code.

@holmanb holmanb added the incomplete Action required by submitter label Jan 21, 2026
@holmanb holmanb self-assigned this Jan 22, 2026
Add support for converting OpenStack network_data.json "linux_bridge"
link type to cloud-init network config v1 bridge type. This enables
guest-side Linux bridge configuration through the OpenStack metadata
service and config drive.

Related-To: https://review.opendev.org/c/openstack/nova/+/973924
@s3rj1k s3rj1k force-pushed the openstack-linux_bridge branch from f35cbc7 to 8dc4128 Compare January 27, 2026 20:41
@s3rj1k
Copy link
Author

s3rj1k commented Jan 27, 2026

Hey @holmanb, sorry for delay, so I test this PR manually like so: https://gist.github.com/s3rj1k/6e90f63e4084beff4b064e23c79169ad

network_data.json (also in guide above):

{
  "links": [
    {
      "id": "interface0",
      "name": "eth0",
      "type": "phy",
      "ethernet_mac_address": "52:54:00:12:34:02",
      "mtu": 1500
    },
    {
      "id": "bridge0",
      "name": "br0",
      "type": "linux_bridge",
      "ethernet_mac_address": "52:54:00:12:34:02",
      "bridge_links": ["interface0"]
    }
  ],
  "networks": [
    {
      "id": "network0",
      "type": "ipv4_dhcp",
      "link": "bridge0",
      "network_id": "da5bb487-5193-4a65-a3df-4a0055a8c0d7"
    }
  ],
  "services": [
    {
      "type": "dns",
      "address": "8.8.8.8"
    },
    {
      "type": "dns",
      "address": "8.8.4.4"
    }
  ]
}

Requested logs are attached.
cloud-init-output.log
cloud-init.log

From logs I see:

2026-01-27 21:05:17,415 - DataSourceConfigDrive.py[DEBUG]: network config provided via network_json
2026-01-27 21:05:17,417 - atomic_helper.py[DEBUG]: Atomically writing to file /var/lib/cloud/instance/network-config.json (via temporary file /var/lib/cloud/instance/tmp4e0mifni) - w: [600] 457 bytes/chars
2026-01-27 21:05:17,418 - util.py[DEBUG]: Creating symbolic link from '/run/cloud-init/network-config.json' => '/var/lib/cloud/instance/network-config.json'
2026-01-27 21:05:17,418 - util.py[DEBUG]: Reading from /usr/lib/python3/dist-packages/cloudinit/config/schemas/schema-network-config-v1.json (quiet=False)
2026-01-27 21:05:17,418 - util.py[DEBUG]: Reading 22494 bytes from /usr/lib/python3/dist-packages/cloudinit/config/schemas/schema-network-config-v1.json
2026-01-27 21:05:17,423 - schema.py[WARNING]: network-config-v1 failed schema validation! You may run 'sudo cloud-init schema --system' to check the details.
2026-01-27 21:05:17,424 - networking.py[DEBUG]: net: all expected physical devices present
2026-01-27 21:05:17,442 - stages.py[INFO]: Applying network configuration from ds bringup=False: {'version': 1, 'config': [{'name': 'eth0', 'type': 'physical', 'mtu': 1500, 'subnets': [], 'mac_address': '52:54:00:12:34:02'}, {'name': 'br0', 'type': 'bridge', 'subnets': [{'type': 'dhcp4'}], 'mac_address': '52:54:00:12:34:02', 'bridge_interfaces': ['eth0']}, {'type': 'nameserver', 'address': '8.8.8.8'}, {'type': 'nameserver', 'address': '8.8.4.4'}]}
2026-01-27 21:05:17,443 - util.py[DEBUG]: Writing to /run/cloud-init/sem/apply_network_config.once - wb: [644] 24 bytes

and network config as expected:

root@vm-openstack:/home/ubuntu# ip -d a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0  allmulti 0 minmtu 0 maxmtu 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 tso_max_size 524280 tso_max_segs 65535 gro_max_size 65536
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host noprefixroute
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UP group default qlen 1000
    link/ether 52:54:00:12:34:02 brd ff:ff:ff:ff:ff:ff promiscuity 1  allmulti 1 minmtu 68 maxmtu 65535
    bridge_slave state forwarding priority 32 cost 100 hairpin off guard off root_block off fastleave off learning on flood on port_id 0x8001 port_no 0x1 designated_port 32769 designated_cost 0 designated_bridge 8000.52:54:0:12:34:2 designated_root 8000.52:54:0:12:34:2 hold_timer    0.00 message_age_timer    0.00 forward_delay_timer    0.00 topology_change_ack 0 config_pending 0 proxy_arp off proxy_arp_wifi off mcast_router 1 mcast_fast_leave off mcast_flood on bcast_flood on mcast_to_unicast off neigh_suppress off group_fwd_mask 0 group_fwd_mask_str 0x0 vlan_tunnel off isolated off locked off numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 tso_max_size 65536 tso_max_segs 65535 gro_max_size 65536 parentbus virtio parentdev virtio0
3: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 52:54:00:12:34:02 brd ff:ff:ff:ff:ff:ff promiscuity 0  allmulti 0 minmtu 68 maxmtu 65535
    bridge forward_delay 1500 hello_time 200 max_age 2000 ageing_time 30000 stp_state 0 priority 32768 vlan_filtering 0 vlan_protocol 802.1Q bridge_id 8000.52:54:0:12:34:2 designated_root 8000.52:54:0:12:34:2 root_port 0 root_path_cost 0 topology_change 0 topology_change_detected 0 hello_timer    0.00 tcn_timer    0.00 topology_change_timer    0.00 gc_timer   68.32 vlan_default_pvid 1 vlan_stats_enabled 0 vlan_stats_per_port 0 group_fwd_mask 0 group_address 01:80:c2:00:00:00 mcast_snooping 1 no_linklocal_learn 0 mcast_vlan_snooping 0 mcast_router 1 mcast_query_use_ifaddr 0 mcast_querier 0 mcast_hash_elasticity 16 mcast_hash_max 4096 mcast_last_member_count 2 mcast_startup_query_count 2 mcast_last_member_interval 100 mcast_membership_interval 26000 mcast_querier_interval 25500 mcast_query_interval 12500 mcast_query_response_interval 1000 mcast_startup_query_interval 3125 mcast_stats_enabled 0 mcast_igmp_version 2 mcast_mld_version 1 nf_call_iptables 0 nf_call_ip6tables 0 nf_call_arptables 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535 tso_max_size 65536 tso_max_segs 65535 gro_max_size 65536
    inet 192.168.122.245/24 metric 100 brd 192.168.122.255 scope global dynamic br0
       valid_lft 2852sec preferred_lft 2852sec
    inet6 fe80::5054:ff:fe12:3402/64 scope link
       valid_lft forever preferred_lft forever

@s3rj1k
Copy link
Author

s3rj1k commented Jan 28, 2026

hmm, email does not match with CLA?

@s3rj1k
Copy link
Author

s3rj1k commented Feb 9, 2026

@holmanb just wondering if we can remove "incomplete" label for this or am I still missing something?

@holmanb holmanb removed the incomplete Action required by submitter label Feb 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants