mirror of
https://github.com/coolsnowwolf/packages.git
synced 2025-05-01 09:10:48 +08:00
igmpproxy: add support for QCA MCS module
This commit is contained in:
parent
b5e83ce6d1
commit
b211c4397e
@ -8,12 +8,12 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=igmpproxy
|
||||
PKG_VERSION:=0.3
|
||||
PKG_RELEASE:=1
|
||||
PKG_VERSION:=0.2.1
|
||||
PKG_RELEASE:=4
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/pali/igmpproxy/releases/download/${PKG_VERSION}/
|
||||
PKG_HASH:=d1fc244cb2fbbf99f720bda3e841fe59ece9b6919073790b4b892739b1b844eb
|
||||
PKG_HASH:=d351e623037390f575c1203d9cbb7ba33a8bdef85a3c5e1d2901c5a2a38449a1
|
||||
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
@ -35,15 +35,43 @@ define Package/igmpproxy/description
|
||||
only IGMP signalling (Internet Group Management Protocol).
|
||||
endef
|
||||
|
||||
define Package/igmpproxy/config
|
||||
if PACKAGE_igmpproxy
|
||||
if PACKAGE_kmod-qca-mcs
|
||||
config PACKAGE_IGMPROXY_QCA_MCS_SUPPORT
|
||||
bool "Enable QCA Multicast Snooping Module Support"
|
||||
default y
|
||||
help
|
||||
This option enables support for the QCA Multicast Snooping module.
|
||||
Enabling this will enable multicast traffic to be accelerated by
|
||||
the QCA NSS ECM module.
|
||||
endif
|
||||
endif
|
||||
endef
|
||||
|
||||
define Package/igmpproxy/conffiles
|
||||
/etc/config/igmpproxy
|
||||
endef
|
||||
|
||||
TARGET_CFLAGS += -Dlog=igmpproxy_log
|
||||
|
||||
ifneq ($(CONFIG_PACKAGE_IGMPROXY_QCA_MCS_SUPPORT),)
|
||||
CONFIG_SUFFIX=.qca-mcs
|
||||
TARGET_CFLAGS += -DIGMPPROXY_QCA_MCS_SUPPORT
|
||||
endif
|
||||
|
||||
define Build/Compile
|
||||
cd $(PKG_BUILD_DIR) && aclocal
|
||||
$(MAKE) -C $(PKG_BUILD_DIR)/src \
|
||||
CC="$(TARGET_CC)" \
|
||||
CFLAGS="$(TARGET_CFLAGS) -std=gnu99"
|
||||
endef
|
||||
|
||||
define Package/igmpproxy/install
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_CONF) ./files/igmpproxy.config $(1)/etc/config/igmpproxy
|
||||
$(INSTALL_CONF) ./files/igmpproxy.config$(CONFIG_SUFFIX) $(1)/etc/config/igmpproxy
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_BIN) ./files/igmpproxy.init $(1)/etc/init.d/igmpproxy
|
||||
$(INSTALL_BIN) ./files/igmpproxy.init$(CONFIG_SUFFIX) $(1)/etc/init.d/igmpproxy
|
||||
$(INSTALL_DIR) $(1)/usr/sbin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/igmpproxy $(1)/usr/sbin/
|
||||
endef
|
||||
|
27
net/igmpproxy/files/igmpproxy.config.qca-mcs
Normal file
27
net/igmpproxy/files/igmpproxy.config.qca-mcs
Normal file
@ -0,0 +1,27 @@
|
||||
config igmpproxy
|
||||
option quickleave 1
|
||||
# option verbose [0-3](none, minimal[default], more, maximum)
|
||||
|
||||
config phyint
|
||||
option network wan
|
||||
option zone wan
|
||||
option direction upstream
|
||||
list altnet 192.168.1.0/24
|
||||
|
||||
config phyint
|
||||
option network lan
|
||||
option zone lan
|
||||
option direction downstream
|
||||
|
||||
# This section configures the QCA MCS support
|
||||
# Uncomment to enable QCA NSS ECM multicast acceleration.
|
||||
#
|
||||
# 'lan' should be the LAN bridge device
|
||||
# 'brport' should be the bridge port(s)
|
||||
#
|
||||
# Up to 16 bridges with up to 16 bridge ports(per bridge) can be configured.
|
||||
#config phyint
|
||||
# option network lan
|
||||
# option zone lan
|
||||
# option direction qca-mcs-bridge
|
||||
# list brport eth1.1
|
164
net/igmpproxy/files/igmpproxy.init.qca-mcs
Normal file
164
net/igmpproxy/files/igmpproxy.init.qca-mcs
Normal file
@ -0,0 +1,164 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Copyright (C) 2010-2014 OpenWrt.org
|
||||
|
||||
START=99
|
||||
USE_PROCD=1
|
||||
PROG=/usr/sbin/igmpproxy
|
||||
CONFIGFILE=/var/etc/igmpproxy.conf
|
||||
|
||||
igmp_header() {
|
||||
local quickleave verbose
|
||||
config_get_bool quickleave "$1" quickleave 0
|
||||
config_get verbose "$1" verbose 1
|
||||
|
||||
[ $verbose = "0" ] && logopts="-d"
|
||||
[ $verbose = "2" ] && logopts="-v"
|
||||
[ $verbose = "3" ] && logopts="-v -v"
|
||||
|
||||
mkdir -p /var/etc
|
||||
rm -f /var/etc/igmpproxy.conf
|
||||
[ $quickleave -gt 0 ] && echo "quickleave" >> /var/etc/igmpproxy.conf
|
||||
|
||||
[ -L /etc/igmpproxy.conf ] || ln -nsf /var/etc/igmpproxy.conf /etc/igmpproxy.conf
|
||||
}
|
||||
|
||||
igmp_add_phyint() {
|
||||
local network direction altnets device up brports
|
||||
|
||||
config_get network $1 network
|
||||
config_get direction $1 direction
|
||||
config_get altnets $1 altnet
|
||||
config_get brports $1 brport
|
||||
|
||||
local status="$(ubus -S call "network.interface.$network" status)"
|
||||
[ -n "$status" ] || return
|
||||
|
||||
json_load "$status"
|
||||
json_get_var device l3_device
|
||||
json_get_var up up
|
||||
|
||||
[ -n "$device" -a "$up" = "1" ] || {
|
||||
procd_append_param error "$network is not up"
|
||||
return;
|
||||
}
|
||||
|
||||
append netdevs "$device"
|
||||
|
||||
[ "$direction" = "upstream" ] && has_upstream=1
|
||||
|
||||
echo -e "\nphyint $device $direction ratelimit 0 threshold 1" >> /var/etc/igmpproxy.conf
|
||||
|
||||
if [ -n "$altnets" ]; then
|
||||
local altnet
|
||||
for altnet in $altnets; do
|
||||
echo -e "\taltnet $altnet" >> /var/etc/igmpproxy.conf
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -n "$brports" ]; then
|
||||
local brport
|
||||
for brport in $brports; do
|
||||
echo -e "\tbrport $brport" >> /var/etc/igmpproxy.conf
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
igmp_add_network() {
|
||||
local network
|
||||
|
||||
config_get network $1 network
|
||||
procd_add_interface_trigger "interface.*" $network /etc/init.d/igmpproxy reload
|
||||
}
|
||||
|
||||
igmp_add_firewall_routing() {
|
||||
config_get direction $1 direction
|
||||
config_get zone $1 zone
|
||||
|
||||
if [ "$direction" != "downstream" ] || [ -z "$zone" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# First drop SSDP packets then accept all other multicast
|
||||
|
||||
json_add_object ""
|
||||
json_add_string type rule
|
||||
json_add_string src "$upstream"
|
||||
json_add_string dest "$zone"
|
||||
json_add_string family ipv4
|
||||
json_add_string proto udp
|
||||
json_add_string dest_ip "239.255.255.250"
|
||||
json_add_string target DROP
|
||||
json_close_object
|
||||
|
||||
json_add_object ""
|
||||
json_add_string type rule
|
||||
json_add_string src "$upstream"
|
||||
json_add_string dest "$zone"
|
||||
json_add_string family ipv4
|
||||
json_add_string proto udp
|
||||
json_add_string dest_ip "224.0.0.0/4"
|
||||
json_add_string target ACCEPT
|
||||
json_close_object
|
||||
}
|
||||
|
||||
igmp_add_firewall_network() {
|
||||
config_get direction $1 direction
|
||||
config_get zone $1 zone
|
||||
|
||||
[ ! -z "$zone" ] || return
|
||||
|
||||
json_add_object ""
|
||||
json_add_string type rule
|
||||
json_add_string src "$zone"
|
||||
json_add_string family ipv4
|
||||
json_add_string proto igmp
|
||||
json_add_string target ACCEPT
|
||||
json_close_object
|
||||
|
||||
[ "$direction" = "upstream" ] && {
|
||||
upstream="$zone"
|
||||
config_foreach igmp_add_firewall_routing phyint
|
||||
}
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "igmpproxy"
|
||||
config_foreach igmp_add_network phyint
|
||||
}
|
||||
|
||||
start_service() {
|
||||
has_upstream=
|
||||
netdevs=
|
||||
logopts=
|
||||
config_load igmpproxy
|
||||
|
||||
config_foreach igmp_header igmpproxy
|
||||
config_foreach igmp_add_phyint phyint
|
||||
[ -n "$has_upstream" ] || return
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command $PROG '-n'
|
||||
[ -n "$logopts" ] && procd_append_param command $logopts
|
||||
procd_append_param command $CONFIGFILE
|
||||
procd_set_param file $CONFIGFILE
|
||||
procd_set_param netdev $netdevs
|
||||
procd_set_param respawn
|
||||
|
||||
procd_open_data
|
||||
|
||||
json_add_array firewall
|
||||
config_foreach igmp_add_firewall_network phyint
|
||||
json_close_array
|
||||
|
||||
procd_close_data
|
||||
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_started() {
|
||||
procd_set_config_changed firewall
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
procd_set_config_changed firewall
|
||||
}
|
621
net/igmpproxy/patches/900-qca-mcs-support.patch
Normal file
621
net/igmpproxy/patches/900-qca-mcs-support.patch
Normal file
@ -0,0 +1,621 @@
|
||||
--- a/src/config.c
|
||||
+++ b/src/config.c
|
||||
@@ -65,6 +65,10 @@ static struct Config commonConfig;
|
||||
struct vifconfig *parsePhyintToken(void);
|
||||
struct SubnetList *parseSubnetAddress(char *addrstr);
|
||||
|
||||
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
|
||||
+void qca_mcs_add_brdev(char *brdevstr);
|
||||
+#endif
|
||||
+
|
||||
/**
|
||||
* Initializes common config..
|
||||
*/
|
||||
@@ -132,17 +136,25 @@ int loadConfig(char *configFile) {
|
||||
my_log(LOG_WARNING, 0, "Unknown token '%s' in configfile", token);
|
||||
return 0;
|
||||
} else {
|
||||
-
|
||||
- my_log(LOG_DEBUG, 0, "IF name : %s", tmpPtr->name);
|
||||
- my_log(LOG_DEBUG, 0, "Next ptr : %x", tmpPtr->next);
|
||||
- my_log(LOG_DEBUG, 0, "Ratelimit : %d", tmpPtr->ratelimit);
|
||||
- my_log(LOG_DEBUG, 0, "Threshold : %d", tmpPtr->threshold);
|
||||
- my_log(LOG_DEBUG, 0, "State : %d", tmpPtr->state);
|
||||
- my_log(LOG_DEBUG, 0, "Allowednet ptr : %x", tmpPtr->allowednets);
|
||||
-
|
||||
- // Insert config, and move temppointer to next location...
|
||||
- *currPtr = tmpPtr;
|
||||
- currPtr = &tmpPtr->next;
|
||||
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
|
||||
+ if (tmpPtr->state == IF_STATE_QCA_MCS_BR) {
|
||||
+ free(tmpPtr->name);
|
||||
+ free(tmpPtr);
|
||||
+ }
|
||||
+ else
|
||||
+#endif
|
||||
+ {
|
||||
+ my_log(LOG_DEBUG, 0, "IF name : %s", tmpPtr->name);
|
||||
+ my_log(LOG_DEBUG, 0, "Next ptr : %x", tmpPtr->next);
|
||||
+ my_log(LOG_DEBUG, 0, "Ratelimit : %d", tmpPtr->ratelimit);
|
||||
+ my_log(LOG_DEBUG, 0, "Threshold : %d", tmpPtr->threshold);
|
||||
+ my_log(LOG_DEBUG, 0, "State : %d", tmpPtr->state);
|
||||
+ my_log(LOG_DEBUG, 0, "Allowednet ptr : %x", tmpPtr->allowednets);
|
||||
+
|
||||
+ // Insert config, and move temppointer to next location...
|
||||
+ *currPtr = tmpPtr;
|
||||
+ currPtr = &tmpPtr->next;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
else if(strcmp("quickleave", token)==0) {
|
||||
@@ -244,6 +256,9 @@ struct vifconfig *parsePhyintToken(void)
|
||||
struct SubnetList **anetPtr, **agrpPtr;
|
||||
char *token;
|
||||
short parseError = 0;
|
||||
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
|
||||
+ char qcaMcsIntfs[300] = { 0 };
|
||||
+#endif
|
||||
|
||||
// First token should be the interface name....
|
||||
token = nextConfigToken();
|
||||
@@ -273,6 +288,10 @@ struct vifconfig *parsePhyintToken(void)
|
||||
my_log(LOG_ERR, 0, "Out of memory.");
|
||||
}
|
||||
|
||||
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
|
||||
+ strcpy(qcaMcsIntfs, tmpPtr->name);
|
||||
+#endif
|
||||
+
|
||||
// Set the altnet pointer to the allowednets pointer.
|
||||
anetPtr = &tmpPtr->allowednets;
|
||||
agrpPtr = &tmpPtr->allowedgroups;
|
||||
@@ -345,6 +364,20 @@ struct vifconfig *parsePhyintToken(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
|
||||
+ else if(strcmp("qca-mcs-bridge", token)==0) {
|
||||
+ // QCA MCS bridge
|
||||
+ my_log(LOG_DEBUG, 0, "Config: IF: Got qca-mcs module bridge token.");
|
||||
+ tmpPtr->state = IF_STATE_QCA_MCS_BR;
|
||||
+ }
|
||||
+ else if(strcmp("brport", token)==0) {
|
||||
+ // QCA MCS bridge port
|
||||
+ token = nextConfigToken();
|
||||
+ my_log(LOG_DEBUG, 0, "Config: IF: Got brport token %s.",token);
|
||||
+ strcat(&qcaMcsIntfs, "|");
|
||||
+ strcat(&qcaMcsIntfs, token);
|
||||
+ }
|
||||
+#endif
|
||||
else {
|
||||
// Unknown token. Break...
|
||||
break;
|
||||
@@ -359,6 +392,13 @@ struct vifconfig *parsePhyintToken(void)
|
||||
tmpPtr = NULL;
|
||||
}
|
||||
|
||||
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
|
||||
+ if (tmpPtr->state == IF_STATE_QCA_MCS_BR) {
|
||||
+ // Configure QCA MCS configurations
|
||||
+ qca_mcs_add_brdev(&qcaMcsIntfs);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
return tmpPtr;
|
||||
}
|
||||
|
||||
--- a/src/igmpproxy.h
|
||||
+++ b/src/igmpproxy.h
|
||||
@@ -122,6 +122,10 @@ void my_log( int Serverity, int Errno, c
|
||||
#define IF_STATE_LOST 3 // aimwang: Temp from downstream to hidden
|
||||
#define IF_STATE_HIDDEN 4 // aimwang: Interface is hidden
|
||||
|
||||
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
|
||||
+#define IF_STATE_QCA_MCS_BR 5 // QCA MCA support
|
||||
+#endif
|
||||
+
|
||||
// Multicast default values...
|
||||
#define DEFAULT_ROBUSTNESS 2
|
||||
#define DEFAULT_THRESHOLD 1
|
||||
--- a/src/igmpproxy.c
|
||||
+++ b/src/igmpproxy.c
|
||||
@@ -61,6 +61,12 @@ int igmpProxyInit(void);
|
||||
void igmpProxyCleanUp(void);
|
||||
void igmpProxyRun(void);
|
||||
|
||||
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
|
||||
+bool qca_mcs_is_configured(void);
|
||||
+void qca_mcs_start(void);
|
||||
+void qca_mcs_stop(void);
|
||||
+#endif
|
||||
+
|
||||
// Global vars...
|
||||
static int sighandled = 0;
|
||||
#define GOT_SIGINT 0x01
|
||||
@@ -152,9 +158,21 @@ int main( int ArgCn, char *ArgVc[] ) {
|
||||
}
|
||||
}
|
||||
|
||||
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
|
||||
+ if (qca_mcs_is_configured()) {
|
||||
+ qca_mcs_start();
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
// Go to the main loop.
|
||||
igmpProxyRun();
|
||||
|
||||
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
|
||||
+ if (qca_mcs_is_configured()) {
|
||||
+ qca_mcs_stop();
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
// Clean up
|
||||
igmpProxyCleanUp();
|
||||
|
||||
--- a/src/rttable.c
|
||||
+++ b/src/rttable.c
|
||||
@@ -71,6 +71,11 @@ void logRouteTable(const char *header);
|
||||
int internAgeRoute(struct RouteTable *croute);
|
||||
int internUpdateKernelRoute(struct RouteTable *route, int activate);
|
||||
|
||||
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
|
||||
+bool qca_mcs_is_configured(void);
|
||||
+void qca_mcs_flood_brport(u_int32_t mc_addr, bool is_join);
|
||||
+#endif
|
||||
+
|
||||
// Socket for sending join or leave requests.
|
||||
int mcGroupSock = 0;
|
||||
|
||||
@@ -159,6 +164,12 @@ static void sendJoinLeaveUpstream(struct
|
||||
joinMcGroup( getMcGroupSock(), upstrIf, route->group );
|
||||
|
||||
route->upstrState = ROUTESTATE_JOINED;
|
||||
+
|
||||
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
|
||||
+ if (qca_mcs_is_configured()) {
|
||||
+ qca_mcs_flood_brport( route->group, true );
|
||||
+ }
|
||||
+#endif
|
||||
} else {
|
||||
my_log(LOG_DEBUG, 0, "No downstream listeners for group %s. No join sent.",
|
||||
inetFmt(route->group, s1));
|
||||
@@ -174,6 +185,12 @@ static void sendJoinLeaveUpstream(struct
|
||||
leaveMcGroup( getMcGroupSock(), upstrIf, route->group );
|
||||
|
||||
route->upstrState = ROUTESTATE_NOTJOINED;
|
||||
+
|
||||
+#ifdef IGMPPROXY_QCA_MCS_SUPPORT
|
||||
+ if (qca_mcs_is_configured()) {
|
||||
+ qca_mcs_flood_brport( route->group, false );
|
||||
+ }
|
||||
+#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
--- a/dev/null
|
||||
+++ b/src/qca-mcs.h
|
||||
@@ -0,0 +1,91 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2012, 2015 The Linux Foundation. All rights reserved.
|
||||
+ *
|
||||
+ * Permission to use, copy, modify, and/or distribute this software for any
|
||||
+ * purpose with or without fee is hereby granted, provided that the above
|
||||
+ * copyright notice and this permission notice appear in all copies.
|
||||
+ *
|
||||
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
+ */
|
||||
+/*
|
||||
+ * Header files copied from QCA NHSS.QSDK.12.0.r8 qca-mcs sources
|
||||
+ */
|
||||
+
|
||||
+#define NETLINK_QCA_MC 23
|
||||
+
|
||||
+#define MC_DEF_IF_MAX 16
|
||||
+#define MC_DEF_IP6_SIZE 16
|
||||
+
|
||||
+#define MC_ACL_RULE_MAX_COUNT 8 /* 8 for IGMP, 8 for MLD */
|
||||
+
|
||||
+/* netlink message type */
|
||||
+enum {
|
||||
+ MC_MSG_SET_ENABLE,
|
||||
+ MC_MSG_SET_DEBUG,
|
||||
+ MC_MSG_SET_POLICY,
|
||||
+ MC_MSG_SET_MEMBERSHIP_INTERVAL,
|
||||
+ MC_MSG_SET_RETAG,
|
||||
+ MC_MSG_SET_ROUTER_PORT,
|
||||
+ MC_MSG_SET_ADD_ACL_RULE,
|
||||
+ MC_MSG_SET_FLUSH_ACL_RULE,
|
||||
+ MC_MSG_SET_CONVERT_ALL,
|
||||
+ MC_MSG_SET_TIMEOUT,
|
||||
+ MC_MSG_SET_M2I3_FILTER,
|
||||
+ MC_MSG_SET_TBIT,
|
||||
+ MC_MSG_SET_LOCAL_QUERY_INTERVAL,
|
||||
+ MC_MSG_SET_PSW_ENCAP,
|
||||
+ MC_MSG_SET_PSW_FLOOD,
|
||||
+ MC_MSG_SET_EVENT_PID,
|
||||
+ MC_MSG_GET_ACL,
|
||||
+ MC_MSG_GET_MDB,
|
||||
+ MC_MSG_SET_ROUTER,
|
||||
+ MC_MSG_GET_ROUTER_PORT,
|
||||
+ MC_MSG_MAX
|
||||
+};
|
||||
+
|
||||
+struct __mcctl_msg_header {
|
||||
+ char if_name[IFNAMSIZ]; /* bridge name: br-lan */
|
||||
+ u_int32_t buf_len; /* not include this header */
|
||||
+ u_int32_t tbl_offsite; /* how many entries to skip */
|
||||
+ u_int32_t status;
|
||||
+ u_int32_t bytes_written;
|
||||
+ u_int32_t bytes_needed;
|
||||
+} __attribute__ ((packed));;
|
||||
+
|
||||
+struct __mc_param_value {
|
||||
+ u_int32_t val;
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ MC_RTPORT_FLOOD = 0,
|
||||
+ MC_RTPORT_DROP,
|
||||
+ MC_RTPORT_SPECIFY,
|
||||
+ MC_RTPORT_DEFAULT,
|
||||
+ MC_RTPORT_MAX
|
||||
+};
|
||||
+
|
||||
+struct __mc_param_router_port {
|
||||
+ u_int32_t type;
|
||||
+ u_int32_t ifindex;
|
||||
+};
|
||||
+
|
||||
+struct __mc_group {
|
||||
+ u_int32_t pro;
|
||||
+ union {
|
||||
+ u_int32_t ip4;
|
||||
+ u_int8_t ip6[MC_DEF_IP6_SIZE];
|
||||
+ } u;
|
||||
+};
|
||||
+
|
||||
+struct __mc_floodtbl_entry {
|
||||
+ struct __mc_group group;
|
||||
+ u_int32_t ifcnt;
|
||||
+ u_int32_t ifindex[MC_DEF_IF_MAX];
|
||||
+} __attribute__ ((packed));
|
||||
+
|
||||
--- a/dev/null
|
||||
+++ b/src/qca-mcs.c
|
||||
@@ -0,0 +1,319 @@
|
||||
+/*
|
||||
+** QCA Multicast Snooping (MCS) Module Support
|
||||
+**
|
||||
+** Enables the ipq806x NSS ECM multicast acceleration support.
|
||||
+**/
|
||||
+
|
||||
+#include <linux/netlink.h>
|
||||
+#include "igmpproxy.h"
|
||||
+#include "qca-mcs.h"
|
||||
+
|
||||
+#define QCA_MCS_MAX_MCAST_GRP 32
|
||||
+
|
||||
+struct qca_mcs_brdev {
|
||||
+ char if_name[IFNAMSIZ]; /* bridge interface name */
|
||||
+ u_int32_t br_ifidx; /* bridge interface index */
|
||||
+ u_int32_t port_num; /* number of bridge port to flood */
|
||||
+ u_int32_t port_ifidx[MC_DEF_IF_MAX]; /* bridge port interface index */
|
||||
+};
|
||||
+
|
||||
+struct qca_mcs_all_brdev {
|
||||
+ u_int32_t num_brdev; /* number of bridge interface to manage */
|
||||
+ struct qca_mcs_brdev brdev[MC_DEF_IF_MAX]; /* bridge details */
|
||||
+};
|
||||
+
|
||||
+static unsigned int mcsNlFd = -1;
|
||||
+
|
||||
+static struct qca_mcs_all_brdev all_brdev = { 0 };
|
||||
+
|
||||
+static u_int32_t flooded_mc_addr[QCA_MCS_MAX_MCAST_GRP] = { 0 };
|
||||
+static int flooded_mc_addr_cnt = 0;
|
||||
+
|
||||
+static bool qca_mcs_configured = false;
|
||||
+
|
||||
+/*
|
||||
+ * data - netlink messages payload - includes the __mcctl_msg_header
|
||||
+ */
|
||||
+static int qca_mcs_sendmsg(void *data, int data_len, int msg_type)
|
||||
+{
|
||||
+ struct sockaddr_nl sa, da;
|
||||
+ struct nlmsghdr *nlh;
|
||||
+ struct iovec iov;
|
||||
+ struct msghdr msg;
|
||||
+ int sentcnt;
|
||||
+
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.nl_family = AF_NETLINK;
|
||||
+ sa.nl_pid = getpid();
|
||||
+ sa.nl_groups = 0;
|
||||
+ if (bind(mcsNlFd, (struct sockaddr *) &sa, sizeof(sa))) {
|
||||
+ my_log( LOG_WARNING, errno, "%s: Unable to bind socket", __func__);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ memset(&da, 0, sizeof(da));
|
||||
+ da.nl_family = AF_NETLINK;
|
||||
+ da.nl_pid = 0;
|
||||
+ da.nl_groups = 0;
|
||||
+
|
||||
+ nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(data_len));
|
||||
+ if (!nlh) {
|
||||
+ my_log( LOG_WARNING, errno, "%s: malloc() failed", __func__);
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ memset(nlh, 0, NLMSG_SPACE(data_len));
|
||||
+ nlh->nlmsg_len = NLMSG_SPACE(data_len);
|
||||
+ nlh->nlmsg_pid = getpid();
|
||||
+ nlh->nlmsg_flags = 0;
|
||||
+ nlh->nlmsg_type = msg_type;
|
||||
+
|
||||
+ memcpy(NLMSG_DATA(nlh), data, data_len);
|
||||
+
|
||||
+ iov.iov_base = (void *)nlh;
|
||||
+ iov.iov_len = nlh->nlmsg_len;
|
||||
+ msg.msg_name = (void *)&da;
|
||||
+ msg.msg_namelen = sizeof(da);
|
||||
+ msg.msg_iov = &iov;
|
||||
+ msg.msg_iovlen = 1;
|
||||
+
|
||||
+ sentcnt = sendmsg(mcsNlFd, &msg, 0);
|
||||
+ if (sentcnt < 0) {
|
||||
+ my_log( LOG_WARNING, 0, "%s: Failed - data_len[%d], mcsNlFd[%d], msg_type[%d]", __func__,
|
||||
+ data_len, mcsNlFd, msg_type);
|
||||
+ }
|
||||
+ free(nlh);
|
||||
+
|
||||
+ return sentcnt;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Enable/disable the QCA MCS bridge device and bridge ports
|
||||
+ */
|
||||
+static int qca_mcs_brdev_state(bool enable)
|
||||
+{
|
||||
+ void *mcctl_br_state;
|
||||
+ struct __mcctl_msg_header *mcctl_msghdr;
|
||||
+ struct __mc_param_value *mc_param_val;
|
||||
+ int br_state_msglen;
|
||||
+ int err = 0;
|
||||
+
|
||||
+ /* Prepare bridge state message structures */
|
||||
+ br_state_msglen = sizeof(struct __mcctl_msg_header) + sizeof(struct __mc_param_value) + 32;
|
||||
+ mcctl_br_state = malloc(br_state_msglen);
|
||||
+ if (!mcctl_br_state) {
|
||||
+ my_log( LOG_ERR, errno, "Out of memory trying to allocate [%] byte(s)!", br_state_msglen );
|
||||
+ return -1;
|
||||
+ }
|
||||
+ memset(mcctl_br_state, 0, br_state_msglen);
|
||||
+ mcctl_msghdr = (struct __mcctl_msg_header *)mcctl_br_state;
|
||||
+ mcctl_msghdr->buf_len = sizeof(struct __mc_param_value);
|
||||
+ mc_param_val = (struct __mc_param_value *)(mcctl_br_state +
|
||||
+ sizeof(struct __mcctl_msg_header));
|
||||
+ if (enable)
|
||||
+ mc_param_val->val = 1;
|
||||
+ else
|
||||
+ mc_param_val->val = 0;
|
||||
+
|
||||
+ for (int i=0; i < all_brdev.num_brdev; i++) {
|
||||
+ /* enable or disable bridge */
|
||||
+ strcpy(mcctl_br_state, all_brdev.brdev[i].if_name);
|
||||
+ qca_mcs_sendmsg(mcctl_br_state, br_state_msglen, MC_MSG_SET_ENABLE);
|
||||
+ }
|
||||
+
|
||||
+ free(mcctl_br_state);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static bool qca_mcs_mcastgrp_flooded(u_int32_t mc_addr)
|
||||
+{
|
||||
+ for (int i=0; i < QCA_MCS_MAX_MCAST_GRP; i++) {
|
||||
+ if (flooded_mc_addr[i] == 0)
|
||||
+ break;
|
||||
+
|
||||
+ if (flooded_mc_addr[i] == mc_addr)
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+static void qca_mcs_add_flood_entry(u_int32_t mc_addr)
|
||||
+{
|
||||
+ for (int i=0; i < QCA_MCS_MAX_MCAST_GRP; i++) {
|
||||
+ if (flooded_mc_addr[i])
|
||||
+ continue;
|
||||
+
|
||||
+ flooded_mc_addr[i] = mc_addr;
|
||||
+ flooded_mc_addr_cnt++;
|
||||
+
|
||||
+ if (flooded_mc_addr_cnt > QCA_MCS_MAX_MCAST_GRP) {
|
||||
+ flooded_mc_addr_cnt = QCA_MCS_MAX_MCAST_GRP;
|
||||
+ my_log( LOG_WARNING, 0, "MCastAddr count is greater than buffer size! Set to max size.");
|
||||
+ }
|
||||
+
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ my_log( LOG_WARNING, 0, "Maximum[%d] multicast group flood entry reach! Unable to add more.",
|
||||
+ QCA_MCS_MAX_MCAST_GRP );
|
||||
+}
|
||||
+
|
||||
+static void qca_mcs_remove_flood_entry(u_int32_t mc_addr)
|
||||
+{
|
||||
+ bool mc_addr_found = false;
|
||||
+ int i;
|
||||
+
|
||||
+ for (i=0; i < flooded_mc_addr_cnt; i++) {
|
||||
+ if (flooded_mc_addr[i] == mc_addr) {
|
||||
+ mc_addr_found = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!mc_addr_found) {
|
||||
+ my_log( LOG_WARNING, 0, "MCastAddr[%d.%d.%d.%d] not found in multcast address list",
|
||||
+ ((char *)&mc_addr)[0], ((char *)&mc_addr)[1],
|
||||
+ ((char *)&mc_addr)[2], ((char *)&mc_addr)[3]);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ for (; i < flooded_mc_addr_cnt - 1; i++) {
|
||||
+ flooded_mc_addr[i] = flooded_mc_addr[i + 1];
|
||||
+ }
|
||||
+ flooded_mc_addr[i] = 0;
|
||||
+
|
||||
+ flooded_mc_addr_cnt--;
|
||||
+ if (flooded_mc_addr_cnt < 0) {
|
||||
+ flooded_mc_addr_cnt = 0;
|
||||
+ my_log( LOG_WARNING, 0, "MCastAddr count is negative! Reset to zero.");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Enable/disabled a multicast group to be flooded to the bridge pors
|
||||
+ * when the multicast router joins an upstream multicast group.
|
||||
+ */
|
||||
+void qca_mcs_flood_brport(u_int32_t mc_addr, bool is_join)
|
||||
+{
|
||||
+ void *mcctl_br_fldentry;
|
||||
+ struct __mcctl_msg_header *mcctl_msghdr;
|
||||
+ struct __mc_floodtbl_entry *mc_fld_entry;
|
||||
+ int br_fldentry_msglen;
|
||||
+ bool flooded = false;
|
||||
+ int err = -1;
|
||||
+
|
||||
+ flooded = qca_mcs_mcastgrp_flooded(mc_addr);
|
||||
+ if (is_join && !flooded)
|
||||
+ qca_mcs_add_flood_entry(mc_addr);
|
||||
+
|
||||
+ /* Prepare bridge state message structures */
|
||||
+ br_fldentry_msglen = sizeof(struct __mcctl_msg_header) +
|
||||
+ (sizeof(struct __mc_floodtbl_entry) * flooded_mc_addr_cnt);
|
||||
+ mcctl_br_fldentry = malloc(br_fldentry_msglen);
|
||||
+ if (!mcctl_br_fldentry) {
|
||||
+ my_log( LOG_WARNING, errno, "%s: out of memory trying to allocate [%d] byte(s)",
|
||||
+ __func__, br_fldentry_msglen );
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ memset(mcctl_br_fldentry, 0, br_fldentry_msglen);
|
||||
+ mcctl_msghdr = (struct __mcctl_msg_header *)mcctl_br_fldentry;
|
||||
+ mcctl_msghdr->buf_len = br_fldentry_msglen - sizeof(struct __mcctl_msg_header);
|
||||
+ mc_fld_entry = (struct __mc_floodtbl_entry *)(mcctl_br_fldentry +
|
||||
+ sizeof(struct __mcctl_msg_header));
|
||||
+
|
||||
+ for (int i=0; i < flooded_mc_addr_cnt; i++) {
|
||||
+ mc_fld_entry[i].group.pro = htons(0x0800); /* ETH_P_IP */
|
||||
+ mc_fld_entry[i].group.u.ip4 = flooded_mc_addr[i];
|
||||
+ }
|
||||
+
|
||||
+ for (int i=0; i < all_brdev.num_brdev; i++) {
|
||||
+ strcpy(mcctl_br_fldentry, all_brdev.brdev[i].if_name);
|
||||
+
|
||||
+ for (int fei=0; fei < flooded_mc_addr_cnt; fei++) {
|
||||
+ if (is_join || mc_fld_entry[fei].group.u.ip4 != mc_addr) {
|
||||
+ mc_fld_entry[fei].ifcnt = all_brdev.brdev[i].port_num;
|
||||
+
|
||||
+ for (int bpi=0; bpi < all_brdev.brdev[i].port_num; bpi++) {
|
||||
+ mc_fld_entry[fei].ifindex[bpi] = all_brdev.brdev[i].port_ifidx[bpi];
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ qca_mcs_sendmsg(mcctl_br_fldentry, br_fldentry_msglen, MC_MSG_SET_PSW_FLOOD);
|
||||
+ }
|
||||
+ free(mcctl_br_fldentry);
|
||||
+
|
||||
+ if (!is_join && flooded)
|
||||
+ qca_mcs_remove_flood_entry(mc_addr);
|
||||
+}
|
||||
+
|
||||
+bool qca_mcs_is_configured(void)
|
||||
+{
|
||||
+ return qca_mcs_configured;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Setup the data structure for bridge and bridge port(s)
|
||||
+ *
|
||||
+ * brdevstr - bridge and bridge port delimited string
|
||||
+ * "<bridge dev>|<bridge port 1>|<bridge port 2>|..."
|
||||
+ */
|
||||
+void qca_mcs_add_brdev(char *brdevstr)
|
||||
+{
|
||||
+ char *token;
|
||||
+ char *delimiter = "|";
|
||||
+ int curIdx, i = 0;
|
||||
+
|
||||
+ if (curIdx >= MC_DEF_IF_MAX) {
|
||||
+ my_log( LOG_ERR, 0, "Max QCA MCS bridge limit[%d] reached.", MC_DEF_IF_MAX );
|
||||
+ }
|
||||
+
|
||||
+ token = strtok(brdevstr, delimiter);
|
||||
+ strcpy(all_brdev.brdev[curIdx].if_name, token);
|
||||
+ all_brdev.brdev[curIdx].br_ifidx = if_nametoindex(token);
|
||||
+
|
||||
+ while(token = strtok(NULL, delimiter)) {
|
||||
+ all_brdev.brdev[curIdx].port_ifidx[i++] = if_nametoindex(token);
|
||||
+ if (i >= MC_DEF_IF_MAX) {
|
||||
+ my_log( LOG_ERR, 0, "Max QCA MCS bridge port limit[%d] reached.", MC_DEF_IF_MAX );
|
||||
+ }
|
||||
+ }
|
||||
+ all_brdev.brdev[curIdx].port_num = i;
|
||||
+ all_brdev.num_brdev++;
|
||||
+ qca_mcs_configured = true;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Start QCA MCS support.
|
||||
+ */
|
||||
+void qca_mcs_start(void)
|
||||
+{
|
||||
+ if (!qca_mcs_configured) {
|
||||
+ my_log( LOG_WARNING, 0, "QCA MCS bridges not configured. Unable to enable QCA MCS support." );
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ mcsNlFd = socket(AF_NETLINK, SOCK_RAW, NETLINK_QCA_MC);
|
||||
+ if ( mcsNlFd < 0 ) {
|
||||
+ my_log( LOG_ERR, errno, "NETLINK_QCA_MC socket open" );
|
||||
+ }
|
||||
+
|
||||
+ qca_mcs_brdev_state(true);
|
||||
+ my_log( LOG_NOTICE, 0, "QCA MCS support enabled." );
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Stop QCA MCS support.
|
||||
+ */
|
||||
+void qca_mcs_stop(void)
|
||||
+{
|
||||
+ qca_mcs_configured = false;
|
||||
+
|
||||
+ qca_mcs_brdev_state(false);
|
||||
+ my_log( LOG_NOTICE, 0, "QCA MCS support disabled." );
|
||||
+
|
||||
+ if ( mcsNlFd > 0 )
|
||||
+ close(mcsNlFd);
|
||||
+}
|
||||
--- a/src/Makefile.am
|
||||
+++ b/src/Makefile.am
|
||||
@@ -21,4 +21,5 @@ igmpproxy_SOURCES = \
|
||||
request.c \
|
||||
rttable.c \
|
||||
syslog.c \
|
||||
- udpsock.c
|
||||
+ udpsock.c \
|
||||
+ qca-mcs.c
|
Loading…
Reference in New Issue
Block a user