diff --git a/opensync-ext-static/src/main/resources/ProfileAPExample.json b/opensync-ext-static/src/main/resources/ProfileAPExample.json index ad5fe5b..9001597 100644 --- a/opensync-ext-static/src/main/resources/ProfileAPExample.json +++ b/opensync-ext-static/src/main/resources/ProfileAPExample.json @@ -42,6 +42,23 @@ "bestAPSteerType": "both" } }, + "greTunnelConfigurations": [ + { + "model_type": "GreTunnelConfiguration", + "greTunnelName": "gre1", + "greParentIfName": "wan", + "greLocalInetAddr": "10.0.0.129", + "greRemoteInetAddr": "192.168.1.101", + "greRemoteMacAddr": { + "model_type": "MacAddress", + "address": "ZEvwIFf/", + "addressAsString": "64:4b:f0:20:57:ff" + }, + "vlanIdsInGreTunnel": [ + 100 + ] + } + ], "profileType": "equipment_ap" }, "createdTimestamp": 1606778369934, diff --git a/opensync-gateway-static-docker/src/main/docker-opensync-gateway-and-mqtt/app/opensync/ProfileAPExample.json b/opensync-gateway-static-docker/src/main/docker-opensync-gateway-and-mqtt/app/opensync/ProfileAPExample.json index ad5fe5b..9001597 100644 --- a/opensync-gateway-static-docker/src/main/docker-opensync-gateway-and-mqtt/app/opensync/ProfileAPExample.json +++ b/opensync-gateway-static-docker/src/main/docker-opensync-gateway-and-mqtt/app/opensync/ProfileAPExample.json @@ -42,6 +42,23 @@ "bestAPSteerType": "both" } }, + "greTunnelConfigurations": [ + { + "model_type": "GreTunnelConfiguration", + "greTunnelName": "gre1", + "greParentIfName": "wan", + "greLocalInetAddr": "10.0.0.129", + "greRemoteInetAddr": "192.168.1.101", + "greRemoteMacAddr": { + "model_type": "MacAddress", + "address": "ZEvwIFf/", + "addressAsString": "64:4b:f0:20:57:ff" + }, + "vlanIdsInGreTunnel": [ + 100 + ] + } + ], "profileType": "equipment_ap" }, "createdTimestamp": 1606778369934, diff --git a/opensync-gateway-static-docker/src/main/docker/app/opensync/ProfileAPExample.json b/opensync-gateway-static-docker/src/main/docker/app/opensync/ProfileAPExample.json index ad5fe5b..9001597 100644 --- a/opensync-gateway-static-docker/src/main/docker/app/opensync/ProfileAPExample.json +++ b/opensync-gateway-static-docker/src/main/docker/app/opensync/ProfileAPExample.json @@ -42,6 +42,23 @@ "bestAPSteerType": "both" } }, + "greTunnelConfigurations": [ + { + "model_type": "GreTunnelConfiguration", + "greTunnelName": "gre1", + "greParentIfName": "wan", + "greLocalInetAddr": "10.0.0.129", + "greRemoteInetAddr": "192.168.1.101", + "greRemoteMacAddr": { + "model_type": "MacAddress", + "address": "ZEvwIFf/", + "addressAsString": "64:4b:f0:20:57:ff" + }, + "vlanIdsInGreTunnel": [ + 100 + ] + } + ], "profileType": "equipment_ap" }, "createdTimestamp": 1606778369934, diff --git a/opensync-gateway-static-process/src/main/resources/app/opensync/ProfileAPExample.json b/opensync-gateway-static-process/src/main/resources/app/opensync/ProfileAPExample.json index ad5fe5b..9001597 100644 --- a/opensync-gateway-static-process/src/main/resources/app/opensync/ProfileAPExample.json +++ b/opensync-gateway-static-process/src/main/resources/app/opensync/ProfileAPExample.json @@ -42,6 +42,23 @@ "bestAPSteerType": "both" } }, + "greTunnelConfigurations": [ + { + "model_type": "GreTunnelConfiguration", + "greTunnelName": "gre1", + "greParentIfName": "wan", + "greLocalInetAddr": "10.0.0.129", + "greRemoteInetAddr": "192.168.1.101", + "greRemoteMacAddr": { + "model_type": "MacAddress", + "address": "ZEvwIFf/", + "addressAsString": "64:4b:f0:20:57:ff" + }, + "vlanIdsInGreTunnel": [ + 100 + ] + } + ], "profileType": "equipment_ap" }, "createdTimestamp": 1606778369934, diff --git a/opensync-gateway/src/main/java/com/telecominfraproject/wlan/opensync/ovsdb/dao/OvsdbDao.java b/opensync-gateway/src/main/java/com/telecominfraproject/wlan/opensync/ovsdb/dao/OvsdbDao.java index dd8a49f..a2f8f8f 100644 --- a/opensync-gateway/src/main/java/com/telecominfraproject/wlan/opensync/ovsdb/dao/OvsdbDao.java +++ b/opensync-gateway/src/main/java/com/telecominfraproject/wlan/opensync/ovsdb/dao/OvsdbDao.java @@ -10,6 +10,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -76,6 +77,7 @@ import com.telecominfraproject.wlan.profile.metrics.ServiceMetricsStatsReportFor import com.telecominfraproject.wlan.profile.models.Profile; import com.telecominfraproject.wlan.profile.models.common.ManagedFileInfo; import com.telecominfraproject.wlan.profile.network.models.ApNetworkConfiguration; +import com.telecominfraproject.wlan.profile.network.models.GreTunnelConfiguration; import com.telecominfraproject.wlan.profile.passpoint.models.PasspointDuple; import com.telecominfraproject.wlan.profile.passpoint.models.PasspointIPv4AddressType; import com.telecominfraproject.wlan.profile.passpoint.models.PasspointIPv6AddressType; @@ -3186,89 +3188,78 @@ public class OvsdbDao { } private void configureGreTunnel(OvsdbClient ovsdbClient, Profile apNetworkConfiguration) { + + + + try { LOG.debug("Configure Gre Tunnel {}", apNetworkConfiguration); List operations = new ArrayList<>(); - Map tableColumns = new HashMap<>(); ApNetworkConfiguration details = (ApNetworkConfiguration) apNetworkConfiguration.getDetails(); - if (details.getGreParentIfName() == null) { - LOG.info("Cannot configure GRE profile without gre_ifname"); - return; - } - tableColumns.put("gre_ifname", new Atom<>(details.getGreParentIfName())); - if (details.getGreLocalInetAddr() != null) { - tableColumns.put("gre_local_inet_addr", new Atom<>(details.getGreLocalInetAddr().getHostAddress())); - } - if (details.getGreRemoteInetAddr() == null) { - LOG.info("Cannot configure GRE profile without gre_remote_inet_addr"); - return; - } - tableColumns.put("gre_remote_inet_addr", new Atom<>(details.getGreRemoteInetAddr().getHostAddress())); - if (details.getGreRemoteMacAddr() != null) { - tableColumns.put("gre_remote_mac_addr", new Atom<>(details.getGreRemoteMacAddr().getAddressAsString())); - } - if (details.getGreTunnelName() == null) { - LOG.info("Cannot configure GRE profile without if_name"); - return; - } - tableColumns.put("if_name", new Atom<>(details.getGreTunnelName())); - tableColumns.put("if_type", new Atom<>("gre")); - tableColumns.put("network", new Atom<>(true)); - tableColumns.put("NAT", new Atom<>(false)); - tableColumns.put("enabled", new Atom<>(true)); - List conditions = new ArrayList<>(); - conditions.add(new Condition("if_name", Function.EQUALS, new Atom<>(details.getGreTunnelName()))); - operations.add(new Select(wifiInetConfigDbTable, conditions)); + for (GreTunnelConfiguration greTunnelConfiguration : details.getGreTunnelConfigurations()) { + if (greTunnelConfiguration.getGreParentIfName() == null) { + LOG.info("Cannot configure GRE profile without gre_ifname"); + continue; + } + if (greTunnelConfiguration.getGreRemoteInetAddr() == null) { + LOG.info("Cannot configure GRE profile without gre_remote_inet_addr"); + continue; + } + + if (greTunnelConfiguration.getGreTunnelName() == null) { + LOG.info("Cannot configure GRE profile without if_name"); + continue; + } + + Map tableColumns = new HashMap<>(); + tableColumns.put("gre_ifname", new Atom<>(greTunnelConfiguration.getGreParentIfName())); + tableColumns.put("gre_remote_inet_addr", new Atom<>(greTunnelConfiguration.getGreRemoteInetAddr().getHostAddress())); + tableColumns.put("if_name", new Atom<>(greTunnelConfiguration.getGreTunnelName())); + + // optional + if (greTunnelConfiguration.getGreLocalInetAddr() != null) { + tableColumns.put("gre_local_inet_addr", new Atom<>(greTunnelConfiguration.getGreLocalInetAddr().getHostAddress())); + } + + // optional + if (greTunnelConfiguration.getGreRemoteMacAddr() != null) { + tableColumns.put("gre_remote_mac_addr", new Atom<>(greTunnelConfiguration.getGreRemoteMacAddr().getAddressAsString())); + } + + tableColumns.put("if_type", new Atom<>("gre")); + tableColumns.put("network", new Atom<>(true)); + tableColumns.put("NAT", new Atom<>(false)); + tableColumns.put("enabled", new Atom<>(true)); + + operations.add(new Insert(wifiInetConfigDbTable, new Row(tableColumns))); + + } + + if (operations.isEmpty()) { + LOG.info("No GRE tunnels to be configured."); + return; + } CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations); OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS); for (OperationResult res : result) { - - if (res instanceof SelectResult) { - LOG.info("configureGreTunnel {}", ((SelectResult) res).toString()); - } else if (res instanceof ErrorResult) { - LOG.error("configureGreTunnel error {}", ((ErrorResult) res)); - throw new RuntimeException("configureGreTunnel " + ((ErrorResult) res).getError() - + " " + ((ErrorResult) res).getDetails()); - } - - } - - if (((SelectResult) result[0]).getRows().isEmpty()) { - LOG.debug("Adding new Gre Tunnel {}", apNetworkConfiguration); - - operations.clear(); - operations.add(new Insert(wifiInetConfigDbTable, new Row(tableColumns))); - } else { - LOG.debug("Updating Gre Tunnel {}", apNetworkConfiguration); - operations.clear(); - operations.add(new Update(wifiInetConfigDbTable, conditions, new Row(tableColumns))); - } - - fResult = ovsdbClient.transact(ovsdbName, operations); - result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS); - for (OperationResult res : result) { - if (res instanceof InsertResult) { LOG.info("configureGreTunnel {}", ((InsertResult) res).toString()); } else if (res instanceof UpdateResult) { - LOG.info("configureGreTunnel {}", ((UpdateResult) res).toString()); } else if (res instanceof ErrorResult) { LOG.error("configureGreTunnel error {}", ((ErrorResult) res)); throw new RuntimeException("configureGreTunnel " + ((ErrorResult) res).getError() + " " + ((ErrorResult) res).getDetails()); } - - } + } } catch (OvsdbClientException | InterruptedException | ExecutionException | TimeoutException e) { LOG.error("Couldn't configure Gre Tunnel {}", apNetworkConfiguration, e); throw new RuntimeException(e); } - } public void createVlanNetworkInterfaces(OvsdbClient ovsdbClient, OpensyncAPConfig opensyncApConfig) { @@ -3280,10 +3271,94 @@ public class OvsdbDao { } } for (Integer vlanId : vlans) { - createVlanNetworkInterfaces(ovsdbClient, vlanId); + + + Optional tunnelConfiguration = ((ApNetworkConfiguration)opensyncApConfig.getApProfile().getDetails()).getGreTunnelConfigurations().stream().filter(new Predicate() { + + @Override + public boolean test(GreTunnelConfiguration t) { + + return t.getVlanIdsInGreTunnel().contains(vlanId); + } + + }).findFirst(); + + if (tunnelConfiguration.isPresent()) { + createVlanInterfaceInGreTunnel(ovsdbClient,vlanId, tunnelConfiguration.get().getGreTunnelName()); + } else { + createVlanNetworkInterfaces(ovsdbClient, vlanId); + } + } } + private void createVlanInterfaceInGreTunnel(OvsdbClient ovsdbClient, int vlanId, String greTunnel) { + try { + + List operations = new ArrayList<>(); + Map tableColumns = new HashMap<>(); + + Map inetConfigMap = getProvisionedWifiInetConfigs(ovsdbClient); + + + WifiInetConfigInfo parentTunnel = inetConfigMap.get(greTunnel); + if (parentTunnel == null) + throw new RuntimeException( + "Cannot get tunnel interface " + parentTunnel + " for vlan " + vlanId); + + tableColumns = new HashMap<>(); + + tableColumns.put("if_type", new Atom<>("vlan")); + tableColumns.put("vlan_id", new Atom<>(vlanId)); + tableColumns.put("if_name", new Atom<>(parentTunnel.ifName + "_" + Integer.toString(vlanId))); + tableColumns.put("parent_ifname", new Atom<>(parentTunnel.ifName)); + tableColumns.put("enabled", new Atom<>(true)); + tableColumns.put("network", new Atom<>(true)); + tableColumns.put("dhcp_sniff", new Atom<>(true)); + tableColumns.put("ip_assign_scheme", new Atom<>(parentTunnel.ipAssignScheme)); + tableColumns.put("NAT", new Atom<>(parentTunnel.nat)); + + tableColumns.put("mtu", new Atom<>(1500)); + + Row row = new Row(tableColumns); + + if (inetConfigMap.containsKey(parentTunnel.ifName + "_" + Integer.toString(vlanId))) { + List conditions = new ArrayList<>(); + conditions.add(new Condition("vlan_id", Function.EQUALS, new Atom<>(vlanId))); + conditions.add(new Condition("parent_ifname", Function.EQUALS, new Atom<>(parentTunnel.ifName))); + } else { + operations.add(new Insert(wifiInetConfigDbTable, row)); + } + + CompletableFuture fResult = ovsdbClient.transact(ovsdbName, operations); + OperationResult[] result = fResult.get(ovsdbTimeoutSec, TimeUnit.SECONDS); + + for (OperationResult res : result) { + + if (res instanceof InsertResult) { + LOG.info("createVlanNetworkInterfaces {}", ((InsertResult) res).toString()); + } else if (res instanceof UpdateResult) { + + LOG.info("createVlanNetworkInterfaces {}", ((UpdateResult) res).toString()); + } else if (res instanceof ErrorResult) { + LOG.error("createVlanNetworkInterfaces error {}", ((ErrorResult) res)); + throw new RuntimeException("createVlanNetworkInterfaces " + ((ErrorResult) res).getError() + + " " + ((ErrorResult) res).getDetails()); + } + } + + inetConfigMap = getProvisionedWifiInetConfigs(ovsdbClient); + + LOG.debug("Provisioned vlan on greTunnel {}", + inetConfigMap.get(parentTunnel.ifName + "_" + Integer.toString(vlanId))); + + } catch (OvsdbClientException | TimeoutException | ExecutionException | InterruptedException e) { + LOG.error("Error in provisioning Vlan", e); + throw new RuntimeException(e); + } + + } + private void createVlanNetworkInterfaces(OvsdbClient ovsdbClient, int vlanId) { try { diff --git a/opensync-gateway/src/test/java/com/telecominfraproject/wlan/opensync/ovsdb/dao/OvsdbDaoTest.java b/opensync-gateway/src/test/java/com/telecominfraproject/wlan/opensync/ovsdb/dao/OvsdbDaoTest.java index 0b32fd9..5a077cc 100644 --- a/opensync-gateway/src/test/java/com/telecominfraproject/wlan/opensync/ovsdb/dao/OvsdbDaoTest.java +++ b/opensync-gateway/src/test/java/com/telecominfraproject/wlan/opensync/ovsdb/dao/OvsdbDaoTest.java @@ -1,6 +1,5 @@ package com.telecominfraproject.wlan.opensync.ovsdb.dao; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -34,6 +33,7 @@ import org.springframework.test.context.junit4.SpringRunner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.telecominfraproject.wlan.core.model.equipment.MacAddress; import com.telecominfraproject.wlan.location.models.Location; import com.telecominfraproject.wlan.opensync.external.integration.models.ConnectNodeInfo; import com.telecominfraproject.wlan.opensync.external.integration.models.OpensyncAPConfig; @@ -41,8 +41,8 @@ import com.telecominfraproject.wlan.opensync.external.integration.models.Opensyn import com.telecominfraproject.wlan.profile.models.Profile; import com.telecominfraproject.wlan.profile.models.ProfileType; import com.telecominfraproject.wlan.profile.network.models.ApNetworkConfiguration; +import com.telecominfraproject.wlan.profile.network.models.GreTunnelConfiguration; import com.telecominfraproject.wlan.profile.ssid.models.SsidConfiguration; -import com.telecominfraproject.wlan.status.network.models.RadiusDetails; import com.vmware.ovsdb.exception.OvsdbClientException; import com.vmware.ovsdb.protocol.operation.notation.Atom; import com.vmware.ovsdb.protocol.operation.notation.Row; @@ -155,18 +155,16 @@ public class OvsdbDaoTest { apProfile.setName("ApProfile"); apProfile.setProfileType(ProfileType.equipment_ap); ApNetworkConfiguration tunnelProfileDetails = ApNetworkConfiguration.createWithDefaults(); - - tunnelProfileDetails.setGreLocalInetAddr(InetAddress.getByName("10.0.10.10")); - tunnelProfileDetails.setGreRemoteInetAddr(InetAddress.getByName("192.168.0.10")); - tunnelProfileDetails.setGreTunnelName("gre1"); - tunnelProfileDetails.setGreParentIfName("wan"); + Set greTunnels = Set.of(new GreTunnelConfiguration("gre1", "wan", + InetAddress.getByName("10.0.10.10"), InetAddress.getByName("192.168.0.10"), + MacAddress.valueOf("3c:22:fb:18:43:16"), Set.of(Integer.valueOf(100)))); + tunnelProfileDetails.setGreTunnelConfigurations(greTunnels); apProfile.setDetails(tunnelProfileDetails); OpensyncAPConfig apConfig = Mockito.mock(OpensyncAPConfig.class); Mockito.when(apConfig.getApProfile()).thenReturn(apProfile); ovsdbDao.configureGreTunnels(ovsdbClient, apConfig); - // 1 call to check existence, 1 to add profile - Mockito.verify(ovsdbClient, Mockito.times(2)).transact(Mockito.eq(OvsdbDao.ovsdbName), Mockito.anyList()); + Mockito.verify(ovsdbClient, Mockito.times(1)).transact(Mockito.eq(OvsdbDao.ovsdbName), Mockito.anyList()); Mockito.verify(apConfig, Mockito.times(3)).getApProfile(); } @@ -182,12 +180,12 @@ public class OvsdbDaoTest { Location location = new Location(); location.setName("Ottawa"); apConfig.setEquipmentLocation(location); - ovsdbDao.getRadiusConfiguration(apConfig, ssidConfig, security); + ovsdbDao.getRadiusConfiguration(apConfig, ssidConfig, security); assert (security.get("radius_server_ip").equals("192.168.0.1")); assert (security.get("radius_server_port").equals("1812")); assert (security.get("radius_server_secret").equals("testing123")); } - + @Test public void testGetRadiusAccountingConfiguration() throws Exception { OpensyncAPConfig apConfig = new OpensyncAPConfig(); @@ -314,10 +312,10 @@ public class OvsdbDaoTest { apProfile.setName("ApProfile"); apProfile.setProfileType(ProfileType.equipment_ap); ApNetworkConfiguration tunnelProfileDetails = ApNetworkConfiguration.createWithDefaults(); - - tunnelProfileDetails.setGreRemoteInetAddr(InetAddress.getByName("192.168.0.10")); - tunnelProfileDetails.setGreTunnelName("gre1"); - tunnelProfileDetails.setGreParentIfName("wan"); + Set greTunnels = Set.of(new GreTunnelConfiguration("gre1", "wan", + null, InetAddress.getByName("192.168.0.10"), + MacAddress.valueOf("3c:22:fb:18:43:16"), Set.of(Integer.valueOf(100)))); + tunnelProfileDetails.setGreTunnelConfigurations(greTunnels); apProfile.setDetails(tunnelProfileDetails); OpensyncAPConfig apConfig = Mockito.mock(OpensyncAPConfig.class); @@ -325,7 +323,7 @@ public class OvsdbDaoTest { ovsdbDao.configureGreTunnels(ovsdbClient, apConfig); // 2 calls to check existence, 2 calls to insert tunnel (1 each per // Profile) - Mockito.verify(ovsdbClient, Mockito.times(2)).transact(Mockito.eq(OvsdbDao.ovsdbName), Mockito.anyList()); + Mockito.verify(ovsdbClient, Mockito.times(1)).transact(Mockito.eq(OvsdbDao.ovsdbName), Mockito.anyList()); Mockito.verify(apConfig, Mockito.times(3)).getApProfile(); } @@ -339,9 +337,10 @@ public class OvsdbDaoTest { apProfile.setProfileType(ProfileType.equipment_ap); ApNetworkConfiguration tunnelProfileDetails = ApNetworkConfiguration.createWithDefaults(); - tunnelProfileDetails.setGreLocalInetAddr(InetAddress.getByName("10.0.10.10")); - tunnelProfileDetails.setGreTunnelName("gre1"); - tunnelProfileDetails.setGreParentIfName("wan"); + Set greTunnels = Set.of(new GreTunnelConfiguration("gre1", "wan", + InetAddress.getByName("10.0.10.10"), null, + MacAddress.valueOf("3c:22:fb:18:43:16"), Set.of(Integer.valueOf(100)))); + tunnelProfileDetails.setGreTunnelConfigurations(greTunnels); apProfile.setDetails(tunnelProfileDetails); OpensyncAPConfig apConfig = Mockito.mock(OpensyncAPConfig.class); @@ -362,9 +361,10 @@ public class OvsdbDaoTest { apProfile.setProfileType(ProfileType.equipment_ap); ApNetworkConfiguration tunnelProfileDetails = ApNetworkConfiguration.createWithDefaults(); - tunnelProfileDetails.setGreLocalInetAddr(InetAddress.getByName("10.0.10.10")); - tunnelProfileDetails.setGreRemoteInetAddr(InetAddress.getByName("192.168.0.10")); - tunnelProfileDetails.setGreTunnelName("gre1"); + Set greTunnels = Set.of(new GreTunnelConfiguration("gre1", null, + InetAddress.getByName("10.0.10.10"), InetAddress.getByName("192.168.0.10"), + MacAddress.valueOf("3c:22:fb:18:43:16"), Set.of(Integer.valueOf(100)))); + tunnelProfileDetails.setGreTunnelConfigurations(greTunnels); apProfile.setDetails(tunnelProfileDetails); OpensyncAPConfig apConfig = Mockito.mock(OpensyncAPConfig.class); @@ -385,9 +385,10 @@ public class OvsdbDaoTest { apProfile.setProfileType(ProfileType.equipment_ap); ApNetworkConfiguration tunnelProfileDetails = ApNetworkConfiguration.createWithDefaults(); - tunnelProfileDetails.setGreLocalInetAddr(InetAddress.getByName("10.0.10.10")); - tunnelProfileDetails.setGreRemoteInetAddr(InetAddress.getByName("192.168.0.10")); - tunnelProfileDetails.setGreParentIfName("wan"); + Set greTunnels = Set.of(new GreTunnelConfiguration(null, "wan", + InetAddress.getByName("10.0.10.10"), InetAddress.getByName("192.168.0.10"), + MacAddress.valueOf("3c:22:fb:18:43:16"), Set.of(Integer.valueOf(100)))); + tunnelProfileDetails.setGreTunnelConfigurations(greTunnels); apProfile.setDetails(tunnelProfileDetails);