aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/uapi/linux/mroute.h4
-rw-r--r--include/uapi/linux/mroute6.h4
-rw-r--r--net/ipv4/ipmr.c119
-rw-r--r--net/ipv6/ip6mr.c126
4 files changed, 225 insertions, 28 deletions
diff --git a/include/uapi/linux/mroute.h b/include/uapi/linux/mroute.h
index 1c11004af5db..a382d2c04a42 100644
--- a/include/uapi/linux/mroute.h
+++ b/include/uapi/linux/mroute.h
@@ -26,7 +26,9 @@
26#define MRT_ASSERT (MRT_BASE+7) /* Activate PIM assert mode */ 26#define MRT_ASSERT (MRT_BASE+7) /* Activate PIM assert mode */
27#define MRT_PIM (MRT_BASE+8) /* enable PIM code */ 27#define MRT_PIM (MRT_BASE+8) /* enable PIM code */
28#define MRT_TABLE (MRT_BASE+9) /* Specify mroute table ID */ 28#define MRT_TABLE (MRT_BASE+9) /* Specify mroute table ID */
29#define MRT_MAX (MRT_BASE+9) 29#define MRT_ADD_MFC_PROXY (MRT_BASE+10) /* Add a (*,*|G) mfc entry */
30#define MRT_DEL_MFC_PROXY (MRT_BASE+11) /* Del a (*,*|G) mfc entry */
31#define MRT_MAX (MRT_BASE+11)
30 32
31#define SIOCGETVIFCNT SIOCPROTOPRIVATE /* IP protocol privates */ 33#define SIOCGETVIFCNT SIOCPROTOPRIVATE /* IP protocol privates */
32#define SIOCGETSGCNT (SIOCPROTOPRIVATE+1) 34#define SIOCGETSGCNT (SIOCPROTOPRIVATE+1)
diff --git a/include/uapi/linux/mroute6.h b/include/uapi/linux/mroute6.h
index c206ae3a2327..ce91215cf7e6 100644
--- a/include/uapi/linux/mroute6.h
+++ b/include/uapi/linux/mroute6.h
@@ -26,7 +26,9 @@
26#define MRT6_ASSERT (MRT6_BASE+7) /* Activate PIM assert mode */ 26#define MRT6_ASSERT (MRT6_BASE+7) /* Activate PIM assert mode */
27#define MRT6_PIM (MRT6_BASE+8) /* enable PIM code */ 27#define MRT6_PIM (MRT6_BASE+8) /* enable PIM code */
28#define MRT6_TABLE (MRT6_BASE+9) /* Specify mroute table ID */ 28#define MRT6_TABLE (MRT6_BASE+9) /* Specify mroute table ID */
29#define MRT6_MAX (MRT6_BASE+9) 29#define MRT6_ADD_MFC_PROXY (MRT6_BASE+10) /* Add a (*,*|G) mfc entry */
30#define MRT6_DEL_MFC_PROXY (MRT6_BASE+11) /* Del a (*,*|G) mfc entry */
31#define MRT6_MAX (MRT6_BASE+11)
30 32
31#define SIOCGETMIFCNT_IN6 SIOCPROTOPRIVATE /* IP protocol privates */ 33#define SIOCGETMIFCNT_IN6 SIOCPROTOPRIVATE /* IP protocol privates */
32#define SIOCGETSGCNT_IN6 (SIOCPROTOPRIVATE+1) 34#define SIOCGETSGCNT_IN6 (SIOCPROTOPRIVATE+1)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index a9454cbd953c..4b5e22670d44 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -828,6 +828,49 @@ static struct mfc_cache *ipmr_cache_find(struct mr_table *mrt,
828 return NULL; 828 return NULL;
829} 829}
830 830
831/* Look for a (*,*,oif) entry */
832static struct mfc_cache *ipmr_cache_find_any_parent(struct mr_table *mrt,
833 int vifi)
834{
835 int line = MFC_HASH(INADDR_ANY, INADDR_ANY);
836 struct mfc_cache *c;
837
838 list_for_each_entry_rcu(c, &mrt->mfc_cache_array[line], list)
839 if (c->mfc_origin == INADDR_ANY &&
840 c->mfc_mcastgrp == INADDR_ANY &&
841 c->mfc_un.res.ttls[vifi] < 255)
842 return c;
843
844 return NULL;
845}
846
847/* Look for a (*,G) entry */
848static struct mfc_cache *ipmr_cache_find_any(struct mr_table *mrt,
849 __be32 mcastgrp, int vifi)
850{
851 int line = MFC_HASH(mcastgrp, INADDR_ANY);
852 struct mfc_cache *c, *proxy;
853
854 if (mcastgrp == INADDR_ANY)
855 goto skip;
856
857 list_for_each_entry_rcu(c, &mrt->mfc_cache_array[line], list)
858 if (c->mfc_origin == INADDR_ANY &&
859 c->mfc_mcastgrp == mcastgrp) {
860 if (c->mfc_un.res.ttls[vifi] < 255)
861 return c;
862
863 /* It's ok if the vifi is part of the static tree */
864 proxy = ipmr_cache_find_any_parent(mrt,
865 c->mfc_parent);
866 if (proxy && proxy->mfc_un.res.ttls[vifi] < 255)
867 return c;
868 }
869
870skip:
871 return ipmr_cache_find_any_parent(mrt, vifi);
872}
873
831/* 874/*
832 * Allocate a multicast cache entry 875 * Allocate a multicast cache entry
833 */ 876 */
@@ -1053,7 +1096,7 @@ ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb)
1053 * MFC cache manipulation by user space mroute daemon 1096 * MFC cache manipulation by user space mroute daemon
1054 */ 1097 */
1055 1098
1056static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc) 1099static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc, int parent)
1057{ 1100{
1058 int line; 1101 int line;
1059 struct mfc_cache *c, *next; 1102 struct mfc_cache *c, *next;
@@ -1062,7 +1105,8 @@ static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc)
1062 1105
1063 list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[line], list) { 1106 list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[line], list) {
1064 if (c->mfc_origin == mfc->mfcc_origin.s_addr && 1107 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
1065 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) { 1108 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr &&
1109 (parent == -1 || parent == c->mfc_parent)) {
1066 list_del_rcu(&c->list); 1110 list_del_rcu(&c->list);
1067 mroute_netlink_event(mrt, c, RTM_DELROUTE); 1111 mroute_netlink_event(mrt, c, RTM_DELROUTE);
1068 ipmr_cache_free(c); 1112 ipmr_cache_free(c);
@@ -1073,7 +1117,7 @@ static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc)
1073} 1117}
1074 1118
1075static int ipmr_mfc_add(struct net *net, struct mr_table *mrt, 1119static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
1076 struct mfcctl *mfc, int mrtsock) 1120 struct mfcctl *mfc, int mrtsock, int parent)
1077{ 1121{
1078 bool found = false; 1122 bool found = false;
1079 int line; 1123 int line;
@@ -1086,7 +1130,8 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
1086 1130
1087 list_for_each_entry(c, &mrt->mfc_cache_array[line], list) { 1131 list_for_each_entry(c, &mrt->mfc_cache_array[line], list) {
1088 if (c->mfc_origin == mfc->mfcc_origin.s_addr && 1132 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
1089 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) { 1133 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr &&
1134 (parent == -1 || parent == c->mfc_parent)) {
1090 found = true; 1135 found = true;
1091 break; 1136 break;
1092 } 1137 }
@@ -1103,7 +1148,8 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
1103 return 0; 1148 return 0;
1104 } 1149 }
1105 1150
1106 if (!ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr)) 1151 if (mfc->mfcc_mcastgrp.s_addr != INADDR_ANY &&
1152 !ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
1107 return -EINVAL; 1153 return -EINVAL;
1108 1154
1109 c = ipmr_cache_alloc(); 1155 c = ipmr_cache_alloc();
@@ -1218,7 +1264,7 @@ static void mrtsock_destruct(struct sock *sk)
1218 1264
1219int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) 1265int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
1220{ 1266{
1221 int ret; 1267 int ret, parent = 0;
1222 struct vifctl vif; 1268 struct vifctl vif;
1223 struct mfcctl mfc; 1269 struct mfcctl mfc;
1224 struct net *net = sock_net(sk); 1270 struct net *net = sock_net(sk);
@@ -1287,16 +1333,22 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
1287 */ 1333 */
1288 case MRT_ADD_MFC: 1334 case MRT_ADD_MFC:
1289 case MRT_DEL_MFC: 1335 case MRT_DEL_MFC:
1336 parent = -1;
1337 case MRT_ADD_MFC_PROXY:
1338 case MRT_DEL_MFC_PROXY:
1290 if (optlen != sizeof(mfc)) 1339 if (optlen != sizeof(mfc))
1291 return -EINVAL; 1340 return -EINVAL;
1292 if (copy_from_user(&mfc, optval, sizeof(mfc))) 1341 if (copy_from_user(&mfc, optval, sizeof(mfc)))
1293 return -EFAULT; 1342 return -EFAULT;
1343 if (parent == 0)
1344 parent = mfc.mfcc_parent;
1294 rtnl_lock(); 1345 rtnl_lock();
1295 if (optname == MRT_DEL_MFC) 1346 if (optname == MRT_DEL_MFC || optname == MRT_DEL_MFC_PROXY)
1296 ret = ipmr_mfc_delete(mrt, &mfc); 1347 ret = ipmr_mfc_delete(mrt, &mfc, parent);
1297 else 1348 else
1298 ret = ipmr_mfc_add(net, mrt, &mfc, 1349 ret = ipmr_mfc_add(net, mrt, &mfc,
1299 sk == rtnl_dereference(mrt->mroute_sk)); 1350 sk == rtnl_dereference(mrt->mroute_sk),
1351 parent);
1300 rtnl_unlock(); 1352 rtnl_unlock();
1301 return ret; 1353 return ret;
1302 /* 1354 /*
@@ -1749,17 +1801,28 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
1749{ 1801{
1750 int psend = -1; 1802 int psend = -1;
1751 int vif, ct; 1803 int vif, ct;
1804 int true_vifi = ipmr_find_vif(mrt, skb->dev);
1752 1805
1753 vif = cache->mfc_parent; 1806 vif = cache->mfc_parent;
1754 cache->mfc_un.res.pkt++; 1807 cache->mfc_un.r