If vxlan_group is specified in CIDR notation, it is interpreted as a
range of group addresses. VXLAN VNIs are mapped to group addresses in
a many-to-one round robin fashion, or one-to-one if a large enough
range is provided. Since VNIs are 24 bits, a /8 such as 239.0.0.0/8
allows each VNI to use a unique multicast group. (239.0.0.0/8 also
happens to be the "site-local" multicast range.)
With multiple VNIs on a single multicast group, it is likely that
VTEPs will unnecessarily receive broadcast/unknown/multicast
datagrams for VNIs in which they do not participate. Using a range of
groups mitigates or eliminates this issue. It is thus an alternative
to the l2_population extension and driver for environments where both
multicast and linuxbridge are used.
The default setting is unchanged, but the comments in the ini file
suggest 239.0.0.0/8 as an alternative. Administrators are free to use
any valid multicast range that can be expressed in CIDR notation, and
should choose a size and starting address that make sense for their
environment.
DocImpact
Closes-Bug: #
1477331
Change-Id: If9a3487a28ba2b02a6ef934c5421cec5d505b53c
# (IntOpt) use specific TOS for vxlan interface protocol packets
# tos =
#
-# (StrOpt) multicast group to use for broadcast emulation.
-# This group must be the same on all the agents.
+# (StrOpt) multicast group or group range to use for broadcast emulation.
+# Specifying a range allows different VNIs to use different group addresses,
+# reducing or eliminating spurious broadcast traffic to the tunnel endpoints.
+# Ranges are specified by using CIDR notation. To reserve a unique group for
+# each possible (24-bit) VNI, use a /8 such as 239.0.0.0/8.
+# This setting must be the same on all the agents.
# vxlan_group = 224.0.0.1
#
# (StrOpt) Local IP address to use for VXLAN endpoints (required)
cfg.IntOpt('tos',
help=_("TOS for vxlan interface protocol packets.")),
cfg.StrOpt('vxlan_group', default=DEFAULT_VXLAN_GROUP,
- help=_("Multicast group for vxlan interface.")),
+ help=_("Multicast group(s) for vxlan interface. A range of "
+ "group addresses may be specified by using CIDR "
+ "notation. To reserve a unique group for each possible "
+ "(24-bit) VNI, use a /8 such as 239.0.0.0/8. This "
+ "setting must be the same on all the agents.")),
cfg.IPOpt('local_ip', version=4,
help=_("Local IP address of the VXLAN endpoints.")),
cfg.BoolOpt('l2_population', default=False,
import eventlet
eventlet.monkey_patch()
+import netaddr
from oslo_config import cfg
from oslo_log import log as logging
import oslo_messaging
LOG.warning(_LW("Invalid Segmentation ID: %s, will lead to "
"incorrect vxlan device name"), segmentation_id)
+ def get_vxlan_group(self, segmentation_id):
+ try:
+ # Ensure the configured group address/range is valid and multicast
+ net = netaddr.IPNetwork(cfg.CONF.VXLAN.vxlan_group)
+ if not (net.network.is_multicast() and
+ net.broadcast.is_multicast()):
+ raise ValueError()
+ # Map the segmentation ID to (one of) the group address(es)
+ return str(net.network +
+ (int(segmentation_id) & int(net.hostmask)))
+ except (netaddr.core.AddrFormatError, ValueError):
+ LOG.warning(_LW("Invalid VXLAN Group: %s, must be an address "
+ "or network (in CIDR notation) in a multicast "
+ "range"),
+ cfg.CONF.VXLAN.vxlan_group)
+
def get_all_neutron_bridges(self):
neutron_bridge_list = []
bridge_list = os.listdir(BRIDGE_FS)
'segmentation_id': segmentation_id})
args = {'dev': self.local_int}
if self.vxlan_mode == lconst.VXLAN_MCAST:
- args['group'] = cfg.CONF.VXLAN.vxlan_group
+ args['group'] = self.get_vxlan_group(segmentation_id)
if cfg.CONF.VXLAN.ttl:
args['ttl'] = cfg.CONF.VXLAN.ttl
if cfg.CONF.VXLAN.tos:
def vxlan_mcast_supported(self):
if not cfg.CONF.VXLAN.vxlan_group:
- LOG.warning(_LW('VXLAN muticast group must be provided in '
+ LOG.warning(_LW('VXLAN muticast group(s) must be provided in '
'vxlan_group option to enable VXLAN MCAST mode'))
return False
if not ip_lib.iproute_arg_supported(
"vxlan-" + str(vn_id))
self.assertIsNone(self.lbm.get_vxlan_device_name(vn_id + 1))
+ def test_get_vxlan_group(self):
+ cfg.CONF.set_override('vxlan_group', '239.1.2.3/24', 'VXLAN')
+ vn_id = p_const.MAX_VXLAN_VNI
+ self.assertEqual('239.1.2.255', self.lbm.get_vxlan_group(vn_id))
+ vn_id = 256
+ self.assertEqual('239.1.2.0', self.lbm.get_vxlan_group(vn_id))
+ vn_id = 257
+ self.assertEqual('239.1.2.1', self.lbm.get_vxlan_group(vn_id))
+ cfg.CONF.set_override('vxlan_group', '240.0.0.0', 'VXLAN')
+ self.assertIsNone(self.lbm.get_vxlan_group(vn_id))
+ cfg.CONF.set_override('vxlan_group', '224.0.0.1/', 'VXLAN')
+ self.assertIsNone(self.lbm.get_vxlan_group(vn_id))
+
def test_get_all_neutron_bridges(self):
br_list = ["br-int", "brq1", "brq2", "br-ex"]
with mock.patch.object(os, 'listdir') as listdir_fn: