From db47b7e1f4b8174698b1894edabf57d022fac609 Mon Sep 17 00:00:00 2001 From: Sean Zhang Date: Wed, 12 Jun 2024 10:28:41 +0300 Subject: [PATCH] Add support for IPv6 network setting Add IPv6 setting in network setting page. - Add IPv6 domain name, DNS servers, NTP servers enable/disable - Add DHCPv6 enable/disable - Add IPv6 default gateway - Add IPv6 addresses - Add IPv6 static addresses - Add IPv6 static addresses adding and deleting Tested: - IPv6 domain name, DNS servers, NTP servers enable/disable function - DHCPv6 enable/disable function - Verified the IPv6 default gateway - IPv6 addresses adding and deleting - Verified the IPv6 addresses in IPv6 table Change-Id: I9eebf6ef5f7de748f79779d8168b8dcfcdda2495 Signed-off-by: Sean Zhang --- src/locales/en-US.json | 11 + src/store/modules/Settings/NetworkStore.js | 172 +++++++++-- .../Settings/Network/ModalDefaultGateway.vue | 114 +++++++ src/views/Settings/Network/ModalIpv6.vue | 133 ++++++++ src/views/Settings/Network/Network.vue | 30 ++ .../Network/NetworkGlobalSettings.vue | 140 ++++++++- src/views/Settings/Network/TableIpv6.vue | 289 ++++++++++++++++++ 7 files changed, 859 insertions(+), 30 deletions(-) create mode 100644 src/views/Settings/Network/ModalDefaultGateway.vue create mode 100644 src/views/Settings/Network/ModalIpv6.vue create mode 100644 src/views/Settings/Network/TableIpv6.vue diff --git a/src/locales/en-US.json b/src/locales/en-US.json index 8ba7ac9450..44a63de392 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -703,16 +703,21 @@ }, "pageNetwork": { "dhcp": "DHCP", + "dhcp6": "DHCPv6", "domainName": "domain name", "dns": "DNS server", "fqdn": "FQDN", "hostname": "Hostname", + "ipVersion": "Version of IP", "interfaceSection": "Interface settings", "ipv4": "IPv4", "ipv4Addresses": "IPv4 addresses", "ipv6": "IPv6", + "ipv6Addresses": "IPv6 addresses", "linkStatus": "Link status", "macAddress": "MAC address", + "gateway": "Gateway", + "ipv6DefaultGateway": "IPv6 Default Gateway", "network": "network", "networkSettings": "Network settings", "ntp": "NTP server", @@ -728,7 +733,9 @@ "dhcpConfirmTitle": "%{dhcpState} DHCP", "editHostnameTitle": "Edit hostname", "editMacAddressTitle": "Edit MAC address", + "editIPv6DefaultGatewayTitle": "Edit IPv6 Default Gateway", "gateway": "Gateway", + "prefixLength": "Prefix Length", "ipAddress": "IP address", "staticDns": "Static DNS", "subnetMask": "Subnet mask" @@ -736,11 +743,15 @@ "table": { "addDnsAddress": "Add IP address", "addIpv4Address": "Add static IPv4 address", + "addIpv6Address": "Add static IPv6 address", "addressOrigin": "Address origin", + "prefixLength": "Prefix Length", "deleteDns": "Delete DNS address", "deleteIpv4": "Delete IPv4 address", + "deleteIpv6": "Delete IPv6 address", "editDns": "Edit DNS address", "editIpv4": "Edit IPv4 address", + "editIpv6": "Edit IPv6 address", "gateway": "Gateway", "ipAddress": "IP address", "subnet": "Subnet mask" diff --git a/src/store/modules/Settings/NetworkStore.js b/src/store/modules/Settings/NetworkStore.js index 7f24e19852..a249d22b36 100644 --- a/src/store/modules/Settings/NetworkStore.js +++ b/src/store/modules/Settings/NetworkStore.js @@ -29,29 +29,47 @@ const NetworkStore = { state.globalNetworkSettings = data.map(({ data }) => { const { DHCPv4, + DHCPv6, HostName, IPv4Addresses, IPv4StaticAddresses, + IPv6Addresses, + IPv6StaticAddresses, LinkStatus, MACAddress, + IPv6DefaultGateway, } = data; return { defaultGateway: IPv4StaticAddresses[0]?.Gateway, //First static gateway is the default gateway + ipv6DefaultGateway: IPv6DefaultGateway, dhcpAddress: IPv4Addresses.filter( (ipv4) => ipv4.AddressOrigin === 'DHCP', ), + dhcpv6Address: IPv6Addresses.filter( + (ipv6) => + ipv6.AddressOrigin === 'SLAAC' || ipv6.AddressOrigin === 'DHCPv6', + ), dhcpEnabled: DHCPv4.DHCPEnabled, + dhcp6Enabled: DHCPv6.OperatingMode, hostname: HostName, macAddress: MACAddress, linkStatus: LinkStatus, staticAddress: IPv4StaticAddresses[0]?.Address, // Display first static address on overview page + ipv6StaticAddress: IPv6StaticAddresses[0]?.Address, useDnsEnabled: DHCPv4.UseDNSServers, useDomainNameEnabled: DHCPv4.UseDomainName, useNtpEnabled: DHCPv4.UseNTPServers, + useDnsEnabledIpv6: DHCPv6.UseDNSServers, + useDomainNameEnabledIpv6: DHCPv6.UseDomainName, + useNtpEnabledIpv6: DHCPv6.UseNTPServers, }; }); }, setNtpState: (state, ntpState) => (state.ntpState = ntpState), + setDomainNameStateIpv6: (state, domainState) => + (state.domainStateIpv6 = domainState), + setDnsStateIpv6: (state, dnsState) => (state.dnsStateIpv6 = dnsState), + setNtpStateIpv6: (state, ntpState) => (state.ntpStateIpv6 = ntpState), setSelectedInterfaceId: (state, selectedInterfaceId) => (state.selectedInterfaceId = selectedInterfaceId), setSelectedInterfaceIndex: (state, selectedInterfaceIndex) => @@ -114,13 +132,49 @@ const NetworkStore = { ); }); }, - async saveDomainNameState({ commit, state }, domainState) { - commit('setDomainNameState', domainState); + async saveDhcp6EnabledState({ state, dispatch }, dhcpState) { const data = { - DHCPv4: { - UseDomainName: domainState, + DHCPv6: { + OperatingMode: dhcpState ? 'Enabled' : 'Disabled', }, }; + return api + .patch( + `${await this.dispatch('global/getBmcPath')}/EthernetInterfaces/${state.selectedInterfaceId}`, + data, + ) + .then(dispatch('getEthernetData')) + .then(() => { + return i18n.t('pageNetwork.toast.successSaveNetworkSettings', { + setting: i18n.t('pageNetwork.dhcp6'), + }); + }) + .catch((error) => { + console.log(error); + throw new Error( + i18n.t('pageNetwork.toast.errorSaveNetworkSettings', { + setting: i18n.t('pageNetwork.dhcp6'), + }), + ); + }); + }, + async saveDomainNameState({ commit, state }, { domainState, ipVersion }) { + var data; + if (ipVersion === 'IPv4') { + commit('setDomainNameState', domainState); + data = { + DHCPv4: { + UseDomainName: domainState, + }, + }; + } else if (ipVersion === 'IPv6') { + commit('setDomainNameStateIpv6', domainState); + data = { + DHCPv6: { + UseDomainName: domainState, + }, + }; + } // Saving to the first interface automatically updates DHCPv4 and DHCPv6 // on all interfaces return api @@ -135,7 +189,9 @@ const NetworkStore = { }) .catch((error) => { console.log(error); - commit('setDomainNameState', !domainState); + if (ipVersion === 'IPv4') commit('setDomainNameState', !domainState); + else if (ipVersion === 'IPv6') + commit('setDomainNameStateIpv6', !domainState); throw new Error( i18n.t('pageNetwork.toast.errorSaveNetworkSettings', { setting: i18n.t('pageNetwork.domainName'), @@ -143,13 +199,23 @@ const NetworkStore = { ); }); }, - async saveDnsState({ commit, state }, dnsState) { - commit('setDnsState', dnsState); - const data = { - DHCPv4: { - UseDNSServers: dnsState, - }, - }; + async saveDnsState({ commit, state }, { dnsState, ipVersion }) { + var data; + if (ipVersion === 'IPv4') { + commit('setDnsState', dnsState); + data = { + DHCPv4: { + UseDNSServers: dnsState, + }, + }; + } else if (ipVersion === 'IPv6') { + commit('setDnsStateIpv6', dnsState); + data = { + DHCPv6: { + UseDNSServers: dnsState, + }, + }; + } // Saving to the first interface automatically updates DHCPv4 and DHCPv6 // on all interfaces return api @@ -164,7 +230,8 @@ const NetworkStore = { }) .catch((error) => { console.log(error); - commit('setDnsState', !dnsState); + if (ipVersion === 'IPv4') commit('setDnsState', !dnsState); + else if (ipVersion === 'IPv6') commit('setDnsStateIpv6', !dnsState); throw new Error( i18n.t('pageNetwork.toast.errorSaveNetworkSettings', { setting: i18n.t('pageNetwork.dns'), @@ -172,13 +239,23 @@ const NetworkStore = { ); }); }, - async saveNtpState({ commit, state }, ntpState) { - commit('setNtpState', ntpState); - const data = { - DHCPv4: { - UseNTPServers: ntpState, - }, - }; + async saveNtpState({ commit, state }, { ntpState, ipVersion }) { + var data; + if (ipVersion === 'IPv4') { + commit('setNtpState', ntpState); + data = { + DHCPv4: { + UseNTPServers: ntpState, + }, + }; + } else if (ipVersion === 'IPv6') { + commit('setNtpStateIpv6', ntpState); + data = { + DHCPv6: { + UseNTPServers: ntpState, + }, + }; + } // Saving to the first interface automatically updates DHCPv4 and DHCPv6 // on all interfaces return api @@ -193,7 +270,8 @@ const NetworkStore = { }) .catch((error) => { console.log(error); - commit('setNtpState', !ntpState); + if (ipVersion === 'IPv4') commit('setNtpState', !ntpState); + else if (ipVersion === 'IPv6') commit('setNtpStateIpv6', !ntpState); throw new Error( i18n.t('pageNetwork.toast.errorSaveNetworkSettings', { setting: i18n.t('pageNetwork.ntp'), @@ -239,6 +317,37 @@ const NetworkStore = { ); }); }, + async saveIpv6Address({ dispatch, state }, ipv6Form) { + const originalAddresses = state.ethernetData[ + state.selectedInterfaceIndex + ].IPv6StaticAddresses.map((ipv6) => { + const { Address, PrefixLength } = ipv6; + return { + Address, + PrefixLength, + }; + }); + const newAddress = [ipv6Form]; + return api + .patch( + `${await this.dispatch('global/getBmcPath')}/EthernetInterfaces/${state.selectedInterfaceId}`, + { IPv6StaticAddresses: originalAddresses.concat(newAddress) }, + ) + .then(dispatch('getEthernetData')) + .then(() => { + return i18n.t('pageNetwork.toast.successSaveNetworkSettings', { + setting: i18n.t('pageNetwork.ipv6'), + }); + }) + .catch((error) => { + console.log(error); + throw new Error( + i18n.t('pageNetwork.toast.errorSaveNetworkSettings', { + setting: i18n.t('pageNetwork.ipv6'), + }), + ); + }); + }, async editIpv4Address({ dispatch, state }, ipv4TableData) { return api .patch( @@ -260,6 +369,27 @@ const NetworkStore = { ); }); }, + async editIpv6Address({ dispatch, state }, ipv6TableData) { + return api + .patch( + `${await this.dispatch('global/getBmcPath')}/EthernetInterfaces/${state.selectedInterfaceId}`, + { IPv6StaticAddresses: ipv6TableData }, + ) + .then(dispatch('getEthernetData')) + .then(() => { + return i18n.t('pageNetwork.toast.successSaveNetworkSettings', { + setting: i18n.t('pageNetwork.ipv6'), + }); + }) + .catch((error) => { + console.log(error); + throw new Error( + i18n.t('pageNetwork.toast.errorSaveNetworkSettings', { + setting: i18n.t('pageNetwork.ipv6'), + }), + ); + }); + }, async saveSettings({ state, dispatch }, interfaceSettingsForm) { return api .patch( diff --git a/src/views/Settings/Network/ModalDefaultGateway.vue b/src/views/Settings/Network/ModalDefaultGateway.vue new file mode 100644 index 0000000000..48c05c1dc4 --- /dev/null +++ b/src/views/Settings/Network/ModalDefaultGateway.vue @@ -0,0 +1,114 @@ + + + diff --git a/src/views/Settings/Network/ModalIpv6.vue b/src/views/Settings/Network/ModalIpv6.vue new file mode 100644 index 0000000000..f707a77412 --- /dev/null +++ b/src/views/Settings/Network/ModalIpv6.vue @@ -0,0 +1,133 @@ + + + diff --git a/src/views/Settings/Network/Network.vue b/src/views/Settings/Network/Network.vue index f731c25f87..0279cbe671 100644 --- a/src/views/Settings/Network/Network.vue +++ b/src/views/Settings/Network/Network.vue @@ -23,6 +23,8 @@ + + @@ -33,9 +35,14 @@ + + @@ -44,14 +51,17 @@ import BVToastMixin from '@/components/Mixins/BVToastMixin'; import DataFormatterMixin from '@/components/Mixins/DataFormatterMixin'; import LoadingBarMixin, { loading } from '@/components/Mixins/LoadingBarMixin'; import ModalMacAddress from './ModalMacAddress.vue'; +import ModalDefaultGateway from './ModalDefaultGateway.vue'; import ModalHostname from './ModalHostname.vue'; import ModalIpv4 from './ModalIpv4.vue'; +import ModalIpv6 from './ModalIpv6.vue'; import ModalDns from './ModalDns.vue'; import NetworkGlobalSettings from './NetworkGlobalSettings.vue'; import NetworkInterfaceSettings from './NetworkInterfaceSettings.vue'; import PageSection from '@/components/Global/PageSection'; import PageTitle from '@/components/Global/PageTitle'; import TableIpv4 from './TableIpv4.vue'; +import TableIpv6 from './TableIpv6.vue'; import TableDns from './TableDns.vue'; import { mapState } from 'vuex'; @@ -60,7 +70,9 @@ export default { components: { ModalHostname, ModalMacAddress, + ModalDefaultGateway, ModalIpv4, + ModalIpv6, ModalDns, NetworkGlobalSettings, NetworkInterfaceSettings, @@ -68,6 +80,7 @@ export default { PageTitle, TableDns, TableIpv4, + TableIpv6, }, mixins: [BVToastMixin, DataFormatterMixin, LoadingBarMixin], beforeRouteLeave(to, from, next) { @@ -79,6 +92,7 @@ export default { currentHostname: '', currentMacAddress: '', defaultGateway: '', + ipv6DefaultGateway: '', loading, tabIndex: 0, }; @@ -105,6 +119,9 @@ export default { const networkTableIpv4 = new Promise((resolve) => { this.$root.$on('network-table-ipv4-complete', () => resolve()); }); + const networkTableIpv6 = new Promise((resolve) => { + this.$root.$on('network-table-ipv6-complete', () => resolve()); + }); // Combine all child component Promises to indicate // when page data load complete Promise.all([ @@ -113,6 +130,7 @@ export default { interfaceSettings, networkTableDns, networkTableIpv4, + networkTableIpv6, ]).finally(() => this.endLoader()); }, methods: { @@ -131,6 +149,10 @@ export default { this.$store.getters['network/globalNetworkSettings'][ this.tabIndex ].macAddress; + this.ipv6DefaultGateway = + this.$store.getters['network/globalNetworkSettings'][ + this.tabIndex + ].ipv6DefaultGateway; }, getTabIndex(selectedIndex) { this.tabIndex = selectedIndex; @@ -149,6 +171,14 @@ export default { .catch(({ message }) => this.errorToast(message)) .finally(() => this.endLoader()); }, + saveIpv6Address(modalFormData) { + this.startLoader(); + this.$store + .dispatch('network/saveIpv6Address', modalFormData) + .then((message) => this.successToast(message)) + .catch(({ message }) => this.errorToast(message)) + .finally(() => this.endLoader()); + }, saveDnsAddress(modalFormData) { this.startLoader(); this.$store diff --git a/src/views/Settings/Network/NetworkGlobalSettings.vue b/src/views/Settings/Network/NetworkGlobalSettings.vue index 3028767368..db834047d7 100644 --- a/src/views/Settings/Network/NetworkGlobalSettings.vue +++ b/src/views/Settings/Network/NetworkGlobalSettings.vue @@ -4,7 +4,7 @@ :section-title="$t('pageNetwork.networkSettings')" > - +
{{ $t('pageNetwork.hostname') }} @@ -15,7 +15,14 @@
{{ dataFormatter(firstInterface.hostname) }}
- + +
+
{{ $t('pageNetwork.ipVersion') }}
+
{{ $t('pageNetwork.ipv4') }}
+
{{ $t('pageNetwork.ipv6') }}
+
+
+
{{ $t('pageNetwork.useDomainName') }}
@@ -32,9 +39,23 @@ {{ $t('global.status.disabled') }}
+
+ + + {{ $t('global.status.enabled') }} + + {{ $t('global.status.disabled') }} + +
- +
{{ $t('pageNetwork.useDns') }}
@@ -51,9 +72,23 @@ {{ $t('global.status.disabled') }}
+
+ + + {{ $t('global.status.enabled') }} + + {{ $t('global.status.disabled') }} + +
- +
{{ $t('pageNetwork.useNtp') }}
@@ -70,6 +105,20 @@ {{ $t('global.status.disabled') }}
+
+ + + {{ $t('global.status.enabled') }} + + {{ $t('global.status.disabled') }} + +
@@ -125,6 +174,33 @@ export default { return newValue; }, }, + useDomainNameStateIpv6: { + get() { + return this.$store.getters['network/globalNetworkSettings'][0] + .useDomainNameEnabledIpv6; + }, + set(newValue) { + return newValue; + }, + }, + useDnsStateIpv6: { + get() { + return this.$store.getters['network/globalNetworkSettings'][0] + .useDnsEnabledIpv6v6; + }, + set(newValue) { + return newValue; + }, + }, + useNtpStateIpv6: { + get() { + return this.$store.getters['network/globalNetworkSettings'][0] + .useNtpEnabledIpv6; + }, + set(newValue) { + return newValue; + }, + }, }, created() { this.$store.dispatch('network/getEthernetData').finally(() => { @@ -135,7 +211,10 @@ export default { methods: { changeDomainNameState(state) { this.$store - .dispatch('network/saveDomainNameState', state) + .dispatch('network/saveDomainNameState', { + domainState: state, + ipVersion: 'IPv4', + }) .then((success) => { this.successToast(success); }) @@ -143,14 +222,57 @@ export default { }, changeDnsState(state) { this.$store - .dispatch('network/saveDnsState', state) - .then((message) => this.successToast(message)) + .dispatch('network/saveDnsState', { + dnsState: state, + ipVersion: 'IPv4', + }) + .then((message) => { + this.successToast(message); + }) .catch(({ message }) => this.errorToast(message)); }, changeNtpState(state) { this.$store - .dispatch('network/saveNtpState', state) - .then((message) => this.successToast(message)) + .dispatch('network/saveNtpState', { + ntpState: state, + ipVersion: 'IPv4', + }) + .then((message) => { + this.successToast(message); + }) + .catch(({ message }) => this.errorToast(message)); + }, + changeDomainNameStateIpv6(state) { + this.$store + .dispatch('network/saveDomainNameState', { + domainState: state, + ipVersion: 'IPv6', + }) + .then((success) => { + this.successToast(success); + }) + .catch(({ message }) => this.errorToast(message)); + }, + changeDnsStateIpv6(state) { + this.$store + .dispatch('network/saveDnsState', { + dnsState: state, + ipVersion: 'IPv6', + }) + .then((message) => { + this.successToast(message); + }) + .catch(({ message }) => this.errorToast(message)); + }, + changeNtpStateIpv6(state) { + this.$store + .dispatch('network/saveNtpState', { + ntpState: state, + ipVersion: 'IPv6', + }) + .then((message) => { + this.successToast(message); + }) .catch(({ message }) => this.errorToast(message)); }, initSettingsModal() { diff --git a/src/views/Settings/Network/TableIpv6.vue b/src/views/Settings/Network/TableIpv6.vue new file mode 100644 index 0000000000..5a16e9dc1c --- /dev/null +++ b/src/views/Settings/Network/TableIpv6.vue @@ -0,0 +1,289 @@ + + +