aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6mr.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/ipv6/ip6mr.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/ipv6/ip6mr.c')
-rw-r--r--net/ipv6/ip6mr.c126
1 files changed, 113 insertions, 13 deletions
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 26dcdec9e3a5..acc32494006a 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -1017,6 +1017,50 @@ static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt,
1017 return NULL; 1017 return NULL;
1018} 1018}
1019 1019
1020/* Look for a (*,*,oif) entry */
1021static struct mfc6_cache *ip6mr_cache_find_any_parent(struct mr6_table *mrt,
1022 mifi_t mifi)
1023{
1024 int line = MFC6_HASH(&in6addr_any, &in6addr_any);
1025 struct mfc6_cache *c;
1026
1027 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list)
1028 if (ipv6_addr_any(&c->mf6c_origin) &&
1029 ipv6_addr_any(&c->mf6c_mcastgrp) &&
1030 (c->mfc_un.res.ttls[mifi] < 255))
1031 return c;
1032
1033 return NULL;
1034}
1035
1036/* Look for a (*,G) entry */
1037static struct mfc6_cache *ip6mr_cache_find_any(struct mr6_table *mrt,
1038 struct in6_addr *mcastgrp,
1039 mifi_t mifi)
1040{
1041 int line = MFC6_HASH(mcastgrp, &in6addr_any);
1042 struct mfc6_cache *c, *proxy;
1043
1044 if (ipv6_addr_any(mcastgrp))
1045 goto skip;
1046
1047 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list)
1048 if (ipv6_addr_any(&c->mf6c_origin) &&
1049 ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp)) {
1050 if (c->mfc_un.res.ttls[mifi] < 255)
1051 return c;
1052
1053 /* It's ok if the mifi is part of the static tree */
1054 proxy = ip6mr_cache_find_any_parent(mrt,
1055 c->mf6c_parent);
1056 if (proxy && proxy->mfc_un.res.ttls[mifi] < 255)
1057 return c;
1058 }
1059
1060skip:
1061 return ip6mr_cache_find_any_parent(mrt, mifi);
1062}
1063
1020/* 1064/*
1021 * Allocate a multicast cache entry 1065 * Allocate a multicast cache entry
1022 */ 1066 */
@@ -1247,7 +1291,8 @@ ip6mr_cache_unresolved(struct mr6_table *mrt, mifi_t mifi, struct sk_buff *skb)
1247 * MFC6 cache manipulation by user space 1291 * MFC6 cache manipulation by user space
1248 */ 1292 */
1249 1293
1250static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc) 1294static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc,
1295 int parent)
1251{ 1296{
1252 int line; 1297 int line;
1253 struct mfc6_cache *c, *next; 1298 struct mfc6_cache *c, *next;
@@ -1256,7 +1301,9 @@ static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc)
1256 1301
1257 list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) { 1302 list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) {
1258 if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && 1303 if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
1259 ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) { 1304 ipv6_addr_equal(&c->mf6c_mcastgrp,
1305 &mfc->mf6cc_mcastgrp.sin6_addr) &&
1306 (parent == -1 || parent == c->mf6c_parent)) {
1260 write_lock_bh(&mrt_lock); 1307 write_lock_bh(&mrt_lock);
1261 list_del(&c->list); 1308 list_del(&c->list);
1262 write_unlock_bh(&mrt_lock); 1309 write_unlock_bh(&mrt_lock);
@@ -1391,7 +1438,7 @@ void ip6_mr_cleanup(void)
1391} 1438}
1392 1439
1393static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, 1440static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
1394 struct mf6cctl *mfc, int mrtsock) 1441 struct mf6cctl *mfc, int mrtsock, int parent)
1395{ 1442{
1396 bool found = false; 1443 bool found = false;
1397 int line; 1444 int line;
@@ -1413,7 +1460,9 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
1413 1460
1414 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) { 1461 list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) {
1415 if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && 1462 if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
1416 ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) { 1463 ipv6_addr_equal(&c->mf6c_mcastgrp,
1464 &mfc->mf6cc_mcastgrp.sin6_addr) &&
1465 (parent == -1 || parent == mfc->mf6cc_parent)) {
1417 found = true; 1466 found = true;
1418 break; 1467 break;
1419 } 1468 }
@@ -1430,7 +1479,8 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
1430 return 0; 1479 return 0;
1431 } 1480 }
1432 1481
1433 if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr)) 1482 if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) &&
1483 !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
1434 return -EINVAL; 1484 return -EINVAL;
1435 1485
1436 c = ip6mr_cache_alloc(); 1486 c = ip6mr_cache_alloc();
@@ -1596,7 +1646,7 @@ struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
1596 1646
1597int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) 1647int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
1598{ 1648{
1599 int ret; 1649 int ret, parent = 0;
1600 struct mif6ctl vif; 1650 struct mif6ctl vif;
1601 struct mf6cctl mfc; 1651 struct mf6cctl mfc;
1602 mifi_t mifi; 1652 mifi_t mifi;
@@ -1653,15 +1703,21 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
1653 */ 1703 */
1654 case MRT6_ADD_MFC: 1704 case MRT6_ADD_MFC:
1655 case MRT6_DEL_MFC: 1705 case MRT6_DEL_MFC:
1706 parent = -1;
1707 case MRT6_ADD_MFC_PROXY:
1708 case MRT6_DEL_MFC_PROXY:
1656 if (optlen < sizeof(mfc)) 1709 if (optlen < sizeof(mfc))
1657 return -EINVAL; 1710 return -EINVAL;
1658 if (copy_from_user(&mfc, optval, sizeof(mfc))) 1711 if (copy_from_user(&mfc, optval, sizeof(mfc)))
1659 return -EFAULT; 1712 return -EFAULT;
1713 if (parent == 0)
1714 parent = mfc.mf6cc_parent;
1660 rtnl_lock(); 1715 rtnl_lock();
1661 if (optname == MRT6_DEL_MFC) 1716 if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY)
1662 ret = ip6mr_mfc_delete(mrt, &mfc); 1717 ret = ip6mr_mfc_delete(mrt, &mfc, parent);
1663 else 1718 else
1664 ret = ip6mr_mfc_add(net, mrt, &mfc, sk == mrt->mroute6_sk); 1719 ret = ip6mr_mfc_add(net, mrt, &mfc,
1720 sk == mrt->mroute6_sk, parent);
1665 rtnl_unlock(); 1721 rtnl_unlock();
1666 return ret; 1722 return ret;
1667 1723
@@ -2015,19 +2071,29 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
2015{ 2071{
2016 int psend = -1; 2072 int psend = -1;
2017 int vif, ct; 2073 int vif, ct;
2074 int true_vifi = ip6mr_find_vif(mrt, skb->dev);
2018 2075
2019 vif = cache->mf6c_parent; 2076 vif = cache->mf6c_parent;
2020 cache->mfc_un.res.pkt++; 2077 cache->mfc_un.res.pkt++;
2021 cache->mfc_un.res.bytes += skb->len; 2078 cache->mfc_un.res.bytes += skb->len;
2022 2079
2080 if (ipv6_addr_any(&cache->mf6c_origin) && true_vifi >= 0) {
2081 struct mfc6_cache *cache_proxy;
2082
2083 /* For an (*,G) entry, we only check that the incomming
2084 * interface is part of the static tree.
2085 */
2086 cache_proxy = ip6mr_cache_find_any_parent(mrt, vif);
2087 if (cache_proxy &&
2088 cache_proxy->mfc_un.res.ttls[true_vifi] < 255)
2089 goto forward;
2090 }
2091
2023 /* 2092 /*
2024 * Wrong interface: drop packet and (maybe) send PIM assert. 2093 * Wrong interface: drop packet and (maybe) send PIM assert.
2025 */ 2094 */
2026 if (mrt->vif6_table[vif].dev != skb->dev) { 2095 if (mrt->vif6_table[vif].dev != skb->dev) {
2027 int true_vifi;
2028
2029 cache->mfc_un.res.wrong_if++; 2096 cache->mfc_un.res.wrong_if++;
2030 true_vifi = ip6mr_find_vif(mrt, skb->dev);
2031 2097
2032 if (true_vifi >= 0 && mrt->mroute_do_assert && 2098 if (true_vifi >= 0 && mrt->mroute_do_assert &&
2033 /* pimsm uses asserts, when switching from RPT to SPT, 2099 /* pimsm uses asserts, when switching from RPT to SPT,
@@ -2045,14 +2111,32 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
2045 goto dont_forward; 2111 goto dont_forward;
2046 } 2112 }
2047 2113
2114forward:
2048 mrt->vif6_table[vif].pkt_in++; 2115 mrt->vif6_table[vif].pkt_in++;
2049 mrt->vif6_table[vif].bytes_in += skb->len; 2116 mrt->vif6_table[vif].bytes_in += skb->len;
2050 2117
2051 /* 2118 /*
2052 * Forward the frame 2119 * Forward the frame
2053 */ 2120 */
2121 if (ipv6_addr_any(&cache->mf6c_origin) &&
2122 ipv6_addr_any(&cache->mf6c_mcastgrp)) {
2123 if (true_vifi >= 0 &&
2124 true_vifi != cache->mf6c_parent &&
2125 ipv6_hdr(skb)->hop_limit >
2126 cache->mfc_un.res.ttls[cache->mf6c_parent]) {
2127 /* It's an (*,*) entry and the packet is not coming from
2128 * the upstream: forward the packet to the upstream
2129 * only.
2130 */
2131 psend = cache->mf6c_parent;
2132 goto last_forward;
2133 }
2134 goto dont_forward;
2135 }
2054 for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) { 2136 for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) {
2055 if (ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) { 2137 /* For (*,G) entry, don't forward to the incoming interface */
2138 if ((!ipv6_addr_any(&cache->mf6c_origin) || ct != true_vifi) &&
2139 ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) {
2056 if (psend != -1) { 2140 if (psend != -1) {
2057 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); 2141 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
2058 if (skb2) 2142 if (skb2)
@@ -2061,6 +2145,7 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
2061 psend = ct; 2145 psend = ct;
2062 } 2146 }
2063 } 2147 }
2148last_forward:
2064 if (psend != -1) { 2149 if (psend != -1) {
2065 ip6mr_forward2(net, mrt, skb, cache, psend); 2150 ip6mr_forward2(net, mrt, skb, cache, psend);
2066 return 0; 2151 return 0;
@@ -2096,6 +2181,14 @@ int ip6_mr_input(struct sk_buff *skb)
2096 read_lock(&mrt_lock); 2181 read_lock(&mrt_lock);
2097 cache = ip6mr_cache_find(mrt, 2182 cache = ip6mr_cache_find(mrt,
2098 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); 2183 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
2184 if (cache == NULL) {
2185 int vif = ip6mr_find_vif(mrt, skb->dev);
2186
2187 if (vif >= 0)
2188 cache = ip6mr_cache_find_any(mrt,
2189 &ipv6_hdr(skb)->daddr,
2190 vif);
2191 }
2099 2192
2100 /* 2193 /*
2101 * No usable cache entry 2194 * No usable cache entry
@@ -2183,6 +2276,13 @@ int ip6mr_get_route(struct net *net,
2183 2276
2184 read_lock(&mrt_lock); 2277 read_lock(&mrt_lock);
2185 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr); 2278 cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
2279 if (!cache && skb->dev) {
2280 int vif = ip6mr_find_vif(mrt, skb->dev);
2281
2282 if (vif >= 0)
2283 cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr,
2284 vif);
2285 }
2186 2286
2187 if (!cache) { 2287 if (!cache) {
2188 struct sk_buff *skb2; 2288 struct sk_buff *skb2;