openwisp / netjsonconfig

Network configuration management library based on NetJSON DeviceConfiguration
https://netjsonconfig.openwisp.org/
Other
359 stars 71 forks source link

[feature] Added support for DSA #195 #261

Open pandafy opened 1 year ago

pandafy commented 1 year ago

Closes #195

coveralls commented 1 year ago

Coverage Status

coverage: 99.522% (+0.03%) from 99.497% when pulling 553af7bbf4a89f80160cf1e28c365ac7ff2d8dcd on issues/195-dsa-switch into 9b2c2146a785564e096f6299e08a568fccfed01b on master.

pandafy commented 1 year ago

In the last review with @nemesisdesign, we discussed the following things:

NetJSON

{
    "interfaces": [
        {
            "type": "8021q",
            "name": "eth0",
            "mtu": 1500,
            "vid": 1
        }
    ]
}

UCI

package network

config device 'device_eth0_1'
    option ifname 'eth0'
    option mtu '1500'
    option name 'eth0.1'
    option type '8021q'
    option vid '1'

config interface 'vlan1'
    option device 'eth0.1'
    option ifname 'vlan1'
    option proto 'none'

NetJSON

{
    "interfaces": [
        {
            "type": "bridge",
            "stp": false,
            "bridge_members": [
                "eth0",
                "eth1"
            ],
            "name": "br-lan",
            "mtu": 1500,
            "disabled": false,
            "network": "",
            "mac": "",
            "vlan_filtering": [
                {
                    "vlan": 1,
                    "ports": [
                        {
                            "ifname": "eth0", 
                            "tagging": "t",
                        },
                        {
                            "ifname": "eth1",
                            "tagging": "u"
                        }
                    ]
                }
            ]
        }
    ]
}

UCI

package network

config device 'device_br_lan'
    option mtu '1500'
    option name 'br-lan'
    list ports 'eth0'
    list ports 'eth1'
    option stp '0'
    option type 'bridge'
    option vlan_filtering '1'

config bridge-vlan 'vlan_br_lan_1'
    option device 'br-lan'
    list ports 'eth0:t'
    list ports 'eth1:u'
    option vlan '1'

config interface 'br_lan'
    option device 'br-lan'
    option enabled '1'
    option proto 'none'

config interface 'vlan1'
    option device 'br-lan.1'
    option proto 'none'
pandafy commented 1 year ago

In the last review with @nemesisdesign, we concluded the following:

We will not add a special interface type "Bridge VLAN Interface" in the schema because this locks down the granularity offered by OpenWrt. Instead, we will direct the users to create interfaces using the existing interface types (Network Interface, Dialup Interface. etc.). If the interface names contains a period (.), e.g.br-lan.1, the code will check if a bridge namedbr-lanis defined in the configuration with a VLAN1. If it is present, then the interface configuration will be updated to add thedevice` option.

codingHahn commented 1 year ago

While testing I found an error while configuring vlans in bridges. If I create a template where vlan-interface lan.1234 is inside a bridge called br-guest, it works. If I then clone that template where I change lan.1234 to br-lan.1234 and remove the first template and apply the second, the network hangs and the configuration fails to apply. Here are both advanced jsons:

Config with lan.1234 inside bridge

{
    "interfaces": [
        {
            "type": "8021q",
            "name": "lan",
            "mtu": 1500,
            "disabled": false,
            "network": "",
            "mac": "",
            "autostart": true,
            "addresses": [],
            "vid": 1234,
            "ingress_qos_mapping": [],
            "egress_qos_mapping": []
        },
        {
            "type": "bridge",
            "stp": false,
            "bridge_members": [
                "lan.1234"
            ],
            "name": "br-guest",
            "mtu": 1500,
            "disabled": false,
            "network": "",
            "mac": "",
            "autostart": true,
            "addresses": [],
            "igmp_snooping": false,
            "multicast_querier": false,
            "query_interval": 12500,
            "query_response_interval": 1000,
            "last_member_interval": 100,
            "hash_max": 512,
            "robustness": 2,
            "forward_delay": 4,
            "hello_time": 2,
            "priority": 32767,
            "ageing_time": 300,
            "max_age": 20,
            "vlan_filtering": []
        }
    ]
}

Config with br-lan.1234 in bridge:

{
    "interfaces": [
        {
            "type": "8021q",
            "name": "br-lan",
            "mtu": 1500,
            "disabled": false,
            "network": "",
            "mac": "",
            "autostart": true,
            "addresses": [],
            "vid": 1234,
            "ingress_qos_mapping": [],
            "egress_qos_mapping": []
        },
        {
            "type": "bridge",
            "stp": false,
            "bridge_members": [
                "br-lan.1234"
            ],
            "name": "br-guest",
            "mtu": 1500,
            "disabled": false,
            "network": "",
            "mac": "",
            "autostart": true,
            "addresses": [],
            "igmp_snooping": false,
            "multicast_querier": false,
            "query_interval": 12500,
            "query_response_interval": 1000,
            "last_member_interval": 100,
            "hash_max": 512,
            "robustness": 2,
            "forward_delay": 4,
            "hello_time": 2,
            "priority": 32767,
            "ageing_time": 300,
            "max_age": 20,
            "vlan_filtering": []
        }
    ]
}

Used antenna: Ubiquiti UniFi 6 Lite

Steps to reproduce:

  1. Apply first config
  2. Wait for successful apply
  3. Deselct first config and select second config, then hit save
  4. Watch as config fails to apply

After deselecting config 2 in openwisp and hitting save, the config 1 is still present on the antenna in uci show network as well as /etc/config/network. Even a restart of the openwisp_config service does not reset the config to the state wanted by the server.

I suspect as both lan and br-lan reference the same physical interface, it fails at registering the vid for both interfaces.

The logread during that time is here: logread_vlan_bridge_bug.txt

pandafy commented 1 year ago

@codingHahn I tried to replicate the locally of the configuration that you provided in your example were applied successfully on my router. My router has OpenWrt 22.03.3.

I have shared the output of logread from applying both configuration on hastebin.

My router does not have any lan device, therefore no bridge was shown in brctl show command after applying the first configuration. But, after applying the second config, the br-guest bridge came up.

codingHahn commented 1 year ago

@pandafy Does it also work for you if you use a device with only one physical ethernet port?

pandafy commented 1 year ago

@codingHahn are you able to get the desired results from LuCI? If so, can you share the UCI configuration generated by LuCI?

zagi-tng commented 1 year ago

@pandafy Does it also work for you if you use a device with only one physical ethernet port?

In my case i have eth0 as br-lan member (untagged vlan) and other lans (iot, guest, ...) as separate bridges with eth0.X vlans as members.

codingHahn commented 1 year ago

@pandafy applying the both configs manually works (both configs work standalone, but when switching configs using OpenWISP, the device's config is left in a corrupted state). It breaks when following the steps outlined in my comment.

nemesifier commented 1 month ago

I've been using this successfully on a couple of deployments. @codingHahn @zagi-tng thanks for your comments, @pandafy asked if you had an example of successful configuration applied via LuCi (the OpenWrt web interface) or manually so we could compare that with the result we get from our code and check if there's any difference.