aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ipmr.c
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2013-01-21 01:00:26 -0500
committerDavid S. Miller <davem@davemloft.net>2013-01-21 13:55:14 -0500
commit660b26dc1a8aeb33c2a2246ebf1b3684449a74b7 (patch)
tree867f1141b7cc2396443b7fa293124a8ef0948330 /net/ipv4/ipmr.c
parentbbb923a4c2d17ebd5ec34755fe19a33914cbd86f (diff)
mcast: add multicast proxy support (IPv4 and IPv6)
This patch add the support of proxy multicast, ie being able to build a static multicast tree. It adds the support of (*,*) and (*,G) entries. The user should define an (*,*) entry which is not used for real forwarding. This entry defines the upstream in iif and contains all interfaces from the static tree in its oifs. It will be used to forward packet upstream when they come from an interface belonging to the static tree. Hence, the user should define (*,G) entries to build its static tree. Note that upstream interface must be part of oifs: packets are sent to all oifs interfaces except the input interface. This ensures to always join the whole static tree, even if the packet is not coming from the upstream interface. Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Acked-by: David L Stevens <dlstevens@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/ipmr.c')
-rw-r--r--net/ipv4/ipmr.c119
1 files changed, 106 insertions, 13 deletions
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.res.pkt++;
1755 cache->mfc_un.res.bytes += skb->len; 1808 cache->mfc_un.res.bytes += skb->len;
1756 1809
1810 if (cache->mfc_origin == INADDR_ANY && true_vifi >= 0) {
1811 struct mfc_cache *cache_proxy;
1812
1813 /* For an (*,G) entry, we only check that the incomming
1814 * interface is part of the static tree.
1815 */
1816 cache_proxy = ipmr_cache_find_any_parent(mrt, vif);
1817 if (cache_proxy &&
1818 cache_proxy->mfc_un.res.ttls[true_vifi] < 255)
1819 goto forward;
1820 }
1821
1757 /* 1822 /*
1758 * Wrong interface: drop packet and (maybe) send PIM assert. 1823 * Wrong interface: drop packet and (maybe) send PIM assert.
1759 */ 1824 */
1760 if (mrt->vif_table[vif].dev != skb->dev) { 1825 if (mrt->vif_table[vif].dev != skb->dev) {
1761 int true_vifi;
1762
1763 if (rt_is_output_route(skb_rtable(skb))) { 1826 if (rt_is_output_route(skb_rtable(skb))) {
1764 /* It is our own packet, looped back. 1827 /* It is our own packet, looped back.
1765 * Very complicated situation... 1828 * Very complicated situation...
@@ -1776,7 +1839,6 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
1776 } 1839 }
1777 1840
1778 cache->mfc_un.res.wrong_if++; 1841 cache->mfc_un.res.wrong_if++;
1779 true_vifi = ipmr_find_vif(mrt, skb->dev);
1780 1842
1781 if (true_vifi >= 0 && mrt->mroute_do_assert && 1843 if (true_vifi >= 0 && mrt->mroute_do_assert &&
1782 /* pimsm uses asserts, when switching from RPT to SPT, 1844 /* pimsm uses asserts, when switching from RPT to SPT,
@@ -1794,15 +1856,33 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
1794 goto dont_forward; 1856 goto dont_forward;
1795 } 1857 }
1796 1858
1859forward:
1797 mrt->vif_table[vif].pkt_in++; 1860 mrt->vif_table[vif].pkt_in++;
1798 mrt->vif_table[vif].bytes_in += skb->len; 1861 mrt->vif_table[vif].bytes_in += skb->len;
1799 1862
1800 /* 1863 /*
1801 * Forward the frame 1864 * Forward the frame
1802 */ 1865 */
1866 if (cache->mfc_origin == INADDR_ANY &&
1867 cache->mfc_mcastgrp == INADDR_ANY) {
1868 if (true_vifi >= 0 &&
1869 true_vifi != cache->mfc_parent &&
1870 ip_hdr(skb)->ttl >
1871 cache->mfc_un.res.ttls[cache->mfc_parent]) {
1872 /* It's an (*,*) entry and the packet is not coming from
1873 * the upstream: forward the packet to the upstream
1874 * only.
1875 */
1876 psend = cache->mfc_parent;
1877 goto last_forward;
1878 }
1879 goto dont_forward;
1880 }
1803 for (ct = cache->mfc_un.res.maxvif - 1; 1881 for (ct = cache->mfc_un.res.maxvif - 1;
1804 ct >= cache->mfc_un.res.minvif; ct--) { 1882 ct >= cache->mfc_un.res.minvif; ct--) {
1805 if (ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) { 1883 /* For (*,G) entry, don't forward to the incoming interface */
1884 if ((cache->mfc_origin != INADDR_ANY || ct != true_vifi) &&
1885 ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
1806 if (psend != -1) { 1886 if (psend != -1) {
1807 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); 1887 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1808 1888
@@ -1813,6 +1893,7 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
1813 psend = ct; 1893 psend = ct;
1814 } 1894 }
1815 } 1895 }
1896last_forward:
1816 if (psend != -1) { 1897 if (psend != -1) {
1817 if (local) { 1898 if (local) {
1818 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); 1899 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
@@ -1902,6 +1983,13 @@ int ip_mr_input(struct sk_buff *skb)
1902 1983
1903 /* already under rcu_read_lock() */ 1984 /* already under rcu_read_lock() */
1904 cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr); 1985 cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
1986 if (cache == NULL) {
1987 int vif = ipmr_find_vif(mrt, skb->dev);
1988
1989 if (vif >= 0)
1990 cache = ipmr_cache_find_any(mrt, ip_hdr(skb)->daddr,
1991 vif);
1992 }
1905 1993
1906 /* 1994 /*
1907 * No usable cache entry 1995 * No usable cache entry
@@ -2107,7 +2195,12 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,
2107 2195
2108 rcu_read_lock(); 2196 rcu_read_lock();
2109 cache = ipmr_cache_find(mrt, saddr, daddr); 2197 cache = ipmr_cache_find(mrt, saddr, daddr);
2198 if (cache == NULL && skb->dev) {
2199 int vif = ipmr_find_vif(mrt, skb->dev);
2110 2200
2201 if (vif >= 0)
2202 cache = ipmr_cache_find_any(mrt, daddr, vif);
2203 }
2111 if (cache == NULL) { 2204 if (cache == NULL) {
2112 struct sk_buff *skb2; 2205 struct sk_buff *skb2;
2113 struct iphdr *iph; 2206 struct iphdr *iph;