bbf: add support for mld snooping and proxy

Added support for MLD configuration using the new proposed data
model.
Resolve bug in IGMP to be able to delete child objects when
parents are deleted from the dmmap_mcast file.
This commit is contained in:
Rahul 2020-04-20 19:55:11 +05:30
parent 685d8fa611
commit 20f0c5211c
7 changed files with 1827 additions and 134 deletions

View file

@ -52,6 +52,7 @@ libbbfdm_la_SOURCES += \
../dmtree/tr181/times.c \
../dmtree/tr181/upnp.c \
../dmtree/tr181/x_iopsys_eu_igmp.c \
../dmtree/tr181/x_iopsys_eu_mld.c \
../dmtree/tr181/x_iopsys_eu_syslog.c \
../dmtree/tr181/x_iopsys_eu_dropbear.c \
../dmtree/tr181/x_iopsys_eu_owsd.c \

View file

@ -16,6 +16,7 @@
#include "times.h"
#include "upnp.h"
#include "x_iopsys_eu_igmp.h"
#include "x_iopsys_eu_mld.h"
#include "x_iopsys_eu_syslog.h"
#include "xmpp.h"
#include "x_iopsys_eu_owsd.h"
@ -80,6 +81,7 @@ DMOBJ tRoot_181_Obj[] = {
{CUSTOM_PREFIX"Syslog", &DMREAD, NULL, NULL, NULL, NULL, NULL, &DMNONE, NULL, NULL, tSe_SyslogParam, NULL, BBFDM_BOTH},
{CUSTOM_PREFIX"OWSD", &DMREAD, NULL, NULL, NULL, NULL, NULL, &DMNONE, NULL, X_IOPSYS_EU_OWSDObj, X_IOPSYS_EU_OWSDParams, NULL, BBFDM_BOTH},
{CUSTOM_PREFIX"IGMP", &DMREAD, NULL, NULL, NULL, NULL, NULL, &DMNONE, NULL, X_IOPSYS_EU_IGMPObj, X_IOPSYS_EU_IGMPParams, NULL, BBFDM_BOTH},
{CUSTOM_PREFIX"MLD", &DMREAD, NULL, NULL, NULL, NULL, NULL, &DMNONE, NULL, X_IOPSYS_EU_MLDObj, X_IOPSYS_EU_MLDParams, NULL, BBFDM_BOTH},
{CUSTOM_PREFIX"Dropbear", &DMWRITE, add_dropbear_instance, delete_dropbear_instance, NULL, browseXIopsysEuDropbear, NULL, &DMNONE, NULL, NULL, X_IOPSYS_EU_DropbearParams, NULL, BBFDM_BOTH},
{CUSTOM_PREFIX"Buttons", &DMREAD, NULL, NULL, NULL, browseXIopsysEuButton, NULL, &DMNONE, NULL, NULL, X_IOPSYS_EU_ButtonParams, NULL, BBFDM_BOTH},
{CUSTOM_PREFIX"WiFiLife", &DMREAD, NULL, NULL, NULL, NULL, NULL, &DMNONE, NULL, X_IOPSYS_EU_WiFiLifeObj, X_IOPSYS_EU_WiFiLifeParams, NULL, BBFDM_BOTH},

View file

@ -11,37 +11,6 @@
#include "dmentry.h"
#include "x_iopsys_eu_igmp.h"
static void sync_dmmap_bool_to_uci_list(struct uci_section *s, char *section, char *value,
bool b)
{
struct uci_list *v = NULL;
struct uci_element *e;
char *val;
dmuci_get_value_by_section_list(s, section, &v);
if (v != NULL) {
uci_foreach_element(v, e) {
val = dmstrdup(e->name);
if (strcmp(val, value) == 0) {
if (!b) {
// remove this entry
dmuci_del_list_value_by_section(s, section, value);
}
// Further action is not required
return;
}
}
}
// If control has reached this point, that means, either the entry was not found
// in the list, hence, if b is true, add this entry to the list
if (b) {
dmuci_add_list_value_by_section(s, section, value);
}
}
static int add_igmp_proxy_obj(char *refparam, struct dmctx *ctx, void *data, char **instance)
{
char *inst, *value, *v, *s_name;
@ -49,10 +18,11 @@ static int add_igmp_proxy_obj(char *refparam, struct dmctx *ctx, void *data, cha
char i_no[16];
check_create_dmmap_package("dmmap_mcast");
inst = get_last_instance_bbfdm("dmmap_mcast", "proxy", "proxy_instance");
inst = get_last_instance_lev2_bbfdm_dmmap_opt("dmmap_mcast", "proxy", "proxy_instance",
"proto", "igmp");
snprintf(i_no, sizeof(i_no), "%d", inst ? atoi(inst)+1 : 1);
dmasprintf(&s_name, "mproxy_%s", i_no);
dmasprintf(&s_name, "igmp_proxy_%s", i_no);
dmuci_add_section("mcast", "proxy", &s, &value);
dmuci_rename_section_by_section(s, s_name);
@ -64,6 +34,7 @@ static int add_igmp_proxy_obj(char *refparam, struct dmctx *ctx, void *data, cha
dmuci_add_section_bbfdm("dmmap_mcast", "proxy", &dmmap, &v);
dmuci_set_value_by_section(dmmap, "section_name", section_name(s));
dmuci_set_value_by_section(dmmap, "proto", "igmp");
*instance = update_instance_bbfdm(dmmap, inst, "proxy_instance");
return 0;
@ -76,6 +47,14 @@ static int del_igmp_proxy_obj(char *refparam, struct dmctx *ctx, void *data, cha
switch (del_action) {
case DEL_INST:
// first delete all filter child nodes related to this object
del_dmmap_sec_with_opt_eq("dmmap_mcast", "proxy_filter",
"section_name", section_name((struct uci_section *)data));
// Now delete all interface child nodes related to this object
del_dmmap_sec_with_opt_eq("dmmap_mcast", "proxy_interface",
"section_name", section_name((struct uci_section *)data));
// Now delete the proxy node
get_dmmap_section_of_config_section("dmmap_mcast", "proxy", section_name((struct uci_section *)data), &dmmap_section);
if (dmmap_section != NULL)
@ -112,7 +91,7 @@ static int browse_igmp_proxy_inst(struct dmctx *dmctx, DMNODE *parent_node, void
struct dmmap_dup *p;
LIST_HEAD(dup_list);
synchronize_specific_config_sections_with_dmmap("mcast", "proxy", "dmmap_mcast", &dup_list);
synchronize_specific_config_sections_with_dmmap_cont("mcast", "proxy", "dmmap_mcast", "proto", "igmp", &dup_list);
list_for_each_entry(p, &dup_list, list) {
inst = handle_update_instance(1, dmctx, &inst_last, update_instance_alias, 3, p->dmmap_section, "proxy_instance", "proxy_alias");
if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)p->config_section, inst) == DM_STOP)
@ -130,10 +109,11 @@ static int add_igmp_snooping_obj(char *refparam, struct dmctx *ctx, void *data,
char i_no[16];
check_create_dmmap_package("dmmap_mcast");
inst = get_last_instance_bbfdm("dmmap_mcast", "snooping", "snooping_instance");
inst = get_last_instance_lev2_bbfdm_dmmap_opt("dmmap_mcast", "snooping",
"snooping_instance", "proto", "igmp");
snprintf(i_no, sizeof(i_no), "%d", inst ? atoi(inst)+1 : 1);
dmasprintf(&s_name, "msnoop_%s", i_no);
dmasprintf(&s_name, "igmp_snoop_%s", i_no);
dmuci_add_section("mcast", "snooping", &s, &value);
dmuci_rename_section_by_section(s, s_name);
@ -145,6 +125,7 @@ static int add_igmp_snooping_obj(char *refparam, struct dmctx *ctx, void *data,
dmuci_add_section_bbfdm("dmmap_mcast", "snooping", &dmmap, &v);
dmuci_set_value_by_section(dmmap, "section_name", section_name(s));
dmuci_set_value_by_section(dmmap, "proto", "igmp");
*instance = update_instance_bbfdm(dmmap, inst, "snooping_instance");
return 0;
@ -157,6 +138,12 @@ static int del_igmp_snooping_obj(char *refparam, struct dmctx *ctx, void *data,
switch (del_action) {
case DEL_INST:
// first delete all filter child nodes related to this object
del_dmmap_sec_with_opt_eq("dmmap_mcast", "snooping_filter",
"section_name", section_name((struct uci_section *)data));
// Now delete all interface child nodes related to this object
del_dmmap_sec_with_opt_eq("dmmap_mcast", "snooping_interface",
"section_name", section_name((struct uci_section *)data));
get_dmmap_section_of_config_section("dmmap_mcast", "snooping", section_name((struct uci_section *)data), &dmmap_section);
if (dmmap_section != NULL)
@ -193,7 +180,7 @@ static int browse_igmp_snooping_inst(struct dmctx *dmctx, DMNODE *parent_node, v
struct dmmap_dup *p;
LIST_HEAD(dup_list);
synchronize_specific_config_sections_with_dmmap("mcast", "snooping", "dmmap_mcast", &dup_list);
synchronize_specific_config_sections_with_dmmap_cont("mcast", "snooping", "dmmap_mcast", "proto", "igmp", &dup_list);
list_for_each_entry(p, &dup_list, list) {
inst = handle_update_instance(1, dmctx, &inst_last, update_instance_alias, 3, p->dmmap_section, "snooping_instance", "snooping_alias");
if (DM_LINK_INST_OBJ(dmctx, parent_node, (void *)p->config_section, inst) == DM_STOP)
@ -208,7 +195,7 @@ static int get_igmps_no_of_entries(char *refparam, struct dmctx *ctx, void *data
struct uci_section *s = NULL;
int cnt = 0;
uci_foreach_sections("mcast", "snooping", s) {
uci_foreach_option_eq("mcast", "snooping", "proto", "igmp", s) {
cnt++;
}
@ -221,7 +208,7 @@ static int get_igmpp_no_of_entries(char *refparam, struct dmctx *ctx, void *data
struct uci_section *s = NULL;
int cnt = 0;
uci_foreach_sections("mcast", "proxy", s) {
uci_foreach_option_eq("mcast", "proxy", "proto", "igmp", s) {
cnt++;
}
@ -263,8 +250,7 @@ static int add_igmps_filter_obj(char *refparam, struct dmctx *ctx, void *data, c
static int del_igmps_filter_obj(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
struct uci_section *d_sec = NULL;
struct uci_section *stmp = NULL;
char *f_inst, *ip_addr, *s_name;
char *f_inst, *ip_addr;
int found = 0;
switch (del_action) {
@ -297,12 +283,8 @@ static int del_igmps_filter_obj(char *refparam, struct dmctx *ctx, void *data, c
}
}
uci_path_foreach_sections_safe(bbfdm, "dmmap_mcast", "snooping_filter", stmp, d_sec) {
dmuci_get_value_by_section_string(d_sec, "section_name", &s_name);
if (strcmp(s_name, section_name((struct uci_section *)data)) == 0)
dmuci_delete_by_section_unnamed_bbfdm(d_sec, NULL, NULL);
}
del_dmmap_sec_with_opt_eq("dmmap_mcast", "snooping_filter",
"section_name", section_name((struct uci_section *)data));
break;
}
@ -622,75 +604,6 @@ static int get_igmp_snooping_interface(char *refparam, struct dmctx *ctx, void *
return 0;
}
static int get_br_key_from_lower_layer(char *lower_layer, char *key, size_t s_key)
{
char *p = strstr(lower_layer, "Port");
if (!p)
return -1;
/* Get the bridge_key. */
int len = strlen(p);
char new_if[250] = {0};
int i;
for (i = 0; i < strlen(lower_layer) - len; i++) {
new_if[i] = lower_layer[i];
}
char br_key = new_if[strlen(new_if) - 2];
snprintf(key, s_key, "%c", br_key);
return 0;
}
static int get_igmp_snooping_interface_val(char *value, char *ifname, size_t s_ifname)
{
char lower_layer[250] = {0};
if (value[strlen(value)-1] != '.')
snprintf(lower_layer, sizeof(lower_layer), "%s.", value);
else
strncpy(lower_layer, value, sizeof(lower_layer) - 1);
/* Check if the value is valid or not. */
if (strncmp(lower_layer, "Device.Bridging.Bridge.", 23) != 0)
return -1;
char key[10] = {0};
if (get_br_key_from_lower_layer(lower_layer, key, sizeof(key)) != 0)
return -1;
/* Find out bridge section name using bridge key. */
struct uci_section *s = NULL;
char *sec_name;
uci_path_foreach_option_eq(bbfdm, "dmmap_network", "interface", "bridge_instance", key, s) {
dmuci_get_value_by_section_string(s, "section_name", &sec_name);
break;
}
// Check if network uci file has this section, if yes, then
// update the snooping interface with value as br-<section name>
struct uci_section *intf_s = NULL;
uci_foreach_sections("network", "interface", intf_s) {
char sec[20] = {0};
strncpy(sec, section_name(intf_s), sizeof(sec) - 1);
if (strncmp(sec, sec_name, sizeof(sec)) != 0)
continue;
char *type;
dmuci_get_value_by_section_string(intf_s, "type", &type);
if (*type == '\0' || strcmp(type, "bridge") != 0)
continue;
snprintf(ifname, s_ifname, "br-%s", sec_name);
break;
}
return 0;
}
static int set_igmp_snooping_interface(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
char ifname[16];
@ -717,7 +630,8 @@ static int add_igmpp_interface_obj(char *refparam, struct dmctx *ctx, void *data
char *last_inst, *v;
struct uci_section *dmmap_igmpp_interface = NULL;
last_inst = get_last_instance_bbfdm("dmmap_mcast", "proxy_interface", "iface_instance");
last_inst = get_last_instance_lev2_bbfdm_dmmap_opt("dmmap_mcast", "proxy_interface", "iface_instance",
"section_name", section_name((struct uci_section *)data));
dmuci_add_section_bbfdm("dmmap_mcast", "proxy_interface", &dmmap_igmpp_interface, &v);
dmuci_set_value_by_section(dmmap_igmpp_interface, "section_name",
@ -731,8 +645,7 @@ static int add_igmpp_interface_obj(char *refparam, struct dmctx *ctx, void *data
static int del_igmpp_interface_obj(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
struct uci_section *d_sec = NULL;
struct uci_section *stmp = NULL;
char *f_inst, *if_name, *s_name, *upstream;
char *f_inst, *if_name, *upstream;
int found = 0;
switch (del_action) {
@ -777,12 +690,8 @@ static int del_igmpp_interface_obj(char *refparam, struct dmctx *ctx, void *data
}
}
uci_path_foreach_sections_safe(bbfdm, "dmmap_mcast", "proxy_interface", stmp, d_sec) {
dmuci_get_value_by_section_string(d_sec, "section_name", &s_name);
if (strcmp(s_name, section_name((struct uci_section *)data)) == 0)
dmuci_delete_by_section_unnamed_bbfdm(d_sec, NULL, NULL);
}
del_dmmap_sec_with_opt_eq("dmmap_mcast", "proxy_interface",
"section_name", section_name((struct uci_section *)data));
break;
}
@ -833,8 +742,7 @@ static int add_igmpp_filter_obj(char *refparam, struct dmctx *ctx, void *data, c
static int del_igmpp_filter_obj(char *refparam, struct dmctx *ctx, void *data, char *instance, unsigned char del_action)
{
struct uci_section *d_sec = NULL;
struct uci_section *stmp = NULL;
char *f_inst, *ip_addr, *s_name;
char *f_inst, *ip_addr;
int found = 0;
switch (del_action) {
@ -866,11 +774,8 @@ static int del_igmpp_filter_obj(char *refparam, struct dmctx *ctx, void *data, c
"filter", ip_addr);
}
uci_path_foreach_sections_safe(bbfdm, "dmmap_mcast", "proxy_filter", stmp, d_sec) {
dmuci_get_value_by_section_string(d_sec, "section_name", &s_name);
if (strcmp(s_name, section_name((struct uci_section *)data)) == 0)
dmuci_delete_by_section_unnamed_bbfdm(d_sec, NULL, NULL);
}
del_dmmap_sec_with_opt_eq("dmmap_mcast", "proxy_filter", "section_name",
section_name((struct uci_section *)data));
break;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,36 @@
/*
* Copyright (C) 2020 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 Rahul Thakur <rahul.thakur@iopsys.eu>
*
*/
#ifndef __SE_MLD_H
#define __SE_MLD_H
#include <libbbf_api/dmcommon.h>
extern DMOBJ X_IOPSYS_EU_MLDObj[];
extern DMLEAF X_IOPSYS_EU_MLDParams[];
extern DMOBJ X_IOPSYS_EU_MLDSnoopingObj[];
extern DMLEAF X_IOPSYS_EU_MLDSnoopingParams[];
extern DMOBJ MLDSnoopingCLientGroupObj[];
extern DMLEAF MLDSnoopingClientGroupParams[];
extern DMLEAF MLDSnoopingClientGroupStatsParams[];
extern DMLEAF MLDSnoopingClientGroupAssociatedDeviceParams[];
extern DMLEAF MLDSnoopingFilterParams[];
extern DMOBJ X_IOPSYS_EU_MLDProxyObj[];
extern DMLEAF X_IOPSYS_EU_MLDProxyParams[];
extern DMLEAF MLDProxyInterfaceParams[];
extern DMOBJ MLDProxyCLientGroupObj[];
extern DMLEAF MLDProxyClientGroupParams[];
extern DMLEAF MLDProxyClientGroupStatsParams[];
extern DMLEAF MLDProxyClientGroupAssociatedDeviceParams[];
extern DMLEAF MLDProxyFilterParams[];
#endif

View file

@ -787,7 +787,7 @@ void synchronize_specific_config_sections_with_dmmap_mcast_iface(char *package,
char *s_name;
dmmap_file_path_get(dmmap_package);
uci_foreach_sections(package, section_type, s) {
uci_foreach_option_eq(package, section_type, "proto", proto, s) {
if (strcmp(section_name(s), section_name((struct uci_section *)data)) != 0)
continue;
@ -889,7 +889,7 @@ void synchronize_specific_config_sections_with_dmmap_filter(char *package, char
dmmap_file_path_get(dmmap_package);
uci_foreach_sections(package, section_type, s) {
uci_foreach_option_eq(package, section_type, "proto", proto, s) {
if (strcmp(section_name(s), section_name((struct uci_section *)data)) != 0)
continue;
/*
@ -2303,3 +2303,115 @@ int create_mac_addr_upstream_intf(char *mac_addr, char *mac, int mac_len)
return -1;
}
void del_dmmap_sec_with_opt_eq(char *dmmap_file, char *section, char *option, char *value)
{
struct uci_section *d_sec = NULL;
struct uci_section *stmp = NULL;
char *opt_val;
uci_path_foreach_sections_safe(bbfdm, dmmap_file, section, stmp, d_sec) {
dmuci_get_value_by_section_string(d_sec, option, &opt_val);
if (strcmp(opt_val, value) == 0)
dmuci_delete_by_section_unnamed_bbfdm(d_sec, NULL, NULL);
}
}
void sync_dmmap_bool_to_uci_list(struct uci_section *s, char *section,
char *value, bool b)
{
struct uci_list *v = NULL;
struct uci_element *e;
char *val;
dmuci_get_value_by_section_list(s, section, &v);
if (v != NULL) {
uci_foreach_element(v, e) {
val = dmstrdup(e->name);
if (strcmp(val, value) == 0) {
if (!b) {
// remove this entry
dmuci_del_list_value_by_section(s, section, value);
}
// Further action is not required
return;
}
}
}
// If control has reached this point, that means, either the entry was not found
// in the list, hence, if b is true, add this entry to the list
if (b) {
dmuci_add_list_value_by_section(s, section, value);
}
}
int get_br_key_from_lower_layer(char *lower_layer, char *key, size_t s_key)
{
char *p = strstr(lower_layer, "Port");
if (!p)
return -1;
/* Get the bridge_key. */
int len = strlen(p);
char new_if[250] = {0};
int i;
for (i = 0; i < strlen(lower_layer) - len; i++) {
new_if[i] = lower_layer[i];
}
char br_key = new_if[strlen(new_if) - 2];
snprintf(key, s_key, "%c", br_key);
return 0;
}
int get_igmp_snooping_interface_val(char *value, char *ifname, size_t s_ifname)
{
char lower_layer[250] = {0};
if (value[strlen(value)-1] != '.')
snprintf(lower_layer, sizeof(lower_layer), "%s.", value);
else
strncpy(lower_layer, value, sizeof(lower_layer) - 1);
/* Check if the value is valid or not. */
if (strncmp(lower_layer, "Device.Bridging.Bridge.", 23) != 0)
return -1;
char key[10] = {0};
if (get_br_key_from_lower_layer(lower_layer, key, sizeof(key)) != 0)
return -1;
/* Find out bridge section name using bridge key. */
struct uci_section *s = NULL;
char *sec_name;
uci_path_foreach_option_eq(bbfdm, "dmmap_network", "interface", "bridge_instance", key, s) {
dmuci_get_value_by_section_string(s, "section_name", &sec_name);
break;
}
// Check if network uci file has this section, if yes, then
// update the snooping interface with value as br-<section name>
struct uci_section *intf_s = NULL;
uci_foreach_sections("network", "interface", intf_s) {
char sec[20] = {0};
strncpy(sec, section_name(intf_s), sizeof(sec) - 1);
if (strncmp(sec, sec_name, sizeof(sec)) != 0)
continue;
char *type;
dmuci_get_value_by_section_string(intf_s, "type", &type);
if (*type == '\0' || strcmp(type, "bridge") != 0)
continue;
snprintf(ifname, s_ifname, "br-%s", sec_name);
break;
}
return 0;
}

View file

@ -340,4 +340,9 @@ char *replace_char(char *str, char find, char replace);
int is_vlan_termination_section(char *name);
int get_upstream_interface(char *intf_tag, int len);
int create_mac_addr_upstream_intf(char *mac_addr, char *mac, int len);
int get_br_key_from_lower_layer(char *lower_layer, char *key, size_t s_key);
int get_igmp_snooping_interface_val(char *value, char *ifname, size_t s_ifname);
void sync_dmmap_bool_to_uci_list(struct uci_section *s, char *section,
char *value, bool b);
void del_dmmap_sec_with_opt_eq(char *dmmap_file, char *section, char *option, char *value);
#endif