Jonathan Hart

Clean up a few SSM-translate things, incl config validation

Change-Id: I5308fd8a73088ea6a522f22642ee834ac8a7a446
...@@ -84,7 +84,6 @@ import static org.slf4j.LoggerFactory.getLogger; ...@@ -84,7 +84,6 @@ import static org.slf4j.LoggerFactory.getLogger;
84 @Component(immediate = true) 84 @Component(immediate = true)
85 public class IgmpSnoop { 85 public class IgmpSnoop {
86 86
87 -
88 private final Logger log = getLogger(getClass()); 87 private final Logger log = getLogger(getClass());
89 88
90 private static final String DEST_MAC = "01:00:5E:00:00:01"; 89 private static final String DEST_MAC = "01:00:5E:00:00:01";
...@@ -144,6 +143,9 @@ public class IgmpSnoop { ...@@ -144,6 +143,9 @@ public class IgmpSnoop {
144 private static final Class<AccessDeviceConfig> CONFIG_CLASS = 143 private static final Class<AccessDeviceConfig> CONFIG_CLASS =
145 AccessDeviceConfig.class; 144 AccessDeviceConfig.class;
146 145
146 + private static final Class<IgmpSsmTranslateConfig> SSM_TRANSLATE_CONFIG_CLASS =
147 + IgmpSsmTranslateConfig.class;
148 +
147 private ConfigFactory<DeviceId, AccessDeviceConfig> configFactory = 149 private ConfigFactory<DeviceId, AccessDeviceConfig> configFactory =
148 new ConfigFactory<DeviceId, AccessDeviceConfig>( 150 new ConfigFactory<DeviceId, AccessDeviceConfig>(
149 SubjectFactories.DEVICE_SUBJECT_FACTORY, CONFIG_CLASS, "accessDevice") { 151 SubjectFactories.DEVICE_SUBJECT_FACTORY, CONFIG_CLASS, "accessDevice") {
...@@ -155,7 +157,7 @@ public class IgmpSnoop { ...@@ -155,7 +157,7 @@ public class IgmpSnoop {
155 157
156 private ConfigFactory<ApplicationId, IgmpSsmTranslateConfig> ssmTranslateConfigFactory = 158 private ConfigFactory<ApplicationId, IgmpSsmTranslateConfig> ssmTranslateConfigFactory =
157 new ConfigFactory<ApplicationId, IgmpSsmTranslateConfig>( 159 new ConfigFactory<ApplicationId, IgmpSsmTranslateConfig>(
158 - SubjectFactories.APP_SUBJECT_FACTORY, IgmpSsmTranslateConfig.class, "ssmTranslate", true) { 160 + SubjectFactories.APP_SUBJECT_FACTORY, SSM_TRANSLATE_CONFIG_CLASS, "ssmTranslate", true) {
159 @Override 161 @Override
160 public IgmpSsmTranslateConfig createConfig() { 162 public IgmpSsmTranslateConfig createConfig() {
161 return new IgmpSsmTranslateConfig(); 163 return new IgmpSsmTranslateConfig();
...@@ -466,9 +468,25 @@ public class IgmpSnoop { ...@@ -466,9 +468,25 @@ public class IgmpSnoop {
466 provisionDefaultFlows((DeviceId) event.subject()); 468 provisionDefaultFlows((DeviceId) event.subject());
467 } 469 }
468 } 470 }
471 + if (event.configClass().equals(SSM_TRANSLATE_CONFIG_CLASS)) {
472 + IgmpSsmTranslateConfig config =
473 + networkConfig.getConfig((ApplicationId) event.subject(),
474 + SSM_TRANSLATE_CONFIG_CLASS);
475 +
476 + if (config != null) {
477 + ssmTranslateTable.clear();
478 + config.getSsmTranslations().forEach(
479 + route -> ssmTranslateTable.put(route.group(), route.source()));
480 + }
481 + }
469 break; 482 break;
483 + case CONFIG_REGISTERED:
470 case CONFIG_UNREGISTERED: 484 case CONFIG_UNREGISTERED:
485 + break;
471 case CONFIG_REMOVED: 486 case CONFIG_REMOVED:
487 + if (event.configClass().equals(SSM_TRANSLATE_CONFIG_CLASS)) {
488 + ssmTranslateTable.clear();
489 + }
472 default: 490 default:
473 break; 491 break;
474 } 492 }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
17 package org.onosproject.igmp; 17 package org.onosproject.igmp;
18 18
19 import com.fasterxml.jackson.databind.JsonNode; 19 import com.fasterxml.jackson.databind.JsonNode;
20 +import com.fasterxml.jackson.databind.node.ObjectNode;
20 import org.onlab.packet.IpAddress; 21 import org.onlab.packet.IpAddress;
21 import org.onosproject.core.ApplicationId; 22 import org.onosproject.core.ApplicationId;
22 import org.onosproject.net.config.Config; 23 import org.onosproject.net.config.Config;
...@@ -26,13 +27,34 @@ import java.util.ArrayList; ...@@ -26,13 +27,34 @@ import java.util.ArrayList;
26 import java.util.List; 27 import java.util.List;
27 28
28 /** 29 /**
29 - * Created by jono on 2/16/16. 30 + * IGMP SSM translate configuration.
30 */ 31 */
31 public class IgmpSsmTranslateConfig extends Config<ApplicationId> { 32 public class IgmpSsmTranslateConfig extends Config<ApplicationId> {
32 - private static final String SSM_TRANSLATE = "ssmTranslate"; 33 +
33 private static final String SOURCE = "source"; 34 private static final String SOURCE = "source";
34 private static final String GROUP = "group"; 35 private static final String GROUP = "group";
35 36
37 + @Override
38 + public boolean isValid() {
39 + for (JsonNode node : array) {
40 + if (!hasOnlyFields((ObjectNode) node, SOURCE, GROUP)) {
41 + return false;
42 + }
43 +
44 + if (!(isIpAddress((ObjectNode) node, SOURCE, FieldPresence.MANDATORY) &&
45 + isIpAddress((ObjectNode) node, GROUP, FieldPresence.MANDATORY))) {
46 + return false;
47 + }
48 +
49 + }
50 + return true;
51 + }
52 +
53 + /**
54 + * Gets the list of SSM translations.
55 + *
56 + * @return SSM translations
57 + */
36 public List<McastRoute> getSsmTranslations() { 58 public List<McastRoute> getSsmTranslations() {
37 List<McastRoute> translations = new ArrayList(); 59 List<McastRoute> translations = new ArrayList();
38 for (JsonNode node : array) { 60 for (JsonNode node : array) {
......
...@@ -393,8 +393,20 @@ public abstract class Config<S> { ...@@ -393,8 +393,20 @@ public abstract class Config<S> {
393 * @return true if all allowedFields are present; false otherwise 393 * @return true if all allowedFields are present; false otherwise
394 */ 394 */
395 protected boolean hasOnlyFields(String... allowedFields) { 395 protected boolean hasOnlyFields(String... allowedFields) {
396 + return hasOnlyFields(object, allowedFields);
397 + }
398 +
399 + /**
400 + * Indicates whether only the specified fields are present in a particular
401 + * JSON object.
402 + *
403 + * @param node node whose fields to check
404 + * @param allowedFields allowed field names
405 + * @return true if all allowedFields are present; false otherwise
406 + */
407 + protected boolean hasOnlyFields(ObjectNode node, String... allowedFields) {
396 Set<String> fields = ImmutableSet.copyOf(allowedFields); 408 Set<String> fields = ImmutableSet.copyOf(allowedFields);
397 - return !Iterators.any(object.fieldNames(), f -> !fields.contains(f)); 409 + return !Iterators.any(node.fieldNames(), f -> !fields.contains(f));
398 } 410 }
399 411
400 /** 412 /**
...@@ -420,9 +432,23 @@ public abstract class Config<S> { ...@@ -420,9 +432,23 @@ public abstract class Config<S> {
420 * @throws IllegalArgumentException if field is present, but not valid IP 432 * @throws IllegalArgumentException if field is present, but not valid IP
421 */ 433 */
422 protected boolean isIpAddress(String field, FieldPresence presence) { 434 protected boolean isIpAddress(String field, FieldPresence presence) {
423 - JsonNode node = object.path(field); 435 + return isIpAddress(object, field, presence);
424 - return isValid(node, presence, node.isTextual() && 436 + }
425 - IpAddress.valueOf(node.asText()) != null); 437 +
438 + /**
439 + * Indicates whether the specified field of a particular node holds a valid
440 + * IP address.
441 + *
442 + * @param node node from whom to access the field
443 + * @param field JSON field name
444 + * @param presence specifies if field is optional or mandatory
445 + * @return true if valid; false otherwise
446 + * @throws IllegalArgumentException if field is present, but not valid IP
447 + */
448 + protected boolean isIpAddress(ObjectNode node, String field, FieldPresence presence) {
449 + JsonNode innerNode = node.path(field);
450 + return isValid(innerNode, presence, innerNode.isTextual() &&
451 + IpAddress.valueOf(innerNode.asText()) != null);
426 } 452 }
427 453
428 /** 454 /**
......