VOL-3166 IgmpProxy should support "double-tagging" of ongoing IGMP messages.
Also, priority bits of IGMP query messages that are sent to UNI ports by
IgmpProxy should be configurable separately.
Change-Id: Ia125c43515d234134b81f1039cf2f1f170d47161
diff --git a/app/src/main/java/org/opencord/igmpproxy/impl/IgmpManager.java b/app/src/main/java/org/opencord/igmpproxy/impl/IgmpManager.java
index 97e97cc..edd23f6 100644
--- a/app/src/main/java/org/opencord/igmpproxy/impl/IgmpManager.java
+++ b/app/src/main/java/org/opencord/igmpproxy/impl/IgmpManager.java
@@ -129,7 +129,9 @@
private static boolean withRADownlink = false;
private static boolean periodicQuery = true;
private static short mvlan = 4000;
+ private static short mvlanInner = VlanId.NONE.toShort();
private static byte igmpCos = 7;
+ private static byte igmpUniCos = 7;
public static boolean connectPointMode = true;
public static ConnectPoint connectPoint = null;
private static ConnectPoint sourceDeviceAndPort = null;
@@ -257,6 +259,8 @@
if (config != null) {
mvlan = config.egressVlan().toShort();
IgmpSender.getInstance().setMvlan(mvlan);
+ mvlanInner = config.egressInnerVlan().toShort();
+ IgmpSender.getInstance().setMvlanInner(mvlanInner);
}
deviceService.addListener(deviceListener);
scheduledExecutorService.scheduleAtFixedRate(new IgmpProxyTimerTask(), 1000, 1000, TimeUnit.MILLISECONDS);
@@ -487,10 +491,14 @@
Ethernet ethpkt;
Ip4Address srcIp = getDeviceIp(groupMember.getDeviceId());
if (groupMember.getv2()) {
- ethpkt = IgmpSender.getInstance().buildIgmpV2Query(groupMember.getGroupIp(), srcIp);
+ ethpkt = IgmpSender.getInstance().buildIgmpV2Query(groupMember.getGroupIp(),
+ srcIp, groupMember.getvlan().toShort());
} else {
- ethpkt = IgmpSender.getInstance().buildIgmpV3Query(groupMember.getGroupIp(), srcIp);
+ ethpkt = IgmpSender.getInstance().buildIgmpV3Query(groupMember.getGroupIp(),
+ srcIp, groupMember.getvlan().toShort());
}
+ log.debug("Sending IGMP query to {}/{} for group {}: {}",
+ groupMember.getDeviceId(), groupMember.getPortNumber(), groupMember.getGroupIp(), ethpkt);
IgmpSender.getInstance().sendIgmpPacket(ethpkt, groupMember.getDeviceId(), groupMember.getPortNumber());
}
@@ -895,6 +903,7 @@
withRAUplink = newCfg.withRAUplink();
withRADownlink = newCfg.withRADownlink();
igmpCos = newCfg.igmpCos();
+ igmpUniCos = newCfg.igmpUniCos(); // defines priority bit of IGMP query message sent to UNI ports
periodicQuery = newCfg.periodicQuery();
fastLeave = newCfg.fastLeave();
pimSSmInterworking = newCfg.pimSsmInterworking();
@@ -925,8 +934,10 @@
getSourceConnectPoint(newCfg);
IgmpSender.getInstance().setIgmpCos(igmpCos);
+ IgmpSender.getInstance().setIgmpUniCos(igmpUniCos);
IgmpSender.getInstance().setMaxResp(maxResp);
IgmpSender.getInstance().setMvlan(mvlan);
+ IgmpSender.getInstance().setMvlanInner(mvlanInner);
IgmpSender.getInstance().setWithRADownlink(withRADownlink);
IgmpSender.getInstance().setWithRAUplink(withRAUplink);
}
@@ -972,10 +983,22 @@
if (event.configClass().equals(MCAST_CONFIG_CLASS)) {
McastConfig config = networkConfig.getConfig(coreAppId, MCAST_CONFIG_CLASS);
- if (config != null && mvlan != config.egressVlan().toShort()) {
- mvlan = config.egressVlan().toShort();
- IgmpSender.getInstance().setMvlan(mvlan);
+ boolean vlanConfigChanged = config != null && mvlan != config.egressVlan().toShort();
+ boolean innerVlanConfigChanged = config != null &&
+ mvlanInner != config.egressInnerVlan().toShort();
+
+ if (vlanConfigChanged || innerVlanConfigChanged) {
+ log.info("igmpproxy vlan config received. {}", config);
+ //at least one of the vlan configs has changed. Call leave before setting new values
groupMemberStore.getAllGroupMembers().forEach(m -> leaveAction(m));
+ if (vlanConfigChanged) {
+ mvlan = config.egressVlan().toShort();
+ IgmpSender.getInstance().setMvlan(mvlan);
+ }
+ if (innerVlanConfigChanged) {
+ mvlanInner = config.egressInnerVlan().toShort();
+ IgmpSender.getInstance().setMvlanInner(mvlanInner);
+ }
}
}
diff --git a/app/src/main/java/org/opencord/igmpproxy/impl/IgmpSender.java b/app/src/main/java/org/opencord/igmpproxy/impl/IgmpSender.java
index adf0e9e..e6584ad 100644
--- a/app/src/main/java/org/opencord/igmpproxy/impl/IgmpSender.java
+++ b/app/src/main/java/org/opencord/igmpproxy/impl/IgmpSender.java
@@ -24,6 +24,7 @@
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -57,7 +58,9 @@
private boolean withRAUplink = true;
private boolean withRADownlink = false;
private short mvlan = DEFAULT_MVLAN;
+ private short mvlanInner = VlanId.NONE.toShort();
private byte igmpCos = DEFAULT_COS;
+ private byte igmpUniCos = DEFAULT_COS;
private int maxResp = DEFAULT_MEX_RESP;
private Logger log = LoggerFactory.getLogger(getClass());
@@ -89,9 +92,16 @@
this.mvlan = mvlan;
}
+ public void setMvlanInner(short mvlanInner) {
+ this.mvlanInner = mvlanInner;
+ }
+
public void setIgmpCos(byte igmpCos) {
this.igmpCos = igmpCos;
}
+ public void setIgmpUniCos(byte igmpUniCos) {
+ this.igmpUniCos = igmpUniCos;
+ }
public void setMaxResp(int maxResp) {
this.maxResp = maxResp;
@@ -101,12 +111,14 @@
IGMPMembership igmpMembership = new IGMPMembership(groupIp);
igmpMembership.setRecordType(IGMPMembership.CHANGE_TO_EXCLUDE_MODE);
- return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT, groupIp, igmpMembership, sourceIp, false);
+ return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT, groupIp, igmpMembership,
+ sourceIp, false, mvlan, mvlanInner, igmpCos);
}
public Ethernet buildIgmpV2Join(Ip4Address groupIp, Ip4Address sourceIp) {
IGMPMembership igmpMembership = new IGMPMembership(groupIp);
- return buildIgmpPacket(IGMP.TYPE_IGMPV2_MEMBERSHIP_REPORT, groupIp, igmpMembership, sourceIp, true);
+ return buildIgmpPacket(IGMP.TYPE_IGMPV2_MEMBERSHIP_REPORT, groupIp, igmpMembership,
+ sourceIp, true, mvlan, mvlanInner, igmpCos);
}
public Ethernet buildIgmpV2ResponseQuery(Ip4Address groupIp, Ip4Address sourceIp) {
@@ -117,31 +129,37 @@
IGMPMembership igmpMembership = new IGMPMembership(groupIp);
igmpMembership.setRecordType(IGMPMembership.MODE_IS_EXCLUDE);
- return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT, groupIp, igmpMembership, sourceIp, false);
+ return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT, groupIp, igmpMembership,
+ sourceIp, false, mvlan, mvlanInner, igmpCos);
}
public Ethernet buildIgmpV3Leave(Ip4Address groupIp, Ip4Address sourceIp) {
IGMPMembership igmpMembership = new IGMPMembership(groupIp);
igmpMembership.setRecordType(IGMPMembership.CHANGE_TO_INCLUDE_MODE);
- return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT, groupIp, igmpMembership, sourceIp, false);
+ return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT, groupIp, igmpMembership,
+ sourceIp, false, mvlan, mvlanInner, igmpCos);
}
public Ethernet buildIgmpV2Leave(Ip4Address groupIp, Ip4Address sourceIp) {
IGMPMembership igmpMembership = new IGMPMembership(groupIp);
- return buildIgmpPacket(IGMP.TYPE_IGMPV2_LEAVE_GROUP, groupIp, igmpMembership, sourceIp, true);
+ return buildIgmpPacket(IGMP.TYPE_IGMPV2_LEAVE_GROUP, groupIp, igmpMembership,
+ sourceIp, true, mvlan, mvlanInner, igmpCos);
}
- public Ethernet buildIgmpV2Query(Ip4Address groupIp, Ip4Address sourceIp) {
- return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY, groupIp, null, sourceIp, true);
+ public Ethernet buildIgmpV2Query(Ip4Address groupIp, Ip4Address sourceIp, short vlan) {
+ return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY, groupIp, null,
+ sourceIp, true, vlan, VlanId.NONE.toShort(), igmpUniCos);
}
- public Ethernet buildIgmpV3Query(Ip4Address groupIp, Ip4Address sourceIp) {
- return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY, groupIp, null, sourceIp, false);
+ public Ethernet buildIgmpV3Query(Ip4Address groupIp, Ip4Address sourceIp, short vlan) {
+ return buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY, groupIp, null,
+ sourceIp, false, vlan, VlanId.NONE.toShort(), igmpUniCos);
}
protected Ethernet buildIgmpPacket(byte type, Ip4Address groupIp, IGMPMembership igmpMembership,
- Ip4Address sourceIp, boolean isV2Query) {
+ Ip4Address sourceIp, boolean isV2Query, short vlan,
+ short innerVlan, byte igmpCos) {
IGMP igmpPacket;
if (isV2Query) {
@@ -210,9 +228,16 @@
ethPkt.setSourceMACAddress(MAC_ADDRESS);
ethPkt.setEtherType(Ethernet.TYPE_IPV4);
ethPkt.setPayload(ip4Packet);
- ethPkt.setVlanID(mvlan);
+ ethPkt.setVlanID(vlan);
ethPkt.setPriorityCode(igmpCos);
+ if (innerVlan != VlanId.NONE.toShort()) {
+ ethPkt.setQinQTPID(Ethernet.TYPE_VLAN);
+ ethPkt.setQinQVID(vlan);
+ ethPkt.setVlanID(innerVlan);
+ ethPkt.setQinQPriorityCode(igmpCos);
+ }
+
return ethPkt;
}
diff --git a/app/src/main/java/org/opencord/igmpproxy/impl/IgmpproxyConfig.java b/app/src/main/java/org/opencord/igmpproxy/impl/IgmpproxyConfig.java
index 95beea8..6d8591a 100644
--- a/app/src/main/java/org/opencord/igmpproxy/impl/IgmpproxyConfig.java
+++ b/app/src/main/java/org/opencord/igmpproxy/impl/IgmpproxyConfig.java
@@ -31,6 +31,7 @@
protected static final String DEFAULT_LAST_QUERY_INTERVAL = "2";
protected static final String DEFAULT_LAST_QUERY_COUNT = "2";
protected static final String DEFAULT_IGMP_COS = "7";
+ protected static final String DEFAULT_UNI_IGMP_COS = "7";
protected static final Boolean DEFAULT_FAST_LEAVE = false;
protected static final Boolean DEFAULT_PERIODIC_QUERY = true;
protected static final String DEFAULT_WITH_RA_UPLINK = "true";
@@ -52,6 +53,7 @@
private static final String FAST_LEAVE = "FastLeave";
private static final String PERIODIC_QUERY = "PeriodicQuery";
private static final String IGMP_COS = "IgmpCos";
+ private static final String IGMP_UNI_COS = "IgmpUniCos";
private static final String WITH_RA_UPLINK = "withRAUpLink";
private static final String WITH_RA_DOWN_LINK = "withRADownLink";
private static final String PIMSSM_INTERWORKING = "pimSSmInterworking";
@@ -149,6 +151,10 @@
return Byte.parseByte(getStringProperty(IGMP_COS, DEFAULT_IGMP_COS));
}
+ public byte igmpUniCos() {
+ return Byte.parseByte(getStringProperty(IGMP_UNI_COS, DEFAULT_UNI_IGMP_COS));
+ }
+
public boolean withRAUplink() {
if (object == null || object.path(WITH_RA_UPLINK) == null) {
return true;
diff --git a/app/src/test/java/org/opencord/igmpproxy/impl/IgmpManagerBase.java b/app/src/test/java/org/opencord/igmpproxy/impl/IgmpManagerBase.java
index 6283c08..a33ab15 100644
--- a/app/src/test/java/org/opencord/igmpproxy/impl/IgmpManagerBase.java
+++ b/app/src/test/java/org/opencord/igmpproxy/impl/IgmpManagerBase.java
@@ -23,6 +23,7 @@
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
import org.onosproject.cfg.ComponentConfigService;
import org.onosproject.cfg.ConfigProperty;
import org.onosproject.core.ApplicationId;
@@ -686,14 +687,15 @@
igmpMembership.setRecordType((byte) 0x33);
return IgmpSender.getInstance().buildIgmpPacket(IGMP.TYPE_IGMPV3_MEMBERSHIP_REPORT, groupIp,
- igmpMembership, sourceIp, false);
+ igmpMembership, sourceIp, false, VlanId.ANY_VALUE, VlanId.NO_VID, IgmpSender.DEFAULT_COS);
}
Ethernet buildUnknownIgmpPacket(Ip4Address groupIp, Ip4Address sourceIp) {
IGMPMembership igmpMembership = new IGMPMembership(groupIp);
igmpMembership.setRecordType((byte) 0x33);
- return IgmpSender.getInstance().buildIgmpPacket((byte) 0x44, groupIp, igmpMembership, sourceIp, false);
+ return IgmpSender.getInstance().buildIgmpPacket((byte) 0x44, groupIp, igmpMembership, sourceIp, false,
+ VlanId.ANY_VALUE, VlanId.NO_VID, IgmpSender.DEFAULT_COS);
}
class TestStateMachineStoreService extends AbstractStateMachineStore {
diff --git a/app/src/test/java/org/opencord/igmpproxy/impl/IgmpStatisticsTest.java b/app/src/test/java/org/opencord/igmpproxy/impl/IgmpStatisticsTest.java
index b2e8271..4421bde 100644
--- a/app/src/test/java/org/opencord/igmpproxy/impl/IgmpStatisticsTest.java
+++ b/app/src/test/java/org/opencord/igmpproxy/impl/IgmpStatisticsTest.java
@@ -28,6 +28,7 @@
import org.onlab.junit.TestUtils;
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
+import org.onlab.packet.VlanId;
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.net.flow.FlowRuleServiceAdapter;
import org.onosproject.net.flowobjective.FlowObjectiveServiceAdapter;
@@ -147,12 +148,13 @@
flagForQueryPacket = true;
//IGMPV3 Group Specific Membership Query packet
- Ethernet igmpv3MembershipQueryPkt = IgmpSender.getInstance().buildIgmpV3Query(GROUP_IP, SOURCE_IP_OF_A);
+ Ethernet igmpv3MembershipQueryPkt = IgmpSender.getInstance().
+ buildIgmpV3Query(GROUP_IP, SOURCE_IP_OF_A, VlanId.MAX_VLAN);
sendPacket(igmpv3MembershipQueryPkt);
//IGMPV3 General Membership Query packet
Ethernet igmpv3MembershipQueryPkt1 =
- IgmpSender.getInstance().buildIgmpV3Query(Ip4Address.valueOf(0), SOURCE_IP_OF_A);
+ IgmpSender.getInstance().buildIgmpV3Query(Ip4Address.valueOf(0), SOURCE_IP_OF_A, VlanId.MAX_VLAN);
sendPacket(igmpv3MembershipQueryPkt1);
assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
assertEquals(igmpStatisticsManager.getIgmpStats()