Skip to content

Commit

Permalink
Merge branch 'mcast'
Browse files Browse the repository at this point in the history
Nicolas Dichtel says:

====================
The goal of this serie is to add the support of proxy multicast, ie being able
to build a static multicast tree. In other words, it adds the support of (*,G)
mf[6]c entries.

v2: use INADDR_ANY instead of 0 for IPv4 addresses
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
davem330 committed Jan 21, 2013
2 parents 202dc3f + 660b26d commit 3fcd550
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 39 deletions.
2 changes: 1 addition & 1 deletion include/linux/mroute.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifdef CONFIG_IP_MROUTE
static inline int ip_mroute_opt(int opt)
{
return (opt >= MRT_BASE) && (opt <= MRT_BASE + 10);
return (opt >= MRT_BASE) && (opt <= MRT_MAX);
}
#else
static inline int ip_mroute_opt(int opt)
Expand Down
2 changes: 1 addition & 1 deletion include/linux/mroute6.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#ifdef CONFIG_IPV6_MROUTE
static inline int ip6_mroute_opt(int opt)
{
return (opt >= MRT6_BASE) && (opt <= MRT6_BASE + 10);
return (opt >= MRT6_BASE) && (opt <= MRT6_MAX);
}
#else
static inline int ip6_mroute_opt(int opt)
Expand Down
15 changes: 4 additions & 11 deletions include/uapi/linux/in6.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,17 +259,10 @@ struct in6_flowlabel_req {

/*
* Multicast Routing:
* see include/linux/mroute6.h.
* see include/uapi/linux/mroute6.h.
*
* MRT6_INIT 200
* MRT6_DONE 201
* MRT6_ADD_MIF 202
* MRT6_DEL_MIF 203
* MRT6_ADD_MFC 204
* MRT6_DEL_MFC 205
* MRT6_VERSION 206
* MRT6_ASSERT 207
* MRT6_PIM 208
* (reserved) 209
* MRT6_BASE 200
* ...
* MRT6_MAX
*/
#endif /* _UAPI_LINUX_IN6_H */
3 changes: 3 additions & 0 deletions include/uapi/linux/mroute.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
#define MRT_ASSERT (MRT_BASE+7) /* Activate PIM assert mode */
#define MRT_PIM (MRT_BASE+8) /* enable PIM code */
#define MRT_TABLE (MRT_BASE+9) /* Specify mroute table ID */
#define MRT_ADD_MFC_PROXY (MRT_BASE+10) /* Add a (*,*|G) mfc entry */
#define MRT_DEL_MFC_PROXY (MRT_BASE+11) /* Del a (*,*|G) mfc entry */
#define MRT_MAX (MRT_BASE+11)

#define SIOCGETVIFCNT SIOCPROTOPRIVATE /* IP protocol privates */
#define SIOCGETSGCNT (SIOCPROTOPRIVATE+1)
Expand Down
3 changes: 3 additions & 0 deletions include/uapi/linux/mroute6.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
#define MRT6_ASSERT (MRT6_BASE+7) /* Activate PIM assert mode */
#define MRT6_PIM (MRT6_BASE+8) /* enable PIM code */
#define MRT6_TABLE (MRT6_BASE+9) /* Specify mroute table ID */
#define MRT6_ADD_MFC_PROXY (MRT6_BASE+10) /* Add a (*,*|G) mfc entry */
#define MRT6_DEL_MFC_PROXY (MRT6_BASE+11) /* Del a (*,*|G) mfc entry */
#define MRT6_MAX (MRT6_BASE+11)

#define SIOCGETMIFCNT_IN6 SIOCPROTOPRIVATE /* IP protocol privates */
#define SIOCGETSGCNT_IN6 (SIOCPROTOPRIVATE+1)
Expand Down
119 changes: 106 additions & 13 deletions net/ipv4/ipmr.c
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,49 @@ static struct mfc_cache *ipmr_cache_find(struct mr_table *mrt,
return NULL;
}

/* Look for a (*,*,oif) entry */
static struct mfc_cache *ipmr_cache_find_any_parent(struct mr_table *mrt,
int vifi)
{
int line = MFC_HASH(INADDR_ANY, INADDR_ANY);
struct mfc_cache *c;

list_for_each_entry_rcu(c, &mrt->mfc_cache_array[line], list)
if (c->mfc_origin == INADDR_ANY &&
c->mfc_mcastgrp == INADDR_ANY &&
c->mfc_un.res.ttls[vifi] < 255)
return c;

return NULL;
}

/* Look for a (*,G) entry */
static struct mfc_cache *ipmr_cache_find_any(struct mr_table *mrt,
__be32 mcastgrp, int vifi)
{
int line = MFC_HASH(mcastgrp, INADDR_ANY);
struct mfc_cache *c, *proxy;

if (mcastgrp == INADDR_ANY)
goto skip;

list_for_each_entry_rcu(c, &mrt->mfc_cache_array[line], list)
if (c->mfc_origin == INADDR_ANY &&
c->mfc_mcastgrp == mcastgrp) {
if (c->mfc_un.res.ttls[vifi] < 255)
return c;

/* It's ok if the vifi is part of the static tree */
proxy = ipmr_cache_find_any_parent(mrt,
c->mfc_parent);
if (proxy && proxy->mfc_un.res.ttls[vifi] < 255)
return c;
}

skip:
return ipmr_cache_find_any_parent(mrt, vifi);
}

/*
* Allocate a multicast cache entry
*/
Expand Down Expand Up @@ -1053,7 +1096,7 @@ ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb)
* MFC cache manipulation by user space mroute daemon
*/

static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc)
static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc, int parent)
{
int line;
struct mfc_cache *c, *next;
Expand All @@ -1062,7 +1105,8 @@ static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc)

list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[line], list) {
if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr &&
(parent == -1 || parent == c->mfc_parent)) {
list_del_rcu(&c->list);
mroute_netlink_event(mrt, c, RTM_DELROUTE);
ipmr_cache_free(c);
Expand All @@ -1073,7 +1117,7 @@ static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc)
}

static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
struct mfcctl *mfc, int mrtsock)
struct mfcctl *mfc, int mrtsock, int parent)
{
bool found = false;
int line;
Expand All @@ -1086,7 +1130,8 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,

list_for_each_entry(c, &mrt->mfc_cache_array[line], list) {
if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr &&
(parent == -1 || parent == c->mfc_parent)) {
found = true;
break;
}
Expand All @@ -1103,7 +1148,8 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
return 0;
}

if (!ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
if (mfc->mfcc_mcastgrp.s_addr != INADDR_ANY &&
!ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
return -EINVAL;

c = ipmr_cache_alloc();
Expand Down Expand Up @@ -1218,7 +1264,7 @@ static void mrtsock_destruct(struct sock *sk)

int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
{
int ret;
int ret, parent = 0;
struct vifctl vif;
struct mfcctl mfc;
struct net *net = sock_net(sk);
Expand Down Expand Up @@ -1287,16 +1333,22 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
*/
case MRT_ADD_MFC:
case MRT_DEL_MFC:
parent = -1;
case MRT_ADD_MFC_PROXY:
case MRT_DEL_MFC_PROXY:
if (optlen != sizeof(mfc))
return -EINVAL;
if (copy_from_user(&mfc, optval, sizeof(mfc)))
return -EFAULT;
if (parent == 0)
parent = mfc.mfcc_parent;
rtnl_lock();
if (optname == MRT_DEL_MFC)
ret = ipmr_mfc_delete(mrt, &mfc);
if (optname == MRT_DEL_MFC || optname == MRT_DEL_MFC_PROXY)
ret = ipmr_mfc_delete(mrt, &mfc, parent);
else
ret = ipmr_mfc_add(net, mrt, &mfc,
sk == rtnl_dereference(mrt->mroute_sk));
sk == rtnl_dereference(mrt->mroute_sk),
parent);
rtnl_unlock();
return ret;
/*
Expand Down Expand Up @@ -1749,17 +1801,28 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
{
int psend = -1;
int vif, ct;
int true_vifi = ipmr_find_vif(mrt, skb->dev);

vif = cache->mfc_parent;
cache->mfc_un.res.pkt++;
cache->mfc_un.res.bytes += skb->len;

if (cache->mfc_origin == INADDR_ANY && true_vifi >= 0) {
struct mfc_cache *cache_proxy;

/* For an (*,G) entry, we only check that the incomming
* interface is part of the static tree.
*/
cache_proxy = ipmr_cache_find_any_parent(mrt, vif);
if (cache_proxy &&
cache_proxy->mfc_un.res.ttls[true_vifi] < 255)
goto forward;
}

/*
* Wrong interface: drop packet and (maybe) send PIM assert.
*/
if (mrt->vif_table[vif].dev != skb->dev) {
int true_vifi;

if (rt_is_output_route(skb_rtable(skb))) {
/* It is our own packet, looped back.
* Very complicated situation...
Expand All @@ -1776,7 +1839,6 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
}

cache->mfc_un.res.wrong_if++;
true_vifi = ipmr_find_vif(mrt, skb->dev);

if (true_vifi >= 0 && mrt->mroute_do_assert &&
/* pimsm uses asserts, when switching from RPT to SPT,
Expand All @@ -1794,15 +1856,33 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
goto dont_forward;
}

forward:
mrt->vif_table[vif].pkt_in++;
mrt->vif_table[vif].bytes_in += skb->len;

/*
* Forward the frame
*/
if (cache->mfc_origin == INADDR_ANY &&
cache->mfc_mcastgrp == INADDR_ANY) {
if (true_vifi >= 0 &&
true_vifi != cache->mfc_parent &&
ip_hdr(skb)->ttl >
cache->mfc_un.res.ttls[cache->mfc_parent]) {
/* It's an (*,*) entry and the packet is not coming from
* the upstream: forward the packet to the upstream
* only.
*/
psend = cache->mfc_parent;
goto last_forward;
}
goto dont_forward;
}
for (ct = cache->mfc_un.res.maxvif - 1;
ct >= cache->mfc_un.res.minvif; ct--) {
if (ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
/* For (*,G) entry, don't forward to the incoming interface */
if ((cache->mfc_origin != INADDR_ANY || ct != true_vifi) &&
ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
if (psend != -1) {
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);

Expand All @@ -1813,6 +1893,7 @@ static int ip_mr_forward(struct net *net, struct mr_table *mrt,
psend = ct;
}
}
last_forward:
if (psend != -1) {
if (local) {
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
Expand Down Expand Up @@ -1902,6 +1983,13 @@ int ip_mr_input(struct sk_buff *skb)

/* already under rcu_read_lock() */
cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
if (cache == NULL) {
int vif = ipmr_find_vif(mrt, skb->dev);

if (vif >= 0)
cache = ipmr_cache_find_any(mrt, ip_hdr(skb)->daddr,
vif);
}

/*
* No usable cache entry
Expand Down Expand Up @@ -2107,7 +2195,12 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,

rcu_read_lock();
cache = ipmr_cache_find(mrt, saddr, daddr);
if (cache == NULL && skb->dev) {
int vif = ipmr_find_vif(mrt, skb->dev);

if (vif >= 0)
cache = ipmr_cache_find_any(mrt, daddr, vif);
}
if (cache == NULL) {
struct sk_buff *skb2;
struct iphdr *iph;
Expand Down
Loading

0 comments on commit 3fcd550

Please sign in to comment.