Re-implement GRE object

This commit is contained in:
Mohd Mehdi 2024-04-09 07:28:52 +00:00 committed by Amin Ben Romdhane
parent 80262573c9
commit fd894e7cb7
7 changed files with 860 additions and 169 deletions

158
docs/guide/libbbfdm_GRE.md Normal file
View file

@ -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: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> 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.

View file

@ -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;

View file

@ -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);

View file

@ -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 <omar.kallel@pivasoftware.com>
* Author: Mohd Husaam Mehdi <husaam.mehdi@iopsys.eu>
*/
#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)
{
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, &current_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");
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;
}
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;
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_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}
};

View file

@ -57,24 +57,35 @@ 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) {
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;
}
}
}
}
} else if (DM_STRNCMP(path, "Device.WiFi.SSID.", strlen("Device.WiFi.SSID.")) == 0) {
get_dmmap_section_of_config_section_eq("dmmap_wireless", "ssid", "ssid_instance", instance + 1, &s);
@ -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) {

View file

@ -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-<iface> or gre6-<iface>
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);
}

View file

@ -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;