netdev-dpdk: Do not add vhost-user ports with '/' or '\' in name.
[cascardo/ovs.git] / lib / mcast-snooping.c
index 39463fa..ee3e2e1 100644 (file)
@@ -125,22 +125,12 @@ mcast_snooping_lookup(const struct mcast_snooping *ms,
     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);
 }
 
@@ -443,8 +433,7 @@ mcast_snooping_add_group4(struct mcast_snooping *ms, ovs_be32 ip4,
                          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);
 }
 
@@ -499,6 +488,77 @@ mcast_snooping_add_report(struct mcast_snooping *ms,
     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,
@@ -526,8 +586,7 @@ bool
 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);
 }