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.r |
