return NULL;
}
-static inline void
-in6_addr_set_mapped_ipv4(struct in6_addr *addr, ovs_be32 ip4)
-{
- union ovs_16aligned_in6_addr *taddr = (void *) addr;
- memset(taddr->be16, 0, sizeof(taddr->be16));
- taddr->be16[5] = OVS_BE16_MAX;
- put_16aligned_be32(&taddr->be32[3], ip4);
-}
-
struct mcast_group *
mcast_snooping_lookup4(const struct mcast_snooping *ms, ovs_be32 ip4,
uint16_t vlan)
OVS_REQ_RDLOCK(ms->rwlock)
{
- struct in6_addr addr;
- in6_addr_set_mapped_ipv4(&addr, ip4);
+ struct in6_addr addr = in6_addr_mapped_ipv4(ip4);
return mcast_snooping_lookup(ms, &addr, vlan);
}
uint16_t vlan, void *port)
OVS_REQ_WRLOCK(ms->rwlock)
{
- struct in6_addr addr;
- in6_addr_set_mapped_ipv4(&addr, ip4);
+ struct in6_addr addr = in6_addr_mapped_ipv4(ip4);
return mcast_snooping_add_group(ms, &addr, vlan, port);
}
return count;
}
+int
+mcast_snooping_add_mld(struct mcast_snooping *ms,
+ const struct dp_packet *p,
+ uint16_t vlan, void *port)
+{
+ const struct in6_addr *addr;
+ size_t offset;
+ const struct mld_header *mld;
+ const struct mld2_record *record;
+ int count = 0;
+ int ngrp;
+ bool ret;
+
+ offset = (char *) dp_packet_l4(p) - (char *) dp_packet_data(p);
+ mld = dp_packet_at(p, offset, MLD_HEADER_LEN);
+ if (!mld) {
+ return 0;
+ }
+ ngrp = ntohs(mld->ngrp);
+ offset += MLD_HEADER_LEN;
+ addr = dp_packet_at(p, offset, sizeof(struct in6_addr));
+
+ switch (mld->type) {
+ case MLD_REPORT:
+ ret = mcast_snooping_add_group(ms, addr, vlan, port);
+ if (ret) {
+ count++;
+ }
+ break;
+ case MLD_DONE:
+ ret = mcast_snooping_leave_group(ms, addr, vlan, port);
+ if (ret) {
+ count++;
+ }
+ break;
+ case MLD2_REPORT:
+ while (ngrp--) {
+ record = dp_packet_at(p, offset, sizeof(struct mld2_record));
+ if (!record) {
+ break;
+ }
+ /* Only consider known record types. */
+ if (record->type >= IGMPV3_MODE_IS_INCLUDE
+ && record->type <= IGMPV3_BLOCK_OLD_SOURCES) {
+ struct in6_addr maddr;
+ memcpy(maddr.s6_addr, record->maddr.be16, 16);
+ addr = &maddr;
+ /*
+ * If record is INCLUDE MODE and there are no sources, it's
+ * equivalent to a LEAVE.
+ */
+ if (record->nsrcs == htons(0)
+ && (record->type == IGMPV3_MODE_IS_INCLUDE
+ || record->type == IGMPV3_CHANGE_TO_INCLUDE_MODE)) {
+ ret = mcast_snooping_leave_group(ms, addr, vlan, port);
+ } else {
+ ret = mcast_snooping_add_group(ms, addr, vlan, port);
+ }
+ if (ret) {
+ count++;
+ }
+ }
+ offset += sizeof(*record)
+ + ntohs(record->nsrcs) * sizeof(struct in6_addr)
+ + record->aux_len;
+ }
+ }
+
+ return count;
+}
+
bool
mcast_snooping_leave_group(struct mcast_snooping *ms,
const struct in6_addr *addr,
mcast_snooping_leave_group4(struct mcast_snooping *ms, ovs_be32 ip4,
uint16_t vlan, void *port)
{
- struct in6_addr addr;
- in6_addr_set_mapped_ipv4(&addr, ip4);
+ struct in6_addr addr = in6_addr_mapped_ipv4(ip4);
return mcast_snooping_leave_group(ms, &addr, vlan, port);
}