mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-16 04:13:31 +00:00
616 lines
19 KiB
Diff
616 lines
19 KiB
Diff
--- a/include/linux/if_bridge.h
|
|
+++ b/include/linux/if_bridge.h
|
|
@@ -69,6 +69,9 @@ void brioctl_set(int (*hook)(struct net
|
|
void __user *uarg));
|
|
int br_ioctl_call(struct net *net, struct net_bridge *br, unsigned int cmd,
|
|
struct ifreq *ifr, void __user *uarg);
|
|
+extern void br_dev_update_stats(struct net_device *dev,
|
|
+ struct rtnl_link_stats64 *nlstats);
|
|
+extern bool br_is_hairpin_enabled(struct net_device *dev);
|
|
|
|
extern void br_dev_update_stats(struct net_device *dev,
|
|
struct rtnl_link_stats64 *nlstats);
|
|
@@ -195,4 +198,42 @@ static inline clock_t br_get_ageing_time
|
|
}
|
|
#endif
|
|
|
|
+/* QCA NSS ECM support - Start */
|
|
+extern struct net_device *br_port_dev_get(struct net_device *dev,
|
|
+ unsigned char *addr,
|
|
+ struct sk_buff *skb,
|
|
+ unsigned int cookie);
|
|
+extern void br_refresh_fdb_entry(struct net_device *dev, const char *addr);
|
|
+extern void br_fdb_entry_refresh(struct net_device *dev, const char *addr, __u16 vid);
|
|
+extern struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev,
|
|
+ const char *addr,
|
|
+ __u16 vid);
|
|
+extern void br_fdb_update_register_notify(struct notifier_block *nb);
|
|
+extern void br_fdb_update_unregister_notify(struct notifier_block *nb);
|
|
+
|
|
+typedef struct net_bridge_port *br_port_dev_get_hook_t(struct net_device *dev,
|
|
+ struct sk_buff *skb,
|
|
+ unsigned char *addr,
|
|
+ unsigned int cookie);
|
|
+extern br_port_dev_get_hook_t __rcu *br_port_dev_get_hook;
|
|
+
|
|
+#define BR_FDB_EVENT_ADD 0x01
|
|
+#define BR_FDB_EVENT_DEL 0x02
|
|
+
|
|
+struct br_fdb_event {
|
|
+ struct net_device *dev;
|
|
+ unsigned char addr[6];
|
|
+ unsigned char is_local;
|
|
+ struct net_bridge *br;
|
|
+ struct net_device *orig_dev;
|
|
+};
|
|
+extern void br_fdb_register_notify(struct notifier_block *nb);
|
|
+extern void br_fdb_unregister_notify(struct notifier_block *nb);
|
|
+
|
|
+typedef struct net_bridge_port *br_get_dst_hook_t(
|
|
+ const struct net_bridge_port *src,
|
|
+ struct sk_buff **skb);
|
|
+extern br_get_dst_hook_t __rcu *br_get_dst_hook;
|
|
+/* QCA NSS ECM support - End */
|
|
+
|
|
#endif
|
|
--- a/include/linux/if_vlan.h
|
|
+++ b/include/linux/if_vlan.h
|
|
@@ -230,7 +230,28 @@ extern void vlan_vids_del_by_dev(struct
|
|
|
|
extern bool vlan_uses_dev(const struct net_device *dev);
|
|
|
|
+/* QCA NSS ECM support - Start */
|
|
+extern void __vlan_dev_update_accel_stats(struct net_device *dev,
|
|
+ struct rtnl_link_stats64 *stats);
|
|
+extern u16 vlan_dev_get_egress_prio(struct net_device *dev, u32 skb_prio);
|
|
+extern struct net_device *vlan_dev_next_dev(const struct net_device *dev);
|
|
+/* QCA NSS ECM support - End */
|
|
+
|
|
#else
|
|
+/* QCA NSS ECM support - Start */
|
|
+static inline void __vlan_dev_update_accel_stats(struct net_device *dev,
|
|
+ struct rtnl_link_stats64 *stats)
|
|
+{
|
|
+
|
|
+}
|
|
+
|
|
+static inline u16 vlan_dev_get_egress_prio(struct net_device *dev,
|
|
+ u32 skb_prio)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+/* QCA NSS ECM support - End */
|
|
+
|
|
static inline struct net_device *
|
|
__vlan_find_dev_deep_rcu(struct net_device *real_dev,
|
|
__be16 vlan_proto, u16 vlan_id)
|
|
--- a/include/linux/netdevice.h
|
|
+++ b/include/linux/netdevice.h
|
|
@@ -2857,6 +2857,10 @@ enum netdev_cmd {
|
|
NETDEV_CVLAN_FILTER_DROP_INFO,
|
|
NETDEV_SVLAN_FILTER_PUSH_INFO,
|
|
NETDEV_SVLAN_FILTER_DROP_INFO,
|
|
+ /* QCA NSS ECM Support - Start */
|
|
+ NETDEV_BR_JOIN,
|
|
+ NETDEV_BR_LEAVE,
|
|
+ /* QCA NSS ECM Support - End */
|
|
};
|
|
const char *netdev_cmd_to_name(enum netdev_cmd cmd);
|
|
|
|
--- a/include/net/ip6_route.h
|
|
+++ b/include/net/ip6_route.h
|
|
@@ -211,6 +211,11 @@ void rt6_multipath_rebalance(struct fib6
|
|
void rt6_uncached_list_add(struct rt6_info *rt);
|
|
void rt6_uncached_list_del(struct rt6_info *rt);
|
|
|
|
+/* QCA NSS ECM support - Start */
|
|
+int rt6_register_notifier(struct notifier_block *nb);
|
|
+int rt6_unregister_notifier(struct notifier_block *nb);
|
|
+/* QCA NSS ECM support - End */
|
|
+
|
|
static inline const struct rt6_info *skb_rt6_info(const struct sk_buff *skb)
|
|
{
|
|
const struct dst_entry *dst = skb_dst(skb);
|
|
--- a/include/net/neighbour.h
|
|
+++ b/include/net/neighbour.h
|
|
@@ -567,4 +567,15 @@ static inline void neigh_update_is_route
|
|
*notify = 1;
|
|
}
|
|
}
|
|
+
|
|
+/* QCA NSS ECM support - Start */
|
|
+struct neigh_mac_update {
|
|
+ unsigned char old_mac[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))];
|
|
+ unsigned char update_mac[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))];
|
|
+};
|
|
+
|
|
+extern void neigh_mac_update_register_notify(struct notifier_block *nb);
|
|
+extern void neigh_mac_update_unregister_notify(struct notifier_block *nb);
|
|
+/* QCA NSS ECM support - End */
|
|
+
|
|
#endif
|
|
--- a/include/net/route.h
|
|
+++ b/include/net/route.h
|
|
@@ -234,6 +234,11 @@ struct rtable *rt_dst_alloc(struct net_d
|
|
bool nopolicy, bool noxfrm);
|
|
struct rtable *rt_dst_clone(struct net_device *dev, struct rtable *rt);
|
|
|
|
+/* QCA NSS ECM support - Start */
|
|
+int ip_rt_register_notifier(struct notifier_block *nb);
|
|
+int ip_rt_unregister_notifier(struct notifier_block *nb);
|
|
+/* QCA NSS ECM support - End */
|
|
+
|
|
struct in_ifaddr;
|
|
void fib_add_ifaddr(struct in_ifaddr *);
|
|
void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *);
|
|
--- a/net/bridge/br_fdb.c
|
|
+++ b/net/bridge/br_fdb.c
|
|
@@ -38,6 +38,35 @@ static int fdb_insert(struct net_bridge
|
|
static void fdb_notify(struct net_bridge *br,
|
|
const struct net_bridge_fdb_entry *, int, bool);
|
|
|
|
+/* QCA NSS ECM support - Start */
|
|
+ATOMIC_NOTIFIER_HEAD(br_fdb_notifier_list);
|
|
+ATOMIC_NOTIFIER_HEAD(br_fdb_update_notifier_list);
|
|
+
|
|
+void br_fdb_register_notify(struct notifier_block *nb)
|
|
+{
|
|
+ atomic_notifier_chain_register(&br_fdb_notifier_list, nb);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(br_fdb_register_notify);
|
|
+
|
|
+void br_fdb_unregister_notify(struct notifier_block *nb)
|
|
+{
|
|
+ atomic_notifier_chain_unregister(&br_fdb_notifier_list, nb);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(br_fdb_unregister_notify);
|
|
+
|
|
+void br_fdb_update_register_notify(struct notifier_block *nb)
|
|
+{
|
|
+ atomic_notifier_chain_register(&br_fdb_update_notifier_list, nb);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(br_fdb_update_register_notify);
|
|
+
|
|
+void br_fdb_update_unregister_notify(struct notifier_block *nb)
|
|
+{
|
|
+ atomic_notifier_chain_unregister(&br_fdb_update_notifier_list, nb);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(br_fdb_update_unregister_notify);
|
|
+/* QCA NSS ECM support - End */
|
|
+
|
|
int __init br_fdb_init(void)
|
|
{
|
|
br_fdb_cache = kmem_cache_create("bridge_fdb_cache",
|
|
@@ -343,6 +372,7 @@ void br_fdb_cleanup(struct work_struct *
|
|
unsigned long delay = hold_time(br);
|
|
unsigned long work_delay = delay;
|
|
unsigned long now = jiffies;
|
|
+ u8 mac_addr[6]; /* QCA NSS ECM support */
|
|
|
|
/* this part is tricky, in order to avoid blocking learning and
|
|
* consequently forwarding, we rely on rcu to delete objects with
|
|
@@ -369,8 +399,15 @@ void br_fdb_cleanup(struct work_struct *
|
|
work_delay = min(work_delay, this_timer - now);
|
|
} else {
|
|
spin_lock_bh(&br->hash_lock);
|
|
- if (!hlist_unhashed(&f->fdb_node))
|
|
+ if (!hlist_unhashed(&f->fdb_node)) {
|
|
+ ether_addr_copy(mac_addr, f->key.addr.addr);
|
|
fdb_delete(br, f, true);
|
|
+ /* QCA NSS ECM support - Start */
|
|
+ atomic_notifier_call_chain(
|
|
+ &br_fdb_update_notifier_list, 0,
|
|
+ (void *)mac_addr);
|
|
+ /* QCA NSS ECM support - End */
|
|
+ }
|
|
spin_unlock_bh(&br->hash_lock);
|
|
}
|
|
}
|
|
@@ -618,6 +655,12 @@ void br_fdb_update(struct net_bridge *br
|
|
&fdb->flags)))
|
|
clear_bit(BR_FDB_ADDED_BY_EXT_LEARN,
|
|
&fdb->flags);
|
|
+
|
|
+ /* QCA NSS ECM support - Start */
|
|
+ atomic_notifier_call_chain(
|
|
+ &br_fdb_update_notifier_list,
|
|
+ 0, (void *)addr);
|
|
+ /* QCA NSS ECM support - End */
|
|
}
|
|
|
|
if (unlikely(test_bit(BR_FDB_ADDED_BY_USER, &flags)))
|
|
@@ -799,6 +842,25 @@ static void fdb_notify(struct net_bridge
|
|
|
|
br_offload_fdb_update(fdb);
|
|
|
|
+ /* QCA NSS ECM support - Start */
|
|
+ if (fdb->dst) {
|
|
+ int event;
|
|
+ struct br_fdb_event fdb_event;
|
|
+
|
|
+ if (type == RTM_NEWNEIGH)
|
|
+ event = BR_FDB_EVENT_ADD;
|
|
+ else
|
|
+ event = BR_FDB_EVENT_DEL;
|
|
+
|
|
+ fdb_event.dev = fdb->dst->dev;
|
|
+ ether_addr_copy(fdb_event.addr, fdb->key.addr.addr);
|
|
+ fdb_event.is_local = test_bit(BR_FDB_LOCAL, &fdb->flags);
|
|
+ atomic_notifier_call_chain(&br_fdb_notifier_list,
|
|
+ event,
|
|
+ (void *)&fdb_event);
|
|
+ }
|
|
+ /* QCA NSS ECM support - End */
|
|
+
|
|
if (swdev_notify)
|
|
br_switchdev_fdb_notify(br, fdb, type);
|
|
|
|
@@ -1382,3 +1444,62 @@ void br_fdb_clear_offload(const struct n
|
|
spin_unlock_bh(&p->br->hash_lock);
|
|
}
|
|
EXPORT_SYMBOL_GPL(br_fdb_clear_offload);
|
|
+
|
|
+/* QCA NSS ECM support - Start */
|
|
+/* Refresh FDB entries for bridge packets being forwarded by offload engines */
|
|
+void br_refresh_fdb_entry(struct net_device *dev, const char *addr)
|
|
+{
|
|
+ struct net_bridge_port *p = br_port_get_rcu(dev);
|
|
+
|
|
+ if (!p || p->state == BR_STATE_DISABLED)
|
|
+ return;
|
|
+
|
|
+ if (!is_valid_ether_addr(addr)) {
|
|
+ pr_info("bridge: Attempt to refresh with invalid ether address %pM\n",
|
|
+ addr);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ rcu_read_lock();
|
|
+ br_fdb_update(p->br, p, addr, 0, true);
|
|
+ rcu_read_unlock();
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(br_refresh_fdb_entry);
|
|
+
|
|
+/* Update timestamp of FDB entries for bridge packets being forwarded by offload engines */
|
|
+void br_fdb_entry_refresh(struct net_device *dev, const char *addr, __u16 vid)
|
|
+{
|
|
+ struct net_bridge_fdb_entry *fdb;
|
|
+ struct net_bridge_port *p = br_port_get_rcu(dev);
|
|
+
|
|
+ if (!p || p->state == BR_STATE_DISABLED)
|
|
+ return;
|
|
+
|
|
+ rcu_read_lock();
|
|
+ fdb = fdb_find_rcu(&p->br->fdb_hash_tbl, addr, vid);
|
|
+ if (likely(fdb)) {
|
|
+ fdb->updated = jiffies;
|
|
+ }
|
|
+ rcu_read_unlock();
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(br_fdb_entry_refresh);
|
|
+
|
|
+/* Look up the MAC address in the device's bridge fdb table */
|
|
+struct net_bridge_fdb_entry *br_fdb_has_entry(struct net_device *dev,
|
|
+ const char *addr, __u16 vid)
|
|
+{
|
|
+ struct net_bridge_port *p = br_port_get_rcu(dev);
|
|
+ struct net_bridge_fdb_entry *fdb;
|
|
+
|
|
+ if (!p || p->state == BR_STATE_DISABLED)
|
|
+ return NULL;
|
|
+
|
|
+ rcu_read_lock();
|
|
+ fdb = fdb_find_rcu(&p->br->fdb_hash_tbl, addr, vid);
|
|
+ rcu_read_unlock();
|
|
+
|
|
+ return fdb;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(br_fdb_has_entry);
|
|
+/* QCA NSS ECM support - End */
|
|
+
|
|
--- a/net/bridge/br_if.c
|
|
+++ b/net/bridge/br_if.c
|
|
@@ -27,6 +27,12 @@
|
|
#include "br_private.h"
|
|
#include "br_private_offload.h"
|
|
|
|
+/* QCA NSS ECM support - Start */
|
|
+/* Hook for external forwarding logic */
|
|
+br_port_dev_get_hook_t __rcu *br_port_dev_get_hook __read_mostly;
|
|
+EXPORT_SYMBOL_GPL(br_port_dev_get_hook);
|
|
+/* QCA NSS ECM support - End */
|
|
+
|
|
/*
|
|
* Determine initial path cost based on speed.
|
|
* using recommendations from 802.1d standard
|
|
@@ -708,6 +714,8 @@ int br_add_if(struct net_bridge *br, str
|
|
|
|
kobject_uevent(&p->kobj, KOBJ_ADD);
|
|
|
|
+ call_netdevice_notifiers(NETDEV_BR_JOIN, dev); /* QCA NSS ECM support */
|
|
+
|
|
return 0;
|
|
|
|
err6:
|
|
@@ -743,6 +751,8 @@ int br_del_if(struct net_bridge *br, str
|
|
if (!p || p->br != br)
|
|
return -EINVAL;
|
|
|
|
+ call_netdevice_notifiers(NETDEV_BR_LEAVE, dev); /* QCA NSS ECM support */
|
|
+
|
|
/* Since more than one interface can be attached to a bridge,
|
|
* there still maybe an alternate path for netconsole to use;
|
|
* therefore there is no reason for a NETDEV_RELEASE event.
|
|
@@ -811,3 +821,74 @@ bool br_port_flag_is_set(const struct ne
|
|
return p->flags & flag;
|
|
}
|
|
EXPORT_SYMBOL_GPL(br_port_flag_is_set);
|
|
+
|
|
+/* API to know if hairpin feature is enabled/disabled on this bridge port */
|
|
+bool br_is_hairpin_enabled(struct net_device *dev)
|
|
+{
|
|
+ struct net_bridge_port *port = br_port_get_check_rcu(dev);
|
|
+
|
|
+ if (likely(port))
|
|
+ return port->flags & BR_HAIRPIN_MODE;
|
|
+ return false;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(br_is_hairpin_enabled);
|
|
+
|
|
+/* br_port_dev_get()
|
|
+ * If a skb is provided, and the br_port_dev_get_hook_t hook exists,
|
|
+ * use that to try and determine the egress port for that skb.
|
|
+ * If not, or no egress port could be determined, use the given addr
|
|
+ * to identify the port to which it is reachable,
|
|
+ * returing a reference to the net device associated with that port.
|
|
+ *
|
|
+ * NOTE: Return NULL if given dev is not a bridge or the mac has no
|
|
+ * associated port.
|
|
+ */
|
|
+struct net_device *br_port_dev_get(struct net_device *dev, unsigned char *addr,
|
|
+ struct sk_buff *skb,
|
|
+ unsigned int cookie)
|
|
+{
|
|
+ struct net_bridge_fdb_entry *fdbe;
|
|
+ struct net_bridge *br;
|
|
+ struct net_device *netdev = NULL;
|
|
+
|
|
+ /* Is this a bridge? */
|
|
+ if (!(dev->priv_flags & IFF_EBRIDGE))
|
|
+ return NULL;
|
|
+
|
|
+ rcu_read_lock();
|
|
+
|
|
+ /* If the hook exists and the skb isn't NULL, try and get the port */
|
|
+ if (skb) {
|
|
+ br_port_dev_get_hook_t *port_dev_get_hook;
|
|
+
|
|
+ port_dev_get_hook = rcu_dereference(br_port_dev_get_hook);
|
|
+ if (port_dev_get_hook) {
|
|
+ struct net_bridge_port *pdst =
|
|
+ __br_get(port_dev_get_hook, NULL, dev, skb,
|
|
+ addr, cookie);
|
|
+ if (pdst) {
|
|
+ dev_hold(pdst->dev);
|
|
+ netdev = pdst->dev;
|
|
+ goto out;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Either there is no hook, or can't
|
|
+ * determine the port to use - fall back to using FDB
|
|
+ */
|
|
+
|
|
+ br = netdev_priv(dev);
|
|
+
|
|
+ /* Lookup the fdb entry and get reference to the port dev */
|
|
+ fdbe = br_fdb_find_rcu(br, addr, 0);
|
|
+ if (fdbe && fdbe->dst) {
|
|
+ netdev = fdbe->dst->dev; /* port device */
|
|
+ dev_hold(netdev);
|
|
+ }
|
|
+out:
|
|
+ rcu_read_unlock();
|
|
+ return netdev;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(br_port_dev_get);
|
|
+/* QCA NSS ECM support - End */
|
|
--- a/net/bridge/br_private.h
|
|
+++ b/net/bridge/br_private.h
|
|
@@ -2122,4 +2122,9 @@ void br_do_proxy_suppress_arp(struct sk_
|
|
void br_do_suppress_nd(struct sk_buff *skb, struct net_bridge *br,
|
|
u16 vid, struct net_bridge_port *p, struct nd_msg *msg);
|
|
struct nd_msg *br_is_nd_neigh_msg(struct sk_buff *skb, struct nd_msg *m);
|
|
+
|
|
+/* QCA NSS ECM support - Start */
|
|
+#define __br_get(__hook, __default, __args ...) \
|
|
+ (__hook ? (__hook(__args)) : (__default))
|
|
+/* QCA NSS ECM support - End */
|
|
#endif
|
|
--- a/net/core/neighbour.c
|
|
+++ b/net/core/neighbour.c
|
|
@@ -1211,7 +1211,21 @@ static void neigh_update_hhs(struct neig
|
|
}
|
|
}
|
|
|
|
+/* QCA NSS ECM support - start */
|
|
+ATOMIC_NOTIFIER_HEAD(neigh_mac_update_notifier_list);
|
|
+
|
|
+void neigh_mac_update_register_notify(struct notifier_block *nb)
|
|
+{
|
|
+ atomic_notifier_chain_register(&neigh_mac_update_notifier_list, nb);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(neigh_mac_update_register_notify);
|
|
|
|
+void neigh_mac_update_unregister_notify(struct notifier_block *nb)
|
|
+{
|
|
+ atomic_notifier_chain_unregister(&neigh_mac_update_notifier_list, nb);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(neigh_mac_update_unregister_notify);
|
|
+/* QCA NSS ECM support - End */
|
|
|
|
/* Generic update routine.
|
|
-- lladdr is new lladdr or NULL, if it is not supplied.
|
|
@@ -1242,6 +1256,7 @@ static int __neigh_update(struct neighbo
|
|
int notify = 0;
|
|
struct net_device *dev;
|
|
int update_isrouter = 0;
|
|
+ struct neigh_mac_update nmu; /* QCA NSS ECM support */
|
|
|
|
trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid);
|
|
|
|
@@ -1256,6 +1271,8 @@ static int __neigh_update(struct neighbo
|
|
new = old;
|
|
goto out;
|
|
}
|
|
+ memset(&nmu, 0, sizeof(struct neigh_mac_update)); /* QCA NSS ECM support */
|
|
+
|
|
if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
|
|
(old & (NUD_NOARP | NUD_PERMANENT)))
|
|
goto out;
|
|
@@ -1293,6 +1310,11 @@ static int __neigh_update(struct neighbo
|
|
- compare new & old
|
|
- if they are different, check override flag
|
|
*/
|
|
+ /* QCA NSS ECM update - Start */
|
|
+ memcpy(nmu.old_mac, neigh->ha, dev->addr_len);
|
|
+ memcpy(nmu.update_mac, lladdr, dev->addr_len);
|
|
+ /* QCA NSS ECM update - End */
|
|
+
|
|
if ((old & NUD_VALID) &&
|
|
!memcmp(lladdr, neigh->ha, dev->addr_len))
|
|
lladdr = neigh->ha;
|
|
@@ -1415,8 +1437,11 @@ out:
|
|
if (((new ^ old) & NUD_PERMANENT) || ext_learn_change)
|
|
neigh_update_gc_list(neigh);
|
|
|
|
- if (notify)
|
|
+ if (notify) {
|
|
neigh_update_notify(neigh, nlmsg_pid);
|
|
+ atomic_notifier_call_chain(&neigh_mac_update_notifier_list, 0,
|
|
+ (struct neigh_mac_update *)&nmu); /* QCA NSS ECM support */
|
|
+ }
|
|
|
|
trace_neigh_update_done(neigh, err);
|
|
|
|
--- a/net/ipv4/fib_trie.c
|
|
+++ b/net/ipv4/fib_trie.c
|
|
@@ -1206,6 +1206,9 @@ static bool fib_valid_key_len(u32 key, u
|
|
static void fib_remove_alias(struct trie *t, struct key_vector *tp,
|
|
struct key_vector *l, struct fib_alias *old);
|
|
|
|
+/* Define route change notification chain. */
|
|
+static BLOCKING_NOTIFIER_HEAD(iproute_chain); /* QCA NSS ECM support */
|
|
+
|
|
/* Caller must hold RTNL. */
|
|
int fib_table_insert(struct net *net, struct fib_table *tb,
|
|
struct fib_config *cfg, struct netlink_ext_ack *extack)
|
|
@@ -1398,6 +1401,9 @@ int fib_table_insert(struct net *net, st
|
|
rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, new_fa->tb_id,
|
|
&cfg->fc_nlinfo, nlflags);
|
|
succeeded:
|
|
+ blocking_notifier_call_chain(&iproute_chain,
|
|
+ RTM_NEWROUTE, fi);
|
|
+
|
|
return 0;
|
|
|
|
out_remove_new_fa:
|
|
@@ -1769,6 +1775,9 @@ int fib_table_delete(struct net *net, st
|
|
if (fa_to_delete->fa_state & FA_S_ACCESSED)
|
|
rt_cache_flush(cfg->fc_nlinfo.nl_net);
|
|
|
|
+ blocking_notifier_call_chain(&iproute_chain,
|
|
+ RTM_DELROUTE, fa_to_delete->fa_info);
|
|
+
|
|
fib_release_info(fa_to_delete->fa_info);
|
|
alias_free_mem_rcu(fa_to_delete);
|
|
return 0;
|
|
@@ -2401,6 +2410,20 @@ void __init fib_trie_init(void)
|
|
0, SLAB_PANIC | SLAB_ACCOUNT, NULL);
|
|
}
|
|
|
|
+/* QCA NSS ECM support - Start */
|
|
+int ip_rt_register_notifier(struct notifier_block *nb)
|
|
+{
|
|
+ return blocking_notifier_chain_register(&iproute_chain, nb);
|
|
+}
|
|
+EXPORT_SYMBOL(ip_rt_register_notifier);
|
|
+
|
|
+int ip_rt_unregister_notifier(struct notifier_block *nb)
|
|
+{
|
|
+ return blocking_notifier_chain_unregister(&iproute_chain, nb);
|
|
+}
|
|
+EXPORT_SYMBOL(ip_rt_unregister_notifier);
|
|
+/* QCA NSS ECM support - End */
|
|
+
|
|
struct fib_table *fib_trie_table(u32 id, struct fib_table *alias)
|
|
{
|
|
struct fib_table *tb;
|
|
--- a/include/net/addrconf.h
|
|
+++ b/include/net/addrconf.h
|
|
@@ -512,4 +512,9 @@ int if6_proc_init(void);
|
|
void if6_proc_exit(void);
|
|
#endif
|
|
|
|
+/* QCA NSS ECM support - Start */
|
|
+struct net_device *ipv6_dev_find_and_hold(struct net *net, struct in6_addr *addr,
|
|
+ int strict);
|
|
+/* QCA NSS ECM support - End */
|
|
+
|
|
#endif
|
|
--- a/net/ipv6/route.c
|
|
+++ b/net/ipv6/route.c
|
|
@@ -3875,6 +3875,9 @@ out_free:
|
|
return ERR_PTR(err);
|
|
}
|
|
|
|
+/* Define route change notification chain. */
|
|
+ATOMIC_NOTIFIER_HEAD(ip6route_chain); /* QCA NSS ECM support */
|
|
+
|
|
int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
|
|
struct netlink_ext_ack *extack)
|
|
{
|
|
@@ -3886,6 +3889,10 @@ int ip6_route_add(struct fib6_config *cf
|
|
return PTR_ERR(rt);
|
|
|
|
err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack);
|
|
+ if (!err)
|
|
+ atomic_notifier_call_chain(&ip6route_chain,
|
|
+ RTM_NEWROUTE, rt);
|
|
+
|
|
fib6_info_release(rt);
|
|
|
|
return err;
|
|
@@ -3907,6 +3914,9 @@ static int __ip6_del_rt(struct fib6_info
|
|
err = fib6_del(rt, info);
|
|
spin_unlock_bh(&table->tb6_lock);
|
|
|
|
+ if (!err)
|
|
+ atomic_notifier_call_chain(&ip6route_chain,
|
|
+ RTM_DELROUTE, rt);
|
|
out:
|
|
fib6_info_release(rt);
|
|
return err;
|
|
@@ -6350,6 +6360,20 @@ static int ip6_route_dev_notify(struct n
|
|
return NOTIFY_OK;
|
|
}
|
|
|
|
+/* QCA NSS ECM support - Start */
|
|
+int rt6_register_notifier(struct notifier_block *nb)
|
|
+{
|
|
+ return atomic_notifier_chain_register(&ip6route_chain, nb);
|
|
+}
|
|
+EXPORT_SYMBOL(rt6_register_notifier);
|
|
+
|
|
+int rt6_unregister_notifier(struct notifier_block *nb)
|
|
+{
|
|
+ return atomic_notifier_chain_unregister(&ip6route_chain, nb);
|
|
+}
|
|
+EXPORT_SYMBOL(rt6_unregister_notifier);
|
|
+/* QCA NSS ECM support - End */
|
|
+
|
|
/*
|
|
* /proc
|
|
*/
|