Skip to content

Commit

Permalink
pim6d: Impelmenting "ipv6 mld join"
Browse files Browse the repository at this point in the history
Fixes: FRRouting#12014

Signed-off-by: Abhishek N R <[email protected]>
  • Loading branch information
AbhishekNR committed Apr 3, 2023
1 parent bdf62ec commit bd2c824
Show file tree
Hide file tree
Showing 9 changed files with 162 additions and 155 deletions.
8 changes: 8 additions & 0 deletions lib/prefix.h
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,14 @@ static inline bool ipv6_mcast_ssm(const struct in6_addr *addr)
return (bits & 0xfff0ffff) == 0xff300000;
}

static inline bool ipv6_mcast_reserved(const struct in6_addr *addr)
{
uint32_t bits = ntohl(addr->s6_addr32[0]);

/* ffx2::/16 */
return (bits & 0xff0fffff) == 0xff020000;
}

static inline uint8_t ipv4_mcast_scope(const struct in_addr *addr)
{
uint32_t bits = ntohl(addr->s_addr);
Expand Down
2 changes: 2 additions & 0 deletions pimd/pim_addr.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ typedef struct in_addr pim_addr;
#define PIM_MROUTE_DBG "mroute"
#define PIMREG "pimreg"
#define GM "IGMP"
#define IPPROTO_GM IPPROTO_IGMP

#define PIM_ADDR_FUNCNAME(name) ipv4_##name

Expand Down Expand Up @@ -57,6 +58,7 @@ typedef struct in6_addr pim_addr;
#define PIM_MROUTE_DBG "mroute6"
#define PIMREG "pim6reg"
#define GM "MLD"
#define IPPROTO_GM IPPROTO_ICMPV6

#define PIM_ADDR_FUNCNAME(name) ipv6_##name

Expand Down
145 changes: 50 additions & 95 deletions pimd/pim_iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@

#if PIM_IPV == 4
static void pim_if_igmp_join_del_all(struct interface *ifp);
static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
struct in_addr group_addr, struct in_addr source_addr,
struct pim_interface *pim_ifp);
#endif
static int gm_join_sock(const char *ifname, ifindex_t ifindex,
pim_addr group_addr, pim_addr source_addr,
struct pim_interface *pim_ifp);

void pim_if_init(struct pim_instance *pim)
{
Expand Down Expand Up @@ -560,7 +560,7 @@ void pim_if_addr_add(struct connected *ifc)
/* Close socket and reopen with Source and Group
*/
close(ij->sock_fd);
join_fd = igmp_join_sock(
join_fd = gm_join_sock(
ifp->name, ifp->ifindex, ij->group_addr,
ij->source_addr, pim_ifp);
if (join_fd < 0) {
Expand All @@ -573,7 +573,7 @@ void pim_if_addr_add(struct connected *ifc)
"<src?>", ij->source_addr,
source_str, sizeof(source_str));
zlog_warn(
"%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
"%s: gm_join_sock() failure for IGMP group %s source %s on interface %s",
__func__, group_str, source_str,
ifp->name);
/* warning only */
Expand Down Expand Up @@ -1214,54 +1214,47 @@ long pim_if_t_suppressed_msec(struct interface *ifp)
return t_suppressed_msec;
}

#if PIM_IPV == 4
static void igmp_join_free(struct gm_join *ij)
static void gm_join_free(struct gm_join *ij)
{
XFREE(MTYPE_PIM_IGMP_JOIN, ij);
}

static struct gm_join *igmp_join_find(struct list *join_list,
struct in_addr group_addr,
struct in_addr source_addr)
static struct gm_join *gm_join_find(struct list *join_list, pim_addr group_addr,
pim_addr source_addr)
{
struct listnode *node;
struct gm_join *ij;

assert(join_list);

for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
if ((group_addr.s_addr == ij->group_addr.s_addr)
&& (source_addr.s_addr == ij->source_addr.s_addr))
if ((!pim_addr_cmp(group_addr, ij->group_addr)) &&
(!pim_addr_cmp(source_addr, ij->source_addr)))
return ij;
}

return 0;
}

static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
struct in_addr group_addr, struct in_addr source_addr,
struct pim_interface *pim_ifp)
static int gm_join_sock(const char *ifname, ifindex_t ifindex,
pim_addr group_addr, pim_addr source_addr,
struct pim_interface *pim_ifp)
{
int join_fd;

pim_ifp->igmp_ifstat_joins_sent++;

join_fd = pim_socket_raw(IPPROTO_IGMP);
join_fd = pim_socket_raw(IPPROTO_GM);
if (join_fd < 0) {
pim_ifp->igmp_ifstat_joins_failed++;
return -1;
}

if (pim_igmp_join_source(join_fd, ifindex, group_addr, source_addr)) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str,
sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str,
sizeof(source_str));
if (pim_gm_join_source(join_fd, ifindex, group_addr, source_addr)) {
zlog_warn(
"%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s",
__func__, join_fd, group_str, source_str, ifindex,
"%s: setsockopt(fd=%d) failure for " GM
" group %pPAs source %pPAs ifindex %d on interface %s: errno=%d: %s",
__func__, join_fd, &group_addr, &source_addr, ifindex,
ifname, errno, safe_strerror(errno));

pim_ifp->igmp_ifstat_joins_failed++;
Expand All @@ -1273,10 +1266,8 @@ static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
return join_fd;
}

#if PIM_IPV == 4
static struct gm_join *igmp_join_new(struct interface *ifp,
struct in_addr group_addr,
struct in_addr source_addr)
static struct gm_join *gm_join_new(struct interface *ifp, pim_addr group_addr,
pim_addr source_addr)
{
struct pim_interface *pim_ifp;
struct gm_join *ij;
Expand All @@ -1285,19 +1276,12 @@ static struct gm_join *igmp_join_new(struct interface *ifp,
pim_ifp = ifp->info;
assert(pim_ifp);

join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr,
source_addr, pim_ifp);
join_fd = gm_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr,
pim_ifp);
if (join_fd < 0) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];

pim_inet4_dump("<grp?>", group_addr, group_str,
sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str,
sizeof(source_str));
zlog_warn(
"%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
__func__, group_str, source_str, ifp->name);
zlog_warn("%s: gm_join_sock() failure for " GM
" group %pPAs source %pPAs on interface %s",
__func__, &group_addr, &source_addr, ifp->name);
return 0;
}

Expand All @@ -1312,11 +1296,9 @@ static struct gm_join *igmp_join_new(struct interface *ifp,

return ij;
}
#endif /* PIM_IPV == 4 */

#if PIM_IPV == 4
ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr,
struct in_addr source_addr)
ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr,
pim_addr source_addr)
{
struct pim_interface *pim_ifp;
struct gm_join *ij;
Expand All @@ -1329,37 +1311,32 @@ ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr,

if (!pim_ifp->gm_join_list) {
pim_ifp->gm_join_list = list_new();
pim_ifp->gm_join_list->del = (void (*)(void *))igmp_join_free;
pim_ifp->gm_join_list->del = (void (*)(void *))gm_join_free;
}

ij = igmp_join_find(pim_ifp->gm_join_list, group_addr, source_addr);
ij = gm_join_find(pim_ifp->gm_join_list, group_addr, source_addr);

/* This interface has already been configured to join this IGMP group
/* This interface has already been configured to join this IGMP/MLD
* group
*/
if (ij) {
return ferr_ok();
}

(void)igmp_join_new(ifp, group_addr, source_addr);
(void)gm_join_new(ifp, group_addr, source_addr);

if (PIM_DEBUG_GM_EVENTS) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str,
sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str,
sizeof(source_str));
zlog_debug(
"%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
__func__, source_str, group_str, ifp->name);
"%s: issued static " GM
" join for channel (S,G)=(%pPA,%pPA) on interface %s",
__func__, &source_addr, &group_addr, ifp->name);
}

return ferr_ok();
}
#endif /* PIM_IPV == 4 */

int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr,
struct in_addr source_addr)
int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr,
pim_addr source_addr)
{
struct pim_interface *pim_ifp;
struct gm_join *ij;
Expand All @@ -1372,40 +1349,29 @@ int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr,
}

if (!pim_ifp->gm_join_list) {
zlog_warn("%s: no IGMP join on interface %s", __func__,
zlog_warn("%s: no " GM " join on interface %s", __func__,
ifp->name);
return -2;
}

ij = igmp_join_find(pim_ifp->gm_join_list, group_addr, source_addr);
ij = gm_join_find(pim_ifp->gm_join_list, group_addr, source_addr);
if (!ij) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str,
sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str,
sizeof(source_str));
zlog_warn(
"%s: could not find IGMP group %s source %s on interface %s",
__func__, group_str, source_str, ifp->name);
zlog_warn("%s: could not find " GM
" group %pPAs source %pPAs on interface %s",
__func__, &group_addr, &source_addr, ifp->name);
return -3;
}

if (close(ij->sock_fd)) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
pim_inet4_dump("<grp?>", group_addr, group_str,
sizeof(group_str));
pim_inet4_dump("<src?>", source_addr, source_str,
sizeof(source_str));
zlog_warn(
"%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
__func__, ij->sock_fd, group_str, source_str, ifp->name,
errno, safe_strerror(errno));
"%s: failure closing sock_fd=%d for " GM
" group %pPAs source %pPAs on interface %s: errno=%d: %s",
__func__, ij->sock_fd, &group_addr, &source_addr,
ifp->name, errno, safe_strerror(errno));
/* warning only */
}
listnode_delete(pim_ifp->gm_join_list, ij);
igmp_join_free(ij);
gm_join_free(ij);
if (listcount(pim_ifp->gm_join_list) < 1) {
list_delete(&pim_ifp->gm_join_list);
pim_ifp->gm_join_list = 0;
Expand All @@ -1414,6 +1380,7 @@ int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr,
return 0;
}

#if PIM_IPV == 4
__attribute__((unused))
static void pim_if_igmp_join_del_all(struct interface *ifp)
{
Expand All @@ -1433,21 +1400,9 @@ static void pim_if_igmp_join_del_all(struct interface *ifp)
return;

for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij))
pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr);
}
#else /* PIM_IPV != 4 */
ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr,
struct in_addr source_addr)
{
return ferr_ok();
}

int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr,
struct in_addr source_addr)
{
return 0;
}
#endif /* PIM_IPV != 4 */
#endif /* PIM_IPV == 4 */

/*
RFC 4601
Expand Down
8 changes: 4 additions & 4 deletions pimd/pim_iface.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,10 @@ int pim_if_t_override_msec(struct interface *ifp);

pim_addr pim_find_primary_addr(struct interface *ifp);

ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr,
struct in_addr source_addr);
int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr,
struct in_addr source_addr);
ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr,
pim_addr source_addr);
int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr,
pim_addr source_addr);

void pim_if_update_could_assert(struct interface *ifp);

Expand Down
Loading

0 comments on commit bd2c824

Please sign in to comment.