Commit 8c5c49a6 authored by David S. Miller's avatar David S. Miller

Merge branch 'Allow-more-than-255-IPv4-multicast-interfaces'

Paul Davey says:

====================
Allow more than 255 IPv4 multicast interfaces

Currently it is not possible to use more than 255 multicast interfaces
for IPv4 due to the format of the igmpmsg header which only has 8 bits
available for the VIF ID.  There is space available in the igmpmsg
header to store the full VIF ID in the form of an unused byte following
the VIF ID field.  There is also enough space for the full VIF ID in
the Netlink cache notifications, however the value is currently taken
directly from the igmpmsg header and has thus already been truncated.

Adding the high byte of the VIF ID into the unused3 byte of igmpmsg
allows use of more than 255 IPv4 multicast interfaces. The full VIF ID
is  also available in the Netlink notification by assembling it from
both bytes from the igmpmsg.

Additionally this reveals a deficiency in the Netlink cache report
notifications, they lack any means for differentiating cache reports
relating to different multicast routing tables.  This is easily
resolved by adding the multicast route table ID to the cache reports.

changes in v2:
 - Added high byte of VIF ID to igmpmsg struct replacing unused3
   member.
 - Assemble VIF ID in Netlink notification from both bytes in igmpmsg
   header.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4f6a5caf bb82067c
...@@ -113,8 +113,8 @@ struct igmpmsg { ...@@ -113,8 +113,8 @@ struct igmpmsg {
__u32 unused1,unused2; __u32 unused1,unused2;
unsigned char im_msgtype; /* What is this */ unsigned char im_msgtype; /* What is this */
unsigned char im_mbz; /* Must be zero */ unsigned char im_mbz; /* Must be zero */
unsigned char im_vif; /* Interface (this ought to be a vifi_t!) */ unsigned char im_vif; /* Low 8 bits of Interface */
unsigned char unused3; unsigned char im_vif_hi; /* High 8 bits of Interface */
struct in_addr im_src,im_dst; struct in_addr im_src,im_dst;
}; };
...@@ -169,6 +169,7 @@ enum { ...@@ -169,6 +169,7 @@ enum {
IPMRA_CREPORT_SRC_ADDR, IPMRA_CREPORT_SRC_ADDR,
IPMRA_CREPORT_DST_ADDR, IPMRA_CREPORT_DST_ADDR,
IPMRA_CREPORT_PKT, IPMRA_CREPORT_PKT,
IPMRA_CREPORT_TABLE,
__IPMRA_CREPORT_MAX __IPMRA_CREPORT_MAX
}; };
#define IPMRA_CREPORT_MAX (__IPMRA_CREPORT_MAX - 1) #define IPMRA_CREPORT_MAX (__IPMRA_CREPORT_MAX - 1)
......
...@@ -1038,10 +1038,13 @@ static int ipmr_cache_report(struct mr_table *mrt, ...@@ -1038,10 +1038,13 @@ static int ipmr_cache_report(struct mr_table *mrt,
memcpy(msg, skb_network_header(pkt), sizeof(struct iphdr)); memcpy(msg, skb_network_header(pkt), sizeof(struct iphdr));
msg->im_msgtype = assert; msg->im_msgtype = assert;
msg->im_mbz = 0; msg->im_mbz = 0;
if (assert == IGMPMSG_WRVIFWHOLE) if (assert == IGMPMSG_WRVIFWHOLE) {
msg->im_vif = vifi; msg->im_vif = vifi;
else msg->im_vif_hi = vifi >> 8;
} else {
msg->im_vif = mrt->mroute_reg_vif_num; msg->im_vif = mrt->mroute_reg_vif_num;
msg->im_vif_hi = mrt->mroute_reg_vif_num >> 8;
}
ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2; ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2;
ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) + ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) +
sizeof(struct iphdr)); sizeof(struct iphdr));
...@@ -1054,6 +1057,7 @@ static int ipmr_cache_report(struct mr_table *mrt, ...@@ -1054,6 +1057,7 @@ static int ipmr_cache_report(struct mr_table *mrt,
ip_hdr(skb)->protocol = 0; ip_hdr(skb)->protocol = 0;
msg = (struct igmpmsg *)skb_network_header(skb); msg = (struct igmpmsg *)skb_network_header(skb);
msg->im_vif = vifi; msg->im_vif = vifi;
msg->im_vif_hi = vifi >> 8;
skb_dst_set(skb, dst_clone(skb_dst(pkt))); skb_dst_set(skb, dst_clone(skb_dst(pkt)));
/* Add our header */ /* Add our header */
igmp = skb_put(skb, sizeof(struct igmphdr)); igmp = skb_put(skb, sizeof(struct igmphdr));
...@@ -2396,6 +2400,7 @@ static size_t igmpmsg_netlink_msgsize(size_t payloadlen) ...@@ -2396,6 +2400,7 @@ static size_t igmpmsg_netlink_msgsize(size_t payloadlen)
+ nla_total_size(4) /* IPMRA_CREPORT_VIF_ID */ + nla_total_size(4) /* IPMRA_CREPORT_VIF_ID */
+ nla_total_size(4) /* IPMRA_CREPORT_SRC_ADDR */ + nla_total_size(4) /* IPMRA_CREPORT_SRC_ADDR */
+ nla_total_size(4) /* IPMRA_CREPORT_DST_ADDR */ + nla_total_size(4) /* IPMRA_CREPORT_DST_ADDR */
+ nla_total_size(4) /* IPMRA_CREPORT_TABLE */
/* IPMRA_CREPORT_PKT */ /* IPMRA_CREPORT_PKT */
+ nla_total_size(payloadlen) + nla_total_size(payloadlen)
; ;
...@@ -2427,11 +2432,12 @@ static void igmpmsg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt) ...@@ -2427,11 +2432,12 @@ static void igmpmsg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt)
rtgenm = nlmsg_data(nlh); rtgenm = nlmsg_data(nlh);
rtgenm->rtgen_family = RTNL_FAMILY_IPMR; rtgenm->rtgen_family = RTNL_FAMILY_IPMR;
if (nla_put_u8(skb, IPMRA_CREPORT_MSGTYPE, msg->im_msgtype) || if (nla_put_u8(skb, IPMRA_CREPORT_MSGTYPE, msg->im_msgtype) ||
nla_put_u32(skb, IPMRA_CREPORT_VIF_ID, msg->im_vif) || nla_put_u32(skb, IPMRA_CREPORT_VIF_ID, msg->im_vif | (msg->im_vif_hi << 8)) ||
nla_put_in_addr(skb, IPMRA_CREPORT_SRC_ADDR, nla_put_in_addr(skb, IPMRA_CREPORT_SRC_ADDR,
msg->im_src.s_addr) || msg->im_src.s_addr) ||
nla_put_in_addr(skb, IPMRA_CREPORT_DST_ADDR, nla_put_in_addr(skb, IPMRA_CREPORT_DST_ADDR,
msg->im_dst.s_addr)) msg->im_dst.s_addr) ||
nla_put_u32(skb, IPMRA_CREPORT_TABLE, mrt->id))
goto nla_put_failure; goto nla_put_failure;
nla = nla_reserve(skb, IPMRA_CREPORT_PKT, payloadlen); nla = nla_reserve(skb, IPMRA_CREPORT_PKT, payloadlen);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment