Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] OpenWrt: Added support for new bridge syntax #196 #222

Merged
merged 23 commits into from
Apr 11, 2022

Conversation

pandafy
Copy link
Member

@pandafy pandafy commented Mar 15, 2022

  • netjsonconfig renders and parses configuration for bridges
    in both old and new syntax.
  • Added STP and IGMP options in OpenWrt bridge interface schema

Closes #196

@pandafy pandafy marked this pull request as draft March 15, 2022 14:07
@coveralls
Copy link

coveralls commented Mar 15, 2022

Coverage Status

Coverage increased (+0.03%) to 99.629% when pulling 5f94e92 on issues/196-bridge-syntax into abc136b on master.

Copy link
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good progress!

I see that macaddr is missing, it also has to be added to the new bridge syntax because it's a layer 2 configuration.

Please also ensure the coverage does not decrease.

@pandafy pandafy force-pushed the issues/196-bridge-syntax branch 2 times, most recently from 495f0f8 to 511628f Compare March 15, 2022 18:37
Copy link
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@okraits @nickberry17 this is a delicate one.

We'll be testing it in the next 2 weeks, I suggest you to do the same.

@@ -595,6 +632,14 @@ Will be rendered as follows::
option ifname 'eth0.2'
option proto 'none'

config device 'device_lan_bridge'
option igmp_snooping '1'
option name 'lan_bridge'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the name should be br-lan_bridge. Let's simplify the example and call it just lan, so it will be called br-lan.

docs/source/backends/openwrt.rst Show resolved Hide resolved
@nemesifier nemesifier marked this pull request as ready for review March 16, 2022 23:58
Copy link
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great progress @pandafy!

Can you add a test for:

{
  "interfaces": [
    {
      "name": "wan",
      "type": "ethernet",
      "macaddr": "00:11:22:33:44:55",
      "addresses": [
        {
          "proto": "dhcp",
          "family": "ipv4"
        }
      ]
    }
  ]
}

Which should be translated to:

package network

config device 'device_wan'
      option name 'wan'
      option macaddr '00:11:22:33:44:55'

config interface 'wan'
	option ifname 'wan'
        option device 'wan'
	option macaddr '00:11:22:33:44:55'
	option proto 'dhcp'

We discussed this, that L2 options need to be defined like this also for non bridge interfaces. We need to do this because if the local OpenWrt config has the device definition OpenWISP won't be able to set the L2 options for that interface.

+=============================+=========+===========+=============================================================+
| ``bridge_members`` | list | ``[]`` | list of interface names for creating bridge |
+-----------------------------+---------+-----------+-------------------------------------------------------------+
| ``igmp_snooping`` | boolean | ``True`` | sets the ``multicast_snooping`` kernel setting for a bridge |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the default is wrong

+-----------------------------+---------+-----------+-------------------------------------------------------------+
| ``igmp_snooping`` | boolean | ``True`` | sets the ``multicast_snooping`` kernel setting for a bridge |
+-----------------------------+---------+-----------+-------------------------------------------------------------+
| ``multicast_querier`` | boolean | ``True`` | enables the bridge as a multicast querier |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the default is wrong

| | | | entries in the filtering DB" (range 10-1000000) |
+-----------------------------+---------+-----------+-------------------------------------------------------------+
| ``vlan_filtering`` | boolean | ``False`` | enables VLAN aware bridge mode |
+-----------------------------+---------+-----------+-------------------------------------------------------------+
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you forgot to add max_age

@@ -155,8 +155,123 @@
"description": "sets the \"multicast_snooping\" kernel setting for a bridge",
"default": True,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the default has been wrong since the start

Copy link
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fine, I'll do a bit more testing before merging.

Copy link
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have been testing the result on OpenWrt 21 and its interaction with LuCi, I found a weird issue.

LuCi always wants to migrate the conf, in doing so, it mistakenly create a duplicate device, eg:

# original
config device 'device_lan'            
        option ageing_time '600'      
        option forward_delay '4'               
        option hello_time '4'         
        option max_age '20'           
        option name 'br-lan'          
        option mtu '1500'             
        list ports 'lan1'             
        list ports 'lan2'             
        list ports 'wan'              
        option priority '4001'        
        option stp '1'                
        option type 'bridge'          
        option vlan_filtering '0'

# luci's duplicate
config device              
        option name 'br-lan' 
        option type 'bridge'      
        list ports 'lan1'                      
        list ports 'lan2'  
        list ports 'wan'     
        option mtu '1500'   

This means mainly one thing: if we deploy this as is we'll go through HELL and we will regret it greatly. Many users do use LuCi to manage their routers, so when they'll log in LuCi, LuCi will force this migration, creating dupes and this will potentially generate issues that are now impossible to foresee.

I have double checked that if we generate and send the new syntax only, this issue doens't happen, eg:

config device 'device_lan'
	option ageing_time '600'
	option forward_delay '4'
	option hello_time '4'
	option max_age '20'
	option mtu '1500'
	option name 'br-lan'
	list ports 'lan1'
	list ports 'lan2'
	list ports 'wan'
	option priority '4001'
	option stp '1'
	option type 'bridge'
	option vlan_filtering '0'

config interface 'lan'
	option auto '1'
	option device 'br-lan'
	option enabled '1'
	option ip6assign '60'
	option proto 'dhcp'

I have been exploring possible solutions.

I still think that creating a new backend for OpenWrt >= 21 is not good for us because maintaining the duplicated converters and docs doesn't justify the effort.

A possible solution is to add an attribute in the backend which tells the code whether it should work in OpenWrt 21 or greater mode or in legacy mode.
This would allow to avoid the double configuration which would cause issues on OpenWrt 21, moreover, we can avoid generating the new syntax on older systems which has the benefit to avoid touching them when we'll deploy the new version of this library, which is definitely a good thing.

We can default this attribute to be OpenWrt 21 or greater.
We can update the docs to show the OpenWrt 21 syntax only, we should mention the attribute which allows the library to work in legacy mode and suggest looking at the docs of previous stable versions of the library for a reference of the generated syntax pre OpenWrt 21.

In OpenWISP controller we have the operating system info of the device and therefore we are able to know whether a specific device is running openwrt >= 21 or not, therefore, if the OpenWrt backend is being used, when instantiating the it we can pass the right attribute according to the Device.os field.
Created issue: openwisp/openwisp-controller#618

In the legacy netjsonconfig.OpenWisp backend instead, this attribute must default to be the legacy option.

See also my comment below.

"description": "enables VLAN aware bridge mode",
"default": False,
"format": "checkbox",
"propertyOrder": 5,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my understanding is that vlan_filtering is used for defining VLANs in bridges, so it may make sense to add this when dealing with #195, therefore I think it can be removed here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codesankalp please address this request (also remove it from the docs please).

tests/openwrt/test_interfaces.py Outdated Show resolved Hide resolved
@codesankalp
Copy link
Member

Updated tests by keeping these points in mind (as mentioned in openwrt docs):

  • in config interface, option ifname has been renamed to device (since it refers to a device section)
  • in config device of type bridge, ifname has been renamed to ports
  • for new installs, the generated configuration now creates separate sections for layer 2 (config device) and layer 3 (config interface) configuration

tests/openwrt/test_interfaces_dsa.py Outdated Show resolved Hide resolved
@@ -1135,7 +1136,7 @@ def test_parse_l2_options_bridge(self):
{
"name": "wan",
"type": "ethernet",
"macaddr": "00:11:22:33:44:55",
"mac": "00:11:22:33:44:55",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes doesn't affect the new syntax.

config device 'device_custom_if0'
option name 'custom_if0'

config interface 'custom_if0'
option device '/dev/usb/modem1'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if two devices are present then only one is present in to_netjson_loop and i didn't edit the _get_uci_blocks function to pass devices in list because it will raise validation error according to schema.

https://forum.openwrt.org/t/interface-with-two-device-and-custom-proto-collides-in-openwrt-21-syntax/123539

"description": "enables VLAN aware bridge mode",
"default": False,
"format": "checkbox",
"propertyOrder": 5,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codesankalp please address this request (also remove it from the docs please).

@codesankalp codesankalp force-pushed the issues/196-bridge-syntax branch 2 times, most recently from 7bf4bf2 to 8f10232 Compare March 30, 2022 11:46
Copy link
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are testing it with openwisp/openwisp-controller#621.

@pandafy pandafy force-pushed the issues/196-bridge-syntax branch 2 times, most recently from 8e06988 to 0e6b8f9 Compare April 6, 2022 21:16
Copy link
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's some issues I found below, I will fix most of those except the seemingly mistaken test which I am puzzled why is giving that result, @codesankalp @pandafy any idea?

@@ -179,8 +179,11 @@ def test_parse_multiple_wifi(self):
}
_wifi_bridge_uci = """package network

config device 'device_eth0_1'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not look right.
There's a bridge here which does not generate the new device config type, why is that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous set_dsa method was changing the self.dsa property for the whole block. So when conversion was happening, self.dsa was False for bridge.
Fixed this in 5f94e92

netjsonconfig/backends/openwrt/converters/interfaces.py Outdated Show resolved Hide resolved
netjsonconfig/backends/openwrt/converters/interfaces.py Outdated Show resolved Hide resolved
netjsonconfig/backends/openwrt/converters/wireless.py Outdated Show resolved Hide resolved
"""
self.dsa = (
self.dsa_interface = (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to create new property instead of using it as a function because while parsing the proto or type can be popped which can give errors.

Copy link
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are ready.

@nemesifier nemesifier merged commit fbe5b8e into master Apr 11, 2022
@nemesifier nemesifier deleted the issues/196-bridge-syntax branch November 29, 2022 18:37
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.

[feature] Add support for new OpenWrt device and bridge syntax
4 participants