diff options
-rw-r--r-- | include/uapi/linux/mroute.h | 4 | ||||
-rw-r--r-- | include/uapi/linux/mroute6.h | 4 | ||||
-rw-r--r-- | net/ipv4/ipmr.c | 119 | ||||
-rw-r--r-- | net/ipv6/ip6mr.c | 126 |
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 */ | ||
832 | static 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 */ | ||
848 | static 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 | |||
870 | skip: | ||
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 | ||
1056 | static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc) | 1099 | static 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 | ||
1075 | static int ipmr_mfc_add(struct net *net, struct mr_table *mrt, | 1119 | static 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 | ||
1219 | int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) | 1265 | int 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 | ||
1859 | forward: | ||
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 | } |
1896 | last_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; |
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 */ | ||
1021 | static 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 */ | ||
1037 | static 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 | |||
1060 | skip: | ||
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 | ||
1250 | static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc) | 1294 | static 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 | ||
1393 | static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt, | 1440 | static 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 | ||
1597 | int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) | 1647 | int 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 | ||
2114 | forward: | ||
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 | } |
2148 | last_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; |