with Docker, the wrapper script will be retired.
- Added support for DPDK Tunneling. VXLAN, GRE, and Geneve are supported
protocols. This is generic tunneling mechanism for userspace datapath.
- - Support for multicast snooping (IGMPv1 and IGMPv2)
+ - Support for multicast snooping (IGMPv1, IGMPv2 and IGMPv3)
- Support for Linux kernels up to 4.0.x
- The documentation now use the term 'destination' to mean one of syslog,
console or file for vlog logging instead of the previously used term
switch (ntohs(igmp_type)) {
case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMPV2_HOST_MEMBERSHIP_REPORT:
+ case IGMPV3_HOST_MEMBERSHIP_REPORT:
case IGMP_HOST_LEAVE_MESSAGE:
return true;
}
return learned;
}
+int
+mcast_snooping_add_report(struct mcast_snooping *ms,
+ const struct dp_packet *p,
+ uint16_t vlan, void *port)
+{
+ ovs_be32 ip4;
+ size_t offset;
+ const struct igmpv3_header *igmpv3;
+ const struct igmpv3_record *record;
+ int count = 0;
+ int ngrp;
+
+ offset = (char *) dp_packet_l4(p) - (char *) dp_packet_data(p);
+ igmpv3 = dp_packet_at(p, offset, IGMPV3_HEADER_LEN);
+ if (!igmpv3) {
+ return 0;
+ }
+ ngrp = ntohs(igmpv3->ngrp);
+ offset += IGMPV3_HEADER_LEN;
+ while (ngrp--) {
+ bool ret;
+ record = dp_packet_at(p, offset, sizeof(struct igmpv3_record));
+ if (!record) {
+ break;
+ }
+ /* Only consider known record types. */
+ if (record->type < IGMPV3_MODE_IS_INCLUDE
+ || record->type > IGMPV3_BLOCK_OLD_SOURCES) {
+ continue;
+ }
+ ip4 = get_16aligned_be32(&record->maddr);
+ /*
+ * If record is INCLUDE MODE and there are no sources, it's equivalent
+ * to a LEAVE.
+ */
+ if (ntohs(record->nsrcs) == 0
+ && (record->type == IGMPV3_MODE_IS_INCLUDE
+ || record->type == IGMPV3_CHANGE_TO_INCLUDE_MODE)) {
+ ret = mcast_snooping_leave_group(ms, ip4, vlan, port);
+ } else {
+ ret = mcast_snooping_add_group(ms, ip4, vlan, port);
+ }
+ if (ret) {
+ count++;
+ }
+ offset += sizeof(*record)
+ + ntohs(record->nsrcs) * sizeof(ovs_be32) + record->aux_len;
+ }
+ return count;
+}
+
bool
mcast_snooping_leave_group(struct mcast_snooping *ms, ovs_be32 ip4,
uint16_t vlan, void *port)
#define MCAST_SNOOPING_H 1
#include <time.h>
+#include "dp-packet.h"
#include "hmap.h"
#include "list.h"
#include "ovs-atomic.h"
bool mcast_snooping_add_group(struct mcast_snooping *ms, ovs_be32 ip4,
uint16_t vlan, void *port)
OVS_REQ_WRLOCK(ms->rwlock);
+int mcast_snooping_add_report(struct mcast_snooping *ms,
+ const struct dp_packet *p,
+ uint16_t vlan, void *port)
+ OVS_REQ_WRLOCK(ms->rwlock);
bool mcast_snooping_leave_group(struct mcast_snooping *ms, ovs_be32 ip4,
uint16_t vlan, void *port)
OVS_REQ_WRLOCK(ms->rwlock);
};
BUILD_ASSERT_DECL(IGMP_HEADER_LEN == sizeof(struct igmp_header));
+#define IGMPV3_HEADER_LEN 8
+struct igmpv3_header {
+ uint8_t type;
+ uint8_t rsvr1;
+ ovs_be16 csum;
+ ovs_be16 rsvr2;
+ ovs_be16 ngrp;
+};
+BUILD_ASSERT_DECL(IGMPV3_HEADER_LEN == sizeof(struct igmpv3_header));
+
+#define IGMPV3_RECORD_LEN 8
+struct igmpv3_record {
+ uint8_t type;
+ uint8_t aux_len;
+ ovs_be16 nsrcs;
+ ovs_16aligned_be32 maddr;
+};
+BUILD_ASSERT_DECL(IGMPV3_RECORD_LEN == sizeof(struct igmpv3_record));
+
#define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* From RFC1112 */
#define IGMP_HOST_MEMBERSHIP_REPORT 0x12 /* Ditto */
#define IGMPV2_HOST_MEMBERSHIP_REPORT 0x16 /* V2 version of 0x12 */
#define IGMP_HOST_LEAVE_MESSAGE 0x17
#define IGMPV3_HOST_MEMBERSHIP_REPORT 0x22 /* V3 version of 0x12 */
+#define IGMPV3_MODE_IS_INCLUDE 1
+#define IGMPV3_MODE_IS_EXCLUDE 2
+#define IGMPV3_CHANGE_TO_INCLUDE_MODE 3
+#define IGMPV3_CHANGE_TO_EXCLUDE_MODE 4
+#define IGMPV3_ALLOW_NEW_SOURCES 5
+#define IGMPV3_BLOCK_OLD_SOURCES 6
+
#define SCTP_HEADER_LEN 12
struct sctp_header {
ovs_be16 sctp_src;
const struct flow *flow,
struct mcast_snooping *ms,
ovs_be32 ip4, int vlan,
- struct xbundle *in_xbundle)
+ struct xbundle *in_xbundle,
+ const struct dp_packet *packet)
OVS_REQ_WRLOCK(ms->rwlock)
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 30);
+ int count;
switch (ntohs(flow->tp_src)) {
case IGMP_HOST_MEMBERSHIP_REPORT:
in_xbundle->name, vlan);
}
break;
+ case IGMPV3_HOST_MEMBERSHIP_REPORT:
+ if ((count = mcast_snooping_add_report(ms, packet, vlan,
+ in_xbundle->ofbundle))) {
+ VLOG_DBG_RL(&rl, "bridge %s: multicast snooping processed %d "
+ "addresses on port %s in VLAN %d",
+ xbridge->name, count, in_xbundle->name, vlan);
+ }
+ break;
}
}
static void
update_mcast_snooping_table(const struct xbridge *xbridge,
const struct flow *flow, int vlan,
- struct xbundle *in_xbundle)
+ struct xbundle *in_xbundle,
+ const struct dp_packet *packet)
{
struct mcast_snooping *ms = xbridge->ms;
struct xlate_cfg *xcfg;
if (!mcast_xbundle || mcast_xbundle != in_xbundle) {
update_mcast_snooping_table__(xbridge, flow, ms, flow->igmp_group_ip4,
- vlan, in_xbundle);
+ vlan, in_xbundle, packet);
}
ovs_rwlock_unlock(&ms->rwlock);
}
mcast_snooping_is_query(flow->tp_src)) {
if (ctx->xin->may_learn) {
update_mcast_snooping_table(ctx->xbridge, flow, vlan,
- in_xbundle);
+ in_xbundle, ctx->xin->packet);
}
/*
* IGMP packets need to take the slow path, in order to be
Protocol (IGMP) traffic between hosts and multicast routers. The
switch uses what IGMP snooping learns to forward multicast traffic
only to interfaces that are connected to interested receivers.
- Currently it supports IGMPv1 and IGMPv2 protocols.
+ Currently it supports IGMPv1, IGMPv2 and IGMPv3 protocols.
<column name="mcast_snooping_enable">
Enable multicast snooping on the bridge. For now, the default