From fd894e7cb7bfaf695f6dccc996478589f162d38b Mon Sep 17 00:00:00 2001 From: Mohd Mehdi Date: Tue, 9 Apr 2024 07:28:52 +0000 Subject: [PATCH] Re-implement GRE object --- docs/guide/libbbfdm_GRE.md | 158 +++++ libbbfdm/dmlayer.c | 35 ++ libbbfdm/dmlayer.h | 3 + libbbfdm/dmtree/tr181/gre.c | 761 ++++++++++++++++++++----- libbbfdm/dmtree/tr181/interfacestack.c | 45 +- libbbfdm/dmtree/tr181/ip.c | 24 +- libbbfdm/dmtree/tr181/routing.c | 3 +- 7 files changed, 860 insertions(+), 169 deletions(-) create mode 100644 docs/guide/libbbfdm_GRE.md diff --git a/docs/guide/libbbfdm_GRE.md b/docs/guide/libbbfdm_GRE.md new file mode 100644 index 00000000..fdbed3ce --- /dev/null +++ b/docs/guide/libbbfdm_GRE.md @@ -0,0 +1,158 @@ +# TR181 GRE datamodel + +Aim of this document is to explain how the Device.GRE.Tunnel.{i}. and Device.GRE.Tunnel.{i}.Interface.{i}. datamodel objects are mapped to network UCI. + +As per the definition in TR-181: + +- Device.GRE.Tunnel.{i}. allows configuration of a tunnel with respect to a certain remote IP Address. +- Device.GRE.Tunnel.{i}.Interface.{i}. allows configuration of a tunnel interface, which will have to be LowerLayer of a Device.IP.Interface.{i}. object. + +## Configuration +A tunnel can be set up in five broad steps: +- Add a Device.GRE.Tunnel. object. +- Set its Device.GRE.Tunnel.{i}.RemoteEndpoints parameter. +- Add a Device.GRE.Tunnel.{i}.Interface. object. +- Set Device.GRE.Tunnel.{i}.Interface.{i}.LowerLayers to the interface with whose address we want to bind this tunnel (default is wan). +- Set up a Device.IP.Interface object. +- Set appropriate Device.IP.Interface.{i}.LowerLayers to point to above added Device.GRE.Tunnel.{i}.Interface. object. + +Please compare the data model values with *ip addr* state below for a clearer picture. + +### Example data model configuration + +```bash +# add IP.Interface +obuspa -c add Device.IP.Interface. +obuspa -c add Device.IP.Interface.3.IPv4Address. +obuspa -c set Device.IP.Interface.3.IPv4Address.1.IPAddress 172.17.0.5 +obuspa -c set Device.IP.Interface.3.IPv4Address.1.SubnetMask 255.255.255.0 +obuspa -c set Device.IP.Interface.3.IPv4Address.1.Enable 1 +obuspa -c set Device.IP.Interface.3.Enable 1 + +# add GRE. +obuspa -c add Device.GRE.Tunnel. +obuspa -c set Device.GRE.Tunnel.1.RemoteEndpoints 10.101.52.1 +obuspa -c add Device.GRE.Tunnel.1.Interface. +obuspa -c set Device.GRE.Tunnel.1.Interface.1.LowerLayers Device.IP.Interface.2. + +# set IP.Interface LowerLayer +obuspa -c set Device.IP.Interface.3.LowerLayers Device.GRE.Tunnel.1.Interface.1. + +``` + +after the above config, the object should should look as follows: + +```bash +root@iopsys:~# obuspa -c get Device.GRE. +Device.GRE.TunnelNumberOfEntries => 1 +Device.GRE.Tunnel.1.Enable => 1 +Device.GRE.Tunnel.1.Status => Enabled +Device.GRE.Tunnel.1.Alias => cpe-1 +Device.GRE.Tunnel.1.RemoteEndpoints => 10.101.52.1 +Device.GRE.Tunnel.1.DeliveryHeaderProtocol => IPv4 +Device.GRE.Tunnel.1.ConnectedRemoteEndpoint => 10.101.52.1 +Device.GRE.Tunnel.1.InterfaceNumberOfEntries => 1 +Device.GRE.Tunnel.1.Interface.1.Enable => 1 +Device.GRE.Tunnel.1.Interface.1.Status => Unknown +Device.GRE.Tunnel.1.Interface.1.Alias => cpe-1 +Device.GRE.Tunnel.1.Interface.1.Name => gre_d1i1 +Device.GRE.Tunnel.1.Interface.1.LastChange => 227 +Device.GRE.Tunnel.1.Interface.1.LowerLayers => Device.IP.Interface.2 +Device.GRE.Tunnel.1.Interface.1.UseChecksum => 0 +Device.GRE.Tunnel.1.Interface.1.UseSequenceNumber => 0 +Device.GRE.Tunnel.1.Interface.1.Stats.BytesSent => 84 +Device.GRE.Tunnel.1.Interface.1.Stats.BytesReceived => 84 +Device.GRE.Tunnel.1.Interface.1.Stats.PacketsSent => 1 +Device.GRE.Tunnel.1.Interface.1.Stats.PacketsReceived => 1 +Device.GRE.Tunnel.1.Interface.1.Stats.ErrorsSent => 0 +Device.GRE.Tunnel.1.Interface.1.Stats.ErrorsReceived => 0 +``` + +```bash +root@iopsys:~# obuspa -c get Device.IP.Interface.3. +Device.IP.Interface.3.Enable => 1 +Device.IP.Interface.3.IPv6Enable => 1 +Device.IP.Interface.3.ULAEnable => 1 +Device.IP.Interface.3.Status => Down +Device.IP.Interface.3.Alias => cpe-3 +Device.IP.Interface.3.Name => iface3 +Device.IP.Interface.3.LastChange => 0 +Device.IP.Interface.3.LowerLayers => Device.GRE.Tunnel.1.Interface.1 +Device.IP.Interface.3.Router => Device.Routing.Router.1 +Device.IP.Interface.3.Reset => 0 +Device.IP.Interface.3.MaxMTUSize => 1500 +Device.IP.Interface.3.Type => Normal +Device.IP.Interface.3.Loopback => 0 +Device.IP.Interface.3.IPv4AddressNumberOfEntries => 1 +Device.IP.Interface.3.IPv6AddressNumberOfEntries => 0 +Device.IP.Interface.3.IPv6PrefixNumberOfEntries => 0 +Device.IP.Interface.3.IPv4Address.1.Enable => 1 +Device.IP.Interface.3.IPv4Address.1.Status => Enabled +Device.IP.Interface.3.IPv4Address.1.Alias => cpe-1 +Device.IP.Interface.3.IPv4Address.1.IPAddress => 172.17.0.5 +Device.IP.Interface.3.IPv4Address.1.SubnetMask => 255.255.255.0 +Device.IP.Interface.3.IPv4Address.1.AddressingType => Static +Device.IP.Interface.3.Stats.BytesSent => 0 +Device.IP.Interface.3.Stats.BytesReceived => 0 +Device.IP.Interface.3.Stats.PacketsSent => 0 +Device.IP.Interface.3.Stats.PacketsReceived => 0 +Device.IP.Interface.3.Stats.ErrorsSent => 0 +Device.IP.Interface.3.Stats.ErrorsReceived => 0 +Device.IP.Interface.3.Stats.DiscardPacketsSent => 0 +Device.IP.Interface.3.Stats.DiscardPacketsReceived => 0 +Device.IP.Interface.3.Stats.MulticastPacketsReceived => 0 +``` + +NOTE: The status might be down for *Device.IP.Interface.3.Status* but the IP will be assigned properly in ifconfig output. + +```bash +gre4-gre_d1i1 Link encap:UNSPEC HWaddr 0A-65-34-64-00-00-00-00-00-00-00-00-00-00-00-00 + inet addr:172.17.0.5 P-t-P:172.17.0.5 Mask:255.255.255.0 + inet6 addr: fe80::5efe:a65:3464/64 Scope:Link + UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1280 Metric:1 + RX packets:1 errors:0 dropped:0 overruns:0 frame:0 + TX packets:1 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:1000 + RX bytes:84 (84.0 B) TX bytes:84 (84.0 B) +``` + +## Network UCI with added new section for GRE Tunnel + +```bash +config device 'gre_dev_1' + option name 'gre_dev_1' + option type 'tunnel' + option mode 'greip' + option remote '10.101.52.1' + +config interface 'gre_d1i1' + option proto 'gre' + option device 'gre_dev_1' + option disabled '0' + option tunlink 'wan' + option peeraddr '10.101.52.1' + +config interface 'gre_ll_1' + option proto 'static' + option ipaddr '172.17.0.5' + option netmask '255.255.255.0' + option device 'gre4-gre_d1i1' + +``` + +### IP addr state + +```bash +23: gre4-gre_d1i1@eth0: mtu 1280 qdisc noqueue state UNKNOWN group default qlen 1000 + link/gre 10.101.52.100 peer 10.101.52.1 + inet 172.17.0.5/24 brd 172.17.0.255 scope global gre4-gre_d1i1 + valid_lft forever preferred_lft forever + inet6 fe80::5efe:c0a8:101/64 scope link + valid_lft forever preferred_lft forever +``` + +## Limitations +- Current system expects one to one mapping between Device.Tunnel.{i}. and Device.Tunnel.{i}.Interface and Device.IP.Interface.{i}.LowerLayer at a time, that is, +at the moment, we can only functionally support single value in Device.GRE.Tunnel.1.Interface.1.LowerLayers and not comma separated list of values. +- When Device.IP.Interface.{i}.LowerLayer is set to Device.GRE.Tunnel.{i}.Interface.{i}., the system finds the Linux generated tunnel name for the Tunnel and sets it to option device in the Device.IP.Interface.{i}. interface section, this is to avoid using "@" notation of referring to interfaces, which causes problems in processing of interfaces in the data model implementation. +- The lowerlayer of the GRE.Tunnel.Interface object maps to option tunlink in the UCI. If not specified, openwrt by default picks wan interface as tunlink. That means if you have a config interface 'wan' section in your UCI, then the IP.Interface object corresponding to this will automatically become the lowerlayer of Tunnel.Interface object. It is strongly recommended that you do not rely on this however, and for clarity, always specify the value of Tunnel.Interface.Lowerlayer parameter, even though, functionally, your tunnel may even be setup if you leave it as blank provided a config interface wan section exists in your network UCI. In such a scenario, even though you have left the Lowerlayer value as blank, the "wan" interface will be used internally as the default value for option tunlink. diff --git a/libbbfdm/dmlayer.c b/libbbfdm/dmlayer.c index 47782332..4b149a82 100644 --- a/libbbfdm/dmlayer.c +++ b/libbbfdm/dmlayer.c @@ -69,6 +69,41 @@ void firewall__create_zone_section(char *s_name) dmuci_add_list_value_by_section(s, "network", s_name); } +/* get the name that linux generates based on ifname of tunnel */ +void gre___get_tunnel_system_name(struct uci_section *iface_section, char *device_str, size_t device_str_size) +{ + char *proto = NULL; + + if (!iface_section || !device_str_size || !device_str_size) + return; + + dmuci_get_value_by_section_string(iface_section, "proto", &proto); + + // to generate appropriate device name + if (proto && !DM_LSTRCMP(proto, "grev6")) { + snprintf(device_str, device_str_size, "gre6-%s", section_name(iface_section)); + } else { + snprintf(device_str, device_str_size, "gre4-%s", section_name(iface_section)); + } +} + +bool ip___is_gre_protocols(const char *proto) +{ + if (!DM_LSTRCMP(proto, "gre")) + return true; + + if (!DM_LSTRCMP(proto, "grev6")) + return true; + + if (!DM_LSTRCMP(proto, "gretap")) + return true; + + if (!DM_LSTRCMP(proto, "grev6tap")) + return true; + + return false; +} + bool ip___is_ip_interface_instance_exists(const char *sec_name, const char *device) { struct uci_section *s = NULL; diff --git a/libbbfdm/dmlayer.h b/libbbfdm/dmlayer.h index a3bbae3f..ec002323 100644 --- a/libbbfdm/dmlayer.h +++ b/libbbfdm/dmlayer.h @@ -14,6 +14,9 @@ #include "libbbfdm-api/dmcommon.h" +void gre___get_tunnel_system_name(struct uci_section *iface_section, char *device_str, size_t device_str_size); + +bool ip___is_gre_protocols(const char *proto); bool ip___is_ip_interface_instance_exists(const char *sec_name, const char *device); void ip___update_child_interfaces(char *device, char *option_name, char *option_value); diff --git a/libbbfdm/dmtree/tr181/gre.c b/libbbfdm/dmtree/tr181/gre.c index daa919bd..0121f20d 100644 --- a/libbbfdm/dmtree/tr181/gre.c +++ b/libbbfdm/dmtree/tr181/gre.c @@ -1,28 +1,208 @@ /* - * Copyright (C) 2019 iopsys Software Solutions AB + * Copyright (C) 2024 iopsys Software Solutions AB * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation * * Author: Omar Kallel + * Author: Mohd Husaam Mehdi */ #include "gre.h" +#include "dmlayer.h" +/************************************************************* +* UTILITY METHODS +**************************************************************/ +/* wrapper to avoid long lines */ +static char *get_tunnel_name(struct uci_section *tunnel_section) +{ + return dmuci_get_value_by_section_fallback_def(tunnel_section, "name", ""); +} + + +/* different family tunnels have different option proto */ +static char *get_tunnel_dev_proto_family(struct uci_section *tunnel_section) +{ + if (!tunnel_section) { + return ""; + } + + char *tunnel_dev_mode = dmuci_get_value_by_section_fallback_def(tunnel_section, "mode", ""); + + if (!DM_LSTRCMP(tunnel_dev_mode, "greip6")) { + return "grev6"; + } else { + return "gre"; + } +} + +/* delete sections from both main UCI and dmmap UCI */ +static void delete_all_sections_with_opt_eq(char *package, char *section_type, char *option, char *value) +{ + struct uci_section *s = NULL, *stmp = NULL, *dmmap_section = NULL; + + if (!package || !section_type || !option || !value) { + return; + } + + uci_foreach_option_eq_safe(package, section_type, option, value, stmp, s) { + dmmap_section = NULL; + + get_dmmap_section_of_config_section("dmmap_gre", section_type, section_name(s), &dmmap_section); + + dmuci_delete_by_section(dmmap_section, NULL, NULL); + dmuci_delete_by_section(s, NULL, NULL); + } +} + +/* set value in all sections in main UCI */ +static void set_all_sections_with_opt_eq(char *package, char *section_type, char *option, char *value, char *set_option, char *set_value) +{ + struct uci_section *s = NULL; + + if (!package || !section_type || !option || !value || !set_option || !set_value) { + return; + } + + uci_foreach_option_eq(package, section_type, option, value, s) { + // do not remove device of interface section + if (!DM_LSTRCMP(set_option, "device") && !DM_LSTRCMP(set_value, "")) { + dmuci_set_value_by_section(s, set_option, section_name(s)); + } else { + dmuci_set_value_by_section(s, set_option, set_value); + } + } +} + +/* update interface sections corresponding to Tunnel.Interface.LowerLayer, as changed proto leads to changed dev name*/ +static void update_all_interface_upper_layers(char *tunnel_dev_name, bool is_current_ipv6) +{ + struct uci_section *s = NULL, *s_lower = NULL; + + if (!tunnel_dev_name || !DM_STRLEN(tunnel_dev_name)) { + return; + } + + // for all interfaces that have this tunnel_dev + uci_foreach_option_eq("network", "interface", "device", tunnel_dev_name, s) { + s_lower = NULL; + // get the interface name + char *if_section_name = section_name(s); + char current_lower_layer_device[32] = {0}; + char new_lower_layer_device[32] = {0}; + + if (is_current_ipv6) { + snprintf(current_lower_layer_device, sizeof(current_lower_layer_device), "gre6-%s", if_section_name); + snprintf(new_lower_layer_device, sizeof(new_lower_layer_device), "gre4-%s", if_section_name); + } else { + snprintf(current_lower_layer_device, sizeof(current_lower_layer_device), "gre4-%s", if_section_name); + snprintf(new_lower_layer_device, sizeof(new_lower_layer_device), "gre6-%s", if_section_name); + } + + // for all interfaces that have device set to the name generated from current tunnel.interface + uci_foreach_option_eq("network", "interface", "device", current_lower_layer_device, s_lower) { + // update device + dmuci_set_value_by_section(s_lower, "device", new_lower_layer_device); + } + } +} + +static char *get_gre_tunnel_interface_statistics(json_object *json_stats, char *key) +{ + char *value = NULL; + if (!json_stats || !key) { + return "0"; + } + + value = dmjson_get_value(json_stats, 2, "statistics", key); + return value ? value : "0"; +} + +/* remove device section of interface sections corresponding to lowerlayer */ +static void empty_all_upper_layers_of_interface(struct uci_section *iface_section) +{ + char tunnel_system_name[32] = {0}; + + if (!iface_section) + return; + + gre___get_tunnel_system_name(iface_section, &tunnel_system_name[0], sizeof(tunnel_system_name)); + + // remove tunnel system name from option device of the interface section of lower layers + // otherwise tunnel interface is not removed from the system + set_all_sections_with_opt_eq("network", "interface", "device", tunnel_system_name, "device", ""); +} + +static void remove_all_interfaces_of_tunnel(char *tunnel_dev_name) +{ + if (!tunnel_dev_name || !DM_STRLEN(tunnel_dev_name)) { + return; + } + + struct uci_section *s = NULL; + + // for all interfaces of this tunnel + uci_foreach_option_eq("network", "interface", "device", tunnel_dev_name, s) { + empty_all_upper_layers_of_interface(s); + } + + // delete all sections corresponding to tunnel.interface + delete_all_sections_with_opt_eq("network", "interface", "device", tunnel_dev_name); +} + +static void remove_tunnel(struct uci_section *tunnel_section, struct uci_section *tunnel_dmmap_section) +{ + if (!tunnel_section) + return; + + char *tunnel_dev_name = NULL; + + tunnel_dev_name = dmuci_get_value_by_section_fallback_def(tunnel_section, "name", ""); + + // delete all sections corresponding to Tunnel.Interface + remove_all_interfaces_of_tunnel(tunnel_dev_name); + + // remove the tunnel dmmap section + if (tunnel_dmmap_section == NULL) { + struct uci_section *dmmap_section = NULL; + get_dmmap_section_of_config_section("dmmap_gre", "interface", section_name(tunnel_section), &dmmap_section); + dmuci_delete_by_section(dmmap_section, NULL, NULL); + } else { + dmuci_delete_by_section(tunnel_dmmap_section, NULL, NULL); + } + + // remove tunnel network UCI section + dmuci_delete_by_section(tunnel_section, NULL, NULL); +} + +static void remove_all_tunnels(void) +{ + struct uci_section *s = NULL, *stmp = NULL; + + uci_foreach_option_eq_safe("network", "device", "mode", "greip", stmp, s) { + remove_tunnel(s, NULL); + } + + s = NULL, stmp = NULL; + uci_foreach_option_eq_safe("network", "device", "mode", "greip6", stmp, s) { + remove_tunnel(s, NULL); + } +} /************************************************************* * ENTRY METHOD *************************************************************/ static int browseGRETunnelInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) { + char *inst = NULL; struct dm_data *curr_data = NULL; LIST_HEAD(dup_list); - char *inst = NULL; - synchronize_specific_config_sections_with_dmmap_eq("network", "interface", "dmmap_network", "proto", "gre", &dup_list); + synchronize_specific_config_sections_with_dmmap_cont("network", "device", "dmmap_gre", "mode", "greip", &dup_list); list_for_each_entry(curr_data, &dup_list, list) { - inst = handle_instance(dmctx, parent_node, curr_data->dmmap_section, "gretunnel_instance", "gretunnel_alias"); + inst = handle_instance(dmctx, parent_node, curr_data->dmmap_section, "gre_tunnel_instance", "gre_tunnel_alias"); if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)curr_data, inst) == DM_STOP) break; @@ -31,37 +211,47 @@ static int browseGRETunnelInst(struct dmctx *dmctx, DMNODE *parent_node, void *p return 0; } -static struct uci_section *has_tunnel_interface_route(char *interface) -{ - struct uci_section *s = NULL; - - uci_foreach_option_eq("network", "route", "interface", interface, s) { - return s; - } - return NULL; -} - static int browseGRETunnelInterfaceInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev_data, char *prev_instance) { - char *inst = NULL, device[128] = {0}; + json_object *res = NULL; + char *inst = NULL; struct dm_data *curr_data = NULL; + char *tunnel_dev_name = NULL; + char *tunnel_instance = NULL; LIST_HEAD(dup_list); - snprintf(device, sizeof(device), "@%s", section_name(((struct dm_data *)prev_data)->config_section)); + tunnel_dev_name = dmuci_get_value_by_section_fallback_def(((struct dm_data *)prev_data)->config_section, "name", ""); + if (!DM_STRLEN(tunnel_dev_name)) + return 0; - synchronize_specific_config_sections_with_dmmap_eq("network", "interface", "dmmap_network", "device", device, &dup_list); + tunnel_instance = dmuci_get_value_by_section_fallback_def(((struct dm_data *)prev_data)->dmmap_section, "gre_tunnel_instance", ""); + + dmubus_call("network.device", "status", UBUS_ARGS{0}, 0, &res); + + synchronize_specific_config_sections_with_dmmap_eq("network", "interface", "dmmap_gre", "device", tunnel_dev_name, &dup_list); list_for_each_entry(curr_data, &dup_list, list) { - struct uci_section *s = NULL; + // get system name for this interface + char tunnel_system_name[32] = {0}; + gre___get_tunnel_system_name(curr_data->config_section, &tunnel_system_name[0], sizeof(tunnel_system_name)); - if ((s = has_tunnel_interface_route(section_name(curr_data->config_section))) == NULL) - continue; + // loop over all objects of network.device status + json_object_object_foreach(res, key, val) { + if (DM_LSTRCMP(key, tunnel_system_name) == 0) { + curr_data->json_object = json_object_get(val); + break; + } + } - inst = handle_instance(dmctx, parent_node, curr_data->dmmap_section, "greiface_instance", "greiface_alias"); + // set tunnel instance in dmmap gre interface section, needed for interfacestack + dmuci_set_value_by_section(curr_data->dmmap_section, "tunnel_instance", tunnel_instance); + + inst = handle_instance(dmctx, parent_node, curr_data->dmmap_section, "gre_iface_instance", "gre_iface_alias"); if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)curr_data, inst) == DM_STOP) break; } free_dmmap_config_dup_list(&dup_list); + return 0; } @@ -70,37 +260,31 @@ static int browseGRETunnelInterfaceInst(struct dmctx *dmctx, DMNODE *parent_node *************************************************************/ static int addObjGRETunnel(char *refparam, struct dmctx *ctx, void *data, char **instance) { - struct uci_section *gre_sec = NULL, *dmmap_sec = NULL; + struct uci_section *dev_sec = NULL, *dmmap_sec = NULL; + char buf[32] = {0}; - dmuci_add_section("network", "interface", &gre_sec); - dmuci_set_value_by_section(gre_sec, "proto", "gre"); + snprintf(buf, sizeof(buf), "gre_dev_%s", *instance); - dmuci_add_section_bbfdm("dmmap_network", "interface", &dmmap_sec); - dmuci_set_value_by_section(dmmap_sec, "section_name", section_name(gre_sec)); - dmuci_set_value_by_section(dmmap_sec, "gretunnel_instance", *instance); + dmuci_add_section("network", "device", &dev_sec); + dmuci_rename_section_by_section(dev_sec, buf); + dmuci_set_value_by_section(dev_sec, "name", buf); + dmuci_set_value_by_section(dev_sec, "type", "tunnel"); + dmuci_set_value_by_section(dev_sec, "mode", "greip"); + + dmuci_add_section_bbfdm("dmmap_gre", "device", &dmmap_sec); + dmuci_set_value_by_section(dmmap_sec, "section_name", buf); + dmuci_set_value_by_section(dmmap_sec, "gre_tunnel_instance", *instance); return 0; } static int delObjGRETunnel(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) { - struct uci_section *s = NULL, *stmp = NULL; - switch (del_action) { case DEL_INST: - dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "gretunnel_instance", ""); - dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "gretunnel_alias", ""); - dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL); + remove_tunnel(((struct dm_data *)data)->config_section, ((struct dm_data *)data)->dmmap_section); break; case DEL_ALL: - uci_foreach_option_eq_safe("network", "interface", "proto", "gre", stmp, s) { - struct uci_section *dmmap_section = NULL; - - get_dmmap_section_of_config_section("dmmap_network", "interface", section_name(s), &dmmap_section); - dmuci_set_value_by_section(dmmap_section, "gretunnel_instance", ""); - dmuci_set_value_by_section(dmmap_section, "gretunnel_alias", ""); - - dmuci_delete_by_section(s, NULL, NULL); - } + remove_all_tunnels(); break; } return 0; @@ -108,58 +292,54 @@ static int delObjGRETunnel(char *refparam, struct dmctx *ctx, void *data, char * static int addObjGRETunnelInterface(char *refparam, struct dmctx *ctx, void *data, char **instance) { - struct uci_section *greiface_sec = NULL, *dmmap_sec = NULL, *route_sec = NULL; - char device_buf[32]; + struct uci_section *if_sec = NULL, *dmmap_sec = NULL; + char buf[32] = {0}; + struct uci_section *tunnel_section = ((struct dm_data *)data)->config_section; + char *tunnel_instance = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->dmmap_section, "gre_tunnel_instance", ""); - dmuci_add_section("network", "interface", &greiface_sec); - snprintf(device_buf, sizeof(device_buf), "@%s", section_name(((struct dm_data *)data)->config_section)); - dmuci_set_value_by_section(greiface_sec, "device", device_buf); + char *proto = get_tunnel_dev_proto_family(tunnel_section); + char *disabled = dmuci_get_value_by_section_fallback_def(tunnel_section, "disabled", "0"); + char *remote = dmuci_get_value_by_section_fallback_def(tunnel_section, "remote", ""); - dmuci_add_section("network", "route", &route_sec); - dmuci_set_value_by_section(route_sec, "interface", section_name(greiface_sec)); + // name is derived from tunnel number and intf number + snprintf(buf, sizeof(buf), "gre_d%si%s", tunnel_instance, *instance); - dmuci_add_section_bbfdm("dmmap_network", "interface", &dmmap_sec); - dmuci_set_value_by_section(dmmap_sec, "section_name", section_name(greiface_sec)); - dmuci_set_value_by_section(dmmap_sec, "gre_tunnel_sect", section_name(((struct dm_data *)data)->config_section)); - dmuci_set_value_by_section(dmmap_sec, "greiface_instance", *instance); + dmuci_add_section("network", "interface", &if_sec); + dmuci_rename_section_by_section(if_sec, buf); + dmuci_set_value_by_section(if_sec, "proto", proto); + dmuci_set_value_by_section(if_sec, "device", get_tunnel_name(tunnel_section)); + dmuci_set_value_by_section(if_sec, "disabled", disabled); + + if (DM_STRLEN(remote)) { + if (!DM_LSTRCMP(proto, "grev6")) { + dmuci_set_value_by_section(if_sec, "peer6addr", remote); + } else { + dmuci_set_value_by_section(if_sec, "peeraddr", remote); + } + } + + dmuci_add_section_bbfdm("dmmap_gre", "interface", &dmmap_sec); + dmuci_set_value_by_section(dmmap_sec, "section_name", buf); + dmuci_set_value_by_section(dmmap_sec, "gre_iface_instance", *instance); return 0; } static int delObjGRETunnelInterface(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action) { - struct uci_section *s = NULL, *stmp = NULL; + char *tunnel_dev_name = NULL; switch (del_action) { case DEL_INST: - dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "greiface_instance", ""); - dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "greiface_alias", ""); - - if ((s = has_tunnel_interface_route(section_name(((struct dm_data *)data)->config_section))) != NULL) - dmuci_delete_by_section(s, NULL, NULL); - + empty_all_upper_layers_of_interface(((struct dm_data *)data)->config_section); + // Remove interface section in network UCI dmuci_delete_by_section(((struct dm_data *)data)->config_section, NULL, NULL); + // Remove interface section in dmmap_gre + dmuci_delete_by_section(((struct dm_data *)data)->dmmap_section, NULL, NULL); + break; case DEL_ALL: - uci_foreach_sections_safe("network", "interface", stmp, s) { - struct uci_section *ss = NULL, *dmmap_section = NULL; - char device_buf[32] = {0}; - char *device = NULL; - - dmuci_get_value_by_section_string(s, "device", &device); - snprintf(device_buf, sizeof(device_buf), "@%s", section_name(((struct dm_data *)data)->config_section)); - - if (!device || DM_STRCMP(device, device_buf) != 0) - continue; - - get_dmmap_section_of_config_section("dmmap_network", "interface", section_name(s), &dmmap_section); - dmuci_set_value_by_section(dmmap_section, "greiface_instance", ""); - dmuci_set_value_by_section(dmmap_section, "greiface_alias", ""); - - if ((ss = has_tunnel_interface_route(section_name(s))) != NULL) - dmuci_delete_by_section(ss, NULL, NULL); - - dmuci_delete_by_section(s, NULL, NULL); - } + tunnel_dev_name = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "name", ""); + remove_all_interfaces_of_tunnel(tunnel_dev_name); break; } return 0; @@ -168,21 +348,6 @@ static int delObjGRETunnelInterface(char *refparam, struct dmctx *ctx, void *dat /************************************************************* * GET & SET PARAM *************************************************************/ -static char *get_gre_tunnel_interface_statistics(char *interface, char *key) -{ - json_object *res = NULL, *diag = NULL; - char *device, *value = "0"; - - dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", interface, String}}, 1, &res); - if (!res) return value; - device = dmjson_get_value(res, 1, "device"); - if(device[0] != '\0') { - dmubus_call("network.device", "status", UBUS_ARGS{{"name", device, String}}, 1, &diag); - if (diag) - value = dmjson_get_value(diag, 2, "statistics", key); - } - return value; -} static int get_GRE_TunnelNumberOfEntries(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { @@ -191,32 +356,171 @@ static int get_GRE_TunnelNumberOfEntries(char *refparam, struct dmctx *ctx, void return 0; } -/*#Device.GRE.Tunnel.{i}.Alias!UCI:dmmap_network/interface,@i-1/gretunnel_alias*/ +static int get_GRETunnel_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *disabled = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "disabled", "0"); + + if (!DM_STRCMP(disabled, "0") || !DM_STRCMP(disabled, "false")) + *value = "1"; + else + *value = "0"; + + return 0; +} + +static int set_GRETunnel_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct uci_section *tunnel_section = ((struct dm_data *)data)->config_section; + bool b = true; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + char *disabled = b ? "0" : "1"; + + dmuci_set_value_by_section(tunnel_section, "disabled", disabled); + // disabling the device will have no effect so apply to all interfaces + set_all_sections_with_opt_eq("network", "interface", "device", get_tunnel_name(tunnel_section), "disabled", disabled ); + break; + } + return 0; +} + +static int get_GRETunnel_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + char *disabled = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "disabled", "0"); + + if (!DM_STRCMP(disabled, "0") || !DM_STRCMP(disabled, "false")) { + *value = "Enabled"; + } else { + *value = "Disabled"; + } + + return 0; +} + +/*#Device.GRE.Tunnel.{i}.Alias!UCI:dmmap_gre/interface,@i-1/gre_tunnel_alias*/ static int get_GRETunnel_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "gretunnel_alias", instance, value); + return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "gre_tunnel_alias", instance, value); } static int set_GRETunnel_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { - return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "gretunnel_alias", instance, value); + return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "gre_tunnel_alias", instance, value); } -static int get_GRETunnel_KeepAliveThreshold(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_GRETunnel_DeliveryHeaderProtocol(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "keepalive", "3"); + char *proto = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "mode", &proto); + + if (proto && !DM_LSTRCMP(proto, "greip6")) { + *value = "IPv6"; + } else { + *value = "IPv4"; + } return 0; } -static int set_GRETunnel_KeepAliveThreshold(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +static int set_GRETunnel_DeliveryHeaderProtocol(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { - switch (action) { + char *DeliveryHeaderProtocol[] = {"IPv4", "IPv6", NULL}; + char *current_delivery_header = NULL; + + switch (action) { case VALUECHECK: - if (bbfdm_validate_unsignedInt(ctx, value, RANGE_ARGS{{NULL,NULL}}, 1)) + if (bbfdm_validate_string(ctx, value, -1, -1, DeliveryHeaderProtocol, NULL)) return FAULT_9007; break; case VALUESET: - dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "keepalive", value); + get_GRETunnel_DeliveryHeaderProtocol(refparam, ctx, data, instance, ¤t_delivery_header); + + // if current delivery header and new delivery header are same, do nothing + // if different, find the device name for this tunnel + // for every interface that has device as this device name, update device name there + // delete current peeraddr or peer6addr as applicable + // and set a new empty one + // finally update the proto + if (DM_LSTRCMP(current_delivery_header, value)) { + struct uci_section *tunnel_section = ((struct dm_data *)data)->config_section; + char *current_proto = get_tunnel_dev_proto_family(tunnel_section); + char *tunnel_dev_name = get_tunnel_name(tunnel_section); + + // changing from grev6 to gre + if (!DM_LSTRCMP(current_proto, "grev6")) { + // update mode in tunnel device section + dmuci_set_value_by_section(tunnel_section, "mode", "greip"); + // remove remote because now we need different family's address + dmuci_set_value_by_section(tunnel_section, "remote", ""); + + // update proto to gre in all sections belonging to tunnel.interface + set_all_sections_with_opt_eq("network", "interface", "device", tunnel_dev_name, "proto", "gre"); + // remove peer6addr because now we need peeraddr + set_all_sections_with_opt_eq("network", "interface", "device", tunnel_dev_name, "peer6addr", ""); + // update device in all sections which have this tunnel.interface as lower layer + bool is_current_ipv6 = true; + update_all_interface_upper_layers(tunnel_dev_name, is_current_ipv6); + // changing from gre to grev6 + } else { + // current is greip, new is greip6 + // update mode in tunnel device section + dmuci_set_value_by_section(tunnel_section, "mode", "greip6"); + // remove remote because now we need different family's address + dmuci_set_value_by_section(tunnel_section, "remote", ""); + + // update proto to grev6 in all sections belonging to tunnel.interface + set_all_sections_with_opt_eq("network", "interface", "device", tunnel_dev_name, "proto", "grev6"); + // remove peeraddr because now we need peer6addr + set_all_sections_with_opt_eq("network", "interface", "device", tunnel_dev_name, "peeraddr", ""); + // update device in all sections which have this tunnel.interface as lower layer + bool is_current_ipv6 = false; + update_all_interface_upper_layers(tunnel_dev_name, is_current_ipv6); + } + } + break; + } + return 0; +} + +static int get_GRETunnel_RemoteEndpoints(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *tunnel_section = ((struct dm_data *)data)->config_section; + + *value = dmuci_get_value_by_section_fallback_def(tunnel_section, "remote", ""); + + return 0; +} + +static int set_GRETunnel_RemoteEndpoints(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct uci_section *tunnel_section = ((struct dm_data *)data)->config_section; + char *proto = NULL, *tunnel_dev_name = NULL; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, value, -1, 45, NULL, IPAddress)) + return FAULT_9007; + break; + case VALUESET: + proto = get_tunnel_dev_proto_family(tunnel_section); + tunnel_dev_name = get_tunnel_name(tunnel_section); + + // set the option remote in tunnel device section + dmuci_set_value_by_section(tunnel_section, "remote", value); + + if (!DM_LSTRCMP(proto, "grev6")) { + // set the peer6addr in all interfaces of this tunnel + set_all_sections_with_opt_eq("network", "interface", "device", tunnel_dev_name, "peer6addr", value); + } else { + set_all_sections_with_opt_eq("network", "interface", "device", tunnel_dev_name, "peeraddr", value); + } + break; } return 0; @@ -224,7 +528,9 @@ static int set_GRETunnel_KeepAliveThreshold(char *refparam, struct dmctx *ctx, v static int get_GRETunnel_ConnectedRemoteEndpoint(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "peeraddr", value); + // current implementation restricts us to only have one possible value for peer address + // ConnectedRemoteEndpoint is same as RemoteEndpoint + get_GRETunnel_RemoteEndpoints(refparam, ctx, data, instance, value); return 0; } @@ -235,51 +541,63 @@ static int get_GRETunnel_InterfaceNumberOfEntries(char *refparam, struct dmctx * return 0; } -static int get_GRETunnelStats_BytesSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_GRETunnelInterface_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value= get_gre_tunnel_interface_statistics(section_name(((struct dm_data *)data)->config_section), "tx_bytes"); + char *disabled = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "disabled", "0"); + + if (!DM_STRCMP(disabled, "0") || !DM_STRCMP(disabled, "false")) { + *value = "1"; + } else { + *value = "0"; + } + return 0; } -static int get_GRETunnelStats_BytesReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int set_GRETunnelInterface_Enable(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { - *value= get_gre_tunnel_interface_statistics(section_name(((struct dm_data *)data)->config_section), "rx_bytes"); + struct uci_section *tunnel_intf_section = ((struct dm_data *)data)->config_section; + bool b = true; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + char *disabled = b ? "0" : "1"; + + dmuci_set_value_by_section(tunnel_intf_section, "disabled", disabled); + break; + } return 0; } -static int get_GRETunnelStats_PacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +static int get_GRETunnelInterface_Status(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value= get_gre_tunnel_interface_statistics(section_name(((struct dm_data *)data)->config_section), "tx_packets"); - return 0; + char *disabled = dmuci_get_value_by_section_fallback_def(((struct dm_data *)data)->config_section, "disabled", "0"); + + if (!DM_STRCMP(disabled, "1") || !DM_STRCMP(disabled, "true")) { + *value = "Down"; + return 0; + } + + char tunnel_system_name[32] = {0}; + gre___get_tunnel_system_name(((struct dm_data *)data)->config_section, &tunnel_system_name[0], sizeof(tunnel_system_name)); + + return get_net_device_status(tunnel_system_name, value); } -static int get_GRETunnelStats_PacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - *value= get_gre_tunnel_interface_statistics(section_name(((struct dm_data *)data)->config_section), "rx_packets"); - return 0; -} - -static int get_GRETunnelStats_ErrorsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - *value= get_gre_tunnel_interface_statistics(section_name(((struct dm_data *)data)->config_section), "tx_errors"); - return 0; -} - -static int get_GRETunnelStats_ErrorsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) -{ - *value= get_gre_tunnel_interface_statistics(section_name(((struct dm_data *)data)->config_section), "rx_errors"); - return 0; -} - -/*#Device.GRE.Tunnel.{i}.Interface.{i}.Alias!UCI:dmmap_network/interface,@i-1/greiface_alias*/ +/*#Device.GRE.Tunnel.{i}.Interface.{i}.Alias!UCI:dmmap_gre/interface,@i-1/gre_iface_alias*/ static int get_GRETunnelInterface_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "greiface_alias", instance, value); + return bbf_get_alias(ctx, ((struct dm_data *)data)->dmmap_section, "gre_iface_alias", instance, value); } static int set_GRETunnelInterface_Alias(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) { - return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "greiface_alias", instance, value); + return bbf_set_alias(ctx, ((struct dm_data *)data)->dmmap_section, "gre_iface_alias", instance, value); } static int get_GRETunnelInterface_Name(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) @@ -288,39 +606,166 @@ static int get_GRETunnelInterface_Name(char *refparam, struct dmctx *ctx, void * return 0; } +static int get_GRETunnelInterface_LastChange(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + json_object *res = NULL; + + char *if_name = section_name(((struct dm_data *)data)->config_section); + dmubus_call("network.interface", "status", UBUS_ARGS{{"interface", if_name, String}}, 1, &res); + DM_ASSERT(res, *value = "0"); + *value = dmjson_get_value(res, 1, "uptime"); + return 0; +} + + +static int get_GRETunnelInterface_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + dmuci_get_value_by_section_string(((struct dm_data *)data)->dmmap_section, "LowerLayers", value); + + if ((*value)[0] == '\0') { + char *tunlink = NULL; + + dmuci_get_value_by_section_string(((struct dm_data *)data)->config_section, "tunlink", &tunlink); + + adm_entry_get_reference_param(ctx, "Device.IP.Interface.*.Name", tunlink, value); + + // Store LowerLayers value + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "LowerLayers", *value); + } else { + if (!adm_entry_object_exists(ctx, *value)) + *value = ""; + } + + return 0; +} + +static int set_GRETunnelInterface_LowerLayers(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + char *allowed_objects[] = {"Device.IP.Interface.", NULL}; + struct dm_reference reference = {0}; + + bbf_get_reference_args(value, &reference); + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_string(ctx, reference.path, -1, -1, NULL, NULL)) + return FAULT_9007; + + if (dm_validate_allowed_objects(ctx, &reference, allowed_objects)) + return FAULT_9007; + break; + case VALUESET: + // Store LowerLayers value under dmmap section + dmuci_set_value_by_section(((struct dm_data *)data)->dmmap_section, "LowerLayers", reference.path); + + // Update tunlink option + dmuci_set_value_by_section(((struct dm_data *)data)->config_section, "tunlink", reference.value); + break; + } + return 0; +} + +static int get_GRETunnelInterface_UseChecksum(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *iface_section = ((struct dm_data *)data)->config_section; + char *ocsum = NULL; + + dmuci_get_value_by_section_string(iface_section, "ocsum", &ocsum); + if (ocsum) { + if (!DM_STRCMP(ocsum, "1") || !DM_STRCMP(ocsum, "true")) + *value = "1"; + else + *value = "0"; + } + + return 0; +} + +static int set_GRETunnelInterface_UseChecksum(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct uci_section *iface_section = ((struct dm_data *)data)->config_section; + bool b = true; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + dmuci_set_value_by_section(iface_section, "ocsum", b ? "1" : "0"); + break; + } + return 0; +} + +static int get_GRETunnelInterface_UseSequenceNumber(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) +{ + struct uci_section *iface_section = ((struct dm_data *)data)->config_section; + char *oseqno = NULL; + + dmuci_get_value_by_section_string(iface_section, "oseqno", &oseqno); + if (oseqno) { + if (!DM_STRCMP(oseqno, "1") || !DM_STRCMP(oseqno, "true")) + *value = "1"; + else + *value = "0"; + } + + return 0; +} + +static int set_GRETunnelInterface_UseSequenceNumber(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action) +{ + struct uci_section *iface_section = ((struct dm_data *)data)->config_section; + bool b = false; + + switch (action) { + case VALUECHECK: + if (bbfdm_validate_boolean(ctx, value)) + return FAULT_9007; + break; + case VALUESET: + string_to_bool(value, &b); + dmuci_set_value_by_section(iface_section, "oseqno", b ? "1" : "0"); + break; + } + return 0; +} + static int get_GRETunnelInterfaceStats_BytesSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = get_gre_tunnel_interface_statistics(section_name(((struct dm_data *)data)->config_section), "tx_bytes"); + *value = get_gre_tunnel_interface_statistics(((struct dm_data *)data)->json_object, "tx_bytes"); return 0; } static int get_GRETunnelInterfaceStats_BytesReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = get_gre_tunnel_interface_statistics(section_name(((struct dm_data *)data)->config_section), "rx_bytes"); + *value = get_gre_tunnel_interface_statistics(((struct dm_data *)data)->json_object, "rx_bytes"); return 0; } static int get_GRETunnelInterfaceStats_PacketsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = get_gre_tunnel_interface_statistics(section_name(((struct dm_data *)data)->config_section), "tx_packets"); + *value = get_gre_tunnel_interface_statistics(((struct dm_data *)data)->json_object, "tx_packets"); return 0; } static int get_GRETunnelInterfaceStats_PacketsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = get_gre_tunnel_interface_statistics(section_name(((struct dm_data *)data)->config_section), "rx_packets"); + *value = get_gre_tunnel_interface_statistics(((struct dm_data *)data)->json_object, "rx_packets"); return 0; } static int get_GRETunnelInterfaceStats_ErrorsSent(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = get_gre_tunnel_interface_statistics(section_name(((struct dm_data *)data)->config_section), "tx_errors"); + *value = get_gre_tunnel_interface_statistics(((struct dm_data *)data)->json_object, "tx_errors"); return 0; } static int get_GRETunnelInterfaceStats_ErrorsReceived(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value) { - *value = get_gre_tunnel_interface_statistics(section_name(((struct dm_data *)data)->config_section), "rx_errors"); + *value = get_gre_tunnel_interface_statistics(((struct dm_data *)data)->json_object, "rx_errors"); return 0; } @@ -352,31 +797,35 @@ DMOBJ tGRETunnelObj[] = { DMLEAF tGRETunnelParams[] = { /* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ -//{"Enable", &DMWRITE, DMT_BOOL, get_GRETunnel_Enable, set_GRETunnel_Enable, BBFDM_BOTH}, -//{"Status", &DMREAD, DMT_STRING, get_GRETunnel_Status, NULL, BBFDM_BOTH}, +{"Enable", &DMWRITE, DMT_BOOL, get_GRETunnel_Enable, set_GRETunnel_Enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_GRETunnel_Status, NULL, BBFDM_BOTH}, {"Alias", &DMWRITE, DMT_STRING, get_GRETunnel_Alias, set_GRETunnel_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, -//{"RemoteEndpoints", &DMWRITE, DMT_STRING, get_GRETunnel_RemoteEndpoints, set_GRETunnel_RemoteEndpoints, BBFDM_BOTH}, +{"RemoteEndpoints", &DMWRITE, DMT_STRING, get_GRETunnel_RemoteEndpoints, set_GRETunnel_RemoteEndpoints, BBFDM_BOTH}, //{"KeepAlivePolicy", &DMWRITE, DMT_STRING, get_GRETunnel_KeepAlivePolicy, set_GRETunnel_KeepAlivePolicy, BBFDM_BOTH}, //{"KeepAliveTimeout", &DMWRITE, DMT_UNINT, get_GRETunnel_KeepAliveTimeout, set_GRETunnel_KeepAliveTimeout, BBFDM_BOTH}, -{"KeepAliveThreshold", &DMWRITE, DMT_UNINT, get_GRETunnel_KeepAliveThreshold, set_GRETunnel_KeepAliveThreshold, BBFDM_BOTH}, -//{"DeliveryHeaderProtocol", &DMWRITE, DMT_STRING, get_GRETunnel_DeliveryHeaderProtocol, set_GRETunnel_DeliveryHeaderProtocol, BBFDM_BOTH}, +//{"KeepAliveThreshold", &DMWRITE, DMT_UNINT, get_GRETunnel_KeepAliveThreshold, set_GRETunnel_KeepAliveThreshold, BBFDM_BOTH}, +{"DeliveryHeaderProtocol", &DMWRITE, DMT_STRING, get_GRETunnel_DeliveryHeaderProtocol, set_GRETunnel_DeliveryHeaderProtocol, BBFDM_BOTH}, //{"DefaultDSCPMark", &DMWRITE, DMT_UNINT, get_GRETunnel_DefaultDSCPMark, set_GRETunnel_DefaultDSCPMark, BBFDM_BOTH}, {"ConnectedRemoteEndpoint", &DMREAD, DMT_STRING, get_GRETunnel_ConnectedRemoteEndpoint, NULL, BBFDM_BOTH}, {"InterfaceNumberOfEntries", &DMREAD, DMT_UNINT, get_GRETunnel_InterfaceNumberOfEntries, NULL, BBFDM_BOTH}, {0} }; +/* + * no tunnel stats because there is no separate device section for tunnel + * and currently we only support only one interface per tunnel at a time + */ /* *** Device.GRE.Tunnel.{i}.Stats. *** */ DMLEAF tGRETunnelStatsParams[] = { /* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ //{"KeepAliveSent", &DMREAD, DMT_UNINT, get_GRETunnelStats_KeepAliveSent, NULL, BBFDM_BOTH}, //{"KeepAliveReceived", &DMREAD, DMT_UNINT, get_GRETunnelStats_KeepAliveReceived, NULL, BBFDM_BOTH}, -{"BytesSent", &DMREAD, DMT_UNINT, get_GRETunnelStats_BytesSent, NULL, BBFDM_BOTH}, -{"BytesReceived", &DMREAD, DMT_UNINT, get_GRETunnelStats_BytesReceived, NULL, BBFDM_BOTH}, -{"PacketsSent", &DMREAD, DMT_UNINT, get_GRETunnelStats_PacketsSent, NULL, BBFDM_BOTH}, -{"PacketsReceived", &DMREAD, DMT_UNINT, get_GRETunnelStats_PacketsReceived, NULL, BBFDM_BOTH}, -{"ErrorsSent", &DMREAD, DMT_UNINT, get_GRETunnelStats_ErrorsSent, NULL, BBFDM_BOTH}, -{"ErrorsReceived", &DMREAD, DMT_UNINT, get_GRETunnelStats_ErrorsReceived, NULL, BBFDM_BOTH}, +//{"BytesSent", &DMREAD, DMT_UNINT, get_GRETunnelStats_BytesSent, NULL, BBFDM_BOTH}, +//{"BytesReceived", &DMREAD, DMT_UNINT, get_GRETunnelStats_BytesReceived, NULL, BBFDM_BOTH}, +//{"PacketsSent", &DMREAD, DMT_UNINT, get_GRETunnelStats_PacketsSent, NULL, BBFDM_BOTH}, +//{"PacketsReceived", &DMREAD, DMT_UNINT, get_GRETunnelStats_PacketsReceived, NULL, BBFDM_BOTH}, +//{"ErrorsSent", &DMREAD, DMT_UNINT, get_GRETunnelStats_ErrorsSent, NULL, BBFDM_BOTH}, +//{"ErrorsReceived", &DMREAD, DMT_UNINT, get_GRETunnelStats_ErrorsReceived, NULL, BBFDM_BOTH}, {0} }; @@ -389,17 +838,17 @@ DMOBJ tGRETunnelInterfaceObj[] = { DMLEAF tGRETunnelInterfaceParams[] = { /* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/ -//{"Enable", &DMWRITE, DMT_BOOL, get_GRETunnelInterface_Enable, set_GRETunnelInterface_Enable, BBFDM_BOTH}, -//{"Status", &DMREAD, DMT_STRING, get_GRETunnelInterface_Status, NULL, BBFDM_BOTH}, +{"Enable", &DMWRITE, DMT_BOOL, get_GRETunnelInterface_Enable, set_GRETunnelInterface_Enable, BBFDM_BOTH}, +{"Status", &DMREAD, DMT_STRING, get_GRETunnelInterface_Status, NULL, BBFDM_BOTH}, {"Alias", &DMWRITE, DMT_STRING, get_GRETunnelInterface_Alias, set_GRETunnelInterface_Alias, BBFDM_BOTH, DM_FLAG_UNIQUE}, -{"Name", &DMREAD, DMT_STRING, get_GRETunnelInterface_Name, NULL, BBFDM_BOTH, DM_FLAG_UNIQUE}, -//{"LastChange", &DMREAD, DMT_UNINT, get_GRETunnelInterface_LastChange, NULL, BBFDM_BOTH}, -//{"LowerLayers", &DMWRITE, DMT_STRING, get_GRETunnelInterface_LowerLayers, set_GRETunnelInterface_LowerLayers, BBFDM_BOTH}, +{"Name", &DMREAD, DMT_STRING, get_GRETunnelInterface_Name, NULL, BBFDM_BOTH, DM_FLAG_UNIQUE|DM_FLAG_LINKER}, +{"LastChange", &DMREAD, DMT_UNINT, get_GRETunnelInterface_LastChange, NULL, BBFDM_BOTH}, +{"LowerLayers", &DMWRITE, DMT_STRING, get_GRETunnelInterface_LowerLayers, set_GRETunnelInterface_LowerLayers, BBFDM_BOTH, DM_FLAG_REFERENCE}, //{"ProtocolIdOverride", &DMWRITE, DMT_UNINT, get_GRETunnelInterface_ProtocolIdOverride, set_GRETunnelInterface_ProtocolIdOverride, BBFDM_BOTH}, -//{"UseChecksum", &DMWRITE, DMT_BOOL, get_GRETunnelInterface_UseChecksum, set_GRETunnelInterface_UseChecksum, BBFDM_BOTH}, +{"UseChecksum", &DMWRITE, DMT_BOOL, get_GRETunnelInterface_UseChecksum, set_GRETunnelInterface_UseChecksum, BBFDM_BOTH}, //{"KeyIdentifierGenerationPolicy", &DMWRITE, DMT_STRING, get_GRETunnelInterface_KeyIdentifierGenerationPolicy, set_GRETunnelInterface_KeyIdentifierGenerationPolicy, BBFDM_BOTH}, //{"KeyIdentifier", &DMWRITE, DMT_UNINT, get_GRETunnelInterface_KeyIdentifier, set_GRETunnelInterface_KeyIdentifier, BBFDM_BOTH}, -//{"UseSequenceNumber", &DMWRITE, DMT_BOOL, get_GRETunnelInterface_UseSequenceNumber, set_GRETunnelInterface_UseSequenceNumber, BBFDM_BOTH}, +{"UseSequenceNumber", &DMWRITE, DMT_BOOL, get_GRETunnelInterface_UseSequenceNumber, set_GRETunnelInterface_UseSequenceNumber, BBFDM_BOTH}, {0} }; diff --git a/libbbfdm/dmtree/tr181/interfacestack.c b/libbbfdm/dmtree/tr181/interfacestack.c index 9005fa40..92108af6 100644 --- a/libbbfdm/dmtree/tr181/interfacestack.c +++ b/libbbfdm/dmtree/tr181/interfacestack.c @@ -57,22 +57,33 @@ static char *get_lower_alias_value(const char *path) } else if (DM_STRNCMP(path, "Device.Ethernet.Interface.", strlen("Device.Ethernet.Interface.")) == 0) { get_dmmap_section_of_config_section_eq("dmmap_ethernet", "device", "eth_iface_instance", instance + 1, &s); dmuci_get_value_by_section_string(s, "eth_iface_alias", &alias_value); - } else if (DM_STRNCMP(path, "Device.Bridging.Bridge.", strlen("Device.Bridging.Bridge.")) == 0) { + } else if (DM_STRNCMP(path, "Device.Bridging.Bridge.", strlen("Device.Bridging.Bridge.")) == 0 || + DM_STRNCMP(path, "Device.GRE.Tunnel.", strlen("Device.GRE.Tunnel.")) == 0) { regmatch_t pmatch[1] = {0}; - char *port_inst = NULL; - char br_inst[8] = {0}; + char first_inst[8] = {0}; + char *second_inst = NULL; bool res = match(path, "([0-9]+)", 1, pmatch); if (res) { - DM_STRNCPY(br_inst, &path[pmatch[0].rm_so], pmatch[0].rm_eo - pmatch[0].rm_so + 1); - if (DM_STRLEN(br_inst) == 0) + DM_STRNCPY(first_inst, &path[pmatch[0].rm_so], pmatch[0].rm_eo - pmatch[0].rm_so + 1); + if (DM_STRLEN(first_inst) == 0) return ""; - uci_path_foreach_option_eq(bbfdm, "dmmap_bridge_port", "bridge_port", "br_inst", br_inst, s) { - dmuci_get_value_by_section_string(s, "bridge_port_instance", &port_inst); - if (DM_STRCMP(port_inst, instance + 1) == 0) { - dmuci_get_value_by_section_string(s, "bridge_port_alias", &alias_value); - break; + if (DM_STRNCMP(path, "Device.Bridging.Bridge.", strlen("Device.Bridging.Bridge.")) == 0) { + uci_path_foreach_option_eq(bbfdm, "dmmap_bridge_port", "bridge_port", "br_inst", first_inst, s) { + dmuci_get_value_by_section_string(s, "bridge_port_instance", &second_inst); + if (DM_STRCMP(second_inst, instance + 1) == 0) { + dmuci_get_value_by_section_string(s, "bridge_port_alias", &alias_value); + break; + } + } + } else if (DM_STRNCMP(path, "Device.GRE.Tunnel.", strlen("Device.GRE.Tunnel.")) == 0) { + uci_path_foreach_option_eq(bbfdm, "dmmap_gre", "interface", "tunnel_instance", first_inst, s) { + dmuci_get_value_by_section_string(s, "gre_iface_instance", &second_inst); + if (DM_STRCMP(second_inst, instance + 1) == 0) { + dmuci_get_value_by_section_string(s, "gre_iface_alias", &alias_value); + break; + } } } } @@ -142,6 +153,20 @@ int browseInterfaceStackInst(struct dmctx *dmctx, DMNODE *parent_node, void *pre goto end; } + /* Higher Layer is Device.GRE.Tunnel.{i}.Interface.{i}. */ + uci_path_foreach_sections(bbfdm, "dmmap_gre", "interface", s) { + char *tunnel_inst = NULL; + char path[128] = {0}; + + dmuci_get_value_by_section_string(s, "tunnel_instance", &tunnel_inst); + + snprintf(path, sizeof(path), "Device.GRE.Tunnel.%s.Interface.", tunnel_inst); + + if (create_interface_stack_instance(dmctx, parent_node, &curr_interfacestack_data, s, + path, "gre_iface_instance", "gre_iface_alias", &idx)) + goto end; + } + /* Higher Layer is Device.PPP.Interface.{i}. */ uci_path_foreach_sections(bbfdm, "dmmap_ppp", "interface", s) { diff --git a/libbbfdm/dmtree/tr181/ip.c b/libbbfdm/dmtree/tr181/ip.c index f16b2cc1..159f5241 100644 --- a/libbbfdm/dmtree/tr181/ip.c +++ b/libbbfdm/dmtree/tr181/ip.c @@ -553,7 +553,8 @@ static int browseIPInterfaceInst(struct dmctx *dmctx, DMNODE *parent_node, void dmuci_get_value_by_section_string(curr_data->config_section, "device", &device); if (strcmp(section_name(curr_data->config_section), "loopback") == 0 || - *proto == '\0' || + DM_STRLEN(proto) == 0 || + ip___is_gre_protocols(proto) || DM_STRCHR(device, '@') || ip___is_ip_interface_instance_exists(section_name(curr_data->config_section), device)) continue; @@ -848,7 +849,8 @@ static int delObjIPInterface(char *refparam, struct dmctx *ctx, void *data, char dmuci_get_value_by_section_string(s, "device", &device); if (strcmp(section_name(s), "loopback") == 0 || - *proto == '\0' || + DM_STRLEN(proto) == 0 || + ip___is_gre_protocols(proto) || DM_STRCHR(device, '@') || ip___is_ip_interface_instance_exists(section_name(s), device)) continue; @@ -1253,6 +1255,13 @@ static int get_IPInterface_LowerLayers(char *refparam, struct dmctx *ctx, void * goto end; adm_entry_get_reference_param(ctx, "Device.Ethernet.Link.*.Name", device, value); + if (DM_STRLEN(*value)) + goto end; + + if ((DM_STRLEN(device) > 5) && DM_LSTRNCMP(device, "gre", 3) == 0) { + // gre device name is of the form gre4- or gre6- + adm_entry_get_reference_param(ctx, "Device.GRE.Tunnel.*.Interface.*.Name", device + 5, value); + } end: // Store LowerLayers value @@ -1274,6 +1283,7 @@ static int set_IPInterface_LowerLayers(char *refparam, struct dmctx *ctx, void * eth_mac_vlan, "Device.Ethernet.VLANTermination.", "Device.Ethernet.Link.", + "Device.GRE.Tunnel.*.Interface.", NULL}; char *curr_device = NULL; struct dm_reference reference = {0}; @@ -1327,6 +1337,16 @@ static int set_IPInterface_LowerLayers(char *refparam, struct dmctx *ctx, void * dmuci_set_value_by_section_bbfdm(ppp_s, "iface_name", section_name((struct uci_section *)data)); ppp___update_sections(ppp_s, (struct uci_section *)data); } + } else if (DM_STRNCMP(reference.path, "Device.GRE.Tunnel.", strlen("Device.GRE.Tunnel.")) == 0) { + // get gre device name for provided interface in gre_device + struct uci_section *iface_s = get_origin_section_from_config("network", "interface", reference.value); + char gre_device[32] = {0}; + + gre___get_tunnel_system_name(iface_s, &gre_device[0], sizeof(gre_device)); + + if (DM_STRLEN(gre_device) > 0) { + ip___update_child_interfaces(curr_device, "device", gre_device); + } } else { ip___update_child_interfaces(curr_device, "device", reference.value); } diff --git a/libbbfdm/dmtree/tr181/routing.c b/libbbfdm/dmtree/tr181/routing.c index 5a75022e..5c7c9ee5 100644 --- a/libbbfdm/dmtree/tr181/routing.c +++ b/libbbfdm/dmtree/tr181/routing.c @@ -368,7 +368,8 @@ static int browseRouterInst(struct dmctx *dmctx, DMNODE *parent_node, void *prev dmuci_get_value_by_section_string(s, "ip4table", &idx); if (strcmp(section_name(s), "loopback") == 0 || - *proto == '\0' || + DM_STRLEN(proto) == 0 || + ip___is_gre_protocols(proto) || DM_STRCHR(device, '@') || ip___is_ip_interface_instance_exists(section_name(s), device)) continue;